@adea-ai/ui 0.105.0 → 0.106.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/README.md +44 -8
- package/dist/components/composites/action-button/action-button.d.ts.map +1 -1
- package/dist/components/composites/action-button/action-button.js +6 -8
- package/dist/components/composites/action-button/action-button.js.map +1 -1
- package/dist/components/composites/appearance-editor/accent-swatch-groups.d.ts +16 -0
- package/dist/components/composites/appearance-editor/accent-swatch-groups.d.ts.map +1 -0
- package/dist/components/composites/appearance-editor/accent-swatch-groups.js +151 -0
- package/dist/components/composites/appearance-editor/accent-swatch-groups.js.map +1 -0
- package/dist/components/composites/appearance-editor/appearance-choices.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-choices.js +24 -84
- package/dist/components/composites/appearance-editor/appearance-choices.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.d.ts +2 -2
- package/dist/components/composites/appearance-editor/appearance-editor.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-editor.js +25 -7
- package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
- package/dist/components/composites/appearance-editor/appearance-types.d.ts +9 -0
- package/dist/components/composites/appearance-editor/appearance-types.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/font-settings-group.d.ts +10 -0
- package/dist/components/composites/appearance-editor/font-settings-group.d.ts.map +1 -0
- package/dist/components/composites/appearance-editor/font-settings-group.js +310 -0
- package/dist/components/composites/appearance-editor/font-settings-group.js.map +1 -0
- package/dist/components/composites/appearance-editor/index.d.ts +2 -0
- package/dist/components/composites/appearance-editor/index.d.ts.map +1 -1
- package/dist/components/composites/appearance-editor/index.js +3 -1
- package/dist/components/composites/update-dialog/update-dialog.js +2 -2
- package/dist/components/composites/update-dialog/update-dialog.js.map +1 -1
- package/dist/components/conversation/message-row.d.ts.map +1 -1
- package/dist/components/conversation/message-row.js +3 -3
- package/dist/components/conversation/message-row.js.map +1 -1
- package/dist/components/conversation/paste-token-editor.js +1 -1
- package/dist/components/conversation/paste-token-editor.js.map +1 -1
- package/dist/components/layout/side-rail/side-rail.js +2 -2
- package/dist/components/layout/side-rail/side-rail.js.map +1 -1
- package/dist/components/layout/top-bar/top-bar.js +1 -1
- package/dist/components/layout/top-bar/top-bar.js.map +1 -1
- package/dist/components/theme/appearance-panel.d.ts +1 -1
- package/dist/components/theme/appearance-panel.d.ts.map +1 -1
- package/dist/components/theme/appearance-panel.js +45 -105
- package/dist/components/theme/appearance-panel.js.map +1 -1
- package/dist/components/theme/theme-provider.d.ts +5 -2
- package/dist/components/theme/theme-provider.d.ts.map +1 -1
- package/dist/components/theme/theme-provider.js +38 -19
- package/dist/components/theme/theme-provider.js.map +1 -1
- package/dist/components/ui/code-block/code-block.d.ts +3 -3
- package/dist/components/ui/code-block/code-block.js +6 -6
- package/dist/components/ui/code-block/code-block.js.map +1 -1
- package/dist/components/ui/command/command.js +1 -1
- package/dist/components/ui/command/command.js.map +1 -1
- package/dist/components/ui/context-menu/context-menu.js +1 -1
- package/dist/components/ui/context-menu/context-menu.js.map +1 -1
- package/dist/components/ui/diff-block/diff-block.js +5 -5
- package/dist/components/ui/diff-block/diff-block.js.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.js +101 -8
- package/dist/components/ui/dropdown-menu/dropdown-menu.js.map +1 -1
- package/dist/components/ui/kbd/kbd.js +1 -1
- package/dist/components/ui/kbd/kbd.js.map +1 -1
- package/dist/components/ui/menubar/menubar.js +1 -1
- package/dist/components/ui/menubar/menubar.js.map +1 -1
- package/dist/components/ui/typography/typography.d.ts +3 -5
- package/dist/components/ui/typography/typography.d.ts.map +1 -1
- package/dist/components/ui/typography/typography.js +6 -8
- package/dist/components/ui/typography/typography.js.map +1 -1
- package/dist/index.js +6 -3
- package/dist/lib/appearance-font-settings.d.ts +53 -0
- package/dist/lib/appearance-font-settings.d.ts.map +1 -0
- package/dist/lib/appearance-font-settings.js +160 -0
- package/dist/lib/appearance-font-settings.js.map +1 -0
- package/dist/lib/font-catalog.d.ts +72 -0
- package/dist/lib/font-catalog.d.ts.map +1 -0
- package/dist/lib/font-catalog.js +71 -0
- package/dist/lib/font-catalog.js.map +1 -0
- package/dist/lib/safe-script.d.ts +3 -0
- package/dist/lib/safe-script.d.ts.map +1 -0
- package/dist/lib/safe-script.js +9 -0
- package/dist/lib/safe-script.js.map +1 -0
- package/dist/lib/tokens.d.ts +2 -19
- package/dist/lib/tokens.d.ts.map +1 -1
- package/dist/lib/tokens.js +63 -39
- package/dist/lib/tokens.js.map +1 -1
- package/dist/r/appearance-editor.json +11 -0
- package/dist/r/lib.json +15 -0
- package/dist/r/registry.json +33 -0
- package/dist/r/src/components/composites/action-button/action-button.tsx +2 -1
- package/dist/r/src/components/composites/appearance-editor/accent-swatch-groups.tsx +147 -0
- package/dist/r/src/components/composites/appearance-editor/appearance-choices.tsx +17 -74
- package/dist/r/src/components/composites/appearance-editor/appearance-editor.tsx +19 -6
- package/dist/r/src/components/composites/appearance-editor/appearance-types.ts +9 -0
- package/dist/r/src/components/composites/appearance-editor/font-settings-group.tsx +350 -0
- package/dist/r/src/components/composites/appearance-editor/index.ts +19 -0
- package/dist/r/src/components/composites/update-dialog/update-dialog.tsx +2 -2
- package/dist/r/src/components/conversation/message-row.tsx +7 -3
- package/dist/r/src/components/conversation/paste-token-editor.tsx +1 -1
- package/dist/r/src/components/layout/side-rail/side-rail.tsx +3 -3
- package/dist/r/src/components/layout/top-bar/top-bar.tsx +1 -1
- package/dist/r/src/components/theme/appearance-panel.tsx +34 -83
- package/dist/r/src/components/theme/theme-provider.tsx +50 -20
- package/dist/r/src/components/ui/code-block/code-block.tsx +6 -6
- package/dist/r/src/components/ui/command/command.tsx +1 -1
- package/dist/r/src/components/ui/context-menu/context-menu.tsx +1 -1
- package/dist/r/src/components/ui/diff-block/diff-block.tsx +7 -7
- package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +145 -7
- package/dist/r/src/components/ui/kbd/kbd.tsx +1 -1
- package/dist/r/src/components/ui/menubar/menubar.tsx +1 -1
- package/dist/r/src/components/ui/typography/typography.tsx +6 -8
- package/dist/r/src/lib/appearance-font-settings.ts +233 -0
- package/dist/r/src/lib/font-catalog.ts +80 -0
- package/dist/r/src/lib/safe-script.ts +7 -0
- package/dist/r/src/lib/tokens.ts +64 -59
- package/dist/r/src/styles/appearance-font-settings.css +110 -0
- package/dist/r/src/styles/fonts.css +4 -5
- package/dist/r/src/styles/globals.css +4 -1
- package/dist/r/src/styles/theme.css +14 -0
- package/dist/r/theme.json +5 -0
- package/dist/r/theming.json +2 -0
- package/package.json +2 -1
- package/registry.json +33 -0
- package/src/components/composites/action-button/action-button.tsx +2 -1
- package/src/components/composites/appearance-editor/accent-swatch-groups.tsx +147 -0
- package/src/components/composites/appearance-editor/appearance-choices.tsx +17 -74
- package/src/components/composites/appearance-editor/appearance-editor.tsx +19 -6
- package/src/components/composites/appearance-editor/appearance-types.ts +9 -0
- package/src/components/composites/appearance-editor/font-settings-group.tsx +350 -0
- package/src/components/composites/appearance-editor/index.ts +19 -0
- package/src/components/composites/update-dialog/update-dialog.tsx +2 -2
- package/src/components/conversation/message-row.tsx +7 -3
- package/src/components/conversation/paste-token-editor.tsx +1 -1
- package/src/components/layout/side-rail/side-rail.tsx +3 -3
- package/src/components/layout/top-bar/top-bar.tsx +1 -1
- package/src/components/theme/appearance-panel.tsx +34 -83
- package/src/components/theme/theme-provider.tsx +50 -20
- package/src/components/ui/code-block/code-block.tsx +6 -6
- package/src/components/ui/command/command.tsx +1 -1
- package/src/components/ui/context-menu/context-menu.tsx +1 -1
- package/src/components/ui/diff-block/diff-block.tsx +7 -7
- package/src/components/ui/dropdown-menu/dropdown-menu.tsx +145 -7
- package/src/components/ui/kbd/kbd.tsx +1 -1
- package/src/components/ui/menubar/menubar.tsx +1 -1
- package/src/components/ui/typography/typography.tsx +6 -8
- package/src/lib/appearance-font-settings.ts +233 -0
- package/src/lib/font-catalog.ts +80 -0
- package/src/lib/safe-script.ts +7 -0
- package/src/lib/tokens.ts +64 -59
- package/src/styles/appearance-font-settings.css +110 -0
- package/src/styles/fonts.css +4 -5
- package/src/styles/globals.css +4 -1
- package/src/styles/theme.css +14 -0
|
@@ -119,11 +119,9 @@ export function Heading<T extends ValidComponent = 'h2'>(props: HeadingProps<T>)
|
|
|
119
119
|
/**
|
|
120
120
|
* Text.
|
|
121
121
|
*
|
|
122
|
-
* Everything that is not a heading.
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* `micro` (11px, 500) is the floor — keyboard keys and the status bar. `code` is
|
|
126
|
-
* the mono face at 12px, for anything a user compares character by character.
|
|
122
|
+
* Everything that is not a heading. Body and strong copy use the content font
|
|
123
|
+
* axis; labels, captions and microcopy inherit the UI face. Code uses its own
|
|
124
|
+
* family and size axis for anything a user compares character by character.
|
|
127
125
|
*
|
|
128
126
|
* `tone` is a separate axis from `variant` because "secondary" is a colour
|
|
129
127
|
* decision, not a size: a muted caption and a muted body line are both common.
|
|
@@ -136,17 +134,17 @@ export const textVariants = cva('', {
|
|
|
136
134
|
variants: {
|
|
137
135
|
variant: {
|
|
138
136
|
/** 14px / 400. Body copy and descriptions. */
|
|
139
|
-
body: 'text-
|
|
137
|
+
body: 'font-content text-content',
|
|
140
138
|
/** 14px / 500. Labels, control text, list-row titles. */
|
|
141
139
|
label: 'text-sm font-medium',
|
|
142
140
|
/** 14px / 600. Emphasis inside body copy. */
|
|
143
|
-
strong: 'text-
|
|
141
|
+
strong: 'font-content text-content font-semibold',
|
|
144
142
|
/** 12px / 400. Metadata, secondary rows, units. */
|
|
145
143
|
caption: 'text-xs',
|
|
146
144
|
/** 11px / 500. The floor: keyboard keys, the status bar. */
|
|
147
145
|
micro: 'text-2xs font-medium',
|
|
148
146
|
/** 12px mono. Ids, paths, hashes, inline code. */
|
|
149
|
-
code: 'font-
|
|
147
|
+
code: 'font-code text-code',
|
|
150
148
|
},
|
|
151
149
|
tone: {
|
|
152
150
|
inherit: '',
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { fontOptions, type FontOption } from './font-catalog'
|
|
2
|
+
import { safeScriptStringLiteral } from './safe-script'
|
|
3
|
+
|
|
4
|
+
export const APPEARANCE_EDITOR_FONT_AXES = ['ui', 'content', 'code'] as const
|
|
5
|
+
|
|
6
|
+
export type AppearanceEditorFontAxis = (typeof APPEARANCE_EDITOR_FONT_AXES)[number]
|
|
7
|
+
export type AppearanceEditorFontFamilyId = FontOption['id']
|
|
8
|
+
|
|
9
|
+
export type AppearanceEditorFontSetting = Readonly<{
|
|
10
|
+
/** A stable id from the shared font catalogue, never a CSS family string. */
|
|
11
|
+
family: AppearanceEditorFontFamilyId
|
|
12
|
+
/** A pixel size, normalized to the supported range. */
|
|
13
|
+
size: number
|
|
14
|
+
}>
|
|
15
|
+
|
|
16
|
+
/** The host-owned choices edited by the shared appearance composition. */
|
|
17
|
+
export type AppearanceEditorFontSettings = Readonly<
|
|
18
|
+
Record<AppearanceEditorFontAxis, AppearanceEditorFontSetting>
|
|
19
|
+
>
|
|
20
|
+
|
|
21
|
+
export const APPEARANCE_EDITOR_FONT_SIZE_MIN = 10
|
|
22
|
+
export const APPEARANCE_EDITOR_FONT_SIZE_MAX = 32
|
|
23
|
+
|
|
24
|
+
/** New preferences use the platform face in each text role. */
|
|
25
|
+
export const DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS: AppearanceEditorFontSettings = Object.freeze({
|
|
26
|
+
ui: Object.freeze({ family: 'system', size: 14 }),
|
|
27
|
+
content: Object.freeze({ family: 'system', size: 14 }),
|
|
28
|
+
code: Object.freeze({ family: 'system', size: 12 }),
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
export type NormalizedAppearanceEditorFontSettings = Readonly<{
|
|
32
|
+
settings: AppearanceEditorFontSettings
|
|
33
|
+
/** Axes whose persisted family or size was unavailable or outside its limits. */
|
|
34
|
+
recoveredAxes: readonly AppearanceEditorFontAxis[]
|
|
35
|
+
}>
|
|
36
|
+
|
|
37
|
+
const fontFamilyIds: ReadonlySet<string> = new Set(fontOptions.map((option) => option.id))
|
|
38
|
+
const fontOptionsById = Object.freeze(
|
|
39
|
+
Object.fromEntries(fontOptions.map((option) => [option.id, option])) as Record<
|
|
40
|
+
AppearanceEditorFontFamilyId,
|
|
41
|
+
FontOption
|
|
42
|
+
>
|
|
43
|
+
)
|
|
44
|
+
const fontProjectionById = Object.freeze(
|
|
45
|
+
Object.fromEntries(
|
|
46
|
+
fontOptions.map((option) => [
|
|
47
|
+
option.id,
|
|
48
|
+
{
|
|
49
|
+
familyVariables: option.familyVariables,
|
|
50
|
+
uiTracking: option.uiTracking,
|
|
51
|
+
uiWordSpacing: option.uiWordSpacing,
|
|
52
|
+
},
|
|
53
|
+
])
|
|
54
|
+
) as Record<
|
|
55
|
+
AppearanceEditorFontFamilyId,
|
|
56
|
+
Pick<FontOption, 'familyVariables' | 'uiTracking' | 'uiWordSpacing'>
|
|
57
|
+
>
|
|
58
|
+
)
|
|
59
|
+
const fontAxisProjection = Object.freeze({
|
|
60
|
+
ui: Object.freeze({
|
|
61
|
+
familyAttribute: 'data-ui-font',
|
|
62
|
+
familyProperty: '--font-ui',
|
|
63
|
+
sizeProperty: '--font-ui-size',
|
|
64
|
+
scaleProperty: '--font-ui-scale',
|
|
65
|
+
defaultSize: DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS.ui.size,
|
|
66
|
+
}),
|
|
67
|
+
content: Object.freeze({
|
|
68
|
+
familyAttribute: 'data-content-font',
|
|
69
|
+
familyProperty: '--font-content',
|
|
70
|
+
sizeProperty: '--font-content-size',
|
|
71
|
+
scaleProperty: '--font-content-scale',
|
|
72
|
+
defaultSize: DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS.content.size,
|
|
73
|
+
}),
|
|
74
|
+
code: Object.freeze({
|
|
75
|
+
familyAttribute: 'data-code-font',
|
|
76
|
+
familyProperty: '--font-code',
|
|
77
|
+
sizeProperty: '--font-code-size',
|
|
78
|
+
scaleProperty: '--font-code-scale',
|
|
79
|
+
defaultSize: DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS.code.size,
|
|
80
|
+
}),
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
84
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function hasOwn(value: Record<string, unknown>, key: string): boolean {
|
|
88
|
+
return Object.prototype.hasOwnProperty.call(value, key)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function normalizeFamily(value: unknown): AppearanceEditorFontFamilyId | undefined {
|
|
92
|
+
return typeof value === 'string' && fontFamilyIds.has(value)
|
|
93
|
+
? (value as AppearanceEditorFontFamilyId)
|
|
94
|
+
: undefined
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function clampFontSize(value: number): number {
|
|
98
|
+
return Math.min(
|
|
99
|
+
APPEARANCE_EDITOR_FONT_SIZE_MAX,
|
|
100
|
+
Math.max(APPEARANCE_EDITOR_FONT_SIZE_MIN, Math.round(value))
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Normalize a single number-input value; invalid edits return the current size. */
|
|
105
|
+
export function normalizeAppearanceEditorFontSize(value: unknown, fallback: number): number {
|
|
106
|
+
const parsed =
|
|
107
|
+
typeof value === 'number'
|
|
108
|
+
? value
|
|
109
|
+
: typeof value === 'string' && value.trim() !== ''
|
|
110
|
+
? Number(value)
|
|
111
|
+
: Number.NaN
|
|
112
|
+
return Number.isFinite(parsed) ? clampFontSize(parsed) : clampFontSize(fallback)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Recover persisted font choices against the shared font catalogue.
|
|
117
|
+
*
|
|
118
|
+
* `legacyUiFamily` lets a host migrate its previous single font field into the
|
|
119
|
+
* UI axis. Content and code remain on the new System defaults during that
|
|
120
|
+
* migration. Missing settings are ordinary defaults; an unknown saved id or an
|
|
121
|
+
* invalid size is reported through `recoveredAxes` for the host's notice.
|
|
122
|
+
*/
|
|
123
|
+
export function normalizeAppearanceEditorFontSettings(
|
|
124
|
+
value: unknown,
|
|
125
|
+
legacyUiFamily?: unknown
|
|
126
|
+
): NormalizedAppearanceEditorFontSettings {
|
|
127
|
+
const source = isRecord(value) ? value : undefined
|
|
128
|
+
const malformedRoot = value !== undefined && value !== null && source === undefined
|
|
129
|
+
const recovered = new Set<AppearanceEditorFontAxis>()
|
|
130
|
+
const settings = {} as Record<AppearanceEditorFontAxis, AppearanceEditorFontSetting>
|
|
131
|
+
|
|
132
|
+
for (const axis of APPEARANCE_EDITOR_FONT_AXES) {
|
|
133
|
+
const axisPresent = source ? hasOwn(source, axis) : false
|
|
134
|
+
const axisValue = source?.[axis]
|
|
135
|
+
const axisSource = isRecord(axisValue) ? axisValue : undefined
|
|
136
|
+
const fallback = DEFAULT_APPEARANCE_EDITOR_FONT_SETTINGS[axis]
|
|
137
|
+
|
|
138
|
+
if (malformedRoot || (axisPresent && axisSource === undefined)) recovered.add(axis)
|
|
139
|
+
|
|
140
|
+
const hasFamily = axisSource ? hasOwn(axisSource, 'family') : false
|
|
141
|
+
const familyInput = hasFamily
|
|
142
|
+
? axisSource?.['family']
|
|
143
|
+
: axis === 'ui' && legacyUiFamily !== undefined
|
|
144
|
+
? legacyUiFamily
|
|
145
|
+
: undefined
|
|
146
|
+
const family = normalizeFamily(familyInput) ?? fallback.family
|
|
147
|
+
if (
|
|
148
|
+
(hasFamily || (axis === 'ui' && legacyUiFamily !== undefined)) &&
|
|
149
|
+
!normalizeFamily(familyInput)
|
|
150
|
+
) {
|
|
151
|
+
recovered.add(axis)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const hasSize = axisSource ? hasOwn(axisSource, 'size') : false
|
|
155
|
+
const sizeInput = axisSource?.['size']
|
|
156
|
+
const size = hasSize
|
|
157
|
+
? normalizeAppearanceEditorFontSize(sizeInput, fallback.size)
|
|
158
|
+
: fallback.size
|
|
159
|
+
if (
|
|
160
|
+
hasSize &&
|
|
161
|
+
(typeof sizeInput !== 'number' || !Number.isFinite(sizeInput) || sizeInput !== size)
|
|
162
|
+
) {
|
|
163
|
+
recovered.add(axis)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
settings[axis] = Object.freeze({ family, size })
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return Object.freeze({
|
|
170
|
+
settings: Object.freeze(settings),
|
|
171
|
+
recoveredAxes: Object.freeze(APPEARANCE_EDITOR_FONT_AXES.filter((axis) => recovered.has(axis))),
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Project normalized font preferences onto a document root.
|
|
177
|
+
*
|
|
178
|
+
* This is shared by `ThemeProvider` and hosts that own their own appearance
|
|
179
|
+
* persistence, so UI/content/code use the same catalogue ids, theme tokens,
|
|
180
|
+
* sizes, and projected CSS variables. The marker activates the optional role
|
|
181
|
+
* stylesheet and survives CSS import reordering.
|
|
182
|
+
*/
|
|
183
|
+
export function applyAppearanceFontSettings(
|
|
184
|
+
root: HTMLElement,
|
|
185
|
+
value: unknown
|
|
186
|
+
): NormalizedAppearanceEditorFontSettings {
|
|
187
|
+
const normalized = normalizeAppearanceEditorFontSettings(value)
|
|
188
|
+
const { settings } = normalized
|
|
189
|
+
|
|
190
|
+
root.removeAttribute('data-font')
|
|
191
|
+
root.setAttribute('data-font-settings', '')
|
|
192
|
+
for (const axis of APPEARANCE_EDITOR_FONT_AXES) {
|
|
193
|
+
const projection = fontAxisProjection[axis]
|
|
194
|
+
const setting = settings[axis]
|
|
195
|
+
const option = fontOptionsById[setting.family]
|
|
196
|
+
if (setting.family === 'system') root.removeAttribute(projection.familyAttribute)
|
|
197
|
+
else root.setAttribute(projection.familyAttribute, setting.family)
|
|
198
|
+
root.style.setProperty(projection.familyProperty, `var(${option.familyVariables[axis]})`)
|
|
199
|
+
root.style.setProperty(projection.sizeProperty, String(setting.size) + 'px')
|
|
200
|
+
root.style.setProperty(projection.scaleProperty, String(setting.size / projection.defaultSize))
|
|
201
|
+
if (axis === 'ui') {
|
|
202
|
+
root.style.setProperty('--ui-tracking', option.uiTracking)
|
|
203
|
+
root.style.setProperty('--ui-word-spacing', option.uiWordSpacing)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return normalized
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Generate a safe inline prepaint script for a host-owned appearance record.
|
|
212
|
+
*
|
|
213
|
+
* The stored object is read from `localStorage[storageKey].fonts`. A legacy
|
|
214
|
+
* top-level `font` family migrates into UI only; content/code use the shared
|
|
215
|
+
* defaults. The script applies the same catalogue whitelist, limits, attributes,
|
|
216
|
+
* and CSS properties as `applyAppearanceFontSettings` before styles paint. When
|
|
217
|
+
* `persistedVersion` is supplied, only a record with that exact top-level version
|
|
218
|
+
* is used; absent or mismatched records receive the System defaults.
|
|
219
|
+
*/
|
|
220
|
+
export function fontSettingsBootstrapScript(storageKey: string, persistedVersion?: number): string {
|
|
221
|
+
if (persistedVersion !== undefined && !Number.isSafeInteger(persistedVersion)) {
|
|
222
|
+
throw new RangeError('persistedVersion must be a safe integer')
|
|
223
|
+
}
|
|
224
|
+
const axisConfig = JSON.stringify(fontAxisProjection)
|
|
225
|
+
const fontProjection = JSON.stringify(fontProjectionById)
|
|
226
|
+
const fontIds = `[${fontOptions.map((option) => safeScriptStringLiteral(option.id)).join(',')}]`
|
|
227
|
+
const persistedVersionGuard =
|
|
228
|
+
persistedVersion === undefined
|
|
229
|
+
? ''
|
|
230
|
+
: `&&parsed.version===Number(${safeScriptStringLiteral(String(persistedVersion))})`
|
|
231
|
+
|
|
232
|
+
return `(function(){var r=document.documentElement;var axes=JSON.parse(${safeScriptStringLiteral(axisConfig)});var projection=JSON.parse(${safeScriptStringLiteral(fontProjection)});var ids=${fontIds};var has=function(v,k){return Object.prototype.hasOwnProperty.call(v,k)};var record=function(v){return typeof v==='object'&&v!==null&&!Array.isArray(v)};var p={};try{var raw=localStorage.getItem(${safeScriptStringLiteral(storageKey)});var parsed=raw?JSON.parse(raw):{};if(record(parsed)${persistedVersionGuard})p=parsed;}catch(e){}var saved=record(p.fonts)?p.fonts:{};var valid=function(v,d){return ids.indexOf(v)!==-1?v:d};var size=function(v,d){var n=typeof v==='number'?v:typeof v==='string'&&v.trim()!==''?Number(v):NaN;return Number.isFinite(n)?Math.min(${APPEARANCE_EDITOR_FONT_SIZE_MAX},Math.max(${APPEARANCE_EDITOR_FONT_SIZE_MIN},Math.round(n))):d};r.setAttribute('data-font-settings','');for(var axis in axes){if(!has(axes,axis))continue;var spec=axes[axis];var candidate=saved[axis];var value=record(candidate)?candidate:{};var legacyUi=axis==='ui'&&!has(value,'family');var family=legacyUi?valid(p.font,'system'):valid(value.family,'system');var font=projection[family];if(family==='system')r.removeAttribute(spec.familyAttribute);else r.setAttribute(spec.familyAttribute,family);r.style.setProperty(spec.familyProperty,'var('+font.familyVariables[axis]+')');var px=size(value.size,spec.defaultSize);r.style.setProperty(spec.sizeProperty,px+'px');r.style.setProperty(spec.scaleProperty,String(px/spec.defaultSize));if(axis==='ui'){r.style.setProperty('--ui-tracking',font.uiTracking);r.style.setProperty('--ui-word-spacing',font.uiWordSpacing);}}r.removeAttribute('data-font');})();`
|
|
233
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable font-family choices shared by the appearance editor and its host APIs.
|
|
3
|
+
*
|
|
4
|
+
* This stays independent of the theme-token manifest so consumers that need
|
|
5
|
+
* only font settings do not retain the palette catalogue.
|
|
6
|
+
*/
|
|
7
|
+
// Explicit catalogue choices resolve to the same named face in every role.
|
|
8
|
+
// System Code is the exception: it resolves to the platform monospace stack.
|
|
9
|
+
const FONT_OPTIONS = [
|
|
10
|
+
{
|
|
11
|
+
id: 'space-grotesk',
|
|
12
|
+
label: 'Space Grotesk',
|
|
13
|
+
description: 'The self-hosted Space Grotesk family.',
|
|
14
|
+
familyVariables: {
|
|
15
|
+
ui: '--font-family-space-grotesk',
|
|
16
|
+
content: '--font-family-space-grotesk',
|
|
17
|
+
code: '--font-family-space-grotesk',
|
|
18
|
+
},
|
|
19
|
+
uiTracking: 'normal',
|
|
20
|
+
uiWordSpacing: 'normal',
|
|
21
|
+
stack: 'both',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'system',
|
|
25
|
+
label: 'System',
|
|
26
|
+
description: "The platform's own interface family and system monospace counterpart.",
|
|
27
|
+
familyVariables: {
|
|
28
|
+
ui: '--font-family-system',
|
|
29
|
+
content: '--font-family-system',
|
|
30
|
+
code: '--font-family-system-mono',
|
|
31
|
+
},
|
|
32
|
+
uiTracking: 'normal',
|
|
33
|
+
uiWordSpacing: 'normal',
|
|
34
|
+
stack: 'both',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'geist',
|
|
38
|
+
label: 'Geist',
|
|
39
|
+
description: 'The face cortana already ships. Neutral and wide.',
|
|
40
|
+
familyVariables: {
|
|
41
|
+
ui: '--font-family-geist',
|
|
42
|
+
content: '--font-family-geist',
|
|
43
|
+
code: '--font-family-geist',
|
|
44
|
+
},
|
|
45
|
+
uiTracking: 'normal',
|
|
46
|
+
uiWordSpacing: 'normal',
|
|
47
|
+
stack: 'both',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'geist-mono',
|
|
51
|
+
label: 'Geist Mono',
|
|
52
|
+
description: 'Monospace throughout, for someone who wants a uniform texture.',
|
|
53
|
+
familyVariables: {
|
|
54
|
+
ui: '--font-family-geist-mono',
|
|
55
|
+
content: '--font-family-geist-mono',
|
|
56
|
+
code: '--font-family-geist-mono',
|
|
57
|
+
},
|
|
58
|
+
uiTracking: '-0.03em',
|
|
59
|
+
uiWordSpacing: '-1.5px',
|
|
60
|
+
stack: 'both',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'jetbrains-mono',
|
|
64
|
+
label: 'JetBrains Mono',
|
|
65
|
+
description: 'Monospace throughout, with coding ligatures off.',
|
|
66
|
+
familyVariables: {
|
|
67
|
+
ui: '--font-family-jetbrains-mono',
|
|
68
|
+
content: '--font-family-jetbrains-mono',
|
|
69
|
+
code: '--font-family-jetbrains-mono',
|
|
70
|
+
},
|
|
71
|
+
uiTracking: '-0.04em',
|
|
72
|
+
uiWordSpacing: '-2.5px',
|
|
73
|
+
stack: 'both',
|
|
74
|
+
},
|
|
75
|
+
] as const
|
|
76
|
+
|
|
77
|
+
/** Stable catalogue record type; saved values never contain CSS family strings. */
|
|
78
|
+
export type FontOption = (typeof FONT_OPTIONS)[number]
|
|
79
|
+
|
|
80
|
+
export const fontOptions: readonly FontOption[] = Object.freeze(FONT_OPTIONS)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Escape a string literal for an inline script's JavaScript source. */
|
|
2
|
+
export function safeScriptStringLiteral(value: string): string {
|
|
3
|
+
return JSON.stringify(value).replace(
|
|
4
|
+
/[<>\u2028\u2029]/g,
|
|
5
|
+
(character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`
|
|
6
|
+
)
|
|
7
|
+
}
|
package/dist/r/src/lib/tokens.ts
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { ACCENTS } from '@adea-ai/themes'
|
|
21
|
+
export { fontOptions } from './font-catalog'
|
|
22
|
+
export type { FontOption } from './font-catalog'
|
|
21
23
|
|
|
22
24
|
export type TokenKind =
|
|
23
25
|
| 'color'
|
|
@@ -388,20 +390,35 @@ export const radiusTokens: TokenDefinition[] = [
|
|
|
388
390
|
]
|
|
389
391
|
|
|
390
392
|
export const typographyTokens: TokenDefinition[] = [
|
|
393
|
+
{
|
|
394
|
+
name: 'font-ui',
|
|
395
|
+
kind: 'font-family',
|
|
396
|
+
description: 'The selected family for interface controls, labels and headings.',
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: 'font-content',
|
|
400
|
+
kind: 'font-family',
|
|
401
|
+
description: 'The selected family for prose, transcripts and long-form reading.',
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
name: 'font-code',
|
|
405
|
+
kind: 'font-family',
|
|
406
|
+
description: 'The selected family for code, terminals, keyboard keys, ids and paths.',
|
|
407
|
+
},
|
|
391
408
|
{
|
|
392
409
|
name: 'font-sans',
|
|
393
410
|
kind: 'font-family',
|
|
394
|
-
description: '
|
|
411
|
+
description: 'Compatibility alias for the selected UI family.',
|
|
395
412
|
},
|
|
396
413
|
{
|
|
397
414
|
name: 'font-mono',
|
|
398
415
|
kind: 'font-family',
|
|
399
|
-
description: '
|
|
416
|
+
description: 'Compatibility alias for the selected code family.',
|
|
400
417
|
},
|
|
401
418
|
{
|
|
402
419
|
name: 'font-family-space-grotesk',
|
|
403
420
|
kind: 'font-family',
|
|
404
|
-
description: 'The
|
|
421
|
+
description: 'The self-hosted Space Grotesk family.',
|
|
405
422
|
},
|
|
406
423
|
{
|
|
407
424
|
name: 'font-family-jetbrains-mono',
|
|
@@ -428,6 +445,36 @@ export const typographyTokens: TokenDefinition[] = [
|
|
|
428
445
|
kind: 'font-family',
|
|
429
446
|
description: "The platform's own monospace face.",
|
|
430
447
|
},
|
|
448
|
+
{
|
|
449
|
+
name: 'font-ui-size',
|
|
450
|
+
kind: 'dimension',
|
|
451
|
+
description: 'Runtime-projected interface size in pixels; scales the shared UI text ladder.',
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
name: 'font-content-size',
|
|
455
|
+
kind: 'dimension',
|
|
456
|
+
description: 'Runtime-projected prose and transcript size in pixels.',
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
name: 'font-code-size',
|
|
460
|
+
kind: 'dimension',
|
|
461
|
+
description: 'Runtime-projected code, terminal and keyboard-key size in pixels.',
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
name: 'font-ui-scale',
|
|
465
|
+
kind: 'number',
|
|
466
|
+
description: 'The UI size ratio applied to the interface text ladder.',
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
name: 'font-content-scale',
|
|
470
|
+
kind: 'number',
|
|
471
|
+
description: 'The content size ratio applied to rem-relative prose text.',
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
name: 'font-code-scale',
|
|
475
|
+
kind: 'number',
|
|
476
|
+
description: 'The code size ratio applied to rem-relative code text.',
|
|
477
|
+
},
|
|
431
478
|
{
|
|
432
479
|
name: 'ui-tracking',
|
|
433
480
|
kind: 'text',
|
|
@@ -443,13 +490,13 @@ export const typographyTokens: TokenDefinition[] = [
|
|
|
443
490
|
{
|
|
444
491
|
name: 'text-2xs',
|
|
445
492
|
kind: 'text',
|
|
446
|
-
description: '
|
|
493
|
+
description: 'The smallest UI-scaled label: status bar and compact metadata.',
|
|
447
494
|
},
|
|
448
|
-
{ name: 'text-xs', kind: 'text', description: '
|
|
495
|
+
{ name: 'text-xs', kind: 'text', description: 'UI-scaled metadata, badges and secondary rows.' },
|
|
449
496
|
{
|
|
450
497
|
name: 'text-sm',
|
|
451
498
|
kind: 'text',
|
|
452
|
-
description: '
|
|
499
|
+
description: 'The UI-scaled interface default for labels and controls.',
|
|
453
500
|
},
|
|
454
501
|
{ name: 'text-base', kind: 'text', description: '16px — card titles and dialog titles.' },
|
|
455
502
|
{ name: 'text-lg', kind: 'text', description: '18px — a section heading inside a page.' },
|
|
@@ -458,7 +505,17 @@ export const typographyTokens: TokenDefinition[] = [
|
|
|
458
505
|
{
|
|
459
506
|
name: 'text-3xl',
|
|
460
507
|
kind: 'text',
|
|
461
|
-
description: '
|
|
508
|
+
description: 'The largest UI-scaled rung. Reserved for an empty-state headline.',
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
name: 'text-content',
|
|
512
|
+
kind: 'text',
|
|
513
|
+
description: 'The selected content size with the prose line-height.',
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
name: 'text-code',
|
|
517
|
+
kind: 'text',
|
|
518
|
+
description: 'The selected code size with the code line-height.',
|
|
462
519
|
},
|
|
463
520
|
]
|
|
464
521
|
|
|
@@ -661,58 +718,6 @@ export const accentPresets: readonly AccentPreset[] = Object.freeze([
|
|
|
661
718
|
...ACCENTS,
|
|
662
719
|
])
|
|
663
720
|
|
|
664
|
-
/**
|
|
665
|
-
* The font axis.
|
|
666
|
-
*
|
|
667
|
-
* The family is a selection, like the accent: `data-font` sits on the same element
|
|
668
|
-
* and each option swaps the interface face. `space-grotesk` is the default because
|
|
669
|
-
* it is the face the visual language was drawn against, and `system` is a
|
|
670
|
-
* first-class option rather than a fallback — an application that wants the
|
|
671
|
-
* platform's own face should be able to say so without losing the rest of the
|
|
672
|
-
* system.
|
|
673
|
-
*/
|
|
674
|
-
export type FontOption = {
|
|
675
|
-
/** The `data-font` value. `space-grotesk` is the default and needs no attribute. */
|
|
676
|
-
id: string
|
|
677
|
-
label: string
|
|
678
|
-
description: string
|
|
679
|
-
/** Which of the two stacks this option sets. */
|
|
680
|
-
stack: 'sans' | 'mono' | 'both'
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
export const fontOptions: readonly FontOption[] = Object.freeze([
|
|
684
|
-
{
|
|
685
|
-
id: 'space-grotesk',
|
|
686
|
-
label: 'Space Grotesk',
|
|
687
|
-
description: 'The default, and the face the visual language was drawn against.',
|
|
688
|
-
stack: 'both',
|
|
689
|
-
},
|
|
690
|
-
{
|
|
691
|
-
id: 'system',
|
|
692
|
-
label: 'System',
|
|
693
|
-
description: "The platform's own face. What a terminal or editor usually wants.",
|
|
694
|
-
stack: 'both',
|
|
695
|
-
},
|
|
696
|
-
{
|
|
697
|
-
id: 'geist',
|
|
698
|
-
label: 'Geist',
|
|
699
|
-
description: 'The face cortana already ships. Neutral and wide.',
|
|
700
|
-
stack: 'both',
|
|
701
|
-
},
|
|
702
|
-
{
|
|
703
|
-
id: 'geist-mono',
|
|
704
|
-
label: 'Geist Mono',
|
|
705
|
-
description: 'Monospace throughout, for someone who wants a uniform texture.',
|
|
706
|
-
stack: 'both',
|
|
707
|
-
},
|
|
708
|
-
{
|
|
709
|
-
id: 'jetbrains-mono',
|
|
710
|
-
label: 'JetBrains Mono',
|
|
711
|
-
description: 'Monospace throughout, with coding ligatures off.',
|
|
712
|
-
stack: 'both',
|
|
713
|
-
},
|
|
714
|
-
])
|
|
715
|
-
|
|
716
721
|
/** Every token, in gallery order. */
|
|
717
722
|
export const designTokens = {
|
|
718
723
|
color: colorTokens,
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* Optional typography roles and Appearance font controls.
|
|
2
|
+
*
|
|
3
|
+
* Import after `theme.css` and `base.css` when the host uses the shared font
|
|
4
|
+
* preference projection. This file defines selectors and utilities only; it
|
|
5
|
+
* never imports font assets. `fonts.css` remains a separate opt-in for bundled
|
|
6
|
+
* typefaces.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* The marker scopes role defaults and wins over theme.css root tokens even
|
|
10
|
+
when a bundler hoists this optional sheet before shared globals. Family
|
|
11
|
+
values come from the validated shared runtime/bootstrap projection. */
|
|
12
|
+
:root[data-font-settings] {
|
|
13
|
+
--font-ui: var(--font-family-system);
|
|
14
|
+
--font-content: var(--font-family-system);
|
|
15
|
+
--font-code: var(--font-family-system-mono);
|
|
16
|
+
--font-sans: var(--font-ui);
|
|
17
|
+
--font-mono: var(--font-code);
|
|
18
|
+
--font-ui-scale: 1;
|
|
19
|
+
--font-content-scale: 1;
|
|
20
|
+
--font-code-scale: 1;
|
|
21
|
+
|
|
22
|
+
--text-2xs: calc(0.6875rem * var(--font-ui-scale));
|
|
23
|
+
--text-xs: calc(0.75rem * var(--font-ui-scale));
|
|
24
|
+
--text-sm: calc(0.875rem * var(--font-ui-scale));
|
|
25
|
+
--text-base: calc(1rem * var(--font-ui-scale));
|
|
26
|
+
--text-lg: calc(1.125rem * var(--font-ui-scale));
|
|
27
|
+
--text-xl: calc(1.25rem * var(--font-ui-scale));
|
|
28
|
+
--text-2xl: calc(1.5rem * var(--font-ui-scale));
|
|
29
|
+
--text-3xl: calc(1.875rem * var(--font-ui-scale));
|
|
30
|
+
--text-content: calc(0.875rem * var(--font-content-scale));
|
|
31
|
+
--text-content--line-height: var(--text-sm--line-height);
|
|
32
|
+
--text-code: calc(0.75rem * var(--font-code-scale));
|
|
33
|
+
--text-code--line-height: var(--text-xs--line-height);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@layer base {
|
|
37
|
+
code,
|
|
38
|
+
kbd,
|
|
39
|
+
pre,
|
|
40
|
+
samp {
|
|
41
|
+
font-family: var(--font-code);
|
|
42
|
+
font-size: var(--text-code);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Appearance's own controls grow with the UI preference while ordinary
|
|
46
|
+
controls retain their established density. */
|
|
47
|
+
.global-appearance-font-settings button,
|
|
48
|
+
.global-appearance-editor-actions button {
|
|
49
|
+
min-height: max(var(--control-height-sm), calc(1lh + 2px));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Text controls keep their density rung but gain room for their projected
|
|
53
|
+
line box. Icon-only controls use size-control-* and keep fixed targets. */
|
|
54
|
+
[data-font-settings] .h-control-2xs {
|
|
55
|
+
--font-control-height: var(--control-height-2xs);
|
|
56
|
+
}
|
|
57
|
+
[data-font-settings] .h-control-xs {
|
|
58
|
+
--font-control-height: var(--control-height-xs);
|
|
59
|
+
}
|
|
60
|
+
[data-font-settings] .h-control-sm {
|
|
61
|
+
--font-control-height: var(--control-height-sm);
|
|
62
|
+
}
|
|
63
|
+
[data-font-settings] .h-control-md {
|
|
64
|
+
--font-control-height: var(--control-height-md);
|
|
65
|
+
}
|
|
66
|
+
[data-font-settings] .h-control-lg {
|
|
67
|
+
--font-control-height: var(--control-height-lg);
|
|
68
|
+
}
|
|
69
|
+
[data-font-settings] .h-control-xl {
|
|
70
|
+
--font-control-height: var(--control-height-xl);
|
|
71
|
+
}
|
|
72
|
+
[data-font-settings] .h-control-2xl {
|
|
73
|
+
--font-control-height: var(--control-height-2xl);
|
|
74
|
+
}
|
|
75
|
+
[data-font-settings]
|
|
76
|
+
:is(
|
|
77
|
+
.h-control-2xs,
|
|
78
|
+
.h-control-xs,
|
|
79
|
+
.h-control-sm,
|
|
80
|
+
.h-control-md,
|
|
81
|
+
.h-control-lg,
|
|
82
|
+
.h-control-xl,
|
|
83
|
+
.h-control-2xl
|
|
84
|
+
) {
|
|
85
|
+
min-height: max(var(--font-control-height), calc(1lh + 2px));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
[data-font-settings]
|
|
89
|
+
input:is(
|
|
90
|
+
.h-control-2xs,
|
|
91
|
+
.h-control-xs,
|
|
92
|
+
.h-control-sm,
|
|
93
|
+
.h-control-md,
|
|
94
|
+
.h-control-lg,
|
|
95
|
+
.h-control-xl,
|
|
96
|
+
.h-control-2xl
|
|
97
|
+
) {
|
|
98
|
+
min-height: max(var(--font-control-height), calc(1lh + var(--spacing) + var(--spacing) + 2px));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.global-appearance-font-settings input[type='number'] {
|
|
102
|
+
min-height: max(var(--control-height-md), calc(1lh + var(--spacing) + var(--spacing) + 3px));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Keep the numeric font-size value visible beside the native number stepper
|
|
107
|
+
as the UI font grows; unlayered so this minimum wins over min-w-0. */
|
|
108
|
+
.global-appearance-font-settings input[type='number'] {
|
|
109
|
+
min-width: calc(3ch + var(--control-padding-md) + var(--control-padding-md) + 1.25rem + 2px);
|
|
110
|
+
}
|
|
@@ -4,15 +4,14 @@
|
|
|
4
4
|
* a desktop app must not fetch a font at runtime, or the first paint after a cold
|
|
5
5
|
* start shows a fallback face and then reflows.
|
|
6
6
|
*
|
|
7
|
-
* Space Grotesk
|
|
8
|
-
* drawn against
|
|
7
|
+
* Space Grotesk a self-hosted proportional family
|
|
9
8
|
* JetBrains Mono code, terminals, ids, paths
|
|
10
9
|
* Geist an alternative interface face; cortana already ships it
|
|
11
10
|
* Geist Mono its monospace counterpart
|
|
12
11
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* These families feed the shared UI, content and code axes. Their stable ids are
|
|
13
|
+
* projected by `@adea-ai/ui/lib/appearance-font-settings`; System is the default
|
|
14
|
+
* and needs no font asset.
|
|
16
15
|
*
|
|
17
16
|
* Consumers import this after the theme:
|
|
18
17
|
*
|