@karaoke-cms/astro 0.9.2 → 0.9.3

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@karaoke-cms/astro",
3
3
  "type": "module",
4
- "version": "0.9.2",
4
+ "version": "0.9.3",
5
5
  "description": "Core Astro integration for karaoke-cms — virtual config, wikilinks, handbook routes",
6
6
  "main": "./src/index.ts",
7
7
  "exports": {
@@ -10,8 +10,10 @@
10
10
  "./collections": "./src/collections.ts",
11
11
  "./env": "./src/utils/load-env.ts",
12
12
  "./layouts/Base.astro": "./src/layouts/Base.astro",
13
+ "./layouts/DefaultPage.astro": "./src/layouts/DefaultPage.astro",
13
14
  "./consts": "./src/consts.ts",
14
15
  "./components/ModuleLoader.astro": "./src/components/ModuleLoader.astro",
16
+ "./components/regions/SiteFooter.astro": "./src/components/regions/SiteFooter.astro",
15
17
  "./pages/rss.xml.ts": "./src/pages/rss.xml.ts",
16
18
  "./pages/karaoke-cms/index.astro": "./src/pages/karaoke-cms/index.astro",
17
19
  "./pages/karaoke-cms/[...slug].astro": "./src/pages/karaoke-cms/[...slug].astro"
@@ -43,4 +45,4 @@
43
45
  "scripts": {
44
46
  "test": "vitest run test/validate-config.test.js test/theme-loading.test.js test/resolve-modules.test.js test/resolve-layout.test.js test/resolve-collections.test.js test/collections.test.js test/load-env.test.js test/resolve-menus.test.js test/define-module.test.js test/define-theme.test.js"
45
47
  }
46
- }
48
+ }
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  import Menu from '../Menu.astro';
3
3
  import { siteTitle } from 'virtual:karaoke-cms/config';
4
+ import pkg from '../../../package.json';
4
5
  ---
5
6
  <div class="footer-grid">
6
7
  <div class="footer-col">
@@ -17,5 +18,5 @@ import { siteTitle } from 'virtual:karaoke-cms/config';
17
18
  </div>
18
19
  <div class="footer-below">
19
20
  <span>&copy; {new Date().getFullYear()} {siteTitle}</span>
20
- <span class="footer-attr">Built with <a href="https://karaoke-cms.org">karaoke-cms</a></span>
21
+ <span class="footer-attr">Built with <a href="https://karaoke-cms.org">karaoke-cms</a> v{pkg.version}</span>
21
22
  </div>
@@ -1,4 +1,6 @@
1
1
  ---
2
- import { SITE_TITLE } from '../../consts';
2
+ import { siteTitle } from 'virtual:karaoke-cms/config';
3
3
  ---
4
- <a href="/" class="site-name">{SITE_TITLE}</a>
4
+ <a href="/" class="site-name">
5
+ <span class="site-icon" aria-hidden="true">🎤</span>{siteTitle}
6
+ </a>
@@ -1,22 +1,18 @@
1
1
  ---
2
- import '@theme/styles.css';
3
- import RegionRenderer from '../components/RegionRenderer.astro';
4
- import { siteTitle, resolvedModules, resolvedLayout } from 'virtual:karaoke-cms/config';
2
+ import { siteTitle } from 'virtual:karaoke-cms/config';
5
3
 
6
4
  interface Props {
7
- title: string;
5
+ title: string;
8
6
  description?: string;
9
- type?: 'website' | 'article';
7
+ type?: 'website' | 'article';
10
8
  }
11
9
 
12
10
  const { title, description, type = 'website' } = Astro.props;
13
11
  const canonicalUrl = Astro.url.href;
14
- const layout = resolvedLayout;
15
- const modules = resolvedModules;
16
- const searchEnabled = modules.search.enabled;
17
12
 
18
- const hasLeft = Astro.slots.has('left') || layout.regions.left.components.length > 0;
19
- const hasRight = Astro.slots.has('right') || layout.regions.right.components.length > 0;
13
+ const pageTitle = title === siteTitle
14
+ ? `🎤 ${title}`
15
+ : `${title} — 🎤 ${siteTitle}`;
20
16
  ---
21
17
 
22
18
  <!doctype html>
@@ -27,7 +23,7 @@ const hasRight = Astro.slots.has('right') || layout.regions.right.components.len
27
23
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
28
24
  <link rel="icon" href="/favicon.ico" />
29
25
  <meta name="generator" content={Astro.generator} />
30
- <title>{title === siteTitle ? title : `${title} — ${siteTitle}`}</title>
26
+ <title>{pageTitle}</title>
31
27
  {description && <meta name="description" content={description} />}
32
28
  <meta property="og:title" content={title} />
33
29
  <meta property="og:type" content={type} />
@@ -35,40 +31,9 @@ const hasRight = Astro.slots.has('right') || layout.regions.right.components.len
35
31
  {description && <meta property="og:description" content={description} />}
36
32
  <meta name="twitter:card" content="summary" />
37
33
  <link rel="alternate" type="application/rss+xml" title={siteTitle} href="/rss.xml" />
34
+ <slot name="head" />
38
35
  </head>
39
36
  <body>
40
- <header>
41
- <div class="header-inner">
42
- <slot name="top">
43
- <RegionRenderer components={layout.regions.top.components} {searchEnabled} />
44
- </slot>
45
- </div>
46
- </header>
47
- <div class:list={['page-body', { 'has-left': hasLeft, 'has-right': hasRight }]}>
48
- {hasLeft && (
49
- <aside class="region-left">
50
- <slot name="left">
51
- <RegionRenderer components={layout.regions.left.components} {searchEnabled} />
52
- </slot>
53
- </aside>
54
- )}
55
- <main>
56
- <slot />
57
- </main>
58
- {hasRight && (
59
- <aside class="region-right">
60
- <slot name="right">
61
- <RegionRenderer components={layout.regions.right.components} {searchEnabled} />
62
- </slot>
63
- </aside>
64
- )}
65
- </div>
66
- <footer>
67
- <div class="footer-inner">
68
- <slot name="bottom">
69
- <RegionRenderer components={layout.regions.bottom.components} {searchEnabled} />
70
- </slot>
71
- </div>
72
- </footer>
37
+ <slot />
73
38
  </body>
74
39
  </html>
@@ -0,0 +1,76 @@
1
+ ---
2
+ import '@theme/styles.css';
3
+ import Base from './Base.astro';
4
+ import RegionRenderer from '../components/RegionRenderer.astro';
5
+ import { resolvedModules, resolvedLayout } from 'virtual:karaoke-cms/config';
6
+
7
+ interface Props {
8
+ title: string;
9
+ description?: string;
10
+ type?: 'website' | 'article';
11
+ /** Landing pages get a full-width <main> with no sidebar regions. */
12
+ variant?: 'default' | 'landing';
13
+ }
14
+
15
+ const { title, description, type = 'website', variant = 'default' } = Astro.props;
16
+ const layout = resolvedLayout;
17
+ const modules = resolvedModules;
18
+ const searchEnabled = modules.search.enabled;
19
+
20
+ const isLanding = variant === 'landing';
21
+
22
+ const hasHero = !isLanding && Astro.slots.has('hero');
23
+ const hasLeft = !isLanding && (Astro.slots.has('left') || layout.regions.left.components.length > 0);
24
+ const hasRight = !isLanding && (Astro.slots.has('right') || layout.regions.right.components.length > 0);
25
+ ---
26
+
27
+ <Base {title} {description} {type}>
28
+ <header>
29
+ <div class="header-inner">
30
+ <slot name="top">
31
+ <RegionRenderer components={layout.regions.top.components} {searchEnabled} />
32
+ </slot>
33
+ <slot name="header-cta" />
34
+ </div>
35
+ </header>
36
+
37
+ {hasHero && (
38
+ <div class="hero-region">
39
+ <slot name="hero" />
40
+ </div>
41
+ )}
42
+
43
+ {isLanding ? (
44
+ <main class="landing-main">
45
+ <slot />
46
+ </main>
47
+ ) : (
48
+ <div class:list={['page-body', { 'has-left': hasLeft, 'has-right': hasRight }]}>
49
+ {hasLeft && (
50
+ <aside class="region-left">
51
+ <slot name="left">
52
+ <RegionRenderer components={layout.regions.left.components} {searchEnabled} />
53
+ </slot>
54
+ </aside>
55
+ )}
56
+ <main>
57
+ <slot />
58
+ </main>
59
+ {hasRight && (
60
+ <aside class="region-right">
61
+ <slot name="right">
62
+ <RegionRenderer components={layout.regions.right.components} {searchEnabled} />
63
+ </slot>
64
+ </aside>
65
+ )}
66
+ </div>
67
+ )}
68
+
69
+ <footer>
70
+ <div class="footer-inner">
71
+ <slot name="bottom">
72
+ <RegionRenderer components={layout.regions.bottom.components} {searchEnabled} />
73
+ </slot>
74
+ </div>
75
+ </footer>
76
+ </Base>
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  import { getCollection, render } from 'astro:content';
3
- import Base from '../../layouts/Base.astro';
3
+ import DefaultPage from '../../layouts/DefaultPage.astro';
4
4
  import { SITE_TITLE } from '../../consts';
5
5
 
6
6
  // Handbook is dev-only — this route is never injected in production.
@@ -16,7 +16,7 @@ const { entry } = Astro.props;
16
16
  const { Content } = await render(entry);
17
17
  ---
18
18
 
19
- <Base title={`${entry.data.title} — ${SITE_TITLE}`} description={entry.data.description}>
19
+ <DefaultPage title={`${entry.data.title} — ${SITE_TITLE}`} description={entry.data.description}>
20
20
  <article>
21
21
  <div class="post-header">
22
22
  <span class="handbook-badge">Handbook — dev only</span>
@@ -29,7 +29,7 @@ const { Content } = await render(entry);
29
29
  <a href="/karaoke-cms">← Handbook</a>
30
30
  </div>
31
31
  </article>
32
- </Base>
32
+ </DefaultPage>
33
33
 
34
34
  <style>
35
35
  .handbook-badge {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  import { getCollection } from 'astro:content';
3
- import Base from '../../layouts/Base.astro';
3
+ import DefaultPage from '../../layouts/DefaultPage.astro';
4
4
  import { SITE_TITLE } from '../../consts';
5
5
 
6
6
  // Handbook is dev-only — this route is never injected in production.
@@ -9,7 +9,7 @@ const entries = (await getCollection('karaoke-cms'))
9
9
  .sort((a, b) => (a.data.title ?? '').localeCompare(b.data.title ?? ''));
10
10
  ---
11
11
 
12
- <Base title={`Handbook — ${SITE_TITLE}`}>
12
+ <DefaultPage title={`Handbook — ${SITE_TITLE}`}>
13
13
  <div class="listing-header">
14
14
  <h1>Handbook</h1>
15
15
  <p class="handbook-badge">dev only</p>
@@ -28,7 +28,7 @@ const entries = (await getCollection('karaoke-cms'))
28
28
  <p>Add Markdown files to <code>content/karaoke-cms/</code> in your vault.</p>
29
29
  </div>
30
30
  )}
31
- </Base>
31
+ </DefaultPage>
32
32
 
33
33
  <style>
34
34
  .handbook-badge {