@layoutdesign/context 0.1.7

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.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +424 -0
  3. package/dist/bin/cli.d.ts +3 -0
  4. package/dist/bin/cli.d.ts.map +1 -0
  5. package/dist/bin/cli.js +57 -0
  6. package/dist/bin/cli.js.map +1 -0
  7. package/dist/src/cli/import-zip.d.ts +2 -0
  8. package/dist/src/cli/import-zip.d.ts.map +1 -0
  9. package/dist/src/cli/import-zip.js +156 -0
  10. package/dist/src/cli/import-zip.js.map +1 -0
  11. package/dist/src/cli/init.d.ts +4 -0
  12. package/dist/src/cli/init.d.ts.map +1 -0
  13. package/dist/src/cli/init.js +104 -0
  14. package/dist/src/cli/init.js.map +1 -0
  15. package/dist/src/cli/install.d.ts +5 -0
  16. package/dist/src/cli/install.d.ts.map +1 -0
  17. package/dist/src/cli/install.js +192 -0
  18. package/dist/src/cli/install.js.map +1 -0
  19. package/dist/src/cli/list.d.ts +2 -0
  20. package/dist/src/cli/list.d.ts.map +1 -0
  21. package/dist/src/cli/list.js +36 -0
  22. package/dist/src/cli/list.js.map +1 -0
  23. package/dist/src/cli/serve.d.ts +2 -0
  24. package/dist/src/cli/serve.d.ts.map +1 -0
  25. package/dist/src/cli/serve.js +9 -0
  26. package/dist/src/cli/serve.js.map +1 -0
  27. package/dist/src/cli/use.d.ts +2 -0
  28. package/dist/src/cli/use.d.ts.map +1 -0
  29. package/dist/src/cli/use.js +54 -0
  30. package/dist/src/cli/use.js.map +1 -0
  31. package/dist/src/compliance/checker.d.ts +23 -0
  32. package/dist/src/compliance/checker.d.ts.map +1 -0
  33. package/dist/src/compliance/checker.js +31 -0
  34. package/dist/src/compliance/checker.js.map +1 -0
  35. package/dist/src/compliance/rules.d.ts +11 -0
  36. package/dist/src/compliance/rules.d.ts.map +1 -0
  37. package/dist/src/compliance/rules.js +147 -0
  38. package/dist/src/compliance/rules.js.map +1 -0
  39. package/dist/src/index.d.ts +9 -0
  40. package/dist/src/index.d.ts.map +1 -0
  41. package/dist/src/index.js +6 -0
  42. package/dist/src/index.js.map +1 -0
  43. package/dist/src/kit/loader.d.ts +16 -0
  44. package/dist/src/kit/loader.d.ts.map +1 -0
  45. package/dist/src/kit/loader.js +98 -0
  46. package/dist/src/kit/loader.js.map +1 -0
  47. package/dist/src/kit/parser.d.ts +21 -0
  48. package/dist/src/kit/parser.d.ts.map +1 -0
  49. package/dist/src/kit/parser.js +98 -0
  50. package/dist/src/kit/parser.js.map +1 -0
  51. package/dist/src/kit/registry.d.ts +4 -0
  52. package/dist/src/kit/registry.d.ts.map +1 -0
  53. package/dist/src/kit/registry.js +91 -0
  54. package/dist/src/kit/registry.js.map +1 -0
  55. package/dist/src/kit/types.d.ts +51 -0
  56. package/dist/src/kit/types.d.ts.map +1 -0
  57. package/dist/src/kit/types.js +11 -0
  58. package/dist/src/kit/types.js.map +1 -0
  59. package/dist/src/mcp/server.d.ts +6 -0
  60. package/dist/src/mcp/server.d.ts.map +1 -0
  61. package/dist/src/mcp/server.js +56 -0
  62. package/dist/src/mcp/server.js.map +1 -0
  63. package/dist/src/mcp/tools/check-compliance.d.ts +16 -0
  64. package/dist/src/mcp/tools/check-compliance.d.ts.map +1 -0
  65. package/dist/src/mcp/tools/check-compliance.js +44 -0
  66. package/dist/src/mcp/tools/check-compliance.js.map +1 -0
  67. package/dist/src/mcp/tools/design-in-figma.d.ts +24 -0
  68. package/dist/src/mcp/tools/design-in-figma.d.ts.map +1 -0
  69. package/dist/src/mcp/tools/design-in-figma.js +202 -0
  70. package/dist/src/mcp/tools/design-in-figma.js.map +1 -0
  71. package/dist/src/mcp/tools/get-component.d.ts +16 -0
  72. package/dist/src/mcp/tools/get-component.d.ts.map +1 -0
  73. package/dist/src/mcp/tools/get-component.js +52 -0
  74. package/dist/src/mcp/tools/get-component.js.map +1 -0
  75. package/dist/src/mcp/tools/get-design-system.d.ts +16 -0
  76. package/dist/src/mcp/tools/get-design-system.d.ts.map +1 -0
  77. package/dist/src/mcp/tools/get-design-system.js +51 -0
  78. package/dist/src/mcp/tools/get-design-system.js.map +1 -0
  79. package/dist/src/mcp/tools/get-screenshots.d.ts +23 -0
  80. package/dist/src/mcp/tools/get-screenshots.d.ts.map +1 -0
  81. package/dist/src/mcp/tools/get-screenshots.js +78 -0
  82. package/dist/src/mcp/tools/get-screenshots.js.map +1 -0
  83. package/dist/src/mcp/tools/get-tokens.d.ts +20 -0
  84. package/dist/src/mcp/tools/get-tokens.d.ts.map +1 -0
  85. package/dist/src/mcp/tools/get-tokens.js +50 -0
  86. package/dist/src/mcp/tools/get-tokens.js.map +1 -0
  87. package/dist/src/mcp/tools/list-components.d.ts +11 -0
  88. package/dist/src/mcp/tools/list-components.d.ts.map +1 -0
  89. package/dist/src/mcp/tools/list-components.js +38 -0
  90. package/dist/src/mcp/tools/list-components.js.map +1 -0
  91. package/dist/src/mcp/tools/preview.d.ts +21 -0
  92. package/dist/src/mcp/tools/preview.d.ts.map +1 -0
  93. package/dist/src/mcp/tools/preview.js +63 -0
  94. package/dist/src/mcp/tools/preview.js.map +1 -0
  95. package/dist/src/mcp/tools/push-to-figma.d.ts +24 -0
  96. package/dist/src/mcp/tools/push-to-figma.d.ts.map +1 -0
  97. package/dist/src/mcp/tools/push-to-figma.js +101 -0
  98. package/dist/src/mcp/tools/push-to-figma.js.map +1 -0
  99. package/dist/src/mcp/tools/update-tokens.d.ts +21 -0
  100. package/dist/src/mcp/tools/update-tokens.d.ts.map +1 -0
  101. package/dist/src/mcp/tools/update-tokens.js +187 -0
  102. package/dist/src/mcp/tools/update-tokens.js.map +1 -0
  103. package/dist/src/mcp/tools/url-to-figma.d.ts +29 -0
  104. package/dist/src/mcp/tools/url-to-figma.d.ts.map +1 -0
  105. package/dist/src/mcp/tools/url-to-figma.js +103 -0
  106. package/dist/src/mcp/tools/url-to-figma.js.map +1 -0
  107. package/dist/src/preview/server.d.ts +15 -0
  108. package/dist/src/preview/server.d.ts.map +1 -0
  109. package/dist/src/preview/server.js +146 -0
  110. package/dist/src/preview/server.js.map +1 -0
  111. package/dist/src/preview/static/index.html +493 -0
  112. package/dist/src/preview/transpile.d.ts +10 -0
  113. package/dist/src/preview/transpile.d.ts.map +1 -0
  114. package/dist/src/preview/transpile.js +40 -0
  115. package/dist/src/preview/transpile.js.map +1 -0
  116. package/dist/src/preview/ws.d.ts +17 -0
  117. package/dist/src/preview/ws.d.ts.map +1 -0
  118. package/dist/src/preview/ws.js +66 -0
  119. package/dist/src/preview/ws.js.map +1 -0
  120. package/kits/linear-lite/DESIGN.md +421 -0
  121. package/kits/linear-lite/kit.json +12 -0
  122. package/kits/linear-lite/tokens.css +46 -0
  123. package/kits/linear-lite/tokens.json +47 -0
  124. package/kits/notion-lite/DESIGN.md +528 -0
  125. package/kits/notion-lite/kit.json +12 -0
  126. package/kits/notion-lite/tokens.css +50 -0
  127. package/kits/notion-lite/tokens.json +51 -0
  128. package/kits/stripe-lite/DESIGN.md +539 -0
  129. package/kits/stripe-lite/kit.json +12 -0
  130. package/kits/stripe-lite/tokens.css +57 -0
  131. package/kits/stripe-lite/tokens.json +58 -0
  132. package/package.json +63 -0
@@ -0,0 +1,528 @@
1
+ # Notion — Design System
2
+
3
+ > Content-first. The UI disappears so the writing can breathe.
4
+
5
+ ---
6
+
7
+ ## Quick Reference
8
+
9
+ **Aesthetic:** Warm off-whites, organic warm-gray text, and almost-invisible borders. The interface is subordinate to content — controls only appear when needed. Typography is the primary design element: comfortable line-height, generous max-width, and subtle serif option for long-form content.
10
+
11
+ ### Colour Palette
12
+ | Role | Token | Value |
13
+ |---|---|---|
14
+ | App background | `--notion-bg-app` | `#FFFFFF` |
15
+ | Surface (sidebars, panels) | `--notion-bg-surface` | `#F7F6F3` |
16
+ | Hover state | `--notion-bg-hover` | `#EEEEE9` |
17
+ | Selected state | `--notion-bg-selected` | `#E8E7E3` |
18
+ | Border (default) | `--notion-border` | `rgba(55,53,47,0.09)` |
19
+ | Border (strong) | `--notion-border-strong` | `rgba(55,53,47,0.18)` |
20
+ | Primary text | `--notion-text-primary` | `#37352F` |
21
+ | Secondary text | `--notion-text-secondary` | `#787774` |
22
+ | Muted text | `--notion-text-muted` | `#9B9A97` |
23
+ | Placeholder | `--notion-text-placeholder` | `rgba(55,53,47,0.4)` |
24
+ | Accent | `--notion-accent` | `#2383E2` |
25
+ | Accent hover | `--notion-accent-hover` | `#1E78D3` |
26
+ | Accent subtle | `--notion-accent-subtle` | `rgba(35,131,226,0.1)` |
27
+ | Callout: blue | `--notion-callout-blue` | `rgba(35,131,226,0.1)` |
28
+ | Callout: yellow | `--notion-callout-yellow` | `rgba(255,184,0,0.14)` |
29
+ | Callout: green | `--notion-callout-green` | `rgba(15,123,108,0.1)` |
30
+ | Callout: red | `--notion-callout-red` | `rgba(235,87,87,0.1)` |
31
+ | Callout: gray | `--notion-callout-gray` | `rgba(55,53,47,0.06)` |
32
+
33
+ ### Typography
34
+ - **UI font:** `ui-sans-serif`, -apple-system, BlinkMacSystemFont, Segoe UI — via `--notion-font-sans`
35
+ - **Content font (optional):** `Georgia`, Times New Roman — via `--notion-font-serif`
36
+ - **Code font:** `SFMono-Regular`, Menlo, Consolas — via `--notion-font-mono`
37
+ - Body text: 16px / 1.7 line-height — generous for reading
38
+ - UI labels: 14px, `--notion-text-secondary`
39
+ - Small labels: 12px, `--notion-text-muted`
40
+ - Max content width: 720px (full width: none, centred)
41
+
42
+ ### Spacing Scale
43
+ `2 / 4 / 8 / 16 / 24 / 32px` — tokens `2xs / xs / sm / md / lg / xl`
44
+
45
+ ### Border Radius
46
+ `3px (sm) / 4px (md) / 6px (lg)` — intentionally small, organic
47
+
48
+ ### Key Design Rules
49
+ 1. **The background is white.** `--notion-bg-app` = `#FFFFFF`. No dark backgrounds.
50
+ 2. **Warm grays, not cool.** All neutrals have a warm brownish undertone (`#37352F`).
51
+ 3. **Borders are opacity-based** on `#37352F` — they adapt to any background tint.
52
+ 4. **Hover is a background change** only — no border or shadow change.
53
+ 5. **No box-shadow on interactive elements.** Only use shadow (if at all) on floating elements like menus.
54
+ 6. **Accent (blue) is for links and active states only.** Never fill a button with it except for a true CTA.
55
+ 7. **Icons appear on hover** — ghost by default, visible when the user approaches.
56
+ 8. **Transitions:** 100ms ease-out. Fast enough to feel instant.
57
+ 9. **Callout colours** are always paired: a tinted background from `--notion-callout-*` with the appropriately-toned text.
58
+
59
+ ---
60
+
61
+ ## Design Tokens
62
+
63
+ ### Backgrounds
64
+ ```
65
+ --notion-bg-app: #FFFFFF
66
+ --notion-bg-surface: #F7F6F3
67
+ --notion-bg-hover: #EEEEE9
68
+ --notion-bg-selected: #E8E7E3
69
+ ```
70
+
71
+ ### Borders
72
+ ```
73
+ --notion-border: rgba(55, 53, 47, 0.09)
74
+ --notion-border-strong: rgba(55, 53, 47, 0.18)
75
+ ```
76
+
77
+ ### Text
78
+ ```
79
+ --notion-text-primary: #37352F
80
+ --notion-text-secondary: #787774
81
+ --notion-text-muted: #9B9A97
82
+ --notion-text-placeholder: rgba(55, 53, 47, 0.4)
83
+ ```
84
+
85
+ ### Accent
86
+ ```
87
+ --notion-accent: #2383E2
88
+ --notion-accent-hover: #1E78D3
89
+ --notion-accent-subtle: rgba(35, 131, 226, 0.1)
90
+ ```
91
+
92
+ ### Callout Backgrounds
93
+ ```
94
+ --notion-callout-blue: rgba(35, 131, 226, 0.1)
95
+ --notion-callout-yellow: rgba(255, 184, 0, 0.14)
96
+ --notion-callout-green: rgba(15, 123, 108, 0.1)
97
+ --notion-callout-red: rgba(235, 87, 87, 0.1)
98
+ --notion-callout-gray: rgba(55, 53, 47, 0.06)
99
+ ```
100
+
101
+ ### Typography
102
+ ```
103
+ --notion-font-sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif
104
+ --notion-font-serif: Georgia, 'Times New Roman', serif
105
+ --notion-font-mono: 'SFMono-Regular', Menlo, Consolas, monospace
106
+ ```
107
+
108
+ ### Spacing
109
+ ```
110
+ --notion-space-2xs: 2px
111
+ --notion-space-xs: 4px
112
+ --notion-space-sm: 8px
113
+ --notion-space-md: 16px
114
+ --notion-space-lg: 24px
115
+ --notion-space-xl: 32px
116
+ ```
117
+
118
+ ### Border Radius
119
+ ```
120
+ --notion-radius-sm: 3px
121
+ --notion-radius-md: 4px
122
+ --notion-radius-lg: 6px
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Components
128
+
129
+ ### Button
130
+
131
+ Minimal ghost-style buttons by default. The "primary" variant is used sparingly — only for true CTAs like "Create" or "Save". Text buttons are the standard. Height 28px, tight padding, barely-there hover.
132
+
133
+ **Tokens used:** `--notion-bg-hover`, `--notion-bg-selected`, `--notion-text-primary`, `--notion-text-secondary`, `--notion-accent`, `--notion-accent-subtle`, `--notion-radius-sm`
134
+
135
+ ```tsx
136
+ type ButtonVariant = 'primary' | 'ghost' | 'text';
137
+
138
+ interface ButtonProps {
139
+ variant?: ButtonVariant;
140
+ children: React.ReactNode;
141
+ onClick?: () => void;
142
+ disabled?: boolean;
143
+ size?: 'sm' | 'md';
144
+ }
145
+
146
+ export function Button({
147
+ variant = 'ghost',
148
+ children,
149
+ onClick,
150
+ disabled,
151
+ size = 'md',
152
+ }: ButtonProps) {
153
+ const height = size === 'sm' ? '24px' : '28px';
154
+ const fontSize = size === 'sm' ? '12px' : '14px';
155
+ const padding = size === 'sm' ? '0 8px' : '0 10px';
156
+
157
+ const base: React.CSSProperties = {
158
+ display: 'inline-flex',
159
+ alignItems: 'center',
160
+ gap: '4px',
161
+ height,
162
+ padding,
163
+ borderRadius: 'var(--notion-radius-sm)',
164
+ fontSize,
165
+ fontWeight: 500,
166
+ fontFamily: 'var(--notion-font-sans)',
167
+ cursor: disabled ? 'not-allowed' : 'pointer',
168
+ opacity: disabled ? 0.5 : 1,
169
+ border: 'none',
170
+ transition: 'background 100ms ease-out',
171
+ };
172
+
173
+ const variants: Record<ButtonVariant, React.CSSProperties> = {
174
+ primary: {
175
+ background: 'var(--notion-text-primary)',
176
+ color: '#FFFFFF',
177
+ },
178
+ ghost: {
179
+ background: 'transparent',
180
+ color: 'var(--notion-text-secondary)',
181
+ },
182
+ text: {
183
+ background: 'transparent',
184
+ color: 'var(--notion-accent)',
185
+ },
186
+ };
187
+
188
+ const hoverBg: Record<ButtonVariant, string> = {
189
+ primary: 'rgba(55,53,47,0.85)',
190
+ ghost: 'var(--notion-bg-hover)',
191
+ text: 'var(--notion-accent-subtle)',
192
+ };
193
+
194
+ return (
195
+ <button
196
+ style={{ ...base, ...variants[variant] }}
197
+ onClick={onClick}
198
+ disabled={disabled}
199
+ onMouseEnter={e => {
200
+ if (!disabled) (e.currentTarget as HTMLButtonElement).style.background = hoverBg[variant];
201
+ }}
202
+ onMouseLeave={e => {
203
+ const defaultBg = variant === 'primary' ? 'var(--notion-text-primary)' : 'transparent';
204
+ (e.currentTarget as HTMLButtonElement).style.background = defaultBg;
205
+ }}
206
+ >
207
+ {children}
208
+ </button>
209
+ );
210
+ }
211
+ ```
212
+
213
+ ---
214
+
215
+ ### TextBlock
216
+
217
+ Editable content block — the core primitive of any Notion-style editor. Renders a `contentEditable` div with Notion's characteristic placeholder behaviour. Uses serif or sans font depending on the content type.
218
+
219
+ **Tokens used:** `--notion-font-sans`, `--notion-font-serif`, `--notion-text-primary`, `--notion-text-placeholder`, `--notion-bg-hover`, `--notion-radius-sm`
220
+
221
+ ```tsx
222
+ type BlockType = 'paragraph' | 'heading1' | 'heading2' | 'heading3';
223
+
224
+ interface TextBlockProps {
225
+ type?: BlockType;
226
+ placeholder?: string;
227
+ defaultValue?: string;
228
+ serif?: boolean;
229
+ onFocus?: () => void;
230
+ onBlur?: () => void;
231
+ }
232
+
233
+ const blockStyles: Record<BlockType, React.CSSProperties> = {
234
+ paragraph: { fontSize: '16px', fontWeight: 400, lineHeight: '1.7' },
235
+ heading1: { fontSize: '30px', fontWeight: 700, lineHeight: '1.3' },
236
+ heading2: { fontSize: '24px', fontWeight: 700, lineHeight: '1.35' },
237
+ heading3: { fontSize: '20px', fontWeight: 600, lineHeight: '1.4' },
238
+ };
239
+
240
+ export function TextBlock({
241
+ type = 'paragraph',
242
+ placeholder = 'Type something…',
243
+ defaultValue,
244
+ serif,
245
+ onFocus,
246
+ onBlur,
247
+ }: TextBlockProps) {
248
+ return (
249
+ <div
250
+ contentEditable
251
+ suppressContentEditableWarning
252
+ data-placeholder={placeholder}
253
+ onFocus={onFocus}
254
+ onBlur={onBlur}
255
+ style={{
256
+ outline: 'none',
257
+ width: '100%',
258
+ color: 'var(--notion-text-primary)',
259
+ fontFamily: serif ? 'var(--notion-font-serif)' : 'var(--notion-font-sans)',
260
+ ...blockStyles[type],
261
+ }}
262
+ >
263
+ {defaultValue}
264
+ </div>
265
+ );
266
+ }
267
+
268
+ /* Required CSS for placeholder behaviour:
269
+ [contenteditable]:empty::before {
270
+ content: attr(data-placeholder);
271
+ color: var(--notion-text-placeholder);
272
+ pointer-events: none;
273
+ }
274
+ */
275
+ ```
276
+
277
+ ---
278
+
279
+ ### Toggle
280
+
281
+ Expandable toggle block with animated arrow. The summary row has a hover state; the content indents beneath it. A fundamental Notion layout primitive.
282
+
283
+ **Tokens used:** `--notion-bg-hover`, `--notion-text-primary`, `--notion-text-secondary`, `--notion-font-sans`, `--notion-radius-sm`, `--notion-space-md`
284
+
285
+ ```tsx
286
+ import { useState } from 'react';
287
+
288
+ interface ToggleProps {
289
+ summary: React.ReactNode;
290
+ children: React.ReactNode;
291
+ defaultOpen?: boolean;
292
+ }
293
+
294
+ export function Toggle({ summary, children, defaultOpen = false }: ToggleProps) {
295
+ const [open, setOpen] = useState(defaultOpen);
296
+
297
+ return (
298
+ <div>
299
+ <div
300
+ onClick={() => setOpen(o => !o)}
301
+ style={{
302
+ display: 'flex',
303
+ alignItems: 'flex-start',
304
+ gap: '4px',
305
+ padding: '2px 4px',
306
+ borderRadius: 'var(--notion-radius-sm)',
307
+ cursor: 'pointer',
308
+ userSelect: 'none',
309
+ transition: 'background 100ms ease-out',
310
+ }}
311
+ onMouseEnter={e => (e.currentTarget.style.background = 'var(--notion-bg-hover)')}
312
+ onMouseLeave={e => (e.currentTarget.style.background = 'transparent')}
313
+ >
314
+ <span
315
+ style={{
316
+ display: 'inline-flex',
317
+ alignItems: 'center',
318
+ justifyContent: 'center',
319
+ width: '22px',
320
+ height: '22px',
321
+ flexShrink: 0,
322
+ color: 'var(--notion-text-muted)',
323
+ transition: 'transform 100ms ease-out',
324
+ transform: open ? 'rotate(90deg)' : 'rotate(0deg)',
325
+ fontSize: '12px',
326
+ marginTop: '2px',
327
+ }}
328
+ >
329
+
330
+ </span>
331
+ <div style={{
332
+ flex: 1,
333
+ fontSize: '16px',
334
+ lineHeight: '1.7',
335
+ color: 'var(--notion-text-primary)',
336
+ fontFamily: 'var(--notion-font-sans)',
337
+ fontWeight: 500,
338
+ }}>
339
+ {summary}
340
+ </div>
341
+ </div>
342
+
343
+ {open && (
344
+ <div style={{ paddingLeft: '26px', marginTop: '2px' }}>
345
+ {children}
346
+ </div>
347
+ )}
348
+ </div>
349
+ );
350
+ }
351
+ ```
352
+
353
+ ---
354
+
355
+ ### Callout
356
+
357
+ Highlighted block with emoji icon. Five colour variants. Used for tips, warnings, and important notes in documents. The emoji serves as the visual anchor — always provide one.
358
+
359
+ **Tokens used:** `--notion-callout-blue/yellow/green/red/gray`, `--notion-text-primary`, `--notion-radius-md`, `--notion-space-md`
360
+
361
+ ```tsx
362
+ type CalloutColour = 'blue' | 'yellow' | 'green' | 'red' | 'gray';
363
+
364
+ interface CalloutProps {
365
+ colour?: CalloutColour;
366
+ emoji?: string;
367
+ children: React.ReactNode;
368
+ }
369
+
370
+ const calloutBg: Record<CalloutColour, string> = {
371
+ blue: 'var(--notion-callout-blue)',
372
+ yellow: 'var(--notion-callout-yellow)',
373
+ green: 'var(--notion-callout-green)',
374
+ red: 'var(--notion-callout-red)',
375
+ gray: 'var(--notion-callout-gray)',
376
+ };
377
+
378
+ const calloutEmoji: Record<CalloutColour, string> = {
379
+ blue: '💡',
380
+ yellow: '⚠️',
381
+ green: '✅',
382
+ red: '🚨',
383
+ gray: '📝',
384
+ };
385
+
386
+ export function Callout({ colour = 'gray', emoji, children }: CalloutProps) {
387
+ return (
388
+ <div
389
+ style={{
390
+ display: 'flex',
391
+ gap: 'var(--notion-space-sm)',
392
+ padding: 'var(--notion-space-md)',
393
+ background: calloutBg[colour],
394
+ borderRadius: 'var(--notion-radius-md)',
395
+ }}
396
+ >
397
+ <span
398
+ style={{
399
+ fontSize: '18px',
400
+ lineHeight: '1.7',
401
+ flexShrink: 0,
402
+ }}
403
+ role="img"
404
+ aria-hidden="true"
405
+ >
406
+ {emoji ?? calloutEmoji[colour]}
407
+ </span>
408
+ <div
409
+ style={{
410
+ flex: 1,
411
+ fontSize: '16px',
412
+ lineHeight: '1.7',
413
+ color: 'var(--notion-text-primary)',
414
+ fontFamily: 'var(--notion-font-sans)',
415
+ }}
416
+ >
417
+ {children}
418
+ </div>
419
+ </div>
420
+ );
421
+ }
422
+ ```
423
+
424
+ ---
425
+
426
+ ### Breadcrumb
427
+
428
+ Page-path breadcrumb with separator chevrons. Items are clickable links styled as muted text; the last item (current page) is non-interactive and shows in primary text.
429
+
430
+ **Tokens used:** `--notion-text-primary`, `--notion-text-muted`, `--notion-accent`, `--notion-font-sans`, `--notion-bg-hover`, `--notion-radius-sm`
431
+
432
+ ```tsx
433
+ interface BreadcrumbItem {
434
+ label: string;
435
+ href?: string;
436
+ onClick?: () => void;
437
+ }
438
+
439
+ interface BreadcrumbProps {
440
+ items: BreadcrumbItem[];
441
+ }
442
+
443
+ export function Breadcrumb({ items }: BreadcrumbProps) {
444
+ return (
445
+ <nav aria-label="Breadcrumb">
446
+ <ol
447
+ style={{
448
+ display: 'flex',
449
+ alignItems: 'center',
450
+ gap: '2px',
451
+ listStyle: 'none',
452
+ margin: 0,
453
+ padding: 0,
454
+ flexWrap: 'wrap',
455
+ }}
456
+ >
457
+ {items.map((item, index) => {
458
+ const isLast = index === items.length - 1;
459
+
460
+ return (
461
+ <li key={index} style={{ display: 'flex', alignItems: 'center', gap: '2px' }}>
462
+ {isLast ? (
463
+ <span
464
+ style={{
465
+ fontSize: '14px',
466
+ fontWeight: 500,
467
+ color: 'var(--notion-text-primary)',
468
+ fontFamily: 'var(--notion-font-sans)',
469
+ padding: '2px 6px',
470
+ borderRadius: 'var(--notion-radius-sm)',
471
+ }}
472
+ aria-current="page"
473
+ >
474
+ {item.label}
475
+ </span>
476
+ ) : (
477
+ <button
478
+ onClick={item.onClick}
479
+ style={{
480
+ fontSize: '14px',
481
+ fontWeight: 400,
482
+ color: 'var(--notion-text-secondary)',
483
+ fontFamily: 'var(--notion-font-sans)',
484
+ background: 'transparent',
485
+ border: 'none',
486
+ padding: '2px 6px',
487
+ borderRadius: 'var(--notion-radius-sm)',
488
+ cursor: item.onClick ? 'pointer' : 'default',
489
+ transition: 'background 100ms ease-out, color 100ms ease-out',
490
+ }}
491
+ onMouseEnter={e => {
492
+ if (!item.onClick) return;
493
+ (e.currentTarget as HTMLButtonElement).style.background = 'var(--notion-bg-hover)';
494
+ (e.currentTarget as HTMLButtonElement).style.color = 'var(--notion-text-primary)';
495
+ }}
496
+ onMouseLeave={e => {
497
+ (e.currentTarget as HTMLButtonElement).style.background = 'transparent';
498
+ (e.currentTarget as HTMLButtonElement).style.color = 'var(--notion-text-secondary)';
499
+ }}
500
+ >
501
+ {item.label}
502
+ </button>
503
+ )}
504
+ {!isLast && (
505
+ <span
506
+ aria-hidden="true"
507
+ style={{
508
+ color: 'var(--notion-text-muted)',
509
+ fontSize: '12px',
510
+ lineHeight: 1,
511
+ userSelect: 'none',
512
+ }}
513
+ >
514
+ /
515
+ </span>
516
+ )}
517
+ </li>
518
+ );
519
+ })}
520
+ </ol>
521
+ </nav>
522
+ );
523
+ }
524
+ ```
525
+
526
+ ---
527
+
528
+ <!-- Generated by Layout — layout.design -->
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "notion-lite",
3
+ "version": "1.0.0",
4
+ "displayName": "Notion",
5
+ "description": "Content-first, block-based design system inspired by Notion",
6
+ "source": "website-extraction",
7
+ "tier": "free",
8
+ "tokenCount": 22,
9
+ "componentCount": 5,
10
+ "aesthetic": "Light, content-first, block-based",
11
+ "layoutUrl": "https://layout.design/kits/notion"
12
+ }
@@ -0,0 +1,50 @@
1
+ /* Notion Lite — Design Tokens */
2
+ /* Generated by Layout — layout.design */
3
+
4
+ :root {
5
+ /* Backgrounds */
6
+ --notion-bg-app: #FFFFFF;
7
+ --notion-bg-surface: #F7F6F3;
8
+ --notion-bg-hover: #EEEEE9;
9
+ --notion-bg-selected: #E8E7E3;
10
+
11
+ /* Borders */
12
+ --notion-border: rgba(55, 53, 47, 0.09);
13
+ --notion-border-strong: rgba(55, 53, 47, 0.18);
14
+
15
+ /* Text */
16
+ --notion-text-primary: #37352F;
17
+ --notion-text-secondary: #787774;
18
+ --notion-text-muted: #9B9A97;
19
+ --notion-text-placeholder: rgba(55, 53, 47, 0.4);
20
+
21
+ /* Accent */
22
+ --notion-accent: #2383E2;
23
+ --notion-accent-hover: #1E78D3;
24
+ --notion-accent-subtle: rgba(35, 131, 226, 0.1);
25
+
26
+ /* Callout backgrounds */
27
+ --notion-callout-blue: rgba(35, 131, 226, 0.1);
28
+ --notion-callout-yellow: rgba(255, 184, 0, 0.14);
29
+ --notion-callout-green: rgba(15, 123, 108, 0.1);
30
+ --notion-callout-red: rgba(235, 87, 87, 0.1);
31
+ --notion-callout-gray: rgba(55, 53, 47, 0.06);
32
+
33
+ /* Typography */
34
+ --notion-font-sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
35
+ --notion-font-serif: Georgia, 'Times New Roman', serif;
36
+ --notion-font-mono: 'SFMono-Regular', Menlo, Consolas, monospace;
37
+
38
+ /* Spacing */
39
+ --notion-space-2xs: 2px;
40
+ --notion-space-xs: 4px;
41
+ --notion-space-sm: 8px;
42
+ --notion-space-md: 16px;
43
+ --notion-space-lg: 24px;
44
+ --notion-space-xl: 32px;
45
+
46
+ /* Radius */
47
+ --notion-radius-sm: 3px;
48
+ --notion-radius-md: 4px;
49
+ --notion-radius-lg: 6px;
50
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "$schema": "https://tr.designtokens.org/format/",
3
+ "color": {
4
+ "bg": {
5
+ "app": { "$type": "color", "$value": "#FFFFFF" },
6
+ "surface": { "$type": "color", "$value": "#F7F6F3" },
7
+ "hover": { "$type": "color", "$value": "#EEEEE9" },
8
+ "selected": { "$type": "color", "$value": "#E8E7E3" }
9
+ },
10
+ "border": {
11
+ "default": { "$type": "color", "$value": "rgba(55, 53, 47, 0.09)" },
12
+ "strong": { "$type": "color", "$value": "rgba(55, 53, 47, 0.18)" }
13
+ },
14
+ "text": {
15
+ "primary": { "$type": "color", "$value": "#37352F" },
16
+ "secondary": { "$type": "color", "$value": "#787774" },
17
+ "muted": { "$type": "color", "$value": "#9B9A97" },
18
+ "placeholder": { "$type": "color", "$value": "rgba(55, 53, 47, 0.4)" }
19
+ },
20
+ "accent": {
21
+ "default": { "$type": "color", "$value": "#2383E2" },
22
+ "hover": { "$type": "color", "$value": "#1E78D3" },
23
+ "subtle": { "$type": "color", "$value": "rgba(35, 131, 226, 0.1)" }
24
+ },
25
+ "callout": {
26
+ "blue": { "$type": "color", "$value": "rgba(35, 131, 226, 0.1)" },
27
+ "yellow": { "$type": "color", "$value": "rgba(255, 184, 0, 0.14)" },
28
+ "green": { "$type": "color", "$value": "rgba(15, 123, 108, 0.1)" },
29
+ "red": { "$type": "color", "$value": "rgba(235, 87, 87, 0.1)" },
30
+ "gray": { "$type": "color", "$value": "rgba(55, 53, 47, 0.06)" }
31
+ }
32
+ },
33
+ "font": {
34
+ "sans": { "$type": "fontFamily", "$value": ["ui-sans-serif", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "sans-serif"] },
35
+ "serif": { "$type": "fontFamily", "$value": ["Georgia", "Times New Roman", "serif"] },
36
+ "mono": { "$type": "fontFamily", "$value": ["SFMono-Regular", "Menlo", "Consolas", "monospace"] }
37
+ },
38
+ "spacing": {
39
+ "2xs": { "$type": "dimension", "$value": "2px" },
40
+ "xs": { "$type": "dimension", "$value": "4px" },
41
+ "sm": { "$type": "dimension", "$value": "8px" },
42
+ "md": { "$type": "dimension", "$value": "16px" },
43
+ "lg": { "$type": "dimension", "$value": "24px" },
44
+ "xl": { "$type": "dimension", "$value": "32px" }
45
+ },
46
+ "borderRadius": {
47
+ "sm": { "$type": "dimension", "$value": "3px" },
48
+ "md": { "$type": "dimension", "$value": "4px" },
49
+ "lg": { "$type": "dimension", "$value": "6px" }
50
+ }
51
+ }