@gradial/aci 0.1.20-preview.2 → 0.1.20
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/README.md +48 -110
- package/bin/{aci → aci-darwin-arm64} +0 -0
- package/bin/aci.js +99 -6
- package/dist/assets/index.d.ts +3 -3
- package/dist/assets/index.js +3 -3
- package/dist/astro/index.d.ts +14 -3
- package/dist/astro/index.js +24 -5
- package/dist/content/assets.d.ts +17 -0
- package/dist/content/assets.js +65 -0
- package/dist/content/index.d.ts +2 -0
- package/dist/content/index.js +2 -0
- package/dist/content/provider.d.ts +19 -0
- package/dist/content/provider.js +7 -0
- package/dist/content/resolve-slots.d.ts +9 -0
- package/dist/content/resolve-slots.js +24 -0
- package/dist/content/types.d.ts +1 -1
- package/dist/define-component.d.ts +1 -2
- package/dist/define-component.js +73 -11
- package/dist/define-layout.d.ts +2 -0
- package/dist/define-layout.js +3 -0
- package/dist/dev/content-watch.d.ts +37 -0
- package/dist/dev/content-watch.js +154 -0
- package/dist/dev/index.d.ts +24 -43
- package/dist/dev/index.js +4 -169
- package/dist/index.d.ts +14 -5
- package/dist/index.js +8 -8
- package/dist/next/asset-route.d.ts +2 -0
- package/dist/next/asset-route.js +12 -4
- package/dist/next/config.d.ts +2 -2
- package/dist/next/config.js +6 -6
- package/dist/next/content-watch.js +6 -1
- package/dist/next/index.d.ts +2 -2
- package/dist/next/index.js +2 -2
- package/dist/next/middleware.d.ts +7 -3
- package/dist/next/middleware.js +12 -7
- package/dist/next/page.d.ts +16 -15
- package/dist/next/page.js +30 -10
- package/dist/next/render.d.ts +5 -0
- package/dist/next/render.js +17 -0
- package/dist/next/root-layout.d.ts +4 -0
- package/dist/next/root-layout.js +5 -0
- package/dist/next/server.d.ts +14 -13
- package/dist/next/server.js +13 -3
- package/dist/providers/file.d.ts +2 -0
- package/dist/providers/file.js +61 -1
- package/dist/providers/s3.d.ts +1 -0
- package/dist/providers/s3.js +14 -1
- package/dist/react/Media.d.ts +24 -0
- package/dist/react/Media.js +30 -0
- package/dist/react/Picture.d.ts +12 -0
- package/dist/react/Picture.js +11 -0
- package/dist/react/VideoPlayer.d.ts +13 -0
- package/dist/react/{GradialVideoPlayer.js → VideoPlayer.js} +6 -5
- package/dist/react/index.d.ts +333 -3
- package/dist/react/index.js +89 -3
- package/dist/registry.d.ts +15 -0
- package/dist/registry.js +10 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.js +15 -2
- package/dist/types/block-ref.d.ts +26 -0
- package/dist/types/block-ref.js +28 -0
- package/dist/types/component.d.ts +36 -41
- package/dist/types/config.d.ts +1 -2
- package/dist/types/image.d.ts +33 -20
- package/dist/types/image.js +42 -50
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/link.d.ts +38 -0
- package/dist/types/link.js +58 -0
- package/dist/types/media.d.ts +16 -35
- package/dist/types/media.js +15 -84
- package/dist/types/page.d.ts +1 -2
- package/dist/types/render-mode.d.ts +0 -1
- package/dist/types/renderer.d.ts +1 -1
- package/dist/types/rich-text.d.ts +40 -0
- package/dist/types/rich-text.js +39 -0
- package/dist/types/video.d.ts +7 -13
- package/dist/types/video.js +3 -3
- package/package.json +32 -74
- package/src/cli/compile-registry.mjs +236 -59
- package/src/cli/validate-content.mjs +38 -75
- package/src/types/image.ts +79 -60
- package/templates/astro/template/.aci.yaml +27 -0
- package/templates/astro/template/.storybook/main.ts +79 -0
- package/templates/astro/template/.storybook/manager.ts +6 -0
- package/templates/astro/template/.storybook/preview.ts +33 -0
- package/templates/astro/template/astro.config.mjs +37 -0
- package/templates/astro/template/package.json.tmpl +41 -0
- package/templates/astro/template/src/cms/contracts/layouts/index.ts +18 -0
- package/templates/astro/template/src/cms/registry.ts +28 -0
- package/templates/astro/template/src/components/chrome/Footer.astro +107 -0
- package/templates/astro/template/src/components/chrome/Header.astro +94 -0
- package/templates/astro/template/src/components/elements/AtomicBlock.astro +15 -0
- package/templates/astro/template/src/components/elements/AtomicBlocks.astro +16 -0
- package/templates/astro/template/src/components/elements/Button.astro +51 -0
- package/templates/astro/template/src/components/elements/ButtonBlock.astro +25 -0
- package/templates/astro/template/src/components/elements/Container.astro +11 -0
- package/templates/astro/template/src/components/elements/Icon.astro +31 -0
- package/templates/astro/template/src/components/elements/Logo.astro +29 -0
- package/templates/astro/template/src/components/elements/RemoteImage.astro +41 -0
- package/templates/astro/template/src/components/sections/ContainerSection.astro +32 -0
- package/templates/astro/template/src/components/sections/FeatureCard.astro +23 -0
- package/templates/astro/template/src/components/sections/FeatureGrid.astro +35 -0
- package/templates/astro/template/src/components/sections/HomeHero.astro +51 -0
- package/templates/astro/template/src/components/sections/StatsBar.astro +33 -0
- package/templates/astro/template/src/design-system/styles.css +399 -0
- package/templates/astro/template/src/design-system/tokens/colors.css +60 -0
- package/templates/astro/template/src/design-system/tokens/components.css +69 -0
- package/templates/astro/template/src/design-system/tokens/index.css +6 -0
- package/templates/astro/template/src/design-system/tokens/radii.css +5 -0
- package/templates/astro/template/src/design-system/tokens/shadows.css +5 -0
- package/templates/astro/template/src/design-system/tokens/spacing.css +13 -0
- package/templates/astro/template/src/design-system/tokens/typography.css +24 -0
- package/templates/astro/template/src/env.d.ts +1 -0
- package/templates/astro/template/src/fixtures/atomicBlocks.ts +33 -0
- package/templates/astro/template/src/fixtures/composition.ts +31 -0
- package/templates/astro/template/src/fixtures/index.ts +17 -0
- package/templates/astro/template/src/fixtures/sections.ts +39 -0
- package/templates/astro/template/src/layouts/SiteLayout.astro +30 -0
- package/templates/astro/template/src/pages/[...slug].astro +61 -0
- package/templates/astro/template/src/render/RenderPage.astro +66 -0
- package/templates/astro/template/src/stories/CompositionStoryFrame.astro +15 -0
- package/templates/astro/template/src/stories/HomeHero.stories.ts +24 -0
- package/templates/astro/template/src/stories/SectionStoryFrame.astro +16 -0
- package/templates/astro/template/src/stories/StoryDocFrame.astro +31 -0
- package/templates/astro/template/tsconfig.json +11 -0
- package/templates/common/.agents/AGENTS.md +37 -0
- package/templates/common/.agents/skills/aci/SKILL.md +162 -0
- package/templates/common/.agents/skills/authoring/SKILL.md +590 -0
- package/templates/common/.agents/skills/authoring/references/block-registry.md +151 -0
- package/templates/common/.agents/skills/authoring/references/contracts.md +153 -0
- package/templates/common/.agents/skills/authoring/references/design-system.md +171 -0
- package/templates/common/.agents/skills/authoring/references/image-assets.md +73 -0
- package/templates/common/.agents/skills/authoring/references/repo-structure.md +157 -0
- package/templates/common/.agents/skills/migration/SKILL.md +160 -0
- package/templates/common/.agents/skills/migration/references/analyzing-source.md +215 -0
- package/templates/common/.agents/skills/migration/references/component-migration.md +200 -0
- package/templates/common/.agents/skills/migration/references/selector-map.md +31 -0
- package/templates/common/.content/.gradial-dam/blobs/sha256/7f/bf/7fbfc7fe230ff12688c496f660119e41d9725c4504d82e310c15665c73c09292 +0 -0
- package/templates/common/.content/.gradial-dam/blobs/sha256/a0/f5/a0f506689de9b15a7055f70103a3f02cd3ba105771ae2de6754df2ede1210d3a +0 -0
- package/templates/common/.content/.gradial-dam/blobs/sha256/dd/b7/ddb7e9642be08317bcd4b2bd26b58ba8d0d34dd7239e03e684a4f3634fa3845b +0 -0
- package/templates/common/.content/.gradial-dam/blobs/sha256/fb/32/fb3260e8286ea8231ea1c77b9c0be92d6edd9026565731eb14cfdcfd6b1b75b3 +0 -0
- package/templates/common/.content/config/site.json +192 -0
- package/templates/common/.content/dam/folders/seed/ast_site_about_hero/asset.json +9 -0
- package/templates/common/.content/dam/folders/seed/ast_site_about_hero/editorial.json +14 -0
- package/templates/common/.content/dam/folders/seed/ast_site_about_hero/governance.json +23 -0
- package/templates/common/.content/dam/folders/seed/ast_site_about_hero/versions/v0001.json +37 -0
- package/templates/common/.content/dam/folders/seed/ast_site_home_hero/asset.json +9 -0
- package/templates/common/.content/dam/folders/seed/ast_site_home_hero/editorial.json +14 -0
- package/templates/common/.content/dam/folders/seed/ast_site_home_hero/governance.json +23 -0
- package/templates/common/.content/dam/folders/seed/ast_site_home_hero/versions/v0001.json +37 -0
- package/templates/common/.content/fragments/navbar/_index.json +25 -0
- package/templates/common/.content/fragments/site-footer/_index.json +62 -0
- package/templates/common/.content/pages/about/_index.json +51 -0
- package/templates/common/.content/pages/home/_index.json +112 -0
- package/templates/common/.content/schemas/site.schema.json +123 -0
- package/templates/common/README.md.tmpl +45 -0
- package/templates/common/contracts/components/button.contract.ts +19 -0
- package/templates/common/contracts/components/container.contract.ts +19 -0
- package/templates/common/contracts/components/featureCard.contract.ts +15 -0
- package/templates/common/contracts/components/featureGrid.contract.ts +16 -0
- package/templates/common/contracts/components/homeHero.contract.ts +36 -0
- package/templates/common/contracts/components/index.ts +21 -0
- package/templates/common/contracts/components/siteFooter.contract.ts +45 -0
- package/templates/common/contracts/components/siteNavigation.contract.ts +30 -0
- package/templates/common/contracts/components/statsBar.contract.ts +19 -0
- package/templates/common/design-system/styles.css +346 -0
- package/templates/common/design-system/tokens/colors.css +110 -0
- package/templates/common/design-system/tokens/components.css +86 -0
- package/templates/common/design-system/tokens/index.css +6 -0
- package/templates/common/design-system/tokens/radii.css +5 -0
- package/templates/common/design-system/tokens/shadows.css +9 -0
- package/templates/common/design-system/tokens/spacing.css +26 -0
- package/templates/common/design-system/tokens/typography.css +32 -0
- package/templates/common/eslint-rules/no-raw-tailwind-values.js +127 -0
- package/templates/common/public/assets/Dwire-model.png +0 -0
- package/templates/common/public/assets/bare-metal-logo.png +0 -0
- package/templates/common/public/assets/meridian-logo.svg +8 -0
- package/templates/common/public/assets/seattle.avif +0 -0
- package/templates/nextjs/template/.aci.yaml +25 -0
- package/templates/nextjs/template/.storybook/main.ts +13 -0
- package/templates/nextjs/template/.storybook/preview.ts +34 -0
- package/templates/nextjs/template/eslint.config.mjs +36 -0
- package/templates/nextjs/template/next-env.d.ts +6 -0
- package/templates/nextjs/template/next.config.ts +8 -0
- package/templates/nextjs/template/package.json.tmpl +46 -0
- package/templates/nextjs/template/postcss.config.mjs +7 -0
- package/templates/nextjs/template/src/app/[[...slug]]/page.tsx +8 -0
- package/templates/nextjs/template/src/app/gradial/assets/[releaseId]/[...path]/route.ts +31 -0
- package/templates/nextjs/template/src/app/layout.tsx +29 -0
- package/templates/nextjs/template/src/cms/contracts/components/button.contract.ts +19 -0
- package/templates/nextjs/template/src/cms/contracts/components/container.contract.ts +20 -0
- package/templates/nextjs/template/src/cms/contracts/components/homeHero.contract.ts +36 -0
- package/templates/nextjs/template/src/cms/contracts/components/index.ts +15 -0
- package/templates/nextjs/template/src/cms/contracts/components/siteFooter.contract.ts +45 -0
- package/templates/nextjs/template/src/cms/contracts/components/siteNavigation.contract.ts +30 -0
- package/templates/nextjs/template/src/cms/contracts/layouts/index.ts +16 -0
- package/templates/nextjs/template/src/cms/registry.ts +28 -0
- package/templates/nextjs/template/src/components/chrome/Footer.tsx +86 -0
- package/templates/nextjs/template/src/components/chrome/Header.tsx +74 -0
- package/templates/nextjs/template/src/components/elements/AtomicBlock.tsx +13 -0
- package/templates/nextjs/template/src/components/elements/Button.tsx +40 -0
- package/templates/nextjs/template/src/components/elements/ButtonBlock.tsx +18 -0
- package/templates/nextjs/template/src/components/elements/Container.tsx +14 -0
- package/templates/nextjs/template/src/components/elements/Icon.tsx +29 -0
- package/templates/nextjs/template/src/components/elements/Logo.tsx +38 -0
- package/templates/nextjs/template/src/components/sections/ContainerSection.tsx +28 -0
- package/templates/nextjs/template/src/components/sections/FeatureCard.tsx +25 -0
- package/templates/nextjs/template/src/components/sections/FeatureGrid.tsx +36 -0
- package/templates/nextjs/template/src/components/sections/HomeHero.tsx +62 -0
- package/templates/nextjs/template/src/components/sections/StatsBar.tsx +30 -0
- package/templates/nextjs/template/src/middleware.ts +4 -0
- package/templates/nextjs/template/src/stories/Button.stories.tsx +38 -0
- package/templates/nextjs/template/src/stories/Header.stories.tsx +30 -0
- package/templates/nextjs/template/src/stories/HomeHero.stories.tsx +33 -0
- package/templates/nextjs/template/tsconfig.json +23 -0
- package/templates/nextjs/template/vercel.json +6 -0
- package/dist/content/cache.test.d.ts +0 -1
- package/dist/content/cache.test.js +0 -86
- package/dist/content/contract.d.ts +0 -83
- package/dist/content/contract.js +0 -104
- package/dist/content/tailwind-validator.d.ts +0 -6
- package/dist/content/tailwind-validator.js +0 -31
- package/dist/content/validation.d.ts +0 -108
- package/dist/content/validation.js +0 -184
- package/dist/next/preview-banner.d.ts +0 -4
- package/dist/next/preview-banner.js +0 -51
- package/dist/next/preview.d.ts +0 -7
- package/dist/next/preview.js +0 -37
- package/dist/react/GradialMedia.d.ts +0 -24
- package/dist/react/GradialMedia.js +0 -31
- package/dist/react/GradialPicture.d.ts +0 -14
- package/dist/react/GradialPicture.js +0 -30
- package/dist/react/GradialVideoPlayer.d.ts +0 -13
- package/dist/sveltekit/index.d.ts +0 -23
- package/dist/sveltekit/index.js +0 -62
- package/dist/sveltekit/preview.d.ts +0 -5
- package/dist/sveltekit/preview.js +0 -33
- package/src/cli/verify-renderer.mjs +0 -73
- package/src/types/component.ts +0 -59
- package/src/types/config.ts +0 -38
- package/src/types/data.ts +0 -47
- package/src/types/index.ts +0 -10
- package/src/types/layout.ts +0 -29
- package/src/types/media.ts +0 -125
- package/src/types/page.ts +0 -48
- package/src/types/render-mode.ts +0 -18
- package/src/types/renderer.ts +0 -83
- package/src/types/video.ts +0 -66
package/src/types/image.ts
CHANGED
|
@@ -1,28 +1,47 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Image source variant (responsive derivative)
|
|
5
|
+
//
|
|
6
|
+
// Each entry is one concrete derivative produced by the compiler for the asset
|
|
7
|
+
// slot. Renderers pick the primary variant and build a srcset from the list.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
3
10
|
export interface ImageSource {
|
|
11
|
+
/** Derivative URL. */
|
|
4
12
|
src: string;
|
|
13
|
+
/** Intrinsic width in pixels. */
|
|
5
14
|
width: number;
|
|
15
|
+
/** Intrinsic height in pixels. */
|
|
6
16
|
height: number;
|
|
17
|
+
/** MIME type hint, e.g. image/webp. */
|
|
7
18
|
type: string;
|
|
8
19
|
}
|
|
9
20
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Image — DAM-backed image asset with compiler-resolved derivatives
|
|
23
|
+
//
|
|
24
|
+
// Content authors write an asset reference: { "$type": "dam.assetRef", ... }
|
|
25
|
+
// The compiler resolves it to this Image value based on the asset's media type.
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
16
27
|
|
|
17
|
-
export interface
|
|
28
|
+
export interface Image {
|
|
29
|
+
/** Discriminator — always 'gradial.image'. */
|
|
18
30
|
$type: 'gradial.image';
|
|
31
|
+
/** DAM asset identifier. */
|
|
19
32
|
assetId: string;
|
|
33
|
+
/** DAM version identifier. */
|
|
20
34
|
versionId: string;
|
|
35
|
+
/** Accessible description of the image content. */
|
|
21
36
|
alt: string;
|
|
22
|
-
|
|
23
|
-
sources:
|
|
37
|
+
/** Responsive derivative variants produced for the asset slot. */
|
|
38
|
+
sources: ImageSource[];
|
|
24
39
|
}
|
|
25
40
|
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Image slot contract (declared by components that accept image props)
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
26
45
|
export interface ImageSlotContract {
|
|
27
46
|
outputs: SlotOutput[];
|
|
28
47
|
formats: string[];
|
|
@@ -35,66 +54,66 @@ export interface SlotOutput {
|
|
|
35
54
|
media?: string;
|
|
36
55
|
}
|
|
37
56
|
|
|
38
|
-
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Zod schema
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
export const ImageSourceSchema = z.object({
|
|
62
|
+
src: z.string().min(1),
|
|
63
|
+
width: z.number().int().nonnegative(),
|
|
64
|
+
height: z.number().int().nonnegative(),
|
|
65
|
+
type: z.string().min(1),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export const ImageSchema = z.object({
|
|
39
69
|
$type: z.literal('gradial.image'),
|
|
40
70
|
assetId: z.string().min(1),
|
|
41
71
|
versionId: z.string().min(1),
|
|
42
72
|
alt: z.string(),
|
|
43
|
-
|
|
44
|
-
src: z.string().min(1),
|
|
45
|
-
width: z.number().int().nonnegative(),
|
|
46
|
-
height: z.number().int().nonnegative(),
|
|
47
|
-
type: z.string().min(1),
|
|
48
|
-
}),
|
|
49
|
-
sources: z.array(z.object({
|
|
50
|
-
media: z.string().optional(),
|
|
51
|
-
type: z.string().min(1),
|
|
52
|
-
srcset: z.string().min(1),
|
|
53
|
-
sizes: z.string().optional(),
|
|
54
|
-
})).nullable().default([]),
|
|
73
|
+
sources: z.array(ImageSourceSchema).min(1),
|
|
55
74
|
});
|
|
56
75
|
|
|
57
|
-
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Shared attrs helper — consumed by React, Astro, and Svelte components
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
58
79
|
|
|
59
|
-
export
|
|
60
|
-
const imgAttrs = renderAttrs({
|
|
61
|
-
...attrs,
|
|
62
|
-
src: image.fallback.src,
|
|
63
|
-
alt: image.alt,
|
|
64
|
-
width: image.fallback.width > 0 ? image.fallback.width : undefined,
|
|
65
|
-
height: image.fallback.height > 0 ? image.fallback.height : undefined,
|
|
66
|
-
});
|
|
67
|
-
const img = `<img${imgAttrs}>`;
|
|
68
|
-
if (!image.sources?.length) {
|
|
69
|
-
return img;
|
|
70
|
-
}
|
|
71
|
-
const sources = image.sources.map((source) => `<source${renderAttrs({
|
|
72
|
-
media: source.media,
|
|
73
|
-
type: source.type,
|
|
74
|
-
srcset: source.srcset,
|
|
75
|
-
sizes: source.sizes,
|
|
76
|
-
})}>`).join('');
|
|
77
|
-
return `<picture>${sources}${img}</picture>`;
|
|
78
|
-
}
|
|
80
|
+
export type ImageAttrs = Record<string, unknown>;
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Picks the primary variant from an image's sources.
|
|
84
|
+
* Uses the largest width; ties fall back to the first entry.
|
|
85
|
+
*/
|
|
86
|
+
export function primaryImageSource(image: Image): ImageSource {
|
|
87
|
+
return image.sources.reduce((largest, source) =>
|
|
88
|
+
source.width > largest.width ? source : largest,
|
|
89
|
+
image.sources[0],
|
|
90
|
+
);
|
|
88
91
|
}
|
|
89
92
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Computes the full set of <img> attributes for an Image.
|
|
95
|
+
*
|
|
96
|
+
* Framework components (React <Picture>, Astro <img>, Svelte <img>) call this
|
|
97
|
+
* and spread the result into their native element. No HTML string serialization.
|
|
98
|
+
*/
|
|
99
|
+
export function imageAttrs(image: Image, overrides: ImageAttrs = {}): ImageAttrs {
|
|
100
|
+
const primary = primaryImageSource(image);
|
|
101
|
+
const srcset = image.sources
|
|
102
|
+
.map((s) => `${s.src} ${s.width}w`)
|
|
103
|
+
.join(', ');
|
|
104
|
+
const sizes = image.sources
|
|
105
|
+
.map((s) => `(max-width: ${s.width}px) ${s.width}px`)
|
|
106
|
+
.join(', ');
|
|
93
107
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
.
|
|
97
|
-
.
|
|
98
|
-
.
|
|
99
|
-
|
|
108
|
+
return {
|
|
109
|
+
src: primary.src,
|
|
110
|
+
alt: image.alt,
|
|
111
|
+
width: primary.width > 0 ? primary.width : undefined,
|
|
112
|
+
height: primary.height > 0 ? primary.height : undefined,
|
|
113
|
+
srcSet: srcset || undefined,
|
|
114
|
+
sizes: sizes || undefined,
|
|
115
|
+
loading: 'lazy',
|
|
116
|
+
decoding: 'async',
|
|
117
|
+
...overrides,
|
|
118
|
+
};
|
|
100
119
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
version: "1"
|
|
2
|
+
siteId: "site_astro"
|
|
3
|
+
framework: astro
|
|
4
|
+
|
|
5
|
+
source:
|
|
6
|
+
root: "./"
|
|
7
|
+
outDir: "dist"
|
|
8
|
+
publicDir: "public"
|
|
9
|
+
|
|
10
|
+
componentRegistry: ./src/cms/contracts/components/index.ts
|
|
11
|
+
layoutRegistry: ./src/cms/contracts/layouts/index.ts
|
|
12
|
+
|
|
13
|
+
capabilities:
|
|
14
|
+
staticRender: true
|
|
15
|
+
ssr: true
|
|
16
|
+
ssrIslands: true
|
|
17
|
+
clientIslands: true
|
|
18
|
+
fragmentRender: true
|
|
19
|
+
|
|
20
|
+
routes:
|
|
21
|
+
cmsManaged: "/[...slug]"
|
|
22
|
+
frameworkOwned:
|
|
23
|
+
- "/api/*"
|
|
24
|
+
- "/_astro/*"
|
|
25
|
+
- "/storybook/*"
|
|
26
|
+
|
|
27
|
+
rendererProtocol: stdio-json
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { dirname, resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import tailwindcss from '@tailwindcss/postcss';
|
|
4
|
+
|
|
5
|
+
const sharedRoot = fileURLToPath(new URL('../src', import.meta.url));
|
|
6
|
+
|
|
7
|
+
function withSharedAlias(alias: any) {
|
|
8
|
+
if (Array.isArray(alias)) {
|
|
9
|
+
return [...alias, { find: '@shared', replacement: sharedRoot }];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
...alias,
|
|
14
|
+
'@shared': sharedRoot
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const config = {
|
|
19
|
+
stories: ['../src/**/*.stories.@(ts|mdx)'],
|
|
20
|
+
addons: ['@storybook/addon-docs'],
|
|
21
|
+
framework: {
|
|
22
|
+
name: '@storybook-astro/framework',
|
|
23
|
+
options: {}
|
|
24
|
+
},
|
|
25
|
+
core: {
|
|
26
|
+
builder: '@storybook/builder-vite'
|
|
27
|
+
},
|
|
28
|
+
staticDirs: ['../public'],
|
|
29
|
+
viteFinal: async (config: any) => {
|
|
30
|
+
const astroComponentPaths = new Set<string>();
|
|
31
|
+
const buildServerPlugin = config.plugins?.flat().find(
|
|
32
|
+
(p: any) => p?.name === 'storybook-astro:build-server'
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (buildServerPlugin) {
|
|
36
|
+
const origWriteBundle = buildServerPlugin.writeBundle;
|
|
37
|
+
buildServerPlugin.writeBundle = async function(this: any, ...args: any[]) {
|
|
38
|
+
for (const componentPath of astroComponentPaths) {
|
|
39
|
+
buildServerPlugin.resolveId?.call(
|
|
40
|
+
this,
|
|
41
|
+
componentPath,
|
|
42
|
+
componentPath
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return origWriteBundle?.apply(this, args);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
config.plugins = [
|
|
50
|
+
{
|
|
51
|
+
name: 'storybook-astro:resolve-compat',
|
|
52
|
+
enforce: 'pre' as const,
|
|
53
|
+
resolveId(id: string, importer: string | undefined) {
|
|
54
|
+
if (id?.endsWith('.astro') && importer) {
|
|
55
|
+
astroComponentPaths.add(resolve(dirname(importer), id));
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
...config.plugins
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
...config,
|
|
65
|
+
resolve: {
|
|
66
|
+
...config.resolve,
|
|
67
|
+
alias: withSharedAlias(config.resolve?.alias)
|
|
68
|
+
},
|
|
69
|
+
css: {
|
|
70
|
+
...config.css,
|
|
71
|
+
postcss: {
|
|
72
|
+
plugins: [tailwindcss()]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export default config;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import '../src/design-system/styles.css';
|
|
2
|
+
|
|
3
|
+
const preview = {
|
|
4
|
+
globalTypes: {
|
|
5
|
+
theme: {
|
|
6
|
+
description: 'Theme for components',
|
|
7
|
+
toolbar: {
|
|
8
|
+
title: 'Theme',
|
|
9
|
+
icon: 'sun',
|
|
10
|
+
items: ['light', 'dark'],
|
|
11
|
+
dynamicTitle: true
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
decorators: [
|
|
16
|
+
(storyFn: any, context: any) => {
|
|
17
|
+
const theme = context.globals.theme || 'light';
|
|
18
|
+
document.body.setAttribute('data-visual-root', '');
|
|
19
|
+
document.body.className = `theme-${theme} min-h-screen bg-[var(--color-surface-default)]`;
|
|
20
|
+
return storyFn();
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
parameters: {
|
|
24
|
+
layout: 'fullscreen',
|
|
25
|
+
options: {
|
|
26
|
+
storySort: {
|
|
27
|
+
order: ['Core Atomic Blocks', 'Composition', '*']
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default preview;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { defineConfig } from 'astro/config';
|
|
3
|
+
import node from '@astrojs/node';
|
|
4
|
+
import tailwindcss from '@tailwindcss/postcss';
|
|
5
|
+
import { withAci } from '@gradial/aci/astro';
|
|
6
|
+
|
|
7
|
+
const pageRuntimeBuild = process.env.ACI_CODE_ARTIFACT_BUILD === '1';
|
|
8
|
+
const rawBasePath = String(process.env.ACI_SITE_BASE_PATH || '').trim().replace(/\/+$/g, '');
|
|
9
|
+
const base = rawBasePath
|
|
10
|
+
? rawBasePath.startsWith('/') ? rawBasePath : `/${rawBasePath}`
|
|
11
|
+
: '/';
|
|
12
|
+
const rawOutDir = String(process.env.ACI_ASTRO_OUT_DIR || '').trim();
|
|
13
|
+
const rawCacheDir = String(process.env.ACI_ASTRO_CACHE_DIR || '').trim();
|
|
14
|
+
const outDir = rawOutDir
|
|
15
|
+
? (path.isAbsolute(rawOutDir) ? rawOutDir : `./${rawOutDir}`)
|
|
16
|
+
: 'dist';
|
|
17
|
+
|
|
18
|
+
export default defineConfig({
|
|
19
|
+
adapter: pageRuntimeBuild ? node({ mode: 'middleware' }) : undefined,
|
|
20
|
+
integrations: [withAci()],
|
|
21
|
+
srcDir: './src',
|
|
22
|
+
outDir,
|
|
23
|
+
cacheDir: rawCacheDir
|
|
24
|
+
? (path.isAbsolute(rawCacheDir) ? rawCacheDir : `./${rawCacheDir}`)
|
|
25
|
+
: undefined,
|
|
26
|
+
output: pageRuntimeBuild ? 'server' : 'static',
|
|
27
|
+
trailingSlash: 'always',
|
|
28
|
+
base,
|
|
29
|
+
devToolbar: { enabled: false },
|
|
30
|
+
vite: {
|
|
31
|
+
css: {
|
|
32
|
+
postcss: {
|
|
33
|
+
plugins: [tailwindcss()],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{siteName}}",
|
|
3
|
+
"version": "{{version}}",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "astro dev --host 0.0.0.0",
|
|
8
|
+
"build": "astro build",
|
|
9
|
+
"preview": "ACI_CONTENT_ROOT=./.aci/compiled astro preview --host 0.0.0.0",
|
|
10
|
+
"typecheck": "ACI_CONTENT_ROOT=./.aci/compiled astro check --tsconfig ./tsconfig.json",
|
|
11
|
+
"aci:compile": "node ./node_modules/@gradial/aci/bin/aci.js build --compile-only",
|
|
12
|
+
"content:compile": "node ./node_modules/@gradial/aci/bin/aci.js build --skip-code --content ./.content --out ./.aci/compiled",
|
|
13
|
+
"aci:build": "node ./node_modules/@gradial/aci/bin/aci.js build --content ./.content",
|
|
14
|
+
"aci:doctor": "node ./node_modules/@gradial/aci/bin/aci.js doctor",
|
|
15
|
+
"aci:validate": "node ./node_modules/@gradial/aci/bin/aci.js build --validate-only",
|
|
16
|
+
"storybook": "storybook dev -p 6006",
|
|
17
|
+
"build:storybook": "storybook build"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@gradial/aci": "^0.1.20",
|
|
21
|
+
"js-yaml": "^4.1.0",
|
|
22
|
+
"marked": "^18.0.3",
|
|
23
|
+
"zod": "^4.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@astrojs/check": "^0.9.8",
|
|
27
|
+
"@astrojs/node": "^10.1.4",
|
|
28
|
+
"@tailwindcss/postcss": "^4.2.4",
|
|
29
|
+
"@types/js-yaml": "^4.0.9",
|
|
30
|
+
"@types/node": "^25.8.0",
|
|
31
|
+
"astro": "^6.1.9",
|
|
32
|
+
"tailwindcss": "^4.2.4",
|
|
33
|
+
"tsx": "^4.20.0",
|
|
34
|
+
"typescript": "5.9.3",
|
|
35
|
+
"vite": "^7.2.7",
|
|
36
|
+
"storybook": "^10.0.0",
|
|
37
|
+
"@storybook-astro/framework": "^1.6.0",
|
|
38
|
+
"@storybook/addon-docs": "^10.0.0",
|
|
39
|
+
"@storybook/builder-vite": "^10.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineLayoutContract, slot, fragmentDefault } from '@gradial/aci';
|
|
2
|
+
|
|
3
|
+
const layoutContracts = [
|
|
4
|
+
defineLayoutContract({
|
|
5
|
+
name: 'default',
|
|
6
|
+
slots: [
|
|
7
|
+
slot('header', false),
|
|
8
|
+
slot('main', true),
|
|
9
|
+
slot('footer', false),
|
|
10
|
+
],
|
|
11
|
+
defaults: {
|
|
12
|
+
header: [fragmentDefault('navbar')],
|
|
13
|
+
footer: [fragmentDefault('site-footer')],
|
|
14
|
+
},
|
|
15
|
+
}),
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export default layoutContracts;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createRegistry } from '@gradial/aci';
|
|
2
|
+
import { homeHeroContract } from './contracts/components/homeHero.contract';
|
|
3
|
+
import { containerContract } from './contracts/components/container.contract';
|
|
4
|
+
import { buttonContract } from './contracts/components/button.contract';
|
|
5
|
+
import { siteNavigationContract } from './contracts/components/siteNavigation.contract';
|
|
6
|
+
import { siteFooterContract } from './contracts/components/siteFooter.contract';
|
|
7
|
+
import { featureGridContract } from './contracts/components/featureGrid.contract';
|
|
8
|
+
import { featureCardContract } from './contracts/components/featureCard.contract';
|
|
9
|
+
import { statsBarContract } from './contracts/components/statsBar.contract';
|
|
10
|
+
import HomeHero from '../components/sections/HomeHero.astro';
|
|
11
|
+
import ContainerSection from '../components/sections/ContainerSection.astro';
|
|
12
|
+
import ButtonBlock from '../components/elements/ButtonBlock.astro';
|
|
13
|
+
import Header from '../components/chrome/Header.astro';
|
|
14
|
+
import Footer from '../components/chrome/Footer.astro';
|
|
15
|
+
import FeatureGrid from '../components/sections/FeatureGrid.astro';
|
|
16
|
+
import FeatureCard from '../components/sections/FeatureCard.astro';
|
|
17
|
+
import StatsBar from '../components/sections/StatsBar.astro';
|
|
18
|
+
|
|
19
|
+
export const registry = createRegistry([
|
|
20
|
+
[homeHeroContract, HomeHero],
|
|
21
|
+
[containerContract, ContainerSection],
|
|
22
|
+
[buttonContract, ButtonBlock],
|
|
23
|
+
[siteNavigationContract, Header],
|
|
24
|
+
[siteFooterContract, Footer],
|
|
25
|
+
[featureGridContract, FeatureGrid],
|
|
26
|
+
[featureCardContract, FeatureCard],
|
|
27
|
+
[statsBarContract, StatsBar],
|
|
28
|
+
]);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Container from '../elements/Container.astro';
|
|
3
|
+
import Logo from '../elements/Logo.astro';
|
|
4
|
+
|
|
5
|
+
interface FooterLink {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
href: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface FooterGroup {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
links: FooterLink[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface FooterColumn {
|
|
18
|
+
id: string;
|
|
19
|
+
title?: string;
|
|
20
|
+
groups?: FooterGroup[];
|
|
21
|
+
links?: FooterLink[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface Props {
|
|
25
|
+
brandHref: string;
|
|
26
|
+
brandLabel?: string;
|
|
27
|
+
brandLogo?: { src: string; alt?: string } | null;
|
|
28
|
+
social?: Array<FooterLink & { icon?: string }>;
|
|
29
|
+
columns?: FooterColumn[];
|
|
30
|
+
legalLinks?: FooterLink[];
|
|
31
|
+
copyright?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const {
|
|
35
|
+
brandHref,
|
|
36
|
+
brandLabel = 'Gradial',
|
|
37
|
+
brandLogo = null,
|
|
38
|
+
social = [],
|
|
39
|
+
columns = [],
|
|
40
|
+
legalLinks = [],
|
|
41
|
+
copyright = ''
|
|
42
|
+
} = Astro.props;
|
|
43
|
+
|
|
44
|
+
function columnGroups(column: FooterColumn): FooterGroup[] {
|
|
45
|
+
if (column.groups?.length) {
|
|
46
|
+
return column.groups;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return [{
|
|
50
|
+
id: column.id,
|
|
51
|
+
title: column.title || '',
|
|
52
|
+
links: column.links || []
|
|
53
|
+
}];
|
|
54
|
+
}
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
<footer class="bm-footer [font-family:var(--font-family-base)] text-fg" id="footer">
|
|
58
|
+
<Container className="py-[var(--spacing-footer-y)]">
|
|
59
|
+
<div class="grid gap-12 pb-24 md:grid-cols-[var(--footer-grid-columns)] lg:gap-24">
|
|
60
|
+
<a href={brandHref} class="self-start">
|
|
61
|
+
<Logo
|
|
62
|
+
label={brandLabel}
|
|
63
|
+
src={brandLogo?.src || ''}
|
|
64
|
+
alt={brandLogo?.alt || brandLabel}
|
|
65
|
+
className="w-[var(--width-logo-footer-mobile)] md:w-[var(--width-logo-footer)]"
|
|
66
|
+
/>
|
|
67
|
+
</a>
|
|
68
|
+
<div class="grid gap-10 sm:grid-cols-2 lg:grid-cols-4">
|
|
69
|
+
{columns.map((column) => (
|
|
70
|
+
<div class="space-y-10">
|
|
71
|
+
{columnGroups(column).map((group) => (
|
|
72
|
+
<section class="space-y-5" aria-label={group.title}>
|
|
73
|
+
<h2 class="text-[length:var(--text-size-body-small)] font-[var(--font-weight-semibold)] text-fg-muted">{group.title}</h2>
|
|
74
|
+
<ul class="space-y-4 text-[length:var(--text-size-body-small)] font-[var(--font-weight-semibold)] leading-body text-fg">
|
|
75
|
+
{group.links.map((link) => (
|
|
76
|
+
<li><a class="transition hover:text-link-hover" href={link.href}>{link.label}</a></li>
|
|
77
|
+
))}
|
|
78
|
+
</ul>
|
|
79
|
+
</section>
|
|
80
|
+
))}
|
|
81
|
+
</div>
|
|
82
|
+
))}
|
|
83
|
+
<section class="space-y-5" aria-label="Social">
|
|
84
|
+
<h2 class="text-[length:var(--text-size-body-small)] font-[var(--font-weight-semibold)] text-fg-muted">Social</h2>
|
|
85
|
+
<ul class="space-y-4 text-[length:var(--text-size-body-small)] font-[var(--font-weight-semibold)] text-fg">
|
|
86
|
+
{social.map((item) => (
|
|
87
|
+
<li>
|
|
88
|
+
<a class="inline-flex items-center gap-2 transition hover:text-link-hover" href={item.href}>
|
|
89
|
+
<span class="min-w-5 text-[length:var(--text-size-caption)] text-fg-muted">{item.icon || item.label.slice(0, 1)}</span>
|
|
90
|
+
<span>{item.label}</span>
|
|
91
|
+
</a>
|
|
92
|
+
</li>
|
|
93
|
+
))}
|
|
94
|
+
</ul>
|
|
95
|
+
</section>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
<div class="flex flex-col gap-6 border-t border-edge pt-8 text-[length:var(--text-size-caption)] font-[var(--font-weight-semibold)] text-fg-muted md:flex-row md:items-center md:justify-between">
|
|
99
|
+
<ul class="flex flex-wrap gap-x-9 gap-y-3 text-fg">
|
|
100
|
+
{legalLinks.map((link) => (
|
|
101
|
+
<li><a class="transition hover:text-link-hover" href={link.href}>{link.label}</a></li>
|
|
102
|
+
))}
|
|
103
|
+
</ul>
|
|
104
|
+
<p>{copyright}</p>
|
|
105
|
+
</div>
|
|
106
|
+
</Container>
|
|
107
|
+
</footer>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Button from '../elements/Button.astro';
|
|
3
|
+
import Container from '../elements/Container.astro';
|
|
4
|
+
import Icon from '../elements/Icon.astro';
|
|
5
|
+
import Logo from '../elements/Logo.astro';
|
|
6
|
+
|
|
7
|
+
interface NavItem {
|
|
8
|
+
id: string;
|
|
9
|
+
label: string;
|
|
10
|
+
href: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface UtilityItem extends NavItem {
|
|
14
|
+
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
brandHref: string;
|
|
19
|
+
brandLabel?: string;
|
|
20
|
+
brandLogo?: { src: string; alt?: string } | null;
|
|
21
|
+
navigation?: NavItem[];
|
|
22
|
+
utilities?: UtilityItem[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
brandHref,
|
|
27
|
+
brandLabel = 'Gradial',
|
|
28
|
+
brandLogo = null,
|
|
29
|
+
navigation = [],
|
|
30
|
+
utilities = []
|
|
31
|
+
} = Astro.props;
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
<header class="bm-header sticky top-0 z-[var(--z-header)] [font-family:var(--font-family-base)] text-fg">
|
|
35
|
+
<a
|
|
36
|
+
href="#content-main"
|
|
37
|
+
class="sr-only focus:not-sr-only focus:absolute focus:left-4 focus:top-4 focus:z-10 focus:rounded-button focus:bg-white focus:px-4 focus:py-2 focus:text-black"
|
|
38
|
+
>
|
|
39
|
+
Skip to main content
|
|
40
|
+
</a>
|
|
41
|
+
<Container className="flex min-h-[var(--height-header)] items-center justify-between gap-4">
|
|
42
|
+
<a href={brandHref} class="shrink-0">
|
|
43
|
+
<Logo label={brandLabel} src={brandLogo?.src || ''} alt={brandLogo?.alt || brandLabel} />
|
|
44
|
+
</a>
|
|
45
|
+
<nav class="hidden items-center gap-9 text-[length:var(--text-size-body-small)] font-[var(--font-weight-semibold)] text-fg-muted lg:flex" aria-label="Primary">
|
|
46
|
+
{navigation.map((item) => (
|
|
47
|
+
<a class="transition hover:text-link-hover" href={item.href}>{item.label}</a>
|
|
48
|
+
))}
|
|
49
|
+
</nav>
|
|
50
|
+
<div class="flex shrink-0 items-center gap-3">
|
|
51
|
+
<div class="hidden items-center gap-3 sm:flex">
|
|
52
|
+
{utilities.map((item) => (
|
|
53
|
+
<Button href={item.href} variant={item.variant || 'outline'}>{item.label}</Button>
|
|
54
|
+
))}
|
|
55
|
+
</div>
|
|
56
|
+
<div class="lg:hidden">
|
|
57
|
+
<input id="site-mobile-nav" class="peer sr-only" type="checkbox" />
|
|
58
|
+
<label
|
|
59
|
+
for="site-mobile-nav"
|
|
60
|
+
class="inline-grid size-11 cursor-pointer place-items-center rounded-button border border-edge text-fg transition hover:text-link-hover"
|
|
61
|
+
aria-label="Open main navigation"
|
|
62
|
+
>
|
|
63
|
+
<Icon name="menu" className="size-6" />
|
|
64
|
+
</label>
|
|
65
|
+
<div class="bm-mobile-nav pointer-events-none fixed inset-0 z-[var(--z-overlay)] flex translate-x-full flex-col px-[var(--spacing-container)] py-5 text-fg opacity-0 transition duration-300 ease-out peer-checked:pointer-events-auto peer-checked:translate-x-0 peer-checked:opacity-100">
|
|
66
|
+
<div class="flex min-h-[var(--height-header)] items-center justify-between gap-4">
|
|
67
|
+
<a href={brandHref} class="shrink-0">
|
|
68
|
+
<Logo label={brandLabel} src={brandLogo?.src || ''} alt={brandLogo?.alt || brandLabel} />
|
|
69
|
+
</a>
|
|
70
|
+
<label
|
|
71
|
+
for="site-mobile-nav"
|
|
72
|
+
class="inline-grid size-11 cursor-pointer place-items-center rounded-button border border-edge text-fg transition hover:text-link-hover"
|
|
73
|
+
aria-label="Close main navigation"
|
|
74
|
+
>
|
|
75
|
+
<Icon name="close" className="size-6" />
|
|
76
|
+
</label>
|
|
77
|
+
</div>
|
|
78
|
+
<nav class="grid flex-1 content-center gap-4 py-10 font-[var(--font-weight-bold)] text-[length:var(--mobile-nav-link-size)] leading-[var(--mobile-nav-link-line-height)] text-fg" aria-label="Mobile main navigation">
|
|
79
|
+
{navigation.map((item) => (
|
|
80
|
+
<a class="transition hover:text-link-hover" href={item.href}>{item.label}</a>
|
|
81
|
+
))}
|
|
82
|
+
</nav>
|
|
83
|
+
{utilities.length ? (
|
|
84
|
+
<div class="grid gap-3 border-t border-edge pt-5 sm:hidden">
|
|
85
|
+
{utilities.map((item) => (
|
|
86
|
+
<Button href={item.href} variant={item.variant || 'outline'} className="w-full">{item.label}</Button>
|
|
87
|
+
))}
|
|
88
|
+
</div>
|
|
89
|
+
) : null}
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</Container>
|
|
94
|
+
</header>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { KernelAtomicBlock } from '@gradial/aci/content';
|
|
3
|
+
import ButtonBlock from './ButtonBlock.astro';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
block: KernelAtomicBlock;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { block } = Astro.props;
|
|
10
|
+
const props = (block.props || {}) as any;
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
{block.component === 'button' ? (
|
|
14
|
+
<ButtonBlock {...props} />
|
|
15
|
+
) : null}
|