@prestack/thread-ui 0.0.1 → 0.0.2
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/dist/ui/animations/anm_appear.ts +13 -0
- package/dist/ui/animations/anm_blur_in.ts +19 -0
- package/dist/ui/animations/anm_blur_out.ts +18 -0
- package/dist/ui/animations/anm_dismiss.ts +18 -0
- package/dist/ui/animations/anm_drop.ts +19 -0
- package/dist/ui/animations/anm_fall.ts +18 -0
- package/dist/ui/animations/anm_flash.ts +18 -0
- package/dist/ui/animations/anm_glow.ts +16 -0
- package/dist/ui/animations/anm_lift.ts +16 -0
- package/dist/ui/animations/anm_nudge.ts +16 -0
- package/dist/ui/animations/anm_pop_in.ts +23 -0
- package/dist/ui/animations/anm_pop_out.ts +22 -0
- package/dist/ui/animations/anm_press.ts +12 -0
- package/dist/ui/animations/anm_pulse.ts +13 -0
- package/dist/ui/animations/anm_rise.ts +19 -0
- package/dist/ui/animations/anm_shake.ts +13 -0
- package/dist/ui/animations/anm_slide_in_left.ts +19 -0
- package/dist/ui/animations/anm_slide_in_right.ts +19 -0
- package/dist/ui/animations/anm_slide_out_left.ts +18 -0
- package/dist/ui/animations/anm_slide_out_right.ts +18 -0
- package/dist/ui/animations/anm_spin.ts +12 -0
- package/dist/ui/animations/anm_swell.ts +16 -0
- package/dist/ui/animations/anm_wobble.ts +24 -0
- package/dist/ui/animations/anm_zoom_in.ts +19 -0
- package/dist/ui/animations/anm_zoom_out.ts +18 -0
- package/dist/ui/animations.ts +317 -0
- package/dist/ui/attach.js +13 -4
- package/dist/ui/attach.ts +613 -0
- package/dist/ui/charts.tsx +74 -0
- package/dist/ui/checked.d.ts +2 -2
- package/dist/ui/checked.ts +32 -0
- package/dist/ui/collector.ts +140 -0
- package/dist/ui/compositions.d.ts +10 -1
- package/dist/ui/compositions.js +262 -23
- package/dist/ui/compositions.ts +640 -0
- package/dist/ui/consent.ts +55 -0
- package/dist/ui/content.tsx +39 -0
- package/dist/ui/contrast.ts +27 -0
- package/dist/ui/controls.tsx +30 -0
- package/dist/ui/disclosure.tsx +22 -0
- package/dist/ui/dismiss-layer.ts +87 -0
- package/dist/ui/door.ts +140 -0
- package/dist/ui/drag.ts +316 -0
- package/dist/ui/elements/accordion.js +2 -2
- package/dist/ui/elements/accordion.tsx +47 -0
- package/dist/ui/elements/accordion.works.ts +66 -0
- package/dist/ui/elements/aspect-ratio.js +1 -1
- package/dist/ui/elements/aspect-ratio.tsx +30 -0
- package/dist/ui/elements/aspect-ratio.works.ts +5 -0
- package/dist/ui/elements/avatar.js +1 -1
- package/dist/ui/elements/avatar.tsx +33 -0
- package/dist/ui/elements/avatar.works.ts +16 -0
- package/dist/ui/elements/badge.js +1 -1
- package/dist/ui/elements/badge.tsx +32 -0
- package/dist/ui/elements/badge.works.ts +9 -0
- package/dist/ui/elements/bars.js +2 -2
- package/dist/ui/elements/bars.tsx +49 -0
- package/dist/ui/elements/bars.works.ts +29 -0
- package/dist/ui/elements/box.js +3 -2
- package/dist/ui/elements/box.tsx +35 -0
- package/dist/ui/elements/breadcrumb.js +2 -2
- package/dist/ui/elements/breadcrumb.tsx +37 -0
- package/dist/ui/elements/breadcrumb.works.ts +24 -0
- package/dist/ui/elements/button.js +1 -1
- package/dist/ui/elements/button.tsx +45 -0
- package/dist/ui/elements/button.works.tsx +52 -0
- package/dist/ui/elements/column.js +1 -1
- package/dist/ui/elements/column.tsx +28 -0
- package/dist/ui/elements/consent.js +2 -2
- package/dist/ui/elements/consent.tsx +70 -0
- package/dist/ui/elements/consent.works.tsx +132 -0
- package/dist/ui/elements/donut.js +2 -2
- package/dist/ui/elements/donut.tsx +44 -0
- package/dist/ui/elements/donut.works.ts +42 -0
- package/dist/ui/elements/each.js +1 -1
- package/dist/ui/elements/each.tsx +33 -0
- package/dist/ui/elements/each.works.tsx +82 -0
- package/dist/ui/elements/empty.js +1 -1
- package/dist/ui/elements/empty.tsx +32 -0
- package/dist/ui/elements/field.js +1 -1
- package/dist/ui/elements/field.tsx +44 -0
- package/dist/ui/elements/field.works.ts +65 -0
- package/dist/ui/elements/funnel.js +2 -2
- package/dist/ui/elements/funnel.tsx +49 -0
- package/dist/ui/elements/funnel.works.ts +37 -0
- package/dist/ui/elements/gauge.js +1 -1
- package/dist/ui/elements/gauge.tsx +39 -0
- package/dist/ui/elements/gauge.works.ts +42 -0
- package/dist/ui/elements/glyph.js +1 -1
- package/dist/ui/elements/glyph.tsx +29 -0
- package/dist/ui/elements/glyph.works.tsx +42 -0
- package/dist/ui/elements/grid.js +1 -1
- package/dist/ui/elements/grid.tsx +28 -0
- package/dist/ui/elements/heatmap.js +2 -2
- package/dist/ui/elements/heatmap.tsx +47 -0
- package/dist/ui/elements/heatmap.works.ts +24 -0
- package/dist/ui/elements/hit-box.js +1 -1
- package/dist/ui/elements/hit-box.tsx +46 -0
- package/dist/ui/elements/hit-box.works.tsx +576 -0
- package/dist/ui/elements/image.js +1 -1
- package/dist/ui/elements/image.tsx +28 -0
- package/dist/ui/elements/line-chart.js +2 -2
- package/dist/ui/elements/line-chart.tsx +44 -0
- package/dist/ui/elements/line-chart.works.ts +41 -0
- package/dist/ui/elements/link.js +1 -1
- package/dist/ui/elements/link.tsx +37 -0
- package/dist/ui/elements/link.works.ts +25 -0
- package/dist/ui/elements/media.js +1 -1
- package/dist/ui/elements/media.tsx +56 -0
- package/dist/ui/elements/menu.js +2 -2
- package/dist/ui/elements/menu.tsx +50 -0
- package/dist/ui/elements/menu.works.tsx +153 -0
- package/dist/ui/elements/money.js +1 -1
- package/dist/ui/elements/money.tsx +28 -0
- package/dist/ui/elements/money.works.ts +9 -0
- package/dist/ui/elements/pagination.js +2 -2
- package/dist/ui/elements/pagination.tsx +38 -0
- package/dist/ui/elements/pagination.works.ts +20 -0
- package/dist/ui/elements/progress.js +1 -1
- package/dist/ui/elements/progress.tsx +33 -0
- package/dist/ui/elements/progress.works.ts +8 -0
- package/dist/ui/elements/radio-group.js +2 -2
- package/dist/ui/elements/radio-group.tsx +49 -0
- package/dist/ui/elements/radio-group.works.ts +33 -0
- package/dist/ui/elements/row.js +1 -1
- package/dist/ui/elements/row.tsx +28 -0
- package/dist/ui/elements/scatter.js +1 -1
- package/dist/ui/elements/scatter.tsx +41 -0
- package/dist/ui/elements/scatter.works.ts +38 -0
- package/dist/ui/elements/select.js +2 -2
- package/dist/ui/elements/select.tsx +42 -0
- package/dist/ui/elements/select.works.ts +5 -0
- package/dist/ui/elements/separator.js +1 -1
- package/dist/ui/elements/separator.tsx +30 -0
- package/dist/ui/elements/skeleton.js +1 -1
- package/dist/ui/elements/skeleton.tsx +30 -0
- package/dist/ui/elements/slider.js +1 -1
- package/dist/ui/elements/slider.tsx +33 -0
- package/dist/ui/elements/slider.works.ts +5 -0
- package/dist/ui/elements/sparkline.js +1 -1
- package/dist/ui/elements/sparkline.tsx +36 -0
- package/dist/ui/elements/sparkline.works.ts +32 -0
- package/dist/ui/elements/spinner.js +1 -1
- package/dist/ui/elements/spinner.tsx +32 -0
- package/dist/ui/elements/stack.js +1 -1
- package/dist/ui/elements/stack.tsx +28 -0
- package/dist/ui/elements/stat.js +1 -1
- package/dist/ui/elements/stat.tsx +35 -0
- package/dist/ui/elements/stat.works.ts +14 -0
- package/dist/ui/elements/surface.js +1 -1
- package/dist/ui/elements/surface.tsx +35 -0
- package/dist/ui/elements/surface.works.ts +9 -0
- package/dist/ui/elements/table.js +2 -2
- package/dist/ui/elements/table.tsx +61 -0
- package/dist/ui/elements/table.works.ts +30 -0
- package/dist/ui/elements/tabs.js +2 -2
- package/dist/ui/elements/tabs.tsx +47 -0
- package/dist/ui/elements/tabs.works.ts +84 -0
- package/dist/ui/elements/text.js +1 -1
- package/dist/ui/elements/text.tsx +32 -0
- package/dist/ui/elements/textarea.js +1 -1
- package/dist/ui/elements/textarea.tsx +37 -0
- package/dist/ui/elements/textarea.works.ts +5 -0
- package/dist/ui/elements/time.js +1 -1
- package/dist/ui/elements/time.tsx +34 -0
- package/dist/ui/elements/time.works.ts +25 -0
- package/dist/ui/elements/toggle.js +1 -1
- package/dist/ui/elements/toggle.tsx +33 -0
- package/dist/ui/elements/toggle.works.ts +5 -0
- package/dist/ui/elements/tooltip.js +1 -1
- package/dist/ui/elements/tooltip.tsx +39 -0
- package/dist/ui/elements/tooltip.works.ts +77 -0
- package/dist/ui/elements/value.js +1 -1
- package/dist/ui/elements/value.tsx +30 -0
- package/dist/ui/elements/value.works.ts +9 -0
- package/dist/ui/elements.ts +127 -0
- package/dist/ui/focus-scope.ts +121 -0
- package/dist/ui/fonts.ts +355 -0
- package/dist/ui/generators/dev.ts +79 -0
- package/dist/ui/generators/elements.d.ts +1 -11
- package/dist/ui/generators/elements.js +43 -13
- package/dist/ui/generators/elements.ts +794 -0
- package/dist/ui/generators/i18n.ts +301 -0
- package/dist/ui/generators/icons.ts +214 -0
- package/dist/ui/generators/react.js +10 -3
- package/dist/ui/generators/react.ts +268 -0
- package/dist/ui/generators/routes.d.ts +1 -0
- package/dist/ui/generators/routes.js +89 -69
- package/dist/ui/generators/routes.ts +739 -0
- package/dist/ui/generators/show.ts +259 -0
- package/dist/ui/generators/styles.js +1 -1
- package/dist/ui/generators/styles.ts +670 -0
- package/dist/ui/generators/variants.ts +205 -0
- package/dist/ui/i18n/catalogs/en.ts +191 -0
- package/dist/ui/i18n/format.ts +221 -0
- package/dist/ui/i18n/locales.ts +33 -0
- package/dist/ui/i18n/parse.ts +315 -0
- package/dist/ui/i18n/translator.ts +31 -0
- package/dist/ui/i18n/types.ts +96 -0
- package/dist/ui/icons.ts +331 -0
- package/dist/ui/islands/map.ts +58 -0
- package/dist/ui/localizations.ts +75 -0
- package/dist/ui/makers/message.ts +292 -0
- package/dist/ui/material.ts +236 -0
- package/dist/ui/materials/mat_bordered.ts +13 -0
- package/dist/ui/materials/mat_ceramic.ts +13 -0
- package/dist/ui/materials/mat_clay.ts +13 -0
- package/dist/ui/materials/mat_elevated.ts +24 -0
- package/dist/ui/materials/mat_flat.ts +34 -0
- package/dist/ui/materials/mat_glass.ts +20 -0
- package/dist/ui/materials/mat_lit.ts +13 -0
- package/dist/ui/materials/mat_moulded.ts +11 -0
- package/dist/ui/materials.ts +206 -0
- package/dist/ui/modes.ts +44 -0
- package/dist/ui/navigation.tsx +32 -0
- package/dist/ui/positioning.ts +90 -0
- package/dist/ui/presented.tsx +119 -0
- package/dist/ui/provider.d.ts +2 -0
- package/dist/ui/provider.js +7 -1
- package/dist/ui/provider.tsx +182 -0
- package/dist/ui/render-loop.ts +133 -0
- package/dist/ui/roving-focus.ts +161 -0
- package/dist/ui/screens.js +17 -8
- package/dist/ui/screens.ts +142 -0
- package/dist/ui/scroll-lock.ts +28 -0
- package/dist/ui/series.ts +97 -0
- package/dist/ui/signals.ts +386 -0
- package/dist/ui/styleguide.ts +231 -0
- package/dist/ui/styleguides.ts +374 -0
- package/dist/ui/themes.ts +22 -0
- package/dist/ui/token.js +1 -1
- package/dist/ui/token.ts +78 -0
- package/dist/ui/tokens/shadow.ts +25 -0
- package/dist/ui/tokens.ts +235 -0
- package/dist/ui/validators.ts +232 -0
- package/dist/ui/variant.d.ts +1 -0
- package/dist/ui/variant.js +3 -0
- package/dist/ui/variant.ts +352 -0
- package/dist/ui/variants/var_avatar-round.ts +14 -0
- package/dist/ui/variants/var_bubble-me.ts +14 -0
- package/dist/ui/variants/var_bubble-them.ts +13 -0
- package/dist/ui/variants/var_button-border.ts +76 -0
- package/dist/ui/variants/var_button-cta.ts +76 -0
- package/dist/ui/variants/var_button-destructive-ghost.ts +72 -0
- package/dist/ui/variants/var_button-destructive.ts +76 -0
- package/dist/ui/variants/var_button-fill.ts +76 -0
- package/dist/ui/variants/var_button-ghost.ts +72 -0
- package/dist/ui/variants/var_button-glass.ts +55 -0
- package/dist/ui/variants/var_button-normal.ts +76 -0
- package/dist/ui/variants/var_button-quiet.ts +74 -0
- package/dist/ui/variants/var_card.ts +17 -0
- package/dist/ui/variants/var_chip.ts +13 -0
- package/dist/ui/variants/var_choice.ts +15 -0
- package/dist/ui/variants/var_framed.ts +10 -0
- package/dist/ui/variants/var_glyph-plain.ts +11 -0
- package/dist/ui/variants/var_input.ts +43 -0
- package/dist/ui/variants/var_link-inline.ts +29 -0
- package/dist/ui/variants/var_list-row.ts +34 -0
- package/dist/ui/variants/var_rule.ts +10 -0
- package/dist/ui/variants/var_skeleton-block.ts +12 -0
- package/dist/ui/variants/var_spinner-turning.ts +12 -0
- package/dist/ui/variants/var_stat-tile.ts +13 -0
- package/dist/ui/variants/var_tab-bar.ts +15 -0
- package/dist/ui/variants/var_tap-target.ts +25 -0
- package/dist/ui/variants.ts +64 -0
- package/dist/ui/wrappers.d.ts +4 -1
- package/dist/ui/wrappers.js +60 -20
- package/dist/ui/wrappers.tsx +426 -0
- package/package.json +8 -2
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { argv, exit, stdout } from 'node:process'
|
|
4
|
+
import { pathToFileURL } from 'node:url'
|
|
5
|
+
|
|
6
|
+
import { ELSEWHERE, RECEIPT, answer, answering, asking, given, guidance, issue, marked, named, needed, only, prompted, refuse, spend, within, wordsIn, wrapped, type Asked } from '@prestack/thread/core/asking'
|
|
7
|
+
import { named as packageOf } from '@prestack/thread/core/scope'
|
|
8
|
+
import { findTree, inTree } from '@prestack/thread/core/tree'
|
|
9
|
+
|
|
10
|
+
import { keyProps, keysIn, readWording, walk, wordingFile } from '../generators/i18n.ts'
|
|
11
|
+
import { fileFor, languagesIn, sourceIn } from '../localizations.ts'
|
|
12
|
+
|
|
13
|
+
const TREE = findTree()
|
|
14
|
+
|
|
15
|
+
const DOTTED = /^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/
|
|
16
|
+
|
|
17
|
+
const KEY: Asked = { at: 'key', guide: 'lowercase words joined by dots — `checkout.confirm`, `errors.db.not_found.title`' }
|
|
18
|
+
|
|
19
|
+
interface Row {
|
|
20
|
+
readonly id: string
|
|
21
|
+
readonly is?: string
|
|
22
|
+
readonly sets?: Readonly<Record<string, string>>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function languages(): Promise<{
|
|
26
|
+
readonly held: readonly { readonly id: string; readonly name: string; readonly flag: string }[]
|
|
27
|
+
readonly source: string
|
|
28
|
+
}> {
|
|
29
|
+
const path = inTree(TREE, `localizations.${'ts'}`)
|
|
30
|
+
let sheet: { LOCALIZATION?: { readonly holds?: readonly Row[]; readonly declares?: readonly Row[] } } = {}
|
|
31
|
+
try {
|
|
32
|
+
sheet = (await import(pathToFileURL(path).href)) as typeof sheet
|
|
33
|
+
} catch {
|
|
34
|
+
sheet = {}
|
|
35
|
+
}
|
|
36
|
+
if (sheet.LOCALIZATION === undefined) {
|
|
37
|
+
refuse(
|
|
38
|
+
`there is no ${within(TREE.at, path)} declaring a \`LOCALIZATION\` here, so this app is in no ` +
|
|
39
|
+
`language and a message has nowhere to go. Run \`npx thread attach ${packageOf('ui')}\`.`,
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
const rows = [...(sheet.LOCALIZATION.holds ?? []), ...(sheet.LOCALIZATION.declares ?? [])]
|
|
43
|
+
const held = languagesIn(rows)
|
|
44
|
+
const source = sourceIn(rows)
|
|
45
|
+
if (held.length === 0 || source === undefined) {
|
|
46
|
+
refuse('no language is declared, so there is nothing to write a message in. Add one with `npx thread create language`.')
|
|
47
|
+
}
|
|
48
|
+
return { held, source }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function usage(props: readonly string[]): ReadonlyMap<string, readonly string[]> {
|
|
52
|
+
const found = new Map<string, string[]>()
|
|
53
|
+
for (const file of walk(TREE.at)) {
|
|
54
|
+
const text = readFileSync(file, 'utf8')
|
|
55
|
+
for (const key of new Set(keysIn(text, props))) {
|
|
56
|
+
const held = found.get(key) ?? []
|
|
57
|
+
held.push(within(TREE.at, file))
|
|
58
|
+
found.set(key, held)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return found
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const mark = (key: string, said: string): string => marked([key, said])
|
|
65
|
+
|
|
66
|
+
function write(at: string, language: string, held: Readonly<Record<string, string>>): void {
|
|
67
|
+
writeFileSync(join(at, fileFor(language)), wordingFile(held), 'utf8')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function run(): Promise<number> {
|
|
71
|
+
const { held: spoken, source } = await languages()
|
|
72
|
+
const props = keyProps(TREE.at)
|
|
73
|
+
if (props.length === 0) {
|
|
74
|
+
refuse(
|
|
75
|
+
`nothing in the installed \`${packageOf('ui')}\` declares a prop of type \`MessageKey\`, so no key could be ` +
|
|
76
|
+
'recognised anywhere. That is a broken install rather than an app with no wording.',
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const LANGUAGES: readonly Asked[] = spoken.map((one) => ({ at: one.id, guide: `what it says in ${one.name}` }))
|
|
81
|
+
|
|
82
|
+
const NEW: readonly Asked[] = [KEY, ...LANGUAGES]
|
|
83
|
+
|
|
84
|
+
const wording = new Map<string, Record<string, string>>()
|
|
85
|
+
for (const one of spoken) wording.set(one.id, { ...readWording(TREE.at, one.id) })
|
|
86
|
+
|
|
87
|
+
const written = wording.get(source) ?? {}
|
|
88
|
+
const keys = Object.keys(written).sort()
|
|
89
|
+
const used = usage(props)
|
|
90
|
+
|
|
91
|
+
const blank = (key: string): readonly string[] =>
|
|
92
|
+
spoken.filter((one) => ((wording.get(one.id) ?? {})[key] ?? '') === '').map((one) => one.id)
|
|
93
|
+
|
|
94
|
+
const listing = [
|
|
95
|
+
`${String(keys.length)} message(s), in ${spoken.map((one) => one.id).join(', ')} — written in ${source}:`,
|
|
96
|
+
'',
|
|
97
|
+
|
|
98
|
+
...keys.map((key) => {
|
|
99
|
+
const missing = blank(key)
|
|
100
|
+
const said = (written[key] ?? '') || '(nothing yet)'
|
|
101
|
+
return (
|
|
102
|
+
` [${mark(key, written[key] ?? '')}] ${key.padEnd(38)} ${said.length > 46 ? `${said.slice(0, 45)}…` : said}` +
|
|
103
|
+
`${missing.length === 0 ? '' : ` · still to write: ${missing.join(', ')}`}` +
|
|
104
|
+
`${(used.get(key) ?? []).length === 0 ? ' · named by nothing here' : ''}`
|
|
105
|
+
)
|
|
106
|
+
}),
|
|
107
|
+
].join('\n')
|
|
108
|
+
|
|
109
|
+
const words = wordsIn(['new'])
|
|
110
|
+
const verb = words[0]
|
|
111
|
+
|
|
112
|
+
const flagged = argv.indexOf(RECEIPT)
|
|
113
|
+
if (flagged === -1) {
|
|
114
|
+
stdout.write(`${listing}\n`)
|
|
115
|
+
const nonce = issue(TREE.at, listing)
|
|
116
|
+
stdout.write(
|
|
117
|
+
[
|
|
118
|
+
'',
|
|
119
|
+
...answering('message'),
|
|
120
|
+
'',
|
|
121
|
+
...guidance(NEW),
|
|
122
|
+
'',
|
|
123
|
+
...wrapped(
|
|
124
|
+
'Every language is asked for and none may be left blank. A key that exists in one language and ' +
|
|
125
|
+
'not another is what makes a screen come out half translated, and it is refused here rather ' +
|
|
126
|
+
'than found by whoever is reading the app in the other one.',
|
|
127
|
+
' ',
|
|
128
|
+
),
|
|
129
|
+
'',
|
|
130
|
+
` npx thread create message new ${RECEIPT} ${nonce}`,
|
|
131
|
+
'',
|
|
132
|
+
...ELSEWHERE,
|
|
133
|
+
'',
|
|
134
|
+
...wrapped(
|
|
135
|
+
'A rename moves the wording in every language and rewrites every file in the interface that ' +
|
|
136
|
+
'names it, in one run.',
|
|
137
|
+
' ',
|
|
138
|
+
),
|
|
139
|
+
'',
|
|
140
|
+
].join('\n'),
|
|
141
|
+
)
|
|
142
|
+
stdout.write(`create: receipt ${nonce} — spent on use, and stale the moment the wording changes.\n`)
|
|
143
|
+
return 0
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
spend(TREE.at, listing, argv[flagged + 1], `the wording`)
|
|
147
|
+
|
|
148
|
+
const all = given()
|
|
149
|
+
const { piped, ask, shut } = asking(all)
|
|
150
|
+
|
|
151
|
+
const ASKS: Readonly<Record<string, readonly string[]>> = {
|
|
152
|
+
new: ['do', ...named(NEW)],
|
|
153
|
+
edit: ['do', 'mark', ...named(NEW)],
|
|
154
|
+
remove: ['do', 'mark'],
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const doing = verb ?? (await ask('do', 'new, edit or remove: '))
|
|
158
|
+
const allowed = ASKS[doing]
|
|
159
|
+
if (allowed === undefined) {
|
|
160
|
+
shut()
|
|
161
|
+
refuse(`there is nothing called "${doing}" to do here — say new, edit, remove, or read, which needs no receipt`)
|
|
162
|
+
}
|
|
163
|
+
if (piped) only(all, allowed, `\`${doing}\``)
|
|
164
|
+
|
|
165
|
+
if (doing === 'remove' || doing === 'edit') {
|
|
166
|
+
const which = words[1] ?? (piped ? needed(all, 'mark', `\`${doing}\``) : await ask('mark', 'mark: '))
|
|
167
|
+
const one = keys.find((key) => mark(key, written[key] ?? '') === which)
|
|
168
|
+
if (one === undefined) {
|
|
169
|
+
shut()
|
|
170
|
+
refuse(`\`${which}\` is not a mark this sheet issued — they are printed in brackets beside each message.`)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (doing === 'remove') {
|
|
174
|
+
const where = used.get(one) ?? []
|
|
175
|
+
if (where.length > 0) {
|
|
176
|
+
shut()
|
|
177
|
+
refuse(
|
|
178
|
+
`\`${one}\` is named by ${where.slice(0, 6).join(', ')}` +
|
|
179
|
+
`${where.length > 6 ? ` and ${String(where.length - 6)} more` : ''}. ` +
|
|
180
|
+
'Removing it would leave those asking for wording that does not exist, which throws the moment ' +
|
|
181
|
+
'the screen renders. Take it out of the interface first.',
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
shut()
|
|
185
|
+
for (const language of spoken) {
|
|
186
|
+
const made = { ...(wording.get(language.id) ?? {}) }
|
|
187
|
+
delete made[one]
|
|
188
|
+
write(TREE.at, language.id, made)
|
|
189
|
+
}
|
|
190
|
+
stdout.write(`create: removed ${one} from ${String(spoken.length)} language file(s)\n`)
|
|
191
|
+
return 0
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const renamed = piped ? (answer(all, KEY.at) ?? '') : await ask(KEY.at, `key (${one}, blank to keep) `)
|
|
195
|
+
if (renamed !== '' && !DOTTED.test(renamed)) {
|
|
196
|
+
shut()
|
|
197
|
+
refuse(`\`${renamed}\` is not a key — lowercase words joined by dots.`)
|
|
198
|
+
}
|
|
199
|
+
if (renamed !== '' && written[renamed] !== undefined) {
|
|
200
|
+
shut()
|
|
201
|
+
refuse(`\`${renamed}\` is already a message. Two keys with one name is one key, and the other's wording is lost.`)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const said = new Map<string, string>()
|
|
205
|
+
for (const language of spoken) {
|
|
206
|
+
const now = (wording.get(language.id) ?? {})[one] ?? ''
|
|
207
|
+
const next = piped
|
|
208
|
+
? (answer(all, language.id) ?? '')
|
|
209
|
+
: await ask(language.id, `${language.name} (${now || 'nothing yet'}) `)
|
|
210
|
+
said.set(language.id, next === '' ? now : next)
|
|
211
|
+
}
|
|
212
|
+
shut()
|
|
213
|
+
|
|
214
|
+
const name = renamed === '' ? one : renamed
|
|
215
|
+
for (const language of spoken) {
|
|
216
|
+
const made = { ...(wording.get(language.id) ?? {}) }
|
|
217
|
+
delete made[one]
|
|
218
|
+
made[name] = said.get(language.id) ?? ''
|
|
219
|
+
write(TREE.at, language.id, made)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
let moved = 0
|
|
223
|
+
if (renamed !== '') {
|
|
224
|
+
for (const file of walk(TREE.at)) {
|
|
225
|
+
const text = readFileSync(file, 'utf8')
|
|
226
|
+
if (!keysIn(text, props).includes(one)) continue
|
|
227
|
+
writeFileSync(
|
|
228
|
+
file,
|
|
229
|
+
text.replace(
|
|
230
|
+
new RegExp(`(\\b(?:${props.join('|')})\\s*=\\s*")${one.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(")`, 'g'),
|
|
231
|
+
`$1${name}$2`,
|
|
232
|
+
),
|
|
233
|
+
'utf8',
|
|
234
|
+
)
|
|
235
|
+
moved += 1
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
stdout.write(
|
|
240
|
+
`create: ${one}${renamed === '' ? '' : ` is now ${name}`} — rewritten in ${String(spoken.length)} language file(s)` +
|
|
241
|
+
`${moved === 0 ? '' : ` and ${String(moved)} file(s) of the interface`}\n`,
|
|
242
|
+
)
|
|
243
|
+
const still = blankIn(said, spoken)
|
|
244
|
+
if (still.length > 0) {
|
|
245
|
+
stdout.write(`create: still nothing in ${still.join(', ')} — the gate refuses while that holds.\n`)
|
|
246
|
+
}
|
|
247
|
+
return 0
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const key = piped ? needed(all, KEY.at, '`new`') : await ask(KEY.at, prompted(KEY))
|
|
251
|
+
if (!DOTTED.test(key)) {
|
|
252
|
+
shut()
|
|
253
|
+
refuse(`\`${key}\` is not a key — lowercase words joined by dots, like \`checkout.confirm\`.`)
|
|
254
|
+
}
|
|
255
|
+
if (written[key] !== undefined) {
|
|
256
|
+
shut()
|
|
257
|
+
refuse(`\`${key}\` is already a message. Edit it by its mark, or choose another key.`)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const said = new Map<string, string>()
|
|
261
|
+
for (const language of spoken) {
|
|
262
|
+
const next = piped
|
|
263
|
+
? (answer(all, language.id) ?? '')
|
|
264
|
+
: await ask(language.id, `what it says in ${language.name}: `)
|
|
265
|
+
if (next === '') {
|
|
266
|
+
shut()
|
|
267
|
+
refuse(
|
|
268
|
+
`\`${key}\` has nothing to say in ${language.name}. Every language is answered at the moment a key ` +
|
|
269
|
+
'is made, because a key that exists in one language and not another is a screen that comes out ' +
|
|
270
|
+
'half translated. There is no way past this on purpose.',
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
said.set(language.id, next)
|
|
274
|
+
}
|
|
275
|
+
shut()
|
|
276
|
+
|
|
277
|
+
for (const language of spoken) {
|
|
278
|
+
write(TREE.at, language.id, { ...(wording.get(language.id) ?? {}), [key]: said.get(language.id) ?? '' })
|
|
279
|
+
}
|
|
280
|
+
stdout.write(`create: wrote ${key} in ${spoken.map((one) => one.id).join(', ')}\n`)
|
|
281
|
+
stdout.write(`create: name it in the interface with one of: ${props.join(', ')} — for example \`label="${key}"\`.\n`)
|
|
282
|
+
return 0
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function blankIn(
|
|
286
|
+
said: ReadonlyMap<string, string>,
|
|
287
|
+
spoken: readonly { readonly id: string }[],
|
|
288
|
+
): readonly string[] {
|
|
289
|
+
return spoken.filter((one) => (said.get(one.id) ?? '') === '').map((one) => one.id)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (argv[1] !== undefined) exit(await run())
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { held, naming, sheeted, type Holds, type Token, type Wearing } from './token.ts'
|
|
2
|
+
|
|
3
|
+
export interface Setting {
|
|
4
|
+
readonly property: string
|
|
5
|
+
|
|
6
|
+
readonly is?: string
|
|
7
|
+
|
|
8
|
+
readonly token?: string
|
|
9
|
+
|
|
10
|
+
readonly asks?: Readonly<Record<string, string | number>>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const BOUND = {
|
|
14
|
+
background: ['colour', 'gradient', 'texture', 'noise', 'img'],
|
|
15
|
+
backgroundImage: ['gradient', 'texture', 'noise', 'img'],
|
|
16
|
+
backdropFilter: ['blur'],
|
|
17
|
+
borderWidth: ['edge'],
|
|
18
|
+
borderStyle: ['line'],
|
|
19
|
+
borderColor: ['colour'],
|
|
20
|
+
boxShadow: ['shadow'],
|
|
21
|
+
color: ['colour'],
|
|
22
|
+
opacity: ['opacity'],
|
|
23
|
+
} as const
|
|
24
|
+
|
|
25
|
+
type Property = keyof typeof BOUND
|
|
26
|
+
|
|
27
|
+
type MaterialSettingFor<P extends Property> = {
|
|
28
|
+
readonly property: P
|
|
29
|
+
|
|
30
|
+
readonly is?: string
|
|
31
|
+
|
|
32
|
+
readonly token?: (typeof BOUND)[P][number]
|
|
33
|
+
|
|
34
|
+
readonly asks?: Readonly<Record<string, string | number>>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type MaterialSetting = { [P in Property]: MaterialSettingFor<P> }[Property]
|
|
38
|
+
|
|
39
|
+
export interface Material {
|
|
40
|
+
readonly id: string
|
|
41
|
+
|
|
42
|
+
readonly sets: readonly MaterialSetting[]
|
|
43
|
+
|
|
44
|
+
readonly states?: readonly {
|
|
45
|
+
readonly when: readonly string[]
|
|
46
|
+
readonly sets: readonly MaterialSetting[]
|
|
47
|
+
}[]
|
|
48
|
+
|
|
49
|
+
readonly plays?: string
|
|
50
|
+
|
|
51
|
+
readonly keyframes?: readonly {
|
|
52
|
+
readonly id: string
|
|
53
|
+
readonly sets: Readonly<Record<string, readonly MaterialSetting[]>>
|
|
54
|
+
}[]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const FREE = ['transition', 'outline'] as const
|
|
58
|
+
|
|
59
|
+
export const material = <const T extends Material>(
|
|
60
|
+
one: T & {
|
|
61
|
+
readonly sets: {
|
|
62
|
+
readonly [I in keyof T['sets']]: T['sets'][I] extends { readonly is: infer Said }
|
|
63
|
+
? { readonly is: Wearing<Said & string> }
|
|
64
|
+
: unknown
|
|
65
|
+
}
|
|
66
|
+
} & (T extends { readonly states: infer States }
|
|
67
|
+
? {
|
|
68
|
+
readonly states: {
|
|
69
|
+
readonly [S in keyof States]: States[S] extends { readonly sets: infer Sets }
|
|
70
|
+
? {
|
|
71
|
+
readonly sets: {
|
|
72
|
+
readonly [I in keyof Sets]: Sets[I] extends { readonly is: infer Said }
|
|
73
|
+
? { readonly is: Wearing<Said & string> }
|
|
74
|
+
: unknown
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
: unknown
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
: unknown) &
|
|
81
|
+
(T extends { readonly keyframes: infer Frames }
|
|
82
|
+
? {
|
|
83
|
+
readonly keyframes: {
|
|
84
|
+
readonly [F in keyof Frames]: Frames[F] extends { readonly sets: infer Stops }
|
|
85
|
+
? {
|
|
86
|
+
readonly sets: {
|
|
87
|
+
readonly [Stop in keyof Stops]: {
|
|
88
|
+
readonly [I in keyof Stops[Stop]]: Stops[Stop][I] extends { readonly is: infer Said }
|
|
89
|
+
? { readonly is: Wearing<Said & string> }
|
|
90
|
+
: unknown
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
: unknown
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
: unknown),
|
|
98
|
+
): T => one
|
|
99
|
+
|
|
100
|
+
function rowsIn(value: string): readonly string[] {
|
|
101
|
+
return value.split(/\s+/).filter((one) => one !== '')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function bounded(
|
|
105
|
+
set: Setting,
|
|
106
|
+
by: string,
|
|
107
|
+
kinds: Readonly<Record<string, string>>,
|
|
108
|
+
bound: Readonly<Record<string, readonly string[]>>,
|
|
109
|
+
): void {
|
|
110
|
+
const value = set.is ?? ''
|
|
111
|
+
|
|
112
|
+
const rows = rowsIn(value)
|
|
113
|
+
|
|
114
|
+
const allowed = bound[set.property]
|
|
115
|
+
if (allowed === undefined) return
|
|
116
|
+
|
|
117
|
+
for (const row of rows) {
|
|
118
|
+
const kind = kinds[row]
|
|
119
|
+
if (kind === undefined || allowed.includes(kind)) continue
|
|
120
|
+
const list = allowed.map((one) => `\`${one}\``).join(' · ')
|
|
121
|
+
throw new Error(
|
|
122
|
+
`\`${by}\` sets \`${set.property}\` to \`${row}\`, and \`${row}\` is a \`${kind}\` row. ` +
|
|
123
|
+
`\`${set.property}\` takes: ${list}.`,
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function valued(
|
|
129
|
+
set: Setting,
|
|
130
|
+
named: ReadonlySet<string>,
|
|
131
|
+
tokens: Readonly<Record<string, Token>>,
|
|
132
|
+
by: string,
|
|
133
|
+
kinds: Readonly<Record<string, string>> | undefined,
|
|
134
|
+
bound: Readonly<Record<string, readonly string[]>>,
|
|
135
|
+
): Holds {
|
|
136
|
+
if (set.is !== undefined && set.token !== undefined) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`\`${by}\` states both a value and a token for \`${set.property}\`. A property is either a ` +
|
|
139
|
+
'value the style guide holds or a token asked for one, never both.',
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (set.is !== undefined) {
|
|
144
|
+
if (kinds !== undefined) bounded(set, by, kinds, bound)
|
|
145
|
+
return naming(named, set.is, by, set.property)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (set.token === undefined) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`\`${by}\` sets \`${set.property}\` to nothing. State a value with \`is\`, or name a token ` +
|
|
151
|
+
'and what to ask it for.',
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const token = tokens[set.token]
|
|
156
|
+
if (token === undefined) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`\`${by}\` asks \`${set.token}\` for \`${set.property}\`, and no token by that name is ` +
|
|
159
|
+
'declared. A token has to exist before anything can ask it for a value.',
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (token.makes === undefined) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`\`${by}\` asks \`${set.token}\` for \`${set.property}\`, and \`${set.token}\` carries no ` +
|
|
166
|
+
'rule, so there is nothing to ask. Name a style guide value instead.',
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return held(named, token.makes(set.asks ?? {}), by)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function composed(
|
|
174
|
+
sets: readonly Setting[],
|
|
175
|
+
named: ReadonlySet<string>,
|
|
176
|
+
tokens: Readonly<Record<string, Token>>,
|
|
177
|
+
by: string,
|
|
178
|
+
kinds: Readonly<Record<string, string>>,
|
|
179
|
+
bound: Readonly<Record<string, readonly string[]>>,
|
|
180
|
+
): Readonly<Record<string, Holds>> {
|
|
181
|
+
const made: Record<string, Holds> = {}
|
|
182
|
+
for (const set of sets) {
|
|
183
|
+
|
|
184
|
+
if (bound[set.property] === undefined && (set.property === 'animation' || set.property === 'animationName')) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`\`${by}\` sets \`${set.property}\` itself, which buries the keyframes name inside a ` +
|
|
187
|
+
'string where nothing can check it. Name a style guide row of the `animation` kind, or ' +
|
|
188
|
+
'declare keyframes and name them with `plays`.',
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
made[set.property] = valued(set, named, tokens, by, kinds, bound)
|
|
192
|
+
}
|
|
193
|
+
return made
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function playing(material: Material, plays: string | undefined): Readonly<Record<string, Holds>> {
|
|
197
|
+
if (plays === undefined) return {}
|
|
198
|
+
if ((material.keyframes ?? []).some((one) => one.id === plays)) return { animationName: sheeted(material.id, plays) }
|
|
199
|
+
const declared = (material.keyframes ?? []).map((one) => one.id)
|
|
200
|
+
throw new Error(
|
|
201
|
+
`\`${material.id}\` plays \`${plays}\`, and declares no keyframes by that name. ` +
|
|
202
|
+
(declared.length === 0
|
|
203
|
+
? 'It declares none at all, so there is nothing for it to play.'
|
|
204
|
+
: `It declares: ${declared.join(' · ')}.`),
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function compose(
|
|
209
|
+
material: Material,
|
|
210
|
+
named: ReadonlySet<string>,
|
|
211
|
+
tokens: Readonly<Record<string, Token>>,
|
|
212
|
+
kinds: Readonly<Record<string, string>>,
|
|
213
|
+
): Readonly<Record<string, Holds>> {
|
|
214
|
+
return {
|
|
215
|
+
...composed(material.sets, named, tokens, material.id, kinds, BOUND),
|
|
216
|
+
...playing(material, material.plays),
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function keyframesOf(
|
|
221
|
+
material: Material,
|
|
222
|
+
named: ReadonlySet<string>,
|
|
223
|
+
tokens: Readonly<Record<string, Token>>,
|
|
224
|
+
kinds: Readonly<Record<string, string>>,
|
|
225
|
+
): readonly {
|
|
226
|
+
readonly id: string
|
|
227
|
+
readonly stops: readonly { readonly stop: string; readonly made: Readonly<Record<string, Holds>> }[]
|
|
228
|
+
}[] {
|
|
229
|
+
return (material.keyframes ?? []).map((one) => ({
|
|
230
|
+
id: one.id,
|
|
231
|
+
stops: Object.keys(one.sets).map((stop) => ({
|
|
232
|
+
stop,
|
|
233
|
+
made: composed(one.sets[stop] ?? [], named, tokens, material.id, kinds, BOUND),
|
|
234
|
+
})),
|
|
235
|
+
}))
|
|
236
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { material } from '../material.ts'
|
|
2
|
+
|
|
3
|
+
export const BORDERED = material({
|
|
4
|
+
id: 'bordered',
|
|
5
|
+
sets: [
|
|
6
|
+
{ property: 'background', is: 'colour-surface' },
|
|
7
|
+
{ property: 'borderWidth', is: 'edge-thick' },
|
|
8
|
+
{ property: 'borderStyle', is: 'line-solid' },
|
|
9
|
+
{ property: 'borderColor', is: 'colour-ink' },
|
|
10
|
+
{ property: 'boxShadow', is: 'shadow-hard' },
|
|
11
|
+
{ property: 'color', is: 'colour-ink' },
|
|
12
|
+
],
|
|
13
|
+
} as const)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { material } from '../material.ts'
|
|
2
|
+
|
|
3
|
+
export const CERAMIC = material({
|
|
4
|
+
id: 'ceramic',
|
|
5
|
+
sets: [
|
|
6
|
+
{ property: 'backgroundImage', is: 'gradient-sheen' },
|
|
7
|
+
{ property: 'borderWidth', is: 'edge-hair' },
|
|
8
|
+
{ property: 'borderStyle', is: 'line-solid' },
|
|
9
|
+
{ property: 'borderColor', is: 'colour-edge-ceramic' },
|
|
10
|
+
{ property: 'boxShadow', is: 'shadow-2' },
|
|
11
|
+
{ property: 'color', is: 'colour-ink' },
|
|
12
|
+
],
|
|
13
|
+
} as const)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { material } from '../material.ts'
|
|
2
|
+
|
|
3
|
+
export const CLAY = material({
|
|
4
|
+
id: 'clay',
|
|
5
|
+
sets: [
|
|
6
|
+
{ property: 'background', is: 'colour-surface' },
|
|
7
|
+
{ property: 'borderWidth', is: 'edge-thin' },
|
|
8
|
+
{ property: 'borderStyle', is: 'line-solid' },
|
|
9
|
+
{ property: 'borderColor', is: 'colour-edge-clay' },
|
|
10
|
+
{ property: 'boxShadow', is: 'shadow-2' },
|
|
11
|
+
{ property: 'color', is: 'colour-ink' },
|
|
12
|
+
],
|
|
13
|
+
} as const)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { material } from '../material.ts'
|
|
2
|
+
|
|
3
|
+
export const ELEVATED = material({
|
|
4
|
+
id: 'elevated',
|
|
5
|
+
sets: [
|
|
6
|
+
{ property: 'background', is: 'colour-surface' },
|
|
7
|
+
{ property: 'boxShadow', is: 'shadow-2' },
|
|
8
|
+
{ property: 'color', is: 'colour-ink' },
|
|
9
|
+
],
|
|
10
|
+
states: [
|
|
11
|
+
{
|
|
12
|
+
when: ['hover'],
|
|
13
|
+
sets: [{ property: 'boxShadow', is: 'shadow-3' }],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
when: ['active'],
|
|
17
|
+
sets: [{ property: 'boxShadow', is: 'shadow-1' }],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
when: ['active', 'hover'],
|
|
21
|
+
sets: [{ property: 'boxShadow', is: 'shadow-1' }],
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
} as const)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { material } from '../material.ts'
|
|
2
|
+
|
|
3
|
+
export const FLAT = material({
|
|
4
|
+
id: 'flat',
|
|
5
|
+
sets: [
|
|
6
|
+
{ property: 'background', is: 'colour-surface' },
|
|
7
|
+
{ property: 'borderWidth', is: 'edge-hair' },
|
|
8
|
+
{ property: 'borderStyle', is: 'line-solid' },
|
|
9
|
+
{ property: 'borderColor', is: 'colour-edge-faint' },
|
|
10
|
+
{ property: 'boxShadow', is: 'shadow-1' },
|
|
11
|
+
{ property: 'color', is: 'colour-ink' },
|
|
12
|
+
],
|
|
13
|
+
states: [
|
|
14
|
+
{
|
|
15
|
+
when: ['hover'],
|
|
16
|
+
sets: [{ property: 'boxShadow', is: 'shadow-2' }],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
when: ['focus'],
|
|
20
|
+
sets: [
|
|
21
|
+
{ property: 'borderColor', is: 'colour-accent' },
|
|
22
|
+
{ property: 'borderWidth', is: 'edge-thick' },
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
when: ['focus', 'hover'],
|
|
27
|
+
sets: [
|
|
28
|
+
{ property: 'borderColor', is: 'colour-accent' },
|
|
29
|
+
{ property: 'borderWidth', is: 'edge-thick' },
|
|
30
|
+
{ property: 'boxShadow', is: 'shadow-2' },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
} as const)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { material } from '../material.ts'
|
|
2
|
+
|
|
3
|
+
export const GLASS = material({
|
|
4
|
+
id: 'glass',
|
|
5
|
+
sets: [
|
|
6
|
+
{ property: 'background', is: 'colour-glass' },
|
|
7
|
+
{ property: 'backdropFilter', is: 'blur-md' },
|
|
8
|
+
{ property: 'borderWidth', is: 'edge-hair' },
|
|
9
|
+
{ property: 'borderStyle', is: 'line-solid' },
|
|
10
|
+
{ property: 'borderColor', is: 'colour-edge-glass' },
|
|
11
|
+
{ property: 'boxShadow', is: 'shadow-3' },
|
|
12
|
+
{ property: 'color', is: 'colour-ink' },
|
|
13
|
+
],
|
|
14
|
+
states: [
|
|
15
|
+
{
|
|
16
|
+
when: ['hover'],
|
|
17
|
+
sets: [{ property: 'backdropFilter', is: 'blur-lg' }],
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
} as const)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { material } from '../material.ts'
|
|
2
|
+
|
|
3
|
+
export const LIT = material({
|
|
4
|
+
id: 'lit',
|
|
5
|
+
sets: [
|
|
6
|
+
{ property: 'background', is: 'colour-surface-lit' },
|
|
7
|
+
{ property: 'borderWidth', is: 'edge-thin' },
|
|
8
|
+
{ property: 'borderStyle', is: 'line-solid' },
|
|
9
|
+
{ property: 'borderColor', is: 'colour-edge-lit' },
|
|
10
|
+
{ property: 'boxShadow', is: 'shadow-glow' },
|
|
11
|
+
{ property: 'color', is: 'colour-ink' },
|
|
12
|
+
],
|
|
13
|
+
} as const)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { material } from '../material.ts'
|
|
2
|
+
|
|
3
|
+
export const MOULDED = material({
|
|
4
|
+
id: 'moulded',
|
|
5
|
+
sets: [
|
|
6
|
+
{ property: 'background', is: 'colour-page' },
|
|
7
|
+
{ property: 'borderStyle', is: 'line-off' },
|
|
8
|
+
{ property: 'boxShadow', is: 'shadow-moulded' },
|
|
9
|
+
{ property: 'color', is: 'colour-ink' },
|
|
10
|
+
],
|
|
11
|
+
} as const)
|