@treeseed/core 0.8.7 → 0.8.9
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/components/content/ContentStatusLegend.astro +4 -4
- package/dist/components/docs/BookFontControls.astro +9 -9
- package/dist/components/docs/DesktopSidebarToggle.astro +8 -8
- package/dist/components/docs/Footer.astro +6 -6
- package/dist/components/docs/PageTitle.astro +1 -1
- package/dist/components/docs/ThemeSelect.astro +3 -1
- package/dist/components/forms/ContactForm.astro +21 -21
- package/dist/components/forms/FooterSubscribeForm.astro +9 -9
- package/dist/components/site/BookList.astro +7 -7
- package/dist/components/site/CTASection.astro +4 -4
- package/dist/components/site/ChronicleList.astro +6 -6
- package/dist/components/site/Hero.astro +3 -3
- package/dist/components/site/PathCard.astro +5 -5
- package/dist/components/site/ProfileList.astro +5 -5
- package/dist/components/site/RouteNotFound.astro +5 -5
- package/dist/components/site/SectionIntro.astro +3 -3
- package/dist/components/site/StageBanner.astro +2 -2
- package/dist/components/site/TrustCallout.astro +3 -3
- package/dist/components/ui/data/ActionList.astro +51 -0
- package/dist/components/ui/data/Badge.astro +19 -0
- package/dist/components/ui/data/DataTable.astro +51 -0
- package/dist/components/ui/data/KeyValueList.astro +28 -0
- package/dist/components/ui/data/MetricCard.astro +25 -0
- package/dist/components/ui/data/MetricGrid.astro +27 -0
- package/dist/components/ui/data/StatusPill.astro +20 -0
- package/dist/components/ui/forms/Button.astro +52 -0
- package/dist/components/ui/forms/Field.astro +39 -0
- package/dist/components/ui/forms/FormActions.astro +12 -0
- package/dist/components/ui/forms/PasswordMeter.astro +80 -0
- package/dist/components/ui/forms/RadioGroup.astro +55 -0
- package/dist/components/ui/forms/Select.astro +44 -0
- package/dist/components/ui/forms/TextInput.astro +58 -0
- package/dist/components/ui/forms/Textarea.astro +45 -0
- package/dist/components/ui/layout/PageHeader.astro +45 -0
- package/dist/components/ui/shell/AppShell.astro +110 -0
- package/dist/components/ui/shell/BottomNav.astro +35 -0
- package/dist/components/ui/shell/ProjectHeader.astro +66 -0
- package/dist/components/ui/shell/PublicShell.astro +108 -0
- package/dist/components/ui/shell/RailNav.astro +35 -0
- package/dist/components/ui/shell/TopBar.astro +52 -0
- package/dist/components/ui/surface/Card.astro +46 -0
- package/dist/components/ui/surface/EmptyState.astro +45 -0
- package/dist/components/ui/surface/Panel.astro +54 -0
- package/dist/components/ui/theme/ThemeMenu.astro +32 -0
- package/dist/components/ui/theme/ThemePreviewSwatch.astro +18 -0
- package/dist/components/ui/theme/ThemeScript.astro +105 -0
- package/dist/components/ui/theme/ThemeSelector.astro +202 -0
- package/dist/components/ui/types.js +0 -0
- package/dist/dev.js +14 -2
- package/dist/layouts/AuthoredEntryLayout.astro +27 -27
- package/dist/layouts/BookLayout.astro +10 -10
- package/dist/layouts/ContentLayout.astro +4 -4
- package/dist/layouts/MainLayout.astro +27 -25
- package/dist/layouts/NoteLayout.astro +6 -6
- package/dist/layouts/ProfileLayout.astro +17 -17
- package/dist/pages/404.astro +6 -6
- package/dist/pages/contact.astro +4 -4
- package/dist/pages/docs-runtime/[...slug].astro +12 -12
- package/dist/pages/docs-runtime/index.astro +13 -13
- package/dist/pages/index.astro +28 -28
- package/dist/pages/ui/index.astro +216 -0
- package/dist/site.js +3 -2
- package/dist/styles/app-shell.css +398 -0
- package/dist/styles/forms.css +258 -0
- package/dist/styles/global.css +119 -119
- package/dist/styles/prose.css +11 -11
- package/dist/styles/theme.css +177 -0
- package/dist/styles/tokens.css +62 -22
- package/dist/styles/ui.css +551 -0
- package/dist/utils/content-status.js +5 -5
- package/dist/utils/site-config.js +2 -2
- package/dist/utils/theme.js +352 -40
- package/package.json +35 -2
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
buildTreeseedThemeCss,
|
|
4
|
+
getBuiltInColorSchemes,
|
|
5
|
+
normalizeThemePreference,
|
|
6
|
+
type ThemePreference,
|
|
7
|
+
} from '../../../utils/theme.js';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
defaultScheme?: ThemePreference['scheme'];
|
|
11
|
+
defaultMode?: ThemePreference['mode'];
|
|
12
|
+
includeCss?: boolean;
|
|
13
|
+
preferDefaultPreference?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const preference = normalizeThemePreference({
|
|
17
|
+
scheme: (Astro.props as Props).defaultScheme,
|
|
18
|
+
mode: (Astro.props as Props).defaultMode,
|
|
19
|
+
});
|
|
20
|
+
const { includeCss = true, preferDefaultPreference = false } = Astro.props as Props;
|
|
21
|
+
const builtInSchemeIds = getBuiltInColorSchemes().map((scheme) => scheme.id);
|
|
22
|
+
const themeCss = buildTreeseedThemeCss();
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
{includeCss ? <style is:inline set:html={themeCss}></style> : null}
|
|
26
|
+
|
|
27
|
+
<script
|
|
28
|
+
is:inline
|
|
29
|
+
define:vars={{
|
|
30
|
+
builtInSchemeIds,
|
|
31
|
+
defaultScheme: preference.scheme,
|
|
32
|
+
defaultMode: preference.mode,
|
|
33
|
+
preferDefaultPreference,
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
(() => {
|
|
37
|
+
const schemeKey = 'treeseed_color_scheme';
|
|
38
|
+
const modeKey = 'treeseed_theme_mode';
|
|
39
|
+
const modes = new Set(['light', 'dark', 'system']);
|
|
40
|
+
const schemes = new Set(builtInSchemeIds);
|
|
41
|
+
const root = document.documentElement;
|
|
42
|
+
|
|
43
|
+
function readCookie(name) {
|
|
44
|
+
const pair = document.cookie
|
|
45
|
+
.split('; ')
|
|
46
|
+
.find((entry) => entry.startsWith(`${name}=`));
|
|
47
|
+
return pair ? decodeURIComponent(pair.slice(name.length + 1)) : '';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function readStored(name) {
|
|
51
|
+
try {
|
|
52
|
+
return window.sessionStorage.getItem(name) || window.localStorage.getItem(name) || '';
|
|
53
|
+
} catch {
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function store(name, value) {
|
|
59
|
+
try {
|
|
60
|
+
window.sessionStorage.setItem(name, value);
|
|
61
|
+
} catch {
|
|
62
|
+
// Session storage can be disabled; local storage/cookies still carry the preference.
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
window.localStorage.setItem(name, value);
|
|
66
|
+
} catch {
|
|
67
|
+
// Local storage can be disabled; cookies still carry the preference for SSR.
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function resolveScheme(value) {
|
|
72
|
+
return schemes.has(value) ? value : defaultScheme;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function resolveMode(value) {
|
|
76
|
+
return modes.has(value) ? value : defaultMode;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function resolveRenderedMode(mode) {
|
|
80
|
+
if (mode !== 'system') return mode;
|
|
81
|
+
return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const storedScheme = readStored(schemeKey) || readCookie(schemeKey);
|
|
85
|
+
const storedModeValue = readStored(modeKey) || readCookie(modeKey);
|
|
86
|
+
const scheme = preferDefaultPreference ? resolveScheme(defaultScheme) : resolveScheme(storedScheme || defaultScheme);
|
|
87
|
+
const storedMode = preferDefaultPreference ? resolveMode(defaultMode) : resolveMode(storedModeValue || defaultMode);
|
|
88
|
+
const renderedMode = resolveRenderedMode(storedMode);
|
|
89
|
+
|
|
90
|
+
root.dataset.tsScheme = scheme;
|
|
91
|
+
root.dataset.tsMode = renderedMode;
|
|
92
|
+
if (storedMode === 'system') {
|
|
93
|
+
root.dataset.tsModeSource = 'system';
|
|
94
|
+
} else {
|
|
95
|
+
delete root.dataset.tsModeSource;
|
|
96
|
+
}
|
|
97
|
+
store(schemeKey, scheme);
|
|
98
|
+
store(modeKey, storedMode);
|
|
99
|
+
window.matchMedia?.('(prefers-color-scheme: dark)').addEventListener?.('change', () => {
|
|
100
|
+
if (root.dataset.tsModeSource === 'system') {
|
|
101
|
+
root.dataset.tsMode = resolveRenderedMode('system');
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
})();
|
|
105
|
+
</script>
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
getBuiltInColorSchemes,
|
|
4
|
+
normalizeThemePreference,
|
|
5
|
+
type ThemePreference,
|
|
6
|
+
} from '../../../utils/theme.js';
|
|
7
|
+
import ThemePreviewSwatch from './ThemePreviewSwatch.astro';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
label?: string;
|
|
11
|
+
selectedScheme?: ThemePreference['scheme'];
|
|
12
|
+
selectedMode?: ThemePreference['mode'];
|
|
13
|
+
includeHiddenFields?: boolean;
|
|
14
|
+
schemeFieldName?: string;
|
|
15
|
+
modeFieldName?: string;
|
|
16
|
+
compact?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
label = 'Appearance',
|
|
21
|
+
selectedScheme,
|
|
22
|
+
selectedMode,
|
|
23
|
+
includeHiddenFields = false,
|
|
24
|
+
schemeFieldName = 'colorScheme',
|
|
25
|
+
modeFieldName = 'themeMode',
|
|
26
|
+
compact = true,
|
|
27
|
+
} = Astro.props as Props;
|
|
28
|
+
|
|
29
|
+
const schemes = getBuiltInColorSchemes();
|
|
30
|
+
const preference = normalizeThemePreference({ scheme: selectedScheme, mode: selectedMode });
|
|
31
|
+
const activeScheme = schemes.find((scheme) => scheme.id === preference.scheme) ?? schemes[0];
|
|
32
|
+
const initialSwatches = preference.mode === 'dark'
|
|
33
|
+
? activeScheme.modeSwatches.dark
|
|
34
|
+
: activeScheme.modeSwatches.light;
|
|
35
|
+
const modes = [
|
|
36
|
+
{ value: 'system', label: 'System' },
|
|
37
|
+
{ value: 'light', label: 'Light' },
|
|
38
|
+
{ value: 'dark', label: 'Dark' },
|
|
39
|
+
];
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
<div
|
|
43
|
+
class:list={['ts-theme-selector', compact && 'ts-theme-selector--compact']}
|
|
44
|
+
data-ts-theme-selector
|
|
45
|
+
data-selected-scheme={preference.scheme}
|
|
46
|
+
data-selected-mode={preference.mode}
|
|
47
|
+
data-scheme-field={schemeFieldName}
|
|
48
|
+
data-mode-field={modeFieldName}
|
|
49
|
+
>
|
|
50
|
+
<div class="ts-theme-selector__summary">
|
|
51
|
+
<ThemePreviewSwatch swatches={initialSwatches} label={`${activeScheme.name} preview`} />
|
|
52
|
+
<span class="ts-theme-selector__label">
|
|
53
|
+
<span>{label}</span>
|
|
54
|
+
<small data-ts-theme-preview-label>{activeScheme.name} · {preference.mode}</small>
|
|
55
|
+
</span>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="ts-theme-selector__controls">
|
|
58
|
+
<label class="ts-theme-selector__field">
|
|
59
|
+
<span>Color scheme</span>
|
|
60
|
+
<select data-ts-theme-scheme-select aria-label="Color scheme">
|
|
61
|
+
{schemes.map((scheme) => (
|
|
62
|
+
<option value={scheme.id} selected={scheme.id === preference.scheme}>
|
|
63
|
+
{scheme.name}
|
|
64
|
+
</option>
|
|
65
|
+
))}
|
|
66
|
+
</select>
|
|
67
|
+
</label>
|
|
68
|
+
<label class="ts-theme-selector__field">
|
|
69
|
+
<span>Mode</span>
|
|
70
|
+
<select data-ts-theme-mode-select aria-label="Theme mode">
|
|
71
|
+
{modes.map((mode) => (
|
|
72
|
+
<option value={mode.value} selected={mode.value === preference.mode}>
|
|
73
|
+
{mode.label}
|
|
74
|
+
</option>
|
|
75
|
+
))}
|
|
76
|
+
</select>
|
|
77
|
+
</label>
|
|
78
|
+
</div>
|
|
79
|
+
{includeHiddenFields ? (
|
|
80
|
+
<>
|
|
81
|
+
<input type="hidden" name={schemeFieldName} value={preference.scheme} data-ts-theme-scheme-field />
|
|
82
|
+
<input type="hidden" name={modeFieldName} value={preference.mode} data-ts-theme-mode-field />
|
|
83
|
+
</>
|
|
84
|
+
) : null}
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<script is:inline define:vars={{ schemes }}>
|
|
88
|
+
(() => {
|
|
89
|
+
const schemeKey = 'treeseed_color_scheme';
|
|
90
|
+
const modeKey = 'treeseed_theme_mode';
|
|
91
|
+
const maxAge = 60 * 60 * 24 * 365;
|
|
92
|
+
const modeValues = new Set(['light', 'dark', 'system']);
|
|
93
|
+
const schemeValues = new Set(schemes.map((scheme) => scheme.id));
|
|
94
|
+
const schemeMap = new Map(schemes.map((scheme) => [scheme.id, scheme]));
|
|
95
|
+
const media = window.matchMedia?.('(prefers-color-scheme: dark)');
|
|
96
|
+
|
|
97
|
+
function cookie(name, value) {
|
|
98
|
+
const secure = window.location.protocol === 'https:' ? '; Secure' : '';
|
|
99
|
+
document.cookie = `${name}=${encodeURIComponent(value)}; Max-Age=${maxAge}; Path=/; SameSite=Lax${secure}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function store(name, value) {
|
|
103
|
+
try {
|
|
104
|
+
window.sessionStorage.setItem(name, value);
|
|
105
|
+
} catch {
|
|
106
|
+
// Session storage can be disabled; local storage/cookies still carry the preference.
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
window.localStorage.setItem(name, value);
|
|
110
|
+
} catch {
|
|
111
|
+
// Storage can be disabled; cookies still carry the preference for SSR.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function renderedMode(mode) {
|
|
116
|
+
if (mode !== 'system') return mode;
|
|
117
|
+
return media?.matches ? 'dark' : 'light';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function applyTheme(scheme, mode, persist = true) {
|
|
121
|
+
const root = document.documentElement;
|
|
122
|
+
const safeScheme = schemeValues.has(scheme) ? scheme : 'fern';
|
|
123
|
+
const safeMode = modeValues.has(mode) ? mode : 'system';
|
|
124
|
+
root.dataset.tsScheme = safeScheme;
|
|
125
|
+
root.dataset.tsMode = renderedMode(safeMode);
|
|
126
|
+
if (safeMode === 'system') {
|
|
127
|
+
root.dataset.tsModeSource = 'system';
|
|
128
|
+
} else {
|
|
129
|
+
delete root.dataset.tsModeSource;
|
|
130
|
+
}
|
|
131
|
+
if (persist) {
|
|
132
|
+
cookie(schemeKey, safeScheme);
|
|
133
|
+
cookie(modeKey, safeMode);
|
|
134
|
+
store(schemeKey, safeScheme);
|
|
135
|
+
store(modeKey, safeMode);
|
|
136
|
+
}
|
|
137
|
+
window.dispatchEvent(new CustomEvent('treeseed:theme-change', {
|
|
138
|
+
detail: { scheme: safeScheme, mode: safeMode, renderedMode: renderedMode(safeMode) },
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function modeSwatches(scheme, mode) {
|
|
143
|
+
const rendered = renderedMode(mode);
|
|
144
|
+
return scheme.modeSwatches?.[rendered] || scheme.swatches || [];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function updateSwatch(selector, schemeId, mode) {
|
|
148
|
+
const scheme = schemeMap.get(schemeId);
|
|
149
|
+
const swatch = selector.querySelector('.ts-theme-swatch');
|
|
150
|
+
const previewLabel = selector.querySelector('[data-ts-theme-preview-label]');
|
|
151
|
+
if (!scheme || !swatch) return;
|
|
152
|
+
swatch.setAttribute('aria-label', `${scheme.name} preview`);
|
|
153
|
+
modeSwatches(scheme, mode).slice(0, 4).forEach((value, index) => {
|
|
154
|
+
swatch.style.setProperty(`--ts-preview-swatch-${index + 1}`, value);
|
|
155
|
+
});
|
|
156
|
+
if (previewLabel) {
|
|
157
|
+
previewLabel.textContent = `${scheme.name} · ${mode === 'system' ? `System ${renderedMode(mode)}` : mode}`;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function currentPreference() {
|
|
162
|
+
const root = document.documentElement;
|
|
163
|
+
const scheme = schemeValues.has(root.dataset.tsScheme) ? root.dataset.tsScheme : '';
|
|
164
|
+
const mode = root.dataset.tsModeSource === 'system' ? 'system' : root.dataset.tsMode;
|
|
165
|
+
return {
|
|
166
|
+
scheme,
|
|
167
|
+
mode: modeValues.has(mode) ? mode : '',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function bind(selector) {
|
|
172
|
+
const schemeSelect = selector.querySelector('[data-ts-theme-scheme-select]');
|
|
173
|
+
const modeSelect = selector.querySelector('[data-ts-theme-mode-select]');
|
|
174
|
+
const schemeField = selector.querySelector('[data-ts-theme-scheme-field]');
|
|
175
|
+
const modeField = selector.querySelector('[data-ts-theme-mode-field]');
|
|
176
|
+
if (!(schemeSelect instanceof HTMLSelectElement) || !(modeSelect instanceof HTMLSelectElement)) return;
|
|
177
|
+
|
|
178
|
+
const activePreference = currentPreference();
|
|
179
|
+
if (activePreference.scheme) schemeSelect.value = activePreference.scheme;
|
|
180
|
+
if (activePreference.mode) modeSelect.value = activePreference.mode;
|
|
181
|
+
|
|
182
|
+
function sync(persist = true) {
|
|
183
|
+
const scheme = schemeSelect.value;
|
|
184
|
+
const mode = modeSelect.value;
|
|
185
|
+
if (schemeField instanceof HTMLInputElement) schemeField.value = scheme;
|
|
186
|
+
if (modeField instanceof HTMLInputElement) modeField.value = mode;
|
|
187
|
+
updateSwatch(selector, scheme, mode);
|
|
188
|
+
applyTheme(scheme, mode, persist);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
schemeSelect.addEventListener('change', () => sync(true));
|
|
192
|
+
modeSelect.addEventListener('change', () => sync(true));
|
|
193
|
+
sync(false);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
document.querySelectorAll('[data-ts-theme-selector]').forEach(bind);
|
|
197
|
+
media?.addEventListener?.('change', () => {
|
|
198
|
+
const mode = document.documentElement.dataset.tsModeSource === 'system' ? 'system' : document.documentElement.dataset.tsMode;
|
|
199
|
+
applyTheme(document.documentElement.dataset.tsScheme || 'fern', mode || 'system', false);
|
|
200
|
+
});
|
|
201
|
+
})();
|
|
202
|
+
</script>
|
|
File without changes
|
package/dist/dev.js
CHANGED
|
@@ -33,6 +33,7 @@ const TREESEED_DEFAULT_MAILPIT_UI_PORT = 8025;
|
|
|
33
33
|
const DEV_RELOAD_FILE = "public/__treeseed/dev-reload.json";
|
|
34
34
|
const DEV_RUNTIME_FILE = ".treeseed/generated/dev/runtime.json";
|
|
35
35
|
const DEFAULT_READINESS_TIMEOUT_MS = 9e4;
|
|
36
|
+
const DEFAULT_SETUP_STEP_TIMEOUT_MS = 3e5;
|
|
36
37
|
const DEFAULT_PROCESS_READY_GRACE_MS = 1200;
|
|
37
38
|
const DEFAULT_SHUTDOWN_GRACE_MS = 2500;
|
|
38
39
|
const DEFAULT_KILL_GRACE_MS = 500;
|
|
@@ -825,7 +826,8 @@ function runSetupStep(step, plan, deps) {
|
|
|
825
826
|
TREESEED_LOCAL_DEV_MODE: "cloudflare",
|
|
826
827
|
TREESEED_PUBLIC_DEV_WATCH_RELOAD: plan.feedbackMode === "live" ? "true" : process.env.TREESEED_PUBLIC_DEV_WATCH_RELOAD
|
|
827
828
|
},
|
|
828
|
-
encoding: "utf8"
|
|
829
|
+
encoding: "utf8",
|
|
830
|
+
timeout: DEFAULT_SETUP_STEP_TIMEOUT_MS
|
|
829
831
|
});
|
|
830
832
|
if ((result.status ?? 1) === 0) {
|
|
831
833
|
return {
|
|
@@ -834,10 +836,12 @@ function runSetupStep(step, plan, deps) {
|
|
|
834
836
|
detail: [result.stdout, result.stderr].filter(Boolean).join("\n").trim() || step.detail
|
|
835
837
|
};
|
|
836
838
|
}
|
|
839
|
+
const timedOut = result.error && "code" in result.error && result.error.code === "ETIMEDOUT";
|
|
840
|
+
const timeoutDetail = timedOut ? `${step.label} timed out after ${Math.round(DEFAULT_SETUP_STEP_TIMEOUT_MS / 1e3)} seconds.` : null;
|
|
837
841
|
return {
|
|
838
842
|
...step,
|
|
839
843
|
status: step.required ? "failed" : "degraded",
|
|
840
|
-
detail: [result.stdout, result.stderr].filter(Boolean).join("\n").trim() || `Exited with ${result.status ?? 1}.`
|
|
844
|
+
detail: [timeoutDetail, result.stdout, result.stderr].filter(Boolean).join("\n").trim() || `Exited with ${result.status ?? 1}.`
|
|
841
845
|
};
|
|
842
846
|
}
|
|
843
847
|
function runLocalSetup(plan, options, deps) {
|
|
@@ -851,6 +855,14 @@ function runLocalSetup(plan, options, deps) {
|
|
|
851
855
|
}
|
|
852
856
|
for (const step of plan.setupSteps) {
|
|
853
857
|
let result = step;
|
|
858
|
+
if (step.status === "planned") {
|
|
859
|
+
emitEvent(options, deps.write, {
|
|
860
|
+
type: "setup",
|
|
861
|
+
status: "running",
|
|
862
|
+
message: `${step.label}: running`,
|
|
863
|
+
detail: step.detail
|
|
864
|
+
});
|
|
865
|
+
}
|
|
854
866
|
if (step.id === "workspace-links") {
|
|
855
867
|
if (plan.setupMode === "check") {
|
|
856
868
|
result = { ...step, status: "skipped", detail: "Workspace links were checked in non-mutating mode." };
|
|
@@ -52,80 +52,80 @@ const {
|
|
|
52
52
|
|
|
53
53
|
<MainLayout title={entry.title} description={entry.description} currentPath={currentPath}>
|
|
54
54
|
<article class="max-w-4xl space-y-8">
|
|
55
|
-
<div class="space-y-4 border-b border-[color:var(--
|
|
55
|
+
<div class="space-y-4 border-b border-[color:var(--ts-color-border)] pb-8">
|
|
56
56
|
<div class="flex flex-wrap items-center gap-3">
|
|
57
57
|
<StatusBadge status={entry.status} />
|
|
58
|
-
<p class="text-sm font-medium text-[color:var(--
|
|
59
|
-
{contributor && <p class="text-sm text-[color:var(--
|
|
60
|
-
{metaLabel && metaValue && <p class="text-sm text-[color:var(--
|
|
58
|
+
<p class="text-sm font-medium text-[color:var(--ts-color-text-subtle)]">{entry.date.toISOString().slice(0, 10)}</p>
|
|
59
|
+
{contributor && <p class="text-sm text-[color:var(--ts-color-text-subtle)]">{contributor.data.name}</p>}
|
|
60
|
+
{metaLabel && metaValue && <p class="text-sm text-[color:var(--ts-color-text-subtle)]">{metaLabel}: {metaValue}</p>}
|
|
61
61
|
</div>
|
|
62
|
-
<h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--
|
|
63
|
-
<p class="max-w-3xl text-xl leading-10 text-[color:var(--
|
|
64
|
-
{(introText ?? entry.motivation) && <p class="max-w-3xl text-base leading-8 text-[color:var(--
|
|
62
|
+
<h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--ts-color-text)] md:text-6xl">{entry.title}</h1>
|
|
63
|
+
<p class="max-w-3xl text-xl leading-10 text-[color:var(--ts-color-text-muted)]">{entry.summary}</p>
|
|
64
|
+
{(introText ?? entry.motivation) && <p class="max-w-3xl text-base leading-8 text-[color:var(--ts-color-text-muted)]">{introText ?? entry.motivation}</p>}
|
|
65
65
|
{entry.tags.length > 0 && (
|
|
66
|
-
<p class="text-sm uppercase tracking-[0.14em] text-[color:var(--
|
|
66
|
+
<p class="text-sm uppercase tracking-[0.14em] text-[color:var(--ts-color-accent-strong)]">{entry.tags.join(' / ')}</p>
|
|
67
67
|
)}
|
|
68
68
|
</div>
|
|
69
69
|
<div class="prose-karyon">
|
|
70
70
|
<slot />
|
|
71
71
|
</div>
|
|
72
|
-
<div class="grid gap-6 border-t border-[color:var(--
|
|
72
|
+
<div class="grid gap-6 border-t border-[color:var(--ts-color-border)] pt-8 md:grid-cols-3">
|
|
73
73
|
{relatedQuestions.length > 0 && (
|
|
74
74
|
<div>
|
|
75
|
-
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--
|
|
76
|
-
<ul class="mt-3 space-y-2 text-[color:var(--
|
|
75
|
+
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">Related questions</p>
|
|
76
|
+
<ul class="mt-3 space-y-2 text-[color:var(--ts-color-text-muted)]">
|
|
77
77
|
{relatedQuestions.map((question) => (
|
|
78
|
-
<li><a href={`/questions/${question.id}/`} class="hover:text-[color:var(--
|
|
78
|
+
<li><a href={`/questions/${question.id}/`} class="hover:text-[color:var(--ts-color-text)]">{entryTitle(question)}</a></li>
|
|
79
79
|
))}
|
|
80
80
|
</ul>
|
|
81
81
|
</div>
|
|
82
82
|
)}
|
|
83
83
|
{relatedObjectives.length > 0 && (
|
|
84
84
|
<div>
|
|
85
|
-
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--
|
|
86
|
-
<ul class="mt-3 space-y-2 text-[color:var(--
|
|
85
|
+
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">Related objectives</p>
|
|
86
|
+
<ul class="mt-3 space-y-2 text-[color:var(--ts-color-text-muted)]">
|
|
87
87
|
{relatedObjectives.map((objective) => (
|
|
88
|
-
<li><a href={`/objectives/${objective.id}/`} class="hover:text-[color:var(--
|
|
88
|
+
<li><a href={`/objectives/${objective.id}/`} class="hover:text-[color:var(--ts-color-text)]">{entryTitle(objective)}</a></li>
|
|
89
89
|
))}
|
|
90
90
|
</ul>
|
|
91
91
|
</div>
|
|
92
92
|
)}
|
|
93
93
|
{relatedNotes.length > 0 && (
|
|
94
94
|
<div>
|
|
95
|
-
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--
|
|
96
|
-
<ul class="mt-3 space-y-2 text-[color:var(--
|
|
95
|
+
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">Related notes</p>
|
|
96
|
+
<ul class="mt-3 space-y-2 text-[color:var(--ts-color-text-muted)]">
|
|
97
97
|
{relatedNotes.map((note) => (
|
|
98
|
-
<li><a href={`/notes/${note.id}/`} class="hover:text-[color:var(--
|
|
98
|
+
<li><a href={`/notes/${note.id}/`} class="hover:text-[color:var(--ts-color-text)]">{entryTitle(note)}</a></li>
|
|
99
99
|
))}
|
|
100
100
|
</ul>
|
|
101
101
|
</div>
|
|
102
102
|
)}
|
|
103
103
|
{relatedProposals.length > 0 && (
|
|
104
104
|
<div>
|
|
105
|
-
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--
|
|
106
|
-
<ul class="mt-3 space-y-2 text-[color:var(--
|
|
105
|
+
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">Related proposals</p>
|
|
106
|
+
<ul class="mt-3 space-y-2 text-[color:var(--ts-color-text-muted)]">
|
|
107
107
|
{relatedProposals.map((proposal) => (
|
|
108
|
-
<li><a href={`/proposals/${proposal.id}/`} class="hover:text-[color:var(--
|
|
108
|
+
<li><a href={`/proposals/${proposal.id}/`} class="hover:text-[color:var(--ts-color-text)]">{entryTitle(proposal)}</a></li>
|
|
109
109
|
))}
|
|
110
110
|
</ul>
|
|
111
111
|
</div>
|
|
112
112
|
)}
|
|
113
113
|
{relatedDecisions.length > 0 && (
|
|
114
114
|
<div>
|
|
115
|
-
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--
|
|
116
|
-
<ul class="mt-3 space-y-2 text-[color:var(--
|
|
115
|
+
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">Related decisions</p>
|
|
116
|
+
<ul class="mt-3 space-y-2 text-[color:var(--ts-color-text-muted)]">
|
|
117
117
|
{relatedDecisions.map((decision) => (
|
|
118
|
-
<li><a href={`/decisions/${decision.id}/`} class="hover:text-[color:var(--
|
|
118
|
+
<li><a href={`/decisions/${decision.id}/`} class="hover:text-[color:var(--ts-color-text)]">{entryTitle(decision)}</a></li>
|
|
119
119
|
))}
|
|
120
120
|
</ul>
|
|
121
121
|
</div>
|
|
122
122
|
)}
|
|
123
123
|
{relatedBooks.length > 0 && (
|
|
124
124
|
<div>
|
|
125
|
-
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--
|
|
126
|
-
<ul class="mt-3 space-y-2 text-[color:var(--
|
|
125
|
+
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">Related books</p>
|
|
126
|
+
<ul class="mt-3 space-y-2 text-[color:var(--ts-color-text-muted)]">
|
|
127
127
|
{relatedBooks.map((book) => (
|
|
128
|
-
<li><a href={`/books/${book.id}/`} class="hover:text-[color:var(--
|
|
128
|
+
<li><a href={`/books/${book.id}/`} class="hover:text-[color:var(--ts-color-text)]">{entryTitle(book)}</a></li>
|
|
129
129
|
))}
|
|
130
130
|
</ul>
|
|
131
131
|
</div>
|
|
@@ -6,25 +6,25 @@ const { entry, currentPath } = Astro.props;
|
|
|
6
6
|
|
|
7
7
|
<MainLayout title={entry.title} description={entry.description} currentPath={currentPath}>
|
|
8
8
|
<article class="max-w-5xl space-y-8">
|
|
9
|
-
<div class="space-y-4 border-b border-[color:var(--
|
|
10
|
-
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--
|
|
11
|
-
<h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--
|
|
12
|
-
<p class="max-w-4xl text-xl leading-10 text-[color:var(--
|
|
9
|
+
<div class="space-y-4 border-b border-[color:var(--ts-color-border)] pb-8">
|
|
10
|
+
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">{entry.sectionLabel}</p>
|
|
11
|
+
<h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--ts-color-text)] md:text-6xl">{entry.title}</h1>
|
|
12
|
+
<p class="max-w-4xl text-xl leading-10 text-[color:var(--ts-color-text-muted)]">{entry.summary}</p>
|
|
13
13
|
{entry.tags.length > 0 && (
|
|
14
|
-
<p class="text-sm uppercase tracking-[0.14em] text-[color:var(--
|
|
14
|
+
<p class="text-sm uppercase tracking-[0.14em] text-[color:var(--ts-color-accent-strong)]">{entry.tags.join(' / ')}</p>
|
|
15
15
|
)}
|
|
16
16
|
<div class="flex flex-wrap gap-3 pt-2">
|
|
17
|
-
<a href={entry.landingPath} class="border border-[color:var(--
|
|
18
|
-
<a href={entry.downloadHref} class="border border-[color:var(--
|
|
17
|
+
<a href={entry.landingPath} class="border border-[color:var(--ts-color-border-strong)] px-4 py-2 text-sm font-semibold text-[color:var(--ts-color-text)] transition hover:border-[color:var(--ts-color-info)] hover:bg-[color:var(--ts-color-info-soft)]">Open knowledge</a>
|
|
18
|
+
<a href={entry.downloadHref} class="border border-[color:var(--ts-color-accent)] bg-[color:var(--ts-color-accent)] px-4 py-2 text-sm font-semibold text-[color:var(--ts-color-text)] transition hover:border-[color:var(--ts-color-info)] hover:bg-[color:var(--ts-color-info-soft)]">Download book</a>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
<div class="grid gap-6 md:grid-cols-[1.25fr_0.75fr]">
|
|
22
22
|
<div class="prose-karyon">
|
|
23
23
|
<slot />
|
|
24
24
|
</div>
|
|
25
|
-
<div class="border border-[color:var(--
|
|
26
|
-
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--
|
|
27
|
-
<ul class="mt-3 space-y-2 text-[color:var(--
|
|
25
|
+
<div class="border border-[color:var(--ts-color-border)] bg-[color:var(--ts-color-surface)] p-5">
|
|
26
|
+
<p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">Book paths</p>
|
|
27
|
+
<ul class="mt-3 space-y-2 text-[color:var(--ts-color-text-muted)]">
|
|
28
28
|
<li>Landing path: <code>{entry.landingPath}</code></li>
|
|
29
29
|
<li>Base path: <code>{entry.basePath}</code></li>
|
|
30
30
|
<li>Download file: <code>{entry.downloadFileName}</code></li>
|
|
@@ -9,13 +9,13 @@ const { entry, currentPath } = Astro.props;
|
|
|
9
9
|
<MainLayout title={entry.title} description={entry.description} currentPath={currentPath}>
|
|
10
10
|
<div class="space-y-8">
|
|
11
11
|
<StageBanner />
|
|
12
|
-
<section class="max-w-5xl space-y-5 border-b border-[color:var(--
|
|
12
|
+
<section class="max-w-5xl space-y-5 border-b border-[color:var(--ts-color-border)] pb-8">
|
|
13
13
|
<div class="flex flex-wrap items-center gap-3">
|
|
14
14
|
<StatusBadge status={entry.status} />
|
|
15
|
-
<p class="text-sm font-medium text-[color:var(--
|
|
15
|
+
<p class="text-sm font-medium text-[color:var(--ts-color-text-subtle)]">Updated {entry.updated.toISOString().slice(0, 10)}</p>
|
|
16
16
|
</div>
|
|
17
|
-
<h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--
|
|
18
|
-
<p class="max-w-4xl text-xl leading-10 text-[color:var(--
|
|
17
|
+
<h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--ts-color-text)] md:text-7xl">{entry.title}</h1>
|
|
18
|
+
<p class="max-w-4xl text-xl leading-10 text-[color:var(--ts-color-text-muted)]">{entry.summary}</p>
|
|
19
19
|
</section>
|
|
20
20
|
<article class="prose-karyon max-w-4xl">
|
|
21
21
|
<slot />
|