@substrate-platform/site 0.1.1-canary.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/dist/animations.d.ts +37 -0
- package/dist/animations.d.ts.map +1 -0
- package/dist/animations.js +139 -0
- package/dist/animations.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.d.ts +46 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +48 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/layout.d.ts +75 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +40 -0
- package/dist/layout.js.map +1 -0
- package/dist/metadata.d.ts +21 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +31 -0
- package/dist/metadata.js.map +1 -0
- package/dist/paint-registrar.d.ts +2 -0
- package/dist/paint-registrar.d.ts.map +1 -0
- package/dist/paint-registrar.js +14 -0
- package/dist/paint-registrar.js.map +1 -0
- package/dist/providers.d.ts +18 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +42 -0
- package/dist/providers.js.map +1 -0
- package/dist/shells.d.ts +12 -0
- package/dist/shells.d.ts.map +1 -0
- package/dist/shells.js +38 -0
- package/dist/shells.js.map +1 -0
- package/dist/smooth-scroll.d.ts +2 -0
- package/dist/smooth-scroll.d.ts.map +1 -0
- package/dist/smooth-scroll.js +15 -0
- package/dist/smooth-scroll.js.map +1 -0
- package/dist/theme-script.d.ts +26 -0
- package/dist/theme-script.d.ts.map +1 -0
- package/dist/theme-script.js +9 -0
- package/dist/theme-script.js.map +1 -0
- package/package.json +82 -0
- package/src/globals.css +220 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Lenis from 'lenis';
|
|
2
|
+
/**
|
|
3
|
+
* Initialize Lenis smooth scrolling.
|
|
4
|
+
* Call once in a client component's useEffect.
|
|
5
|
+
*/
|
|
6
|
+
export declare function initSmoothScroll(options?: {
|
|
7
|
+
duration?: number;
|
|
8
|
+
easing?: (t: number) => number;
|
|
9
|
+
}): () => void;
|
|
10
|
+
/** Get the current Lenis instance (if initialized). */
|
|
11
|
+
export declare function getLenis(): Lenis | null;
|
|
12
|
+
/** Scroll to a target element or position smoothly. */
|
|
13
|
+
export declare function scrollTo(target: string | number | HTMLElement, options?: {
|
|
14
|
+
offset?: number;
|
|
15
|
+
duration?: number;
|
|
16
|
+
}): void;
|
|
17
|
+
/**
|
|
18
|
+
* Fade-in-up animation for page sections.
|
|
19
|
+
*/
|
|
20
|
+
export declare function fadeInUp(target: HTMLElement | string, delay?: number): gsap.core.Tween;
|
|
21
|
+
/**
|
|
22
|
+
* Stagger reveal for grid items.
|
|
23
|
+
*/
|
|
24
|
+
export declare function staggerReveal(target: HTMLElement | string, stagger?: number): gsap.core.Tween;
|
|
25
|
+
/**
|
|
26
|
+
* Scale + rotate entrance for hero / canvas elements.
|
|
27
|
+
*/
|
|
28
|
+
export declare function scaleEntrance(target: HTMLElement | string): gsap.core.Tween;
|
|
29
|
+
/**
|
|
30
|
+
* 3D Y-axis rotation card flip.
|
|
31
|
+
*/
|
|
32
|
+
export declare function cardFlip(target: HTMLElement | string): gsap.core.Tween;
|
|
33
|
+
/**
|
|
34
|
+
* Magnetic hover effect — element follows cursor slightly.
|
|
35
|
+
*/
|
|
36
|
+
export declare function magneticHover(target: HTMLElement, strength?: number): () => void;
|
|
37
|
+
//# sourceMappingURL=animations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animations.d.ts","sourceRoot":"","sources":["../src/animations.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAS1B;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,cAwB/F;AAED,uDAAuD;AACvD,wBAAgB,QAAQ,iBAEvB;AAED,uDAAuD;AACvD,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,EACrC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,QAMjD;AAID;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,KAAK,SAAI,mBAY/D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,OAAO,SAAM,mBAaxE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,mBAYzD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,mBAapD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,SAAM,cA6BhE"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSAP + Lenis — smooth scroll and animation utilities.
|
|
3
|
+
*
|
|
4
|
+
* Lenis provides buttery smooth scrolling (replaces native scroll with
|
|
5
|
+
* a rAF-driven interpolated scroll). GSAP's ScrollTrigger integrates
|
|
6
|
+
* with Lenis for scroll-driven animations.
|
|
7
|
+
*
|
|
8
|
+
* All factories are generic — no application-specific names or semantics.
|
|
9
|
+
*/
|
|
10
|
+
'use client';
|
|
11
|
+
import { gsap } from 'gsap';
|
|
12
|
+
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
|
13
|
+
import Lenis from 'lenis';
|
|
14
|
+
// Register GSAP plugin (client-side only).
|
|
15
|
+
gsap.registerPlugin(ScrollTrigger);
|
|
16
|
+
// ── Lenis smooth scroll ─────────────────────────────────────────────
|
|
17
|
+
let lenisInstance = null;
|
|
18
|
+
/**
|
|
19
|
+
* Initialize Lenis smooth scrolling.
|
|
20
|
+
* Call once in a client component's useEffect.
|
|
21
|
+
*/
|
|
22
|
+
export function initSmoothScroll(options) {
|
|
23
|
+
if (typeof window === 'undefined')
|
|
24
|
+
return () => { };
|
|
25
|
+
const lenis = new Lenis({
|
|
26
|
+
duration: options?.duration ?? 1.2,
|
|
27
|
+
easing: options?.easing ?? ((t) => Math.min(1, 1.001 - 2 ** (-10 * t))),
|
|
28
|
+
smoothWheel: true,
|
|
29
|
+
});
|
|
30
|
+
lenisInstance = lenis;
|
|
31
|
+
// Sync Lenis with GSAP ScrollTrigger.
|
|
32
|
+
lenis.on('scroll', ScrollTrigger.update);
|
|
33
|
+
// Drive Lenis via GSAP's ticker for unified rAF loop.
|
|
34
|
+
gsap.ticker.add((time) => {
|
|
35
|
+
lenis.raf(time * 1000);
|
|
36
|
+
});
|
|
37
|
+
gsap.ticker.lagSmoothing(0);
|
|
38
|
+
return () => {
|
|
39
|
+
lenis.destroy();
|
|
40
|
+
lenisInstance = null;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Get the current Lenis instance (if initialized). */
|
|
44
|
+
export function getLenis() {
|
|
45
|
+
return lenisInstance;
|
|
46
|
+
}
|
|
47
|
+
/** Scroll to a target element or position smoothly. */
|
|
48
|
+
export function scrollTo(target, options) {
|
|
49
|
+
lenisInstance?.scrollTo(target, {
|
|
50
|
+
offset: options?.offset ?? 0,
|
|
51
|
+
duration: options?.duration ?? 1.2,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// ── GSAP animation factories ────────────────────────────────────────
|
|
55
|
+
/**
|
|
56
|
+
* Fade-in-up animation for page sections.
|
|
57
|
+
*/
|
|
58
|
+
export function fadeInUp(target, delay = 0) {
|
|
59
|
+
const vars = {
|
|
60
|
+
opacity: 1,
|
|
61
|
+
y: 0,
|
|
62
|
+
duration: 0.8,
|
|
63
|
+
delay,
|
|
64
|
+
ease: 'power3.out',
|
|
65
|
+
};
|
|
66
|
+
if (typeof target === 'string') {
|
|
67
|
+
vars.scrollTrigger = target;
|
|
68
|
+
}
|
|
69
|
+
return gsap.fromTo(target, { opacity: 0, y: 40 }, vars);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Stagger reveal for grid items.
|
|
73
|
+
*/
|
|
74
|
+
export function staggerReveal(target, stagger = 0.1) {
|
|
75
|
+
return gsap.fromTo(target, { opacity: 0, y: 30, scale: 0.95 }, {
|
|
76
|
+
opacity: 1,
|
|
77
|
+
y: 0,
|
|
78
|
+
scale: 1,
|
|
79
|
+
duration: 0.6,
|
|
80
|
+
stagger,
|
|
81
|
+
ease: 'power2.out',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Scale + rotate entrance for hero / canvas elements.
|
|
86
|
+
*/
|
|
87
|
+
export function scaleEntrance(target) {
|
|
88
|
+
return gsap.fromTo(target, { opacity: 0, scale: 0.8, rotation: -5 }, {
|
|
89
|
+
opacity: 1,
|
|
90
|
+
scale: 1,
|
|
91
|
+
rotation: 0,
|
|
92
|
+
duration: 1.2,
|
|
93
|
+
ease: 'power4.out',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 3D Y-axis rotation card flip.
|
|
98
|
+
*/
|
|
99
|
+
export function cardFlip(target) {
|
|
100
|
+
return gsap.fromTo(target, { rotationY: 90, opacity: 0 }, {
|
|
101
|
+
rotationY: 0,
|
|
102
|
+
opacity: 1,
|
|
103
|
+
duration: 0.6,
|
|
104
|
+
ease: 'back.out(1.7)',
|
|
105
|
+
transformPerspective: 800,
|
|
106
|
+
transformOrigin: 'center center',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Magnetic hover effect — element follows cursor slightly.
|
|
111
|
+
*/
|
|
112
|
+
export function magneticHover(target, strength = 0.3) {
|
|
113
|
+
const onMove = (e) => {
|
|
114
|
+
const rect = target.getBoundingClientRect();
|
|
115
|
+
const x = e.clientX - rect.left - rect.width / 2;
|
|
116
|
+
const y = e.clientY - rect.top - rect.height / 2;
|
|
117
|
+
gsap.to(target, {
|
|
118
|
+
x: x * strength,
|
|
119
|
+
y: y * strength,
|
|
120
|
+
duration: 0.4,
|
|
121
|
+
ease: 'power2.out',
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
const onLeave = () => {
|
|
125
|
+
gsap.to(target, {
|
|
126
|
+
x: 0,
|
|
127
|
+
y: 0,
|
|
128
|
+
duration: 0.6,
|
|
129
|
+
ease: 'elastic.out(1, 0.3)',
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
target.addEventListener('mousemove', onMove);
|
|
133
|
+
target.addEventListener('mouseleave', onLeave);
|
|
134
|
+
return () => {
|
|
135
|
+
target.removeEventListener('mousemove', onMove);
|
|
136
|
+
target.removeEventListener('mouseleave', onLeave);
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=animations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animations.js","sourceRoot":"","sources":["../src/animations.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @substrate-platform/site — site shell primitives for Substrate-based Next.js sites.
|
|
3
|
+
*
|
|
4
|
+
* This package provides the minimal set of components, hooks, and
|
|
5
|
+
* utilities that every Substrate site needs. It does NOT include
|
|
6
|
+
* any application-specific features (newsletter, search, auth, etc.).
|
|
7
|
+
*
|
|
8
|
+
* ## Usage
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* // app/layout.tsx
|
|
12
|
+
* import {
|
|
13
|
+
* SubstrateLayout,
|
|
14
|
+
* SubstrateProviders,
|
|
15
|
+
* SubstrateFooter,
|
|
16
|
+
* createMetadata,
|
|
17
|
+
* ThemeScript,
|
|
18
|
+
* SmoothScroll,
|
|
19
|
+
* PaintRegistrar,
|
|
20
|
+
* } from '@substrate-platform/site';
|
|
21
|
+
* import '@substrate-platform/site/globals.css';
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* ## Dependency invariant
|
|
25
|
+
*
|
|
26
|
+
* `@substrate-platform/site` only depends on platform packages:
|
|
27
|
+
* @substrate-platform/ui, @substrate-platform/contracts, @substrate-platform/config, @substrate-platform/observability
|
|
28
|
+
*
|
|
29
|
+
* It MUST NOT depend on any application package. Applications depend
|
|
30
|
+
* on `@substrate-platform/site`, never the reverse.
|
|
31
|
+
*/
|
|
32
|
+
export { cardFlip, fadeInUp, getLenis, initSmoothScroll, magneticHover, scaleEntrance, scrollTo, staggerReveal, } from './animations';
|
|
33
|
+
export { type InstrumentationConfig, registerInstrumentation } from './instrumentation';
|
|
34
|
+
export { type PoweredByConfig, SubstrateFooter, SubstrateLayout, type SubstrateLayoutProps, } from './layout';
|
|
35
|
+
export { createMetadata } from './metadata';
|
|
36
|
+
export { PaintRegistrar } from './paint-registrar';
|
|
37
|
+
export { SubstrateProviders, type SubstrateProvidersProps } from './providers';
|
|
38
|
+
export { type ErrorShellProps, SubstrateError, SubstrateGlobalError, SubstrateLoading, SubstrateNotFound, } from './shells';
|
|
39
|
+
export { SmoothScroll } from './smooth-scroll';
|
|
40
|
+
export { ThemeScript } from './theme-script';
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,QAAQ,EACR,aAAa,GACd,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,KAAK,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAExF,OAAO,EACL,KAAK,eAAe,EACpB,eAAe,EACf,eAAe,EACf,KAAK,oBAAoB,GAC1B,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE/E,OAAO,EACL,KAAK,eAAe,EACpB,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @substrate-platform/site — site shell primitives for Substrate-based Next.js sites.
|
|
3
|
+
*
|
|
4
|
+
* This package provides the minimal set of components, hooks, and
|
|
5
|
+
* utilities that every Substrate site needs. It does NOT include
|
|
6
|
+
* any application-specific features (newsletter, search, auth, etc.).
|
|
7
|
+
*
|
|
8
|
+
* ## Usage
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* // app/layout.tsx
|
|
12
|
+
* import {
|
|
13
|
+
* SubstrateLayout,
|
|
14
|
+
* SubstrateProviders,
|
|
15
|
+
* SubstrateFooter,
|
|
16
|
+
* createMetadata,
|
|
17
|
+
* ThemeScript,
|
|
18
|
+
* SmoothScroll,
|
|
19
|
+
* PaintRegistrar,
|
|
20
|
+
* } from '@substrate-platform/site';
|
|
21
|
+
* import '@substrate-platform/site/globals.css';
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* ## Dependency invariant
|
|
25
|
+
*
|
|
26
|
+
* `@substrate-platform/site` only depends on platform packages:
|
|
27
|
+
* @substrate-platform/ui, @substrate-platform/contracts, @substrate-platform/config, @substrate-platform/observability
|
|
28
|
+
*
|
|
29
|
+
* It MUST NOT depend on any application package. Applications depend
|
|
30
|
+
* on `@substrate-platform/site`, never the reverse.
|
|
31
|
+
*/
|
|
32
|
+
// ── Animation utilities ────────────────────────────────────────────
|
|
33
|
+
export { cardFlip, fadeInUp, getLenis, initSmoothScroll, magneticHover, scaleEntrance, scrollTo, staggerReveal, } from './animations.js';
|
|
34
|
+
// ── Instrumentation ────────────────────────────────────────────────
|
|
35
|
+
export { registerInstrumentation } from './instrumentation.js';
|
|
36
|
+
// ── Layout primitives ──────────────────────────────────────────────
|
|
37
|
+
export { SubstrateFooter, SubstrateLayout, } from './layout.js';
|
|
38
|
+
// ── Metadata helpers ───────────────────────────────────────────────
|
|
39
|
+
export { createMetadata } from './metadata.js';
|
|
40
|
+
export { PaintRegistrar } from './paint-registrar.js';
|
|
41
|
+
// ── Providers ──────────────────────────────────────────────────────
|
|
42
|
+
export { SubstrateProviders } from './providers.js';
|
|
43
|
+
// ── Error / Loading / Not-Found shells ─────────────────────────────
|
|
44
|
+
export { SubstrateError, SubstrateGlobalError, SubstrateLoading, SubstrateNotFound, } from './shells.js';
|
|
45
|
+
// ── Side-effect components ─────────────────────────────────────────
|
|
46
|
+
export { SmoothScroll } from './smooth-scroll.js';
|
|
47
|
+
// ── Theme ──────────────────────────────────────────────────────────
|
|
48
|
+
export { ThemeScript } from './theme-script.js';
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,sEAAsE;AACtE,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,QAAQ,EACR,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,sEAAsE;AACtE,OAAO,EAA8B,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACxF,sEAAsE;AACtE,OAAO,EAEL,eAAe,EACf,eAAe,GAEhB,MAAM,UAAU,CAAC;AAClB,sEAAsE;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,sEAAsE;AACtE,OAAO,EAAE,kBAAkB,EAAgC,MAAM,aAAa,CAAC;AAC/E,sEAAsE;AACtE,OAAO,EAEL,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAClB,sEAAsE;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,sEAAsE;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* registerInstrumentation — Next.js instrumentation hook factory.
|
|
3
|
+
*
|
|
4
|
+
* The application calls this from its `instrumentation.ts`:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* // instrumentation.ts
|
|
8
|
+
* import { registerInstrumentation } from '@substrate-platform/site/instrumentation';
|
|
9
|
+
*
|
|
10
|
+
* export const register = registerInstrumentation({
|
|
11
|
+
* featurePreset: 'reference',
|
|
12
|
+
* serviceName: 'my-site',
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The factory handles:
|
|
17
|
+
* 1. Feature manifest initialization from a preset name.
|
|
18
|
+
* 2. OpenTelemetry SDK startup (if endpoint is configured).
|
|
19
|
+
* 3. Env validation warnings for enabled features.
|
|
20
|
+
*
|
|
21
|
+
* The platform does NOT hardcode any application name, service name,
|
|
22
|
+
* or feature preset.
|
|
23
|
+
*/
|
|
24
|
+
import type { FeatureManifest } from '@substrate-platform/config/features';
|
|
25
|
+
export type InstrumentationConfig = {
|
|
26
|
+
/**
|
|
27
|
+
* Feature preset name. Maps to presets in @substrate-platform/config.
|
|
28
|
+
* If omitted, defaults to 'minimal' in production, 'full' otherwise.
|
|
29
|
+
*/
|
|
30
|
+
featurePreset?: 'minimal' | 'graphics' | 'ai-archive' | 'realtime' | 'reference';
|
|
31
|
+
/**
|
|
32
|
+
* OTEL service name. Defaults to 'substrate'.
|
|
33
|
+
* Applications should override with their own name.
|
|
34
|
+
*/
|
|
35
|
+
serviceName?: string;
|
|
36
|
+
/**
|
|
37
|
+
* OTEL trace sample rate. Defaults to 0.1.
|
|
38
|
+
*/
|
|
39
|
+
traceSampleRate?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Custom feature manifest. If provided, overrides `featurePreset`.
|
|
42
|
+
*/
|
|
43
|
+
featureManifest?: FeatureManifest;
|
|
44
|
+
};
|
|
45
|
+
export declare function registerInstrumentation(config?: InstrumentationConfig): () => Promise<void>;
|
|
46
|
+
//# sourceMappingURL=instrumentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAE3E,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;OAGG;IACH,aAAa,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;IACjF;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,qBAAqB,SAClC,OAAO,CAAC,IAAI,CAAC,CA6DhD"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export function registerInstrumentation(config) {
|
|
2
|
+
return async function register() {
|
|
3
|
+
const { initFeatures, minimalSiteFeatures, graphicsLabFeatures, aiArchiveFeatures, realtimeRoomFeatures, referenceFeatures, validateEnv, } = await import('@substrate-platform/config/features');
|
|
4
|
+
// Determine the feature manifest.
|
|
5
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
6
|
+
const profile = config?.featurePreset ?? (isProduction ? 'minimal' : 'reference');
|
|
7
|
+
const presets = {
|
|
8
|
+
minimal: minimalSiteFeatures,
|
|
9
|
+
graphics: graphicsLabFeatures,
|
|
10
|
+
'ai-archive': aiArchiveFeatures,
|
|
11
|
+
realtime: realtimeRoomFeatures,
|
|
12
|
+
reference: referenceFeatures,
|
|
13
|
+
};
|
|
14
|
+
const manifest = config?.featureManifest ?? presets[profile] ?? minimalSiteFeatures;
|
|
15
|
+
initFeatures(manifest);
|
|
16
|
+
// Warn about missing env vars for enabled features.
|
|
17
|
+
const missing = validateEnv(manifest);
|
|
18
|
+
if (missing.length > 0) {
|
|
19
|
+
console.warn(`[features] Missing env vars: ${missing.join(', ')}`);
|
|
20
|
+
}
|
|
21
|
+
// Start OpenTelemetry if on Node.js runtime and endpoint is configured.
|
|
22
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
23
|
+
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
24
|
+
if (!endpoint) {
|
|
25
|
+
console.warn('[OTel] OTEL_EXPORTER_OTLP_ENDPOINT not set — skipping SDK init');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const { startOTEL } = await import('@substrate-platform/observability');
|
|
29
|
+
// Parse headers from "key1=val1,key2=val2" format.
|
|
30
|
+
const headers = {};
|
|
31
|
+
const rawHeaders = process.env.OTEL_EXPORTER_OTLP_HEADERS;
|
|
32
|
+
if (rawHeaders) {
|
|
33
|
+
for (const pair of rawHeaders.split(',')) {
|
|
34
|
+
const [k, v] = pair.split('=').map((s) => s.trim());
|
|
35
|
+
if (k && v)
|
|
36
|
+
headers[k] = v;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
await startOTEL({
|
|
40
|
+
endpoint,
|
|
41
|
+
headers,
|
|
42
|
+
serviceName: config?.serviceName ?? process.env.OTEL_SERVICE_NAME ?? 'substrate',
|
|
43
|
+
traceSampleRate: config?.traceSampleRate ?? Number(process.env.OTEL_TRACES_SAMPLE_RATE ?? 0.1),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=instrumentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"AA8CA,MAAM,UAAU,uBAAuB,CAAC,MAA8B;IACpE,OAAO,KAAK,UAAU,QAAQ;QAC5B,MAAM,EACJ,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,GACZ,GAAG,MAAM,MAAM,CAAC,qCAAqC,CAAC,CAAC;QAExD,kCAAkC;QAClC,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;QAC3D,MAAM,OAAO,GAAG,MAAM,EAAE,aAAa,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QAElF,MAAM,OAAO,GAAG;YACd,OAAO,EAAE,mBAAmB;YAC5B,QAAQ,EAAE,mBAAmB;YAC7B,YAAY,EAAE,iBAAiB;YAC/B,QAAQ,EAAE,oBAAoB;YAC9B,SAAS,EAAE,iBAAiB;SAC7B,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,EAAE,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,mBAAmB,CAAC;QACpF,YAAY,CAAC,QAAQ,CAAC,CAAC;QAEvB,oDAAoD;QACpD,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,gCAAgC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,wEAAwE;QACxE,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;YAC1C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;YACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;gBAC/E,OAAO;YACT,CAAC;YAED,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,mCAAmC,CAAC,CAAC;YAExE,mDAAmD;YACnD,MAAM,OAAO,GAA2B,EAAE,CAAC;YAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;YAC1D,IAAI,UAAU,EAAE,CAAC;gBACf,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;oBACpD,IAAI,CAAC,IAAI,CAAC;wBAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;YAED,MAAM,SAAS,CAAC;gBACd,QAAQ;gBACR,OAAO;gBACP,WAAW,EAAE,MAAM,EAAE,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,WAAW;gBAChF,eAAe,EACb,MAAM,EAAE,eAAe,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,GAAG,CAAC;aAChF,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubstrateLayout — minimal root layout shell for a Next.js site.
|
|
3
|
+
*
|
|
4
|
+
* Wraps children in the standard HTML structure with font variables,
|
|
5
|
+
* dark theme default, and an optional "Powered by Substrate" footer.
|
|
6
|
+
*
|
|
7
|
+
* The attribution is **on by default** and can be disabled via
|
|
8
|
+
* `poweredBy: { enabled: false }`. The label and link are **not
|
|
9
|
+
* configurable** — when shown, the attribution always reads
|
|
10
|
+
* "Powered by Substrate" and always links to the official repository.
|
|
11
|
+
*
|
|
12
|
+
* ```tsx
|
|
13
|
+
* // Default — shows "Powered by Substrate" → official GitHub.
|
|
14
|
+
* <SubstrateLayout fontClass={fontVar}>{children}</SubstrateLayout>
|
|
15
|
+
*
|
|
16
|
+
* // Disable.
|
|
17
|
+
* <SubstrateLayout poweredBy={{ enabled: false }}>
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* The footer is a platform brand default, not a licence requirement.
|
|
21
|
+
* Consumers are free to disable it under Apache-2.0.
|
|
22
|
+
*/
|
|
23
|
+
import type { ReactNode } from 'react';
|
|
24
|
+
/**
|
|
25
|
+
* Configuration for the "Powered by Substrate" attribution.
|
|
26
|
+
*
|
|
27
|
+
* `enabled` is the **only** option. The label and link URL are
|
|
28
|
+
* platform constants — they cannot be overridden by consumers.
|
|
29
|
+
* This ensures the attribution always serves its purpose as an
|
|
30
|
+
* ecosystem entry point to the official Substrate project.
|
|
31
|
+
*/
|
|
32
|
+
export type PoweredByConfig = {
|
|
33
|
+
/** Show the attribution? Defaults to `true`. */
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
};
|
|
36
|
+
export type SubstrateLayoutProps = {
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
/** CSS class containing font CSS variables (e.g. GeistSans.variable). */
|
|
39
|
+
fontClass?: string;
|
|
40
|
+
/** Language attribute. Defaults to 'en'. */
|
|
41
|
+
lang?: string;
|
|
42
|
+
/** Additional className for <html>. Defaults to 'dark'. */
|
|
43
|
+
htmlClassName?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Render the SubstrateFooter? Defaults to `true`.
|
|
46
|
+
*
|
|
47
|
+
* Legacy shorthand for `poweredBy: { enabled: true }`.
|
|
48
|
+
*/
|
|
49
|
+
footer?: boolean;
|
|
50
|
+
/** Configure the "Powered by Substrate" attribution. */
|
|
51
|
+
poweredBy?: PoweredByConfig;
|
|
52
|
+
};
|
|
53
|
+
export declare function SubstrateLayout({ children, fontClass, lang, htmlClassName, footer, poweredBy, }: SubstrateLayoutProps): import("react").JSX.Element;
|
|
54
|
+
/**
|
|
55
|
+
* SubstrateFooter — renders the "Powered by Substrate" attribution.
|
|
56
|
+
*
|
|
57
|
+
* **On by default.** This is a platform brand default, not a licence
|
|
58
|
+
* requirement. Under Apache-2.0, consumers are free to disable it:
|
|
59
|
+
*
|
|
60
|
+
* ```tsx
|
|
61
|
+
* // Disable
|
|
62
|
+
* <SubstrateFooter enabled={false} />
|
|
63
|
+
*
|
|
64
|
+
* // Or via layout
|
|
65
|
+
* <SubstrateLayout poweredBy={{ enabled: false }}>
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* The label is always "Powered by Substrate" and the link always
|
|
69
|
+
* points to the official Substrate repository. Neither is
|
|
70
|
+
* configurable — see `PoweredByConfig`.
|
|
71
|
+
*/
|
|
72
|
+
export declare function SubstrateFooter({ enabled }?: {
|
|
73
|
+
enabled?: boolean;
|
|
74
|
+
}): import("react").JSX.Element | null;
|
|
75
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,SAAS,CAAC;IACpB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wDAAwD;IACxD,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B,CAAC;AAeF,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,SAAc,EACd,IAAW,EACX,aAAsB,EACtB,MAAa,EACb,SAAS,GACV,EAAE,oBAAoB,+BAYtB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,EAAE,OAAc,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,sCAqB7E"}
|
package/dist/layout.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// ── Constants ───────────────────────────────────────────────────────
|
|
3
|
+
/**
|
|
4
|
+
* The official Substrate repository URL.
|
|
5
|
+
*
|
|
6
|
+
* This is a platform constant. It is not exported and cannot be
|
|
7
|
+
* overridden by consumers. When the "Powered by Substrate"
|
|
8
|
+
* attribution is shown, it always links here.
|
|
9
|
+
*/
|
|
10
|
+
const SUBSTRATE_REPOSITORY = 'https://github.com/Juwan-Hwang/substrate';
|
|
11
|
+
// ── Components ──────────────────────────────────────────────────────
|
|
12
|
+
export function SubstrateLayout({ children, fontClass = '', lang = 'en', htmlClassName = 'dark', footer = true, poweredBy, }) {
|
|
13
|
+
// `poweredBy` takes precedence over legacy `footer` prop.
|
|
14
|
+
const enabled = poweredBy?.enabled ?? footer;
|
|
15
|
+
return (_jsx("html", { lang: lang, className: `${htmlClassName} ${fontClass}`.trim(), suppressHydrationWarning: true, children: _jsxs("body", { children: [children, _jsx(SubstrateFooter, { enabled: enabled })] }) }));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* SubstrateFooter — renders the "Powered by Substrate" attribution.
|
|
19
|
+
*
|
|
20
|
+
* **On by default.** This is a platform brand default, not a licence
|
|
21
|
+
* requirement. Under Apache-2.0, consumers are free to disable it:
|
|
22
|
+
*
|
|
23
|
+
* ```tsx
|
|
24
|
+
* // Disable
|
|
25
|
+
* <SubstrateFooter enabled={false} />
|
|
26
|
+
*
|
|
27
|
+
* // Or via layout
|
|
28
|
+
* <SubstrateLayout poweredBy={{ enabled: false }}>
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* The label is always "Powered by Substrate" and the link always
|
|
32
|
+
* points to the official Substrate repository. Neither is
|
|
33
|
+
* configurable — see `PoweredByConfig`.
|
|
34
|
+
*/
|
|
35
|
+
export function SubstrateFooter({ enabled = true } = {}) {
|
|
36
|
+
if (!enabled)
|
|
37
|
+
return null;
|
|
38
|
+
return (_jsx("footer", { className: "mx-auto max-w-5xl px-6 pb-4 pt-4 text-center", children: _jsxs("p", { className: "text-[0.6875rem]", style: { color: 'var(--substrate-text-tertiary)', opacity: 0.35 }, children: ["Powered by", ' ', _jsx("a", { href: SUBSTRATE_REPOSITORY, target: "_blank", rel: "noopener noreferrer", className: "underline transition-opacity hover:opacity-80", children: "Substrate" })] }) }));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.tsx"],"names":[],"mappings":";AAyDA,uEAAuE;AAEvE;;;;;;GAMG;AACH,MAAM,oBAAoB,GAAG,0CAA0C,CAAC;AAExE,uEAAuE;AAEvE,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,EACR,SAAS,GAAG,EAAE,EACd,IAAI,GAAG,IAAI,EACX,aAAa,GAAG,MAAM,EACtB,MAAM,GAAG,IAAI,EACb,SAAS,GACY;IACrB,0DAA0D;IAC1D,MAAM,OAAO,GAAG,SAAS,EAAE,OAAO,IAAI,MAAM,CAAC;IAE7C,OAAO,CACL,eAAM,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,aAAa,IAAI,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,wBAAwB,kBAC3F,2BACG,QAAQ,EACT,KAAC,eAAe,IAAC,OAAO,EAAE,OAAO,GAAI,IAChC,GACF,CACR,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,GAA0B,EAAE;IAC5E,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,OAAO,CACL,iBAAQ,SAAS,EAAC,8CAA8C,YAC9D,aACE,SAAS,EAAC,kBAAkB,EAC5B,KAAK,EAAE,EAAE,KAAK,EAAE,gCAAgC,EAAE,OAAO,EAAE,IAAI,EAAE,2BAEtD,GAAG,EACd,YACE,IAAI,EAAE,oBAAoB,EAC1B,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,qBAAqB,EACzB,SAAS,EAAC,+CAA+C,0BAGvD,IACF,GACG,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createMetadata — generates Next.js Metadata from a SiteIdentity.
|
|
3
|
+
*
|
|
4
|
+
* The application calls this with its own identity:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { createMetadata } from '@substrate-platform/site/metadata';
|
|
8
|
+
*
|
|
9
|
+
* export const metadata = createMetadata({
|
|
10
|
+
* name: 'My Site',
|
|
11
|
+
* url: 'https://example.com',
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* The returned Metadata uses the site name as the default title and
|
|
16
|
+
* creates a `%s — Site Name` template for per-page titles.
|
|
17
|
+
*/
|
|
18
|
+
import type { SiteIdentity } from '@substrate-platform/contracts';
|
|
19
|
+
import type { Metadata } from 'next';
|
|
20
|
+
export declare function createMetadata(identity: SiteIdentity): Metadata;
|
|
21
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAErC,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,QAAQ,CAY/D"}
|
package/dist/metadata.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createMetadata — generates Next.js Metadata from a SiteIdentity.
|
|
3
|
+
*
|
|
4
|
+
* The application calls this with its own identity:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { createMetadata } from '@substrate-platform/site/metadata';
|
|
8
|
+
*
|
|
9
|
+
* export const metadata = createMetadata({
|
|
10
|
+
* name: 'My Site',
|
|
11
|
+
* url: 'https://example.com',
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* The returned Metadata uses the site name as the default title and
|
|
16
|
+
* creates a `%s — Site Name` template for per-page titles.
|
|
17
|
+
*/
|
|
18
|
+
export function createMetadata(identity) {
|
|
19
|
+
return {
|
|
20
|
+
title: {
|
|
21
|
+
default: identity.name,
|
|
22
|
+
template: `%s — ${identity.name}`,
|
|
23
|
+
},
|
|
24
|
+
metadataBase: new URL(identity.url),
|
|
25
|
+
openGraph: {
|
|
26
|
+
title: identity.name,
|
|
27
|
+
type: 'website',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,MAAM,UAAU,cAAc,CAAC,QAAsB;IACnD,OAAO;QACL,KAAK,EAAE;YACL,OAAO,EAAE,QAAQ,CAAC,IAAI;YACtB,QAAQ,EAAE,QAAQ,QAAQ,CAAC,IAAI,EAAE;SAClC;QACD,YAAY,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QACnC,SAAS,EAAE;YACT,KAAK,EAAE,QAAQ,CAAC,IAAI;YACpB,IAAI,EAAE,SAAS;SAChB;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paint-registrar.d.ts","sourceRoot":"","sources":["../src/paint-registrar.tsx"],"names":[],"mappings":"AASA,wBAAgB,cAAc,SAM7B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers Houdini Paint Worklets on mount.
|
|
3
|
+
* Renders nothing — it's a side-effect-only component.
|
|
4
|
+
*/
|
|
5
|
+
'use client';
|
|
6
|
+
import { registerPaintWorklets } from '@substrate-platform/ui';
|
|
7
|
+
import { useEffect } from 'react';
|
|
8
|
+
export function PaintRegistrar() {
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
registerPaintWorklets();
|
|
11
|
+
}, []);
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=paint-registrar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paint-registrar.js","sourceRoot":"","sources":["../src/paint-registrar.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,YAAY,CAAC;AAEb,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,MAAM,UAAU,cAAc;IAC5B,SAAS,CAAC,GAAG,EAAE;QACb,qBAAqB,EAAE,CAAC;IAC1B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type QueryClient } from '@tanstack/react-query';
|
|
2
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
3
|
+
export type SubstrateProvidersProps = {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
queryClient: QueryClient;
|
|
6
|
+
/**
|
|
7
|
+
* Optional outer provider component (e.g. `trpc.Provider`).
|
|
8
|
+
* Receives `outerProps` plus `children`.
|
|
9
|
+
* Omit for static sites that only need React Query.
|
|
10
|
+
*/
|
|
11
|
+
outerProvider?: ComponentType<Record<string, unknown> & {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}>;
|
|
14
|
+
/** Props to pass to `outerProvider` (excluding children). */
|
|
15
|
+
outerProps?: Record<string, unknown>;
|
|
16
|
+
};
|
|
17
|
+
export declare function SubstrateProviders({ children, queryClient, outerProvider, outerProps, }: SubstrateProvidersProps): import("react").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../src/providers.tsx"],"names":[],"mappings":"AAgCA,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,SAAS,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;IACzB;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACjF,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,WAAW,EACX,aAAa,EACb,UAAU,GACX,EAAE,uBAAuB,+BASzB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubstrateProviders — React Query provider wrapper with optional outer provider.
|
|
3
|
+
*
|
|
4
|
+
* The platform provides the shell; the application provides the
|
|
5
|
+
* configured providers. This keeps the platform free of any knowledge
|
|
6
|
+
* about API endpoints, auth, or transport.
|
|
7
|
+
*
|
|
8
|
+
* ## With tRPC
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { SubstrateProviders } from '@substrate-platform/site/providers';
|
|
12
|
+
* import { trpc, getTrpcLink, createQueryClient } from './lib/trpc.js';
|
|
13
|
+
*
|
|
14
|
+
* <SubstrateProviders
|
|
15
|
+
* queryClient={queryClient}
|
|
16
|
+
* outerProvider={trpc.Provider}
|
|
17
|
+
* outerProps={{ client: trpcClient }}
|
|
18
|
+
* >
|
|
19
|
+
* {children}
|
|
20
|
+
* </SubstrateProviders>
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* ## Without tRPC (static site)
|
|
24
|
+
*
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <SubstrateProviders queryClient={queryClient}>
|
|
27
|
+
* {children}
|
|
28
|
+
* </SubstrateProviders>
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
'use client';
|
|
32
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
33
|
+
import { QueryClientProvider } from '@tanstack/react-query';
|
|
34
|
+
export function SubstrateProviders({ children, queryClient, outerProvider, outerProps, }) {
|
|
35
|
+
const inner = _jsx(QueryClientProvider, { client: queryClient, children: children });
|
|
36
|
+
if (outerProvider) {
|
|
37
|
+
const Outer = outerProvider;
|
|
38
|
+
return _jsx(Outer, { ...(outerProps ?? {}), children: inner });
|
|
39
|
+
}
|
|
40
|
+
return inner;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../src/providers.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,YAAY,CAAC;;AAEb,OAAO,EAAoB,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAgB9E,MAAM,UAAU,kBAAkB,CAAC,EACjC,QAAQ,EACR,WAAW,EACX,aAAa,EACb,UAAU,GACc;IACxB,MAAM,KAAK,GAAG,KAAC,mBAAmB,IAAC,MAAM,EAAE,WAAW,YAAG,QAAQ,GAAuB,CAAC;IAEzF,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,aAAa,CAAC;QAC5B,OAAO,KAAC,KAAK,OAAK,CAAC,UAAU,IAAI,EAAE,CAAC,YAAG,KAAK,GAAS,CAAC;IACxD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/shells.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ReactElement } from 'react';
|
|
2
|
+
export type ErrorShellProps = {
|
|
3
|
+
error: Error & {
|
|
4
|
+
digest?: string;
|
|
5
|
+
};
|
|
6
|
+
reset: () => void;
|
|
7
|
+
};
|
|
8
|
+
export declare function SubstrateError({ error, reset }: ErrorShellProps): ReactElement;
|
|
9
|
+
export declare function SubstrateGlobalError({ error, reset }: ErrorShellProps): ReactElement;
|
|
10
|
+
export declare function SubstrateLoading(): ReactElement;
|
|
11
|
+
export declare function SubstrateNotFound(): ReactElement;
|
|
12
|
+
//# sourceMappingURL=shells.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shells.d.ts","sourceRoot":"","sources":["../src/shells.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,OAAO,CAAC;AAIrD,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,KAAK,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAIF,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,eAAe,GAAG,YAAY,CAqB9E;AAID,wBAAgB,oBAAoB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,eAAe,GAAG,YAAY,CAyBpF;AAID,wBAAgB,gBAAgB,IAAI,YAAY,CAmB/C;AAID,wBAAgB,iBAAiB,IAAI,YAAY,CAehD"}
|
package/dist/shells.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error / Loading / Not-Found shells — generic, application-agnostic
|
|
3
|
+
* UI for Next.js convention files.
|
|
4
|
+
*
|
|
5
|
+
* Applications re-export these from their `app/error.tsx`,
|
|
6
|
+
* `app/global-error.tsx`, `app/loading.tsx`, and `app/not-found.tsx`.
|
|
7
|
+
*
|
|
8
|
+
* ```tsx
|
|
9
|
+
* // app/error.tsx
|
|
10
|
+
* export { SubstrateError as default } from '@substrate-platform/site/shells';
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
'use client';
|
|
14
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
15
|
+
import { useEffect } from 'react';
|
|
16
|
+
// ── Error boundary ──────────────────────────────────────────────────
|
|
17
|
+
export function SubstrateError({ error, reset }) {
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
console.error('[Route Error]', error);
|
|
20
|
+
}, [error]);
|
|
21
|
+
return (_jsx("div", { className: "mx-auto flex min-h-screen max-w-2xl flex-col items-center justify-center px-6", children: _jsxs("div", { className: "substrate-glass-card p-8 text-center", children: [_jsx("h2", { className: "text-2xl font-semibold text-text-primary", children: "Something went wrong" }), _jsx("p", { className: "mt-3 text-sm text-text-secondary", children: error.message || 'An unexpected error occurred while rendering this page.' }), error.digest && (_jsxs("p", { className: "mt-2 font-mono text-xs text-text-tertiary", children: ["Error ID: ", error.digest] })), _jsx("button", { type: "button", className: "btn btn-accent mt-6", onClick: reset, children: "Try again" })] }) }));
|
|
22
|
+
}
|
|
23
|
+
// ── Global error boundary ───────────────────────────────────────────
|
|
24
|
+
export function SubstrateGlobalError({ error, reset }) {
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
console.error('[Global Error]', error);
|
|
27
|
+
}, [error]);
|
|
28
|
+
return (_jsx("html", { lang: "en", children: _jsx("body", { children: _jsx("div", { className: "mx-auto flex min-h-screen max-w-2xl flex-col items-center justify-center px-6", children: _jsxs("div", { className: "substrate-glass-card p-8 text-center", children: [_jsx("h2", { className: "text-2xl font-semibold text-text-primary", children: "Application error" }), _jsx("p", { className: "mt-3 text-sm text-text-secondary", children: error.message || 'A critical error occurred while rendering this page.' }), error.digest && (_jsxs("p", { className: "mt-2 font-mono text-xs text-text-tertiary", children: ["Error ID: ", error.digest] })), _jsx("button", { type: "button", className: "btn btn-accent mt-6", onClick: reset, children: "Try again" })] }) }) }) }));
|
|
29
|
+
}
|
|
30
|
+
// ── Loading shell ───────────────────────────────────────────────────
|
|
31
|
+
export function SubstrateLoading() {
|
|
32
|
+
return (_jsx("div", { className: "mx-auto min-h-screen max-w-5xl px-6 py-24", "aria-busy": "true", children: _jsxs("div", { className: "animate-pulse", children: [_jsxs("div", { className: "mb-20", children: [_jsx("div", { className: "h-12 w-32 rounded-lg bg-text-primary/10" }), _jsx("div", { className: "mt-4 h-6 w-80 rounded-lg bg-text-primary/5" })] }), _jsx("div", { className: "grid gap-6 sm:grid-cols-3", children: [0, 1, 2].map((i) => (_jsxs("div", { className: "substrate-glass-card h-32 p-6", children: [_jsx("div", { className: "h-5 w-24 rounded bg-text-primary/10" }), _jsx("div", { className: "mt-3 h-4 w-40 rounded bg-text-primary/5" })] }, i))) })] }) }));
|
|
33
|
+
}
|
|
34
|
+
// ── Not-found shell ─────────────────────────────────────────────────
|
|
35
|
+
export function SubstrateNotFound() {
|
|
36
|
+
return (_jsx("main", { className: "mx-auto flex min-h-screen max-w-2xl flex-col items-center justify-center px-6", children: _jsxs("div", { className: "substrate-glass-card p-8 text-center", children: [_jsx("p", { className: "font-mono text-sm text-text-tertiary", children: "404" }), _jsx("h1", { className: "mt-2 text-3xl font-semibold text-text-primary", children: "Page not found" }), _jsx("p", { className: "mt-3 text-sm text-text-secondary", children: "The page you're looking for doesn't exist or has been moved." }), _jsx("a", { href: "/", className: "btn btn-accent mt-6 inline-block", children: "Back to home" })] }) }));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=shells.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shells.js","sourceRoot":"","sources":["../src/shells.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,YAAY,CAAC;;AAEb,OAAO,EAAqB,SAAS,EAAE,MAAM,OAAO,CAAC;AASrD,uEAAuE;AAEvE,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,KAAK,EAAmB;IAC9D,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO,CACL,cAAK,SAAS,EAAC,+EAA+E,YAC5F,eAAK,SAAS,EAAC,sCAAsC,aACnD,aAAI,SAAS,EAAC,0CAA0C,qCAA0B,EAClF,YAAG,SAAS,EAAC,kCAAkC,YAC5C,KAAK,CAAC,OAAO,IAAI,yDAAyD,GACzE,EACH,KAAK,CAAC,MAAM,IAAI,CACf,aAAG,SAAS,EAAC,2CAA2C,2BAAY,KAAK,CAAC,MAAM,IAAK,CACtF,EACD,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,qBAAqB,EAAC,OAAO,EAAE,KAAK,0BAE3D,IACL,GACF,CACP,CAAC;AACJ,CAAC;AAED,uEAAuE;AAEvE,MAAM,UAAU,oBAAoB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAmB;IACpE,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO,CACL,eAAM,IAAI,EAAC,IAAI,YACb,yBACE,cAAK,SAAS,EAAC,+EAA+E,YAC5F,eAAK,SAAS,EAAC,sCAAsC,aACnD,aAAI,SAAS,EAAC,0CAA0C,kCAAuB,EAC/E,YAAG,SAAS,EAAC,kCAAkC,YAC5C,KAAK,CAAC,OAAO,IAAI,sDAAsD,GACtE,EACH,KAAK,CAAC,MAAM,IAAI,CACf,aAAG,SAAS,EAAC,2CAA2C,2BAAY,KAAK,CAAC,MAAM,IAAK,CACtF,EACD,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,qBAAqB,EAAC,OAAO,EAAE,KAAK,0BAE3D,IACL,GACF,GACD,GACF,CACR,CAAC;AACJ,CAAC;AAED,uEAAuE;AAEvE,MAAM,UAAU,gBAAgB;IAC9B,OAAO,CACL,cAAK,SAAS,EAAC,2CAA2C,eAAW,MAAM,YACzE,eAAK,SAAS,EAAC,eAAe,aAC5B,eAAK,SAAS,EAAC,OAAO,aACpB,cAAK,SAAS,EAAC,yCAAyC,GAAG,EAC3D,cAAK,SAAS,EAAC,4CAA4C,GAAG,IAC1D,EACN,cAAK,SAAS,EAAC,2BAA2B,YACvC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACpB,eAAa,SAAS,EAAC,+BAA+B,aACpD,cAAK,SAAS,EAAC,qCAAqC,GAAG,EACvD,cAAK,SAAS,EAAC,yCAAyC,GAAG,KAFnD,CAAC,CAGL,CACP,CAAC,GACE,IACF,GACF,CACP,CAAC;AACJ,CAAC;AAED,uEAAuE;AAEvE,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CACL,eAAM,SAAS,EAAC,+EAA+E,YAC7F,eAAK,SAAS,EAAC,sCAAsC,aACnD,YAAG,SAAS,EAAC,sCAAsC,oBAAQ,EAC3D,aAAI,SAAS,EAAC,+CAA+C,+BAAoB,EACjF,YAAG,SAAS,EAAC,kCAAkC,6EAE3C,EACJ,YAAG,IAAI,EAAC,GAAG,EAAC,SAAS,EAAC,kCAAkC,6BAEpD,IACA,GACD,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smooth-scroll.d.ts","sourceRoot":"","sources":["../src/smooth-scroll.tsx"],"names":[],"mappings":"AASA,wBAAgB,YAAY,SAO3B"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmoothScroll — initializes Lenis smooth scrolling on mount.
|
|
3
|
+
* Renders nothing — it's a side-effect-only component.
|
|
4
|
+
*/
|
|
5
|
+
'use client';
|
|
6
|
+
import { useEffect } from 'react';
|
|
7
|
+
import { initSmoothScroll } from './animations.js';
|
|
8
|
+
export function SmoothScroll() {
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const cleanup = initSmoothScroll();
|
|
11
|
+
return cleanup;
|
|
12
|
+
}, []);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=smooth-scroll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smooth-scroll.js","sourceRoot":"","sources":["../src/smooth-scroll.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,UAAU,YAAY;IAC1B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ThemeScript — injects the theme class before hydration to prevent
|
|
3
|
+
* flash-of-incorrect-theme (FOIT).
|
|
4
|
+
*
|
|
5
|
+
* Place this inside <head> in your root layout:
|
|
6
|
+
*
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <head>
|
|
9
|
+
* <ThemeScript />
|
|
10
|
+
* </head>
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Reads the `theme` value from localStorage. Defaults to `dark` if
|
|
14
|
+
* no preference is stored. No application-specific logic — the theme
|
|
15
|
+
* token name and default are configurable via props.
|
|
16
|
+
*/
|
|
17
|
+
import type { ReactElement } from 'react';
|
|
18
|
+
export declare function ThemeScript(options?: {
|
|
19
|
+
/** CSS custom property or class name prefix. */
|
|
20
|
+
attribute?: 'class' | 'data-theme';
|
|
21
|
+
/** Default theme when no localStorage entry exists. */
|
|
22
|
+
defaultTheme?: string;
|
|
23
|
+
/** localStorage key. */
|
|
24
|
+
storageKey?: string;
|
|
25
|
+
}): ReactElement;
|
|
26
|
+
//# sourceMappingURL=theme-script.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-script.d.ts","sourceRoot":"","sources":["../src/theme-script.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE;IACpC,gDAAgD;IAChD,SAAS,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;IACnC,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,YAAY,CAWf"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function ThemeScript(options) {
|
|
3
|
+
const { attribute = 'class', defaultTheme = 'dark', storageKey = 'theme' } = options ?? {};
|
|
4
|
+
const script = `(function(){try{var t=localStorage.getItem('${storageKey}')||'${defaultTheme}';document.documentElement.setAttribute('${attribute}',t)}catch(e){document.documentElement.setAttribute('${attribute}','${defaultTheme}')}})()`;
|
|
5
|
+
return (_jsx("script", {
|
|
6
|
+
// biome-ignore lint/security/noDangerouslySetInnerHtml: static string, no user input
|
|
7
|
+
dangerouslySetInnerHTML: { __html: script } }));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=theme-script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-script.js","sourceRoot":"","sources":["../src/theme-script.tsx"],"names":[],"mappings":";AAkBA,MAAM,UAAU,WAAW,CAAC,OAO3B;IACC,MAAM,EAAE,SAAS,GAAG,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,UAAU,GAAG,OAAO,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAE3F,MAAM,MAAM,GAAG,+CAA+C,UAAU,QAAQ,YAAY,4CAA4C,SAAS,wDAAwD,SAAS,MAAM,YAAY,SAAS,CAAC;IAE9O,OAAO,CACL;QACE,qFAAqF;QACrF,uBAAuB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAC3C,CACH,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@substrate-platform/site",
|
|
3
|
+
"version": "0.1.1-canary.0",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./providers": {
|
|
14
|
+
"import": "./dist/providers.js",
|
|
15
|
+
"types": "./dist/providers.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./layout": {
|
|
18
|
+
"import": "./dist/layout.js",
|
|
19
|
+
"types": "./dist/layout.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./shells": {
|
|
22
|
+
"import": "./dist/shells.js",
|
|
23
|
+
"types": "./dist/shells.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./metadata": {
|
|
26
|
+
"import": "./dist/metadata.js",
|
|
27
|
+
"types": "./dist/metadata.d.ts"
|
|
28
|
+
},
|
|
29
|
+
"./instrumentation": {
|
|
30
|
+
"import": "./dist/instrumentation.js",
|
|
31
|
+
"types": "./dist/instrumentation.d.ts"
|
|
32
|
+
},
|
|
33
|
+
"./animations": {
|
|
34
|
+
"import": "./dist/animations.js",
|
|
35
|
+
"types": "./dist/animations.d.ts"
|
|
36
|
+
},
|
|
37
|
+
"./smooth-scroll": {
|
|
38
|
+
"import": "./dist/smooth-scroll.js",
|
|
39
|
+
"types": "./dist/smooth-scroll.d.ts"
|
|
40
|
+
},
|
|
41
|
+
"./paint-registrar": {
|
|
42
|
+
"import": "./dist/paint-registrar.js",
|
|
43
|
+
"types": "./dist/paint-registrar.d.ts"
|
|
44
|
+
},
|
|
45
|
+
"./theme-script": {
|
|
46
|
+
"import": "./dist/theme-script.js",
|
|
47
|
+
"types": "./dist/theme-script.d.ts"
|
|
48
|
+
},
|
|
49
|
+
"./globals.css": "./src/globals.css"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsc --project tsconfig.build.json && bun run ../../scripts/fix-import-extensions.ts dist",
|
|
53
|
+
"lint": "biome check src",
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"test": "vitest run --passWithNoTests",
|
|
56
|
+
"clean": "rm -rf dist .turbo"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@substrate-platform/ui": "workspace:*",
|
|
60
|
+
"@substrate-platform/contracts": "workspace:*",
|
|
61
|
+
"@substrate-platform/config": "workspace:*",
|
|
62
|
+
"@substrate-platform/observability": "workspace:*"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"next": "^16.0.0",
|
|
66
|
+
"react": "^19.0.0",
|
|
67
|
+
"react-dom": "^19.0.0",
|
|
68
|
+
"gsap": "^3.13.0",
|
|
69
|
+
"lenis": "^1.1.18",
|
|
70
|
+
"@tanstack/react-query": "^5.65.0"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@types/react": "^19.2.17",
|
|
74
|
+
"@types/react-dom": "^19.2.3"
|
|
75
|
+
},
|
|
76
|
+
"files": [
|
|
77
|
+
"dist/**",
|
|
78
|
+
"README.md",
|
|
79
|
+
"LICENSE",
|
|
80
|
+
"src/**/*.css"
|
|
81
|
+
]
|
|
82
|
+
}
|
package/src/globals.css
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @substrate-platform/site — platform global styles.
|
|
3
|
+
*
|
|
4
|
+
* ## CSS Package Boundary Contract
|
|
5
|
+
*
|
|
6
|
+
* The CSS layering is explicitly defined as three tiers:
|
|
7
|
+
*
|
|
8
|
+
* 1. @substrate-platform/ui/styles.css
|
|
9
|
+
* Design tokens (--substrate-*) and component styles (.substrate-*).
|
|
10
|
+
* Uses relative @import only (./tokens.css, ./theme.css).
|
|
11
|
+
* Zero external module dependencies.
|
|
12
|
+
*
|
|
13
|
+
* 2. @substrate-platform/site/globals.css (THIS FILE)
|
|
14
|
+
* Tailwind v4 @theme bridge: maps --substrate-* tokens into
|
|
15
|
+
* Tailwind's --color-* / --font-* / --radius-* namespace.
|
|
16
|
+
* Platform utility classes (.glass, .text-gradient, paint worklets).
|
|
17
|
+
* Container queries and anchor positioning.
|
|
18
|
+
* Does NOT @import "tailwindcss" — that is the consumer's responsibility.
|
|
19
|
+
*
|
|
20
|
+
* 3. Application globals.css
|
|
21
|
+
* `@import "tailwindcss"` — the Tailwind v4 entry point.
|
|
22
|
+
* Application-specific tokens (--accent-primary, --bg-primary, etc.).
|
|
23
|
+
* Application-specific styles, layouts, and overrides.
|
|
24
|
+
*
|
|
25
|
+
* ## Consumer CSS Template
|
|
26
|
+
*
|
|
27
|
+
* A consumer's globals.css should look like:
|
|
28
|
+
*
|
|
29
|
+
* @import "tailwindcss";
|
|
30
|
+
* @import "@substrate-platform/ui/styles.css";
|
|
31
|
+
* @import "@substrate-platform/site/globals.css"; // optional
|
|
32
|
+
*
|
|
33
|
+
* :root {
|
|
34
|
+
* --accent-primary: #your-brand-color;
|
|
35
|
+
* --bg-primary: #your-bg;
|
|
36
|
+
* ...
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* Or, if the consumer does not need the Tailwind theme bridge:
|
|
40
|
+
*
|
|
41
|
+
* @import "tailwindcss";
|
|
42
|
+
* @import "@substrate-platform/ui/styles.css";
|
|
43
|
+
*
|
|
44
|
+
* :root { ... }
|
|
45
|
+
*
|
|
46
|
+
* ## Why @substrate-platform/site/globals.css does NOT @import "tailwindcss"
|
|
47
|
+
*
|
|
48
|
+
* Tailwind v4's `@import "tailwindcss"` is processed by the
|
|
49
|
+
* @tailwindcss/postcss plugin, which runs in the consumer project's
|
|
50
|
+
* PostCSS environment. If a platform CSS file contains this directive,
|
|
51
|
+
* Turbopack's CSS module resolver attempts to resolve "tailwindcss" from
|
|
52
|
+
* the platform package's directory — but tailwindcss is installed in the
|
|
53
|
+
* consumer's node_modules, not the platform package's. This causes a
|
|
54
|
+
* "Can't resolve 'tailwindcss'" build error.
|
|
55
|
+
*
|
|
56
|
+
* The fix is architectural: the Tailwind entry directive belongs in the
|
|
57
|
+
* consumer's CSS, where the PostCSS environment can resolve it correctly.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/* ── Tailwind v4 theme bridge ───────────────────────────────────────
|
|
61
|
+
*
|
|
62
|
+
* Maps the platform's --substrate-* design tokens into Tailwind v4's
|
|
63
|
+
* --color-* / --font-* / --radius-* namespace, so Tailwind utility
|
|
64
|
+
* classes (bg-bg-base, text-text-primary, etc.) work with the platform's
|
|
65
|
+
* design system.
|
|
66
|
+
*
|
|
67
|
+
* This block does not require @import "tailwindcss" — it only declares
|
|
68
|
+
* custom properties that Tailwind's @theme processor picks up if the
|
|
69
|
+
* consumer has imported Tailwind elsewhere in the CSS graph.
|
|
70
|
+
*/
|
|
71
|
+
@theme {
|
|
72
|
+
--font-sans: var(--font-sans);
|
|
73
|
+
--font-mono: var(--font-mono);
|
|
74
|
+
|
|
75
|
+
--color-accent: var(--color-accent);
|
|
76
|
+
--color-accent-glow: var(--color-accent-glow);
|
|
77
|
+
|
|
78
|
+
--color-bg-base: var(--substrate-bg-base);
|
|
79
|
+
--color-bg-secondary: var(--substrate-bg-secondary);
|
|
80
|
+
--color-bg-muted: var(--substrate-bg-muted);
|
|
81
|
+
--color-bg-elevated: var(--substrate-bg-elevated);
|
|
82
|
+
|
|
83
|
+
--color-text-primary: var(--substrate-text-primary);
|
|
84
|
+
--color-text-secondary: var(--substrate-text-secondary);
|
|
85
|
+
--color-text-tertiary: var(--substrate-text-tertiary);
|
|
86
|
+
--color-text-muted: var(--substrate-text-muted);
|
|
87
|
+
|
|
88
|
+
--color-border-default: var(--substrate-border-default);
|
|
89
|
+
--color-border-subtle: var(--substrate-border-subtle);
|
|
90
|
+
--color-border-strong: var(--substrate-border-strong);
|
|
91
|
+
|
|
92
|
+
--color-danger: var(--substrate-color-danger);
|
|
93
|
+
--color-warning: var(--substrate-color-warning);
|
|
94
|
+
--color-success: var(--substrate-color-success);
|
|
95
|
+
--color-info: var(--substrate-color-info);
|
|
96
|
+
|
|
97
|
+
--radius-card: var(--substrate-card-radius);
|
|
98
|
+
--radius-button: var(--substrate-button-radius);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* ── Platform base styles ─────────────────────────────────────────── */
|
|
102
|
+
|
|
103
|
+
@layer base {
|
|
104
|
+
body {
|
|
105
|
+
background: var(--substrate-bg-base);
|
|
106
|
+
color: var(--substrate-text-primary);
|
|
107
|
+
font-family: var(--font-sans);
|
|
108
|
+
-webkit-font-smoothing: antialiased;
|
|
109
|
+
text-rendering: optimizeLegibility;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* View Transitions API */
|
|
113
|
+
::view-transition-old(root),
|
|
114
|
+
::view-transition-new(root) {
|
|
115
|
+
animation-duration: 0.3s;
|
|
116
|
+
animation-timing-function: var(--substrate-easing-spring);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@layer utilities {
|
|
121
|
+
.glass {
|
|
122
|
+
backdrop-filter: var(--substrate-glass-blur);
|
|
123
|
+
-webkit-backdrop-filter: var(--substrate-glass-blur);
|
|
124
|
+
}
|
|
125
|
+
.text-gradient {
|
|
126
|
+
background: linear-gradient(135deg, var(--color-accent), var(--substrate-color-info));
|
|
127
|
+
-webkit-background-clip: text;
|
|
128
|
+
background-clip: text;
|
|
129
|
+
-webkit-text-fill-color: transparent;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* ── Houdini Paint Worklet ── */
|
|
133
|
+
.paint-noise {
|
|
134
|
+
background-image: paint(substrate-noise);
|
|
135
|
+
background-color: var(--substrate-bg-elevated);
|
|
136
|
+
}
|
|
137
|
+
.paint-mesh {
|
|
138
|
+
background-image: paint(substrate-mesh);
|
|
139
|
+
background-color: var(--substrate-bg-base);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
144
|
+
CSS Container Queries
|
|
145
|
+
═══════════════════════════════════════════════════════════════ */
|
|
146
|
+
|
|
147
|
+
.card-container {
|
|
148
|
+
container-type: inline-size;
|
|
149
|
+
container-name: card;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.sidebar-layout {
|
|
153
|
+
container-type: inline-size;
|
|
154
|
+
container-name: sidebar;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@container card (min-width: 400px) {
|
|
158
|
+
.card-grid {
|
|
159
|
+
grid-template-columns: 1fr 1fr;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@container card (min-width: 640px) {
|
|
164
|
+
.card-grid {
|
|
165
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@container sidebar (max-width: 768px) {
|
|
170
|
+
.sidebar-nav {
|
|
171
|
+
display: none;
|
|
172
|
+
}
|
|
173
|
+
.sidebar-toggle {
|
|
174
|
+
display: block;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@container sidebar (min-width: 769px) {
|
|
179
|
+
.sidebar-toggle {
|
|
180
|
+
display: none;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
185
|
+
CSS Anchor Positioning
|
|
186
|
+
═══════════════════════════════════════════════════════════════ */
|
|
187
|
+
|
|
188
|
+
.anchor-tooltip {
|
|
189
|
+
anchor-name: --tooltip-anchor;
|
|
190
|
+
position: fixed;
|
|
191
|
+
position-anchor: --tooltip-anchor;
|
|
192
|
+
position-area: top span-left;
|
|
193
|
+
margin-bottom: 8px;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.anchor-popover {
|
|
197
|
+
anchor-name: --popover-anchor;
|
|
198
|
+
position: fixed;
|
|
199
|
+
position-anchor: --popover-anchor;
|
|
200
|
+
position-area: bottom span-right;
|
|
201
|
+
margin-top: 8px;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.anchor-dropdown {
|
|
205
|
+
anchor-name: --dropdown-anchor;
|
|
206
|
+
position: fixed;
|
|
207
|
+
position-anchor: --dropdown-anchor;
|
|
208
|
+
position-area: bottom span-left;
|
|
209
|
+
margin-top: 4px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
@supports not (anchor-name: --test) {
|
|
213
|
+
.anchor-tooltip,
|
|
214
|
+
.anchor-popover,
|
|
215
|
+
.anchor-dropdown {
|
|
216
|
+
position: absolute;
|
|
217
|
+
top: 100%;
|
|
218
|
+
left: 0;
|
|
219
|
+
}
|
|
220
|
+
}
|