stack-site-builder 1.19.5 → 1.21.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/CHANGELOG.md +20 -0
- package/README.md +1 -0
- package/index.mjs +12 -0
- package/package.json +1 -1
- package/src/components/DefaultFooter.astro +26 -0
- package/src/layouts/BaseLayout.astro +26 -18
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,26 @@ content schema, while a consuming site supplies only content, taxonomy data and
|
|
|
11
11
|
config. Sites track the theme with `pnpm up stack-site-builder`, so each release
|
|
12
12
|
here is a plain version bump they pull in.
|
|
13
13
|
|
|
14
|
+
## [1.21.0] - 2026-07-24
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Header brand options** — `site.header = { logo, logoInvert, name }`:
|
|
19
|
+
`logo` (a public/ path) replaces the hardcoded ⚡ bolt with the site's
|
|
20
|
+
mark, `name: false` drops the wordmark for a logo-only brand (the home
|
|
21
|
+
link keeps `site.name` as its aria-label), and `logoInvert` flips a
|
|
22
|
+
black line-art logo in dark mode. Defaults unchanged: ⚡ + site name.
|
|
23
|
+
|
|
24
|
+
## [1.20.0] - 2026-07-24
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **Per-site custom footer** — footers are site identity, not theme chrome.
|
|
29
|
+
A site that ships `src/components/Footer.astro` (receiving a `lang` prop)
|
|
30
|
+
now replaces the theme's stock footer wholesale; without one, the stock
|
|
31
|
+
"Built with Astro" footer renders as before (now living in
|
|
32
|
+
`DefaultFooter.astro`, resolved through the `@aas-footer` alias).
|
|
33
|
+
|
|
14
34
|
## [1.19.5] - 2026-07-24
|
|
15
35
|
|
|
16
36
|
### Added
|
package/README.md
CHANGED
|
@@ -43,6 +43,7 @@ export const collections = defineAasCollections({ categoryMap });
|
|
|
43
43
|
| `src/content/{stacks,concepts,courses,products,papers,articles,slides}/` | The content, one MDX file per locale |
|
|
44
44
|
| `src/content/pages/` | Standalone top-level pages (e.g. an About/소개), rendered at `/<slug>/` and optionally linked in the header nav |
|
|
45
45
|
| `public/` · `samples/` | Logos/favicons and runnable sample projects |
|
|
46
|
+
| `src/components/Footer.astro` (optional) | Replaces the theme's stock footer wholesale — receives a `lang` prop |
|
|
46
47
|
|
|
47
48
|
The theme reaches the site's data through the `@aas-data/*` alias (set up by
|
|
48
49
|
the integration), so everything above is swappable per site.
|
package/index.mjs
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
// components resolve per-site taxonomy (categories, glossary, site identity)
|
|
16
16
|
// at build time.
|
|
17
17
|
import { fileURLToPath } from 'node:url';
|
|
18
|
+
import { existsSync } from 'node:fs';
|
|
18
19
|
import mdx from '@astrojs/mdx';
|
|
19
20
|
import sitemap from '@astrojs/sitemap';
|
|
20
21
|
import tailwindcss from '@tailwindcss/vite';
|
|
@@ -175,6 +176,17 @@ export default function aasTheme({ glossary, sections = {} }) {
|
|
|
175
176
|
alias: {
|
|
176
177
|
'@aas-data': fileURLToPath(new URL('./src/data', config.root)),
|
|
177
178
|
'@assets': fileURLToPath(new URL('./src/assets', config.root)),
|
|
179
|
+
// Footers are site identity, not theme chrome: when the site
|
|
180
|
+
// ships `src/components/Footer.astro`, BaseLayout renders it
|
|
181
|
+
// (via this alias) instead of the theme's stock footer.
|
|
182
|
+
'@aas-footer': (() => {
|
|
183
|
+
const siteFooter = fileURLToPath(
|
|
184
|
+
new URL('./src/components/Footer.astro', config.root),
|
|
185
|
+
);
|
|
186
|
+
return existsSync(siteFooter)
|
|
187
|
+
? siteFooter
|
|
188
|
+
: fileURLToPath(new URL('./src/components/DefaultFooter.astro', import.meta.url));
|
|
189
|
+
})(),
|
|
178
190
|
},
|
|
179
191
|
},
|
|
180
192
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stack-site-builder",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.21.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "The engine behind the awesome-*-stack catalog sites: an Astro theme with the catalog/concepts/articles/slides/samples routes, components, styles and markdown pipeline. Sites provide content, taxonomy data and config.",
|
|
7
7
|
"repository": {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
// The theme's stock footer. A site replaces it wholesale by shipping its own
|
|
3
|
+
// `src/components/Footer.astro` — the integration aliases `@aas-footer` to
|
|
4
|
+
// that file when it exists (this one otherwise), so BaseLayout needs no
|
|
5
|
+
// site-specific knowledge. A custom footer receives the same `lang` prop.
|
|
6
|
+
import { useTranslations, type Lang } from '../i18n/ui';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
lang: Lang;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { lang } = Astro.props;
|
|
13
|
+
const t = useTranslations(lang);
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<footer class="border-t border-[var(--aas-border)] py-8 text-center text-sm text-[var(--aas-muted)]">
|
|
17
|
+
<p>
|
|
18
|
+
{t('footer.builtWith')}
|
|
19
|
+
<a
|
|
20
|
+
href="https://astro.build"
|
|
21
|
+
target="_blank"
|
|
22
|
+
rel="noopener noreferrer"
|
|
23
|
+
class="text-[var(--aas-accent)]">Astro</a
|
|
24
|
+
>. {t('footer.contribute')}
|
|
25
|
+
</p>
|
|
26
|
+
</footer>
|
|
@@ -6,6 +6,10 @@ import { useTranslations, languages, type Lang } from '../i18n/ui';
|
|
|
6
6
|
import LanguageSwitcher from '../components/LanguageSwitcher.astro';
|
|
7
7
|
import ThemeToggle from '../components/ThemeToggle.astro';
|
|
8
8
|
import BackToTop from '../components/BackToTop.astro';
|
|
9
|
+
// Resolved by the integration: the site's src/components/Footer.astro when it
|
|
10
|
+
// exists, the theme's DefaultFooter otherwise.
|
|
11
|
+
// @ts-expect-error -- virtual alias, no static types
|
|
12
|
+
import Footer from '@aas-footer';
|
|
9
13
|
import { getNavPages, pageSlugOf } from '../lib/pages';
|
|
10
14
|
import { getNavProducts, getTopProducts, productSlugOf } from '../lib/products';
|
|
11
15
|
import { homeTemplate } from '../lib/home';
|
|
@@ -49,6 +53,14 @@ const base = import.meta.env.BASE_URL;
|
|
|
49
53
|
|
|
50
54
|
const baseNoSlash = base.replace(/\/$/, '');
|
|
51
55
|
|
|
56
|
+
// Header brand: `site.header = { logo?: '/path.png', logoInvert?: bool,
|
|
57
|
+
// name?: bool }`. A logo replaces the ⚡ bolt; `name: false` drops the
|
|
58
|
+
// wordmark (logo-only brand — the link keeps site.name as its aria-label).
|
|
59
|
+
const header = (site as { header?: { logo?: string; logoInvert?: boolean; name?: boolean } })
|
|
60
|
+
.header;
|
|
61
|
+
const brandLogo = header?.logo;
|
|
62
|
+
const brandName = header?.name !== false;
|
|
63
|
+
|
|
52
64
|
// Home URL per locale, for the language auto-detect redirect on the root home.
|
|
53
65
|
const localeHomes = Object.fromEntries(
|
|
54
66
|
(Object.keys(languages) as Lang[]).map((c) => [c, getRelativeLocaleUrl(c, '')]),
|
|
@@ -262,9 +274,19 @@ const navItems = allNavItems.filter((item) => !item.section || sectionEnabled(it
|
|
|
262
274
|
aria-label={site.name}
|
|
263
275
|
class="flex min-w-0 items-center gap-1.5 text-base font-bold tracking-tight whitespace-nowrap no-underline sm:text-lg"
|
|
264
276
|
>
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
277
|
+
{
|
|
278
|
+
brandLogo ? (
|
|
279
|
+
<img
|
|
280
|
+
src={`${baseNoSlash}${brandLogo}`}
|
|
281
|
+
alt=""
|
|
282
|
+
class:list={['h-7 w-7 shrink-0 object-contain', header?.logoInvert && 'aas-icon-invert']}
|
|
283
|
+
/>
|
|
284
|
+
) : (
|
|
285
|
+
<span aria-hidden="true">⚡</span>
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
{/* Below 600px only the mark remains, so the narrow header never truncates the wordmark. */}
|
|
289
|
+
{brandName && <span class="hidden truncate min-[600px]:inline">{site.name}</span>}
|
|
268
290
|
</a>
|
|
269
291
|
{/* Section links are icon-only (labels live in aria-label). On phones
|
|
270
292
|
(<sm) they collapse into the labelled dropdown menu below, so the
|
|
@@ -378,21 +400,7 @@ const navItems = allNavItems.filter((item) => !item.section || sectionEnabled(it
|
|
|
378
400
|
<slot />
|
|
379
401
|
</main>
|
|
380
402
|
|
|
381
|
-
<
|
|
382
|
-
class="border-t border-[var(--aas-border)] py-8 text-center text-sm text-[var(--aas-muted)]"
|
|
383
|
-
>
|
|
384
|
-
<p>
|
|
385
|
-
{t('footer.builtWith')}
|
|
386
|
-
<a
|
|
387
|
-
href="https://astro.build"
|
|
388
|
-
target="_blank"
|
|
389
|
-
rel="noopener noreferrer"
|
|
390
|
-
class="text-[var(--aas-accent)]">Astro</a
|
|
391
|
-
>. {
|
|
392
|
-
t('footer.contribute')
|
|
393
|
-
}
|
|
394
|
-
</p>
|
|
395
|
-
</footer>
|
|
403
|
+
<Footer lang={lang} />
|
|
396
404
|
|
|
397
405
|
<BackToTop lang={lang} />
|
|
398
406
|
|