Get started
การออกแบบการนำเข้าธีมกำหนดเองจาก Tweakcn
การออกแบบการนำเข้าธีมกำหนดเองจาก Tweakcn
สถานะ: ได้รับอนุมัติในเทอร์มินัลเมื่อ 2026-04-22
สรุป
เพิ่มสล็อตธีมกำหนดเองของ UI ควบคุมแบบภายในเบราว์เซอร์เพียงหนึ่งสล็อตที่สามารถนำเข้าได้จากลิงก์แชร์ของ tweakcn กลุ่มธีมในตัวที่มีอยู่ยังคงเป็น claw, knot และ dash กลุ่มใหม่ custom ทำงานเหมือนกลุ่มธีม OpenClaw ปกติ และรองรับโหมด light, dark และ system เมื่อเพย์โหลด tweakcn ที่นำเข้ามีชุดโทเค็นทั้งแบบสว่างและมืด
ธีมที่นำเข้าจะถูกจัดเก็บเฉพาะในโปรไฟล์เบราว์เซอร์ปัจจุบันร่วมกับการตั้งค่า UI ควบคุมที่เหลือ ไม่ถูกเขียนลงในการกำหนดค่า Gateway และไม่ซิงก์ข้ามอุปกรณ์หรือเบราว์เซอร์
ปัญหา
ระบบธีมของ UI ควบคุมในปัจจุบันถูกจำกัดไว้กับกลุ่มธีมที่ฮาร์ดโค้ดไว้สามกลุ่ม:
ui/src/ui/theme.tsui/src/ui/views/config.tsui/src/styles/base.css
ผู้ใช้สามารถสลับระหว่างกลุ่มในตัวและตัวแปรโหมดได้ แต่ไม่สามารถนำเข้าธีมจาก tweakcn ได้โดยไม่แก้ไข CSS ของ repo ผลลัพธ์ที่ต้องการมีขอบเขตเล็กกว่าระบบธีมทั่วไป: คงธีมในตัวสามธีมไว้ และเพิ่มสล็อตนำเข้าที่ผู้ใช้ควบคุมได้หนึ่งสล็อตซึ่งสามารถแทนที่ได้จากลิงก์ tweakcn
เป้าหมาย
- คงกลุ่มธีมในตัวที่มีอยู่ไว้โดยไม่เปลี่ยนแปลง
- เพิ่มสล็อตกำหนดเองที่นำเข้าได้เพียงหนึ่งสล็อต ไม่ใช่คลังธีม
- รับลิงก์แชร์ของ tweakcn หรือ URL ตรง
https://tweakcn.com/r/themes/{id} - บันทึกธีมที่นำเข้าไว้ในพื้นที่จัดเก็บภายในของเบราว์เซอร์เท่านั้น
- ทำให้สล็อตที่นำเข้าใช้งานได้กับตัวควบคุมโหมด
light,darkและsystemที่มีอยู่ - รักษาพฤติกรรมเมื่อเกิดความล้มเหลวให้ปลอดภัย: การนำเข้าที่ไม่ถูกต้องต้องไม่ทำให้ธีม UI ที่ใช้งานอยู่เสียหาย
สิ่งที่ไม่ใช่เป้าหมาย
- ไม่มีคลังหลายธีมหรือรายการนำเข้าแบบภายในเบราว์เซอร์
- ไม่มีการบันทึกฝั่ง Gateway หรือการซิงก์ข้ามอุปกรณ์
- ไม่มีตัวแก้ไข CSS อิสระหรือตัวแก้ไข JSON ธีมดิบ
- ไม่มีการโหลดแอสเซ็ตฟอนต์ระยะไกลจาก tweakcn โดยอัตโนมัติ
- ไม่พยายามรองรับเพย์โหลด tweakcn ที่เปิดเผยเพียงโหมดเดียว
- ไม่มีการปรับโครงสร้างระบบธีมทั่วทั้ง repo นอกเหนือจาก seam ที่จำเป็นสำหรับ UI ควบคุม
การตัดสินใจของผู้ใช้ที่ทำไว้แล้ว
- คงธีมในตัวสามธีมไว้
- เพิ่มสล็อตนำเข้าที่ขับเคลื่อนด้วย tweakcn หนึ่งสล็อต
- จัดเก็บธีมที่นำเข้าไว้ในเบราว์เซอร์ ไม่ใช่การกำหนดค่า Gateway
- รองรับ
light,darkและsystemสำหรับสล็อตที่นำเข้า - การเขียนทับสล็อตกำหนดเองด้วยการนำเข้าครั้งถัดไปคือพฤติกรรมที่ตั้งใจไว้
แนวทางที่แนะนำ
เพิ่มรหัสกลุ่มธีมที่สี่คือ custom ในโมเดลธีมของ UI ควบคุม กลุ่ม custom จะเลือกได้เฉพาะเมื่อมีการนำเข้า tweakcn ที่ถูกต้องเท่านั้น เพย์โหลดที่นำเข้าจะถูกทำให้เป็นมาตรฐานเป็นระเบียนธีมกำหนดเองเฉพาะ OpenClaw และจัดเก็บในพื้นที่จัดเก็บภายในของเบราว์เซอร์ร่วมกับการตั้งค่า UI ที่เหลือ
ขณะรัน OpenClaw จะแสดงแท็ก <style> ที่จัดการอยู่ ซึ่งกำหนดบล็อกตัวแปร CSS กำหนดเองที่ resolve แล้ว:
:root[data-theme="custom"] { ... }
:root[data-theme="custom-light"] { ... }
วิธีนี้ทำให้ตัวแปรธีมกำหนดเองถูกจำกัดขอบเขตไว้กับกลุ่ม custom และหลีกเลี่ยงการรั่วไหลของตัวแปร CSS แบบ inline เข้าไปในกลุ่มในตัว
สถาปัตยกรรม
โมเดลธีม
อัปเดต ui/src/ui/theme.ts:
- ขยาย
ThemeNameให้รวมcustom - ขยาย
ResolvedThemeให้รวมcustomและcustom-light - ขยาย
VALID_THEME_NAMES - อัปเดต
resolveTheme()เพื่อให้customสะท้อนพฤติกรรมกลุ่มที่มีอยู่:custom + dark->customcustom + light->custom-lightcustom + system->customหรือcustom-lightตามค่ากำหนดของ OS
ไม่มีการเพิ่ม alias เดิมสำหรับ custom
โมเดลการบันทึกข้อมูล
ขยายการบันทึก UiSettings ใน ui/src/ui/storage.ts ด้วยเพย์โหลดธีมกำหนดเองแบบไม่บังคับหนึ่งรายการ:
customTheme?: ImportedCustomTheme
รูปทรงข้อมูลที่แนะนำให้จัดเก็บ:
type ImportedCustomTheme = {
sourceUrl: string;
themeId: string;
label: string;
importedAt: string;
light: Record<string, string>;
dark: Record<string, string>;
};
หมายเหตุ:
sourceUrlจัดเก็บอินพุตเดิมของผู้ใช้หลังการทำให้เป็นมาตรฐานthemeIdคือรหัสธีม tweakcn ที่ดึงออกมาจาก URLlabelคือฟิลด์nameของ tweakcn เมื่อมีอยู่ มิฉะนั้นใช้Customlightและdarkคือแมปโทเค็น OpenClaw ที่ทำให้เป็นมาตรฐานแล้ว ไม่ใช่เพย์โหลด tweakcn ดิบ- เพย์โหลดที่นำเข้าอยู่ข้างการตั้งค่าแบบภายในเบราว์เซอร์อื่น ๆ และถูก serialize ในเอกสาร local-storage เดียวกัน
- หากข้อมูลธีมกำหนดเองที่จัดเก็บไว้หายไปหรือไม่ถูกต้องระหว่างโหลด ให้ละเว้นเพย์โหลดและ fallback เป็น
theme: "claw"เมื่อกลุ่มที่บันทึกไว้เป็นcustom
การใช้งานขณะรัน
เพิ่มตัวจัดการ stylesheet ธีมกำหนดเองแบบแคบใน runtime ของ UI ควบคุม โดยเป็นเจ้าของใกล้ ui/src/ui/app-settings.ts และ ui/src/ui/theme.ts
ความรับผิดชอบ:
- สร้างหรืออัปเดตแท็ก
<style id="openclaw-custom-theme">ที่เสถียรหนึ่งแท็กในdocument.head - ปล่อย CSS เฉพาะเมื่อมีเพย์โหลดธีมกำหนดเองที่ถูกต้อง
- ลบเนื้อหาแท็ก style เมื่อเพย์โหลดถูกล้าง
- คง CSS ของกลุ่มในตัวไว้ใน
ui/src/styles/base.css; อย่าแทรกโทเค็นที่นำเข้าเข้าไปใน stylesheet ที่ check in ไว้
ตัวจัดการนี้ทำงานทุกครั้งที่มีการโหลด บันทึก นำเข้า หรือล้างการตั้งค่า
ตัวเลือกโหมดสว่าง
การใช้งานควรเลือกใช้ data-theme-mode="light" สำหรับสไตล์โหมดสว่างข้ามกลุ่ม แทนการกรณีพิเศษ custom-light หาก selector ที่มีอยู่ถูกตรึงกับ data-theme="light" และจำเป็นต้องใช้กับทุกกลุ่มแบบสว่าง ให้ขยาย selector นั้นเป็นส่วนหนึ่งของงานนี้
UX การนำเข้า
อัปเดต ui/src/ui/views/config.ts ในส่วน Appearance:
- เพิ่มการ์ดธีม
Customข้างClaw,KnotและDash - แสดงการ์ดเป็น disabled เมื่อไม่มีธีมกำหนดเองที่นำเข้าไว้
- เพิ่มแผงนำเข้าใต้กริดธีมพร้อม:
- ช่องกรอกข้อความหนึ่งช่องสำหรับลิงก์แชร์ของ tweakcn หรือ URL
/r/themes/{id} - ปุ่ม
Importหนึ่งปุ่ม - เส้นทาง
Replaceหนึ่งเส้นทางเมื่อมีเพย์โหลดกำหนดเองอยู่แล้ว - การกระทำ
Clearหนึ่งรายการเมื่อมีเพย์โหลดกำหนดเองอยู่แล้ว
- ช่องกรอกข้อความหนึ่งช่องสำหรับลิงก์แชร์ของ tweakcn หรือ URL
- แสดงป้ายกำกับธีมที่นำเข้าและโฮสต์ต้นทางเมื่อมีเพย์โหลดอยู่
- หากธีมที่ใช้งานอยู่คือ
customการนำเข้าการแทนที่จะมีผลทันที - หากธีมที่ใช้งานอยู่ไม่ใช่
customการนำเข้าจะเพียงจัดเก็บเพย์โหลดใหม่ไว้จนกว่าผู้ใช้จะเลือกการ์ดCustom
ตัวเลือกธีมในการตั้งค่าแบบเร็วใน ui/src/ui/views/config-quick.ts ควรแสดง Custom เฉพาะเมื่อมีเพย์โหลดอยู่ด้วย
การแยกวิเคราะห์ URL และการ fetch ระยะไกล
เส้นทางนำเข้าในเบราว์เซอร์รับ:
https://tweakcn.com/themes/{id}https://tweakcn.com/r/themes/{id}
การใช้งานควรทำให้ทั้งสองรูปแบบเป็นมาตรฐานเป็น:
https://tweakcn.com/r/themes/{id}
จากนั้นเบราว์เซอร์จะ fetch endpoint /r/themes/{id} ที่ทำให้เป็นมาตรฐานแล้วโดยตรง
ใช้ตัวตรวจสอบ schema แบบแคบสำหรับเพย์โหลดภายนอก แนะนำให้ใช้ zod เพราะนี่คือขอบเขตภายนอกที่ไม่น่าเชื่อถือ
ฟิลด์ระยะไกลที่จำเป็น:
nameระดับบนสุดเป็น string แบบไม่บังคับcssVars.themeเป็น object แบบไม่บังคับcssVars.lightเป็น objectcssVars.darkเป็น object
หาก cssVars.light หรือ cssVars.dark ขาดหายไป ให้ปฏิเสธการนำเข้า นี่เป็นเจตนา: พฤติกรรมผลิตภัณฑ์ที่อนุมัติคือการรองรับโหมดเต็มรูปแบบ ไม่ใช่การสังเคราะห์ด้านที่ขาดหายไปแบบพยายามให้ดีที่สุด
การแมปโทเค็น
อย่าสะท้อนตัวแปร tweakcn แบบตรง ๆ โดยไม่คัดกรอง ให้ทำ subset ที่มีขอบเขตให้เป็นมาตรฐานเป็นโทเค็น OpenClaw และ derive ส่วนที่เหลือใน helper
โทเค็นที่นำเข้าโดยตรง
จากแต่ละบล็อกโหมดของ tweakcn:
backgroundforegroundcardcard-foregroundpopoverpopover-foregroundprimaryprimary-foregroundsecondarysecondary-foregroundmutedmuted-foregroundaccentaccent-foregrounddestructivedestructive-foregroundborderinputringradius
จาก cssVars.theme ที่ใช้ร่วมกันเมื่อมีอยู่:
font-sansfont-mono
หากบล็อกโหมด override font-sans, font-mono หรือ radius ค่าภายในโหมดจะชนะ
โทเค็นที่ derive สำหรับ OpenClaw
ตัวนำเข้าจะ derive ตัวแปรเฉพาะ OpenClaw จากสีฐานที่นำเข้า:
--bg-accent--bg-elevated--bg-hover--panel--panel-strong--panel-hover--chrome--chrome-strong--text--text-strong--chat-text--muted--muted-strong--accent-hover--accent-muted--accent-subtle--accent-glow--focus--focus-ring--focus-glow--secondary--secondary-foreground--danger--danger-muted--danger-subtle
กฎการ derive อยู่ใน helper แบบ pure เพื่อให้ทดสอบได้โดยอิสระ สูตรผสมสีที่แน่นอนเป็นรายละเอียดการใช้งาน แต่ helper ต้องเป็นไปตามข้อจำกัดสองข้อ:
- รักษาคอนทราสต์ให้อ่านได้ใกล้เคียงกับเจตนาของธีมที่นำเข้า
- ให้เอาต์พุตที่เสถียรสำหรับเพย์โหลดที่นำเข้าเดียวกัน
โทเค็นที่ละเว้นใน v1
โทเค็น tweakcn เหล่านี้ถูกละเว้นโดยเจตนาในเวอร์ชันแรก:
chart-*sidebar-*font-serifshadow-*tracking-*letter-spacingspacing
วิธีนี้จำกัดขอบเขตไว้ที่โทเค็นที่ UI ควบคุมปัจจุบันต้องการจริง ๆ
ฟอนต์
สตริง font stack จะถูกนำเข้าหากมีอยู่ แต่ OpenClaw จะไม่โหลดแอสเซ็ตฟอนต์ระยะไกลใน v1 หาก stack ที่นำเข้าอ้างอิงฟอนต์ที่ไม่มีในเบราว์เซอร์ พฤติกรรม fallback ปกติจะถูกใช้
พฤติกรรมเมื่อเกิดความล้มเหลว
การนำเข้าที่ไม่ถูกต้องต้อง fail closed
- รูปแบบ URL ไม่ถูกต้อง: แสดงข้อผิดพลาด validation แบบ inline และไม่ fetch
- โฮสต์หรือรูปแบบ path ไม่รองรับ: แสดงข้อผิดพลาด validation แบบ inline และไม่ fetch
- เครือข่ายล้มเหลว, response ไม่ OK หรือ JSON ผิดรูปแบบ: แสดงข้อผิดพลาด inline และคงเพย์โหลดที่จัดเก็บปัจจุบันไว้โดยไม่แตะต้อง
- Schema ล้มเหลวหรือบล็อก light/dark ขาดหาย: แสดงข้อผิดพลาด inline และคงเพย์โหลดที่จัดเก็บปัจจุบันไว้โดยไม่แตะต้อง
- การกระทำ Clear:
- ลบเพย์โหลดกำหนดเองที่จัดเก็บไว้
- ลบเนื้อหาแท็ก style กำหนดเองที่จัดการอยู่
- หาก
customใช้งานอยู่ ให้สลับกลุ่มธีมกลับเป็นclaw
- เพย์โหลดกำหนดเองที่จัดเก็บไว้ไม่ถูกต้องในการโหลดครั้งแรก:
- ละเว้นเพย์โหลดที่จัดเก็บไว้
- ไม่ปล่อย CSS กำหนดเอง
- หากกลุ่มธีมที่บันทึกไว้เป็น
customให้ fallback เป็นclaw
ไม่ควรมีจุดใดที่การนำเข้าล้มเหลวแล้วทำให้เอกสารที่ใช้งานอยู่มีตัวแปร CSS กำหนดเองบางส่วนถูกใช้งาน
ไฟล์ที่คาดว่าจะเปลี่ยนในการใช้งาน
ไฟล์หลัก:
ui/src/ui/theme.tsui/src/ui/storage.tsui/src/ui/app-settings.tsui/src/ui/views/config.tsui/src/ui/views/config-quick.tsui/src/styles/base.css
Helper ใหม่ที่เป็นไปได้:
ui/src/ui/custom-theme.ts
การทดสอบ:
ui/src/ui/app-settings.test.tsui/src/ui/storage.node.test.tsui/src/ui/views/config.browser.test.ts- การทดสอบแบบมุ่งเน้นใหม่สำหรับการแยกวิเคราะห์ URL และการทำให้เพย์โหลดเป็นมาตรฐาน
การทดสอบ
coverage ขั้นต่ำของการใช้งาน:
- แยกวิเคราะห์ URL ลิงก์แชร์เป็นรหัสธีม tweakcn
- ทำให้
/themes/{id}และ/r/themes/{id}เป็นมาตรฐานเป็น URL สำหรับ fetch - ปฏิเสธโฮสต์ที่ไม่รองรับและรหัสที่ผิดรูปแบบ
- ตรวจสอบรูปทรงเพย์โหลด tweakcn
- แมปเพย์โหลด tweakcn ที่ถูกต้องเป็นแมปโทเค็น OpenClaw แบบ light และ dark ที่ทำให้เป็นมาตรฐาน
- โหลดและบันทึกเพย์โหลดกำหนดเองในการตั้งค่าแบบภายในเบราว์เซอร์
- resolve
customสำหรับlight,darkและsystem - ปิดใช้งานการเลือก
Customเมื่อไม่มีเพย์โหลด - ใช้ธีมที่นำเข้าทันทีเมื่อ
customใช้งานอยู่แล้ว - fallback เป็น
clawเมื่อธีมกำหนดเองที่ใช้งานอยู่ถูกล้าง
เป้าหมายการตรวจสอบด้วยตนเอง:
- นำเข้าธีม tweakcn ที่รู้จักจาก Settings
- สลับระหว่าง
light,darkและsystem - สลับระหว่าง
customและกลุ่มในตัว - โหลดหน้าใหม่และยืนยันว่าธีมกำหนดเองที่นำเข้ายังคงอยู่เฉพาะภายในเครื่อง
หมายเหตุการ rollout
ฟีเจอร์นี้ตั้งใจให้มีขนาดเล็ก หากผู้ใช้ขอหลายธีมที่นำเข้า การเปลี่ยนชื่อ การส่งออก หรือการซิงก์ข้ามอุปกรณ์ในภายหลัง ให้ถือว่าเป็นการออกแบบต่อยอด อย่าสร้าง abstraction ของคลังธีมไว้ล่วงหน้าในการใช้งานนี้