@treeseed/core 0.10.22 → 0.11.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 +69 -125
- package/dist/dev-watch.js +2 -1
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +51 -35
- package/dist/pages/404.astro +1 -1
- package/dist/pages/[slug].astro +4 -4
- package/dist/pages/agents/[slug].astro +3 -3
- package/dist/pages/agents/index.astro +3 -3
- package/dist/pages/books/[slug].astro +3 -3
- package/dist/pages/books/index.astro +3 -3
- package/dist/pages/contact.astro +2 -2
- package/dist/pages/decisions/[slug].astro +3 -3
- package/dist/pages/decisions/index.astro +3 -3
- package/dist/pages/docs-runtime/[...slug].astro +3 -3
- package/dist/pages/docs-runtime/index.astro +3 -3
- package/dist/pages/index.astro +11 -11
- package/dist/pages/notes/[slug].astro +3 -3
- package/dist/pages/notes/index.astro +3 -3
- package/dist/pages/objectives/[slug].astro +3 -3
- package/dist/pages/objectives/index.astro +3 -3
- package/dist/pages/people/[slug].astro +3 -3
- package/dist/pages/people/index.astro +3 -3
- package/dist/pages/proposals/[slug].astro +3 -3
- package/dist/pages/proposals/index.astro +3 -3
- package/dist/pages/questions/[slug].astro +3 -3
- package/dist/pages/questions/index.astro +3 -3
- package/dist/pages/ui/index.astro +23 -23
- package/dist/platform-resources.js +5 -1
- package/dist/scripts/build-dist.js +2 -0
- package/dist/scripts/release-verify.js +24 -2
- package/dist/scripts/workspace-bootstrap.js +3 -0
- package/dist/site.js +49 -11
- package/dist/styles/global.css +5 -5
- package/package.json +3 -45
- package/templates/github/deploy-web.workflow.yml +36 -2
- package/dist/components/DevWatchReload.astro +0 -45
- package/dist/components/SiteTitle.astro +0 -51
- package/dist/components/content/ContentStatusLegend.astro +0 -18
- package/dist/components/content/StatusBadge.astro +0 -11
- package/dist/components/docs/BookFontControls.astro +0 -180
- package/dist/components/docs/DesktopSidebarToggle.astro +0 -88
- package/dist/components/docs/DownloadBook.astro +0 -34
- package/dist/components/docs/Footer.astro +0 -112
- package/dist/components/docs/Header.astro +0 -157
- package/dist/components/docs/PageFrame.astro +0 -260
- package/dist/components/docs/PageSidebar.astro +0 -63
- package/dist/components/docs/PageTitle.astro +0 -39
- package/dist/components/docs/Sidebar.astro +0 -41
- package/dist/components/docs/ThemeSelect.astro +0 -5
- package/dist/components/forms/ContactForm.astro +0 -233
- package/dist/components/forms/FooterSubscribeForm.astro +0 -188
- package/dist/components/site/BookList.astro +0 -27
- package/dist/components/site/CTASection.astro +0 -24
- package/dist/components/site/ChronicleList.astro +0 -33
- package/dist/components/site/Hero.astro +0 -18
- package/dist/components/site/NotesList.astro +0 -29
- package/dist/components/site/PathCard.astro +0 -16
- package/dist/components/site/ProfileList.astro +0 -30
- package/dist/components/site/PublishedContentBody.astro +0 -5
- package/dist/components/site/RouteNotFound.astro +0 -25
- package/dist/components/site/SectionIntro.astro +0 -9
- package/dist/components/site/StageBanner.astro +0 -8
- package/dist/components/site/TrustCallout.astro +0 -9
- package/dist/components/starlight.js +0 -6
- package/dist/components/ui/data/ActionList.astro +0 -51
- package/dist/components/ui/data/Badge.astro +0 -19
- package/dist/components/ui/data/DataTable.astro +0 -51
- package/dist/components/ui/data/KeyValueList.astro +0 -28
- package/dist/components/ui/data/MetricCard.astro +0 -25
- package/dist/components/ui/data/MetricGrid.astro +0 -27
- package/dist/components/ui/data/StatusPill.astro +0 -20
- package/dist/components/ui/forms/Button.astro +0 -59
- package/dist/components/ui/forms/Field.astro +0 -39
- package/dist/components/ui/forms/FormActions.astro +0 -12
- package/dist/components/ui/forms/PasswordMeter.astro +0 -80
- package/dist/components/ui/forms/RadioGroup.astro +0 -55
- package/dist/components/ui/forms/Select.astro +0 -47
- package/dist/components/ui/forms/TextInput.astro +0 -58
- package/dist/components/ui/forms/Textarea.astro +0 -45
- package/dist/components/ui/layout/PageHeader.astro +0 -45
- package/dist/components/ui/shell/AppShell.astro +0 -130
- package/dist/components/ui/shell/BottomNav.astro +0 -42
- package/dist/components/ui/shell/ProjectHeader.astro +0 -66
- package/dist/components/ui/shell/PublicFooter.astro +0 -39
- package/dist/components/ui/shell/PublicShell.astro +0 -184
- package/dist/components/ui/shell/RailNav.astro +0 -42
- package/dist/components/ui/shell/ShellIconLink.astro +0 -30
- package/dist/components/ui/shell/TopBar.astro +0 -52
- package/dist/components/ui/surface/Card.astro +0 -46
- package/dist/components/ui/surface/EmptyState.astro +0 -45
- package/dist/components/ui/surface/Panel.astro +0 -54
- package/dist/components/ui/theme/ThemeMenu.astro +0 -58
- package/dist/components/ui/theme/ThemePreviewSwatch.astro +0 -18
- package/dist/components/ui/theme/ThemeScript.astro +0 -112
- package/dist/components/ui/theme/ThemeSelector.astro +0 -202
- package/dist/components/ui/types.js +0 -0
- package/dist/layouts/AuthoredEntryLayout.astro +0 -195
- package/dist/layouts/BookLayout.astro +0 -35
- package/dist/layouts/BridgeLayout.astro +0 -11
- package/dist/layouts/ContentLayout.astro +0 -24
- package/dist/layouts/MainLayout.astro +0 -76
- package/dist/layouts/NoteLayout.astro +0 -26
- package/dist/layouts/ProfileLayout.astro +0 -85
- package/dist/styles/app-shell.css +0 -626
- package/dist/styles/forms.css +0 -274
- package/dist/styles/theme.css +0 -198
- package/dist/styles/tokens.css +0 -65
- package/dist/styles/ui.css +0 -551
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { Tone } from '../types.js';
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
tone?: Tone;
|
|
6
|
-
label?: string;
|
|
7
|
-
class?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const {
|
|
11
|
-
tone = 'default',
|
|
12
|
-
label,
|
|
13
|
-
class: className,
|
|
14
|
-
} = Astro.props as Props;
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
<span class:list={['ts-status-pill', className]} data-tone={tone}>
|
|
18
|
-
<span class="ts-status-pill__dot" aria-hidden="true"></span>
|
|
19
|
-
<span><slot>{label}</slot></span>
|
|
20
|
-
</span>
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { ButtonSize, ButtonVariant } from '../types.js';
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
href?: string;
|
|
6
|
-
type?: 'button' | 'submit' | 'reset';
|
|
7
|
-
variant?: ButtonVariant;
|
|
8
|
-
size?: ButtonSize;
|
|
9
|
-
disabled?: boolean;
|
|
10
|
-
ariaLabel?: string;
|
|
11
|
-
reload?: boolean;
|
|
12
|
-
class?: string;
|
|
13
|
-
[key: string]: unknown;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const {
|
|
17
|
-
href,
|
|
18
|
-
type = 'button',
|
|
19
|
-
variant = 'primary',
|
|
20
|
-
size = 'md',
|
|
21
|
-
disabled = false,
|
|
22
|
-
ariaLabel,
|
|
23
|
-
reload = false,
|
|
24
|
-
class: className,
|
|
25
|
-
...buttonAttributes
|
|
26
|
-
} = Astro.props as Props;
|
|
27
|
-
|
|
28
|
-
const classes = ['ts-button', className].filter(Boolean).join(' ');
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
{
|
|
32
|
-
href ? (
|
|
33
|
-
<a
|
|
34
|
-
href={disabled ? undefined : href}
|
|
35
|
-
class={classes}
|
|
36
|
-
data-variant={variant}
|
|
37
|
-
data-size={size}
|
|
38
|
-
aria-label={ariaLabel}
|
|
39
|
-
aria-disabled={disabled ? 'true' : undefined}
|
|
40
|
-
tabindex={disabled ? -1 : undefined}
|
|
41
|
-
data-astro-reload={reload ? true : undefined}
|
|
42
|
-
{...buttonAttributes}
|
|
43
|
-
>
|
|
44
|
-
<slot />
|
|
45
|
-
</a>
|
|
46
|
-
) : (
|
|
47
|
-
<button
|
|
48
|
-
{...buttonAttributes}
|
|
49
|
-
type={type}
|
|
50
|
-
class={classes}
|
|
51
|
-
data-variant={variant}
|
|
52
|
-
data-size={size}
|
|
53
|
-
disabled={disabled}
|
|
54
|
-
aria-label={ariaLabel}
|
|
55
|
-
>
|
|
56
|
-
<slot />
|
|
57
|
-
</button>
|
|
58
|
-
)
|
|
59
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
label: string;
|
|
4
|
-
id?: string;
|
|
5
|
-
name?: string;
|
|
6
|
-
help?: string;
|
|
7
|
-
error?: string;
|
|
8
|
-
required?: boolean;
|
|
9
|
-
full?: boolean;
|
|
10
|
-
class?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const {
|
|
14
|
-
label,
|
|
15
|
-
id,
|
|
16
|
-
name,
|
|
17
|
-
help,
|
|
18
|
-
error,
|
|
19
|
-
required = false,
|
|
20
|
-
full = false,
|
|
21
|
-
class: className,
|
|
22
|
-
} = Astro.props as Props;
|
|
23
|
-
|
|
24
|
-
const fieldId = id ?? name;
|
|
25
|
-
const helpId = fieldId && help ? `${fieldId}-help` : undefined;
|
|
26
|
-
const errorId = fieldId && error ? `${fieldId}-error` : undefined;
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
<div class:list={['ts-field', full && 'ts-field--full', className]}>
|
|
30
|
-
<label class="ts-field__label" for={fieldId}>
|
|
31
|
-
<span>{label}</span>
|
|
32
|
-
{required ? <span class="ts-field__required" aria-hidden="true">*</span> : null}
|
|
33
|
-
</label>
|
|
34
|
-
<div class="ts-field__control">
|
|
35
|
-
<slot helpId={helpId} errorId={errorId} describedBy={[helpId, errorId].filter(Boolean).join(' ') || undefined} />
|
|
36
|
-
</div>
|
|
37
|
-
{help ? <p class="ts-field__help" id={helpId}>{help}</p> : null}
|
|
38
|
-
{error ? <p class="ts-field__error" id={errorId}>{error}</p> : null}
|
|
39
|
-
</div>
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
align?: 'start' | 'end' | 'between';
|
|
4
|
-
class?: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const { align = 'end', class: className } = Astro.props as Props;
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
<div class:list={['ts-form-actions', `ts-form-actions--${align}`, className]}>
|
|
11
|
-
<slot />
|
|
12
|
-
</div>
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
inputId?: string;
|
|
4
|
-
label?: string;
|
|
5
|
-
minLength?: number;
|
|
6
|
-
class?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const {
|
|
10
|
-
inputId,
|
|
11
|
-
label = 'Password strength',
|
|
12
|
-
minLength = 12,
|
|
13
|
-
class: className,
|
|
14
|
-
} = Astro.props as Props;
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
<div
|
|
18
|
-
class:list={['ts-password-meter', className]}
|
|
19
|
-
data-ts-password-meter
|
|
20
|
-
data-input-id={inputId}
|
|
21
|
-
data-min-length={minLength}
|
|
22
|
-
>
|
|
23
|
-
<div class="ts-password-meter__header">
|
|
24
|
-
<span>{label}</span>
|
|
25
|
-
<span class="ts-password-meter__status" data-ts-password-meter-status>Not started</span>
|
|
26
|
-
</div>
|
|
27
|
-
<div class="ts-password-meter__track" aria-hidden="true">
|
|
28
|
-
<span class="ts-password-meter__bar" data-ts-password-meter-bar></span>
|
|
29
|
-
</div>
|
|
30
|
-
<ul class="ts-password-meter__rules">
|
|
31
|
-
<li data-ts-password-rule="length">Use at least {minLength} characters</li>
|
|
32
|
-
<li data-ts-password-rule="case">Mix upper and lower case letters</li>
|
|
33
|
-
<li data-ts-password-rule="number">Include a number</li>
|
|
34
|
-
<li data-ts-password-rule="symbol">Include a symbol</li>
|
|
35
|
-
</ul>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
<script is:inline>
|
|
39
|
-
(() => {
|
|
40
|
-
function scorePassword(value, minLength) {
|
|
41
|
-
const checks = {
|
|
42
|
-
length: value.length >= minLength,
|
|
43
|
-
case: /[a-z]/.test(value) && /[A-Z]/.test(value),
|
|
44
|
-
number: /\d/.test(value),
|
|
45
|
-
symbol: /[^A-Za-z0-9]/.test(value),
|
|
46
|
-
};
|
|
47
|
-
return { checks, score: Object.values(checks).filter(Boolean).length };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function bindMeter(meter) {
|
|
51
|
-
if (!(meter instanceof HTMLElement)) return;
|
|
52
|
-
const minLength = Number(meter.dataset.minLength || 12);
|
|
53
|
-
const inputId = meter.dataset.inputId;
|
|
54
|
-
const input = inputId
|
|
55
|
-
? document.getElementById(inputId)
|
|
56
|
-
: meter.closest('form')?.querySelector('[data-ts-password-input], input[type="password"]');
|
|
57
|
-
if (!(input instanceof HTMLInputElement)) return;
|
|
58
|
-
|
|
59
|
-
const status = meter.querySelector('[data-ts-password-meter-status]');
|
|
60
|
-
const bar = meter.querySelector('[data-ts-password-meter-bar]');
|
|
61
|
-
const labels = ['Not started', 'Weak', 'Fair', 'Good', 'Strong'];
|
|
62
|
-
|
|
63
|
-
function update() {
|
|
64
|
-
const { checks, score } = scorePassword(input.value, minLength);
|
|
65
|
-
meter.dataset.strength = String(score);
|
|
66
|
-
if (status) status.textContent = input.value ? labels[score] : labels[0];
|
|
67
|
-
if (bar instanceof HTMLElement) bar.style.setProperty('--ts-password-strength', String(score));
|
|
68
|
-
for (const [rule, passed] of Object.entries(checks)) {
|
|
69
|
-
const item = meter.querySelector(`[data-ts-password-rule="${rule}"]`);
|
|
70
|
-
if (item instanceof HTMLElement) item.dataset.passed = passed ? 'true' : 'false';
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
input.addEventListener('input', update);
|
|
75
|
-
update();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
document.querySelectorAll('[data-ts-password-meter]').forEach(bindMeter);
|
|
79
|
-
})();
|
|
80
|
-
</script>
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface RadioOption {
|
|
3
|
-
label: string;
|
|
4
|
-
value: string;
|
|
5
|
-
help?: string;
|
|
6
|
-
disabled?: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface Props {
|
|
10
|
-
name: string;
|
|
11
|
-
legend: string;
|
|
12
|
-
value?: string;
|
|
13
|
-
options: RadioOption[];
|
|
14
|
-
required?: boolean;
|
|
15
|
-
class?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const {
|
|
19
|
-
name,
|
|
20
|
-
legend,
|
|
21
|
-
value,
|
|
22
|
-
options,
|
|
23
|
-
required = false,
|
|
24
|
-
class: className,
|
|
25
|
-
} = Astro.props as Props;
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
<fieldset class:list={['ts-radio-group', className]}>
|
|
29
|
-
<legend class="ts-radio-group__legend">
|
|
30
|
-
{legend}
|
|
31
|
-
{required ? <span class="ts-field__required" aria-hidden="true">*</span> : null}
|
|
32
|
-
</legend>
|
|
33
|
-
<div class="ts-radio-group__options">
|
|
34
|
-
{options.map((option) => {
|
|
35
|
-
const optionId = `${name}-${option.value}`;
|
|
36
|
-
return (
|
|
37
|
-
<label class="ts-radio-option" for={optionId} data-disabled={option.disabled ? 'true' : undefined}>
|
|
38
|
-
<input
|
|
39
|
-
id={optionId}
|
|
40
|
-
type="radio"
|
|
41
|
-
name={name}
|
|
42
|
-
value={option.value}
|
|
43
|
-
checked={option.value === value}
|
|
44
|
-
required={required}
|
|
45
|
-
disabled={option.disabled}
|
|
46
|
-
/>
|
|
47
|
-
<span class="ts-radio-option__body">
|
|
48
|
-
<span class="ts-radio-option__label">{option.label}</span>
|
|
49
|
-
{option.help ? <span class="ts-radio-option__help">{option.help}</span> : null}
|
|
50
|
-
</span>
|
|
51
|
-
</label>
|
|
52
|
-
);
|
|
53
|
-
})}
|
|
54
|
-
</div>
|
|
55
|
-
</fieldset>
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface SelectOption {
|
|
3
|
-
label: string;
|
|
4
|
-
value: string;
|
|
5
|
-
disabled?: boolean;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
name: string;
|
|
10
|
-
id?: string;
|
|
11
|
-
value?: string;
|
|
12
|
-
options: SelectOption[];
|
|
13
|
-
required?: boolean;
|
|
14
|
-
disabled?: boolean;
|
|
15
|
-
ariaDescribedby?: string;
|
|
16
|
-
class?: string;
|
|
17
|
-
[key: string]: unknown;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const {
|
|
21
|
-
name,
|
|
22
|
-
id = name,
|
|
23
|
-
value,
|
|
24
|
-
options,
|
|
25
|
-
required = false,
|
|
26
|
-
disabled = false,
|
|
27
|
-
ariaDescribedby,
|
|
28
|
-
class: className,
|
|
29
|
-
...selectAttributes
|
|
30
|
-
} = Astro.props as Props;
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
<select
|
|
34
|
-
{...selectAttributes}
|
|
35
|
-
class:list={['ts-control', 'ts-control--select', className]}
|
|
36
|
-
id={id}
|
|
37
|
-
name={name}
|
|
38
|
-
required={required}
|
|
39
|
-
disabled={disabled}
|
|
40
|
-
aria-describedby={ariaDescribedby}
|
|
41
|
-
>
|
|
42
|
-
{options.map((option) => (
|
|
43
|
-
<option value={option.value} selected={option.value === value} disabled={option.disabled}>
|
|
44
|
-
{option.label}
|
|
45
|
-
</option>
|
|
46
|
-
))}
|
|
47
|
-
</select>
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
name: string;
|
|
4
|
-
id?: string;
|
|
5
|
-
type?: 'text' | 'email' | 'url' | 'password' | 'search' | 'number' | 'tel';
|
|
6
|
-
value?: string | number;
|
|
7
|
-
placeholder?: string;
|
|
8
|
-
autocomplete?: string;
|
|
9
|
-
required?: boolean;
|
|
10
|
-
disabled?: boolean;
|
|
11
|
-
readonly?: boolean;
|
|
12
|
-
minlength?: number;
|
|
13
|
-
maxlength?: number;
|
|
14
|
-
pattern?: string;
|
|
15
|
-
inputmode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search';
|
|
16
|
-
ariaDescribedby?: string;
|
|
17
|
-
class?: string;
|
|
18
|
-
[key: string]: unknown;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const {
|
|
22
|
-
name,
|
|
23
|
-
id = name,
|
|
24
|
-
type = 'text',
|
|
25
|
-
value,
|
|
26
|
-
placeholder,
|
|
27
|
-
autocomplete,
|
|
28
|
-
required = false,
|
|
29
|
-
disabled = false,
|
|
30
|
-
readonly = false,
|
|
31
|
-
minlength,
|
|
32
|
-
maxlength,
|
|
33
|
-
pattern,
|
|
34
|
-
inputmode,
|
|
35
|
-
ariaDescribedby,
|
|
36
|
-
class: className,
|
|
37
|
-
...inputAttributes
|
|
38
|
-
} = Astro.props as Props;
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
<input
|
|
42
|
-
{...inputAttributes}
|
|
43
|
-
class:list={['ts-control', className]}
|
|
44
|
-
id={id}
|
|
45
|
-
name={name}
|
|
46
|
-
type={type}
|
|
47
|
-
value={value}
|
|
48
|
-
placeholder={placeholder}
|
|
49
|
-
autocomplete={autocomplete}
|
|
50
|
-
required={required}
|
|
51
|
-
disabled={disabled}
|
|
52
|
-
readonly={readonly}
|
|
53
|
-
minlength={minlength}
|
|
54
|
-
maxlength={maxlength}
|
|
55
|
-
pattern={pattern}
|
|
56
|
-
inputmode={inputmode}
|
|
57
|
-
aria-describedby={ariaDescribedby}
|
|
58
|
-
/>
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
name: string;
|
|
4
|
-
id?: string;
|
|
5
|
-
value?: string;
|
|
6
|
-
placeholder?: string;
|
|
7
|
-
rows?: number;
|
|
8
|
-
required?: boolean;
|
|
9
|
-
disabled?: boolean;
|
|
10
|
-
readonly?: boolean;
|
|
11
|
-
minlength?: number;
|
|
12
|
-
maxlength?: number;
|
|
13
|
-
ariaDescribedby?: string;
|
|
14
|
-
class?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const {
|
|
18
|
-
name,
|
|
19
|
-
id = name,
|
|
20
|
-
value,
|
|
21
|
-
placeholder,
|
|
22
|
-
rows = 4,
|
|
23
|
-
required = false,
|
|
24
|
-
disabled = false,
|
|
25
|
-
readonly = false,
|
|
26
|
-
minlength,
|
|
27
|
-
maxlength,
|
|
28
|
-
ariaDescribedby,
|
|
29
|
-
class: className,
|
|
30
|
-
} = Astro.props as Props;
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
<textarea
|
|
34
|
-
class:list={['ts-control', 'ts-control--textarea', className]}
|
|
35
|
-
id={id}
|
|
36
|
-
name={name}
|
|
37
|
-
placeholder={placeholder}
|
|
38
|
-
rows={rows}
|
|
39
|
-
required={required}
|
|
40
|
-
disabled={disabled}
|
|
41
|
-
readonly={readonly}
|
|
42
|
-
minlength={minlength}
|
|
43
|
-
maxlength={maxlength}
|
|
44
|
-
aria-describedby={ariaDescribedby}
|
|
45
|
-
>{value}</textarea>
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import Button from '../forms/Button.astro';
|
|
3
|
-
import type { ButtonAction } from '../types.js';
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
eyebrow?: string;
|
|
7
|
-
title: string;
|
|
8
|
-
description?: string;
|
|
9
|
-
actions?: ButtonAction[];
|
|
10
|
-
class?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const {
|
|
14
|
-
eyebrow,
|
|
15
|
-
title,
|
|
16
|
-
description,
|
|
17
|
-
actions = [],
|
|
18
|
-
class: className,
|
|
19
|
-
} = Astro.props as Props;
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
<header class:list={['ts-page-header', className]}>
|
|
23
|
-
<div class="ts-page-header__content">
|
|
24
|
-
{eyebrow ? <p class="ts-page-header__eyebrow">{eyebrow}</p> : null}
|
|
25
|
-
<h1 class="ts-page-header__title">{title}</h1>
|
|
26
|
-
{description ? <p class="ts-page-header__description">{description}</p> : null}
|
|
27
|
-
<slot />
|
|
28
|
-
</div>
|
|
29
|
-
{actions.length > 0 || Astro.slots.has('actions') ? (
|
|
30
|
-
<div class="ts-page-header__actions">
|
|
31
|
-
{actions.map((action) => (
|
|
32
|
-
<Button
|
|
33
|
-
href={action.href}
|
|
34
|
-
type={action.type}
|
|
35
|
-
variant={action.variant ?? 'secondary'}
|
|
36
|
-
ariaLabel={action.ariaLabel}
|
|
37
|
-
disabled={action.disabled}
|
|
38
|
-
>
|
|
39
|
-
{action.label}
|
|
40
|
-
</Button>
|
|
41
|
-
))}
|
|
42
|
-
<slot name="actions" />
|
|
43
|
-
</div>
|
|
44
|
-
) : null}
|
|
45
|
-
</header>
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import '../../../styles/tokens.css';
|
|
3
|
-
import '../../../styles/theme.css';
|
|
4
|
-
import '../../../styles/ui.css';
|
|
5
|
-
import '../../../styles/forms.css';
|
|
6
|
-
import '../../../styles/app-shell.css';
|
|
7
|
-
import { ClientRouter } from 'astro:transitions';
|
|
8
|
-
import ThemeScript from '../theme/ThemeScript.astro';
|
|
9
|
-
import ThemeMenu from '../theme/ThemeMenu.astro';
|
|
10
|
-
import RailNav from './RailNav.astro';
|
|
11
|
-
import BottomNav from './BottomNav.astro';
|
|
12
|
-
import TopBar from './TopBar.astro';
|
|
13
|
-
import ShellIconLink from './ShellIconLink.astro';
|
|
14
|
-
import Button from '../forms/Button.astro';
|
|
15
|
-
import DevWatchReload from '../../DevWatchReload.astro';
|
|
16
|
-
import type { ButtonAction } from '../types.js';
|
|
17
|
-
import type { ThemePreference } from '../../../utils/theme.js';
|
|
18
|
-
|
|
19
|
-
interface Brand {
|
|
20
|
-
name: string;
|
|
21
|
-
tag?: string;
|
|
22
|
-
href: string;
|
|
23
|
-
logoSrc?: string;
|
|
24
|
-
logoAlt?: string;
|
|
25
|
-
mark?: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface NavItem {
|
|
29
|
-
label: string;
|
|
30
|
-
href: string;
|
|
31
|
-
ariaLabel?: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface Props {
|
|
35
|
-
title: string;
|
|
36
|
-
description: string;
|
|
37
|
-
currentPath: string;
|
|
38
|
-
appearance: ThemePreference;
|
|
39
|
-
brand: Brand;
|
|
40
|
-
navItems: NavItem[];
|
|
41
|
-
quickActions?: ButtonAction[];
|
|
42
|
-
bottomNavItems?: NavItem[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const {
|
|
46
|
-
title,
|
|
47
|
-
description,
|
|
48
|
-
currentPath,
|
|
49
|
-
appearance,
|
|
50
|
-
brand,
|
|
51
|
-
navItems,
|
|
52
|
-
quickActions = [],
|
|
53
|
-
bottomNavItems = navItems.slice(0, 5),
|
|
54
|
-
} = Astro.props as Props;
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
<!doctype html>
|
|
58
|
-
<html lang="en">
|
|
59
|
-
<head>
|
|
60
|
-
<meta charset="utf-8" />
|
|
61
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
62
|
-
<title>{title}</title>
|
|
63
|
-
<meta name="description" content={description} />
|
|
64
|
-
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
|
65
|
-
<link rel="shortcut icon" href="/favicon.svg" type="image/svg+xml" />
|
|
66
|
-
<ThemeScript defaultScheme={appearance.scheme} defaultMode={appearance.mode} preferDefaultPreference />
|
|
67
|
-
<ClientRouter />
|
|
68
|
-
</head>
|
|
69
|
-
<body>
|
|
70
|
-
<a class="ts-skip-link" href="#main-content">Skip to content</a>
|
|
71
|
-
<div class="ts-app-shell">
|
|
72
|
-
<aside class="ts-app-shell__rail">
|
|
73
|
-
<div class="ts-app-shell__rail-scroll">
|
|
74
|
-
<TopBar brand={brand} />
|
|
75
|
-
<div class="ts-app-shell__rail-context">
|
|
76
|
-
<slot name="railContext" />
|
|
77
|
-
</div>
|
|
78
|
-
<RailNav items={navItems} currentPath={currentPath} />
|
|
79
|
-
</div>
|
|
80
|
-
{quickActions.length > 0 ? (
|
|
81
|
-
<div class="ts-app-shell__quick-actions">
|
|
82
|
-
<p class="ts-app-shell__eyebrow">Quick actions</p>
|
|
83
|
-
<div class="ts-app-shell__quick-list">
|
|
84
|
-
{quickActions.map((action) => (
|
|
85
|
-
<Button
|
|
86
|
-
href={action.href}
|
|
87
|
-
type={action.type}
|
|
88
|
-
variant={action.variant ?? 'secondary'}
|
|
89
|
-
ariaLabel={action.ariaLabel}
|
|
90
|
-
disabled={action.disabled}
|
|
91
|
-
reload={action.reload}
|
|
92
|
-
size="sm"
|
|
93
|
-
>
|
|
94
|
-
{action.label}
|
|
95
|
-
</Button>
|
|
96
|
-
))}
|
|
97
|
-
</div>
|
|
98
|
-
</div>
|
|
99
|
-
) : null}
|
|
100
|
-
</aside>
|
|
101
|
-
<main class="ts-app-shell__main" id="main-content">
|
|
102
|
-
<TopBar brand={brand} class="ts-app-shell__mobile-top">
|
|
103
|
-
<Fragment slot="actions">
|
|
104
|
-
<ThemeMenu selectedScheme={appearance.scheme} selectedMode={appearance.mode} />
|
|
105
|
-
<ShellIconLink href="/" label="Book home" icon="book" />
|
|
106
|
-
</Fragment>
|
|
107
|
-
</TopBar>
|
|
108
|
-
<header class="ts-app-shell__header">
|
|
109
|
-
<div class="ts-app-shell__title">
|
|
110
|
-
<h1>{title}</h1>
|
|
111
|
-
<p>{description}</p>
|
|
112
|
-
</div>
|
|
113
|
-
<div class="ts-app-shell__header-actions">
|
|
114
|
-
<div class="ts-shell-utility-actions">
|
|
115
|
-
<ThemeMenu selectedScheme={appearance.scheme} selectedMode={appearance.mode} />
|
|
116
|
-
<ShellIconLink href="/" label="Book home" icon="book" />
|
|
117
|
-
</div>
|
|
118
|
-
<slot name="headerAction" />
|
|
119
|
-
</div>
|
|
120
|
-
</header>
|
|
121
|
-
<slot name="projectContext" />
|
|
122
|
-
<slot />
|
|
123
|
-
</main>
|
|
124
|
-
{bottomNavItems.length > 0 ? <BottomNav items={bottomNavItems} currentPath={currentPath} /> : null}
|
|
125
|
-
</div>
|
|
126
|
-
<slot name="sensitiveModal" />
|
|
127
|
-
<slot name="modal" />
|
|
128
|
-
<DevWatchReload />
|
|
129
|
-
</body>
|
|
130
|
-
</html>
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface NavItem {
|
|
3
|
-
label: string;
|
|
4
|
-
href: string;
|
|
5
|
-
ariaLabel?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
items: NavItem[];
|
|
10
|
-
currentPath: string;
|
|
11
|
-
label?: string;
|
|
12
|
-
class?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const {
|
|
16
|
-
items,
|
|
17
|
-
currentPath,
|
|
18
|
-
label = 'Primary',
|
|
19
|
-
class: className,
|
|
20
|
-
} = Astro.props as Props;
|
|
21
|
-
|
|
22
|
-
function normalizePath(path: string) {
|
|
23
|
-
if (path.length <= 1) return path;
|
|
24
|
-
return path.replace(/\/+$/u, '');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function isCurrentPath(href: string) {
|
|
28
|
-
const current = normalizePath(currentPath);
|
|
29
|
-
const target = normalizePath(href);
|
|
30
|
-
if (target === '/') return current === '/';
|
|
31
|
-
if (target === '/app') return current === '/app';
|
|
32
|
-
return current === target || current.startsWith(`${target}/`);
|
|
33
|
-
}
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
<nav class:list={['ts-bottom-nav', className]} aria-label={label}>
|
|
37
|
-
{items.map((item) => (
|
|
38
|
-
<a class="ts-bottom-nav__link" href={item.href} aria-label={item.ariaLabel} aria-current={isCurrentPath(item.href) ? 'page' : undefined}>
|
|
39
|
-
<span>{item.label}</span>
|
|
40
|
-
</a>
|
|
41
|
-
))}
|
|
42
|
-
</nav>
|