@gradial/aci 0.1.27 → 0.1.29
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 +47 -0
- package/bin/aci-darwin-arm64 +0 -0
- package/dist/assets/index.d.ts +1 -1
- package/dist/astro/index.d.ts +1 -0
- package/dist/astro/index.js +7 -0
- package/dist/collect/api.d.ts +24 -0
- package/dist/collect/api.js +63 -0
- package/dist/collect/batcher.d.ts +65 -0
- package/dist/collect/batcher.js +127 -0
- package/dist/collect/config.d.ts +30 -0
- package/dist/collect/config.js +53 -0
- package/dist/collect/consent/adapters/c15t.d.ts +2 -0
- package/dist/collect/consent/adapters/c15t.js +43 -0
- package/dist/collect/consent/adapters/cookiebot.d.ts +2 -0
- package/dist/collect/consent/adapters/cookiebot.js +48 -0
- package/dist/collect/consent/adapters/onetrust.d.ts +2 -0
- package/dist/collect/consent/adapters/onetrust.js +54 -0
- package/dist/collect/consent/adapters/trustarc.d.ts +2 -0
- package/dist/collect/consent/adapters/trustarc.js +65 -0
- package/dist/collect/consent/envelope.d.ts +49 -0
- package/dist/collect/consent/envelope.js +100 -0
- package/dist/collect/consent/mapping.d.ts +62 -0
- package/dist/collect/consent/mapping.js +129 -0
- package/dist/collect/declarative.d.ts +35 -0
- package/dist/collect/declarative.js +100 -0
- package/dist/collect/gapbuffer.d.ts +55 -0
- package/dist/collect/gapbuffer.js +134 -0
- package/dist/collect/index.d.ts +6 -0
- package/dist/collect/index.js +154 -0
- package/dist/collect/linkclicks.d.ts +12 -0
- package/dist/collect/linkclicks.js +35 -0
- package/dist/collect/pageviews.d.ts +22 -0
- package/dist/collect/pageviews.js +42 -0
- package/dist/collect/transport.d.ts +22 -0
- package/dist/collect/transport.js +52 -0
- package/dist/collect/ulid.d.ts +6 -0
- package/dist/collect/ulid.js +36 -0
- package/dist/collect/variationviews.d.ts +31 -0
- package/dist/collect/variationviews.js +80 -0
- package/dist/collect/webvitals.d.ts +38 -0
- package/dist/collect/webvitals.js +99 -0
- package/dist/content/index.d.ts +1 -0
- package/dist/content/index.js +1 -0
- package/dist/content/personalization.d.ts +57 -0
- package/dist/content/personalization.js +54 -0
- package/dist/content/types.d.ts +3 -0
- package/dist/index.d.ts +1 -1
- package/dist/next/asset-route.js +16 -3
- package/dist/next/collect-script.d.ts +12 -0
- package/dist/next/collect-script.js +15 -0
- package/dist/next/config.js +1 -0
- package/dist/next/index.d.ts +3 -0
- package/dist/next/index.js +3 -0
- package/dist/next/page.d.ts +2 -0
- package/dist/next/page.js +5 -2
- package/dist/react/VideoPlayer.d.ts +3 -3
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +2 -1
- package/dist/types/data.d.ts +2 -0
- package/dist/types/image.d.ts +37 -11
- package/dist/types/image.js +20 -17
- package/dist/types/media.d.ts +14 -2
- package/dist/types/page.d.ts +2 -0
- package/dist/types/video.d.ts +7 -1
- package/package.json +6 -1
- package/src/types/data.ts +3 -0
- package/src/types/image.ts +44 -29
- package/src/types/page.ts +2 -0
- package/templates/astro/template/package.json.tmpl +1 -1
- package/templates/astro/template/src/fixtures/sections.ts +2 -1
- package/templates/astro/template/src/layouts/SiteLayout.astro +77 -1
- package/templates/astro/template/src/pages/[...slug].astro +3 -2
- package/templates/common/.agents/AGENTS.md +5 -0
- package/templates/common/.agents/skills/authoring/SKILL.md +31 -0
- package/templates/common/.agents/skills/authoring/references/asset-rendering.md +110 -0
- package/templates/common/.agents/skills/authoring/references/block-slots.md +140 -0
- package/templates/common/.agents/skills/authoring/references/rich-text.md +75 -0
- package/templates/common/.agents/skills/authoring/references/sdk-server-functions.md +192 -0
- package/templates/common/.agents/skills/authoring/references/type-safety.md +141 -0
- package/templates/common/.content/config/site.json +5 -0
- package/templates/common/.content/schemas/site.schema.json +15 -0
- package/templates/common/README.md.tmpl +15 -0
- package/templates/nextjs/template/package.json.tmpl +3 -1
- package/templates/nextjs/template/src/app/_components/ConsentManager.tsx +132 -0
- package/templates/nextjs/template/src/app/layout.tsx +3 -1
- package/templates/nextjs/template/src/components/sections/HomeHero.tsx +1 -1
package/dist/types/media.d.ts
CHANGED
|
@@ -9,10 +9,16 @@ export declare const AssetSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
9
9
|
assetId: z.ZodString;
|
|
10
10
|
versionId: z.ZodString;
|
|
11
11
|
alt: z.ZodString;
|
|
12
|
-
|
|
12
|
+
fallback: z.ZodObject<{
|
|
13
13
|
src: z.ZodString;
|
|
14
14
|
width: z.ZodNumber;
|
|
15
15
|
height: z.ZodNumber;
|
|
16
|
+
type: z.ZodOptional<z.ZodString>;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
sources: z.ZodArray<z.ZodObject<{
|
|
19
|
+
srcset: z.ZodString;
|
|
20
|
+
sizes: z.ZodOptional<z.ZodString>;
|
|
21
|
+
media: z.ZodOptional<z.ZodString>;
|
|
16
22
|
type: z.ZodString;
|
|
17
23
|
}, z.core.$strip>>;
|
|
18
24
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -29,10 +35,16 @@ export declare const AssetSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
29
35
|
assetId: z.ZodString;
|
|
30
36
|
versionId: z.ZodString;
|
|
31
37
|
alt: z.ZodString;
|
|
32
|
-
|
|
38
|
+
fallback: z.ZodObject<{
|
|
33
39
|
src: z.ZodString;
|
|
34
40
|
width: z.ZodNumber;
|
|
35
41
|
height: z.ZodNumber;
|
|
42
|
+
type: z.ZodOptional<z.ZodString>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
sources: z.ZodArray<z.ZodObject<{
|
|
45
|
+
srcset: z.ZodString;
|
|
46
|
+
sizes: z.ZodOptional<z.ZodString>;
|
|
47
|
+
media: z.ZodOptional<z.ZodString>;
|
|
36
48
|
type: z.ZodString;
|
|
37
49
|
}, z.core.$strip>>;
|
|
38
50
|
}, z.core.$strip>>;
|
package/dist/types/page.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { VaryDimension } from './render-mode.js';
|
|
2
|
+
import type { TaxonomyAssignments } from './data.js';
|
|
2
3
|
export interface PageDocument {
|
|
3
4
|
path: string;
|
|
4
5
|
layout: string;
|
|
5
6
|
locale: string;
|
|
6
7
|
metadata: PageMetadata;
|
|
8
|
+
taxonomy?: TaxonomyAssignments;
|
|
7
9
|
regions: Record<string, RegionNode>;
|
|
8
10
|
}
|
|
9
11
|
export interface PageMetadata {
|
package/dist/types/video.d.ts
CHANGED
|
@@ -52,10 +52,16 @@ export declare const VideoSchema: z.ZodObject<{
|
|
|
52
52
|
assetId: z.ZodString;
|
|
53
53
|
versionId: z.ZodString;
|
|
54
54
|
alt: z.ZodString;
|
|
55
|
-
|
|
55
|
+
fallback: z.ZodObject<{
|
|
56
56
|
src: z.ZodString;
|
|
57
57
|
width: z.ZodNumber;
|
|
58
58
|
height: z.ZodNumber;
|
|
59
|
+
type: z.ZodOptional<z.ZodString>;
|
|
60
|
+
}, z.core.$strip>;
|
|
61
|
+
sources: z.ZodArray<z.ZodObject<{
|
|
62
|
+
srcset: z.ZodString;
|
|
63
|
+
sizes: z.ZodOptional<z.ZodString>;
|
|
64
|
+
media: z.ZodOptional<z.ZodString>;
|
|
59
65
|
type: z.ZodString;
|
|
60
66
|
}, z.core.$strip>>;
|
|
61
67
|
}, z.core.$strip>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradial/aci",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -74,6 +74,11 @@
|
|
|
74
74
|
"types": "./dist/next/dev-refresh.d.ts",
|
|
75
75
|
"import": "./dist/next/dev-refresh.js"
|
|
76
76
|
},
|
|
77
|
+
"./next/server": {
|
|
78
|
+
"types": "./dist/next/server.d.ts",
|
|
79
|
+
"import": "./dist/next/server.js",
|
|
80
|
+
"default": "./dist/next/server.js"
|
|
81
|
+
},
|
|
77
82
|
"./astro": {
|
|
78
83
|
"types": "./dist/astro/index.d.ts",
|
|
79
84
|
"import": "./dist/astro/index.js",
|
package/src/types/data.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
+
export type TaxonomyAssignments = Record<string, string[]>;
|
|
4
|
+
|
|
3
5
|
type InferDataProps<TSchema> = TSchema extends z.ZodType<infer T>
|
|
4
6
|
? T
|
|
5
7
|
: Record<string, unknown>;
|
|
@@ -19,6 +21,7 @@ export interface DataModelContract<TSchema = unknown, TType extends string = str
|
|
|
19
21
|
export interface DataEntry<TProps = Record<string, unknown>, TType extends string = string> {
|
|
20
22
|
$type: TType;
|
|
21
23
|
props: TProps;
|
|
24
|
+
taxonomy?: TaxonomyAssignments;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export type InferDataModelProps<TContract> = TContract extends DataModelContract<infer TSchema, string>
|
package/src/types/image.ts
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
|
-
// Image
|
|
4
|
+
// Image fallback + source variants
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
6
|
+
// The fallback is the base <img> rendition (largest derivative); each source
|
|
7
|
+
// entry is one <source> element candidate with a ready-made srcset scoped by
|
|
8
|
+
// the optional media/sizes of the slot output that produced it.
|
|
8
9
|
// ---------------------------------------------------------------------------
|
|
9
10
|
|
|
10
|
-
export interface
|
|
11
|
-
/** Derivative URL
|
|
11
|
+
export interface ImageFallback {
|
|
12
|
+
/** Derivative URL for the base <img>. */
|
|
12
13
|
src: string;
|
|
13
|
-
/** Intrinsic width in pixels. */
|
|
14
|
+
/** Intrinsic width in pixels (0 when the format carries none, e.g. SVG). */
|
|
14
15
|
width: number;
|
|
15
|
-
/** Intrinsic height in pixels. */
|
|
16
|
+
/** Intrinsic height in pixels (0 when the format carries none). */
|
|
16
17
|
height: number;
|
|
17
18
|
/** MIME type hint, e.g. image/webp. */
|
|
19
|
+
type?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ImageSource {
|
|
23
|
+
/** srcset value — a single URL or a width-descriptor candidate list. */
|
|
24
|
+
srcset: string;
|
|
25
|
+
/** sizes attribute from the slot contract. */
|
|
26
|
+
sizes?: string;
|
|
27
|
+
/** Media query scoping this source (art direction). */
|
|
28
|
+
media?: string;
|
|
29
|
+
/** MIME type hint, e.g. image/webp. */
|
|
18
30
|
type: string;
|
|
19
31
|
}
|
|
20
32
|
|
|
@@ -35,7 +47,9 @@ export interface Image {
|
|
|
35
47
|
versionId: string;
|
|
36
48
|
/** Accessible description of the image content. */
|
|
37
49
|
alt: string;
|
|
38
|
-
/**
|
|
50
|
+
/** Base <img> rendition. */
|
|
51
|
+
fallback: ImageFallback;
|
|
52
|
+
/** <source> candidates produced for the asset slot. */
|
|
39
53
|
sources: ImageSource[];
|
|
40
54
|
}
|
|
41
55
|
|
|
@@ -59,10 +73,17 @@ export interface SlotOutput {
|
|
|
59
73
|
// Zod schema
|
|
60
74
|
// ---------------------------------------------------------------------------
|
|
61
75
|
|
|
62
|
-
export const
|
|
76
|
+
export const ImageFallbackSchema = z.object({
|
|
63
77
|
src: z.string().min(1),
|
|
64
78
|
width: z.number().int().nonnegative(),
|
|
65
79
|
height: z.number().int().nonnegative(),
|
|
80
|
+
type: z.string().min(1).optional(),
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
export const ImageSourceSchema = z.object({
|
|
84
|
+
srcset: z.string().min(1),
|
|
85
|
+
sizes: z.string().min(1).optional(),
|
|
86
|
+
media: z.string().min(1).optional(),
|
|
66
87
|
type: z.string().min(1),
|
|
67
88
|
});
|
|
68
89
|
|
|
@@ -71,6 +92,7 @@ export const ImageSchema = z.object({
|
|
|
71
92
|
assetId: z.string().min(1),
|
|
72
93
|
versionId: z.string().min(1),
|
|
73
94
|
alt: z.string(),
|
|
95
|
+
fallback: ImageFallbackSchema,
|
|
74
96
|
sources: z.array(ImageSourceSchema).min(1),
|
|
75
97
|
});
|
|
76
98
|
|
|
@@ -81,38 +103,31 @@ export const ImageSchema = z.object({
|
|
|
81
103
|
export type ImageAttrs = Record<string, unknown>;
|
|
82
104
|
|
|
83
105
|
/**
|
|
84
|
-
*
|
|
85
|
-
* Uses the largest width; ties fall back to the first entry.
|
|
106
|
+
* The primary rendition of an image — its fallback (base <img>) entry.
|
|
86
107
|
*/
|
|
87
|
-
export function primaryImageSource(image: Image):
|
|
88
|
-
return image.
|
|
89
|
-
source.width > largest.width ? source : largest,
|
|
90
|
-
image.sources[0],
|
|
91
|
-
);
|
|
108
|
+
export function primaryImageSource(image: Image): ImageFallback {
|
|
109
|
+
return image.fallback;
|
|
92
110
|
}
|
|
93
111
|
|
|
94
112
|
/**
|
|
95
113
|
* Computes the full set of <img> attributes for an Image.
|
|
96
114
|
*
|
|
97
115
|
* Framework components (React <Picture>, Astro <img>, Svelte <img>) call this
|
|
98
|
-
* and spread the result into their native element. No HTML string
|
|
116
|
+
* and spread the result into their native element. No HTML string
|
|
117
|
+
* serialization. Media-scoped sources need a <picture> wrapper and are not
|
|
118
|
+
* representable as plain <img> attributes, so srcset/sizes are taken from the
|
|
119
|
+
* first unscoped source only.
|
|
99
120
|
*/
|
|
100
121
|
export function imageAttrs(image: Image, overrides: ImageAttrs = {}): ImageAttrs {
|
|
101
|
-
const
|
|
102
|
-
const srcset = image.sources
|
|
103
|
-
.map((s) => `${s.src} ${s.width}w`)
|
|
104
|
-
.join(', ');
|
|
105
|
-
const sizes = image.sources
|
|
106
|
-
.map((s) => `(max-width: ${s.width}px) ${s.width}px`)
|
|
107
|
-
.join(', ');
|
|
122
|
+
const unscoped = image.sources.find((s) => !s.media);
|
|
108
123
|
|
|
109
124
|
return {
|
|
110
|
-
src:
|
|
125
|
+
src: image.fallback.src,
|
|
111
126
|
alt: image.alt,
|
|
112
|
-
width:
|
|
113
|
-
height:
|
|
114
|
-
srcSet: srcset || undefined,
|
|
115
|
-
sizes: sizes || undefined,
|
|
127
|
+
width: image.fallback.width > 0 ? image.fallback.width : undefined,
|
|
128
|
+
height: image.fallback.height > 0 ? image.fallback.height : undefined,
|
|
129
|
+
srcSet: unscoped?.srcset || undefined,
|
|
130
|
+
sizes: unscoped?.sizes || undefined,
|
|
116
131
|
loading: 'lazy',
|
|
117
132
|
decoding: 'async',
|
|
118
133
|
...overrides,
|
package/src/types/page.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { VaryDimension } from './render-mode.js';
|
|
2
|
+
import type { TaxonomyAssignments } from './data.js';
|
|
2
3
|
|
|
3
4
|
export interface PageDocument {
|
|
4
5
|
path: string;
|
|
5
6
|
layout: string;
|
|
6
7
|
locale: string;
|
|
7
8
|
metadata: PageMetadata;
|
|
9
|
+
taxonomy?: TaxonomyAssignments;
|
|
8
10
|
regions: Record<string, RegionNode>;
|
|
9
11
|
}
|
|
10
12
|
|
|
@@ -27,8 +27,9 @@ export const sectionStoryFixtures: SectionStoryFixture[] = [
|
|
|
27
27
|
assetId: 'fixture_seattle',
|
|
28
28
|
versionId: 'v0001',
|
|
29
29
|
alt: 'Seattle skyline at dusk',
|
|
30
|
+
fallback: { src: '/assets/seattle.avif', width: 1920, height: 1280, type: 'image/avif' },
|
|
30
31
|
sources: [
|
|
31
|
-
{
|
|
32
|
+
{ srcset: '/assets/seattle.avif', sizes: '100vw', type: 'image/avif' }
|
|
32
33
|
]
|
|
33
34
|
}
|
|
34
35
|
}
|
|
@@ -6,9 +6,17 @@ interface Props {
|
|
|
6
6
|
description: string;
|
|
7
7
|
canonical?: string;
|
|
8
8
|
siteName?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Pre-rendered Gradial collect script tag (collectScriptTagHTML from
|
|
11
|
+
* '@gradial/aci/astro'). Empty string / undefined = personalization
|
|
12
|
+
* disabled, no tag. Emitted here because the Astro integration has no
|
|
13
|
+
* attribute-bearing HTML-injection seam (injectScript only injects script
|
|
14
|
+
* content).
|
|
15
|
+
*/
|
|
16
|
+
collectTag?: string;
|
|
9
17
|
}
|
|
10
18
|
|
|
11
|
-
const { title, description, canonical, siteName = 'Gradial' } = Astro.props;
|
|
19
|
+
const { title, description, canonical, siteName = 'Gradial', collectTag } = Astro.props;
|
|
12
20
|
---
|
|
13
21
|
|
|
14
22
|
<!doctype html>
|
|
@@ -23,8 +31,76 @@ const { title, description, canonical, siteName = 'Gradial' } = Astro.props;
|
|
|
23
31
|
<meta property="og:title" content={title} />
|
|
24
32
|
<meta property="og:description" content={description} />
|
|
25
33
|
<meta property="og:site_name" content={siteName} />
|
|
34
|
+
{collectTag ? <Fragment set:html={collectTag} /> : null}
|
|
26
35
|
</head>
|
|
27
36
|
<body>
|
|
28
37
|
<slot />
|
|
38
|
+
<script>
|
|
39
|
+
// Gradial collect ↔ c15t bridge. The collect SDK's c15t preset
|
|
40
|
+
// (data-aci-consent="c15t" on the collect tag) reads
|
|
41
|
+
// window.c15t = { consents, onConsentChange }. c15t itself publishes
|
|
42
|
+
// its zustand store as window.c15tStore instead, so this bridge
|
|
43
|
+
// mirrors any c15t store on the page into the shape the SDK reads.
|
|
44
|
+
//
|
|
45
|
+
// c15t has no Astro UI package — add a consent banner via a React
|
|
46
|
+
// island (@astrojs/react + @c15t/react) or any setup built on
|
|
47
|
+
// c15t's createConsentManagerStore; this bridge picks it up either
|
|
48
|
+
// way. Without a c15t setup the poll gives up silently and only the
|
|
49
|
+
// JS consent API (aci('consent', …) under the manual preset) writes
|
|
50
|
+
// envelopes.
|
|
51
|
+
//
|
|
52
|
+
// Consents are mirrored only after a real visitor decision
|
|
53
|
+
// (consentInfo set), never for pre-decision defaults, so the SDK
|
|
54
|
+
// cannot mistake an untouched banner for a withdrawal.
|
|
55
|
+
type Consents = Record<string, boolean>;
|
|
56
|
+
type ConsentListener = (payload: { consents: Consents }) => void;
|
|
57
|
+
interface ConsentStoreState {
|
|
58
|
+
consents?: Consents;
|
|
59
|
+
consentInfo?: unknown;
|
|
60
|
+
}
|
|
61
|
+
interface ConsentStoreLike {
|
|
62
|
+
getState(): ConsentStoreState;
|
|
63
|
+
subscribe(listener: (state: ConsentStoreState) => void): () => void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const listeners: ConsentListener[] = [];
|
|
67
|
+
|
|
68
|
+
function publish(consents: Consents): void {
|
|
69
|
+
const w = window as typeof window & {
|
|
70
|
+
c15t?: { consents?: Consents; onConsentChange?: (cb: ConsentListener) => void };
|
|
71
|
+
};
|
|
72
|
+
const bridge = (w.c15t ??= {});
|
|
73
|
+
bridge.consents = consents;
|
|
74
|
+
bridge.onConsentChange ??= (cb: ConsentListener) => {
|
|
75
|
+
listeners.push(cb);
|
|
76
|
+
};
|
|
77
|
+
for (const listener of [...listeners]) {
|
|
78
|
+
listener({ consents });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function onState(state: ConsentStoreState): void {
|
|
83
|
+
if (state.consentInfo && state.consents) publish(state.consents);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function connect(store: ConsentStoreLike): void {
|
|
87
|
+
onState(store.getState());
|
|
88
|
+
store.subscribe(onState);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Bounded poll for the store global — same schedule the collect SDK
|
|
92
|
+
// uses for window.c15t (250 ms for up to 10 s, then give up silently).
|
|
93
|
+
let remaining = 40;
|
|
94
|
+
function poll(): void {
|
|
95
|
+
const store = (window as { c15tStore?: ConsentStoreLike }).c15tStore;
|
|
96
|
+
if (store) {
|
|
97
|
+
connect(store);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
remaining -= 1;
|
|
101
|
+
if (remaining > 0) setTimeout(poll, 250);
|
|
102
|
+
}
|
|
103
|
+
poll();
|
|
104
|
+
</script>
|
|
29
105
|
</body>
|
|
30
106
|
</html>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { getGradialStaticPaths, getPageRuntimeRenderInput, createRenderChildren } from '@gradial/aci/astro';
|
|
2
|
+
import { getGradialStaticPaths, getPageRuntimeRenderInput, createRenderChildren, collectScriptTagHTML } from '@gradial/aci/astro';
|
|
3
3
|
import { normalizeRoute, routeMetadataForContent, resolveSlots } from '@gradial/aci/content';
|
|
4
4
|
import { FileContentProvider } from '@gradial/aci/providers/file';
|
|
5
5
|
import type { KernelPage, KernelSiteConfig, LayoutEntry, FragmentData } from '@gradial/aci/content';
|
|
@@ -36,9 +36,10 @@ const resolvedSlots = await resolveSlots(
|
|
|
36
36
|
);
|
|
37
37
|
|
|
38
38
|
const renderChildren = createRenderChildren(registry);
|
|
39
|
+
const collectTag = collectScriptTagHTML(siteConfig);
|
|
39
40
|
---
|
|
40
41
|
|
|
41
|
-
<SiteLayout title={meta.title} description={meta.description} canonical={meta.canonical} siteName={meta.siteName}>
|
|
42
|
+
<SiteLayout title={meta.title} description={meta.description} canonical={meta.canonical} siteName={meta.siteName} collectTag={collectTag}>
|
|
42
43
|
{layout.slots.map((slot) => {
|
|
43
44
|
const blocks = resolvedSlots[slot.name];
|
|
44
45
|
if (!blocks?.length) return null;
|
|
@@ -22,6 +22,11 @@ Skills live in `.agents/skills/`. Each has a `SKILL.md` entry point and
|
|
|
22
22
|
- Registry lives in `src/cms/registry.ts` (`createRegistry` with `[contract, component]` tuples).
|
|
23
23
|
- Compiled output goes to `.aci/compiled/` (generated, not checked in).
|
|
24
24
|
- Framework integration via `withAci()` in the framework config.
|
|
25
|
+
- Next.js server functions from `@gradial/aci/next` — use `getSiteConfig()`, `getPage()`, `getFragment()` instead of importing `FileContentProvider` or `S3ContentProvider` directly.
|
|
26
|
+
- Rich text from `@gradial/aci/react` — use `RichText` component, never raw `marked`/`dangerouslySetInnerHTML`.
|
|
27
|
+
- Images from `@gradial/aci` — use `imageAttrs()` or SDK components, never manual `srcSet` construction.
|
|
28
|
+
- Block slots use `blockRefArray()` in contracts and `renderChildren` in components — never hardcoded component name matching.
|
|
29
|
+
- No `as any` casts — use `ContentProps` from contracts.
|
|
25
30
|
- Supported frameworks: Astro and Next.js (SvelteKit removed).
|
|
26
31
|
|
|
27
32
|
## Commands
|
|
@@ -588,3 +588,34 @@ chrome-specific override scopes, and token creation workflow.
|
|
|
588
588
|
Read `references/repo-structure.md` for the full annotated directory
|
|
589
589
|
layout, framework-specific paths, naming conventions, and generated
|
|
590
590
|
files list.
|
|
591
|
+
|
|
592
|
+
## Deep Dive: SDK Server Functions
|
|
593
|
+
|
|
594
|
+
Read `references/sdk-server-functions.md` for `@gradial/aci/next`
|
|
595
|
+
server-side functions (`createPage`, `getSiteConfig`, `getFragment`,
|
|
596
|
+
etc.), the three-tier content resolution chain, and the critical rule
|
|
597
|
+
against importing `FileContentProvider` or `S3ContentProvider`
|
|
598
|
+
directly in app code.
|
|
599
|
+
|
|
600
|
+
## Deep Dive: Block Slots
|
|
601
|
+
|
|
602
|
+
Read `references/block-slots.md` for `blockRefArray()` in contracts,
|
|
603
|
+
`renderChildren` in components, and the rules for nested block
|
|
604
|
+
rendering without hardcoded component name matching.
|
|
605
|
+
|
|
606
|
+
## Deep Dive: Rich Text
|
|
607
|
+
|
|
608
|
+
Read `references/rich-text.md` for the SDK `RichText` component from
|
|
609
|
+
`@gradial/aci/react`, sanitization policy, and why you should never
|
|
610
|
+
use `marked` or `dangerouslySetInnerHTML` directly.
|
|
611
|
+
|
|
612
|
+
## Deep Dive: Asset Rendering
|
|
613
|
+
|
|
614
|
+
Read `references/asset-rendering.md` for `imageAttrs()`, `Picture`,
|
|
615
|
+
`Image`, `Media` components, and CSS background image patterns.
|
|
616
|
+
|
|
617
|
+
## Deep Dive: Type Safety
|
|
618
|
+
|
|
619
|
+
Read `references/type-safety.md` for `ContentProps` from contracts,
|
|
620
|
+
`as any` prohibition, CSS custom property typing, site config
|
|
621
|
+
generics, and block slot type imports.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Asset Rendering Reference
|
|
2
|
+
|
|
3
|
+
## Rules
|
|
4
|
+
|
|
5
|
+
- **NEVER** construct `<img>` tags manually with `src`/`srcSet` from
|
|
6
|
+
image sources.
|
|
7
|
+
- **ALWAYS** use the SDK's `imageAttrs()` function from `@gradial/aci`
|
|
8
|
+
or the `Image`/`Picture` component from `@gradial/aci/react`.
|
|
9
|
+
- **NEVER** duplicate the `Image` type locally — always import from
|
|
10
|
+
`@gradial/aci`.
|
|
11
|
+
|
|
12
|
+
## SDK Exports
|
|
13
|
+
|
|
14
|
+
### From `@gradial/aci`
|
|
15
|
+
|
|
16
|
+
| Export | Type | Purpose |
|
|
17
|
+
|--------|------|---------|
|
|
18
|
+
| `Image` | type | The DAM-backed image type (`$type`, `assetId`, `versionId`, `alt`, `sources`) |
|
|
19
|
+
| `ImageSource` | type | A single responsive derivative (`src`, `width`, `height`, `type`) |
|
|
20
|
+
| `imageAttrs(image, overrides?)` | function | Returns a complete attributes object for `<img>` |
|
|
21
|
+
| `primaryImageSource(image)` | function | Picks the largest-width source from an image |
|
|
22
|
+
| `ImageSchema` | Zod schema | Schema for image fields in contracts |
|
|
23
|
+
|
|
24
|
+
### From `@gradial/aci/react`
|
|
25
|
+
|
|
26
|
+
| Export | Type | Purpose |
|
|
27
|
+
|--------|------|---------|
|
|
28
|
+
| `Image` | component | Renders an `Image` as `<img>` with computed attrs |
|
|
29
|
+
| `Picture` | component | Renders an `Image` as responsive `<img>` (delegates to `imageAttrs()`) |
|
|
30
|
+
| `Media` | component | Renders media assets (images, videos) with type detection |
|
|
31
|
+
|
|
32
|
+
## imageAttrs()
|
|
33
|
+
|
|
34
|
+
`imageAttrs(image, overrides?)` returns a complete attributes object
|
|
35
|
+
including `src`, `alt`, `width`, `height`, `srcSet`, `sizes`, `loading`,
|
|
36
|
+
and `decoding`. Spread the result into a native `<img>` element:
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { imageAttrs, type Image } from '@gradial/aci';
|
|
40
|
+
|
|
41
|
+
export function HeroImage({ image }: { image: Image }) {
|
|
42
|
+
return <img {...imageAttrs(image)} />;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Override specific attributes by passing a second argument:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<img {...imageAttrs(image, { loading: 'eager' })} />
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## SDK Components
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { Picture, Image } from '@gradial/aci/react';
|
|
56
|
+
|
|
57
|
+
// Picture: delegates to imageAttrs() internally
|
|
58
|
+
<Picture image={image} />
|
|
59
|
+
|
|
60
|
+
// Image: same behavior, accepts image or value prop
|
|
61
|
+
<Image image={image} />
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Both components call `imageAttrs()` internally and spread the result
|
|
65
|
+
into a native `<img>` element.
|
|
66
|
+
|
|
67
|
+
## CSS Background Images
|
|
68
|
+
|
|
69
|
+
For CSS background images, use `primaryImageSource()` to get the URL:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { primaryImageSource } from '@gradial/aci';
|
|
73
|
+
|
|
74
|
+
export function HeroBackground({ image }: { image: Image }) {
|
|
75
|
+
const src = primaryImageSource(image).src;
|
|
76
|
+
return (
|
|
77
|
+
<div style={{ backgroundImage: `url(${src})` } as React.CSSProperties} />
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## In Contracts
|
|
83
|
+
|
|
84
|
+
Use `ImageSchema` for DAM-managed image fields:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { ImageSchema, defineComponentContract } from '@gradial/aci';
|
|
88
|
+
import { z } from 'zod';
|
|
89
|
+
|
|
90
|
+
export const schema = z.object({
|
|
91
|
+
image: ImageSchema,
|
|
92
|
+
cards: z.array(z.object({
|
|
93
|
+
image: ImageSchema.optional(),
|
|
94
|
+
})),
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Declare `imageSlots` matching every `ImageSchema` field, including
|
|
99
|
+
nested dot paths like `cards.image`. See
|
|
100
|
+
`references/image-assets.md` for full image slot configuration.
|
|
101
|
+
|
|
102
|
+
## Anti-Patterns
|
|
103
|
+
|
|
104
|
+
- Manually building `srcSet` strings from `image.sources` — use
|
|
105
|
+
`imageAttrs()` instead
|
|
106
|
+
- Constructing `<img src={image.sources[0].src} />` — use `imageAttrs()`
|
|
107
|
+
or SDK components
|
|
108
|
+
- Duplicating the `Image` type locally — import from `@gradial/aci`
|
|
109
|
+
- Ignoring `width`/`height` — `imageAttrs()` includes them to prevent
|
|
110
|
+
layout shift
|