@treeseed/core 0.10.16 → 0.10.18

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.
@@ -99,7 +99,7 @@ const formsApiBaseUrl = SITE_FORMS?.apiBaseUrl ?? '/api/form/submit';
99
99
  <label class="grid gap-2">
100
100
  <span class="text-sm font-semibold text-[color:var(--ts-color-text)]">Topic <span aria-hidden="true" class="text-[color:var(--ts-color-warning)]">*</span></span>
101
101
  <select
102
- class="min-h-12 rounded-md border border-[color:var(--ts-color-border-strong)] bg-white/70 px-4 py-3"
102
+ class="ts-control ts-control--select min-h-12 rounded-md border border-[color:var(--ts-color-border-strong)] px-4 py-3"
103
103
  name="contactType"
104
104
  required
105
105
  aria-required="true"
@@ -10,6 +10,7 @@ interface Props {
10
10
  ariaLabel?: string;
11
11
  reload?: boolean;
12
12
  class?: string;
13
+ [key: string]: unknown;
13
14
  }
14
15
 
15
16
  const {
@@ -21,6 +22,7 @@ const {
21
22
  ariaLabel,
22
23
  reload = false,
23
24
  class: className,
25
+ ...buttonAttributes
24
26
  } = Astro.props as Props;
25
27
 
26
28
  const classes = ['ts-button', className].filter(Boolean).join(' ');
@@ -37,11 +39,13 @@ const classes = ['ts-button', className].filter(Boolean).join(' ');
37
39
  aria-disabled={disabled ? 'true' : undefined}
38
40
  tabindex={disabled ? -1 : undefined}
39
41
  data-astro-reload={reload ? true : undefined}
42
+ {...buttonAttributes}
40
43
  >
41
44
  <slot />
42
45
  </a>
43
46
  ) : (
44
47
  <button
48
+ {...buttonAttributes}
45
49
  type={type}
46
50
  class={classes}
47
51
  data-variant={variant}
@@ -14,6 +14,7 @@ interface Props {
14
14
  disabled?: boolean;
15
15
  ariaDescribedby?: string;
16
16
  class?: string;
17
+ [key: string]: unknown;
17
18
  }
18
19
 
19
20
  const {
@@ -25,10 +26,12 @@ const {
25
26
  disabled = false,
26
27
  ariaDescribedby,
27
28
  class: className,
29
+ ...selectAttributes
28
30
  } = Astro.props as Props;
29
31
  ---
30
32
 
31
33
  <select
34
+ {...selectAttributes}
32
35
  class:list={['ts-control', 'ts-control--select', className]}
33
36
  id={id}
34
37
  name={name}
@@ -61,6 +61,8 @@ const {
61
61
  <meta name="viewport" content="width=device-width, initial-scale=1" />
62
62
  <title>{title}</title>
63
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" />
64
66
  <ThemeScript defaultScheme={appearance.scheme} defaultMode={appearance.mode} preferDefaultPreference />
65
67
  <ClientRouter />
66
68
  </head>
@@ -122,6 +124,7 @@ const {
122
124
  {bottomNavItems.length > 0 ? <BottomNav items={bottomNavItems} currentPath={currentPath} /> : null}
123
125
  </div>
124
126
  <slot name="sensitiveModal" />
127
+ <slot name="modal" />
125
128
  <DevWatchReload />
126
129
  </body>
127
130
  </html>
@@ -75,6 +75,8 @@ function isCurrentPath(href: string) {
75
75
  <meta name="viewport" content="width=device-width, initial-scale=1" />
76
76
  <title>{title}</title>
77
77
  <meta name="description" content={description} />
78
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
79
+ <link rel="shortcut icon" href="/favicon.svg" type="image/svg+xml" />
78
80
  <ThemeScript
79
81
  defaultScheme={appearance.scheme}
80
82
  defaultMode={appearance.mode}
package/dist/env.yaml CHANGED
@@ -60,9 +60,10 @@ entries:
60
60
  label: Turnstile site key
61
61
  group: forms
62
62
  cluster: turnstile
63
- description: Public site key used by the browser to render the Turnstile challenge when forms protection is enabled.
64
- howToGet: Create a Turnstile widget in Cloudflare Turnstile and copy the site key.
63
+ description: Public site key generated by the managed Cloudflare Turnstile widget for each hosted project environment.
64
+ howToGet: Treeseed creates and syncs this from the managed Cloudflare Turnstile widget during deploy.
65
65
  sensitivity: plain
66
+ visibility: system
66
67
  targets:
67
68
  - github-variable
68
69
  - cloudflare-var
@@ -70,25 +71,22 @@ entries:
70
71
  - staging
71
72
  - prod
72
73
  storage: shared
73
- requirement: conditional
74
+ requirement: generated
74
75
  purposes:
75
- - save
76
76
  - deploy
77
- - config
78
77
  validation:
79
78
  kind: nonempty
80
79
  sourcePriority:
81
- - machine-config
82
- - process-env
80
+ - generated
83
81
  relevanceRef: turnstileEnabled
84
- requiredWhenRef: turnstileNonLocal
85
82
  TREESEED_TURNSTILE_SECRET_KEY:
86
83
  label: Turnstile secret key
87
84
  group: forms
88
85
  cluster: turnstile
89
- description: Server-side Turnstile secret used to verify challenge responses.
90
- howToGet: Create a Turnstile widget in Cloudflare Turnstile and copy the secret key.
86
+ description: Server-side Turnstile secret generated by the managed Cloudflare Turnstile widget for each hosted project environment.
87
+ howToGet: Treeseed creates and syncs this from the managed Cloudflare Turnstile widget during deploy.
91
88
  sensitivity: secret
89
+ visibility: system
92
90
  targets:
93
91
  - github-secret
94
92
  - cloudflare-secret
@@ -96,18 +94,14 @@ entries:
96
94
  - staging
97
95
  - prod
98
96
  storage: shared
99
- requirement: conditional
97
+ requirement: generated
100
98
  purposes:
101
- - save
102
99
  - deploy
103
- - config
104
100
  validation:
105
101
  kind: nonempty
106
102
  sourcePriority:
107
- - machine-config
108
- - process-env
103
+ - generated
109
104
  relevanceRef: turnstileEnabled
110
- requiredWhenRef: turnstileNonLocal
111
105
  TREESEED_SMTP_HOST:
112
106
  label: SMTP host
113
107
  group: smtp
@@ -32,8 +32,6 @@ const navItems = SITE_NAV_GROUPS.flatMap((group) => group.items);
32
32
  contentWidth="content"
33
33
  >
34
34
  <Fragment slot="head">
35
- <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
36
- <link rel="shortcut icon" href="/favicon.svg" type="image/svg+xml" />
37
35
  {SITE_THEME_CSS && <style is:global>{SITE_THEME_CSS}</style>}
38
36
  </Fragment>
39
37
  <Fragment slot="actions">
@@ -40,7 +40,8 @@
40
40
 
41
41
  .ts-app-shell__rail-scroll {
42
42
  display: grid;
43
- gap: var(--ts-space-3);
43
+ align-content: start;
44
+ gap: var(--ts-space-2);
44
45
  min-height: 0;
45
46
  overflow: auto;
46
47
  padding-right: 0.15rem;
@@ -129,7 +130,7 @@
129
130
  .ts-app-shell__quick-actions {
130
131
  border-top: 1px solid var(--ts-color-border);
131
132
  display: grid;
132
- gap: var(--ts-space-2);
133
+ gap: var(--ts-space-1);
133
134
  padding-top: var(--ts-space-2);
134
135
  }
135
136
 
@@ -154,8 +155,9 @@
154
155
  .ts-rail-nav {
155
156
  border-top: 1px solid var(--ts-color-border);
156
157
  display: grid;
157
- gap: 0.2rem;
158
- padding-top: var(--ts-space-2);
158
+ gap: 0.08rem;
159
+ margin-top: 1.25rem;
160
+ padding-top: var(--ts-space-1);
159
161
  }
160
162
 
161
163
  .ts-rail-nav__link,
@@ -168,10 +170,12 @@
168
170
 
169
171
  .ts-rail-nav__link {
170
172
  border-radius: var(--ts-radius-md);
173
+ box-sizing: border-box;
171
174
  display: flex;
172
175
  font-weight: 650;
173
176
  justify-content: space-between;
174
- padding: 0.55rem 0.55rem;
177
+ min-height: 1.7rem;
178
+ padding: 0.24rem 0.55rem;
175
179
  }
176
180
 
177
181
  .ts-rail-nav__link[aria-current='page'],
@@ -43,7 +43,9 @@
43
43
 
44
44
  .ts-control {
45
45
  appearance: none;
46
- background-color: var(--ts-color-surface);
46
+ -webkit-appearance: none;
47
+ -moz-appearance: none;
48
+ background: var(--ts-control-background, var(--ts-color-surface));
47
49
  border: 1px solid var(--ts-color-border);
48
50
  border-radius: var(--ts-radius-md);
49
51
  color: var(--ts-color-text);
@@ -78,11 +80,13 @@
78
80
  .ts-control--select,
79
81
  select.ts-control {
80
82
  appearance: none;
81
- background-color: var(--ts-color-surface);
82
- background-image:
83
+ -webkit-appearance: none;
84
+ -moz-appearance: none;
85
+ background:
83
86
  linear-gradient(var(--ts-color-border), var(--ts-color-border)),
84
87
  linear-gradient(45deg, transparent 50%, currentColor 50%),
85
- linear-gradient(135deg, currentColor 50%, transparent 50%);
88
+ linear-gradient(135deg, currentColor 50%, transparent 50%),
89
+ var(--ts-control-background, var(--ts-color-surface));
86
90
  background-position:
87
91
  calc(100% - 2rem) 50%,
88
92
  calc(100% - 1.17rem) calc(50% - 0.08rem),
@@ -95,6 +99,12 @@ select.ts-control {
95
99
  padding-right: 2.5rem;
96
100
  }
97
101
 
102
+ .ts-control--select option,
103
+ select.ts-control option {
104
+ background-color: var(--ts-control-background, var(--ts-color-surface));
105
+ color: var(--ts-color-text);
106
+ }
107
+
98
108
  .ts-control--textarea {
99
109
  min-height: 7rem;
100
110
  resize: vertical;
@@ -120,11 +120,13 @@ body {
120
120
 
121
121
  .ts-theme-selector__field select {
122
122
  appearance: none;
123
- background-color: var(--ts-color-surface);
124
- background-image:
123
+ -webkit-appearance: none;
124
+ -moz-appearance: none;
125
+ background:
125
126
  linear-gradient(var(--ts-color-border), var(--ts-color-border)),
126
127
  linear-gradient(45deg, transparent 50%, currentColor 50%),
127
- linear-gradient(135deg, currentColor 50%, transparent 50%);
128
+ linear-gradient(135deg, currentColor 50%, transparent 50%),
129
+ var(--ts-control-background, var(--ts-color-surface));
128
130
  background-position:
129
131
  calc(100% - 1.7rem) 50%,
130
132
  calc(100% - 1rem) calc(50% - 0.08rem),
@@ -151,6 +153,11 @@ body {
151
153
  outline-offset: 2px;
152
154
  }
153
155
 
156
+ .ts-theme-selector__field select option {
157
+ background-color: var(--ts-control-background, var(--ts-color-surface));
158
+ color: var(--ts-color-text);
159
+ }
160
+
154
161
  .ts-theme-swatch {
155
162
  display: inline-grid;
156
163
  grid-template-columns: repeat(4, 0.85rem);
@@ -9,6 +9,7 @@
9
9
  --ts-color-surface-muted: #e8efe1;
10
10
  --ts-color-surface-raised: #fafcf7;
11
11
  --ts-color-surface-overlay: rgba(255, 255, 255, 0.88);
12
+ --ts-control-background: var(--ts-color-surface);
12
13
 
13
14
  --ts-color-text: #1f2a20;
14
15
  --ts-color-text-muted: #51604d;
package/dist/templates.js CHANGED
@@ -129,18 +129,23 @@ async function listSiteTemplates(context = {}) {
129
129
  };
130
130
  }
131
131
  const catalogItems = context.catalogProvider && typeof context.catalogProvider.listItems === "function" ? await context.catalogProvider.listItems({ locals: context.locals }) : [];
132
- if (catalogItems.length > 0) {
133
- return {
134
- rendered: true,
135
- items: sortTemplateCards(catalogItems.map(cardFromCatalogItem))
136
- };
132
+ const localEntries = await listLocalTemplateEntries(context.listLocalEntries);
133
+ const cardsBySlug = /* @__PURE__ */ new Map();
134
+ for (const entry of localEntries) {
135
+ const card = contentCardFromEntry(entry);
136
+ if (card) {
137
+ cardsBySlug.set(card.slug, card);
138
+ }
139
+ }
140
+ for (const item of catalogItems) {
141
+ const card = cardFromCatalogItem(item);
142
+ if (!cardsBySlug.has(card.slug)) {
143
+ cardsBySlug.set(card.slug, card);
144
+ }
137
145
  }
138
- const entries = await listLocalTemplateEntries(context.listLocalEntries);
139
146
  return {
140
147
  rendered: true,
141
- items: sortTemplateCards(
142
- entries.map(contentCardFromEntry).filter((entry) => Boolean(entry))
143
- )
148
+ items: sortTemplateCards([...cardsBySlug.values()])
144
149
  };
145
150
  }
146
151
  async function resolveSiteTemplate(slug, context = {}) {
@@ -150,18 +155,18 @@ async function resolveSiteTemplate(slug, context = {}) {
150
155
  item: null
151
156
  };
152
157
  }
153
- const catalogItem = await selectCatalogItemBySlug(slug, context);
154
- if (catalogItem) {
158
+ const entries = await listLocalTemplateEntries(context.listLocalEntries);
159
+ const entry = entries.find((candidate) => candidate.data.slug === slug && candidate.data.status === "live") ?? null;
160
+ if (entry) {
155
161
  return {
156
162
  rendered: true,
157
- item: detailFromCatalogItem(catalogItem)
163
+ item: detailFromContentEntry(entry)
158
164
  };
159
165
  }
160
- const entries = await listLocalTemplateEntries(context.listLocalEntries);
161
- const entry = entries.find((candidate) => candidate.data.slug === slug && candidate.data.status === "live") ?? null;
166
+ const catalogItem = await selectCatalogItemBySlug(slug, context);
162
167
  return {
163
168
  rendered: true,
164
- item: entry ? detailFromContentEntry(entry) : null
169
+ item: catalogItem ? detailFromCatalogItem(catalogItem) : null
165
170
  };
166
171
  }
167
172
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/core",
3
- "version": "0.10.16",
3
+ "version": "0.10.18",
4
4
  "description": "Treeseed web framework package for Astro/Starlight site runtimes.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -70,7 +70,7 @@
70
70
  "@astrojs/sitemap": "3.7.0",
71
71
  "@astrojs/starlight": "0.37.6",
72
72
  "@tailwindcss/vite": "^4.1.4",
73
- "@treeseed/sdk": "github:treeseed-ai/sdk#0.10.22",
73
+ "@treeseed/sdk": "github:treeseed-ai/sdk#0.10.24",
74
74
  "astro": "^5.6.1",
75
75
  "esbuild": "^0.28.0",
76
76
  "katex": "^0.16.22",
@@ -108,7 +108,11 @@ __WORKING_DIRECTORY_BLOCK__ web:
108
108
  shell: bash
109
109
  run: |
110
110
  set -euo pipefail
111
+ TIMING_SUMMARY="${RUNNER_TEMP:-/tmp}/treeseed-provider-timing.md"
112
+ : > "${TIMING_SUMMARY}"
113
+ export TREESEED_PROVIDER_TIMING_SUMMARY_PATH="${TIMING_SUMMARY}"
111
114
  EXTRA_ARGS=()
112
115
  if [[ -n "${TREESEED_WORKFLOW_PROJECT:-}" ]]; then EXTRA_ARGS+=(--project-id "${TREESEED_WORKFLOW_PROJECT}"); fi
113
116
  if [[ -n "${TREESEED_WORKFLOW_PREVIEW_ID:-}" ]]; then EXTRA_ARGS+=(--preview-id "${TREESEED_WORKFLOW_PREVIEW_ID}"); fi
114
117
  node ./packages/sdk/scripts/run-ts.mjs ./packages/sdk/scripts/tenant-workflow-action.ts --action "${TREESEED_WORKFLOW_ACTION}" --environment "${TREESEED_WORKFLOW_ENVIRONMENT}" "${EXTRA_ARGS[@]}"
118
+ if [[ -n "${GITHUB_STEP_SUMMARY:-}" && -s "${TIMING_SUMMARY}" ]]; then cat "${TIMING_SUMMARY}" >> "${GITHUB_STEP_SUMMARY}"; fi