@gogitcms/design-system 0.15.0-next.3

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 (70) hide show
  1. package/README.md +77 -0
  2. package/css/components.css +312 -0
  3. package/css/tokens.css +212 -0
  4. package/package.json +65 -0
  5. package/src/ThemeProvider.tsx +86 -0
  6. package/src/__tests__/ApplyChangesModal.test.tsx +148 -0
  7. package/src/__tests__/BranchImport.test.tsx +46 -0
  8. package/src/__tests__/Button.test.tsx +45 -0
  9. package/src/__tests__/ChangeRequestSummary.test.tsx +57 -0
  10. package/src/__tests__/ContentBrowser.changes.test.tsx +611 -0
  11. package/src/__tests__/ContentBrowser.collab.test.tsx +322 -0
  12. package/src/__tests__/ContentBrowser.collabsync.test.tsx +264 -0
  13. package/src/__tests__/ContentBrowser.contentslot.test.tsx +53 -0
  14. package/src/__tests__/ContentBrowser.discriminator.test.tsx +142 -0
  15. package/src/__tests__/ContentBrowser.drafts.test.tsx +271 -0
  16. package/src/__tests__/ContentBrowser.fields.test.tsx +117 -0
  17. package/src/__tests__/ContentBrowser.media.test.tsx +140 -0
  18. package/src/__tests__/ContentBrowser.mixedcollab.test.tsx +63 -0
  19. package/src/__tests__/ContentBrowser.mixedvalues.test.tsx +38 -0
  20. package/src/__tests__/ContentBrowser.pagination.test.tsx +62 -0
  21. package/src/__tests__/ContentBrowser.previewtab.test.tsx +212 -0
  22. package/src/__tests__/ContentBrowser.reorder.test.tsx +45 -0
  23. package/src/__tests__/ContentBrowser.search.test.tsx +135 -0
  24. package/src/__tests__/ContentBrowser.selectvalue.test.tsx +185 -0
  25. package/src/__tests__/ContentBrowser.staged.test.tsx +132 -0
  26. package/src/__tests__/ContentBrowser.usermenu.test.tsx +56 -0
  27. package/src/__tests__/MediaBrowser.test.tsx +353 -0
  28. package/src/__tests__/MediaField.test.tsx +185 -0
  29. package/src/__tests__/Notifications.test.tsx +69 -0
  30. package/src/__tests__/Onboarding.test.tsx +287 -0
  31. package/src/__tests__/cssTokens.test.ts +201 -0
  32. package/src/__tests__/fieldComponents.test.ts +43 -0
  33. package/src/__tests__/reorder.test.ts +58 -0
  34. package/src/components/ApplyChangesModal.tsx +348 -0
  35. package/src/components/BranchImport.tsx +157 -0
  36. package/src/components/BranchMenu.tsx +192 -0
  37. package/src/components/Button.tsx +131 -0
  38. package/src/components/ChangeDetail.tsx +472 -0
  39. package/src/components/ChangeRequestSummary.tsx +173 -0
  40. package/src/components/CollabField.tsx +388 -0
  41. package/src/components/ContentBrowser.tsx +5073 -0
  42. package/src/components/Icon.tsx +28 -0
  43. package/src/components/Icon.web.tsx +31 -0
  44. package/src/components/Input.tsx +106 -0
  45. package/src/components/MediaBrowser.tsx +766 -0
  46. package/src/components/MediaField.tsx +670 -0
  47. package/src/components/MediaPreview.tsx +91 -0
  48. package/src/components/MediaPreview.web.tsx +169 -0
  49. package/src/components/NavRow.tsx +105 -0
  50. package/src/components/Notifications.tsx +301 -0
  51. package/src/components/Onboarding.tsx +751 -0
  52. package/src/components/ProjectMenu.tsx +124 -0
  53. package/src/components/Segment.tsx +87 -0
  54. package/src/components/Skeleton.tsx +216 -0
  55. package/src/components/Spinner.tsx +44 -0
  56. package/src/components/Text.tsx +85 -0
  57. package/src/components/documentDrafts.ts +213 -0
  58. package/src/components/layout.tsx +284 -0
  59. package/src/components/primitives.tsx +143 -0
  60. package/src/components/reorder.ts +40 -0
  61. package/src/fieldComponents.ts +63 -0
  62. package/src/icons.ts +102 -0
  63. package/src/index.ts +198 -0
  64. package/src/media.ts +229 -0
  65. package/src/theme.ts +116 -0
  66. package/src/web/Button.tsx +110 -0
  67. package/src/web/Icon.tsx +52 -0
  68. package/src/web/Input.tsx +39 -0
  69. package/src/web/index.ts +43 -0
  70. package/src/web/primitives.tsx +119 -0
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # @gogitcms/design-system
2
+
3
+ The **Go·Git CMS** design system — monochrome, terminal-adjacent, desktop-first.
4
+ Authored once against React Native primitives and consumed as source, so the
5
+ same components render:
6
+
7
+ - **natively** in the Expo mobile app (`react-native`),
8
+ - **on the web** in the Wails desktop app and the SPA frontend (`react-native-web`).
9
+
10
+ ## Foundations
11
+
12
+ - **`theme.ts`** — a single neutral **ink ramp** (light + dark) carries the whole
13
+ UI; the only chromatic tokens are the git **diff signals** (add green / del red).
14
+ Plus spacing (4px grid), radius (3/5/8), typography (Geist / Geist Mono), and
15
+ control/layout dimensions.
16
+ - **`ThemeProvider` / `useTheme` / `useThemeMode`** — theme context following the
17
+ system color scheme with a manual toggle (`<ThemeToggle/>`). Hooks fall back to
18
+ the light theme when no provider is mounted, so components never crash in isolation.
19
+ - **`useResponsive()`** — `{ isDesktop, isMobile, width }` from
20
+ `useWindowDimensions`. This is how one component picks the desktop vs mobile
21
+ layout on **every** platform — no CSS media queries needed. Breakpoint:
22
+ `DESKTOP_BREAKPOINT` (900px).
23
+
24
+ ## Components
25
+
26
+ | Group | Components |
27
+ |---|---|
28
+ | Typography | `Text` (display/h1–h3/body/mono/label variants) |
29
+ | Forms | `Button` (primary/default/ghost/danger × sm/md/lg), `IconButton`, `Input` |
30
+ | Data display | `Card`, `Badge`, `DiffStat`, `Avatar`, `Divider`, `SectionLabel`, `NavRow` |
31
+ | Icons | `Icon` — Lucide-style line icons, platform-split: raw `<svg>` on web, `react-native-svg` on native |
32
+ | Layout | `Screen`, `TopBar`, `Pane`, `AppShell`, `MobileScreen`, `ThemeToggle` |
33
+ | Templates | `ContentBrowser` — responsive CMS browser (desktop multi-pane ↔ mobile drill-down) |
34
+
35
+ ### Icons are platform-split
36
+
37
+ `Icon.web.tsx` renders a raw `<svg>` (valid inside the react-native-web DOM);
38
+ `Icon.tsx` uses `react-native-svg`. Bundlers resolve the right one automatically
39
+ (Vite → `.web.tsx`, Metro → `.tsx`), so web apps never pull in `react-native-svg`
40
+ (it's an **optional** peer dependency, needed only by native consumers).
41
+
42
+ ## Responsive across all three targets
43
+
44
+ `ContentBrowser` is the whole story: it calls `useResponsive()` and renders
45
+ `AppShell` (sidebar → entries → editor panes) at desktop widths or `MobileScreen`
46
+ (drill-down list → entries → entry) below the breakpoint.
47
+
48
+ ```tsx
49
+ import { ThemeProvider, ContentBrowser } from "@gogitcms/design-system";
50
+
51
+ <ThemeProvider>
52
+ <ContentBrowser
53
+ workspace={{ name: "Acme Docs", initials: "AD", branch: "main", changed: 4 }}
54
+ sections={sections} /* nav items with icons + counts */
55
+ activeNavKey={active}
56
+ onSelectNav={setActive}
57
+ entries={entries} /* { path, status, added, removed, title, body } */
58
+ userInitials="ED"
59
+ onSignOut={signOut}
60
+ />
61
+ </ThemeProvider>
62
+ ```
63
+
64
+ - **Mobile app** — the viewport is always narrow → native mobile drill-down.
65
+ - **Desktop app** — a wide window → the multi-pane power layout.
66
+ - **SPA frontend** — switches between the two live as the browser resizes.
67
+
68
+ ## Fonts
69
+
70
+ On the web, load Geist + Geist Mono via a `<link>` in the host page (see the apps'
71
+ `index.html`). On native they fall back to the platform system + monospace fonts;
72
+ add the font files via `expo-font` to get Geist on device.
73
+
74
+ ## Testing
75
+
76
+ `pnpm test` renders the components through react-native-web in jsdom (the same
77
+ path the web apps use), including the web `Icon`. Run from the package root.
@@ -0,0 +1,312 @@
1
+ /* Go Git CMS — component styles for web surfaces.
2
+ *
3
+ * The companion to ../src/web/*.tsx. Those components only pick class names;
4
+ * every visual decision lives here so a button renders correctly from server
5
+ * HTML alone, with no hydration. Depends on tokens.css.
6
+ *
7
+ * Hover and press are CSS states rather than React state on purpose — the docs
8
+ * site ships most of these as static markup.
9
+ */
10
+
11
+ /* ── Button ──────────────────────────────────────────────────────────────── */
12
+
13
+ .ds-btn {
14
+ display: inline-flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+ gap: var(--space-1);
18
+ height: var(--control-md);
19
+ padding: 0 var(--space-4);
20
+ font-family: var(--font-sans);
21
+ font-size: var(--fs-body);
22
+ font-weight: var(--fw-medium);
23
+ line-height: 1;
24
+ white-space: nowrap;
25
+ text-decoration: none;
26
+ border: 1px solid transparent;
27
+ border-radius: var(--radius-md);
28
+ cursor: pointer;
29
+ transition:
30
+ background var(--dur-fast) var(--ease-standard),
31
+ border-color var(--dur-fast) var(--ease-standard),
32
+ opacity var(--dur-fast) var(--ease-standard);
33
+ }
34
+
35
+ .ds-btn:focus-visible {
36
+ outline: none;
37
+ box-shadow: var(--focus-ring);
38
+ }
39
+
40
+ .ds-btn[disabled],
41
+ .ds-btn[aria-disabled="true"] {
42
+ opacity: 0.4;
43
+ cursor: not-allowed;
44
+ }
45
+
46
+ .ds-btn--sm {
47
+ height: var(--control-sm);
48
+ padding: 0 var(--space-3);
49
+ font-size: var(--fs-sm);
50
+ }
51
+ .ds-btn--lg {
52
+ height: var(--control-lg);
53
+ }
54
+ .ds-btn--full {
55
+ width: 100%;
56
+ }
57
+
58
+ .ds-btn--primary {
59
+ background: var(--surface-inverted);
60
+ color: var(--text-inverted);
61
+ }
62
+ .ds-btn--primary:not([disabled]):hover {
63
+ background: var(--ink-900);
64
+ }
65
+ .ds-btn--primary:not([disabled]):active {
66
+ background: var(--ink-800);
67
+ }
68
+
69
+ .ds-btn--default {
70
+ background: var(--surface-raised);
71
+ color: var(--text-primary);
72
+ border-color: var(--border-default);
73
+ }
74
+ .ds-btn--default:not([disabled]):hover {
75
+ background: var(--surface-hover);
76
+ border-color: var(--border-hover);
77
+ }
78
+ .ds-btn--default:not([disabled]):active {
79
+ background: var(--surface-active);
80
+ }
81
+
82
+ .ds-btn--ghost {
83
+ background: transparent;
84
+ color: var(--text-primary);
85
+ }
86
+ .ds-btn--ghost:not([disabled]):hover {
87
+ background: var(--surface-hover);
88
+ }
89
+ .ds-btn--ghost:not([disabled]):active {
90
+ background: var(--surface-active);
91
+ }
92
+
93
+ .ds-btn--danger {
94
+ background: transparent;
95
+ color: var(--diff-del-fg);
96
+ border-color: var(--border-default);
97
+ }
98
+ .ds-btn--danger:not([disabled]):hover,
99
+ .ds-btn--danger:not([disabled]):active {
100
+ background: var(--diff-del-bg);
101
+ }
102
+
103
+ /* An anchor styled as a button is a button: no link underline, and no hover
104
+ fade, since the background shift already answers the hover. */
105
+ a.ds-btn {
106
+ text-decoration: none;
107
+ }
108
+ a.ds-btn:hover {
109
+ opacity: 1;
110
+ }
111
+
112
+ /* ── Icon button ─────────────────────────────────────────────────────────── */
113
+
114
+ .ds-iconbtn {
115
+ display: inline-flex;
116
+ align-items: center;
117
+ justify-content: center;
118
+ width: var(--control-md);
119
+ height: var(--control-md);
120
+ padding: 0;
121
+ color: var(--text-secondary);
122
+ background: var(--surface-raised);
123
+ border: 1px solid var(--border-default);
124
+ border-radius: var(--radius-md);
125
+ cursor: pointer;
126
+ transition:
127
+ border-color var(--dur-fast) var(--ease-standard),
128
+ background var(--dur-fast) var(--ease-standard);
129
+ }
130
+ .ds-iconbtn:hover {
131
+ border-color: var(--border-hover);
132
+ }
133
+ .ds-iconbtn:focus-visible {
134
+ outline: none;
135
+ box-shadow: var(--focus-ring);
136
+ }
137
+ .ds-iconbtn--sm {
138
+ width: var(--control-sm);
139
+ height: var(--control-sm);
140
+ }
141
+ .ds-iconbtn--bare {
142
+ width: auto;
143
+ height: auto;
144
+ background: none;
145
+ border: none;
146
+ }
147
+ .ds-iconbtn--bare:hover {
148
+ opacity: 0.6;
149
+ }
150
+
151
+ /* ── Badge ───────────────────────────────────────────────────────────────── */
152
+
153
+ .ds-badge {
154
+ display: inline-flex;
155
+ align-items: center;
156
+ gap: 5px;
157
+ height: 18px;
158
+ padding: 0 6px;
159
+ font-family: var(--font-mono);
160
+ font-size: var(--fs-mono-sm);
161
+ font-weight: var(--fw-medium);
162
+ line-height: 1;
163
+ white-space: nowrap;
164
+ border: 1px solid;
165
+ border-radius: var(--radius-sm);
166
+ }
167
+ .ds-badge--sans {
168
+ font-family: var(--font-sans);
169
+ }
170
+ .ds-badge--neutral {
171
+ background: var(--surface-sunken);
172
+ color: var(--text-secondary);
173
+ border-color: var(--border-subtle);
174
+ }
175
+ .ds-badge--add {
176
+ background: var(--diff-add-bg);
177
+ color: var(--diff-add-fg);
178
+ border-color: var(--diff-add-bg);
179
+ }
180
+ .ds-badge--del {
181
+ background: var(--diff-del-bg);
182
+ color: var(--diff-del-fg);
183
+ border-color: var(--diff-del-bg);
184
+ }
185
+ .ds-badge--strong {
186
+ background: var(--surface-inverted);
187
+ color: var(--text-inverted);
188
+ border-color: var(--surface-inverted);
189
+ }
190
+
191
+ /* ── Avatar ──────────────────────────────────────────────────────────────── */
192
+
193
+ .ds-avatar {
194
+ display: inline-flex;
195
+ align-items: center;
196
+ justify-content: center;
197
+ flex-shrink: 0;
198
+ font-family: var(--font-mono);
199
+ font-size: var(--fs-mono-sm);
200
+ font-weight: var(--fw-semibold);
201
+ line-height: 1;
202
+ color: var(--text-secondary);
203
+ background: var(--surface-sunken);
204
+ border: 1px solid var(--border-default);
205
+ border-radius: var(--radius-sm);
206
+ }
207
+
208
+ /* ── Card ────────────────────────────────────────────────────────────────── */
209
+
210
+ .ds-card {
211
+ background: var(--surface-raised);
212
+ border: 1px solid var(--border-default);
213
+ border-radius: var(--radius-md);
214
+ padding: var(--space-5);
215
+ }
216
+ .ds-card--sunken {
217
+ background: var(--surface-sunken);
218
+ }
219
+ .ds-card--interactive {
220
+ display: block;
221
+ width: 100%;
222
+ text-align: left;
223
+ cursor: pointer;
224
+ text-decoration: none;
225
+ color: inherit;
226
+ transition: border-color var(--dur-fast) var(--ease-standard);
227
+ }
228
+ .ds-card--interactive:hover {
229
+ border-color: var(--border-hover);
230
+ opacity: 1;
231
+ }
232
+ .ds-card--interactive:focus-visible {
233
+ outline: none;
234
+ box-shadow: var(--focus-ring);
235
+ }
236
+
237
+ /* ── Input ───────────────────────────────────────────────────────────────── */
238
+
239
+ .ds-input {
240
+ width: 100%;
241
+ height: var(--control-lg);
242
+ padding: 0 var(--space-3);
243
+ font-family: var(--font-sans);
244
+ font-size: var(--fs-body);
245
+ color: var(--text-primary);
246
+ background: var(--surface-raised);
247
+ border: 1px solid var(--border-default);
248
+ border-radius: var(--radius-md);
249
+ outline: none;
250
+ transition: border-color var(--dur-fast) var(--ease-standard);
251
+ }
252
+ .ds-input:hover {
253
+ border-color: var(--border-hover);
254
+ }
255
+ .ds-input:focus {
256
+ border-color: var(--border-focus);
257
+ }
258
+ .ds-input--mono {
259
+ font-family: var(--font-mono);
260
+ font-size: var(--fs-mono);
261
+ }
262
+ .ds-input--sm {
263
+ height: var(--control-md);
264
+ }
265
+
266
+ textarea.ds-input {
267
+ height: auto;
268
+ padding: var(--space-3);
269
+ line-height: var(--lh-body);
270
+ resize: vertical;
271
+ }
272
+
273
+ select.ds-input {
274
+ padding: 0 var(--space-2);
275
+ }
276
+
277
+ /* ── Section label ───────────────────────────────────────────────────────── */
278
+
279
+ /* The uppercase mono micro-label. Wide tracking is the brand tell — don't set
280
+ it in sentence case. */
281
+ .ds-label {
282
+ font-family: var(--font-mono);
283
+ font-size: var(--fs-xs);
284
+ line-height: var(--lh-xs);
285
+ letter-spacing: var(--ls-label);
286
+ text-transform: uppercase;
287
+ color: var(--text-tertiary);
288
+ }
289
+
290
+ /* ── Divider ─────────────────────────────────────────────────────────────── */
291
+
292
+ .ds-divider {
293
+ height: 1px;
294
+ border: 0;
295
+ margin: 0;
296
+ background: var(--border-subtle);
297
+ }
298
+ .ds-divider--vertical {
299
+ width: 1px;
300
+ height: 100%;
301
+ background: var(--border-default);
302
+ }
303
+
304
+ /* ── Mono metadata ───────────────────────────────────────────────────────── */
305
+
306
+ /* Paths, hashes, branches, timestamps, counts. */
307
+ .ds-meta {
308
+ font-family: var(--font-mono);
309
+ font-size: var(--fs-mono-sm);
310
+ line-height: var(--lh-mono-sm);
311
+ color: var(--text-tertiary);
312
+ }
package/css/tokens.css ADDED
@@ -0,0 +1,212 @@
1
+ /* Go Git CMS design tokens as CSS custom properties.
2
+ *
3
+ * This file is the CSS projection of ../src/theme.ts — the React Native theme
4
+ * object is still the source of truth. Every value here has a counterpart
5
+ * there, and __tests__/cssTokens.test.ts fails the build if the two drift.
6
+ * Reach for it from web surfaces that don't run react-native-web (the Astro
7
+ * docs site, marketing pages, e-mail templates); the SPAs and the mobile app
8
+ * keep consuming theme.ts directly.
9
+ *
10
+ * Monochrome by design: one neutral ink ramp carries the whole UI and the only
11
+ * chromatic tokens are the git diff signals.
12
+ */
13
+
14
+ :root {
15
+ /* Ink ramp — 0 is paper white, 1000 is near-black */
16
+ --ink-0: #ffffff;
17
+ --ink-50: #f7f7f7;
18
+ --ink-100: #ededed;
19
+ --ink-150: #e4e4e4;
20
+ --ink-200: #dcdcdc;
21
+ --ink-300: #c9c9c9;
22
+ --ink-400: #a6a6a6;
23
+ --ink-500: #808080;
24
+ --ink-600: #5c5c5c;
25
+ --ink-700: #3d3d3d;
26
+ --ink-800: #242424;
27
+ --ink-900: #151515;
28
+ --ink-1000: #0a0a0a;
29
+
30
+ /* Raised surfaces sit flush with the page in light mode and lift one step in
31
+ dark, where a pure-black card would disappear into the background. */
32
+ --surface-raised: var(--ink-0);
33
+ /* The top bar is permanent dark chrome in both modes. */
34
+ --surface-topbar: #1a1a1a;
35
+
36
+ /* Git diff signals — the only permitted color */
37
+ --diff-add-fg: #1a7f37;
38
+ --diff-add-bg: #e6f4ea;
39
+ --diff-add-line: #addab8;
40
+ --diff-del-fg: #b42318;
41
+ --diff-del-bg: #fbeae8;
42
+ --diff-del-line: #f0b7b1;
43
+
44
+ color-scheme: light;
45
+ }
46
+
47
+ /* Dark is the same semantic mapping over an inverted ramp. Scope it to
48
+ [data-theme="dark"] (or .dark) on any container — usually <html>. */
49
+ [data-theme="dark"],
50
+ .dark {
51
+ --ink-0: #0b0b0b;
52
+ --ink-50: #151515;
53
+ --ink-100: #1e1e1e;
54
+ --ink-150: #242424;
55
+ --ink-200: #2d2d2d;
56
+ --ink-300: #3a3a3a;
57
+ --ink-400: #585858;
58
+ --ink-500: #808080;
59
+ --ink-600: #a2a2a2;
60
+ --ink-700: #c4c4c4;
61
+ --ink-800: #dcdcdc;
62
+ --ink-900: #ececec;
63
+ --ink-1000: #f4f4f4;
64
+
65
+ --surface-raised: var(--ink-50);
66
+ --surface-topbar: #1e1e1e;
67
+
68
+ --diff-add-fg: #3fb950;
69
+ --diff-add-bg: #12261a;
70
+ --diff-add-line: #1f5132;
71
+ --diff-del-fg: #f85149;
72
+ --diff-del-bg: #2a1615;
73
+ --diff-del-line: #6a2b28;
74
+
75
+ color-scheme: dark;
76
+ }
77
+
78
+ /* Semantic aliases are declared for both scopes rather than at :root alone.
79
+ A var() alias resolves against the element it is *declared* on, so a :root-only
80
+ alias keeps pointing at the light ramp whenever [data-theme] sits on a nested
81
+ container instead of <html>. Repeating the block makes scoped dark islands
82
+ (a dark top bar over a light page) work. */
83
+ :root,
84
+ [data-theme="dark"],
85
+ .dark {
86
+ /* Text */
87
+ --text-primary: var(--ink-1000);
88
+ --text-secondary: var(--ink-600);
89
+ --text-tertiary: var(--ink-500);
90
+ --text-disabled: var(--ink-400);
91
+ --text-inverted: var(--ink-0);
92
+ --text-link: var(--ink-1000);
93
+
94
+ /* Surfaces */
95
+ --surface-page: var(--ink-0);
96
+ --surface-sunken: var(--ink-50);
97
+ --surface-hover: var(--ink-50);
98
+ --surface-active: var(--ink-100);
99
+ --surface-inverted: var(--ink-1000);
100
+ --surface-overlay: rgba(10, 10, 10, 0.45);
101
+
102
+ /* Borders — hairlines carry structure, not shadows */
103
+ --border-subtle: var(--ink-100);
104
+ --border-default: var(--ink-200);
105
+ --border-hover: var(--ink-400);
106
+ --border-strong: var(--ink-1000);
107
+ --border-focus: var(--ink-1000);
108
+ /* Active column/tab rule. Mid-gray in both modes: it sits directly under the
109
+ dark top bar, where near-black merges into the bar and white glares. */
110
+ --border-active: var(--ink-600);
111
+
112
+ /* Selection */
113
+ --selection-bg: var(--ink-1000);
114
+ --selection-fg: var(--ink-0);
115
+ }
116
+
117
+ :root {
118
+ /* Type — Geist for UI and prose, Geist Mono for every technical string:
119
+ paths, hashes, branch names, timestamps, code, uppercase micro-labels. */
120
+ --font-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
121
+ --font-mono: "Geist Mono", ui-monospace, "SF Mono", "Menlo", "Consolas", monospace;
122
+
123
+ --fw-light: 300;
124
+ --fw-regular: 400;
125
+ --fw-medium: 500;
126
+ --fw-semibold: 600;
127
+ --fw-bold: 700;
128
+
129
+ --fs-display: 40px;
130
+ --lh-display: 44px;
131
+ --fs-h1: 28px;
132
+ --lh-h1: 34px;
133
+ --fs-h2: 22px;
134
+ --lh-h2: 28px;
135
+ --fs-h3: 17px;
136
+ --lh-h3: 24px;
137
+ --fs-body: 14px;
138
+ --lh-body: 21px;
139
+ --fs-body-lg: 16px;
140
+ --lh-body-lg: 24px;
141
+ --fs-sm: 13px;
142
+ --lh-sm: 18px;
143
+ --fs-xs: 11px;
144
+ --lh-xs: 16px;
145
+ --fs-mono: 13px;
146
+ --lh-mono: 20px;
147
+ --fs-mono-sm: 12px;
148
+ --lh-mono-sm: 18px;
149
+
150
+ --ls-tight: -0.4px;
151
+ --ls-normal: 0;
152
+ --ls-wide: 0.3px;
153
+ --ls-label: 0.9px;
154
+
155
+ /* Spacing — 4px base grid */
156
+ --space-0: 0;
157
+ --space-1: 4px;
158
+ --space-2: 8px;
159
+ --space-3: 12px;
160
+ --space-4: 16px;
161
+ --space-5: 20px;
162
+ --space-6: 24px;
163
+ --space-8: 32px;
164
+ --space-10: 40px;
165
+ --space-12: 48px;
166
+ --space-16: 64px;
167
+ --space-20: 80px;
168
+ --space-24: 96px;
169
+
170
+ /* Radius — small and sharp; nothing rounder than a pill */
171
+ --radius-0: 0;
172
+ --radius-sm: 3px;
173
+ --radius-md: 5px;
174
+ --radius-lg: 8px;
175
+ --radius-pill: 999px;
176
+
177
+ /* Control heights */
178
+ --control-sm: 28px;
179
+ --control-md: 34px;
180
+ --control-lg: 40px;
181
+
182
+ /* Layout dims */
183
+ --sidebar-w: 260px;
184
+ --column-w: 300px;
185
+ --topbar-h: 48px;
186
+ --container: 1200px;
187
+
188
+ /* Elevation — overlays only. Cards are defined by a border. */
189
+ --shadow-none: none;
190
+ --shadow-sm: 0 1px 2px rgba(10, 10, 10, 0.06);
191
+ --shadow-md: 0 4px 12px rgba(10, 10, 10, 0.1);
192
+ --shadow-lg: 0 12px 32px rgba(10, 10, 10, 0.14);
193
+
194
+ /* Motion — fast and restrained, no overshoot */
195
+ --ease-standard: cubic-bezier(0.2, 0, 0.1, 1);
196
+ --dur-fast: 90ms;
197
+ --dur-base: 150ms;
198
+ --dur-slow: 240ms;
199
+
200
+ /* Focus — a crisp near-black ring offset by the page color, never a glow */
201
+ --focus-ring: 0 0 0 2px var(--surface-page), 0 0 0 4px var(--ink-1000);
202
+
203
+ /* Responsive breakpoint, mirroring DESKTOP_BREAKPOINT in theme.ts. Custom
204
+ properties can't be used in a media query, so this is documentation for
205
+ humans; the queries themselves hard-code 900px. */
206
+ --desktop-breakpoint: 900px;
207
+ }
208
+
209
+ ::selection {
210
+ background: var(--selection-bg);
211
+ color: var(--selection-fg);
212
+ }
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@gogitcms/design-system",
3
+ "version": "0.15.0-next.3",
4
+ "main": "src/index.ts",
5
+ "types": "src/index.ts",
6
+ "// exports": "The root entry is the react-native source the SPAs, desktop app and mobile app consume. ./web is the plain-DOM build for server-rendered surfaces (the Astro docs site) that don't run react-native-web, and ./css ships the tokens as custom properties. The trailing wildcard keeps deep paths resolvable — plugin bundling and the Vite aliases reach into src/ directly.",
7
+ "exports": {
8
+ ".": "./src/index.ts",
9
+ "./web": "./src/web/index.ts",
10
+ "./css/tokens.css": "./css/tokens.css",
11
+ "./css/components.css": "./css/components.css",
12
+ "./package.json": "./package.json",
13
+ "./*": "./*"
14
+ },
15
+ "sideEffects": [
16
+ "*.css"
17
+ ],
18
+ "peerDependencies": {
19
+ "react": "*",
20
+ "react-native": "*",
21
+ "react-native-svg": "*"
22
+ },
23
+ "peerDependenciesMeta": {
24
+ "react-native-svg": {
25
+ "optional": true
26
+ },
27
+ "react-native": {
28
+ "optional": true
29
+ }
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/go-git-cms/gogitcms.git",
34
+ "directory": "packages/design-system"
35
+ },
36
+ "scripts": {
37
+ "test": "jest",
38
+ "typecheck": "tsc --noEmit -p tsconfig.json"
39
+ },
40
+ "devDependencies": {
41
+ "@babel/core": "^7.25.2",
42
+ "@babel/preset-env": "^7.25.4",
43
+ "@babel/preset-react": "^7.24.7",
44
+ "@babel/preset-typescript": "^7.24.7",
45
+ "@testing-library/jest-dom": "^6.4.8",
46
+ "@testing-library/react": "^16.0.1",
47
+ "@types/jest": "^29.5.14",
48
+ "@types/node": "^22.20.1",
49
+ "@types/react": "^19.0.0",
50
+ "babel-jest": "^29.7.0",
51
+ "jest": "^29.7.0",
52
+ "jest-environment-jsdom": "^29.7.0",
53
+ "react": "^19.2.0",
54
+ "react-dom": "^19.2.0",
55
+ "react-native-web": "^0.21.2",
56
+ "typescript": "^5.5.4"
57
+ },
58
+ "files": [
59
+ "src",
60
+ "css"
61
+ ],
62
+ "publishConfig": {
63
+ "access": "public"
64
+ }
65
+ }