@treeseed/core 0.8.8 → 0.8.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/components/SiteTitle.astro +2 -2
  2. package/dist/components/content/ContentStatusLegend.astro +4 -4
  3. package/dist/components/docs/BookFontControls.astro +9 -9
  4. package/dist/components/docs/DesktopSidebarToggle.astro +8 -8
  5. package/dist/components/docs/Footer.astro +7 -91
  6. package/dist/components/docs/Header.astro +9 -2
  7. package/dist/components/docs/PageTitle.astro +1 -1
  8. package/dist/components/docs/ThemeSelect.astro +3 -1
  9. package/dist/components/forms/ContactForm.astro +21 -21
  10. package/dist/components/forms/FooterSubscribeForm.astro +9 -9
  11. package/dist/components/site/BookList.astro +7 -7
  12. package/dist/components/site/CTASection.astro +4 -4
  13. package/dist/components/site/ChronicleList.astro +6 -6
  14. package/dist/components/site/Hero.astro +3 -3
  15. package/dist/components/site/PathCard.astro +5 -5
  16. package/dist/components/site/ProfileList.astro +5 -5
  17. package/dist/components/site/RouteNotFound.astro +6 -6
  18. package/dist/components/site/SectionIntro.astro +3 -3
  19. package/dist/components/site/StageBanner.astro +2 -2
  20. package/dist/components/site/TrustCallout.astro +3 -3
  21. package/dist/components/ui/data/ActionList.astro +51 -0
  22. package/dist/components/ui/data/Badge.astro +19 -0
  23. package/dist/components/ui/data/DataTable.astro +51 -0
  24. package/dist/components/ui/data/KeyValueList.astro +28 -0
  25. package/dist/components/ui/data/MetricCard.astro +25 -0
  26. package/dist/components/ui/data/MetricGrid.astro +27 -0
  27. package/dist/components/ui/data/StatusPill.astro +20 -0
  28. package/dist/components/ui/forms/Button.astro +52 -0
  29. package/dist/components/ui/forms/Field.astro +39 -0
  30. package/dist/components/ui/forms/FormActions.astro +12 -0
  31. package/dist/components/ui/forms/PasswordMeter.astro +80 -0
  32. package/dist/components/ui/forms/RadioGroup.astro +55 -0
  33. package/dist/components/ui/forms/Select.astro +44 -0
  34. package/dist/components/ui/forms/TextInput.astro +58 -0
  35. package/dist/components/ui/forms/Textarea.astro +45 -0
  36. package/dist/components/ui/layout/PageHeader.astro +45 -0
  37. package/dist/components/ui/shell/AppShell.astro +112 -0
  38. package/dist/components/ui/shell/BottomNav.astro +35 -0
  39. package/dist/components/ui/shell/ProjectHeader.astro +66 -0
  40. package/dist/components/ui/shell/PublicFooter.astro +39 -0
  41. package/dist/components/ui/shell/PublicShell.astro +179 -0
  42. package/dist/components/ui/shell/RailNav.astro +35 -0
  43. package/dist/components/ui/shell/TopBar.astro +52 -0
  44. package/dist/components/ui/surface/Card.astro +46 -0
  45. package/dist/components/ui/surface/EmptyState.astro +45 -0
  46. package/dist/components/ui/surface/Panel.astro +54 -0
  47. package/dist/components/ui/theme/ThemeMenu.astro +32 -0
  48. package/dist/components/ui/theme/ThemePreviewSwatch.astro +18 -0
  49. package/dist/components/ui/theme/ThemeScript.astro +111 -0
  50. package/dist/components/ui/theme/ThemeSelector.astro +202 -0
  51. package/dist/components/ui/types.js +0 -0
  52. package/dist/dev-watch.d.ts +6 -2
  53. package/dist/dev-watch.js +12 -3
  54. package/dist/dev.d.ts +10 -2
  55. package/dist/dev.js +352 -68
  56. package/dist/layouts/AuthoredEntryLayout.astro +27 -27
  57. package/dist/layouts/BookLayout.astro +10 -10
  58. package/dist/layouts/ContentLayout.astro +4 -4
  59. package/dist/layouts/MainLayout.astro +66 -193
  60. package/dist/layouts/NoteLayout.astro +6 -6
  61. package/dist/layouts/ProfileLayout.astro +17 -17
  62. package/dist/middleware/starlightRouteData.js +20 -14
  63. package/dist/pages/404.astro +8 -8
  64. package/dist/pages/[slug].astro +1 -1
  65. package/dist/pages/books/[slug].astro +5 -5
  66. package/dist/pages/contact.astro +4 -4
  67. package/dist/pages/docs-runtime/[...slug].astro +12 -12
  68. package/dist/pages/docs-runtime/index.astro +13 -13
  69. package/dist/pages/index.astro +28 -28
  70. package/dist/pages/ui/index.astro +216 -0
  71. package/dist/scripts/dev-platform.js +7 -1
  72. package/dist/site.js +53 -5
  73. package/dist/styles/app-shell.css +597 -0
  74. package/dist/styles/forms.css +258 -0
  75. package/dist/styles/global.css +125 -120
  76. package/dist/styles/prose.css +11 -11
  77. package/dist/styles/theme.css +177 -0
  78. package/dist/styles/tokens.css +62 -22
  79. package/dist/styles/ui.css +551 -0
  80. package/dist/utils/color-schemes/cedar.js +53 -0
  81. package/dist/utils/color-schemes/fern.js +53 -0
  82. package/dist/utils/color-schemes/index.js +13 -0
  83. package/dist/utils/color-schemes/lichen.js +53 -0
  84. package/dist/utils/color-schemes/shared.js +33 -0
  85. package/dist/utils/color-schemes/tidepool.js +53 -0
  86. package/dist/utils/content-status.js +5 -5
  87. package/dist/utils/site-config.js +2 -2
  88. package/dist/utils/starlight-nav.js +13 -7
  89. package/dist/utils/theme.js +133 -41
  90. package/package.json +36 -2
@@ -8,7 +8,7 @@ import { isPublishedRuntimeContentMode, loadPublishedEntry } from '../utils/site
8
8
 
9
9
  export const prerender = false;
10
10
 
11
- const slug = String(Astro.params.slug ?? '');
11
+ const slug = String(Astro.params.slug ?? Astro.url.pathname.replace(/^\/+|\/+$/g, ''));
12
12
  const publishedRuntime = isPublishedRuntimeContentMode();
13
13
  const localEntry = publishedRuntime ? null : (await getCollection('pages')).find((candidate) => candidate.data.slug === slug) ?? null;
14
14
  const publishedEntry = publishedRuntime ? await loadPublishedEntry(Astro.locals, 'pages', slug) : null;
@@ -9,14 +9,14 @@ export const prerender = false;
9
9
 
10
10
  const slug = String(Astro.params.slug ?? '');
11
11
  const publishedRuntime = isPublishedRuntimeContentMode();
12
- const books = publishedRuntime ? [] : (await getCollection('books')).sort((a, b) => a.data.order - b.data.order);
13
- const localBook = publishedRuntime ? null : books.find((candidate) => candidate.id === slug) ?? null;
12
+ const books = (await getCollection('books')).sort((a, b) => a.data.order - b.data.order);
13
+ const localBook = books.find((candidate) => candidate.id === slug || candidate.data.slug === slug) ?? null;
14
14
  const publishedBook = publishedRuntime ? await loadPublishedEntry(Astro.locals, 'books', slug) : null;
15
- const book = publishedRuntime ? publishedBook?.entry ?? null : localBook;
15
+ const book = publishedRuntime ? publishedBook?.entry ?? localBook : localBook;
16
16
  if (!book) {
17
17
  Astro.response.status = 404;
18
18
  }
19
- const rendered = !publishedRuntime && localBook ? await render(localBook) : null;
19
+ const rendered = localBook ? await render(localBook) : null;
20
20
  const Content = rendered?.Content ?? null;
21
21
  ---
22
22
 
@@ -25,7 +25,7 @@ const Content = rendered?.Content ?? null;
25
25
  <RouteNotFound title="Book not found" description="The requested book could not be found in this Treeseed." currentPath="/books/" />
26
26
  ) : (
27
27
  <BookLayout entry={book.data} currentPath="/books/">
28
- {publishedRuntime ? <PublishedContentBody html={publishedBook?.html ?? ''} /> : <Content />}
28
+ {publishedBook?.html ? <PublishedContentBody html={publishedBook.html} /> : Content ? <Content /> : null}
29
29
  </BookLayout>
30
30
  )
31
31
  }
@@ -12,12 +12,12 @@ const code = Astro.url.searchParams.get('formCode');
12
12
  currentPath="/contact/"
13
13
  >
14
14
  <div class="space-y-6">
15
- <section class="max-w-3xl space-y-4 border-b border-[color:var(--site-border)] pb-6">
16
- <p class="text-sm font-semibold uppercase tracking-[0.18em] text-[color:var(--site-accent-strong)]">Contact</p>
17
- <h1 class="max-w-3xl font-serif text-5xl font-bold tracking-tight text-[color:var(--site-text)] md:text-6xl">
15
+ <section class="max-w-3xl space-y-4 border-b border-[color:var(--ts-color-border)] pb-6">
16
+ <p class="text-sm font-semibold uppercase tracking-[0.18em] text-[color:var(--ts-color-accent-strong)]">Contact</p>
17
+ <h1 class="max-w-3xl font-serif text-5xl font-bold tracking-tight text-[color:var(--ts-color-text)] md:text-6xl">
18
18
  Get in touch...
19
19
  </h1>
20
- <p class="max-w-2xl text-lg leading-9 text-[color:var(--site-text-muted)]">
20
+ <p class="max-w-2xl text-lg leading-9 text-[color:var(--ts-color-text-muted)]">
21
21
  We welcome questions, feedback, collaboration, and issue reports. Messages are routed by topic so they land in the right inbox.
22
22
  </p>
23
23
  </section>
@@ -46,32 +46,32 @@ const download = activeBook
46
46
  currentPath={currentPath}
47
47
  >
48
48
  <div class="grid gap-8 lg:grid-cols-[0.75fr_1.25fr]">
49
- <aside class="space-y-6 border border-[color:var(--site-border)] bg-[color:var(--site-surface)] p-6">
49
+ <aside class="space-y-6 border border-[color:var(--ts-color-border)] bg-[color:var(--ts-color-surface)] p-6">
50
50
  <div class="space-y-3">
51
- <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--site-blue-strong)]">
51
+ <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--ts-color-info-text)]">
52
52
  {activeBook?.sectionLabel ?? 'Knowledge'}
53
53
  </p>
54
- <a href="/knowledge/" class="block text-sm font-medium text-[color:var(--site-text-muted)] hover:text-[color:var(--site-text)]">Knowledge home</a>
54
+ <a href={runtime?.TREESEED_LINKS.home ?? '/books/'} class="block text-sm font-medium text-[color:var(--ts-color-text-muted)] hover:text-[color:var(--ts-color-text)]">Books home</a>
55
55
  {activeBook?.landingPath && (
56
- <a href={activeBook.landingPath} class="block text-sm font-medium text-[color:var(--site-text-muted)] hover:text-[color:var(--site-text)]">Open book landing page</a>
56
+ <a href={activeBook.landingPath} class="block text-sm font-medium text-[color:var(--ts-color-text-muted)] hover:text-[color:var(--ts-color-text)]">Open book landing page</a>
57
57
  )}
58
58
  {download && (
59
59
  <a
60
60
  href={download.href}
61
- class="inline-flex border border-[color:var(--site-accent)] bg-[color:var(--site-accent)] px-4 py-2 text-sm font-semibold text-[color:var(--site-text)] transition hover:border-[color:var(--site-blue)] hover:bg-[color:var(--site-blue-soft)]"
61
+ class="inline-flex 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)]"
62
62
  >
63
63
  {download.title}
64
64
  </a>
65
65
  )}
66
66
  </div>
67
- <ul class="space-y-2 text-sm text-[color:var(--site-text-muted)]">
67
+ <ul class="space-y-2 text-sm text-[color:var(--ts-color-text-muted)]">
68
68
  {sidebarEntries.map((entry) => (
69
69
  <li>
70
70
  <a
71
71
  href={entry.path}
72
72
  class:list={[
73
- 'hover:text-[color:var(--site-text)]',
74
- entry.path === currentPath && 'font-semibold text-[color:var(--site-text)]',
73
+ 'hover:text-[color:var(--ts-color-text)]',
74
+ entry.path === currentPath && 'font-semibold text-[color:var(--ts-color-text)]',
75
75
  ]}
76
76
  >
77
77
  {entry.title ?? entry.slug}
@@ -81,15 +81,15 @@ const download = activeBook
81
81
  </ul>
82
82
  </aside>
83
83
  <article class="space-y-6">
84
- <header class="space-y-4 border-b border-[color:var(--site-border)] pb-6">
85
- <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--site-blue-strong)]">
84
+ <header class="space-y-4 border-b border-[color:var(--ts-color-border)] pb-6">
85
+ <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--ts-color-info-text)]">
86
86
  {activeBook?.sectionLabel ?? 'Knowledge'}
87
87
  </p>
88
- <h1 class="font-serif text-5xl font-bold tracking-tight text-[color:var(--site-text)] md:text-6xl">
88
+ <h1 class="font-serif text-5xl font-bold tracking-tight text-[color:var(--ts-color-text)] md:text-6xl">
89
89
  {document.entry.data.title ?? document.entry.slug}
90
90
  </h1>
91
91
  {document.entry.data.summary && (
92
- <p class="max-w-3xl text-xl leading-10 text-[color:var(--site-text-muted)]">{document.entry.data.summary}</p>
92
+ <p class="max-w-3xl text-xl leading-10 text-[color:var(--ts-color-text-muted)]">{document.entry.data.summary}</p>
93
93
  )}
94
94
  </header>
95
95
  <div class="prose-karyon max-w-none">
@@ -36,13 +36,13 @@ const ungroupedEntries = (docsTree ?? []).filter((entry) =>
36
36
  currentPath="/knowledge/"
37
37
  >
38
38
  <div class="grid gap-8 lg:grid-cols-[0.75fr_1.25fr]">
39
- <aside class="space-y-6 border border-[color:var(--site-border)] bg-[color:var(--site-surface)] p-6">
39
+ <aside class="space-y-6 border border-[color:var(--ts-color-border)] bg-[color:var(--ts-color-surface)] p-6">
40
40
  <div class="space-y-3">
41
- <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--site-blue-strong)]">Knowledge hub</p>
41
+ <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--ts-color-info-text)]">Knowledge hub</p>
42
42
  {runtime?.TREESEED_LIBRARY_DOWNLOAD && (
43
43
  <a
44
44
  href={runtime.TREESEED_LIBRARY_DOWNLOAD.downloadHref}
45
- class="inline-flex border border-[color:var(--site-accent)] bg-[color:var(--site-accent)] px-4 py-2 text-sm font-semibold text-[color:var(--site-text)] transition hover:border-[color:var(--site-blue)] hover:bg-[color:var(--site-blue-soft)]"
45
+ class="inline-flex 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)]"
46
46
  >
47
47
  {runtime.TREESEED_LIBRARY_DOWNLOAD.downloadTitle}
48
48
  </a>
@@ -50,33 +50,33 @@ const ungroupedEntries = (docsTree ?? []).filter((entry) =>
50
50
  </div>
51
51
  {bookGroups.map((group) => (
52
52
  <div class="space-y-3">
53
- <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">{group.book.sectionLabel}</p>
54
- <ul class="space-y-2 text-sm text-[color:var(--site-text-muted)]">
53
+ <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">{group.book.sectionLabel}</p>
54
+ <ul class="space-y-2 text-sm text-[color:var(--ts-color-text-muted)]">
55
55
  {group.entries.map((entry) => (
56
- <li><a href={entry.path} class="hover:text-[color:var(--site-text)]">{entry.title ?? entry.slug}</a></li>
56
+ <li><a href={entry.path} class="hover:text-[color:var(--ts-color-text)]">{entry.title ?? entry.slug}</a></li>
57
57
  ))}
58
58
  </ul>
59
59
  </div>
60
60
  ))}
61
61
  {ungroupedEntries.length > 0 && (
62
62
  <div class="space-y-3">
63
- <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">More knowledge</p>
64
- <ul class="space-y-2 text-sm text-[color:var(--site-text-muted)]">
63
+ <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--ts-color-info-text)]">More knowledge</p>
64
+ <ul class="space-y-2 text-sm text-[color:var(--ts-color-text-muted)]">
65
65
  {ungroupedEntries.map((entry) => (
66
- <li><a href={entry.path} class="hover:text-[color:var(--site-text)]">{entry.title ?? entry.slug}</a></li>
66
+ <li><a href={entry.path} class="hover:text-[color:var(--ts-color-text)]">{entry.title ?? entry.slug}</a></li>
67
67
  ))}
68
68
  </ul>
69
69
  </div>
70
70
  )}
71
71
  </aside>
72
72
  <article class="space-y-6">
73
- <header class="space-y-4 border-b border-[color:var(--site-border)] pb-6">
74
- <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--site-blue-strong)]">Published docs</p>
75
- <h1 class="font-serif text-5xl font-bold tracking-tight text-[color:var(--site-text)] md:text-6xl">
73
+ <header class="space-y-4 border-b border-[color:var(--ts-color-border)] pb-6">
74
+ <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--ts-color-info-text)]">Published docs</p>
75
+ <h1 class="font-serif text-5xl font-bold tracking-tight text-[color:var(--ts-color-text)] md:text-6xl">
76
76
  {document.entry.data.title ?? 'Knowledge'}
77
77
  </h1>
78
78
  {document.entry.data.summary && (
79
- <p class="max-w-3xl text-xl leading-10 text-[color:var(--site-text-muted)]">{document.entry.data.summary}</p>
79
+ <p class="max-w-3xl text-xl leading-10 text-[color:var(--ts-color-text-muted)]">{document.entry.data.summary}</p>
80
80
  )}
81
81
  </header>
82
82
  <div class="prose-karyon max-w-none">
@@ -155,12 +155,12 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
155
155
  <StageBanner />
156
156
  </div>
157
157
  <div slot="title">
158
- <h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--site-text)] md:text-7xl">
158
+ <h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--ts-color-text)] md:text-7xl">
159
159
  A small TreeSeed site that doubles as documentation and a real test ground.
160
160
  </h1>
161
161
  </div>
162
162
  <div slot="body">
163
- <p class="max-w-3xl text-xl leading-10 text-[color:var(--site-text-muted)]">
163
+ <p class="max-w-3xl text-xl leading-10 text-[color:var(--ts-color-text-muted)]">
164
164
  TreeSeed works best when contributors can understand the package, inspect the
165
165
  tenant surface, and verify real workflows without reconstructing everything from
166
166
  source code alone. This fixture keeps those paths visible by combining pages,
@@ -168,12 +168,12 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
168
168
  </p>
169
169
  </div>
170
170
  <div slot="actions">
171
- <a href="/status/" class="border border-[color:var(--site-accent)] bg-[color:var(--site-accent)] px-5 py-3 text-base font-semibold text-[color:var(--site-text)] transition hover:border-[color:var(--site-blue)] hover:bg-[color:var(--site-blue-soft)]">See what exists today</a>
172
- <a href="/vision/" class="border border-[color:var(--site-border-strong)] px-5 py-3 text-base font-semibold text-[color:var(--site-text)] transition hover:border-[color:var(--site-blue)] hover:bg-[color:var(--site-blue-soft)]">Read the vision</a>
171
+ <a href="/status/" class="border border-[color:var(--ts-color-accent)] bg-[color:var(--ts-color-accent)] px-5 py-3 text-base font-semibold text-[color:var(--ts-color-text)] transition hover:border-[color:var(--ts-color-info)] hover:bg-[color:var(--ts-color-info-soft)]">See what exists today</a>
172
+ <a href="/vision/" class="border border-[color:var(--ts-color-border-strong)] px-5 py-3 text-base font-semibold text-[color:var(--ts-color-text)] transition hover:border-[color:var(--ts-color-info)] hover:bg-[color:var(--ts-color-info-soft)]">Read the vision</a>
173
173
  </div>
174
174
  <div slot="aside" class="space-y-4">
175
- <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--site-blue-strong)]">Right now</p>
176
- <ul class="space-y-4 text-base leading-8 text-[color:var(--site-text-muted)]">
175
+ <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--ts-color-info-text)]">Right now</p>
176
+ <ul class="space-y-4 text-base leading-8 text-[color:var(--ts-color-text-muted)]">
177
177
  <li>A full TreeSeed content surface with pages, notes, questions, objectives, proposals, decisions, people, agents, books, and docs.</li>
178
178
  <li>Package defaults exercised through a realistic tenant instead of isolated unit tests alone.</li>
179
179
  <li>Forms, book exports, and navigation paths that participate in release verification.</li>
@@ -189,7 +189,7 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
189
189
  title="A working site for documentation, management, and verification"
190
190
  description="TreeSeed is easiest to understand when the package runtime and the tenant experience are visible together. The fixture exists to make that relationship concrete."
191
191
  />
192
- <div class="space-y-4 text-lg leading-9 text-[color:var(--site-text-muted)]">
192
+ <div class="space-y-4 text-lg leading-9 text-[color:var(--ts-color-text-muted)]">
193
193
  <p>
194
194
  The site is intentionally generic. It is not here to tell one project’s story.
195
195
  It is here to show how TreeSeed can organize content, contributor roles, inquiry,
@@ -209,25 +209,25 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
209
209
  />
210
210
  </section>
211
211
 
212
- <section class="space-y-6 border-t border-[color:var(--site-border)] pt-10">
212
+ <section class="space-y-6 border-t border-[color:var(--ts-color-border)] pt-10">
213
213
  <SectionIntro
214
214
  eyebrow="What Makes It Useful"
215
215
  title="The site keeps docs, inquiry, and operations in the same surface"
216
216
  description="The fixture is designed to show how TreeSeed can turn scattered workflow concepts into one inspectable tenant."
217
217
  />
218
218
  <div class="grid gap-6 md:grid-cols-2">
219
- <div class="border border-[color:var(--site-border)] bg-[color:var(--site-surface)] p-6">
220
- <h2 class="font-serif text-2xl text-[color:var(--site-text)]">Content commitments</h2>
221
- <ul class="mt-4 space-y-3 text-base leading-8 text-[color:var(--site-text-muted)]">
219
+ <div class="border border-[color:var(--ts-color-border)] bg-[color:var(--ts-color-surface)] p-6">
220
+ <h2 class="font-serif text-2xl text-[color:var(--ts-color-text)]">Content commitments</h2>
221
+ <ul class="mt-4 space-y-3 text-base leading-8 text-[color:var(--ts-color-text-muted)]">
222
222
  <li>Questions, objectives, proposals, and decisions stay visible instead of disappearing into process notes.</li>
223
223
  <li>Books and docs remain queryable content, not only navigation configuration.</li>
224
224
  <li>People and agents are explicit contributors rather than invisible supporting actors.</li>
225
225
  <li>Notes can still capture evidence and rationale without replacing proposal and decision records.</li>
226
226
  </ul>
227
227
  </div>
228
- <div class="border border-[color:var(--site-border)] bg-[color:var(--site-surface)] p-6">
229
- <h2 class="font-serif text-2xl text-[color:var(--site-text)]">Execution posture</h2>
230
- <ul class="mt-4 space-y-3 text-base leading-8 text-[color:var(--site-text-muted)]">
228
+ <div class="border border-[color:var(--ts-color-border)] bg-[color:var(--ts-color-surface)] p-6">
229
+ <h2 class="font-serif text-2xl text-[color:var(--ts-color-text)]">Execution posture</h2>
230
+ <ul class="mt-4 space-y-3 text-base leading-8 text-[color:var(--ts-color-text-muted)]">
231
231
  <li>The fixture participates directly in `check`, `build`, and smoke verification.</li>
232
232
  <li>Shared defaults should read clearly in a generic tenant, not only in package code.</li>
233
233
  <li>Generated book exports and forms flows are part of the package contract.</li>
@@ -237,14 +237,14 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
237
237
  </div>
238
238
  </section>
239
239
 
240
- <section class="space-y-6 border-t border-[color:var(--site-border)] pt-10">
240
+ <section class="space-y-6 border-t border-[color:var(--ts-color-border)] pt-10">
241
241
  <SectionIntro
242
242
  eyebrow="What Exists Today"
243
243
  title="A realistic tenant that stays intentionally generic"
244
244
  description="The fixture is broad enough to exercise the package meaningfully, but it stays small enough to remain maintainable and easy to read."
245
245
  />
246
246
  <div class="grid gap-6 lg:grid-cols-[1fr_1fr]">
247
- <div class="space-y-4 text-base leading-8 text-[color:var(--site-text-muted)]">
247
+ <div class="space-y-4 text-base leading-8 text-[color:var(--ts-color-text-muted)]">
248
248
  <p>
249
249
  The current fixture demonstrates the full TreeSeed surface: pages, notes, questions,
250
250
  objectives, proposals, decisions, people, agents, books, docs, and forms. That gives package changes a
@@ -256,14 +256,14 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
256
256
  possible downstream use case.
257
257
  </p>
258
258
  </div>
259
- <div class="border border-[color:var(--site-border)] bg-[color:var(--site-surface)] p-6">
260
- <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--site-accent-strong)]">Best current shorthand</p>
261
- <p class="mt-4 font-serif text-3xl text-[color:var(--site-text)]">
259
+ <div class="border border-[color:var(--ts-color-border)] bg-[color:var(--ts-color-surface)] p-6">
260
+ <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--ts-color-accent-strong)]">Best current shorthand</p>
261
+ <p class="mt-4 font-serif text-3xl text-[color:var(--ts-color-text)]">
262
262
  Documentation-first example, real enough to break usefully.
263
263
  </p>
264
- <p class="mt-4 text-base leading-8 text-[color:var(--site-text-muted)]">
264
+ <p class="mt-4 text-base leading-8 text-[color:var(--ts-color-text-muted)]">
265
265
  If you want the evidence behind that judgment, the{' '}
266
- <a href="/status/" class="text-[color:var(--site-text)] underline decoration-[color:var(--site-accent)] underline-offset-4">
266
+ <a href="/status/" class="text-[color:var(--ts-color-text)] underline decoration-[color:var(--ts-color-accent)] underline-offset-4">
267
267
  Project Status
268
268
  </a>{' '}
269
269
  page is the right next step.
@@ -272,14 +272,14 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
272
272
  </div>
273
273
  </section>
274
274
 
275
- <section class="grid gap-10 border-t border-[color:var(--site-border)] pt-10 lg:grid-cols-[1.2fr_0.8fr]">
275
+ <section class="grid gap-10 border-t border-[color:var(--ts-color-border)] pt-10 lg:grid-cols-[1.2fr_0.8fr]">
276
276
  <div class="space-y-6">
277
277
  <SectionIntro
278
278
  eyebrow="How To Read The Site"
279
279
  title="Follow the path that matches the question you have"
280
280
  description="Each public page has a single job: explain the platform, ground it in implementation reality, define active work, or make collaboration legible."
281
281
  />
282
- <div class="border-b border-[color:var(--site-border)]">
282
+ <div class="border-b border-[color:var(--ts-color-border)]">
283
283
  <PathCard href="/vision/" title="Vision" meta="Why this fixture exists" description="Start with the reason TreeSeed keeps a generic working site in the repo." />
284
284
  <PathCard href="/status/" title="Status" meta="What the fixture proves today" description="See which package surfaces the fixture is expected to exercise and why that matters." />
285
285
  <PathCard href="/research-direction/" title="Research Direction" meta="What questions organize the work" description="Follow the implementation-facing questions that keep the fixture useful." />
@@ -287,9 +287,9 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
287
287
  <PathCard href="/contribute/" title="Contribute" meta="How to help usefully" description="Find the most useful contribution lanes for a documentation-first TreeSeed site." />
288
288
  </div>
289
289
  </div>
290
- <div class="border border-[color:var(--site-border)] bg-[color:var(--site-surface)] p-6">
291
- <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--site-blue-strong)]">Useful feedback</p>
292
- <p class="mt-4 text-base leading-8 text-[color:var(--site-text-muted)]">
290
+ <div class="border border-[color:var(--ts-color-border)] bg-[color:var(--ts-color-surface)] p-6">
291
+ <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--ts-color-info-text)]">Useful feedback</p>
292
+ <p class="mt-4 text-base leading-8 text-[color:var(--ts-color-text-muted)]">
293
293
  The most helpful feedback is concrete: which defaults still feel confusing, which
294
294
  workflows are hard to infer, and which parts of the fixture are too thin or too heavy
295
295
  to serve as a reliable test ground.
@@ -298,7 +298,7 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
298
298
  </section>
299
299
 
300
300
  {notesRendered && (
301
- <section class="space-y-6 border-t border-[color:var(--site-border)] pt-10">
301
+ <section class="space-y-6 border-t border-[color:var(--ts-color-border)] pt-10">
302
302
  <SectionIntro
303
303
  eyebrow="Notes"
304
304
  title="Working notes instead of polished announcements"
@@ -309,7 +309,7 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
309
309
  )}
310
310
 
311
311
  {(questionsRendered || objectivesRendered || proposalsRendered || decisionsRendered || peopleRendered || agentsRendered || booksRendered) && (
312
- <section class="space-y-8 border-t border-[color:var(--site-border)] pt-10">
312
+ <section class="space-y-8 border-t border-[color:var(--ts-color-border)] pt-10">
313
313
  <SectionIntro
314
314
  eyebrow="TreeSeed"
315
315
  title="Questions, objectives, proposals, decisions, contributors, and books form one connected working surface"
@@ -0,0 +1,216 @@
1
+ ---
2
+ import '../../styles/global.css';
3
+ import '../../styles/theme.css';
4
+ import '../../styles/ui.css';
5
+ import '../../styles/forms.css';
6
+ import ThemeScript from '../../components/ui/theme/ThemeScript.astro';
7
+ import ThemeSelector from '../../components/ui/theme/ThemeSelector.astro';
8
+ import Button from '../../components/ui/forms/Button.astro';
9
+ import Field from '../../components/ui/forms/Field.astro';
10
+ import TextInput from '../../components/ui/forms/TextInput.astro';
11
+ import Select from '../../components/ui/forms/Select.astro';
12
+ import Textarea from '../../components/ui/forms/Textarea.astro';
13
+ import RadioGroup from '../../components/ui/forms/RadioGroup.astro';
14
+ import FormActions from '../../components/ui/forms/FormActions.astro';
15
+ import PasswordMeter from '../../components/ui/forms/PasswordMeter.astro';
16
+ import Panel from '../../components/ui/surface/Panel.astro';
17
+ import Card from '../../components/ui/surface/Card.astro';
18
+ import EmptyState from '../../components/ui/surface/EmptyState.astro';
19
+ import Badge from '../../components/ui/data/Badge.astro';
20
+ import StatusPill from '../../components/ui/data/StatusPill.astro';
21
+ import MetricGrid from '../../components/ui/data/MetricGrid.astro';
22
+ import ActionList from '../../components/ui/data/ActionList.astro';
23
+ import KeyValueList from '../../components/ui/data/KeyValueList.astro';
24
+ import DataTable from '../../components/ui/data/DataTable.astro';
25
+ import PageHeader from '../../components/ui/layout/PageHeader.astro';
26
+ import { getBuiltInColorSchemes, normalizeThemePreference } from '../../utils/theme.js';
27
+
28
+ const selected = normalizeThemePreference({
29
+ scheme: Astro.url.searchParams.get('scheme'),
30
+ mode: Astro.url.searchParams.get('mode'),
31
+ });
32
+ const schemes = getBuiltInColorSchemes();
33
+ const modes = ['system', 'light', 'dark'] as const;
34
+ const tones = ['default', 'muted', 'accent', 'info', 'success', 'warning', 'danger'] as const;
35
+ const themeLinks = schemes.flatMap((scheme) => modes.map((mode) => ({
36
+ label: `${scheme.name} / ${mode}`,
37
+ href: `/ui/?scheme=${scheme.id}&mode=${mode}`,
38
+ active: scheme.id === selected.scheme && mode === selected.mode,
39
+ })));
40
+ const projectMetrics = [
41
+ { label: 'Open decisions', value: 7, description: 'Three are blocked by missing context.', tone: 'warning' as const },
42
+ { label: 'Ready releases', value: 2, description: 'Both have verification notes attached.', tone: 'success' as const },
43
+ { label: 'Active hosts', value: 14, description: 'Capacity is steady across the team.', tone: 'info' as const },
44
+ ];
45
+ const actionItems = [
46
+ {
47
+ title: 'Review release candidate',
48
+ description: 'Confirm the staged package summary before the next handoff.',
49
+ href: '#',
50
+ meta: 'Waiting',
51
+ tone: 'warning' as const,
52
+ actionLabel: 'Open',
53
+ },
54
+ {
55
+ title: 'Resolve shared direction',
56
+ description: 'One proposal needs a final owner note.',
57
+ href: '#',
58
+ meta: 'Decision',
59
+ tone: 'accent' as const,
60
+ actionLabel: 'Review',
61
+ },
62
+ {
63
+ title: 'Host capacity checked',
64
+ description: 'No action required after the latest sync.',
65
+ meta: 'Clear',
66
+ tone: 'success' as const,
67
+ },
68
+ ];
69
+ const tableColumns = [
70
+ { key: 'name', label: 'Name' },
71
+ { key: 'status', label: 'Status' },
72
+ { key: 'owner', label: 'Owner' },
73
+ ];
74
+ const tableRows = [
75
+ { name: 'Direction brief', status: 'Ready', owner: 'Research' },
76
+ { name: 'Release notes', status: 'Drafting', owner: 'Platform' },
77
+ { name: 'Host review', status: 'Queued', owner: 'Ops' },
78
+ ];
79
+ ---
80
+
81
+ <!doctype html>
82
+ <html lang="en" data-ts-scheme={selected.scheme} data-ts-mode={selected.mode}>
83
+ <head>
84
+ <meta charset="UTF-8" />
85
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
86
+ <title>TreeSeed UI Catalog</title>
87
+ <ThemeScript defaultScheme={selected.scheme} defaultMode={selected.mode} />
88
+ </head>
89
+ <body>
90
+ <main class="ts-ui-catalog">
91
+ <PageHeader
92
+ eyebrow="Core UI"
93
+ title="TreeSeed primitive catalog"
94
+ description="A focused review surface for the first shared component set. Use the appearance controls and scheme links to inspect the same primitives across every built-in theme."
95
+ actions={[{ label: 'Back home', href: '/', variant: 'secondary' }]}
96
+ >
97
+ <div class="ts-ui-catalog__selector">
98
+ <ThemeSelector selectedScheme={selected.scheme} selectedMode={selected.mode} compact={false} />
99
+ </div>
100
+ </PageHeader>
101
+
102
+ <Panel title="Scheme and mode checks" description="Each link reloads this same catalog with a different default appearance.">
103
+ <div class="ts-ui-catalog__theme-links">
104
+ {themeLinks.map((link) => (
105
+ <Button href={link.href} variant={link.active ? 'primary' : 'secondary'} size="sm">
106
+ {link.label}
107
+ </Button>
108
+ ))}
109
+ </div>
110
+ </Panel>
111
+
112
+ <Panel title="Buttons, badges, and status" description="Tones are semantic; pages should not pass arbitrary color classes.">
113
+ <div class="ts-ui-catalog__stack">
114
+ <div class="ts-ui-catalog__row">
115
+ <Button>Primary action</Button>
116
+ <Button variant="secondary">Secondary</Button>
117
+ <Button variant="ghost">Ghost</Button>
118
+ <Button variant="danger">Danger</Button>
119
+ <Button disabled>Disabled</Button>
120
+ </div>
121
+ <div class="ts-ui-catalog__row">
122
+ {tones.map((tone) => <Badge tone={tone}>{tone}</Badge>)}
123
+ </div>
124
+ <div class="ts-ui-catalog__row">
125
+ {tones.map((tone) => <StatusPill tone={tone} label={tone} />)}
126
+ </div>
127
+ </div>
128
+ </Panel>
129
+
130
+ <MetricGrid metrics={projectMetrics} />
131
+
132
+ <div class="ts-ui-catalog__grid">
133
+ <Card
134
+ eyebrow="Card"
135
+ title="Direction summary"
136
+ description="Compact cards use the same border, surface, and tone language as panels."
137
+ tone="accent"
138
+ interactive
139
+ >
140
+ <StatusPill tone="success" label="Current" />
141
+ </Card>
142
+ <Card href="#" eyebrow="Linked card" title="Open proposal" description="Cards can render anchors when a route owns the whole surface.">
143
+ <Badge tone="info">Proposal</Badge>
144
+ </Card>
145
+ <EmptyState
146
+ eyebrow="Empty state"
147
+ title="No queued reviews"
148
+ description="The empty surface keeps actions visible without introducing a custom card style."
149
+ actions={[{ label: 'Create review', href: '#', variant: 'secondary' }]}
150
+ />
151
+ </div>
152
+
153
+ <Panel
154
+ title="Form controls"
155
+ description="Labels, help text, controls, radio choices, actions, and password feedback share one form vocabulary."
156
+ >
157
+ <form class="ts-ui-catalog__form">
158
+ <Field label="Project name" name="projectName" help="Use a short name that people can scan quickly.">
159
+ <TextInput name="projectName" value="Release Garden" />
160
+ </Field>
161
+ <Field label="Workspace" name="workspace">
162
+ <Select
163
+ name="workspace"
164
+ value="research"
165
+ options={[
166
+ { label: 'Research', value: 'research' },
167
+ { label: 'Operations', value: 'operations' },
168
+ { label: 'Platform', value: 'platform' },
169
+ ]}
170
+ />
171
+ </Field>
172
+ <Field label="Notes" name="notes" full>
173
+ <Textarea name="notes" value="Capture the next decision and keep the release handoff visible." />
174
+ </Field>
175
+ <RadioGroup
176
+ name="cadence"
177
+ legend="Review cadence"
178
+ value="weekly"
179
+ options={[
180
+ { label: 'Daily', value: 'daily', help: 'Best for launch week.' },
181
+ { label: 'Weekly', value: 'weekly', help: 'A good default for steady projects.' },
182
+ { label: 'Paused', value: 'paused', help: 'Hide reminders until work resumes.' },
183
+ ]}
184
+ />
185
+ <Field label="Password preview" name="catalogPassword" full>
186
+ <TextInput id="catalogPassword" name="catalogPassword" type="password" value="TreeSeed-2026" />
187
+ </Field>
188
+ <PasswordMeter inputId="catalogPassword" />
189
+ <FormActions align="between">
190
+ <Button variant="ghost" type="reset">Reset</Button>
191
+ <Button type="submit">Save example</Button>
192
+ </FormActions>
193
+ </form>
194
+ </Panel>
195
+
196
+ <div class="ts-ui-catalog__grid">
197
+ <Panel title="Action list" description="Rows remain dense but touch-friendly on mobile.">
198
+ <ActionList items={actionItems} />
199
+ </Panel>
200
+ <Panel title="Key details" description="Settings and summaries can use a consistent key/value rhythm.">
201
+ <KeyValueList
202
+ items={[
203
+ { key: 'Team', value: 'Canopy Systems' },
204
+ { key: 'Environment', value: 'Staging', tone: 'info' },
205
+ { key: 'Risk', value: 'Low', tone: 'success' },
206
+ ]}
207
+ />
208
+ </Panel>
209
+ </div>
210
+
211
+ <Panel title="Data table" description="The table collapses into labeled mobile rows without page-specific CSS.">
212
+ <DataTable columns={tableColumns} rows={tableRows} caption="Review artifacts" />
213
+ </Panel>
214
+ </main>
215
+ </body>
216
+ </html>
@@ -20,7 +20,13 @@ function readNumberOption(name) {
20
20
  return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
21
21
  }
22
22
  function parseSurface(value) {
23
- if (value === 'web' || value === 'integrated') {
23
+ if (value === 'web' ||
24
+ value === 'api' ||
25
+ value === 'manager' ||
26
+ value === 'worker' ||
27
+ value === 'agents' ||
28
+ value === 'services' ||
29
+ value === 'integrated') {
24
30
  return value;
25
31
  }
26
32
  return 'integrated';