@rizom/site-rizom 0.2.0-alpha.142
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/index.d.ts +135 -0
- package/dist/index.js +31089 -0
- package/dist/index.js.map +259 -0
- package/package.json +54 -0
- package/src/content.ts +9 -0
- package/src/contracts.ts +157 -0
- package/src/create-site.ts +108 -0
- package/src/index.ts +63 -0
- package/src/runtime/base-site.ts +13 -0
- package/src/runtime/boot/boot.boot.d.ts +2 -0
- package/src/runtime/boot/boot.boot.js +83 -0
- package/src/runtime/canvases/constellation.canvas.d.ts +2 -0
- package/src/runtime/canvases/constellation.canvas.js +307 -0
- package/src/runtime/canvases/prelude.canvas.d.ts +2 -0
- package/src/runtime/canvases/prelude.canvas.js +193 -0
- package/src/runtime/canvases/products.canvas.d.ts +2 -0
- package/src/runtime/canvases/roots.canvas.d.ts +2 -0
- package/src/runtime/canvases/roots.canvas.js +358 -0
- package/src/runtime/canvases/tree.canvas.d.ts +2 -0
- package/src/runtime/canvases/tree.canvas.js +544 -0
- package/src/runtime/default-layout.tsx +10 -0
- package/src/runtime/index.ts +8 -0
- package/src/runtime/plugin.ts +147 -0
- package/src/ui/Badge.tsx +14 -0
- package/src/ui/Button.tsx +56 -0
- package/src/ui/Divider.tsx +12 -0
- package/src/ui/Footer.tsx +76 -0
- package/src/ui/Header.tsx +45 -0
- package/src/ui/Section.tsx +22 -0
- package/src/ui/SideNav.tsx +22 -0
- package/src/ui/cn.ts +1 -0
- package/src/ui/external-link.ts +8 -0
- package/src/ui/frame.tsx +28 -0
- package/src/ui/highlighted-text.tsx +45 -0
- package/src/ui/index.ts +21 -0
- package/src/ui/site-info-links.ts +24 -0
- package/src/ui/types.ts +6 -0
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rizom/site-rizom",
|
|
3
|
+
"version": "0.2.0-alpha.142",
|
|
4
|
+
"description": "Shared Rizom site core — structural base for rizom.ai, rizom.foundation, and rizom.work",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "bun scripts/build.ts",
|
|
20
|
+
"lint": "eslint src scripts/build.ts --max-warnings 0",
|
|
21
|
+
"lint:fix": "eslint src scripts/build.ts --max-warnings 0 --fix",
|
|
22
|
+
"postpack": "publish-manifest restore",
|
|
23
|
+
"prepack": "publish-manifest prepare",
|
|
24
|
+
"prepublishOnly": "bun scripts/build.ts",
|
|
25
|
+
"test": "bun test",
|
|
26
|
+
"typecheck": "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@rizom/site": "0.2.0-alpha.142",
|
|
30
|
+
"clsx": "^2.1.0",
|
|
31
|
+
"preact": "^10.27.2",
|
|
32
|
+
"tailwind-merge": "^3.6.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/rizom-ai/brains.git",
|
|
40
|
+
"directory": "sites/rizom"
|
|
41
|
+
},
|
|
42
|
+
"license": "Apache-2.0",
|
|
43
|
+
"author": "Yeehaa <yeehaa@rizom.ai> (https://rizom.ai)",
|
|
44
|
+
"homepage": "https://github.com/rizom-ai/brains/tree/main/sites/rizom#readme",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/rizom-ai/brains/issues"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"bun": ">=1.3.3"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@rizom/brain": ">=0.2.0-alpha.141 <0.3.0"
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/content.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createSiteContentTemplates as createInternalSiteContentTemplates } from "@brains/site-composition";
|
|
2
|
+
import type { SiteContentDefinition } from "@rizom/site";
|
|
3
|
+
import type { Template } from "./contracts";
|
|
4
|
+
|
|
5
|
+
export function createSiteContentTemplates(
|
|
6
|
+
definition: SiteContentDefinition,
|
|
7
|
+
): Record<string, Template> {
|
|
8
|
+
return createInternalSiteContentTemplates(definition);
|
|
9
|
+
}
|
package/src/contracts.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ComponentType,
|
|
3
|
+
EntityDisplayEntry,
|
|
4
|
+
RouteDefinitionInput,
|
|
5
|
+
RuntimeScript,
|
|
6
|
+
SiteContentDefinition,
|
|
7
|
+
SiteLayoutInfo,
|
|
8
|
+
UserPermissionLevel,
|
|
9
|
+
} from "@rizom/site";
|
|
10
|
+
import type { ComponentChildren } from "preact";
|
|
11
|
+
|
|
12
|
+
export type {
|
|
13
|
+
ComponentType,
|
|
14
|
+
EntityDisplayEntry,
|
|
15
|
+
NavigationItem,
|
|
16
|
+
NavigationMetadata,
|
|
17
|
+
NavigationSlot,
|
|
18
|
+
RizomBrandSuffix,
|
|
19
|
+
RizomFooterTagline,
|
|
20
|
+
RizomLayoutProps,
|
|
21
|
+
RizomLink,
|
|
22
|
+
RizomSideNavItem,
|
|
23
|
+
RouteDefinition,
|
|
24
|
+
RouteDefinitionInput,
|
|
25
|
+
RuntimeScript,
|
|
26
|
+
SectionDefinition,
|
|
27
|
+
SectionDefinitionInput,
|
|
28
|
+
SiteContentArrayFieldDefinition,
|
|
29
|
+
SiteContentDefinition,
|
|
30
|
+
SiteContentEnumFieldDefinition,
|
|
31
|
+
SiteContentFieldDefinition,
|
|
32
|
+
SiteContentNumberFieldDefinition,
|
|
33
|
+
SiteContentObjectFieldDefinition,
|
|
34
|
+
SiteContentSectionDefinition,
|
|
35
|
+
SiteContentStringFieldDefinition,
|
|
36
|
+
SiteDefinition,
|
|
37
|
+
SiteDefinitionOverrides,
|
|
38
|
+
SiteLayoutInfo,
|
|
39
|
+
SiteMetadata,
|
|
40
|
+
SiteMetadataCTA,
|
|
41
|
+
SiteMetadataSection,
|
|
42
|
+
UserPermissionLevel,
|
|
43
|
+
} from "@rizom/site";
|
|
44
|
+
export { NavigationSlots } from "@rizom/site";
|
|
45
|
+
|
|
46
|
+
export type RizomThemeProfile = "product" | "editorial" | "studio";
|
|
47
|
+
|
|
48
|
+
export interface RizomRuntimeConfig {
|
|
49
|
+
themeProfile?: RizomThemeProfile;
|
|
50
|
+
theme?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface RizomPluginCapabilities {
|
|
54
|
+
tools: [];
|
|
55
|
+
resources: [];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface RizomMessageBus {
|
|
59
|
+
subscribe(
|
|
60
|
+
channel: string,
|
|
61
|
+
handler: () => Promise<{ success: boolean }>,
|
|
62
|
+
): unknown;
|
|
63
|
+
send(message: {
|
|
64
|
+
type: string;
|
|
65
|
+
sender: string;
|
|
66
|
+
payload: Record<string, unknown>;
|
|
67
|
+
}): Promise<unknown>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface RizomLogger {
|
|
71
|
+
info(message: string): void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface DataSourceRegistry {
|
|
75
|
+
register(dataSource: unknown): void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface RizomSiteShell {
|
|
79
|
+
getMessageBus(): RizomMessageBus;
|
|
80
|
+
getLogger(): RizomLogger;
|
|
81
|
+
registerTemplates(
|
|
82
|
+
templates: Record<string, unknown>,
|
|
83
|
+
namespace?: string,
|
|
84
|
+
): void;
|
|
85
|
+
getDataSourceRegistry(): DataSourceRegistry;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface SiteCompositionPlugin {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
readonly version: string;
|
|
91
|
+
readonly type: "core" | "entity" | "service" | "interface";
|
|
92
|
+
readonly packageName: string;
|
|
93
|
+
readonly description?: string | undefined;
|
|
94
|
+
readonly dependencies?: string[] | undefined;
|
|
95
|
+
register?(
|
|
96
|
+
shell: RizomSiteShell,
|
|
97
|
+
context?: unknown,
|
|
98
|
+
): Promise<RizomPluginCapabilities>;
|
|
99
|
+
ready?(): Promise<void>;
|
|
100
|
+
shutdown?(): Promise<void>;
|
|
101
|
+
requiresDaemonStartup?(): boolean;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface ContentFormatter<T = unknown> {
|
|
105
|
+
format(data: T): string;
|
|
106
|
+
parse(content: string): T;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface Template {
|
|
110
|
+
name: string;
|
|
111
|
+
description: string;
|
|
112
|
+
schema: unknown;
|
|
113
|
+
requiredPermission: UserPermissionLevel;
|
|
114
|
+
formatter?: ContentFormatter<unknown>;
|
|
115
|
+
layout?: {
|
|
116
|
+
component?: ComponentType<unknown>;
|
|
117
|
+
fullscreen?: boolean;
|
|
118
|
+
};
|
|
119
|
+
runtimeScripts?: RuntimeScript[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface DataSource {
|
|
123
|
+
id: string;
|
|
124
|
+
name: string;
|
|
125
|
+
description?: string;
|
|
126
|
+
fetch?<T>(
|
|
127
|
+
query: unknown,
|
|
128
|
+
outputSchema: unknown,
|
|
129
|
+
context: unknown,
|
|
130
|
+
): Promise<T>;
|
|
131
|
+
generate?<T>(request: unknown, schema: unknown): Promise<T>;
|
|
132
|
+
transform?<T>(content: unknown, format: string, schema: unknown): Promise<T>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface SitePackage<
|
|
136
|
+
TPluginConfig = Record<string, unknown>,
|
|
137
|
+
TPlugin extends SiteCompositionPlugin = SiteCompositionPlugin,
|
|
138
|
+
> {
|
|
139
|
+
layouts: Record<string, unknown>;
|
|
140
|
+
routes: RouteDefinitionInput[];
|
|
141
|
+
plugin?: ((config?: TPluginConfig) => TPlugin) | undefined;
|
|
142
|
+
content?: SiteContentDefinition | SiteContentDefinition[];
|
|
143
|
+
themeOverride?: string;
|
|
144
|
+
headScripts?: string[];
|
|
145
|
+
entityDisplay: Record<string, EntityDisplayEntry>;
|
|
146
|
+
staticAssets?: Record<string, string>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Keeps this module as the source-owned bridge for the current runtime shape;
|
|
150
|
+
// the author-facing layout props themselves come from @rizom/site.
|
|
151
|
+
export interface RuntimeRizomLayoutProps {
|
|
152
|
+
sections: ComponentChildren[];
|
|
153
|
+
title: string;
|
|
154
|
+
description: string;
|
|
155
|
+
path: string;
|
|
156
|
+
siteInfo: SiteLayoutInfo;
|
|
157
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { extendSite } from "@brains/site-composition";
|
|
2
|
+
import type {
|
|
3
|
+
RouteDefinitionInput,
|
|
4
|
+
SiteContentDefinition,
|
|
5
|
+
SiteDefinition,
|
|
6
|
+
} from "@rizom/site";
|
|
7
|
+
import rizomBaseSite from ".";
|
|
8
|
+
import type {
|
|
9
|
+
RizomPluginCapabilities,
|
|
10
|
+
RizomSiteShell,
|
|
11
|
+
RizomThemeProfile,
|
|
12
|
+
SitePackage,
|
|
13
|
+
} from "./contracts";
|
|
14
|
+
import { buildRizomHeadScript, RizomRuntimePlugin } from "./runtime/plugin";
|
|
15
|
+
|
|
16
|
+
interface TemplateGroup {
|
|
17
|
+
namespace: string;
|
|
18
|
+
templates: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface RizomRuntimeHooks {
|
|
22
|
+
contentNamespace: string;
|
|
23
|
+
templates?: Record<string, unknown>;
|
|
24
|
+
dataSources?: unknown[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class RizomVariantPlugin extends RizomRuntimePlugin {
|
|
28
|
+
private readonly templateGroups: TemplateGroup[];
|
|
29
|
+
private readonly dataSources: unknown[];
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
packageName: string,
|
|
33
|
+
config: Record<string, unknown>,
|
|
34
|
+
templateGroups: TemplateGroup[],
|
|
35
|
+
dataSources: unknown[] = [],
|
|
36
|
+
) {
|
|
37
|
+
super(packageName, config);
|
|
38
|
+
this.templateGroups = templateGroups;
|
|
39
|
+
this.dataSources = dataSources;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override async register(
|
|
43
|
+
shell: RizomSiteShell,
|
|
44
|
+
_context?: unknown,
|
|
45
|
+
): Promise<RizomPluginCapabilities> {
|
|
46
|
+
for (const group of this.templateGroups) {
|
|
47
|
+
shell.registerTemplates(group.templates, group.namespace);
|
|
48
|
+
}
|
|
49
|
+
for (const dataSource of this.dataSources) {
|
|
50
|
+
shell.getDataSourceRegistry().register(dataSource);
|
|
51
|
+
}
|
|
52
|
+
return { tools: [], resources: [] };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface CreateRizomSiteOptions {
|
|
57
|
+
packageName: string;
|
|
58
|
+
themeProfile: RizomThemeProfile;
|
|
59
|
+
layout: unknown;
|
|
60
|
+
routes: RouteDefinitionInput[];
|
|
61
|
+
content?: SiteContentDefinition | SiteContentDefinition[];
|
|
62
|
+
themeOverride?: string;
|
|
63
|
+
/** Advanced runtime hooks for in-repo sites that need custom template/data-source wiring. */
|
|
64
|
+
runtime?: RizomRuntimeHooks;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function buildTemplateGroups(options: CreateRizomSiteOptions): TemplateGroup[] {
|
|
68
|
+
if (!options.runtime?.templates) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
return [
|
|
72
|
+
{
|
|
73
|
+
namespace: options.runtime.contentNamespace,
|
|
74
|
+
templates: options.runtime.templates,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function createRuntimePlugin(
|
|
80
|
+
options: CreateRizomSiteOptions,
|
|
81
|
+
): SitePackage["plugin"] {
|
|
82
|
+
if (!options.runtime?.templates && !options.runtime?.dataSources?.length) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return (config?: Record<string, unknown>): RizomRuntimePlugin =>
|
|
87
|
+
new RizomVariantPlugin(
|
|
88
|
+
options.packageName,
|
|
89
|
+
{ themeProfile: options.themeProfile, ...(config ?? {}) },
|
|
90
|
+
buildTemplateGroups(options),
|
|
91
|
+
options.runtime?.dataSources,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function createRizomSite(
|
|
96
|
+
options: CreateRizomSiteOptions,
|
|
97
|
+
): SiteDefinition {
|
|
98
|
+
const plugin = createRuntimePlugin(options);
|
|
99
|
+
|
|
100
|
+
return extendSite(rizomBaseSite, {
|
|
101
|
+
layouts: { default: options.layout },
|
|
102
|
+
routes: options.routes,
|
|
103
|
+
...(options.content ? { content: options.content } : {}),
|
|
104
|
+
headScripts: [buildRizomHeadScript(options.themeProfile)],
|
|
105
|
+
...(plugin ? { plugin } : {}),
|
|
106
|
+
...(options.themeOverride ? { themeOverride: options.themeOverride } : {}),
|
|
107
|
+
});
|
|
108
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Rizom site core.
|
|
3
|
+
*
|
|
4
|
+
* This is the structural base that the app-owned Rizom variants
|
|
5
|
+
* compose from. It re-exports shared Rizom runtime and UI
|
|
6
|
+
* primitives used by the app-owned site/content layers.
|
|
7
|
+
*/
|
|
8
|
+
export {
|
|
9
|
+
DefaultRizomLayout,
|
|
10
|
+
rizomBaseSite,
|
|
11
|
+
rizomBaseSite as default,
|
|
12
|
+
} from "./runtime";
|
|
13
|
+
|
|
14
|
+
export { createRizomSite } from "./create-site";
|
|
15
|
+
export type { CreateRizomSiteOptions } from "./create-site";
|
|
16
|
+
export type { RizomThemeProfile } from "./contracts";
|
|
17
|
+
export type {
|
|
18
|
+
EntityDisplayEntry,
|
|
19
|
+
RouteDefinitionInput,
|
|
20
|
+
SectionDefinitionInput,
|
|
21
|
+
SiteContentArrayFieldDefinition,
|
|
22
|
+
SiteContentDefinition,
|
|
23
|
+
SiteContentEnumFieldDefinition,
|
|
24
|
+
SiteContentFieldDefinition,
|
|
25
|
+
SiteContentNumberFieldDefinition,
|
|
26
|
+
SiteContentObjectFieldDefinition,
|
|
27
|
+
SiteContentSectionDefinition,
|
|
28
|
+
SiteContentStringFieldDefinition,
|
|
29
|
+
SiteDefinition,
|
|
30
|
+
SiteDefinitionOverrides,
|
|
31
|
+
SiteLayoutInfo,
|
|
32
|
+
} from "@rizom/site";
|
|
33
|
+
export {
|
|
34
|
+
Badge,
|
|
35
|
+
Button,
|
|
36
|
+
Divider,
|
|
37
|
+
Footer,
|
|
38
|
+
Header,
|
|
39
|
+
RizomFrame,
|
|
40
|
+
Section,
|
|
41
|
+
SideNav,
|
|
42
|
+
socialLinksToRizomLinks,
|
|
43
|
+
renderHighlightedText,
|
|
44
|
+
GUTTER,
|
|
45
|
+
} from "./ui";
|
|
46
|
+
export type {
|
|
47
|
+
RizomBrandSuffix,
|
|
48
|
+
RizomFooterTagline,
|
|
49
|
+
RizomLayoutProps,
|
|
50
|
+
RizomLink,
|
|
51
|
+
RizomSideNavItem,
|
|
52
|
+
} from "./ui";
|
|
53
|
+
export type {
|
|
54
|
+
BadgeProps,
|
|
55
|
+
ButtonProps,
|
|
56
|
+
ButtonSize,
|
|
57
|
+
ButtonVariant,
|
|
58
|
+
DividerProps,
|
|
59
|
+
RizomFrameProps,
|
|
60
|
+
SectionProps,
|
|
61
|
+
} from "./ui";
|
|
62
|
+
export { Wordmark, Ecosystem } from "@rizom/ui";
|
|
63
|
+
export type { WordmarkProps, EcosystemCard, EcosystemContent } from "@rizom/ui";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SiteDefinition } from "@rizom/site";
|
|
2
|
+
import { DefaultRizomLayout } from "./default-layout";
|
|
3
|
+
import { buildRizomHeadScript, rizomRuntimeStaticAssets } from "./plugin";
|
|
4
|
+
|
|
5
|
+
export const rizomBaseSite: SiteDefinition = {
|
|
6
|
+
layouts: {
|
|
7
|
+
default: DefaultRizomLayout,
|
|
8
|
+
},
|
|
9
|
+
routes: [],
|
|
10
|
+
headScripts: [buildRizomHeadScript()],
|
|
11
|
+
entityDisplay: {},
|
|
12
|
+
staticAssets: rizomRuntimeStaticAssets,
|
|
13
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rizom site boot script.
|
|
3
|
+
*
|
|
4
|
+
* Runs once at page load and wires up:
|
|
5
|
+
* 1. Scroll-reveal IntersectionObserver → toggles `.visible` on `.reveal`
|
|
6
|
+
* 2. Side-nav active-dot tracker (home route only)
|
|
7
|
+
* 3. #themeToggle label sync on click (delegates theme flip to
|
|
8
|
+
* window.toggleTheme, which is defined by site-builder's inline
|
|
9
|
+
* FOUC-prevention script — see plugins/site-builder html-generator.ts)
|
|
10
|
+
*
|
|
11
|
+
* Shipped as a static asset at /boot.js and loaded with <script defer>.
|
|
12
|
+
* Theme profile selection is applied separately via a tiny inline head
|
|
13
|
+
* script that writes `data-theme-profile` onto <html> before this file runs.
|
|
14
|
+
*/
|
|
15
|
+
(function () {
|
|
16
|
+
function init() {
|
|
17
|
+
// Scroll reveal — toggle .visible on .reveal elements as they enter view
|
|
18
|
+
var io = new IntersectionObserver(
|
|
19
|
+
function (entries) {
|
|
20
|
+
entries.forEach(function (e) {
|
|
21
|
+
if (e.isIntersecting) {
|
|
22
|
+
e.target.classList.add("visible");
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
{ threshold: 0.1, rootMargin: "0px 0px -40px 0px" },
|
|
27
|
+
);
|
|
28
|
+
document.querySelectorAll(".reveal").forEach(function (el) {
|
|
29
|
+
io.observe(el);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Side nav active-dot tracker (skipped on routes without SideNav).
|
|
33
|
+
// The dot → section mapping is derived from the rendered dots'
|
|
34
|
+
// href attributes, so SideNav.tsx stays the single source of truth.
|
|
35
|
+
var dots = document.querySelectorAll(".side-nav-dot");
|
|
36
|
+
if (dots.length > 0) {
|
|
37
|
+
var ids = Array.prototype.map.call(dots, function (d) {
|
|
38
|
+
return (d.getAttribute("href") || "").replace(/^#/, "");
|
|
39
|
+
});
|
|
40
|
+
var so = new IntersectionObserver(
|
|
41
|
+
function (entries) {
|
|
42
|
+
entries.forEach(function (e) {
|
|
43
|
+
if (!e.isIntersecting) return;
|
|
44
|
+
var idx = ids.indexOf(e.target.id);
|
|
45
|
+
if (idx < 0 || dots[idx].classList.contains("active")) return;
|
|
46
|
+
dots.forEach(function (d) {
|
|
47
|
+
d.classList.remove("active");
|
|
48
|
+
});
|
|
49
|
+
dots[idx].classList.add("active");
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
{ threshold: 0.4 },
|
|
53
|
+
);
|
|
54
|
+
ids.forEach(function (id) {
|
|
55
|
+
if (!id) return;
|
|
56
|
+
var el = document.getElementById(id);
|
|
57
|
+
if (el) so.observe(el);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Theme toggle — delegate actual flip to window.toggleTheme (injected
|
|
62
|
+
// by site-builder), we just keep the button label in sync.
|
|
63
|
+
var toggle = document.getElementById("themeToggle");
|
|
64
|
+
if (toggle) {
|
|
65
|
+
var syncLabel = function () {
|
|
66
|
+
var isLight =
|
|
67
|
+
document.documentElement.getAttribute("data-theme") === "light";
|
|
68
|
+
toggle.textContent = isLight ? "\u263e Dark" : "\u2600 Light";
|
|
69
|
+
};
|
|
70
|
+
syncLabel();
|
|
71
|
+
toggle.addEventListener("click", function () {
|
|
72
|
+
if (typeof window.toggleTheme === "function") window.toggleTheme();
|
|
73
|
+
syncLabel();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (document.readyState === "loading") {
|
|
79
|
+
document.addEventListener("DOMContentLoaded", init);
|
|
80
|
+
} else {
|
|
81
|
+
init();
|
|
82
|
+
}
|
|
83
|
+
})();
|