SLOPSHOPPER

claude-skins-th

ธีมไทย 5 แบบ: สลับโหมดมืด/สว่างของ Claude Code และวาดแถบสีธีมเหนือช่องพิมพ์

newbandcommand
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · claude-skins-th
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM › /skin ⎿ claude-skins-th: 🎨 ธีมไทยทั้งหมด (Mod 02) ⎿ claude-skins-th: ---------------------------------------- ⎿ claude-skins-th: 🇹🇭 สงกรานต์ /skin songkran ฟ้า-เหลืองทอง สดใส ⎿ claude-skins-th: 🌕 ลอยกระทง /skin loykrathong ดำ-ม่วง-ทอง ค่ำคืน ⎿ claude-skins-th: 👉 🌙 ดาร์กไทย /skin dark-thai ดาร์กสบายตา เขียวมิ้นท์ ⎿ claude-skins-th: 🤍 มินิมอล /skin minimal ขาวคลีน โฟกัสงาน 🌕 ลอยกระทง · ดำ-ม่วง-ทอง ค่ำคืน ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Band
🌕 ลอยกระทง · ดำ-ม่วง-ทอง ค่ำคืน
README

Mod 02: Claude Skins TH

ธีมไทย 5 แบบ: 🇹🇭 สงกรานต์, 🌕 ลอยกระทง, 🌙 ดาร์กไทย (ค่าเริ่มต้น), 🤍 มินิมอล, 🛍️ ตลาดนัด เลือกแล้วจะสลับธีมหลักของ Claude Code เป็นโหมดมืดหรือสว่างตามธีม และวาดแถบสีของธีมไว้เหนือช่องพิมพ์ ธีมที่เลือกจะจำไว้ข้าม session

คำสั่ง

คำสั่งทำอะไร
/skinดูรายการธีม
/skin loykrathongเปลี่ยนธีม
/skin offซ่อนแถบธีม
/skin-randomสุ่มธีม

ติดตั้ง

/plugin install claude-skins-th --marketplace tksoft11/claude-code-mods-th

ต้องตั้ง CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 ก่อนเปิด claude (ดู README หลัก)

โค้ดสอนอะไร

เปิด hooks/register.tsx แล้วอ่านตามบทที่เขียนไว้ในคอมเมนต์:

  1. นิยามธีมเป็น object
  2. เปลี่ยนการตั้งค่าของ Claude Code ด้วย $.config.set และรับมือกับ { deny }
  3. จำค่าข้าม session ด้วย $.store
  4. คำสั่งที่มี argument (e.args)
  5. ใช้สี hex กับ <Text color>

หมายเหตุ

Mod ไม่มี DOM จึงเปลี่ยนสีทุกส่วนของหน้าจอไม่ได้ สิ่งที่ Mod คุมได้คือธีมหลัก (มืด/สว่าง) และสีของสิ่งที่ Mod วาดเอง ถ้าองค์กรล็อกการตั้งค่าธีมไว้ จะขึ้นคำเตือนแทน

Source 1 files
hooks/register.tsx 147 lines
1/**
2 * ============================================================================
3 * MOD 02: Claude Skins TH - ธีมไทย 5 แบบ (ฉบับสอนทำ)
4 * ============================================================================
5 * แรงบันดาลใจจาก: https://github.com/hellosverre/claude-skins
6 *
7 * หน้าที่ของ Mod นี้:
8 * 1. มีธีมไทย 5 แบบ: สงกรานต์, ลอยกระทง, ดาร์กไทย, มินิมอล, ตลาดนัด
9 * 2. เปลี่ยนธีมของ Claude Code (มืด/สว่าง) ผ่าน $.config.set("theme")
10 * 3. วาดแถบสีของธีมเหนือช่องพิมพ์ ด้วยสี hex ของธีมนั้น
11 * 4. จำธีมที่เลือกไว้ข้าม session ด้วย $.store
12 *
13 * หมายเหตุ: Mod ไม่มี DOM จึง inject CSS ไม่ได้ สีที่ Mod คุมได้คือ
14 * สีของ element ที่ Mod วาดเอง (Text color="#hex") + ธีมหลักของ Claude Code
15 */
16
17import type { EngineInterface, Register } from 'claude-code'
18
19// ==========================================================================
20// บทที่ 1: นิยามธีมเป็น Object - แก้ตรงนี้เพื่อสร้างธีมของคุณเอง
21// ==========================================================================
22type Skin = {
23  name: string
24  base: 'dark' | 'light' // ธีมหลักของ Claude Code ที่จะสลับไป
25  accent: string // สีหลัก (hex)
26  soft: string // สีรอง (hex)
27  tagline: string
28}
29
30const SKINS: Record<string, Skin> = {
31  songkran: { name: '🇹🇭 สงกรานต์', base: 'light', accent: '#0288d1', soft: '#ffb300', tagline: 'ฟ้า-เหลืองทอง สดใส' },
32  loykrathong: { name: '🌕 ลอยกระทง', base: 'dark', accent: '#ffd54f', soft: '#9575cd', tagline: 'ดำ-ม่วง-ทอง ค่ำคืน' },
33  'dark-thai': { name: '🌙 ดาร์กไทย', base: 'dark', accent: '#4db6ac', soft: '#80cbc4', tagline: 'ดาร์กสบายตา เขียวมิ้นท์' },
34  minimal: { name: '🤍 มินิมอล', base: 'light', accent: '#424242', soft: '#9e9e9e', tagline: 'ขาวคลีน โฟกัสงาน' },
35  taladnat: { name: '🛍️ ตลาดนัด', base: 'dark', accent: '#ff1744', soft: '#ffea00', tagline: 'สีจัดจ้านแบบป้ายตลาด' },
36}
37
38const DEFAULT_SKIN = 'dark-thai'
39const STORE_KEY = 'skin' // key ใน $.store (เก็บข้าม session)
40
41let currentSkin = DEFAULT_SKIN // id ของธีมที่เลือกอยู่ ("" = ซ่อนแถบธีม)
42
43// เปลี่ยนธีมที่แสดงแล้วสั่งให้แถบวาดใหม่
44function setSkin($: EngineInterface, id: string): void {
45  currentSkin = id
46  $.ui.invalidate('ui.render')
47}
48
49// ==========================================================================
50// บทที่ 2: เปลี่ยนธีมหลักของ Claude Code
51// ==========================================================================
52// $.config.set ทำเหมือนผู้ใช้เปลี่ยนใน /config เอง อาจได้ { deny } กลับมา
53// (เช่น องค์กรล็อกค่าไว้) จึงต้องเช็คก่อนบอกว่าสำเร็จ
54async function applyBaseTheme($: EngineInterface, base: 'dark' | 'light'): Promise<string> {
55  const row = (await $.config.list()).find(r => r.key === 'theme')
56  if (!row) return 'ไม่พบการตั้งค่า theme ใน /config'
57  if (row.value === base) return ''
58  if (row.options && !row.options.includes(base)) return `ธีม "${base}" ไม่มีใน /config`
59
60  const result = await $.config.set({ key: 'theme', value: base })
61  return 'deny' in result && result.deny ? `เปลี่ยนธีมหลักไม่ได้: ${result.deny}` : ''
62}
63
64// เลือกธีม: เปลี่ยนแถบ + เก็บใน $.store (จำข้าม session)
65async function chooseSkin($: EngineInterface, id: string): Promise<string> {
66  const skin = SKINS[id]
67  if (!skin) return `❌ ไม่มีธีม "${id}" ลองพิมพ์ /skin เพื่อดูรายการ`
68
69  setSkin($, id)
70  await $.store.set(STORE_KEY, id)
71  const warning = await applyBaseTheme($, skin.base)
72
73  return `🎨 เปลี่ยนเป็นธีม ${skin.name} (${skin.tagline})${warning ? `\n⚠️ ${warning}` : ''}`
74}
75
76function listSkins(current: string): string {
77  const lines = Object.entries(SKINS).map(
78    ([id, s]) => `${id === current ? '👉' : '  '} ${s.name.padEnd(14)} /skin ${id.padEnd(12)} ${s.tagline}`,
79  )
80  return ['🎨 ธีมไทยทั้งหมด (Mod 02)', '----------------------------------------', ...lines, '', '/skin off = ซ่อนแถบธีม | /skin-random = สุ่มธีม'].join('\n')
81}
82
83export const register: Register = on => {
84  // ==========================================================================
85  // บทที่ 3: session.start - โหลดธีมที่เคยเลือก + ลงทะเบียนคำสั่ง
86  // ==========================================================================
87  on('session.start', async ($, e, next) => {
88    const saved = await $.store.get(STORE_KEY)
89    const id = typeof saved === 'string' && (saved === '' || SKINS[saved]) ? saved : DEFAULT_SKIN
90    setSkin($, id)
91
92    await $.command.register({ name: 'skin', description: 'เปลี่ยนธีมไทย (ไม่ใส่ชื่อ = ดูรายการ)', argumentHint: '[ชื่อธีม|off]' })
93    await $.command.register({ name: 'skin-random', description: 'สุ่มธีมไทย' })
94
95    return next(e)
96  })
97
98  // ==========================================================================
99  // บทที่ 4: คำสั่งแบบมี argument - /skin loykrathong
100  // ==========================================================================
101  on('command.run', { command: 'skin' }, async ($, e) => {
102    const arg = e.args.trim().toLowerCase() // e.args = ข้อความหลังชื่อคำสั่ง
103    if (arg === '' || arg === 'list') return { text: listSkins(currentSkin) }
104    if (arg === 'off') {
105      setSkin($, '')
106      await $.store.set(STORE_KEY, '')
107      return { text: '🙈 ซ่อนแถบธีมแล้ว (/skin <ชื่อ> เพื่อเปิดอีกครั้ง)' }
108    }
109    return { text: await chooseSkin($, arg) }
110  })
111
112  on('command.run', { command: 'skin-random' }, async $ => {
113    const ids = Object.keys(SKINS)
114    const id = ids[Math.floor(Math.random() * ids.length)] ?? DEFAULT_SKIN
115    return { text: `🎲 สุ่มได้...\n${await chooseSkin($, id)}` }
116  })
117
118  // ==========================================================================
119  // บทที่ 5: วาดแถบธีมเหนือช่องพิมพ์ด้วยสี hex ของธีม
120  // ==========================================================================
121  on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
122    const skin = currentSkin ? SKINS[currentSkin] : undefined
123    if (e.props.hasSurvey || !skin) return next(e)
124
125    const { Box, Text } = $.ui.resolve(e)
126    return (
127      <Box>
128        <Text color={skin.accent} bold>
129          {skin.name}
130        </Text>
131        <Text color={skin.soft}> · {skin.tagline}</Text>
132      </Box>
133    )
134  })
135}
136
137/**
138 * ========================================================================
139 * การบ้าน / ต่อยอด
140 * ========================================================================
141 * 1. สร้างธีมของคุณเอง: ก็อป 'dark-thai' ใน SKINS แล้วตั้งชื่อใหม่ เช่น 'my-brand'
142 *    เปลี่ยน accent/soft เป็นสีแบรนด์ (แดงธงชาติ #ed1c24, น้ำเงิน #241d4f, ทอง #ffd700)
143 *    บันทึกไฟล์ แล้ว /reload-plugins และ /skin my-brand
144 * 2. เปลี่ยนธีมอัตโนมัติตามเวลา: กลางวันใช้ธีมสว่าง กลางคืนใช้ธีมมืด ด้วย $.clock.every
145 * 3. แสดงแถบธีมเฉพาะตอนเริ่ม session แล้วซ่อนเองหลัง 1 นาที ด้วย $.clock.after
146 */
147