Get started

طراحی واردسازی قالب سفارشی Tweakcn

طراحی واردسازی قالب سفارشی Tweakcn

وضعیت: تاییدشده در ترمینال در 2026-04-22

خلاصه

دقیقا یک جایگاه قالب سفارشیِ محلیِ مرورگر به رابط کاربری کنترل اضافه کنید که بتوان آن را از یک لینک اشتراک‌گذاری tweakcn وارد کرد. خانواده‌های قالب داخلی موجود همچنان claw، knot و dash می‌مانند. خانواده جدید custom مانند یک خانواده قالب عادی OpenClaw رفتار می‌کند و وقتی محموله واردشده tweakcn شامل هر دو مجموعه توکن روشن و تیره باشد، از حالت‌های light، dark و system پشتیبانی می‌کند.

قالب واردشده فقط در نمایه مرورگر فعلی و همراه با بقیه تنظیمات رابط کاربری کنترل ذخیره می‌شود. این قالب در پیکربندی Gateway نوشته نمی‌شود و بین دستگاه‌ها یا مرورگرها همگام‌سازی نمی‌شود.

مشکل

سامانه قالب رابط کاربری کنترل در حال حاضر به سه خانواده قالب سخت‌کدنویسی‌شده محدود است:

  • ui/src/ui/theme.ts
  • ui/src/ui/views/config.ts
  • ui/src/styles/base.css

کاربران می‌توانند بین خانواده‌های داخلی و گونه‌های حالت جابه‌جا شوند، اما بدون ویرایش CSS مخزن نمی‌توانند قالبی را از tweakcn وارد کنند. نتیجه درخواستی کوچک‌تر از یک سامانه قالب‌دهی عمومی است: سه قالب داخلی را نگه دارید و یک جایگاه واردشده تحت کنترل کاربر اضافه کنید که بتوان آن را از یک لینک tweakcn جایگزین کرد.

اهداف

  • خانواده‌های قالب داخلی موجود را بدون تغییر نگه دارید.
  • دقیقا یک جایگاه سفارشی واردشده اضافه کنید، نه یک کتابخانه قالب.
  • یک لینک اشتراک‌گذاری tweakcn یا یک URL مستقیم https://tweakcn.com/r/themes/{id} را بپذیرید.
  • قالب واردشده را فقط در فضای ذخیره‌سازی محلی مرورگر ماندگار کنید.
  • جایگاه واردشده را با کنترل‌های حالت موجود light، dark و system سازگار کنید.
  • رفتار شکست را امن نگه دارید: واردسازی نامعتبر هرگز قالب فعال رابط کاربری را خراب نمی‌کند.

غیرهدف‌ها

  • بدون کتابخانه چندقالبی یا فهرست محلیِ مرورگر از واردسازی‌ها.
  • بدون ماندگاری در سمت Gateway یا همگام‌سازی بین دستگاهی.
  • بدون ویرایشگر CSS دلخواه یا ویرایشگر JSON خام قالب.
  • بدون بارگذاری خودکار دارایی‌های فونت راه‌دور از tweakcn.
  • بدون تلاش برای پشتیبانی از محموله‌های tweakcn که فقط یک حالت را در معرض می‌گذارند.
  • بدون بازآرایی قالب‌دهی در کل مخزن، فراتر از درگاه‌های لازم برای رابط کاربری کنترل.

تصمیم‌های کاربر که از قبل گرفته شده‌اند

  • سه قالب داخلی را نگه دارید.
  • یک جایگاه واردسازی مبتنی بر tweakcn اضافه کنید.
  • قالب واردشده را در مرورگر ذخیره کنید، نه در پیکربندی Gateway.
  • از light، dark و system برای جایگاه واردشده پشتیبانی کنید.
  • بازنویسی جایگاه سفارشی با واردسازی بعدی رفتار مورد نظر است.

رویکرد پیشنهادی

یک شناسه خانواده قالب چهارم، یعنی custom، به مدل قالب رابط کاربری کنترل اضافه کنید. خانواده custom فقط زمانی قابل انتخاب می‌شود که یک واردسازی معتبر tweakcn وجود داشته باشد. محموله واردشده به یک رکورد قالب سفارشی ویژه OpenClaw نرمال‌سازی می‌شود و همراه با بقیه تنظیمات رابط کاربری در فضای ذخیره‌سازی محلی مرورگر ذخیره می‌شود.

در زمان اجرا، OpenClaw یک تگ <style> مدیریت‌شده رندر می‌کند که بلوک‌های متغیر CSS سفارشی حل‌شده را تعریف می‌کند:

:root[data-theme="custom"] { ... }
:root[data-theme="custom-light"] { ... }

این کار متغیرهای قالب سفارشی را به خانواده custom محدود می‌کند و از نشت متغیرهای CSS درون‌خطی به خانواده‌های داخلی جلوگیری می‌کند.

معماری

مدل قالب

ui/src/ui/theme.ts را به‌روزرسانی کنید:

  • ThemeName را گسترش دهید تا شامل custom شود.
  • ResolvedTheme را گسترش دهید تا شامل custom و custom-light شود.
  • VALID_THEME_NAMES را گسترش دهید.
  • resolveTheme() را به‌روزرسانی کنید تا custom رفتار خانواده موجود را بازتاب دهد:
    • custom + dark -> custom
    • custom + light -> custom-light
    • custom + system -> custom یا custom-light بر اساس ترجیح سیستم‌عامل

هیچ نام مستعار قدیمی برای 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 است که از URL استخراج شده است.
  • label وقتی وجود داشته باشد فیلد name در tweakcn است، وگرنه Custom.
  • light و dark نقشه‌های توکن OpenClaw هستند که از قبل نرمال‌سازی شده‌اند، نه محموله‌های خام tweakcn.
  • محموله واردشده کنار سایر تنظیمات محلیِ مرورگر قرار می‌گیرد و در همان سند فضای ذخیره‌سازی محلی سریال‌سازی می‌شود.
  • اگر داده قالب سفارشی ذخیره‌شده هنگام بارگذاری وجود نداشته باشد یا نامعتبر باشد، محموله را نادیده بگیرید و وقتی خانواده ماندگارشده custom بوده است به theme: "claw" برگردید.

اعمال در زمان اجرا

یک مدیر باریکِ شیوه‌نامه قالب سفارشی در زمان اجرای رابط کاربری کنترل اضافه کنید، با مالکیت نزدیک به ui/src/ui/app-settings.ts و ui/src/ui/theme.ts.

مسئولیت‌ها:

  • ایجاد یا به‌روزرسانی یک تگ پایدار <style id="openclaw-custom-theme"> در document.head.
  • انتشار CSS فقط وقتی یک محموله قالب سفارشی معتبر وجود دارد.
  • حذف محتوای تگ شیوه‌نامه وقتی محموله پاک می‌شود.
  • نگه داشتن CSS خانواده‌های داخلی در ui/src/styles/base.css؛ توکن‌های واردشده را داخل شیوه‌نامه ثبت‌شده در مخزن وصله نکنید.

این مدیر هر بار که تنظیمات بارگذاری، ذخیره، وارد یا پاک می‌شوند اجرا می‌شود.

گزینشگرهای حالت روشن

پیاده‌سازی باید برای سبک‌دهی روشنِ بین خانواده‌ها، به جای موردی‌کردن custom-light، data-theme-mode="light" را ترجیح دهد. اگر یک گزینشگر موجود به data-theme="light" سنجاق شده است و باید به هر خانواده روشن اعمال شود، آن را به عنوان بخشی از این کار گسترده‌تر کنید.

تجربه کاربری واردسازی

ui/src/ui/views/config.ts را در بخش Appearance به‌روزرسانی کنید:

  • یک کارت قالب Custom کنار Claw، Knot و Dash اضافه کنید.
  • وقتی هیچ قالب سفارشی واردشده‌ای وجود ندارد، کارت را غیرفعال نشان دهید.
  • یک پنل واردسازی زیر شبکه قالب اضافه کنید با:
    • یک ورودی متن برای لینک اشتراک‌گذاری tweakcn یا URL از نوع /r/themes/{id}
    • یک دکمه Import
    • یک مسیر Replace وقتی یک محموله سفارشی از قبل وجود دارد
    • یک اقدام Clear وقتی یک محموله سفارشی از قبل وجود دارد
  • وقتی محموله‌ای وجود دارد، برچسب قالب واردشده و میزبان منبع را نشان دهید.
  • اگر قالب فعال custom باشد، وارد کردن جایگزین بلافاصله اعمال می‌شود.
  • اگر قالب فعال custom نباشد، واردسازی فقط محموله جدید را ذخیره می‌کند تا کاربر کارت Custom را انتخاب کند.

گزینشگر سریع قالب در ui/src/ui/views/config-quick.ts نیز باید Custom را فقط وقتی محموله‌ای وجود دارد نشان دهد.

تجزیه URL و دریافت راه‌دور

مسیر واردسازی مرورگر این موارد را می‌پذیرد:

  • https://tweakcn.com/themes/{id}
  • https://tweakcn.com/r/themes/{id}

پیاده‌سازی باید هر دو شکل را به این مقدار نرمال‌سازی کند:

  • https://tweakcn.com/r/themes/{id}

سپس مرورگر مستقیما نقطه پایانی نرمال‌شده /r/themes/{id} را دریافت می‌کند.

برای محموله خارجی از یک اعتبارسنج طرح‌واره باریک استفاده کنید. طرح‌واره zod ترجیح داده می‌شود چون این یک مرز خارجی غیرقابل اعتماد است.

فیلدهای راه‌دور الزامی:

  • name در سطح بالا به عنوان رشته اختیاری
  • cssVars.theme به عنوان شیء اختیاری
  • cssVars.light به عنوان شیء
  • cssVars.dark به عنوان شیء

اگر هرکدام از cssVars.light یا cssVars.dark وجود نداشته باشد، واردسازی را رد کنید. این عمدی است: رفتار محصول تاییدشده پشتیبانی کامل از حالت‌ها است، نه ساختنِ بهترین تلاش برای سمتِ گمشده.

نگاشت توکن

متغیرهای tweakcn را کورکورانه بازتاب ندهید. یک زیرمجموعه محدود را به توکن‌های OpenClaw نرمال‌سازی کنید و باقی را در یک کمک‌کننده مشتق کنید.

توکن‌هایی که مستقیم وارد می‌شوند

از هر بلوک حالت tweakcn:

  • background
  • foreground
  • card
  • card-foreground
  • popover
  • popover-foreground
  • primary
  • primary-foreground
  • secondary
  • secondary-foreground
  • muted
  • muted-foreground
  • accent
  • accent-foreground
  • destructive
  • destructive-foreground
  • border
  • input
  • ring
  • radius

از cssVars.theme مشترک وقتی وجود داشته باشد:

  • font-sans
  • font-mono

اگر یک بلوک حالت font-sans، font-mono یا radius را بازنویسی کند، مقدار محلیِ حالت برنده است.

توکن‌های مشتق‌شده برای OpenClaw

واردکننده متغیرهای فقط 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

قواعد مشتق‌سازی در یک کمک‌کننده خالص قرار می‌گیرند تا بتوان آن‌ها را مستقل آزمود. فرمول‌های دقیق آمیختن رنگ جزئیات پیاده‌سازی هستند، اما کمک‌کننده باید دو قید را برآورده کند:

  • کنتراست خوانا را نزدیک به نیت قالب واردشده حفظ کند
  • برای همان محموله واردشده خروجی پایدار تولید کند

توکن‌هایی که در نسخه ۱ نادیده گرفته می‌شوند

این توکن‌های tweakcn در نسخه نخست عمدا نادیده گرفته می‌شوند:

  • chart-*
  • sidebar-*
  • font-serif
  • shadow-*
  • tracking-*
  • letter-spacing
  • spacing

این کار دامنه را روی توکن‌هایی نگه می‌دارد که رابط کاربری کنترل فعلی واقعا نیاز دارد.

فونت‌ها

رشته‌های پشته فونت، اگر وجود داشته باشند، وارد می‌شوند، اما OpenClaw در نسخه ۱ دارایی‌های فونت راه‌دور را بارگذاری نمی‌کند. اگر پشته واردشده به فونت‌هایی ارجاع دهد که در مرورگر در دسترس نیستند، رفتار عادی جایگزینی اعمال می‌شود.

رفتار شکست

واردسازی‌های نامعتبر باید بسته و امن شکست بخورند.

  • قالب URL نامعتبر: خطای اعتبارسنجی درون‌خطی نشان دهید، دریافت نکنید.
  • میزبان یا شکل مسیر پشتیبانی‌نشده: خطای اعتبارسنجی درون‌خطی نشان دهید، دریافت نکنید.
  • شکست شبکه، پاسخ غیر OK، یا JSON بدشکل: خطای درون‌خطی نشان دهید، محموله ذخیره‌شده فعلی را دست‌نخورده نگه دارید.
  • شکست طرح‌واره یا نبود بلوک‌های روشن/تیره: خطای درون‌خطی نشان دهید، محموله ذخیره‌شده فعلی را دست‌نخورده نگه دارید.
  • اقدام پاک‌سازی:
    • محموله سفارشی ذخیره‌شده را حذف می‌کند
    • محتوای تگ شیوه‌نامه سفارشی مدیریت‌شده را حذف می‌کند
    • اگر custom فعال باشد، خانواده قالب را به claw برمی‌گرداند
  • محموله سفارشی ذخیره‌شده نامعتبر در نخستین بارگذاری:
    • محموله ذخیره‌شده را نادیده بگیرید
    • CSS سفارشی منتشر نکنید
    • اگر خانواده قالب ماندگارشده custom بوده است، به claw برگردید

در هیچ نقطه‌ای نباید یک واردسازی شکست‌خورده سند فعال را با متغیرهای CSS سفارشی نیمه‌اعمال‌شده رها کند.

فایل‌هایی که انتظار می‌رود در پیاده‌سازی تغییر کنند

فایل‌های اصلی:

  • ui/src/ui/theme.ts
  • ui/src/ui/storage.ts
  • ui/src/ui/app-settings.ts
  • ui/src/ui/views/config.ts
  • ui/src/ui/views/config-quick.ts
  • ui/src/styles/base.css

کمک‌کننده‌های احتمالی جدید:

  • ui/src/ui/custom-theme.ts

آزمون‌ها:

  • ui/src/ui/app-settings.test.ts
  • ui/src/ui/storage.node.test.ts
  • ui/src/ui/views/config.browser.test.ts
  • آزمون‌های متمرکز جدید برای تجزیه URL و نرمال‌سازی محموله

آزمون

حداقل پوشش پیاده‌سازی:

  • تجزیه URL لینک اشتراک‌گذاری به شناسه قالب tweakcn
  • نرمال‌سازی /themes/{id} و /r/themes/{id} به URL دریافت
  • رد کردن میزبان‌های پشتیبانی‌نشده و شناسه‌های بدشکل
  • اعتبارسنجی شکل محموله tweakcn
  • نگاشت یک محموله معتبر tweakcn به نقشه‌های توکن روشن و تیره نرمال‌شده OpenClaw
  • بارگذاری و ذخیره محموله سفارشی در تنظیمات محلیِ مرورگر
  • حل کردن custom برای light، dark و system
  • غیرفعال کردن انتخاب Custom وقتی محموله‌ای وجود ندارد
  • اعمال فوری قالب واردشده وقتی custom از قبل فعال است
  • برگشت به claw وقتی قالب سفارشی فعال پاک می‌شود

هدف راستی‌آزمایی دستی:

  • یک قالب شناخته‌شده tweakcn را از تنظیمات وارد کنید
  • بین light، dark و system جابه‌جا شوید
  • بین custom و خانواده‌های داخلی جابه‌جا شوید
  • صفحه را دوباره بارگذاری کنید و تایید کنید قالب سفارشی واردشده به‌صورت محلی ماندگار می‌ماند

یادداشت‌های عرضه

این قابلیت عمدا کوچک است. اگر کاربران بعدا چند قالب واردشده، تغییر نام، صادر کردن، یا همگام‌سازی بین دستگاهی خواستند، آن را به عنوان طراحی پیگیری‌شونده در نظر بگیرید. در این پیاده‌سازی از قبل یک انتزاع کتابخانه قالب نسازید.