@hotelfriendag/design-tokens 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +558 -0
- package/README.uk.md +377 -0
- package/RFC-0001-cross-project-design-system.md +273 -0
- package/RFC-0002-semantic-tier-naming.md +296 -0
- package/UI_DESIGN.md +608 -0
- package/ai-rules/CLAUDE.md +80 -0
- package/ai-rules/cursorrules.template +39 -0
- package/ai-rules/github-copilot-instructions.md +45 -0
- package/ai-rules/system-prompt-compact.md +43 -0
- package/components.html +3018 -0
- package/generate-tokens.cjs +665 -0
- package/package.json +98 -0
- package/portal-audit.html +2306 -0
- package/pre-built/_tokens.scss +138 -0
- package/pre-built/components.css +515 -0
- package/pre-built/shadcn-tokens.css +67 -0
- package/pre-built/status.css +51 -0
- package/pre-built/stylelint-design-system.cjs +69 -0
- package/pre-built/tailwind.additive.css +158 -0
- package/pre-built/tailwind.css +158 -0
- package/pre-built/tailwind.preset.js +207 -0
- package/pre-built/tokens.css +185 -0
- package/pre-built/tokens.d.ts +240 -0
- package/pre-built/tokens.js +243 -0
- package/pre-built/tokens.ts +240 -0
- package/scripts/integration-smoke.sh +91 -0
- package/scripts/pre-commit.sh +55 -0
- package/scripts/validate-tokens.cjs +113 -0
- package/states-canonical.json +240 -0
- package/states.json +2950 -0
- package/status-map.json +47 -0
- package/tokens.figma.json +230 -0
package/README.uk.md
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# HotelFriend Design System
|
|
2
|
+
|
|
3
|
+
Спільна дизайн-основа для всіх проєктів: токени, згенеровані файли під кожен стек (CSS / SCSS / TS / Tailwind v3 + v4 / shadcn), шар компонентів `.hf-*` та правила для AI-інструментів.
|
|
4
|
+
|
|
5
|
+
> **Виокремлено 2026-05-25** із [`hotelfriend/backend-hf`](https://bitbucket.org/hotelfriend/backend-hf) (`docs/portable-design/`), щоб цей репозиторій став єдиним джерелом істини для решти проєктів HotelFriend.
|
|
6
|
+
>
|
|
7
|
+
> **Статус:** RFC-0001 Фаза 1 завершена (семантична трирівнева модель + префіксація без колізій + CI-гейт на дрейф). Наступний крок — версійований npm-пакет (`@hotelfriend/design-tokens` через GitHub Packages). Повний чек-лист — у `RFC-0001-cross-project-design-system.md` §9.
|
|
8
|
+
|
|
9
|
+
## Ієрархія файлів (читати в цьому порядку)
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
portable-design/
|
|
13
|
+
│
|
|
14
|
+
├── components.html ← ОСНОВНЕ · канонічний візуальний референс (відкрити у браузері)
|
|
15
|
+
├── UI_DESIGN.md ← НАРАТИВ · обґрунтування, анатомія, рішення (AI читає це першим)
|
|
16
|
+
├── tokens.figma.json ← ТОКЕНИ · атомарний експорт Tokens Studio → живить Figma + генератори
|
|
17
|
+
│
|
|
18
|
+
├── pre-built/ ← ЗГЕНЕРОВАНІ · підставляєте у свій білд-пайплайн
|
|
19
|
+
│ ├── tailwind.css · Tailwind v4 @theme-блок (рекомендовано)
|
|
20
|
+
│ ├── tailwind.preset.js · Tailwind v3 preset (легасі)
|
|
21
|
+
│ ├── tokens.css · звичайні CSS custom properties
|
|
22
|
+
│ ├── _tokens.scss · SCSS-змінні
|
|
23
|
+
│ ├── tokens.ts · TypeScript const
|
|
24
|
+
│ ├── shadcn-tokens.css · контракт shadcn/ui
|
|
25
|
+
│ └── components.css · примітиви `.hf-*` (витяг із components.html)
|
|
26
|
+
│
|
|
27
|
+
├── states-canonical.json ← курований набір інтерактивних станів (використовуйте цей)
|
|
28
|
+
├── states.json ← сирий експорт із порталу (160 КБ — краще брати states-canonical.json)
|
|
29
|
+
├── generate-tokens.cjs ← Node-скрипт (без залежностей) — перетворює токени на Tailwind/CSS/SCSS/TS/shadcn
|
|
30
|
+
│
|
|
31
|
+
├── ai-rules/ ← покладіть ОДИН файл у корінь нового проєкту
|
|
32
|
+
│ ├── CLAUDE.md · для Claude Code (підхоплюється автоматично)
|
|
33
|
+
│ ├── cursorrules.template · перейменуйте на .cursorrules
|
|
34
|
+
│ ├── github-copilot-instructions.md · покласти в .github/copilot-instructions.md
|
|
35
|
+
│ └── system-prompt-compact.md · компактний промпт для ChatGPT/v0/Lovable
|
|
36
|
+
│
|
|
37
|
+
├── portal-audit.html ← АРХІВ · знімок аудиту старого порталу (НЕ для нового коду)
|
|
38
|
+
└── README.md ← ви тут (швидкий старт)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Правило пріоритету — коли файли суперечать одне одному
|
|
42
|
+
|
|
43
|
+
1. **`components.html`** — канон для **візуальних рішень** (кольори, розміри, анатомія)
|
|
44
|
+
2. **`tokens.figma.json`** — канон для **значень токенів**. Після редагування — перегенеруйте `pre-built/*`
|
|
45
|
+
3. **`UI_DESIGN.md`** — канон для **ЧОМУ було прийнято рішення** (історія, компроміси, нотатки про дрейф порталу)
|
|
46
|
+
4. **`pre-built/*`** — **згенеровані**, руками не правити. Після зміни JSON запускайте `generate-tokens.cjs`
|
|
47
|
+
5. **`portal-audit.html`** — **тільки архів**. Показує поточний вигляд легасі-порталу — корисно для трекінгу міграції, НЕ для нового UI
|
|
48
|
+
|
|
49
|
+
Якщо `components.html` і `UI_DESIGN.md` суперечать одне одному — **виграє `components.html`**, а `UI_DESIGN.md` вважається застарілим.
|
|
50
|
+
|
|
51
|
+
## Швидкий старт за 60 секунд
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# 1. Скопіювати цю папку у новий проєкт (куди завгодно; рекомендуємо docs/)
|
|
55
|
+
cp -r /path/to/portable-design ../new-project/docs/
|
|
56
|
+
|
|
57
|
+
# 2. Підключити CSS у білд (оберіть ОДНЕ)
|
|
58
|
+
# Tailwind v4: @import pre-built/tailwind.css
|
|
59
|
+
# Vanilla CSS: підключити tokens.css + components.css
|
|
60
|
+
# SCSS: @import _tokens.scss
|
|
61
|
+
|
|
62
|
+
# 3. Підключити AI до правил системи (оберіть ОДНЕ)
|
|
63
|
+
cp docs/portable-design/ai-rules/CLAUDE.md ../../CLAUDE.md # Claude Code
|
|
64
|
+
cp docs/portable-design/ai-rules/cursorrules.template ../../.cursorrules
|
|
65
|
+
mkdir -p ../../.github && cp docs/portable-design/ai-rules/github-copilot-instructions.md ../../.github/copilot-instructions.md
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## ⚠️ Інтеграція у наявний проєкт
|
|
69
|
+
|
|
70
|
+
> **Статус:** ✅ Вирішено у Фазі 1A (RFC-0001 §4.2). Усі згенеровані токени мають префікс `hf-` ВСЕРЕДИНІ категорії (`--color-hf-*`, `--text-hf-*`, `--radius-hf-*`, `--spacing-hf-*`, `--font-hf-*`, `--shadow-hf-*`). Жоден не може зіткнутися з дефолтами Tailwind v4. Повний `@import` у наявному проєкті — безпечний.
|
|
71
|
+
|
|
72
|
+
**Рекомендована конфігурація для будь-якого проєкту (новий чи наявний):**
|
|
73
|
+
|
|
74
|
+
```css
|
|
75
|
+
/* app/globals.css */
|
|
76
|
+
@import "tailwindcss";
|
|
77
|
+
@import "./docs/portable-design/pre-built/tailwind.css"; /* @theme — додає --color-hf-*, --text-hf-* тощо */
|
|
78
|
+
@import "./docs/portable-design/pre-built/components.css"; /* примітиви .hf-* */
|
|
79
|
+
|
|
80
|
+
/* Опційно: виключити демо-HTML із пакета зі сканування Tailwind,
|
|
81
|
+
щоб легасі-класи / bg-[#hex] із showcase не потрапили у ваш бандл. */
|
|
82
|
+
@source not "./docs/portable-design/components.html";
|
|
83
|
+
@source not "./docs/portable-design/portal-audit.html";
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Що ви отримуєте:
|
|
87
|
+
|
|
88
|
+
- `bg-hf-accent` (= `#24AFE8` — бренд) — `bg-blue-500` із Tailwind лишається дефолтним
|
|
89
|
+
- `text-hf-base` (= 14px — основний текст) — `text-base` із Tailwind лишається 16px
|
|
90
|
+
- `rounded-hf-sm` (= 6px) — `rounded-sm` із Tailwind лишається 2px
|
|
91
|
+
- `shadow-hf-modal` (= тінь модалки порталу)
|
|
92
|
+
- … тощо. Ваші наявні утиліти **не змінюються**.
|
|
93
|
+
|
|
94
|
+
**Для проєктів, чиї інтеграційні скрипти просять "additive"-таргет за назвою**, `--target=tailwind-v4-additive` — явний alias для `--target=tailwind-v4`. Вихідний файл ідентичний — префікс зробив additive-фільтр непотрібним.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
node generate-tokens.cjs --target=tailwind-v4-additive > pre-built/tailwind.additive.css
|
|
98
|
+
# (байт-у-байт як --target=tailwind-v4)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Сніпети під конкретні стеки
|
|
102
|
+
|
|
103
|
+
### React + Tailwind v4 (рекомендовано, новий проєкт)
|
|
104
|
+
|
|
105
|
+
```css
|
|
106
|
+
/* app/globals.css */
|
|
107
|
+
@import "tailwindcss";
|
|
108
|
+
@import "./docs/portable-design/pre-built/tailwind.css"; /* @theme токени */
|
|
109
|
+
@import "./docs/portable-design/pre-built/components.css"; /* примітиви .hf-* */
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```jsx
|
|
113
|
+
<button className="bg-hf-primary hover:bg-hf-primary-hover text-white h-10 px-5 rounded-hf text-hf-md font-semibold">
|
|
114
|
+
Зберегти
|
|
115
|
+
</button>
|
|
116
|
+
<span className="hf-pill status-booking-confirmed">Підтверджено</span>
|
|
117
|
+
<div className="hf-modal max-w-[500px]">
|
|
118
|
+
<div className="hf-modal__header">
|
|
119
|
+
<h2 className="hf-modal__title">Редагувати гостя</h2>
|
|
120
|
+
<button className="hf-modal__close">✕</button>
|
|
121
|
+
</div>
|
|
122
|
+
<div className="hf-modal__body">…</div>
|
|
123
|
+
<div className="hf-modal__footer"><button>Скасувати</button><button>Зберегти</button></div>
|
|
124
|
+
</div>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### React + Tailwind v3 (легасі)
|
|
128
|
+
|
|
129
|
+
```js
|
|
130
|
+
// tailwind.config.js
|
|
131
|
+
const hfPreset = require('./docs/portable-design/pre-built/tailwind.preset.js');
|
|
132
|
+
module.exports = {
|
|
133
|
+
presets: [hfPreset],
|
|
134
|
+
content: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```html
|
|
139
|
+
<link rel="stylesheet" href="docs/portable-design/pre-built/components.css">
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Next.js + shadcn/ui
|
|
143
|
+
|
|
144
|
+
Допишіть `pre-built/shadcn-tokens.css` у `app/globals.css`. Компоненти shadcn автоматично підхоплять `--primary`, `--background`, `--ring` тощо.
|
|
145
|
+
|
|
146
|
+
### Vue 3 / Nuxt
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
// nuxt.config.ts
|
|
150
|
+
export default defineNuxtConfig({
|
|
151
|
+
css: [
|
|
152
|
+
'~/docs/portable-design/pre-built/tokens.css',
|
|
153
|
+
'~/docs/portable-design/pre-built/components.css',
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
У шаблонах використовуйте `var(--color-hf-accent)`, `var(--font-size-hf-base)` або `.hf-modal` / `.hf-pill .status-booking-confirmed`.
|
|
159
|
+
|
|
160
|
+
### SCSS-стек (Yii / Laravel / WP)
|
|
161
|
+
|
|
162
|
+
```scss
|
|
163
|
+
// _app.scss
|
|
164
|
+
@import 'docs/portable-design/pre-built/tokens';
|
|
165
|
+
@import 'docs/portable-design/pre-built/components.css';
|
|
166
|
+
|
|
167
|
+
.my-btn {
|
|
168
|
+
background: $colorPrimaryDefault;
|
|
169
|
+
height: $sizeBtnDefault;
|
|
170
|
+
border-radius: $borderRadiusSm;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### TS / CSS-in-JS
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import { tokens } from './docs/portable-design/pre-built/tokens';
|
|
178
|
+
|
|
179
|
+
const Button = styled.button`
|
|
180
|
+
background: ${tokens.color.primary.default};
|
|
181
|
+
height: ${tokens.size.btnDefault};
|
|
182
|
+
border-radius: ${tokens.borderRadius.sm};
|
|
183
|
+
`;
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Ванільний / статичний HTML
|
|
187
|
+
|
|
188
|
+
```html
|
|
189
|
+
<link rel="stylesheet" href="docs/portable-design/pre-built/tokens.css">
|
|
190
|
+
<link rel="stylesheet" href="docs/portable-design/pre-built/components.css">
|
|
191
|
+
|
|
192
|
+
<span class="hf-pill status-booking-confirmed">Підтверджено</span>
|
|
193
|
+
<button class="hf-modal__close">✕</button>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Примітиви компонентів у `components.css`
|
|
197
|
+
|
|
198
|
+
| Клас | Анатомія | Дивись |
|
|
199
|
+
|---|---|---|
|
|
200
|
+
| `.hf-pill` + `.status-{domain}-{state}` | Статус-бейдж — радіус 6px, фон 15% + текст 100% + рамка 1px | components.html#status |
|
|
201
|
+
| `.hf-tab` / `.hf-tab--sm` / `.hf-pill-tabs` | Таби з підкресленням та сегментовані | components.html#tabs |
|
|
202
|
+
| `.hf-pagination` + `__item` / `__ellipsis` | Активний — стриманий сірий (НЕ primary!) — 34×34, радіус 8px | components.html#pagination |
|
|
203
|
+
| `.hf-modal` + `__header/__title/__body/__footer/__close` | Радіус 6px, у футера немає верхньої рамки | components.html#modal |
|
|
204
|
+
| `.hf-alert` + `--success/--info/--warn/--error` | Білий фон + 3px акцентна смуга зверху + квадратна іконка 26×26 | components.html#alerts |
|
|
205
|
+
| `.hf-alert--tinted` / `--banner` / `--compact` | Модифікатори — тонований фон / на всю ширину / компактний у картці | components.html#alerts |
|
|
206
|
+
| `.hf-toast` | Плаваюче сповіщення (правий нижній кут) — радіус 9px | components.html#alerts |
|
|
207
|
+
| `.hf-check` / `.hf-radio` | Кастомні чекбокс та радіо — 18×18, активний — заливка primary | components.html#inputs |
|
|
208
|
+
| `.hf-dropdown-menu` + `__item / __header / __shortcut / __icon / __divider` | Дропдаун з радіусом 9px та тінню `0 1px 10px rgba(0,0,0,.1)` | components.html#dropdown |
|
|
209
|
+
| `.skeleton` + `.hf-spin` | Примітиви станів завантаження (шимер + обертання) | components.html#empty |
|
|
210
|
+
|
|
211
|
+
## Як цим користується AI
|
|
212
|
+
|
|
213
|
+
Після того як ви поклали один із файлів `ai-rules/*` у корінь нового проєкту:
|
|
214
|
+
|
|
215
|
+
1. **Claude Code / Cursor / Copilot** автоматично додають його до кожного чату. Агент знає:
|
|
216
|
+
- канонічну палітру (primary `#24AFE8`, кольори статусів, нейтральні)
|
|
217
|
+
- типографіку (Roboto, розміри 11/13/14/15/16/18/20/22/26/30, ваги 400/500/600)
|
|
218
|
+
- шкалу відступів (кратно 4)
|
|
219
|
+
- шкалу радіусів (6/8/9/12/99)
|
|
220
|
+
- набір тіней (default/subtle/wrapper/card/modal/outline/hover)
|
|
221
|
+
- бібліотеку компонентів (`.hf-modal`, `.hf-alert`, `.hf-pill`, `.hf-tab`, `.hf-pagination`, `.hf-check`, `.hf-dropdown-menu` тощо)
|
|
222
|
+
- жорсткі правила ("ніколи не зашивати hex", "завжди робити hover/focus/disabled", "не мішати іконкові набори")
|
|
223
|
+
|
|
224
|
+
2. **Візуальний референс для нових проєктів:** відкрийте `components.html` у браузері — це канон, де відрендерені всі патерни `.hf-*`.
|
|
225
|
+
|
|
226
|
+
3. **Для чат-AI** (ChatGPT, v0, Lovable): вставте `ai-rules/system-prompt-compact.md` або JSON-довідник токенів із `UI_DESIGN.md` §9 як system prompt перед запитом UI-завдання.
|
|
227
|
+
|
|
228
|
+
## Оновлення згенерованих файлів
|
|
229
|
+
|
|
230
|
+
Коли змінюється `tokens.figma.json`, перегенеруйте:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
cd docs/portable-design
|
|
234
|
+
node generate-tokens.cjs --target=tailwind-v4 > pre-built/tailwind.css # v4 (рекомендовано)
|
|
235
|
+
node generate-tokens.cjs --target=tailwind > pre-built/tailwind.preset.js # v3 (легасі)
|
|
236
|
+
node generate-tokens.cjs --target=css > pre-built/tokens.css
|
|
237
|
+
node generate-tokens.cjs --target=scss > pre-built/_tokens.scss
|
|
238
|
+
node generate-tokens.cjs --target=ts > pre-built/tokens.ts
|
|
239
|
+
node generate-tokens.cjs --target=shadcn > pre-built/shadcn-tokens.css
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
> `pre-built/components.css` поки **не генерується** — він вручну витягнутий із `components.html`. Якщо ви змінюєте блок `<style type="text/tailwindcss">` / `@layer components` у `components.html`, синхронізуйте витягнутий файл вручну. Заголовок `pre-built/components.css` містить координати джерела.
|
|
243
|
+
|
|
244
|
+
Або вбудуйте регенерацію в `package.json`:
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"scripts": {
|
|
249
|
+
"tokens:build:v4": "node docs/portable-design/generate-tokens.cjs --target=tailwind-v4 > tailwind.css",
|
|
250
|
+
"tokens:build:v3": "node docs/portable-design/generate-tokens.cjs --target=tailwind > tailwind.preset.js",
|
|
251
|
+
"prebuild": "npm run tokens:build:v3 && npm run tokens:build:v4"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Чек-ліст валідації
|
|
257
|
+
|
|
258
|
+
Після перенесення у новий проєкт перевірте:
|
|
259
|
+
|
|
260
|
+
- [ ] `cat CLAUDE.md` (або `.cursorrules`) показує правила дизайн-системи.
|
|
261
|
+
- [ ] `node docs/portable-design/generate-tokens.cjs --target=css` відпрацьовує чисто і дає стабільний вивід.
|
|
262
|
+
- [ ] AI-агент на питання "який primary color?" відповідає `#24AFE8`.
|
|
263
|
+
- [ ] Перша згенерована AI кнопка відповідає `.btn-primary` (40px / 15px / 600 / `#24AFE8` / радіус 6px).
|
|
264
|
+
- [ ] Бейджі статусів резолвляться через токени `--status-{domain}-{state}-color`.
|
|
265
|
+
- [ ] `.hf-modal`, `.hf-alert`, `.hf-pagination` рендеряться коректно, коли підвантажений `pre-built/components.css`.
|
|
266
|
+
|
|
267
|
+
## Що НЕ переноситься
|
|
268
|
+
|
|
269
|
+
Ці файли у батьківському `docs/` — **специфічні для порталу HotelFriend** (легасі-аудит / детект дрейфу), копіювати їх НЕ треба:
|
|
270
|
+
|
|
271
|
+
- `docs/migration-plan.md` — черга прибирання старого SCSS (тільки портал на Yii)
|
|
272
|
+
- `docs/design-tokens-audit.md` — звіт про дрейф
|
|
273
|
+
- `docs/ui-elements-catalog.*` — спостережені компоненти у порталі
|
|
274
|
+
- `docs/icon-audit.*` — карта міграції FA→Lucide
|
|
275
|
+
- `docs/component-anatomy.json` — обміри легасі-модалок
|
|
276
|
+
- `scratch/` — Playwright-воркери, що сканують портал
|
|
277
|
+
|
|
278
|
+
Вони лежать у вихідному репо для господарських потреб; новому проєкту вони не потрібні.
|
|
279
|
+
|
|
280
|
+
`portal-audit.html` всередині цього пакета — єдиний легасі-артефакт, що подорожує разом із portable-папкою — залиште його як історичний референс і для трекінгу міграції. Новий код **ніколи** не повинен копіювати патерни з `portal-audit.html`.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Детект дрейфу та інтеграція з CI
|
|
285
|
+
|
|
286
|
+
### Pre-commit hook (рекомендовано для будь-якого проєкту, що чіпає цей пакет)
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
# З husky (рекомендовано)
|
|
290
|
+
pnpm add -D husky
|
|
291
|
+
pnpm husky init
|
|
292
|
+
cp docs/portable-design/scripts/pre-commit.sh .husky/pre-commit
|
|
293
|
+
chmod +x .husky/pre-commit
|
|
294
|
+
|
|
295
|
+
# Без husky (сирий git-hook)
|
|
296
|
+
cp docs/portable-design/scripts/pre-commit.sh .git/hooks/pre-commit
|
|
297
|
+
chmod +x .git/hooks/pre-commit
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Хук запускає `validate-tokens.cjs`, коли в staging є будь-які файли з tokens / pre-built / docs / components.html. Падає на дрейфі. Мовчить на успіху.
|
|
301
|
+
|
|
302
|
+
### Конфіг Stylelint (рекомендовано для проєктів-споживачів)
|
|
303
|
+
|
|
304
|
+
Сумісний Stylelint-конфіг, який забороняє сирий hex / іменовані кольори / літеральні `box-shadow`:
|
|
305
|
+
|
|
306
|
+
```js
|
|
307
|
+
// .stylelintrc.cjs
|
|
308
|
+
module.exports = {
|
|
309
|
+
extends: [
|
|
310
|
+
'stylelint-config-standard',
|
|
311
|
+
'./node_modules/@hotelfriend/design-tokens/pre-built/stylelint-design-system.cjs'
|
|
312
|
+
// — або, якщо підключено через копіювання папки:
|
|
313
|
+
// './docs/portable-design/pre-built/stylelint-design-system.cjs'
|
|
314
|
+
],
|
|
315
|
+
overrides: [
|
|
316
|
+
// У згенерованих файлах hex допустимий (fallback-и, примітиви) — opt-out
|
|
317
|
+
{ files: ['**/pre-built/*.css'], rules: { 'color-no-hex': null } },
|
|
318
|
+
],
|
|
319
|
+
};
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Самостійний валідатор (одноразова перевірка у CI)
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
cd docs/portable-design
|
|
326
|
+
node scripts/validate-tokens.cjs
|
|
327
|
+
# ✓ validate-tokens: all checks passed
|
|
328
|
+
# 168 CSS variables defined, all var() refs resolve, no bare hex.
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Використовуйте у CI поруч із лінтом та тестами. Виходить із ненульовим кодом, якщо:
|
|
332
|
+
1. `var(--*)` посилається на CSS-змінну, яка ніде не визначена
|
|
333
|
+
2. У `components.css` / `status.css` є сирий hex (поза коментарями та fallback-ами `var()`; `#fff`/`#000` дозволені)
|
|
334
|
+
3. У код-блоці документації згадано токен, якого нема в `pre-built/*`
|
|
335
|
+
|
|
336
|
+
## NPM-пакет (приватний реєстр)
|
|
337
|
+
|
|
338
|
+
Пакет публікується як `@hotelfriend/design-tokens` у приватний реєстр GitHub Packages:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
# У проєкті-споживачі:
|
|
342
|
+
echo "@hotelfriend:registry=https://npm.pkg.github.com" >> .npmrc
|
|
343
|
+
pnpm add @hotelfriend/design-tokens
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Імпорт під свій стек:
|
|
347
|
+
|
|
348
|
+
```css
|
|
349
|
+
/* CSS / Tailwind v4 */
|
|
350
|
+
@import "@hotelfriend/design-tokens/tailwind.css";
|
|
351
|
+
@import "@hotelfriend/design-tokens/components.css";
|
|
352
|
+
@import "@hotelfriend/design-tokens/status.css";
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
// TypeScript
|
|
357
|
+
import { tokens } from '@hotelfriend/design-tokens/tokens.ts';
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
```scss
|
|
361
|
+
// SCSS
|
|
362
|
+
@import '@hotelfriend/design-tokens/_tokens';
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Публікація (для мейнтейнера)
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
cd docs/portable-design
|
|
369
|
+
pnpm version patch # або minor / major
|
|
370
|
+
pnpm publish # запускає prepublishOnly → build + validate
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
`prepublishOnly` перезбирає та валідує, тож опублікований пакет завжди узгоджений.
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
Зібрано на основі HotelFriend Design System v0.1.0 — JSON-довідник токенів див. у `UI_DESIGN.md` §9, канонічний візуальний референс — у `components.html`. Англомовна версія цього файлу — [`README.md`](README.md), повний журнал фаз і змін — там же.
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# RFC-0001 — Evolving the HotelFriend Design System into a cross-project foundation
|
|
2
|
+
|
|
3
|
+
> **Status:** Draft / proposal
|
|
4
|
+
> **Author:** (fill in)
|
|
5
|
+
> **Created:** 2026-05-20
|
|
6
|
+
> **Reviewed against:** `portable-design_v2` (2026-05-21) — see §2.1
|
|
7
|
+
> **Scope:** `docs/portable-design` bundle (tokens + generator + docs + AI rules)
|
|
8
|
+
> **Supersedes:** nothing yet — first RFC for this bundle.
|
|
9
|
+
|
|
10
|
+
## 1. Goal
|
|
11
|
+
|
|
12
|
+
Make this design system usable as **one shared foundation for both new (greenfield) and
|
|
13
|
+
existing projects**, so that several HotelFriend codebases (e.g. the Vue 3 / Tailwind v4
|
|
14
|
+
`ui-hf` portal and the legacy Yii / SCSS portal) render with the **same visual design** and
|
|
15
|
+
can be **updated from a single source of truth**.
|
|
16
|
+
|
|
17
|
+
### Non-goals (for this RFC)
|
|
18
|
+
|
|
19
|
+
- Rewriting the actual portal UI.
|
|
20
|
+
- Picking a specific component framework. We discuss component strategy but defer the choice.
|
|
21
|
+
- Visual redesign — this is about distribution, naming, and architecture, not new aesthetics.
|
|
22
|
+
|
|
23
|
+
## 2. Why now / evidence
|
|
24
|
+
|
|
25
|
+
This RFC is grounded in a real integration of the bundle into the `ui-hf` Tailwind v4 project.
|
|
26
|
+
Concrete friction observed (these are the problems to fix):
|
|
27
|
+
|
|
28
|
+
1. **Namespace collisions with framework defaults.** The generated `pre-built/tailwind.css`
|
|
29
|
+
redefines keys that Tailwind v4 (and the consuming project) already own — `--text-xs` (11px
|
|
30
|
+
vs default), `--text-sm` (13px vs 14px), `--text-xl` (18px vs the project's 26px), `--text-2xl`
|
|
31
|
+
(20px vs 24px), `--spacing-7` (30px vs 28px), `--radius-sm` (6px vs 2px), `--font-sans`.
|
|
32
|
+
A naïve `@import` silently resized utilities used **thousands** of times (`text-xs` ×1093,
|
|
33
|
+
`text-sm` ×113, `text-xl` ×57). Integration required a hand-written filter that imports
|
|
34
|
+
only the additive, non-colliding subset.
|
|
35
|
+
2. **Token-name drift between docs and the generator.** None of the README examples compile
|
|
36
|
+
as-is:
|
|
37
|
+
- `ai-rules/CLAUDE.md` says the primary is CSS var `--color-primary-default`; the generator
|
|
38
|
+
emits `--color-primary`.
|
|
39
|
+
- README shows `bg-badge-booking-confirmed/15` + `text-badge-booking-confirmed` (and
|
|
40
|
+
`--status-{domain}-{state}-color`); the generator emits `--color-badge-booking-confirmed-color`
|
|
41
|
+
and `--color-badge-booking-confirmed-bg`, i.e. utilities are `bg-badge-booking-confirmed-bg` /
|
|
42
|
+
`text-badge-booking-confirmed-color`.
|
|
43
|
+
3. **Generator breaks in modern toolchains.** `generate-tokens.js` is CommonJS (`require`); any
|
|
44
|
+
project with `"type": "module"` (Vite/Vue/most new repos) fails with
|
|
45
|
+
`ReferenceError: require is not defined`. We had to run a temporary `.cjs` copy.
|
|
46
|
+
4. **Awkward generated utility names.** `--color-text-primary` yields the class `text-text-primary`.
|
|
47
|
+
5. **Bundle is incomplete as a sole source.** No primitive ramps (gray/blue 25–950), no fluid
|
|
48
|
+
spacing, no column widths / table min-widths, no component utility classes (`btn-*`, `input-*`).
|
|
49
|
+
It can only *augment* an existing token layer, never replace it.
|
|
50
|
+
6. **Copy-folder distribution guarantees drift.** Each project owns a divergent copy the moment
|
|
51
|
+
it is pasted; there is no mechanism keeping N projects on the same version.
|
|
52
|
+
7. **The component layer re-hardcodes values and forks the token namespace** (introduced in v2 —
|
|
53
|
+
see §2.1). `pre-built/components.css` defines its own `--status-{domain}-{state}-color/-bg` set
|
|
54
|
+
with raw `rgb(...)` literals instead of binding to the canonical `--color-badge-*` tokens, and
|
|
55
|
+
contains ~56 hardcoded hex values (e.g. `#24AFE8`, `#50627E`) — violating the bundle's own
|
|
56
|
+
"never hardcode hex" rule. Change a token in `tokens.figma.json` and the components do not follow.
|
|
57
|
+
|
|
58
|
+
### 2.1 Status against `portable-design_v2` (reviewed 2026-05-21)
|
|
59
|
+
|
|
60
|
+
`portable-design` was archived as `portable-design_v1` and a new `portable-design_v2` was added.
|
|
61
|
+
What v2 changed, mapped to the problems above and the proposal below:
|
|
62
|
+
|
|
63
|
+
**Progress (mostly on §5 — components):**
|
|
64
|
+
- **New `components.html`** — a canonical visual reference, declared authoritative ("when
|
|
65
|
+
`components.html` and `UI_DESIGN.md` disagree, components.html wins"). Genuine progress on the
|
|
66
|
+
§5 anatomy/visual-reference goal.
|
|
67
|
+
- **New `pre-built/components.css`** — a real `.hf-*` primitive layer (pill, tab, …) wired into
|
|
68
|
+
the README setup snippets for every stack.
|
|
69
|
+
- **New `portal-audit.html`** — partial progress toward the §4.6 drift audit.
|
|
70
|
+
- Minor token additions: split `--color-text-placeholder` (`#AEBCCF`) vs `-legacy` (`#99A1B7`);
|
|
71
|
+
extra shadows (`subtle`, `modal`, `outline`); badge `cancel` / `deleted` + cancellation aliases.
|
|
72
|
+
|
|
73
|
+
**Still open (verified unchanged in v2):**
|
|
74
|
+
- §2.1 collisions — `--text-{xs,sm,base,lg,xl,2xl}`, `--spacing-7`, `--radius-sm`, `--font-sans`
|
|
75
|
+
remain unprefixed. No `--target=*-additive`, no `@source not` doc. (→ §4.2)
|
|
76
|
+
- §2.2 doc/token drift — `ai-rules/CLAUDE.md` still says `--color-primary-default`; generator emits
|
|
77
|
+
`--color-primary`. (→ §4.3, §8)
|
|
78
|
+
- §2.3 generator ESM — still `require()`; `node generate-tokens.js` still fails under `"type":"module"`.
|
|
79
|
+
- `--color-text-primary` → still `text-text-primary`.
|
|
80
|
+
- No semantic tier (§4.1); tokens remain flat/primitive-only.
|
|
81
|
+
|
|
82
|
+
**New problems v2 introduced:**
|
|
83
|
+
- §2 item 7 above (component layer hardcodes + forks namespace). There are now **three** color
|
|
84
|
+
namespaces: `--color-badge-*` (tailwind.css/tokens.css), `--status-*` (components.css), plus the
|
|
85
|
+
doc references in `ai-rules`.
|
|
86
|
+
- `components.css` is **hand-maintained** ("extracted from components.html"), not generated —
|
|
87
|
+
another drift source. `generate-tokens.js` has no knowledge of components.
|
|
88
|
+
- **Component class names diverge from token names:** `.status-clean-*` vs token
|
|
89
|
+
`room-item-cleaning-*`; `.status-order-action` vs `order-action-required`.
|
|
90
|
+
- **Two competing visual SSOTs:** `components.html` is now authoritative and `UI_DESIGN.md` is
|
|
91
|
+
declared "stale" — a doc-rot risk rather than a single source of truth.
|
|
92
|
+
|
|
93
|
+
## 3. Core thesis
|
|
94
|
+
|
|
95
|
+
Cross-project consistency breaks in two places: **distribution** (copy-folder → instant drift)
|
|
96
|
+
and **token naming** (collides in real projects). Everything else is downstream. The two highest-
|
|
97
|
+
leverage changes are:
|
|
98
|
+
|
|
99
|
+
1. A **semantic token layer** that both new and existing projects bind to.
|
|
100
|
+
2. **Versioned package distribution** that is **collision-safe by construction**.
|
|
101
|
+
|
|
102
|
+
## 4. Proposal
|
|
103
|
+
|
|
104
|
+
### 4.1 Three-tier token architecture (the bridge between new ↔ existing)
|
|
105
|
+
|
|
106
|
+
Adopt the W3C **DTCG** / Tokens Studio model with three explicit tiers:
|
|
107
|
+
|
|
108
|
+
| Tier | Example | Used directly by app code? |
|
|
109
|
+
|------|---------|----------------------------|
|
|
110
|
+
| **Primitive** | `--hf-blue-500: #24AFE8`, `--hf-gray-300` | No |
|
|
111
|
+
| **Semantic (role)** | `--hf-color-accent`, `--hf-color-bg-surface`, `--hf-color-fg-default`, `--hf-color-fg-muted`, `--hf-color-status-success` | Yes |
|
|
112
|
+
| **Component** (optional) | `--hf-button-bg`, `--hf-input-border` | Yes |
|
|
113
|
+
|
|
114
|
+
Why this serves both scenarios:
|
|
115
|
+
|
|
116
|
+
- **New project** consumes semantic tokens directly.
|
|
117
|
+
- **Existing project** aliases its legacy names onto the semantic layer — exactly the pattern
|
|
118
|
+
already used in `ui-hf` (`--color-hf-blue: var(--hf-color-accent)`). One semantic layer keeps
|
|
119
|
+
both worlds consistent.
|
|
120
|
+
- **Theming / multi-brand** becomes trivial: override the semantic layer per brand/mode, leave
|
|
121
|
+
primitives untouched. Encode modes via Tokens Studio `$themes` (light/dark, per-brand).
|
|
122
|
+
|
|
123
|
+
### 4.2 Collision-safe by construction
|
|
124
|
+
|
|
125
|
+
This is the biggest practical fix.
|
|
126
|
+
|
|
127
|
+
- **Prefix every token** (`--hf-text-*`, `--hf-radius-*`, `--hf-space-*`, `--hf-color-*`) so it can
|
|
128
|
+
never shadow a Tailwind/framework default or a host-project key.
|
|
129
|
+
- Ship an explicit **`--target=tailwind-v4-additive`** that emits only safe keys (the filtering
|
|
130
|
+
`ui-hf` currently does by hand in `scripts/sync-design-system.mjs` belongs in the bundle).
|
|
131
|
+
- Document, for Tailwind v4 consumers, the `@source not "<path>"` rule so the bundle's own
|
|
132
|
+
`ui-kit.html` showcase does not leak utilities (e.g. legacy `bg-[#26ADE4]`) into the app bundle.
|
|
133
|
+
|
|
134
|
+
### 4.3 One SSOT, generated targets, zero doc drift
|
|
135
|
+
|
|
136
|
+
- Replace the hand-rolled `generate-tokens.js` with **Style Dictionary** (mature, DTCG-native,
|
|
137
|
+
all targets out of the box) — and fix the ESM breakage along the way.
|
|
138
|
+
- **Generate or test the doc examples.** Add a snapshot test asserting every token/utility shown
|
|
139
|
+
in README and `ai-rules/CLAUDE.md` actually exists in the generated output. This kills the
|
|
140
|
+
doc-drift class of bugs (§2.2) permanently.
|
|
141
|
+
|
|
142
|
+
### 4.4 Versioned package distribution (the mechanism that keeps N projects in sync)
|
|
143
|
+
|
|
144
|
+
- Publish `@hotelfriend/design-tokens` (and optionally `@hotelfriend/tailwind-preset`) to a private
|
|
145
|
+
registry, **SemVer**. Every project `pnpm update`s to the same version — *this* is what enforces
|
|
146
|
+
sameness.
|
|
147
|
+
- Keep the copy-folder bundle only as a **generated fallback** for non-npm stacks (Yii/PHP), stamped
|
|
148
|
+
with version + origin so its lag is visible.
|
|
149
|
+
- Maintain a changelog + migration notes per minor.
|
|
150
|
+
|
|
151
|
+
### 4.5 Adapter + codemod for existing projects
|
|
152
|
+
|
|
153
|
+
Formalize the manual `ui-hf` work:
|
|
154
|
+
|
|
155
|
+
- A generated **compat layer** per project (`legacy → semantic` aliases).
|
|
156
|
+
- A **codemod** "hardcoded hex → token" (done by hand across ~25 files in `ui-hf`; should be a script).
|
|
157
|
+
|
|
158
|
+
### 4.6 Conformance / drift CI (or consistency rots within a month)
|
|
159
|
+
|
|
160
|
+
- A shareable **ESLint/Stylelint rule**: forbid raw hex and arbitrary `bg-[#…]`, allow only DS tokens.
|
|
161
|
+
Drop it into every project.
|
|
162
|
+
- A **drift audit** in CI comparing a project's computed values against the DS and failing on
|
|
163
|
+
divergence. The README mentions a Yii-only `design-tokens-audit.md` — generalize it to all projects.
|
|
164
|
+
|
|
165
|
+
## 5. Do we need to describe components (buttons, inputs, …)? — Yes
|
|
166
|
+
|
|
167
|
+
> **v2 status: partially started.** `components.html` (visual reference) and `pre-built/components.css`
|
|
168
|
+
> (`.hf-*` CSS layer) now exist — the right *direction*. But the current implementation reproduces the
|
|
169
|
+
> exact drift this RFC warns against (see §2 item 7 / §2.1): it hardcodes hex, forks a `--status-*`
|
|
170
|
+
> namespace instead of binding to `--color-badge-*`, is hand-maintained rather than generated, and its
|
|
171
|
+
> class names diverge from token names. The criteria below are the bar v2's component layer must meet.
|
|
172
|
+
|
|
173
|
+
Tokens guarantee consistent **values** (color, spacing, radius). They do **not** guarantee a
|
|
174
|
+
consistent **look** — that comes from components. So components must be described, but choose the
|
|
175
|
+
*right layer* for a multi-framework reality (Vue portal + Yii/PHP):
|
|
176
|
+
|
|
177
|
+
**Hard criteria for the component layer (must all hold):**
|
|
178
|
+
|
|
179
|
+
- **(a) Bind to tokens, never hardcode.** Every declaration references a canonical token
|
|
180
|
+
(`var(--color-badge-…)` / `var(--hf-color-…)`); zero hex literals in `components.css`.
|
|
181
|
+
- **(b) Generated, not hand-extracted.** The CSS layer is emitted by the generator from a single
|
|
182
|
+
source, so a token change propagates automatically.
|
|
183
|
+
- **(c) One namespace.** Drop the parallel `--status-*` set; consume the canonical color tokens directly.
|
|
184
|
+
- **(d) Class names equal token names.** `.status-room-item-cleaning-*` (not `.status-clean-*`),
|
|
185
|
+
`.status-order-action-required` (not `.status-order-action`).
|
|
186
|
+
|
|
187
|
+
**Mandatory — framework-agnostic component contracts** (the portable, highest-value layer):
|
|
188
|
+
|
|
189
|
+
- **Anatomy** — the parts of each component (button: container / label / icon / spinner).
|
|
190
|
+
- **Token bindings** — which token each part uses (`button.bg = --hf-color-accent`,
|
|
191
|
+
`button.bg-hover = --hf-color-accent-hover`, `button.radius = --hf-radius-md`). This is what makes
|
|
192
|
+
a button identical across frameworks.
|
|
193
|
+
- **All states** — default / hover / focus-visible / active / disabled / loading, with exact
|
|
194
|
+
declarations. `states-canonical.json` already does part of this; make it the normative source and
|
|
195
|
+
cover every primitive.
|
|
196
|
+
- **Variants & sizes** — primary / secondary / outline / danger; sm / md / lg.
|
|
197
|
+
|
|
198
|
+
**Recommended — a portable CSS component layer** (`.btn-*`, `.hf-card-*`, `.input-*`, `.hf-pill`) built
|
|
199
|
+
on the semantic tokens. Both a Vue app and a PHP template can apply the same class and get the same
|
|
200
|
+
result with zero framework lock-in. The `ai-rules` already reference these class names — make them
|
|
201
|
+
real and generated.
|
|
202
|
+
|
|
203
|
+
**Optional — per-framework component libraries** (Vue/React) that consume the same tokens + CSS layer.
|
|
204
|
+
Justified only when projects share a framework. Bridge design↔code with **Figma Code Connect**
|
|
205
|
+
(`.figma.ts` mappings) so the canonical component in Figma points at the canonical code.
|
|
206
|
+
|
|
207
|
+
**Recommended priority for components:** contracts (anatomy + token bindings + states) first →
|
|
208
|
+
portable CSS layer → framework libraries last.
|
|
209
|
+
|
|
210
|
+
Minimum set to specify first (covers ~80% of screens): Button, Input/Select, Checkbox/Radio, Card,
|
|
211
|
+
Modal/Dialog, Tabs, Table/DataGrid row, Status pill, Toast, Form field + error.
|
|
212
|
+
|
|
213
|
+
## 6. Phased rollout
|
|
214
|
+
|
|
215
|
+
1. **Phase 1 — foundation (unblocks everything):** semantic token tier (§4.1) + prefixing /
|
|
216
|
+
additive target (§4.2). Without these, the rest is held together with tape.
|
|
217
|
+
2. **Phase 2 — distribution:** versioned npm package (§4.4); copy-folder becomes a generated artifact.
|
|
218
|
+
3. **Phase 3 — integrity:** Style Dictionary + doc-example tests (§4.3) + drift CI & lint rule (§4.6).
|
|
219
|
+
4. **Phase 4 — components:** contracts → CSS layer → (optional) framework libs (§5). Runs in parallel
|
|
220
|
+
with Phase 3. *(Partially started in v2 via `components.html` + `components.css`; must be reworked
|
|
221
|
+
to meet the §5 hard criteria — token-bound, generated, single namespace, matching class names.)*
|
|
222
|
+
5. **Phase 5 — existing-project onboarding:** compat-layer generator + hex→token codemod (§4.5).
|
|
223
|
+
|
|
224
|
+
## 7. Open questions
|
|
225
|
+
|
|
226
|
+
- Private registry choice for the npm package (GitHub Packages / Verdaccio / npm org)?
|
|
227
|
+
- Single multi-brand DS, or one base + per-product themes?
|
|
228
|
+
- Component layer: ship CSS-first now, or wait for a shared framework decision?
|
|
229
|
+
- Who owns the SSOT (`tokens.figma.json`) — Figma (Tokens Studio push) or repo, and which direction
|
|
230
|
+
is authoritative?
|
|
231
|
+
|
|
232
|
+
## 8. Appendix — concrete bundle fixes (independent of the larger plan)
|
|
233
|
+
|
|
234
|
+
These are small, shippable, and worth doing regardless of how the RFC lands. Checked against v2 —
|
|
235
|
+
none are addressed yet:
|
|
236
|
+
|
|
237
|
+
- [ ] Align token names across README / `ai-rules/CLAUDE.md` / `pre-built/*` (`--color-primary` vs
|
|
238
|
+
`--color-primary-default`; `badge-*-color/-bg` vs README examples).
|
|
239
|
+
- [ ] Make `generate-tokens.js` run under ESM (rename to `.cjs`, or rewrite ESM, or `createRequire`).
|
|
240
|
+
- [ ] Rename text-color tokens to avoid `text-text-primary` (e.g. `--hf-color-fg`, `--hf-color-fg-muted`).
|
|
241
|
+
- [ ] Add a `--target=tailwind-v4-additive`.
|
|
242
|
+
- [ ] Document the `@source not` exclusion for Tailwind v4 consumers.
|
|
243
|
+
- [ ] Add an "existing project" setup section to the README, separate from greenfield, warning about
|
|
244
|
+
collisions.
|
|
245
|
+
- [ ] **Fix `components.css` to bind to canonical tokens** — drop the self-defined `--status-*` set
|
|
246
|
+
and its raw `rgb(...)`/hardcoded hex; reference `--color-badge-*` (or the §4.1 semantic tokens).
|
|
247
|
+
- [ ] **Normalize component class names to token names** (`.status-clean-*` → `room-item-cleaning-*`,
|
|
248
|
+
`.status-order-action` → `order-action-required`).
|
|
249
|
+
- [ ] **Generate `components.css` from the source** instead of hand-extracting it from `components.html`.
|
|
250
|
+
- [ ] **Resolve the two visual SSOTs** — either fold `UI_DESIGN.md` into `components.html` or mark it
|
|
251
|
+
explicitly non-normative, so there is one authoritative visual reference.
|
|
252
|
+
|
|
253
|
+
## 9. Implementation status (verified 2026-05-22)
|
|
254
|
+
|
|
255
|
+
Status of each proposal against the shipped bundle. Legend: ✅ done · 🟡 partial · ⏸ deferred (needs an external decision / low ROI).
|
|
256
|
+
|
|
257
|
+
| § | Item | Status | Evidence / note |
|
|
258
|
+
|---|------|--------|-----------------|
|
|
259
|
+
| 4.1 | Three-tier token model (primitive → semantic → component) | ✅ | `tokens.figma.json` + generated `pre-built/*`; semantic `--color-hf-{fg,bg,border,…}`, component `--color-hf-input-border` |
|
|
260
|
+
| 4.2 | Collision-safe prefixing + additive target | ✅ | All emitted tokens `--*-hf-*`; `pre-built/tailwind.additive.css`; `@source not` documented in README |
|
|
261
|
+
| 4.3 | SSOT generated, zero doc drift | 🟡 | Doc-example token test ✅ (`validate-tokens.cjs` check 3). Style Dictionary migration ⏸ — custom generator covers all targets |
|
|
262
|
+
| 4.4 | Versioned npm package | 🟡 | `package.json` (`@hotelfriend/design-tokens`) + `publishConfig` scaffolded. Actual publish ⏸ — pending registry decision (GitHub Packages) |
|
|
263
|
+
| 4.5 | Adapter + hex→token codemod | ⏸ | Legacy portal unlikely to adopt; revisit if it does |
|
|
264
|
+
| 4.6 | Conformance / drift CI + lint rule | ✅ | `stylelint-design-system.cjs` + `validate-tokens.cjs` + `.github/workflows/design-system.yml` (build → drift check → validate). `portal-audit.html` = computed-value audit |
|
|
265
|
+
| 5a | Component layer binds to tokens, no hex | ✅ | `validate-tokens.cjs` check 2 enforces no bare hex |
|
|
266
|
+
| 5b | Component layer generated, not hand-extracted | ❌ | `components.css` is still hand-maintained; drift caught by validator, not prevented |
|
|
267
|
+
| 5c | One namespace (drop forked `--status-*`) | ✅ | No `--status-*` declarations; status colors come from canonical tokens |
|
|
268
|
+
| 5d | Class names equal token names | ✅ | `.status-room-item-cleaning-*`, `.status-order-action-required` in `status.css` |
|
|
269
|
+
| 8 | Appendix concrete fixes | ✅ 9/10 | Only "auto-generate components.css" (= 5b) outstanding |
|
|
270
|
+
|
|
271
|
+
**Phases:** 1 (foundation) ✅ · 2 (npm publish) ⏸ · 3 (Style Dictionary ⏸ / doc-drift test ✅ / drift CI ✅) · 4 (components: started, not yet generated) · 5 (onboarding) ⏸.
|
|
272
|
+
|
|
273
|
+
**True remaining work (intentional, needs external decisions):** GitHub Packages publish (§4.4 — registry decision), Figma Code Connect (§5 optional — needs designer's Figma file), Style Dictionary (§4.3 — premature), legacy codemod (§4.5 — low ROI), auto-generate `components.css` (§5b — validator covers drift).
|