@olonjs/cli 3.0.109 → 3.0.111
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/assets/src_tenant_alpha.sh +1959 -454
- package/assets/templates/agritourism/src_tenant.sh +1 -1
- package/assets/templates/alpha/src_tenant.sh +1959 -454
- package/package.json +1 -1
|
@@ -1607,11 +1607,9 @@ cat << 'END_OF_FILE_CONTENT' > "index.html"
|
|
|
1607
1607
|
<meta charset="UTF-8" />
|
|
1608
1608
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1609
1609
|
<meta name="description" content="Olon — Agentic Content Infrastructure" />
|
|
1610
|
-
<link rel="
|
|
1611
|
-
<link href="https://
|
|
1612
|
-
<link href="https://
|
|
1613
|
-
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,wght@0,300;0,500;0,700;1,300;1,500;1,700&display=swap" rel="stylesheet" />
|
|
1614
|
-
<link href="https://cdn.jsdelivr.net/npm/@fontsource-variable/merriweather@5.2.6/wdth.css" rel="stylesheet" />
|
|
1610
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
1611
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
1612
|
+
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&family=Instrument+Sans:ital,wght@0,400..700;1,400..700&family=Merriweather:ital,opsz,wght@0,18..144,300..900;1,18..144,300..900&display=swap" rel="stylesheet">
|
|
1615
1613
|
<title>Olon</title>
|
|
1616
1614
|
</head>
|
|
1617
1615
|
<body>
|
|
@@ -1646,7 +1644,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
|
|
|
1646
1644
|
"@tiptap/extension-link": "^2.11.5",
|
|
1647
1645
|
"@tiptap/react": "^2.11.5",
|
|
1648
1646
|
"@tiptap/starter-kit": "^2.11.5",
|
|
1649
|
-
"@olonjs/core": "^1.0.
|
|
1647
|
+
"@olonjs/core": "^1.0.98",
|
|
1650
1648
|
"class-variance-authority": "^0.7.1",
|
|
1651
1649
|
"clsx": "^2.1.1",
|
|
1652
1650
|
"lucide-react": "^0.474.0",
|
|
@@ -4141,7 +4139,7 @@ export function OlonMark({ size = 32, className }: OlonMarkProps) {
|
|
|
4141
4139
|
|
|
4142
4140
|
// Dark: nucleus = Parchment #E2D5B0 (warm, human)
|
|
4143
4141
|
// Light: nucleus = Primary #1E1814 (brand, on white bg)
|
|
4144
|
-
const nucleusFill = theme === 'dark' ? '#
|
|
4142
|
+
const nucleusFill = theme === 'dark' ? '#F4F3EF' : '#080808'
|
|
4145
4143
|
|
|
4146
4144
|
return (
|
|
4147
4145
|
<svg
|
|
@@ -4153,8 +4151,8 @@ export function OlonMark({ size = 32, className }: OlonMarkProps) {
|
|
|
4153
4151
|
>
|
|
4154
4152
|
<defs>
|
|
4155
4153
|
<linearGradient id="olon-ring" x1="0" y1="0" x2="0" y2="1">
|
|
4156
|
-
<stop offset="0%" stopColor="#
|
|
4157
|
-
<stop offset="100%" stopColor="#
|
|
4154
|
+
<stop offset="0%" stopColor="#84ABFF" />
|
|
4155
|
+
<stop offset="100%" stopColor="#0F52E0" />
|
|
4158
4156
|
</linearGradient>
|
|
4159
4157
|
</defs>
|
|
4160
4158
|
<circle cx="50" cy="50" r="38" stroke="url(#olon-ring)" strokeWidth="20" />
|
|
@@ -5970,7 +5968,7 @@ mkdir -p "src/components/header"
|
|
|
5970
5968
|
echo "Creating src/components/header/View.tsx..."
|
|
5971
5969
|
cat << 'END_OF_FILE_CONTENT' > "src/components/header/View.tsx"
|
|
5972
5970
|
import { useState, useRef, useEffect } from 'react';
|
|
5973
|
-
import { Menu, X, ChevronDown } from 'lucide-react';
|
|
5971
|
+
import { Menu, X, ChevronDown, Zap } from 'lucide-react';
|
|
5974
5972
|
import { OlonMark } from '@/components/OlonWordmark';
|
|
5975
5973
|
import { Button } from '@/components/ui/button';
|
|
5976
5974
|
import { ThemeToggle } from '@/components/ThemeToggle';
|
|
@@ -6052,11 +6050,11 @@ export function Header({ data, settings, menu }: HeaderViewProps) {
|
|
|
6052
6050
|
>
|
|
6053
6051
|
<div className="max-w-6xl mx-auto px-6 h-18 flex items-center gap-8">
|
|
6054
6052
|
|
|
6055
|
-
{/* Logo */}
|
|
6053
|
+
{/* Logo da homepage */}
|
|
6056
6054
|
<a href="/" className="flex items-center gap-2 shrink-0" aria-label="OlonJS home">
|
|
6057
6055
|
<OlonMark size={26} className="mb-0.5" />
|
|
6058
|
-
<span
|
|
6059
|
-
className="text-2xl text-
|
|
6056
|
+
<div className="flex items-center gap-1"><span
|
|
6057
|
+
className="text-2xl text-foreground leading-none"
|
|
6060
6058
|
style={{
|
|
6061
6059
|
fontFamily: 'var(--wordmark-font)',
|
|
6062
6060
|
letterSpacing: 'var(--wordmark-tracking)',
|
|
@@ -6065,12 +6063,9 @@ export function Header({ data, settings, menu }: HeaderViewProps) {
|
|
|
6065
6063
|
}}
|
|
6066
6064
|
>
|
|
6067
6065
|
{data.logoText}
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
{data.badge}
|
|
6072
|
-
</span>
|
|
6073
|
-
)}
|
|
6066
|
+
</span>
|
|
6067
|
+
<span className="text-primary-light font-mono">{data.badge}</span>
|
|
6068
|
+
</div>
|
|
6074
6069
|
</a>
|
|
6075
6070
|
|
|
6076
6071
|
{/* Desktop nav */}
|
|
@@ -6165,7 +6160,7 @@ export function Header({ data, settings, menu }: HeaderViewProps) {
|
|
|
6165
6160
|
);
|
|
6166
6161
|
})}
|
|
6167
6162
|
</nav>
|
|
6168
|
-
|
|
6163
|
+
|
|
6169
6164
|
{/* Actions */}
|
|
6170
6165
|
<div className="hidden md:flex items-center gap-1 ml-auto shrink-0">
|
|
6171
6166
|
<ThemeToggle />
|
|
@@ -6194,6 +6189,15 @@ export function Header({ data, settings, menu }: HeaderViewProps) {
|
|
|
6194
6189
|
</button>
|
|
6195
6190
|
</div>
|
|
6196
6191
|
|
|
6192
|
+
{/* Banner Sotto il Menu */}
|
|
6193
|
+
<div className="border-t border-border/60 py-1 px-4 text-center text-[10px] uppercase font-semibold tracking-wider text-muted-foreground flex justify-center items-center gap-1.5 bg-background/50">
|
|
6194
|
+
<Zap className="w-2.5 h-2.5 text-primary-light" />
|
|
6195
|
+
<span>Built with</span>
|
|
6196
|
+
<a href="https://github.com/olonjs/npm-jpcore" target="_blank" rel="noopener noreferrer" className="text-foreground hover:text-primary-light transition-colors font-bold">
|
|
6197
|
+
OlonJS
|
|
6198
|
+
</a>
|
|
6199
|
+
</div>
|
|
6200
|
+
|
|
6197
6201
|
{/* Mobile drawer */}
|
|
6198
6202
|
<div className={cn(
|
|
6199
6203
|
'md:hidden border-t border-border bg-card overflow-hidden transition-all duration-200',
|
|
@@ -6297,50 +6301,207 @@ export function Header({ data, settings, menu }: HeaderViewProps) {
|
|
|
6297
6301
|
);
|
|
6298
6302
|
}
|
|
6299
6303
|
|
|
6304
|
+
END_OF_FILE_CONTENT
|
|
6305
|
+
# SKIP: src/components/header/View.tsx:Zone.Identifier is binary and cannot be embedded as text.
|
|
6306
|
+
echo "Creating src/components/header/View_.tsx..."
|
|
6307
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/header/View_.tsx"
|
|
6308
|
+
import React, { useState } from 'react';
|
|
6309
|
+
import { cn } from '@/lib/utils';
|
|
6310
|
+
import { OlonMark } from '@/components/ui/OlonMark';
|
|
6311
|
+
import { Badge } from '@/components/ui/badge';
|
|
6312
|
+
import { Button } from '@/components/ui/button';
|
|
6313
|
+
import { Sparkles } from 'lucide-react';
|
|
6314
|
+
import type { MenuItem } from '@olonjs/core';
|
|
6315
|
+
import type { HeaderData, HeaderSettings } from './types';
|
|
6316
|
+
|
|
6317
|
+
export const Header: React.FC<{
|
|
6318
|
+
data: HeaderData;
|
|
6319
|
+
settings?: HeaderSettings;
|
|
6320
|
+
menu: MenuItem[];
|
|
6321
|
+
}> = ({ data, menu }) => {
|
|
6322
|
+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
6323
|
+
|
|
6324
|
+
return (
|
|
6325
|
+
<>
|
|
6326
|
+
<div style={{ height: '80px' }} aria-hidden />
|
|
6327
|
+
<header
|
|
6328
|
+
className={cn(
|
|
6329
|
+
'fixed top-0 left-0 right-0 w-full z-50 transition-all duration-300',
|
|
6330
|
+
'flex flex-col',
|
|
6331
|
+
'bg-background/88 backdrop-blur-[16px] border-b border-border/60'
|
|
6332
|
+
)}
|
|
6333
|
+
>
|
|
6334
|
+
<div className="max-w-[1040px] w-full h-14 mx-auto px-8 flex items-center gap-3">
|
|
6335
|
+
|
|
6336
|
+
|
|
6337
|
+
{/* Logo */}
|
|
6338
|
+
<a href="/" className="flex items-center gap-2 shrink-0" aria-label="OlonJS home">
|
|
6339
|
+
<OlonMark size={26} className="mb-0.5" />
|
|
6340
|
+
<div className="flex items-center gap-1"><span
|
|
6341
|
+
className="text-2xl text-foreground leading-none"
|
|
6342
|
+
style={{
|
|
6343
|
+
fontFamily: 'var(--wordmark-font)',
|
|
6344
|
+
letterSpacing: 'var(--wordmark-tracking)',
|
|
6345
|
+
fontWeight: 'var(--wordmark-weight)',
|
|
6346
|
+
fontVariationSettings: '"wdth" var(--wordmark-width)',
|
|
6347
|
+
}}
|
|
6348
|
+
>
|
|
6349
|
+
{data.logoText}
|
|
6350
|
+
</span>
|
|
6351
|
+
<span className="text-primary-light font-mono">{data.badge}</span>
|
|
6352
|
+
</div>
|
|
6353
|
+
</a>
|
|
6354
|
+
|
|
6355
|
+
{data.badge && (
|
|
6356
|
+
<>
|
|
6357
|
+
<span className="w-px h-4 bg-border" aria-hidden />
|
|
6358
|
+
<Badge variant="outline" className="rounded-full" data-jp-field="badge">
|
|
6359
|
+
{data.badge}
|
|
6360
|
+
</Badge>
|
|
6361
|
+
</>
|
|
6362
|
+
)}
|
|
6363
|
+
|
|
6364
|
+
<div className="flex-1" />
|
|
6365
|
+
|
|
6366
|
+
<nav className="hidden md:flex items-center gap-0.5" aria-label="Site">
|
|
6367
|
+
{menu.map((item, idx) => (
|
|
6368
|
+
<Button
|
|
6369
|
+
key={(item as { id?: string }).id ?? idx}
|
|
6370
|
+
asChild
|
|
6371
|
+
variant={item.isCta ? 'default' : 'ghost'}
|
|
6372
|
+
size="sm"
|
|
6373
|
+
className={cn(
|
|
6374
|
+
'text-[13px]',
|
|
6375
|
+
!item.isCta && 'text-muted-foreground hover:text-foreground'
|
|
6376
|
+
)}
|
|
6377
|
+
>
|
|
6378
|
+
<a
|
|
6379
|
+
href={item.href}
|
|
6380
|
+
data-jp-item-id={(item as { id?: string }).id ?? `legacy-${idx}`}
|
|
6381
|
+
data-jp-item-field="links"
|
|
6382
|
+
target={item.external ? '_blank' : undefined}
|
|
6383
|
+
rel={item.external ? 'noopener noreferrer' : undefined}
|
|
6384
|
+
>
|
|
6385
|
+
{item.label}
|
|
6386
|
+
</a>
|
|
6387
|
+
</Button>
|
|
6388
|
+
))}
|
|
6389
|
+
</nav>
|
|
6390
|
+
|
|
6391
|
+
<button
|
|
6392
|
+
type="button"
|
|
6393
|
+
className="md:hidden p-2 rounded-lg border border-border text-muted-foreground hover:bg-muted hover:text-foreground transition-colors"
|
|
6394
|
+
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
|
6395
|
+
aria-label={mobileMenuOpen ? 'Close menu' : 'Open menu'}
|
|
6396
|
+
>
|
|
6397
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
6398
|
+
{mobileMenuOpen ? (
|
|
6399
|
+
<><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></>
|
|
6400
|
+
) : (
|
|
6401
|
+
<><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="18" x2="21" y2="18" /></>
|
|
6402
|
+
)}
|
|
6403
|
+
</svg>
|
|
6404
|
+
</button>
|
|
6405
|
+
</div>
|
|
6406
|
+
|
|
6407
|
+
{/* Banner Sotto il Menu */}
|
|
6408
|
+
<div className="border-t border-border/60 py-1 px-4 text-center text-[10px] uppercase font-semibold tracking-wider text-muted-foreground flex justify-center items-center gap-1.5 bg-background/50">
|
|
6409
|
+
<Sparkles className="w-2.5 h-2.5 text-primary-light" />
|
|
6410
|
+
<span>Built with</span>
|
|
6411
|
+
<a href="https://github.com/olonjs/npm-jpcore" target="_blank" rel="noopener noreferrer" className="text-foreground hover:text-primary-light transition-colors font-bold">
|
|
6412
|
+
OlonJS
|
|
6413
|
+
</a>
|
|
6414
|
+
</div>
|
|
6415
|
+
|
|
6416
|
+
{mobileMenuOpen && (
|
|
6417
|
+
<nav
|
|
6418
|
+
className="absolute top-[82px] left-0 right-0 md:hidden border-b border-border bg-background/95 backdrop-blur-[16px]"
|
|
6419
|
+
aria-label="Mobile menu"
|
|
6420
|
+
>
|
|
6421
|
+
<div className="max-w-[1040px] mx-auto px-8 py-4 flex flex-col gap-1">
|
|
6422
|
+
{menu.map((item, idx) => (
|
|
6423
|
+
<a
|
|
6424
|
+
key={(item as { id?: string }).id ?? idx}
|
|
6425
|
+
href={item.href}
|
|
6426
|
+
className="text-sm font-medium text-muted-foreground hover:text-foreground transition-colors py-2.5 no-underline"
|
|
6427
|
+
onClick={() => setMobileMenuOpen(false)}
|
|
6428
|
+
data-jp-item-id={(item as { id?: string }).id ?? `legacy-${idx}`}
|
|
6429
|
+
data-jp-item-field="links"
|
|
6430
|
+
>
|
|
6431
|
+
{item.label}
|
|
6432
|
+
</a>
|
|
6433
|
+
))}
|
|
6434
|
+
</div>
|
|
6435
|
+
</nav>
|
|
6436
|
+
)}
|
|
6437
|
+
</header>
|
|
6438
|
+
</>
|
|
6439
|
+
);
|
|
6440
|
+
};
|
|
6441
|
+
|
|
6300
6442
|
END_OF_FILE_CONTENT
|
|
6301
6443
|
echo "Creating src/components/header/index.ts..."
|
|
6302
6444
|
cat << 'END_OF_FILE_CONTENT' > "src/components/header/index.ts"
|
|
6303
|
-
export * from './View';
|
|
6304
|
-
export * from './schema';
|
|
6305
|
-
export * from './types';
|
|
6306
|
-
|
|
6445
|
+
export * from './View';
|
|
6446
|
+
export * from './schema';
|
|
6447
|
+
export * from './types';
|
|
6307
6448
|
END_OF_FILE_CONTENT
|
|
6449
|
+
# SKIP: src/components/header/index.ts:Zone.Identifier is binary and cannot be embedded as text.
|
|
6308
6450
|
echo "Creating src/components/header/schema.ts..."
|
|
6309
6451
|
cat << 'END_OF_FILE_CONTENT' > "src/components/header/schema.ts"
|
|
6310
|
-
import { z } from 'zod';
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
});
|
|
6452
|
+
import { z } from 'zod';
|
|
6453
|
+
|
|
6454
|
+
/**
|
|
6455
|
+
* 📝 HEADER SCHEMA (Contract)
|
|
6456
|
+
* Definisce la struttura dati che l'Admin userà per generare la form.
|
|
6457
|
+
*/
|
|
6458
|
+
export const HeaderSchema = z.object({
|
|
6459
|
+
logoText: z.string().describe('ui:text'),
|
|
6460
|
+
logoHighlight: z.string().optional().describe('ui:text'),
|
|
6461
|
+
logoIconText: z.string().optional().describe('ui:text'),
|
|
6462
|
+
badge: z.string().optional().describe('ui:text'),
|
|
6463
|
+
signinHref: z.string().optional().describe('ui:text'),
|
|
6464
|
+
ctaHref: z.string().optional().describe('ui:text'),
|
|
6465
|
+
ctaLabel: z.string().optional().describe('ui:text'),
|
|
6466
|
+
links: z.array(z.object({
|
|
6467
|
+
label: z.string().describe('ui:text'),
|
|
6468
|
+
href: z.string().describe('ui:text'),
|
|
6469
|
+
isCta: z.boolean().default(false).describe('ui:checkbox'),
|
|
6470
|
+
external: z.boolean().default(false).optional().describe('ui:checkbox'),
|
|
6471
|
+
})).describe('ui:list'),
|
|
6472
|
+
});
|
|
6332
6473
|
|
|
6474
|
+
/**
|
|
6475
|
+
* ⚙️ HEADER SETTINGS
|
|
6476
|
+
* Definisce i parametri tecnici (non di contenuto).
|
|
6477
|
+
*/
|
|
6478
|
+
export const HeaderSettingsSchema = z.object({
|
|
6479
|
+
sticky: z.boolean().default(true).describe('ui:checkbox'),
|
|
6480
|
+
});
|
|
6333
6481
|
END_OF_FILE_CONTENT
|
|
6482
|
+
# SKIP: src/components/header/schema.ts:Zone.Identifier is binary and cannot be embedded as text.
|
|
6334
6483
|
echo "Creating src/components/header/types.ts..."
|
|
6335
6484
|
cat << 'END_OF_FILE_CONTENT' > "src/components/header/types.ts"
|
|
6336
|
-
import { z } from 'zod';
|
|
6337
|
-
import { HeaderSchema, HeaderSettingsSchema } from './schema';
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6485
|
+
import { z } from 'zod';
|
|
6486
|
+
import { HeaderSchema, HeaderSettingsSchema } from './schema';
|
|
6487
|
+
|
|
6488
|
+
/**
|
|
6489
|
+
* 🧩 HEADER DATA
|
|
6490
|
+
* Tipo inferito dallo schema Zod del contenuto.
|
|
6491
|
+
* Utilizzato dalla View per renderizzare logo e links.
|
|
6492
|
+
*/
|
|
6493
|
+
export type HeaderData = z.infer<typeof HeaderSchema>;
|
|
6341
6494
|
|
|
6495
|
+
/**
|
|
6496
|
+
* ⚙️ HEADER SETTINGS
|
|
6497
|
+
* Tipo inferito dallo schema Zod dei settings.
|
|
6498
|
+
* Gestisce comportamenti tecnici come lo 'sticky'.
|
|
6499
|
+
*/
|
|
6500
|
+
export type HeaderSettings = z.infer<typeof HeaderSettingsSchema>;
|
|
6342
6501
|
END_OF_FILE_CONTENT
|
|
6502
|
+
# SKIP: src/components/header/types.ts:Zone.Identifier is binary and cannot be embedded as text.
|
|
6343
6503
|
mkdir -p "src/components/hero"
|
|
6504
|
+
# SKIP: src/components/hero/RadialBackground - Copy.tsx:Zone.Identifier is binary and cannot be embedded as text.
|
|
6344
6505
|
echo "Creating src/components/hero/RadialBackground.tsx..."
|
|
6345
6506
|
cat << 'END_OF_FILE_CONTENT' > "src/components/hero/RadialBackground.tsx"
|
|
6346
6507
|
import { useEffect, useRef, useState } from 'react';
|
|
@@ -6427,6 +6588,93 @@ export function RadialBackground({
|
|
|
6427
6588
|
);
|
|
6428
6589
|
}
|
|
6429
6590
|
|
|
6591
|
+
END_OF_FILE_CONTENT
|
|
6592
|
+
echo "Creating src/components/hero/RadialBackground.txt..."
|
|
6593
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/hero/RadialBackground.txt"
|
|
6594
|
+
import { useEffect, useRef, useState } from 'react';
|
|
6595
|
+
import { motion } from 'motion/react';
|
|
6596
|
+
|
|
6597
|
+
// CSS var names — order matches STOPS
|
|
6598
|
+
const TOKEN_VARS = [
|
|
6599
|
+
'--background', // #0B0907 center
|
|
6600
|
+
'--background', // #130F0D
|
|
6601
|
+
'--background', // #1E1814
|
|
6602
|
+
'--background', // #2E271F
|
|
6603
|
+
'--background', // #241D17
|
|
6604
|
+
'--elevated', // #1E1814
|
|
6605
|
+
'--background', // #0B0907 outer
|
|
6606
|
+
] as const;
|
|
6607
|
+
|
|
6608
|
+
const STOPS = [0, 30, 55, 72, 84, 93, 100] as const;
|
|
6609
|
+
|
|
6610
|
+
function readTokenColors(): string[] {
|
|
6611
|
+
if (typeof document === 'undefined') return TOKEN_VARS.map(() => '#000');
|
|
6612
|
+
const s = getComputedStyle(document.documentElement);
|
|
6613
|
+
return TOKEN_VARS.map((v) => s.getPropertyValue(v).trim() || '#000');
|
|
6614
|
+
}
|
|
6615
|
+
|
|
6616
|
+
export function RadialBackground({
|
|
6617
|
+
startingGap =80,
|
|
6618
|
+
breathing = true,
|
|
6619
|
+
animationSpeed = 0.01,
|
|
6620
|
+
breathingRange = 180,
|
|
6621
|
+
topOffset = 0,
|
|
6622
|
+
}: {
|
|
6623
|
+
startingGap?: number;
|
|
6624
|
+
breathing?: boolean;
|
|
6625
|
+
animationSpeed?: number;
|
|
6626
|
+
breathingRange?: number;
|
|
6627
|
+
topOffset?: number;
|
|
6628
|
+
}) {
|
|
6629
|
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
6630
|
+
const [colors, setColors] = useState<string[]>(() => readTokenColors());
|
|
6631
|
+
|
|
6632
|
+
// Re-read tokens when data-theme changes (dark ↔ light)
|
|
6633
|
+
useEffect(() => {
|
|
6634
|
+
setColors(readTokenColors());
|
|
6635
|
+
const observer = new MutationObserver(() => setColors(readTokenColors()));
|
|
6636
|
+
observer.observe(document.documentElement, {
|
|
6637
|
+
attributes: true,
|
|
6638
|
+
attributeFilter: ['data-theme'],
|
|
6639
|
+
});
|
|
6640
|
+
return () => observer.disconnect();
|
|
6641
|
+
}, []);
|
|
6642
|
+
|
|
6643
|
+
useEffect(() => {
|
|
6644
|
+
let animationFrame: number;
|
|
6645
|
+
let width = startingGap;
|
|
6646
|
+
let direction = 1;
|
|
6647
|
+
|
|
6648
|
+
const animate = () => {
|
|
6649
|
+
if (width >= startingGap + breathingRange) direction = -1;
|
|
6650
|
+
if (width <= startingGap - breathingRange) direction = 1;
|
|
6651
|
+
if (!breathing) direction = 0;
|
|
6652
|
+
width += direction * animationSpeed;
|
|
6653
|
+
|
|
6654
|
+
const stops = STOPS.map((s, i) => `${colors[i]} ${s}%`).join(', ');
|
|
6655
|
+
const gradient = `radial-gradient(${width}% ${width + topOffset}% at 50% 20%, ${stops})`;
|
|
6656
|
+
|
|
6657
|
+
if (containerRef.current) {
|
|
6658
|
+
containerRef.current.style.background = gradient;
|
|
6659
|
+
}
|
|
6660
|
+
animationFrame = requestAnimationFrame(animate);
|
|
6661
|
+
};
|
|
6662
|
+
|
|
6663
|
+
animationFrame = requestAnimationFrame(animate);
|
|
6664
|
+
return () => cancelAnimationFrame(animationFrame);
|
|
6665
|
+
}, [startingGap, breathing, animationSpeed, breathingRange, topOffset, colors]);
|
|
6666
|
+
|
|
6667
|
+
return (
|
|
6668
|
+
<motion.div
|
|
6669
|
+
animate={{ opacity: 1, scale: 1, transition: { duration: 2, ease: [0.25, 0.1, 0.25, 1] } }}
|
|
6670
|
+
className="absolute inset-0 overflow-hidden"
|
|
6671
|
+
initial={{ opacity: 0, scale: 1.5 }}
|
|
6672
|
+
>
|
|
6673
|
+
<div className="absolute inset-0" ref={containerRef} />
|
|
6674
|
+
</motion.div>
|
|
6675
|
+
);
|
|
6676
|
+
}
|
|
6677
|
+
|
|
6430
6678
|
END_OF_FILE_CONTENT
|
|
6431
6679
|
echo "Creating src/components/hero/View.tsx..."
|
|
6432
6680
|
cat << 'END_OF_FILE_CONTENT' > "src/components/hero/View.tsx"
|
|
@@ -6470,11 +6718,11 @@ export function Hero({ data, settings }: HeroViewProps) {
|
|
|
6470
6718
|
)}
|
|
6471
6719
|
|
|
6472
6720
|
{/* Headline */}
|
|
6473
|
-
<h1 className="font-display font-
|
|
6721
|
+
<h1 className="font-display font-bold text-7xl text-foreground leading-tight tracking-tight mb-1" data-jp-field="title">
|
|
6474
6722
|
{data.title}
|
|
6475
6723
|
</h1>
|
|
6476
6724
|
{data.titleHighlight && (
|
|
6477
|
-
<h2 className="font-display font-normal italic text-5xl md:text-6xl text-primary-light leading-tight tracking-
|
|
6725
|
+
<h2 className="font-display font-normal italic text-5xl md:text-6xl text-primary-light leading-tight tracking-tight mb-7" data-jp-field="titleHighlight">
|
|
6478
6726
|
{data.titleHighlight}
|
|
6479
6727
|
</h2>
|
|
6480
6728
|
)}
|
|
@@ -6773,39 +7021,978 @@ export function Login({ data, settings }: LoginViewProps) {
|
|
|
6773
7021
|
}
|
|
6774
7022
|
|
|
6775
7023
|
END_OF_FILE_CONTENT
|
|
6776
|
-
echo "Creating src/components/login/index.ts..."
|
|
6777
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/login/index.ts"
|
|
6778
|
-
export * from './View';
|
|
6779
|
-
export * from './schema';
|
|
6780
|
-
export * from './types';
|
|
7024
|
+
echo "Creating src/components/login/index.ts..."
|
|
7025
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/login/index.ts"
|
|
7026
|
+
export * from './View';
|
|
7027
|
+
export * from './schema';
|
|
7028
|
+
export * from './types';
|
|
7029
|
+
|
|
7030
|
+
END_OF_FILE_CONTENT
|
|
7031
|
+
echo "Creating src/components/login/schema.ts..."
|
|
7032
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/login/schema.ts"
|
|
7033
|
+
import { z } from 'zod';
|
|
7034
|
+
import { BaseSectionData } from '@/lib/base-schemas';
|
|
7035
|
+
|
|
7036
|
+
export const LoginSchema = BaseSectionData.extend({
|
|
7037
|
+
title: z.string().describe('ui:text'),
|
|
7038
|
+
subtitle: z.string().optional().describe('ui:text'),
|
|
7039
|
+
forgotHref: z.string().optional().describe('ui:text'),
|
|
7040
|
+
signupHref: z.string().optional().describe('ui:text'),
|
|
7041
|
+
termsHref: z.string().optional().describe('ui:text'),
|
|
7042
|
+
privacyHref: z.string().optional().describe('ui:text'),
|
|
7043
|
+
});
|
|
7044
|
+
|
|
7045
|
+
export const LoginSettingsSchema = z.object({
|
|
7046
|
+
showOauth: z.boolean().default(true).describe('ui:checkbox'),
|
|
7047
|
+
});
|
|
7048
|
+
|
|
7049
|
+
END_OF_FILE_CONTENT
|
|
7050
|
+
echo "Creating src/components/login/types.ts..."
|
|
7051
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/login/types.ts"
|
|
7052
|
+
import { z } from 'zod';
|
|
7053
|
+
import { LoginSchema, LoginSettingsSchema } from './schema';
|
|
7054
|
+
|
|
7055
|
+
export type LoginData = z.infer<typeof LoginSchema>;
|
|
7056
|
+
export type LoginSettings = z.infer<typeof LoginSettingsSchema>;
|
|
7057
|
+
|
|
7058
|
+
END_OF_FILE_CONTENT
|
|
7059
|
+
mkdir -p "src/components/olon-architecture"
|
|
7060
|
+
echo "Creating src/components/olon-architecture/View.tsx..."
|
|
7061
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-architecture/View.tsx"
|
|
7062
|
+
import type { OlonArchitectureData } from './types';
|
|
7063
|
+
|
|
7064
|
+
const ICONS: Record<string, React.ReactNode> = {
|
|
7065
|
+
mtrp: (
|
|
7066
|
+
<svg width="32" height="32" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7067
|
+
<defs><linearGradient id="am" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#84ABFF"/><stop offset="1" stopColor="#0F52E0"/></linearGradient><linearGradient id="amc" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#EEF3FF"/><stop offset="1" stopColor="#84ABFF"/></linearGradient></defs>
|
|
7068
|
+
<rect x="25" y="30" width="130" height="140" rx="10" fill="none" stroke="url(#am)" strokeWidth="7"/>
|
|
7069
|
+
<line x1="25" y1="60" x2="155" y2="60" stroke="url(#am)" strokeWidth="5"/>
|
|
7070
|
+
<path fill="none" stroke="url(#am)" strokeLinecap="round" strokeLinejoin="round" strokeWidth="4.5" d="M72,42 c-5,0 -8,2 -8,6v2c0,4 -3,5 -6,5 3,0 6,1 6,5v2c0,4 3,6 8,6"/>
|
|
7071
|
+
<path fill="none" stroke="url(#am)" strokeLinecap="round" strokeLinejoin="round" strokeWidth="4.5" d="M108,42 c5,0 8,2 8,6v2c0,4 3,5 6,5 -3,0 -6,1 -6,5v2c0,4 -3,6 -8,6"/>
|
|
7072
|
+
<circle fill="url(#am)" opacity="0.35" cx="46" cy="90" r="4.5"/>
|
|
7073
|
+
<rect fill="url(#am)" opacity="0.35" x="59" y="86.5" width="68" height="7" rx="3.5"/>
|
|
7074
|
+
<circle fill="url(#amc)" cx="46" cy="117" r="6.5"/>
|
|
7075
|
+
<rect fill="url(#amc)" x="59" y="113" width="82" height="8" rx="4"/>
|
|
7076
|
+
<circle fill="url(#am)" opacity="0.55" cx="46" cy="145" r="4.5"/>
|
|
7077
|
+
<rect fill="url(#am)" opacity="0.55" x="59" y="141.5" width="50" height="7" rx="3.5"/>
|
|
7078
|
+
<path fill="none" stroke="url(#amc)" strokeLinecap="round" strokeWidth="5" d="M192,117 h-35"/>
|
|
7079
|
+
<path fill="none" stroke="url(#amc)" strokeLinecap="round" strokeLinejoin="round" strokeWidth="5" d="M170,108 l17,9 -17,9"/>
|
|
7080
|
+
</svg>
|
|
7081
|
+
),
|
|
7082
|
+
tbp: (
|
|
7083
|
+
<svg width="32" height="32" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7084
|
+
<defs><linearGradient id="at" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#84ABFF"/><stop offset="1" stopColor="#0F52E0"/></linearGradient><linearGradient id="atc" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#EEF3FF"/><stop offset="1" stopColor="#84ABFF"/></linearGradient></defs>
|
|
7085
|
+
<rect fill="none" stroke="url(#at)" strokeWidth="5.5" strokeLinejoin="round" opacity="0.3" x="65" y="22" width="108" height="74" rx="9"/>
|
|
7086
|
+
<rect fill="none" stroke="url(#at)" strokeWidth="5.5" strokeLinejoin="round" opacity="0.6" x="46" y="50" width="108" height="74" rx="9"/>
|
|
7087
|
+
<rect fill="none" stroke="url(#at)" strokeWidth="6.5" strokeLinejoin="round" x="27" y="78" width="108" height="74" rx="9"/>
|
|
7088
|
+
<rect fill="url(#at)" opacity="0.6" x="42" y="101" width="52" height="6" rx="3"/>
|
|
7089
|
+
<rect fill="url(#atc)" x="42" y="116" width="36" height="6" rx="3"/>
|
|
7090
|
+
<circle fill="url(#at)" opacity="0.3" cx="162" cy="33" r="4"/>
|
|
7091
|
+
<circle fill="url(#at)" opacity="0.6" cx="143" cy="61" r="4"/>
|
|
7092
|
+
<circle fill="url(#atc)" cx="124" cy="89" r="5"/>
|
|
7093
|
+
</svg>
|
|
7094
|
+
),
|
|
7095
|
+
jsp: (
|
|
7096
|
+
<svg width="32" height="32" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7097
|
+
<defs><linearGradient id="aj" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#84ABFF"/><stop offset="1" stopColor="#0F52E0"/></linearGradient><linearGradient id="ajc" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#EEF3FF"/><stop offset="1" stopColor="#84ABFF"/></linearGradient></defs>
|
|
7098
|
+
<rect fill="none" stroke="url(#aj)" strokeWidth="7" strokeLinejoin="round" x="14" y="22" width="172" height="128" rx="12"/>
|
|
7099
|
+
<line x1="14" y1="52" x2="186" y2="52" stroke="url(#aj)" strokeWidth="5"/>
|
|
7100
|
+
<circle fill="url(#aj)" opacity="0.4" cx="34" cy="37" r="5"/>
|
|
7101
|
+
<circle fill="url(#aj)" opacity="0.6" cx="52" cy="37" r="5"/>
|
|
7102
|
+
<circle fill="url(#ajc)" cx="70" cy="37" r="5"/>
|
|
7103
|
+
<path fill="none" stroke="url(#ajc)" strokeLinecap="round" strokeLinejoin="round" strokeWidth="6" d="M28,75 l12,11 -12,11"/>
|
|
7104
|
+
<rect fill="url(#ajc)" x="48" y="80" width="22" height="7" rx="3.5"/>
|
|
7105
|
+
<rect fill="url(#aj)" opacity="0.7" x="28" y="106" width="88" height="6" rx="3"/>
|
|
7106
|
+
<rect fill="url(#aj)" opacity="0.5" x="28" y="121" width="62" height="6" rx="3"/>
|
|
7107
|
+
<rect fill="url(#aj)" opacity="0.35" x="28" y="136" width="76" height="6" rx="3"/>
|
|
7108
|
+
</svg>
|
|
7109
|
+
),
|
|
7110
|
+
idac: (
|
|
7111
|
+
<svg width="32" height="32" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7112
|
+
<defs><linearGradient id="ai" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#84ABFF"/><stop offset="1" stopColor="#0F52E0"/></linearGradient><linearGradient id="aic" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#EEF3FF"/><stop offset="1" stopColor="#84ABFF"/></linearGradient></defs>
|
|
7113
|
+
<rect fill="none" stroke="url(#ai)" strokeWidth="6.5" strokeLinejoin="round" x="8" y="36" width="72" height="128" rx="9"/>
|
|
7114
|
+
<rect fill="url(#ai)" opacity="0.5" x="20" y="56" width="48" height="5.5" rx="2.75"/>
|
|
7115
|
+
<rect fill="url(#aic)" x="20" y="75" width="48" height="8" rx="4"/>
|
|
7116
|
+
<rect fill="url(#ai)" opacity="0.4" x="20" y="98" width="48" height="5.5" rx="2.75"/>
|
|
7117
|
+
<path fill="none" stroke="url(#aic)" strokeLinecap="round" strokeWidth="5.5" d="M80,100 h40"/>
|
|
7118
|
+
<circle fill="url(#aic)" cx="100" cy="100" r="5.5"/>
|
|
7119
|
+
<path fill="none" stroke="url(#ai)" strokeLinecap="round" strokeWidth="4" opacity="0.4" d="M80,75 h40"/>
|
|
7120
|
+
<path fill="none" stroke="url(#ai)" strokeLinecap="round" strokeWidth="4" opacity="0.4" d="M80,125 h40"/>
|
|
7121
|
+
<rect fill="none" stroke="url(#ai)" strokeWidth="6.5" strokeLinejoin="round" x="120" y="36" width="72" height="128" rx="9"/>
|
|
7122
|
+
<rect fill="url(#ai)" opacity="0.5" x="132" y="56" width="48" height="5.5" rx="2.75"/>
|
|
7123
|
+
<rect fill="url(#aic)" x="132" y="75" width="48" height="8" rx="4"/>
|
|
7124
|
+
<rect fill="url(#ai)" opacity="0.4" x="132" y="98" width="48" height="5.5" rx="2.75"/>
|
|
7125
|
+
</svg>
|
|
7126
|
+
),
|
|
7127
|
+
bsds: (
|
|
7128
|
+
<svg width="32" height="32" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7129
|
+
<defs><linearGradient id="ab" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#84ABFF"/><stop offset="1" stopColor="#0F52E0"/></linearGradient><linearGradient id="abc" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#EEF3FF"/><stop offset="1" stopColor="#84ABFF"/></linearGradient></defs>
|
|
7130
|
+
<rect fill="none" stroke="url(#ab)" strokeWidth="8" strokeLinejoin="round" x="16" y="152" width="168" height="32" rx="8"/>
|
|
7131
|
+
<circle fill="url(#abc)" cx="100" cy="168" r="7"/>
|
|
7132
|
+
<path fill="none" stroke="url(#ab)" strokeLinecap="round" strokeWidth="5" opacity="0.5" d="M54,138 v14"/>
|
|
7133
|
+
<path fill="none" stroke="url(#ab)" strokeLinecap="round" strokeWidth="5" opacity="0.5" d="M146,138 v14"/>
|
|
7134
|
+
<rect fill="none" stroke="url(#ab)" strokeWidth="6" strokeLinejoin="round" x="16" y="68" width="76" height="70" rx="9"/>
|
|
7135
|
+
<rect fill="url(#ab)" opacity="0.55" x="28" y="84" width="42" height="6" rx="3"/>
|
|
7136
|
+
<rect fill="url(#abc)" x="28" y="112" width="32" height="6" rx="3"/>
|
|
7137
|
+
<rect fill="none" stroke="url(#ab)" strokeWidth="6" strokeLinejoin="round" x="108" y="44" width="76" height="94" rx="9"/>
|
|
7138
|
+
<rect fill="url(#ab)" opacity="0.55" x="120" y="60" width="42" height="6" rx="3"/>
|
|
7139
|
+
<rect fill="url(#abc)" x="120" y="88" width="32" height="6" rx="3"/>
|
|
7140
|
+
</svg>
|
|
7141
|
+
),
|
|
7142
|
+
pss: (
|
|
7143
|
+
<svg width="32" height="32" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7144
|
+
<defs><linearGradient id="ap" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#84ABFF"/><stop offset="1" stopColor="#0F52E0"/></linearGradient><linearGradient id="apc" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#EEF3FF"/><stop offset="1" stopColor="#84ABFF"/></linearGradient></defs>
|
|
7145
|
+
<path fill="none" stroke="url(#apc)" strokeLinecap="round" strokeWidth="5.5" d="M100,32 L52,90"/>
|
|
7146
|
+
<path fill="none" stroke="url(#ap)" strokeLinecap="round" strokeWidth="5" opacity="0.3" d="M100,32 L148,90"/>
|
|
7147
|
+
<path fill="none" stroke="url(#ap)" strokeLinecap="round" strokeWidth="4.5" opacity="0.3" d="M52,90 L22,158"/>
|
|
7148
|
+
<path fill="none" stroke="url(#apc)" strokeLinecap="round" strokeWidth="5.5" d="M52,90 L90,158"/>
|
|
7149
|
+
<path fill="none" stroke="url(#ap)" strokeLinecap="round" strokeWidth="4" opacity="0.25" d="M148,90 L170,158"/>
|
|
7150
|
+
<circle fill="url(#apc)" cx="100" cy="22" r="11"/>
|
|
7151
|
+
<circle fill="url(#apc)" cx="52" cy="90" r="10"/>
|
|
7152
|
+
<circle fill="url(#ap)" opacity="0.3" cx="148" cy="90" r="8"/>
|
|
7153
|
+
<circle fill="url(#ap)" opacity="0.3" cx="22" cy="165" r="7"/>
|
|
7154
|
+
<circle fill="url(#apc)" cx="90" cy="165" r="11"/>
|
|
7155
|
+
<rect fill="none" stroke="url(#apc)" strokeWidth="4" strokeLinejoin="round" opacity="0.5" x="76" y="151" width="28" height="28" rx="5"/>
|
|
7156
|
+
</svg>
|
|
7157
|
+
),
|
|
7158
|
+
};
|
|
7159
|
+
|
|
7160
|
+
interface Props { data: OlonArchitectureData; }
|
|
7161
|
+
|
|
7162
|
+
export function OlonArchitectureView({ data }: Props) {
|
|
7163
|
+
return (
|
|
7164
|
+
<section
|
|
7165
|
+
style={{
|
|
7166
|
+
'--local-bg': 'var(--background)',
|
|
7167
|
+
'--local-fg': 'var(--foreground)',
|
|
7168
|
+
'--local-muted': 'var(--muted-foreground)',
|
|
7169
|
+
'--local-p400': 'var(--primary)',
|
|
7170
|
+
'--local-card': 'var(--card)',
|
|
7171
|
+
'--local-border':'var(--border)',
|
|
7172
|
+
} as React.CSSProperties}
|
|
7173
|
+
className="bg-[var(--local-bg)] text-[var(--local-fg)] py-24 border-t border-[var(--local-border)]"
|
|
7174
|
+
data-jp-section-id={data.id}
|
|
7175
|
+
data-jp-section-type="olon-architecture"
|
|
7176
|
+
>
|
|
7177
|
+
<div className="max-w-6xl mx-auto px-8">
|
|
7178
|
+
<p className="text-xs font-semibold tracking-[0.12em] uppercase text-[var(--local-muted)] mb-3"
|
|
7179
|
+
data-jp-field="label">{data.label}</p>
|
|
7180
|
+
<h2 className="text-4xl font-bold tracking-[-0.03em] text-foreground mb-3"
|
|
7181
|
+
data-jp-field="headline">{data.headline}</h2>
|
|
7182
|
+
<p className="text-base text-[var(--local-muted)] leading-relaxed max-w-2xl mb-3"
|
|
7183
|
+
data-jp-field="body">{data.body}</p>
|
|
7184
|
+
{data.specHref && (
|
|
7185
|
+
<p className="text-sm text-[var(--local-muted)] mb-12">
|
|
7186
|
+
Full specification:{' '}
|
|
7187
|
+
<a href={data.specHref} target="_blank" rel="noopener noreferrer"
|
|
7188
|
+
className="text-[var(--local-p400)] hover:underline">
|
|
7189
|
+
olonjsSpecs_V_1_5.md ↗
|
|
7190
|
+
</a>
|
|
7191
|
+
</p>
|
|
7192
|
+
)}
|
|
7193
|
+
|
|
7194
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 border border-[var(--local-border)] rounded-2xl overflow-hidden"
|
|
7195
|
+
data-jp-array="protocols">
|
|
7196
|
+
{data.protocols.map((p) => (
|
|
7197
|
+
<div key={p.id}
|
|
7198
|
+
className="bg-[var(--local-card)] p-7 flex flex-col gap-3 border-r border-b border-[var(--local-border)] hover:bg-[var(--elevated)] transition-colors"
|
|
7199
|
+
data-jp-item-id={p.id}>
|
|
7200
|
+
<div>{ICONS[p.icon]}</div>
|
|
7201
|
+
<p className="text-[11px] font-semibold tracking-[0.1em] uppercase text-[var(--local-p400)] font-mono"
|
|
7202
|
+
data-jp-field="version">{p.acronym} · {p.version}</p>
|
|
7203
|
+
<p className="font-bold text-foreground text-base" data-jp-field="name">{p.name}</p>
|
|
7204
|
+
<p className="text-sm text-[var(--local-muted)] leading-relaxed flex-1"
|
|
7205
|
+
data-jp-field="desc">{p.desc}</p>
|
|
7206
|
+
<a href={p.specHref} target="_blank" rel="noopener noreferrer"
|
|
7207
|
+
className="text-xs text-[var(--local-p400)] hover:text-foreground transition-colors mt-auto"
|
|
7208
|
+
data-jp-field="specHref">Read spec ↗</a>
|
|
7209
|
+
</div>
|
|
7210
|
+
))}
|
|
7211
|
+
</div>
|
|
7212
|
+
</div>
|
|
7213
|
+
</section>
|
|
7214
|
+
);
|
|
7215
|
+
}
|
|
7216
|
+
|
|
7217
|
+
END_OF_FILE_CONTENT
|
|
7218
|
+
echo "Creating src/components/olon-architecture/index.ts..."
|
|
7219
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-architecture/index.ts"
|
|
7220
|
+
export { OlonArchitectureView as View } from './View';
|
|
7221
|
+
export { OlonArchitectureSchema } from './schema';
|
|
7222
|
+
export type { OlonArchitectureData } from './types';
|
|
7223
|
+
|
|
7224
|
+
END_OF_FILE_CONTENT
|
|
7225
|
+
echo "Creating src/components/olon-architecture/schema.ts..."
|
|
7226
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-architecture/schema.ts"
|
|
7227
|
+
import { z } from 'zod';
|
|
7228
|
+
import { BaseSectionData, BaseArrayItem } from '@/lib/base-schemas';
|
|
7229
|
+
|
|
7230
|
+
export const ProtocolSchema = BaseArrayItem.extend({
|
|
7231
|
+
version: z.string(),
|
|
7232
|
+
acronym: z.string(),
|
|
7233
|
+
name: z.string(),
|
|
7234
|
+
desc: z.string(),
|
|
7235
|
+
specHref: z.string(),
|
|
7236
|
+
icon: z.enum(['mtrp', 'tbp', 'jsp', 'idac', 'bsds', 'pss']),
|
|
7237
|
+
});
|
|
7238
|
+
|
|
7239
|
+
export const OlonArchitectureSchema = BaseSectionData.extend({
|
|
7240
|
+
label: z.string().default('Architecture'),
|
|
7241
|
+
headline: z.string().default('Six governing protocols.'),
|
|
7242
|
+
body: z.string().default(''),
|
|
7243
|
+
specHref: z.string().default(''),
|
|
7244
|
+
protocols: z.array(ProtocolSchema).min(1).max(6),
|
|
7245
|
+
});
|
|
7246
|
+
|
|
7247
|
+
export type OlonArchitectureData = z.infer<typeof OlonArchitectureSchema>;
|
|
7248
|
+
|
|
7249
|
+
END_OF_FILE_CONTENT
|
|
7250
|
+
echo "Creating src/components/olon-architecture/types.ts..."
|
|
7251
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-architecture/types.ts"
|
|
7252
|
+
export type { OlonArchitectureData } from './schema';
|
|
7253
|
+
|
|
7254
|
+
END_OF_FILE_CONTENT
|
|
7255
|
+
mkdir -p "src/components/olon-example"
|
|
7256
|
+
echo "Creating src/components/olon-example/View.tsx..."
|
|
7257
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-example/View.tsx"
|
|
7258
|
+
import type { OlonExampleData } from './types';
|
|
7259
|
+
|
|
7260
|
+
interface Props { data: OlonExampleData; }
|
|
7261
|
+
|
|
7262
|
+
export function OlonExampleView({ data }: Props) {
|
|
7263
|
+
return (
|
|
7264
|
+
<section
|
|
7265
|
+
style={{
|
|
7266
|
+
'--local-bg': 'var(--background)',
|
|
7267
|
+
'--local-fg': 'var(--foreground)',
|
|
7268
|
+
'--local-muted': 'var(--muted-foreground)',
|
|
7269
|
+
'--local-p400': 'var(--primary)',
|
|
7270
|
+
'--local-p300': 'var(--primary-light)',
|
|
7271
|
+
'--local-card': 'var(--card)',
|
|
7272
|
+
'--local-border':'var(--border)',
|
|
7273
|
+
} as React.CSSProperties}
|
|
7274
|
+
className="bg-[var(--local-bg)] text-[var(--local-fg)] py-24 border-t border-[var(--local-border)]"
|
|
7275
|
+
data-jp-section-id={data.id}
|
|
7276
|
+
data-jp-section-type="olon-example"
|
|
7277
|
+
>
|
|
7278
|
+
<div className="max-w-6xl mx-auto px-8">
|
|
7279
|
+
<p className="text-xs font-semibold tracking-[0.12em] uppercase text-[var(--local-muted)] mb-3"
|
|
7280
|
+
data-jp-field="label">{data.label}</p>
|
|
7281
|
+
<h2 className="text-4xl font-bold tracking-[-0.03em] text-foreground mb-3"
|
|
7282
|
+
data-jp-field="headline">{data.headline}</h2>
|
|
7283
|
+
<p className="text-base text-[var(--local-muted)] leading-relaxed max-w-2xl mb-12"
|
|
7284
|
+
data-jp-field="body">{data.body}</p>
|
|
7285
|
+
|
|
7286
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
7287
|
+
{data.steps.map((step) => (
|
|
7288
|
+
<div key={step.number}
|
|
7289
|
+
className="bg-[var(--local-card)] border border-[var(--local-border)] rounded-2xl overflow-hidden">
|
|
7290
|
+
{/* Step header */}
|
|
7291
|
+
<div className="px-6 py-4 border-b border-[var(--local-border)] flex items-center gap-3">
|
|
7292
|
+
<span className="w-6 h-6 rounded-full bg-[var(--local-p400)] text-foreground text-xs font-bold flex items-center justify-center flex-shrink-0">
|
|
7293
|
+
{step.number}
|
|
7294
|
+
</span>
|
|
7295
|
+
<span className="font-semibold text-foreground text-sm">{step.title}</span>
|
|
7296
|
+
<span className="ml-auto text-xs text-[var(--local-muted)]">{step.meta}</span>
|
|
7297
|
+
</div>
|
|
7298
|
+
{/* Code block */}
|
|
7299
|
+
<pre className="p-6 font-mono text-xs leading-relaxed bg-[#080E14] text-gray-300 overflow-x-auto whitespace-pre-wrap min-h-[200px]">
|
|
7300
|
+
{step.code}
|
|
7301
|
+
</pre>
|
|
7302
|
+
</div>
|
|
7303
|
+
))}
|
|
7304
|
+
</div>
|
|
7305
|
+
|
|
7306
|
+
{/* MCP manifest note */}
|
|
7307
|
+
{data.note && (
|
|
7308
|
+
<div className="mt-6 px-6 py-4 bg-[var(--local-card)] border border-[var(--local-border)] rounded-xl flex items-start gap-3">
|
|
7309
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"
|
|
7310
|
+
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
|
|
7311
|
+
className="text-[var(--local-p400)] mt-0.5 flex-shrink-0">
|
|
7312
|
+
<circle cx="12" cy="12" r="10"/>
|
|
7313
|
+
<line x1="12" y1="8" x2="12" y2="12"/>
|
|
7314
|
+
<line x1="12" y1="16" x2="12.01" y2="16"/>
|
|
7315
|
+
</svg>
|
|
7316
|
+
<p className="text-sm text-[var(--local-muted)]" data-jp-field="note">
|
|
7317
|
+
{data.note}{' '}
|
|
7318
|
+
{data.noteHref && (
|
|
7319
|
+
<code className="font-mono text-[var(--local-p300)] text-xs">{data.noteHref}</code>
|
|
7320
|
+
)}
|
|
7321
|
+
</p>
|
|
7322
|
+
</div>
|
|
7323
|
+
)}
|
|
7324
|
+
</div>
|
|
7325
|
+
</section>
|
|
7326
|
+
);
|
|
7327
|
+
}
|
|
7328
|
+
|
|
7329
|
+
END_OF_FILE_CONTENT
|
|
7330
|
+
echo "Creating src/components/olon-example/index.ts..."
|
|
7331
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-example/index.ts"
|
|
7332
|
+
export { OlonExampleView as View } from './View';
|
|
7333
|
+
export { OlonExampleSchema } from './schema';
|
|
7334
|
+
export type { OlonExampleData } from './types';
|
|
7335
|
+
|
|
7336
|
+
END_OF_FILE_CONTENT
|
|
7337
|
+
echo "Creating src/components/olon-example/schema.ts..."
|
|
7338
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-example/schema.ts"
|
|
7339
|
+
import { z } from 'zod';
|
|
7340
|
+
import { BaseSectionData } from '@/lib/base-schemas';
|
|
7341
|
+
|
|
7342
|
+
const StepSchema = z.object({
|
|
7343
|
+
number: z.number(),
|
|
7344
|
+
title: z.string(),
|
|
7345
|
+
meta: z.string(),
|
|
7346
|
+
code: z.string(),
|
|
7347
|
+
});
|
|
7348
|
+
|
|
7349
|
+
export const OlonExampleSchema = BaseSectionData.extend({
|
|
7350
|
+
label: z.string().default('Quick Example'),
|
|
7351
|
+
headline: z.string().default('Two steps. One contract.'),
|
|
7352
|
+
body: z.string().default(''),
|
|
7353
|
+
note: z.string().default(''),
|
|
7354
|
+
noteHref: z.string().default(''),
|
|
7355
|
+
steps: z.tuple([StepSchema, StepSchema]),
|
|
7356
|
+
});
|
|
7357
|
+
|
|
7358
|
+
export type OlonExampleData = z.infer<typeof OlonExampleSchema>;
|
|
7359
|
+
|
|
7360
|
+
END_OF_FILE_CONTENT
|
|
7361
|
+
echo "Creating src/components/olon-example/types.ts..."
|
|
7362
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-example/types.ts"
|
|
7363
|
+
export type { OlonExampleData } from './schema';
|
|
7364
|
+
|
|
7365
|
+
END_OF_FILE_CONTENT
|
|
7366
|
+
mkdir -p "src/components/olon-getstarted"
|
|
7367
|
+
echo "Creating src/components/olon-getstarted/View.tsx..."
|
|
7368
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-getstarted/View.tsx"
|
|
7369
|
+
import type { OlonGetStartedData } from './types';
|
|
7370
|
+
import { Button } from '@/components/ui/button';
|
|
7371
|
+
|
|
7372
|
+
const BADGE_STYLES: Record<string, string> = {
|
|
7373
|
+
oss: 'bg-blue-500/15 text-blue-400 border border-blue-500/30',
|
|
7374
|
+
cli: 'bg-primary/10 text-primary border border-primary/20',
|
|
7375
|
+
deploy: 'bg-muted text-muted-foreground border border-border',
|
|
7376
|
+
};
|
|
7377
|
+
|
|
7378
|
+
interface Props { data: OlonGetStartedData; }
|
|
7379
|
+
|
|
7380
|
+
export function OlonGetStartedView({ data }: Props) {
|
|
7381
|
+
return (
|
|
7382
|
+
<section
|
|
7383
|
+
style={{
|
|
7384
|
+
'--local-bg': 'var(--background)',
|
|
7385
|
+
'--local-fg': 'var(--foreground)',
|
|
7386
|
+
'--local-muted': 'var(--muted-foreground)',
|
|
7387
|
+
'--local-p400': 'var(--primary)',
|
|
7388
|
+
'--local-p300': 'var(--primary-light)',
|
|
7389
|
+
'--local-card': 'var(--card)',
|
|
7390
|
+
'--local-border':'var(--border)',
|
|
7391
|
+
} as React.CSSProperties}
|
|
7392
|
+
className="bg-[var(--local-bg)] text-[var(--local-fg)] py-24 border-t border-[var(--local-border)]"
|
|
7393
|
+
data-jp-section-id={data.id}
|
|
7394
|
+
data-jp-section-type="olon-getstarted"
|
|
7395
|
+
>
|
|
7396
|
+
<div className="max-w-6xl mx-auto px-8">
|
|
7397
|
+
<p className="text-xs font-semibold tracking-[0.12em] uppercase text-[var(--local-muted)] mb-3"
|
|
7398
|
+
data-jp-field="label">{data.label}</p>
|
|
7399
|
+
<h2 className="text-4xl font-bold tracking-[-0.03em] text-foreground mb-3"
|
|
7400
|
+
data-jp-field="headline">{data.headline}</h2>
|
|
7401
|
+
<p className="text-base text-[var(--local-muted)] leading-relaxed max-w-2xl mb-12"
|
|
7402
|
+
data-jp-field="body">{data.body}</p>
|
|
7403
|
+
|
|
7404
|
+
<div className="grid grid-cols-1 md:grid-cols-3 border border-[var(--local-border)] rounded-2xl overflow-hidden"
|
|
7405
|
+
data-jp-array="cards">
|
|
7406
|
+
{data.cards.map((card) => (
|
|
7407
|
+
<div key={card.id}
|
|
7408
|
+
className="bg-[var(--local-card)] p-8 flex flex-col gap-4 border-r last:border-r-0 border-[var(--local-border)] hover:bg-[var(--elevated)] transition-colors"
|
|
7409
|
+
data-jp-item-id={card.id}>
|
|
7410
|
+
<span className={`text-[11px] font-bold tracking-[0.08em] uppercase px-2.5 py-0.5 rounded-full w-fit ${BADGE_STYLES[card.badgeStyle]}`}
|
|
7411
|
+
data-jp-field="badge">
|
|
7412
|
+
{card.badge}
|
|
7413
|
+
</span>
|
|
7414
|
+
<p className="font-bold text-foreground text-base" data-jp-field="title">{card.title}</p>
|
|
7415
|
+
<p className="text-sm text-[var(--local-muted)] leading-relaxed flex-1"
|
|
7416
|
+
data-jp-field="body">{card.body}</p>
|
|
7417
|
+
{card.code && (
|
|
7418
|
+
<code className="font-mono text-xs bg-[#080E14] border border-[var(--local-border)] rounded-lg px-4 py-3 text-[var(--local-p300)] block"
|
|
7419
|
+
data-jp-field="code">
|
|
7420
|
+
{card.code}
|
|
7421
|
+
</code>
|
|
7422
|
+
)}
|
|
7423
|
+
{card.deployHref && card.deployLabel && (
|
|
7424
|
+
<Button asChild variant="outline" size="sm" className="w-fit">
|
|
7425
|
+
<a href={card.deployHref} target="_blank" rel="noopener noreferrer">
|
|
7426
|
+
{card.deployLabel}
|
|
7427
|
+
</a>
|
|
7428
|
+
</Button>
|
|
7429
|
+
)}
|
|
7430
|
+
<a href={card.linkHref} target="_blank" rel="noopener noreferrer"
|
|
7431
|
+
className="text-sm text-[var(--local-p400)] hover:text-[var(--local-p300)] transition-colors flex items-center gap-1 mt-auto"
|
|
7432
|
+
data-jp-field="linkLabel">
|
|
7433
|
+
{card.linkLabel} ↗
|
|
7434
|
+
</a>
|
|
7435
|
+
</div>
|
|
7436
|
+
))}
|
|
7437
|
+
</div>
|
|
7438
|
+
</div>
|
|
7439
|
+
</section>
|
|
7440
|
+
);
|
|
7441
|
+
}
|
|
7442
|
+
|
|
7443
|
+
END_OF_FILE_CONTENT
|
|
7444
|
+
echo "Creating src/components/olon-getstarted/index.ts..."
|
|
7445
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-getstarted/index.ts"
|
|
7446
|
+
export { OlonGetStartedView as View } from './View';
|
|
7447
|
+
export { OlonGetStartedSchema } from './schema';
|
|
7448
|
+
export type { OlonGetStartedData } from './types';
|
|
7449
|
+
|
|
7450
|
+
END_OF_FILE_CONTENT
|
|
7451
|
+
echo "Creating src/components/olon-getstarted/schema.ts..."
|
|
7452
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-getstarted/schema.ts"
|
|
7453
|
+
import { z } from 'zod';
|
|
7454
|
+
import { BaseSectionData, BaseArrayItem } from '@/lib/base-schemas';
|
|
7455
|
+
|
|
7456
|
+
export const StartCardSchema = BaseArrayItem.extend({
|
|
7457
|
+
badge: z.string(),
|
|
7458
|
+
badgeStyle: z.enum(['oss', 'cli', 'deploy']),
|
|
7459
|
+
title: z.string(),
|
|
7460
|
+
body: z.string(),
|
|
7461
|
+
code: z.string().optional(),
|
|
7462
|
+
linkLabel: z.string(),
|
|
7463
|
+
linkHref: z.string(),
|
|
7464
|
+
deployLabel:z.string().optional(),
|
|
7465
|
+
deployHref: z.string().optional(),
|
|
7466
|
+
});
|
|
7467
|
+
|
|
7468
|
+
export const OlonGetStartedSchema = BaseSectionData.extend({
|
|
7469
|
+
label: z.string().default('Get Started'),
|
|
7470
|
+
headline: z.string().default('Three paths in.'),
|
|
7471
|
+
body: z.string().default(''),
|
|
7472
|
+
cards: z.array(StartCardSchema).min(1).max(3),
|
|
7473
|
+
});
|
|
7474
|
+
|
|
7475
|
+
export type OlonGetStartedData = z.infer<typeof OlonGetStartedSchema>;
|
|
7476
|
+
|
|
7477
|
+
END_OF_FILE_CONTENT
|
|
7478
|
+
echo "Creating src/components/olon-getstarted/types.ts..."
|
|
7479
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-getstarted/types.ts"
|
|
7480
|
+
export type { OlonGetStartedData } from './schema';
|
|
7481
|
+
|
|
7482
|
+
END_OF_FILE_CONTENT
|
|
7483
|
+
mkdir -p "src/components/olon-hero"
|
|
7484
|
+
echo "Creating src/components/olon-hero/DawnBackground.tsx..."
|
|
7485
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-hero/DawnBackground.tsx"
|
|
7486
|
+
import { useEffect, useRef } from 'react';
|
|
7487
|
+
import { motion } from 'motion/react';
|
|
7488
|
+
|
|
7489
|
+
export function DawnBackground({
|
|
7490
|
+
dawnDuration = 3.5,
|
|
7491
|
+
breathingSpeed = 0.5,
|
|
7492
|
+
breathingRange = 0.03,
|
|
7493
|
+
intensity = 0.55,
|
|
7494
|
+
}: {
|
|
7495
|
+
dawnDuration?: number;
|
|
7496
|
+
breathingSpeed?: number;
|
|
7497
|
+
breathingRange?: number;
|
|
7498
|
+
intensity?: number;
|
|
7499
|
+
}) {
|
|
7500
|
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
7501
|
+
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
|
7502
|
+
const rafRef = useRef<number>(0);
|
|
7503
|
+
const startRef = useRef<number | null>(null);
|
|
7504
|
+
|
|
7505
|
+
useEffect(() => {
|
|
7506
|
+
const canvas = canvasRef.current;
|
|
7507
|
+
const container = containerRef.current;
|
|
7508
|
+
if (!canvas || !container) return;
|
|
7509
|
+
|
|
7510
|
+
const ctx = canvas.getContext('2d');
|
|
7511
|
+
if (!ctx) return;
|
|
7512
|
+
|
|
7513
|
+
function resize() {
|
|
7514
|
+
if (!canvas || !container) return;
|
|
7515
|
+
const dpr = window.devicePixelRatio || 1;
|
|
7516
|
+
canvas.width = container.offsetWidth * dpr;
|
|
7517
|
+
canvas.height = container.offsetHeight * dpr;
|
|
7518
|
+
}
|
|
7519
|
+
resize();
|
|
7520
|
+
|
|
7521
|
+
const ro = new ResizeObserver(resize);
|
|
7522
|
+
ro.observe(container);
|
|
7523
|
+
|
|
7524
|
+
function easeOut(t: number) {
|
|
7525
|
+
return 1 - Math.pow(1 - t, 3);
|
|
7526
|
+
}
|
|
7527
|
+
|
|
7528
|
+
function draw(ts: number) {
|
|
7529
|
+
if (!canvas || !ctx) return;
|
|
7530
|
+
if (!startRef.current) startRef.current = ts;
|
|
7531
|
+
|
|
7532
|
+
const elapsed = (ts - startRef.current) / 1000;
|
|
7533
|
+
const dawnP = Math.min(elapsed / dawnDuration, 1);
|
|
7534
|
+
const dawnE = easeOut(dawnP);
|
|
7535
|
+
const breathT = Math.max(0, elapsed - dawnDuration);
|
|
7536
|
+
const breathe = dawnP >= 1
|
|
7537
|
+
? 1 + Math.sin(breathT * breathingSpeed) * breathingRange
|
|
7538
|
+
: 1;
|
|
7539
|
+
|
|
7540
|
+
const W = canvas.width;
|
|
7541
|
+
const H = canvas.height;
|
|
7542
|
+
const masterIntensity = dawnE * intensity * breathe;
|
|
7543
|
+
|
|
7544
|
+
ctx.clearRect(0, 0, W, H);
|
|
7545
|
+
|
|
7546
|
+
// Left source — bottom left, primary blue
|
|
7547
|
+
const lx = W * 0.18;
|
|
7548
|
+
const ly = H * 0.92;
|
|
7549
|
+
const lr = W * 0.75 * breathe;
|
|
7550
|
+
const gL = ctx.createRadialGradient(lx, ly, 0, lx, ly, lr);
|
|
7551
|
+
gL.addColorStop(0.00, `rgba(15,52,224,${0.70 * masterIntensity})`);
|
|
7552
|
+
gL.addColorStop(0.20, `rgba(23,99,255,${0.60 * masterIntensity})`);
|
|
7553
|
+
gL.addColorStop(0.45, `rgba(91,142,255,${0.35 * masterIntensity})`);
|
|
7554
|
+
gL.addColorStop(0.70, `rgba(84,171,255,${0.15 * masterIntensity})`);
|
|
7555
|
+
gL.addColorStop(1.00, 'rgba(12,17,22,0)');
|
|
7556
|
+
ctx.fillStyle = gL;
|
|
7557
|
+
ctx.fillRect(0, 0, W, H);
|
|
7558
|
+
|
|
7559
|
+
// Right source — mirror
|
|
7560
|
+
const gR = ctx.createRadialGradient(W - lx, ly, 0, W - lx, ly, lr);
|
|
7561
|
+
gR.addColorStop(0.00, `rgba(15,52,224,${0.70 * masterIntensity})`);
|
|
7562
|
+
gR.addColorStop(0.20, `rgba(23,99,255,${0.60 * masterIntensity})`);
|
|
7563
|
+
gR.addColorStop(0.45, `rgba(91,142,255,${0.35 * masterIntensity})`);
|
|
7564
|
+
gR.addColorStop(0.70, `rgba(84,171,255,${0.15 * masterIntensity})`);
|
|
7565
|
+
gR.addColorStop(1.00, 'rgba(12,17,22,0)');
|
|
7566
|
+
ctx.fillStyle = gR;
|
|
7567
|
+
ctx.fillRect(0, 0, W, H);
|
|
7568
|
+
|
|
7569
|
+
// Center V tip — deep navy, very subtle
|
|
7570
|
+
const vr = W * 0.32 * breathe;
|
|
7571
|
+
const gV = ctx.createRadialGradient(W * 0.5, H * 0.72, 0, W * 0.5, H * 0.72, vr);
|
|
7572
|
+
gV.addColorStop(0.00, `rgba(9,64,184,${0.50 * masterIntensity})`);
|
|
7573
|
+
gV.addColorStop(0.40, `rgba(15,52,224,${0.25 * masterIntensity})`);
|
|
7574
|
+
gV.addColorStop(1.00, 'rgba(12,17,22,0)');
|
|
7575
|
+
ctx.fillStyle = gV;
|
|
7576
|
+
ctx.fillRect(0, 0, W, H);
|
|
7577
|
+
|
|
7578
|
+
// Top dark veil — keeps header very dark
|
|
7579
|
+
const gTop = ctx.createLinearGradient(0, 0, 0, H * 0.6);
|
|
7580
|
+
gTop.addColorStop(0, 'rgba(12,17,22,1)');
|
|
7581
|
+
gTop.addColorStop(0.55, 'rgba(12,17,22,0.85)');
|
|
7582
|
+
gTop.addColorStop(1, 'rgba(12,17,22,0)');
|
|
7583
|
+
ctx.fillStyle = gTop;
|
|
7584
|
+
ctx.fillRect(0, 0, W, H);
|
|
7585
|
+
|
|
7586
|
+
rafRef.current = requestAnimationFrame(draw);
|
|
7587
|
+
}
|
|
7588
|
+
|
|
7589
|
+
rafRef.current = requestAnimationFrame(draw);
|
|
7590
|
+
|
|
7591
|
+
return () => {
|
|
7592
|
+
cancelAnimationFrame(rafRef.current);
|
|
7593
|
+
ro.disconnect();
|
|
7594
|
+
};
|
|
7595
|
+
}, [dawnDuration, breathingSpeed, breathingRange, intensity]);
|
|
7596
|
+
|
|
7597
|
+
return (
|
|
7598
|
+
<motion.div
|
|
7599
|
+
ref={containerRef}
|
|
7600
|
+
className="absolute inset-0 overflow-hidden"
|
|
7601
|
+
animate={{ opacity: 1, transition: { duration: 0.1 } }}
|
|
7602
|
+
initial={{ opacity: 0 }}
|
|
7603
|
+
>
|
|
7604
|
+
<canvas
|
|
7605
|
+
ref={canvasRef}
|
|
7606
|
+
className="absolute inset-0 w-full h-full"
|
|
7607
|
+
/>
|
|
7608
|
+
</motion.div>
|
|
7609
|
+
);
|
|
7610
|
+
}
|
|
7611
|
+
|
|
7612
|
+
END_OF_FILE_CONTENT
|
|
7613
|
+
echo "Creating src/components/olon-hero/View.tsx..."
|
|
7614
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-hero/View.tsx"
|
|
7615
|
+
import type { OlonHeroData } from './types';
|
|
7616
|
+
import { Button } from '@/components/ui/button';
|
|
7617
|
+
import { Github, Terminal } from 'lucide-react';
|
|
7618
|
+
|
|
7619
|
+
|
|
7620
|
+
interface Props {
|
|
7621
|
+
data: OlonHeroData;
|
|
7622
|
+
}
|
|
7623
|
+
|
|
7624
|
+
const heroPlugImage = '/assets/images/plug-graded-square.jpg';
|
|
7625
|
+
|
|
7626
|
+
export function OlonHeroView({ data }: Props) {
|
|
7627
|
+
return (
|
|
7628
|
+
<section
|
|
7629
|
+
style={{
|
|
7630
|
+
'--local-bg': 'var(--background)',
|
|
7631
|
+
'--local-fg': 'var(--foreground)',
|
|
7632
|
+
'--local-muted': 'var(--muted-foreground)',
|
|
7633
|
+
'--local-primary': 'var(--primary)',
|
|
7634
|
+
'--local-p300': 'var(--primary-light)',
|
|
7635
|
+
} as React.CSSProperties}
|
|
7636
|
+
className="relative min-h-screen bg-[var(--local-bg)] text-[var(--local-fg)] pt-36 pb-24 overflow-hidden"
|
|
7637
|
+
data-jp-section-id={data.id}
|
|
7638
|
+
data-jp-section-type="olon-hero"
|
|
7639
|
+
>
|
|
7640
|
+
{/* Dawn background — absolute, behind content */}
|
|
7641
|
+
|
|
7642
|
+
|
|
7643
|
+
{/* Content — relative, above background */}
|
|
7644
|
+
<div className="relative z-10 max-w-6xl mx-auto px-8 grid grid-cols-1 md:grid-cols-2 gap-16 items-center">
|
|
7645
|
+
{/* Left: copy */}
|
|
7646
|
+
<div className="flex flex-col gap-6">
|
|
7647
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
7648
|
+
<p
|
|
7649
|
+
className="text-xs font-semibold tracking-[0.12em] uppercase text-[var(--local-muted)]"
|
|
7650
|
+
data-jp-field="eyebrow"
|
|
7651
|
+
>
|
|
7652
|
+
{data.eyebrow}
|
|
7653
|
+
</p>
|
|
7654
|
+
<div className="flex items-center gap-2">
|
|
7655
|
+
<a href="https://www.npmjs.com/package/@olonjs/core">
|
|
7656
|
+
<img src="https://img.shields.io/npm/v/@olonjs/core?color=blue&style=flat-square" alt="npm version"/>
|
|
7657
|
+
</a>
|
|
7658
|
+
<a href="https://github.com/olonjs/npm-jpcore/blob/main/LICENSE">
|
|
7659
|
+
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="license"/>
|
|
7660
|
+
</a>
|
|
7661
|
+
</div>
|
|
7662
|
+
</div>
|
|
7663
|
+
|
|
7664
|
+
<div>
|
|
7665
|
+
<h1
|
|
7666
|
+
className="text-6xl md:text-7xl font-bold tracking-[-0.03em] leading-[1.05] text-foreground"
|
|
7667
|
+
data-jp-field="headline"
|
|
7668
|
+
>
|
|
7669
|
+
{data.headline}
|
|
7670
|
+
</h1>
|
|
7671
|
+
<p
|
|
7672
|
+
className="text-4xl md:text-5xl font-semibold tracking-[-0.03em] leading-[1.1] text-[var(--local-p300)] italic mt-1"
|
|
7673
|
+
data-jp-field="subline"
|
|
7674
|
+
>
|
|
7675
|
+
{data.subline}
|
|
7676
|
+
</p>
|
|
7677
|
+
</div>
|
|
7678
|
+
|
|
7679
|
+
<p
|
|
7680
|
+
className="text-base text-[var(--local-muted)] leading-relaxed max-w-lg"
|
|
7681
|
+
data-jp-field="body"
|
|
7682
|
+
>
|
|
7683
|
+
{data.body}
|
|
7684
|
+
</p>
|
|
7685
|
+
|
|
7686
|
+
<div className="flex flex-wrap gap-3 items-center">
|
|
7687
|
+
<Button asChild size="lg" className="font-semibold">
|
|
7688
|
+
<a href={data.cta.primary.href}>
|
|
7689
|
+
{data.cta.primary.label} →
|
|
7690
|
+
</a>
|
|
7691
|
+
</Button>
|
|
7692
|
+
<Button asChild variant="outline" size="lg" className="font-semibold gap-2">
|
|
7693
|
+
<a href={data.cta.secondary.href}>
|
|
7694
|
+
<Github className="w-4 h-4" />
|
|
7695
|
+
{data.cta.secondary.label}
|
|
7696
|
+
</a>
|
|
7697
|
+
</Button>
|
|
7698
|
+
<a
|
|
7699
|
+
href={data.cta.ghost.href}
|
|
7700
|
+
className="text-sm text-[var(--local-muted)] hover:text-[var(--local-fg)] transition-colors flex items-center gap-1.5"
|
|
7701
|
+
>
|
|
7702
|
+
{data.cta.ghost.label}
|
|
7703
|
+
<Terminal className="w-4 h-4" />
|
|
7704
|
+
</a>
|
|
7705
|
+
</div>
|
|
7706
|
+
</div>
|
|
7707
|
+
|
|
7708
|
+
{/* Right: branded product photo */}
|
|
7709
|
+
<div className="hidden md:flex items-center justify-center">
|
|
7710
|
+
<div className="relative w-full max-w-lg">
|
|
7711
|
+
<div className="absolute inset-[-8%] bg-[radial-gradient(circle_at_50%_50%,rgba(52,109,255,0.22),rgba(12,17,22,0)_70%)] blur-2xl" />
|
|
7712
|
+
<div className="relative aspect-[1/1.03] overflow-hidden rounded-none border border-white/14 bg-[#0d1219] shadow-[0_22px_56px_rgba(4,8,20,0.42)]">
|
|
7713
|
+
<img
|
|
7714
|
+
src={heroPlugImage}
|
|
7715
|
+
alt="Olon interface port engraved into a dark stone surface"
|
|
7716
|
+
className="absolute inset-0 h-full w-full object-cover"
|
|
7717
|
+
style={{ objectPosition: '50% 50%' }}
|
|
7718
|
+
/>
|
|
7719
|
+
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(7,11,21,0.02)_0%,rgba(7,11,21,0.14)_24%,rgba(7,11,21,0.44)_100%)]" />
|
|
7720
|
+
<div className="absolute inset-0 bg-[radial-gradient(circle_at_62%_44%,rgba(122,163,255,0.18),rgba(29,78,216,0.08)_24%,rgba(12,17,22,0)_54%)] mix-blend-screen" />
|
|
7721
|
+
</div>
|
|
7722
|
+
</div>
|
|
7723
|
+
</div>
|
|
7724
|
+
</div>
|
|
7725
|
+
</section>
|
|
7726
|
+
);
|
|
7727
|
+
}
|
|
7728
|
+
|
|
7729
|
+
END_OF_FILE_CONTENT
|
|
7730
|
+
echo "Creating src/components/olon-hero/View_.tsx..."
|
|
7731
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-hero/View_.tsx"
|
|
7732
|
+
import type { OlonHeroData } from './types';
|
|
7733
|
+
import { Button } from '@/components/ui/button';
|
|
7734
|
+
|
|
7735
|
+
interface Props {
|
|
7736
|
+
data: OlonHeroData;
|
|
7737
|
+
}
|
|
7738
|
+
|
|
7739
|
+
export function OlonHeroView({ data }: Props) {
|
|
7740
|
+
return (
|
|
7741
|
+
<section
|
|
7742
|
+
style={{
|
|
7743
|
+
'--local-bg': 'var(--background)',
|
|
7744
|
+
'--local-fg': 'var(--foreground)',
|
|
7745
|
+
'--local-muted': 'var(--muted-foreground)',
|
|
7746
|
+
'--local-primary': 'var(--primary)',
|
|
7747
|
+
'--local-p300': 'var(--primary-light)',
|
|
7748
|
+
} as React.CSSProperties}
|
|
7749
|
+
className="min-h-screen bg-[var(--local-bg)] text-[var(--local-fg)] pt-36 pb-24"
|
|
7750
|
+
data-jp-section-id={data.id}
|
|
7751
|
+
data-jp-section-type="olon-hero"
|
|
7752
|
+
>
|
|
7753
|
+
<div className="max-w-6xl mx-auto px-8 grid grid-cols-1 md:grid-cols-2 gap-16 items-center">
|
|
7754
|
+
{/* Left: copy */}
|
|
7755
|
+
<div className="flex flex-col gap-6">
|
|
7756
|
+
<p className="text-xs font-semibold tracking-[0.12em] uppercase text-[var(--local-muted)]"
|
|
7757
|
+
data-jp-field="eyebrow">
|
|
7758
|
+
{data.eyebrow}
|
|
7759
|
+
</p>
|
|
7760
|
+
|
|
7761
|
+
<div>
|
|
7762
|
+
<h1 className="text-5xl md:text-6xl font-bold tracking-[-0.03em] leading-[1.05] text-foreground"
|
|
7763
|
+
data-jp-field="headline">
|
|
7764
|
+
{data.headline}
|
|
7765
|
+
</h1>
|
|
7766
|
+
<p className="text-4xl md:text-5xl font-semibold tracking-[-0.03em] leading-[1.1] text-[var(--local-p300)] italic mt-1"
|
|
7767
|
+
data-jp-field="subline">
|
|
7768
|
+
{data.subline}
|
|
7769
|
+
</p>
|
|
7770
|
+
</div>
|
|
7771
|
+
|
|
7772
|
+
<p className="text-base text-[var(--local-muted)] leading-relaxed max-w-lg"
|
|
7773
|
+
data-jp-field="body">
|
|
7774
|
+
{data.body}
|
|
7775
|
+
</p>
|
|
7776
|
+
|
|
7777
|
+
<div className="flex flex-wrap gap-3 items-center">
|
|
7778
|
+
<Button asChild size="lg" className="font-semibold">
|
|
7779
|
+
<a href={data.cta.primary.href}>{data.cta.primary.label} →</a>
|
|
7780
|
+
</Button>
|
|
7781
|
+
<Button asChild variant="outline" size="lg" className="font-semibold">
|
|
7782
|
+
<a href={data.cta.secondary.href}>{data.cta.secondary.label}</a>
|
|
7783
|
+
</Button>
|
|
7784
|
+
<a href={data.cta.ghost.href}
|
|
7785
|
+
className="text-sm text-[var(--local-muted)] hover:text-[var(--local-fg)] transition-colors flex items-center gap-1.5">
|
|
7786
|
+
{data.cta.ghost.label}
|
|
7787
|
+
</a>
|
|
7788
|
+
</div>
|
|
7789
|
+
</div>
|
|
7790
|
+
|
|
7791
|
+
{/* Right: SVG illustration */}
|
|
7792
|
+
<div className="hidden md:flex items-center justify-center">
|
|
7793
|
+
<svg viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full max-w-md">
|
|
7794
|
+
<defs>
|
|
7795
|
+
<linearGradient id="hero-main" x1="0" y1="0" x2="1" y2="1">
|
|
7796
|
+
<stop offset="0%" stopColor="#84ABFF"/>
|
|
7797
|
+
<stop offset="60%" stopColor="#1763FF"/>
|
|
7798
|
+
<stop offset="100%" stopColor="#0F52E0"/>
|
|
7799
|
+
</linearGradient>
|
|
7800
|
+
<linearGradient id="hero-accent" x1="0" y1="0" x2="0" y2="1">
|
|
7801
|
+
<stop offset="0%" stopColor="#EEF3FF"/>
|
|
7802
|
+
<stop offset="100%" stopColor="#84ABFF"/>
|
|
7803
|
+
</linearGradient>
|
|
7804
|
+
<linearGradient id="hero-glow" x1="0" y1="0" x2="0" y2="1">
|
|
7805
|
+
<stop offset="0%" stopColor="#1763FF" stopOpacity="0.3"/>
|
|
7806
|
+
<stop offset="100%" stopColor="#1763FF" stopOpacity="0"/>
|
|
7807
|
+
</linearGradient>
|
|
7808
|
+
<filter id="glow"><feGaussianBlur stdDeviation="8" result="blur"/><feComposite in="SourceGraphic" in2="blur" operator="over"/></filter>
|
|
7809
|
+
</defs>
|
|
7810
|
+
<circle cx="200" cy="200" r="160" fill="url(#hero-glow)" opacity="0.4"/>
|
|
7811
|
+
<rect x="90" y="90" width="220" height="220" rx="28" fill="none" stroke="url(#hero-main)" strokeWidth="14"/>
|
|
7812
|
+
<line x1="16" y1="148" x2="90" y2="148" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7813
|
+
<line x1="16" y1="200" x2="90" y2="200" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7814
|
+
<line x1="16" y1="252" x2="90" y2="252" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7815
|
+
<line x1="310" y1="148" x2="384" y2="148" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7816
|
+
<line x1="310" y1="200" x2="384" y2="200" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7817
|
+
<line x1="310" y1="252" x2="384" y2="252" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7818
|
+
<line x1="148" y1="16" x2="148" y2="90" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7819
|
+
<line x1="200" y1="16" x2="200" y2="90" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7820
|
+
<line x1="252" y1="16" x2="252" y2="90" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7821
|
+
<line x1="148" y1="310" x2="148" y2="384" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7822
|
+
<line x1="200" y1="310" x2="200" y2="384" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7823
|
+
<line x1="252" y1="310" x2="252" y2="384" stroke="url(#hero-main)" strokeWidth="10" strokeLinecap="round"/>
|
|
7824
|
+
<circle cx="148" cy="148" r="13" fill="url(#hero-main)"/>
|
|
7825
|
+
<circle cx="252" cy="148" r="13" fill="url(#hero-main)"/>
|
|
7826
|
+
<circle cx="148" cy="252" r="13" fill="url(#hero-main)"/>
|
|
7827
|
+
<circle cx="252" cy="252" r="13" fill="url(#hero-main)"/>
|
|
7828
|
+
<line x1="148" y1="148" x2="200" y2="200" stroke="#84ABFF" strokeWidth="2.5" opacity="0.35"/>
|
|
7829
|
+
<line x1="252" y1="148" x2="200" y2="200" stroke="#84ABFF" strokeWidth="2.5" opacity="0.35"/>
|
|
7830
|
+
<line x1="148" y1="252" x2="200" y2="200" stroke="#84ABFF" strokeWidth="2.5" opacity="0.35"/>
|
|
7831
|
+
<line x1="252" y1="252" x2="200" y2="200" stroke="#84ABFF" strokeWidth="2.5" opacity="0.35"/>
|
|
7832
|
+
<circle cx="200" cy="200" r="18" fill="url(#hero-accent)" filter="url(#glow)"/>
|
|
7833
|
+
</svg>
|
|
7834
|
+
</div>
|
|
7835
|
+
</div>
|
|
7836
|
+
</section>
|
|
7837
|
+
);
|
|
7838
|
+
}
|
|
7839
|
+
|
|
7840
|
+
END_OF_FILE_CONTENT
|
|
7841
|
+
echo "Creating src/components/olon-hero/index.ts..."
|
|
7842
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-hero/index.ts"
|
|
7843
|
+
export { OlonHeroView as View } from './View';
|
|
7844
|
+
export { OlonHeroSchema } from './schema';
|
|
7845
|
+
export type { OlonHeroData } from './types';
|
|
7846
|
+
|
|
7847
|
+
END_OF_FILE_CONTENT
|
|
7848
|
+
echo "Creating src/components/olon-hero/schema.ts..."
|
|
7849
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-hero/schema.ts"
|
|
7850
|
+
import { z } from 'zod';
|
|
7851
|
+
import { BaseSectionData } from '@/lib/base-schemas';
|
|
7852
|
+
|
|
7853
|
+
export const OlonHeroSchema = BaseSectionData.extend({
|
|
7854
|
+
eyebrow: z.string().default('CONTRACT LAYER · V1.5 · OPEN CORE'),
|
|
7855
|
+
headline: z.string().default('Contract Layer'),
|
|
7856
|
+
subline: z.string().default('for the agentic web.'),
|
|
7857
|
+
body: z.string().default(''),
|
|
7858
|
+
cta: z.object({
|
|
7859
|
+
primary: z.object({ label: z.string(), href: z.string() }),
|
|
7860
|
+
secondary: z.object({ label: z.string(), href: z.string() }),
|
|
7861
|
+
ghost: z.object({ label: z.string(), href: z.string() }),
|
|
7862
|
+
}),
|
|
7863
|
+
});
|
|
7864
|
+
|
|
7865
|
+
export type OlonHeroData = z.infer<typeof OlonHeroSchema>;
|
|
7866
|
+
|
|
7867
|
+
END_OF_FILE_CONTENT
|
|
7868
|
+
echo "Creating src/components/olon-hero/types.ts..."
|
|
7869
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-hero/types.ts"
|
|
7870
|
+
export type { OlonHeroData } from './schema';
|
|
7871
|
+
|
|
7872
|
+
END_OF_FILE_CONTENT
|
|
7873
|
+
mkdir -p "src/components/olon-why"
|
|
7874
|
+
echo "Creating src/components/olon-why/View.tsx..."
|
|
7875
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-why/View.tsx"
|
|
7876
|
+
import type { OlonWhyData } from './types';
|
|
7877
|
+
|
|
7878
|
+
const ICONS = {
|
|
7879
|
+
contract: (
|
|
7880
|
+
<svg width="36" height="36" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7881
|
+
<defs>
|
|
7882
|
+
<linearGradient id="w1" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#84ABFF"/><stop offset="1" stopColor="#0F52E0"/></linearGradient>
|
|
7883
|
+
</defs>
|
|
7884
|
+
<rect x="20" y="20" width="160" height="160" rx="16" fill="none" stroke="url(#w1)" strokeWidth="10"/>
|
|
7885
|
+
<line x1="20" y1="70" x2="180" y2="70" stroke="url(#w1)" strokeWidth="7"/>
|
|
7886
|
+
<rect x="40" y="100" width="60" height="8" rx="4" fill="url(#w1)" opacity="0.4"/>
|
|
7887
|
+
<rect x="40" y="118" width="90" height="8" rx="4" fill="url(#w1)" opacity="0.7"/>
|
|
7888
|
+
<rect x="40" y="136" width="72" height="8" rx="4" fill="url(#w1)" opacity="0.5"/>
|
|
7889
|
+
</svg>
|
|
7890
|
+
),
|
|
7891
|
+
holon: (
|
|
7892
|
+
<svg width="36" height="36" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7893
|
+
<defs>
|
|
7894
|
+
<linearGradient id="w2" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#84ABFF"/><stop offset="1" stopColor="#0F52E0"/></linearGradient>
|
|
7895
|
+
<linearGradient id="w2a" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#EEF3FF"/><stop offset="1" stopColor="#84ABFF"/></linearGradient>
|
|
7896
|
+
</defs>
|
|
7897
|
+
<circle cx="100" cy="100" r="75" fill="none" stroke="url(#w2)" strokeWidth="10"/>
|
|
7898
|
+
<circle cx="100" cy="100" r="28" fill="url(#w2a)"/>
|
|
7899
|
+
</svg>
|
|
7900
|
+
),
|
|
7901
|
+
generated: (
|
|
7902
|
+
<svg width="36" height="36" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7903
|
+
<defs>
|
|
7904
|
+
<linearGradient id="w3" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#84ABFF"/><stop offset="1" stopColor="#0F52E0"/></linearGradient>
|
|
7905
|
+
</defs>
|
|
7906
|
+
<circle cx="100" cy="40" r="14" fill="url(#w3)"/>
|
|
7907
|
+
<circle cx="50" cy="110" r="12" fill="url(#w3)" opacity="0.6"/>
|
|
7908
|
+
<circle cx="150" cy="110" r="12" fill="url(#w3)" opacity="0.6"/>
|
|
7909
|
+
<circle cx="80" cy="175" r="10" fill="url(#w3)" opacity="0.35"/>
|
|
7910
|
+
<circle cx="130" cy="175" r="14" fill="url(#w3)"/>
|
|
7911
|
+
<line x1="100" y1="54" x2="54" y2="98" stroke="url(#w3)" strokeWidth="5" strokeLinecap="round"/>
|
|
7912
|
+
<line x1="100" y1="54" x2="146" y2="98" stroke="url(#w3)" strokeWidth="5" strokeLinecap="round" opacity="0.4"/>
|
|
7913
|
+
<line x1="54" y1="122" x2="82" y2="165" stroke="url(#w3)" strokeWidth="4" strokeLinecap="round" opacity="0.35"/>
|
|
7914
|
+
<line x1="146" y1="122" x2="128" y2="165" stroke="url(#w3)" strokeWidth="5" strokeLinecap="round"/>
|
|
7915
|
+
</svg>
|
|
7916
|
+
),
|
|
7917
|
+
};
|
|
7918
|
+
|
|
7919
|
+
interface Props { data: OlonWhyData; }
|
|
7920
|
+
|
|
7921
|
+
export function OlonWhyView({ data }: Props) {
|
|
7922
|
+
return (
|
|
7923
|
+
<section
|
|
7924
|
+
style={{
|
|
7925
|
+
'--local-bg': 'var(--background)',
|
|
7926
|
+
'--local-fg': 'var(--foreground)',
|
|
7927
|
+
'--local-muted': 'var(--muted-foreground)',
|
|
7928
|
+
'--local-p300': 'var(--primary-light)',
|
|
7929
|
+
'--local-card': 'var(--card)',
|
|
7930
|
+
'--local-border':'var(--border)',
|
|
7931
|
+
} as React.CSSProperties}
|
|
7932
|
+
className="bg-[var(--local-bg)] text-[var(--local-fg)] py-24 border-t border-[var(--local-border)]"
|
|
7933
|
+
data-jp-section-id={data.id}
|
|
7934
|
+
data-jp-section-type="olon-why"
|
|
7935
|
+
>
|
|
7936
|
+
<div className="max-w-6xl mx-auto px-8">
|
|
7937
|
+
<p className="text-xs font-semibold tracking-[0.12em] uppercase text-[var(--local-muted)] mb-3"
|
|
7938
|
+
data-jp-field="label">{data.label}</p>
|
|
7939
|
+
<h2 className="text-4xl font-bold tracking-[-0.03em] text-foreground leading-tight"
|
|
7940
|
+
data-jp-field="headline">{data.headline}</h2>
|
|
7941
|
+
<p className="text-3xl font-semibold tracking-[-0.03em] text-[var(--local-p300)] leading-tight mb-4"
|
|
7942
|
+
data-jp-field="subline">{data.subline}</p>
|
|
7943
|
+
<p className="text-base text-[var(--local-muted)] leading-relaxed max-w-2xl mb-12"
|
|
7944
|
+
data-jp-field="body">{data.body}</p>
|
|
7945
|
+
|
|
7946
|
+
<div className="grid grid-cols-1 md:grid-cols-3 border border-[var(--local-border)] rounded-2xl overflow-hidden"
|
|
7947
|
+
data-jp-array="pillars">
|
|
7948
|
+
{data.pillars.map((pillar) => (
|
|
7949
|
+
<div key={pillar.id}
|
|
7950
|
+
className="bg-[var(--local-card)] p-8 flex flex-col gap-4 border-r last:border-r-0 border-[var(--local-border)]"
|
|
7951
|
+
data-jp-item-id={pillar.id}>
|
|
7952
|
+
<div>{ICONS[pillar.icon]}</div>
|
|
7953
|
+
<div className="font-bold text-foreground" data-jp-field="title">{pillar.title}</div>
|
|
7954
|
+
<div className="text-sm text-[var(--local-muted)] leading-relaxed" data-jp-field="body">{pillar.body}</div>
|
|
7955
|
+
</div>
|
|
7956
|
+
))}
|
|
7957
|
+
</div>
|
|
7958
|
+
</div>
|
|
7959
|
+
</section>
|
|
7960
|
+
);
|
|
7961
|
+
}
|
|
7962
|
+
|
|
7963
|
+
END_OF_FILE_CONTENT
|
|
7964
|
+
echo "Creating src/components/olon-why/index.ts..."
|
|
7965
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-why/index.ts"
|
|
7966
|
+
export { OlonWhyView as View } from './View';
|
|
7967
|
+
export { OlonWhySchema } from './schema';
|
|
7968
|
+
export type { OlonWhyData } from './types';
|
|
6781
7969
|
|
|
6782
7970
|
END_OF_FILE_CONTENT
|
|
6783
|
-
echo "Creating src/components/
|
|
6784
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/
|
|
6785
|
-
import { z } from 'zod';
|
|
6786
|
-
import { BaseSectionData } from '@/lib/base-schemas';
|
|
6787
|
-
|
|
6788
|
-
export const
|
|
6789
|
-
title:
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
7971
|
+
echo "Creating src/components/olon-why/schema.ts..."
|
|
7972
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-why/schema.ts"
|
|
7973
|
+
import { z } from 'zod';
|
|
7974
|
+
import { BaseSectionData, BaseArrayItem } from '@/lib/base-schemas';
|
|
7975
|
+
|
|
7976
|
+
export const PillarSchema = BaseArrayItem.extend({
|
|
7977
|
+
title: z.string(),
|
|
7978
|
+
body: z.string(),
|
|
7979
|
+
icon: z.enum(['contract', 'holon', 'generated']),
|
|
7980
|
+
});
|
|
7981
|
+
|
|
7982
|
+
export const OlonWhySchema = BaseSectionData.extend({
|
|
7983
|
+
label: z.string().default('Why OlonJS'),
|
|
7984
|
+
headline: z.string().default('A Meaningful Web'),
|
|
7985
|
+
subline: z.string().default('Whole in itself, part of something greater.'),
|
|
7986
|
+
body: z.string().default(''),
|
|
7987
|
+
pillars: z.array(PillarSchema).min(1).max(3),
|
|
7988
|
+
});
|
|
7989
|
+
|
|
7990
|
+
export type OlonWhyData = z.infer<typeof OlonWhySchema>;
|
|
6800
7991
|
|
|
6801
7992
|
END_OF_FILE_CONTENT
|
|
6802
|
-
echo "Creating src/components/
|
|
6803
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/
|
|
6804
|
-
|
|
6805
|
-
import { LoginSchema, LoginSettingsSchema } from './schema';
|
|
6806
|
-
|
|
6807
|
-
export type LoginData = z.infer<typeof LoginSchema>;
|
|
6808
|
-
export type LoginSettings = z.infer<typeof LoginSettingsSchema>;
|
|
7993
|
+
echo "Creating src/components/olon-why/types.ts..."
|
|
7994
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/olon-why/types.ts"
|
|
7995
|
+
export type { OlonWhyData } from './schema';
|
|
6809
7996
|
|
|
6810
7997
|
END_OF_FILE_CONTENT
|
|
6811
7998
|
mkdir -p "src/components/page-hero"
|
|
@@ -9072,7 +10259,7 @@ const StudioTiptapEditor: React.FC<{ data: TiptapData }> = ({ data }) => {
|
|
|
9072
10259
|
type="button"
|
|
9073
10260
|
onMouseDown={(e) => e.preventDefault()}
|
|
9074
10261
|
onClick={applyLink}
|
|
9075
|
-
className="shrink-0 rounded-[var(--local-radius-sm)] px-2 py-0.5 text-xs bg-[var(--local-primary)] hover:brightness-110 text-
|
|
10262
|
+
className="shrink-0 rounded-[var(--local-radius-sm)] px-2 py-0.5 text-xs bg-[var(--local-primary)] hover:brightness-110 text-foreground transition-colors"
|
|
9076
10263
|
>
|
|
9077
10264
|
Set
|
|
9078
10265
|
</button>
|
|
@@ -9267,88 +10454,88 @@ END_OF_FILE_CONTENT
|
|
|
9267
10454
|
mkdir -p "src/components/ui"
|
|
9268
10455
|
echo "Creating src/components/ui/OlonMark.tsx..."
|
|
9269
10456
|
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/OlonMark.tsx"
|
|
9270
|
-
import { cn } from '@/lib/utils'
|
|
9271
|
-
|
|
9272
|
-
interface OlonMarkProps {
|
|
9273
|
-
size?: number
|
|
9274
|
-
/** mono: uses currentColor — for single-colour print/emboss contexts */
|
|
9275
|
-
variant?: 'default' | 'mono'
|
|
9276
|
-
className?: string
|
|
9277
|
-
}
|
|
9278
|
-
|
|
9279
|
-
export function OlonMark({ size = 32, variant = 'default', className }: OlonMarkProps) {
|
|
9280
|
-
const gid = `olon-ring-${size}`
|
|
9281
|
-
|
|
9282
|
-
if (variant === 'mono') {
|
|
9283
|
-
return (
|
|
9284
|
-
<svg
|
|
9285
|
-
viewBox="0 0 100 100"
|
|
9286
|
-
fill="none"
|
|
9287
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
9288
|
-
width={size}
|
|
9289
|
-
height={size}
|
|
9290
|
-
aria-label="Olon mark"
|
|
9291
|
-
className={cn('flex-shrink-0', className)}
|
|
9292
|
-
>
|
|
9293
|
-
<circle cx="50" cy="50" r="38" stroke="currentColor" strokeWidth="20"/>
|
|
9294
|
-
<circle cx="50" cy="50" r="15" fill="currentColor"/>
|
|
9295
|
-
</svg>
|
|
9296
|
-
)
|
|
9297
|
-
}
|
|
9298
|
-
|
|
9299
|
-
return (
|
|
9300
|
-
<svg
|
|
9301
|
-
viewBox="0 0 100 100"
|
|
9302
|
-
fill="none"
|
|
9303
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
9304
|
-
width={size}
|
|
9305
|
-
height={size}
|
|
9306
|
-
aria-label="Olon mark"
|
|
9307
|
-
className={cn('flex-shrink-0', className)}
|
|
9308
|
-
>
|
|
9309
|
-
<defs>
|
|
9310
|
-
<linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
|
|
9311
|
-
<stop offset="0%" stopColor="var(--olon-ring-top)"/>
|
|
9312
|
-
<stop offset="100%" stopColor="var(--olon-ring-bottom)"/>
|
|
9313
|
-
</linearGradient>
|
|
9314
|
-
</defs>
|
|
9315
|
-
<circle cx="50" cy="50" r="38" stroke={`url(#${gid})`} strokeWidth="20"/>
|
|
9316
|
-
<circle cx="50" cy="50" r="15" fill="var(--olon-nucleus)"/>
|
|
9317
|
-
</svg>
|
|
9318
|
-
)
|
|
9319
|
-
}
|
|
9320
|
-
|
|
9321
|
-
interface OlonLogoProps {
|
|
9322
|
-
markSize?: number
|
|
9323
|
-
fontSize?: number
|
|
9324
|
-
variant?: 'default' | 'mono'
|
|
9325
|
-
className?: string
|
|
9326
|
-
}
|
|
9327
|
-
|
|
9328
|
-
export function OlonLogo({
|
|
9329
|
-
markSize = 32,
|
|
9330
|
-
fontSize = 24,
|
|
9331
|
-
variant = 'default',
|
|
9332
|
-
className,
|
|
9333
|
-
}: OlonLogoProps) {
|
|
9334
|
-
return (
|
|
9335
|
-
<div className={cn('flex items-center gap-3', className)}>
|
|
9336
|
-
<OlonMark size={markSize} variant={variant}/>
|
|
9337
|
-
<span
|
|
9338
|
-
style={{
|
|
9339
|
-
fontFamily: "'Instrument Sans', Helvetica, Arial, sans-serif",
|
|
9340
|
-
fontWeight: 700,
|
|
9341
|
-
fontSize,
|
|
9342
|
-
letterSpacing: '-0.02em',
|
|
9343
|
-
color: 'hsl(var(--foreground))',
|
|
9344
|
-
lineHeight: 1,
|
|
9345
|
-
}}
|
|
9346
|
-
>
|
|
9347
|
-
Olon
|
|
9348
|
-
</span>
|
|
9349
|
-
</div>
|
|
9350
|
-
)
|
|
9351
|
-
}
|
|
10457
|
+
import { cn } from '@/lib/utils'
|
|
10458
|
+
|
|
10459
|
+
interface OlonMarkProps {
|
|
10460
|
+
size?: number
|
|
10461
|
+
/** mono: uses currentColor — for single-colour print/emboss contexts */
|
|
10462
|
+
variant?: 'default' | 'mono'
|
|
10463
|
+
className?: string
|
|
10464
|
+
}
|
|
10465
|
+
|
|
10466
|
+
export function OlonMark({ size = 32, variant = 'default', className }: OlonMarkProps) {
|
|
10467
|
+
const gid = `olon-ring-${size}`
|
|
10468
|
+
|
|
10469
|
+
if (variant === 'mono') {
|
|
10470
|
+
return (
|
|
10471
|
+
<svg
|
|
10472
|
+
viewBox="0 0 100 100"
|
|
10473
|
+
fill="none"
|
|
10474
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10475
|
+
width={size}
|
|
10476
|
+
height={size}
|
|
10477
|
+
aria-label="Olon mark"
|
|
10478
|
+
className={cn('flex-shrink-0', className)}
|
|
10479
|
+
>
|
|
10480
|
+
<circle cx="50" cy="50" r="38" stroke="currentColor" strokeWidth="20"/>
|
|
10481
|
+
<circle cx="50" cy="50" r="15" fill="currentColor"/>
|
|
10482
|
+
</svg>
|
|
10483
|
+
)
|
|
10484
|
+
}
|
|
10485
|
+
|
|
10486
|
+
return (
|
|
10487
|
+
<svg
|
|
10488
|
+
viewBox="0 0 100 100"
|
|
10489
|
+
fill="none"
|
|
10490
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10491
|
+
width={size}
|
|
10492
|
+
height={size}
|
|
10493
|
+
aria-label="Olon mark"
|
|
10494
|
+
className={cn('flex-shrink-0', className)}
|
|
10495
|
+
>
|
|
10496
|
+
<defs>
|
|
10497
|
+
<linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
|
|
10498
|
+
<stop offset="0%" stopColor="var(--olon-ring-top)"/>
|
|
10499
|
+
<stop offset="100%" stopColor="var(--olon-ring-bottom)"/>
|
|
10500
|
+
</linearGradient>
|
|
10501
|
+
</defs>
|
|
10502
|
+
<circle cx="50" cy="50" r="38" stroke={`url(#${gid})`} strokeWidth="20"/>
|
|
10503
|
+
<circle cx="50" cy="50" r="15" fill="var(--olon-nucleus)"/>
|
|
10504
|
+
</svg>
|
|
10505
|
+
)
|
|
10506
|
+
}
|
|
10507
|
+
|
|
10508
|
+
interface OlonLogoProps {
|
|
10509
|
+
markSize?: number
|
|
10510
|
+
fontSize?: number
|
|
10511
|
+
variant?: 'default' | 'mono'
|
|
10512
|
+
className?: string
|
|
10513
|
+
}
|
|
10514
|
+
|
|
10515
|
+
export function OlonLogo({
|
|
10516
|
+
markSize = 32,
|
|
10517
|
+
fontSize = 24,
|
|
10518
|
+
variant = 'default',
|
|
10519
|
+
className,
|
|
10520
|
+
}: OlonLogoProps) {
|
|
10521
|
+
return (
|
|
10522
|
+
<div className={cn('flex items-center gap-3', className)}>
|
|
10523
|
+
<OlonMark size={markSize} variant={variant}/>
|
|
10524
|
+
<span
|
|
10525
|
+
style={{
|
|
10526
|
+
fontFamily: "'Instrument Sans', Helvetica, Arial, sans-serif",
|
|
10527
|
+
fontWeight: 700,
|
|
10528
|
+
fontSize,
|
|
10529
|
+
letterSpacing: '-0.02em',
|
|
10530
|
+
color: 'hsl(var(--foreground))',
|
|
10531
|
+
lineHeight: 1,
|
|
10532
|
+
}}
|
|
10533
|
+
>
|
|
10534
|
+
Olon
|
|
10535
|
+
</span>
|
|
10536
|
+
</div>
|
|
10537
|
+
)
|
|
10538
|
+
}
|
|
9352
10539
|
|
|
9353
10540
|
END_OF_FILE_CONTENT
|
|
9354
10541
|
echo "Creating src/components/ui/badge.tsx..."
|
|
@@ -10053,8 +11240,37 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/menu.json"
|
|
|
10053
11240
|
{
|
|
10054
11241
|
"main": [
|
|
10055
11242
|
{
|
|
10056
|
-
"label": "
|
|
10057
|
-
"href": "
|
|
11243
|
+
"label": "Why",
|
|
11244
|
+
"href": "#Why"
|
|
11245
|
+
|
|
11246
|
+
},
|
|
11247
|
+
{
|
|
11248
|
+
"label": "Architecture",
|
|
11249
|
+
"href": "#Architecture"
|
|
11250
|
+
},
|
|
11251
|
+
{
|
|
11252
|
+
"label": "Example",
|
|
11253
|
+
"href": "#Example"
|
|
11254
|
+
},
|
|
11255
|
+
{
|
|
11256
|
+
"label": "Get started",
|
|
11257
|
+
"href": "#Getstarted"
|
|
11258
|
+
},
|
|
11259
|
+
{
|
|
11260
|
+
"label": "GitHub",
|
|
11261
|
+
"href": "https://github.com/olonjs/core"
|
|
11262
|
+
}
|
|
11263
|
+
]
|
|
11264
|
+
}
|
|
11265
|
+
END_OF_FILE_CONTENT
|
|
11266
|
+
# SKIP: src/data/config/menu.json:Zone.Identifier is binary and cannot be embedded as text.
|
|
11267
|
+
echo "Creating src/data/config/menu_example_for_schema.json..."
|
|
11268
|
+
cat << 'END_OF_FILE_CONTENT' > "src/data/config/menu_example_for_schema.json"
|
|
11269
|
+
{
|
|
11270
|
+
"main": [
|
|
11271
|
+
{
|
|
11272
|
+
"label": "Why",
|
|
11273
|
+
"href": "/why",
|
|
10058
11274
|
"children": [
|
|
10059
11275
|
{
|
|
10060
11276
|
"label": "Overview",
|
|
@@ -10093,7 +11309,6 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/menu.json"
|
|
|
10093
11309
|
]
|
|
10094
11310
|
}
|
|
10095
11311
|
END_OF_FILE_CONTENT
|
|
10096
|
-
# SKIP: src/data/config/menu.json:Zone.Identifier is binary and cannot be embedded as text.
|
|
10097
11312
|
echo "Creating src/data/config/site.json..."
|
|
10098
11313
|
cat << 'END_OF_FILE_CONTENT' > "src/data/config/site.json"
|
|
10099
11314
|
{
|
|
@@ -10116,36 +11331,47 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/site.json"
|
|
|
10116
11331
|
"type": "header",
|
|
10117
11332
|
"data": {
|
|
10118
11333
|
"logoText": "Olon",
|
|
10119
|
-
"badge": "",
|
|
10120
|
-
"links":
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
11334
|
+
"badge": "JS",
|
|
11335
|
+
"links": [
|
|
11336
|
+
{
|
|
11337
|
+
"label": "Why",
|
|
11338
|
+
"href": "#Why"
|
|
11339
|
+
},
|
|
11340
|
+
{
|
|
11341
|
+
"label": "Architecture",
|
|
11342
|
+
"href": "#Architecture"
|
|
11343
|
+
},
|
|
11344
|
+
{
|
|
11345
|
+
"label": "Example",
|
|
11346
|
+
"href": "#Example"
|
|
11347
|
+
},
|
|
11348
|
+
{
|
|
11349
|
+
"label": "Get started",
|
|
11350
|
+
"href": "#Getstarted"
|
|
11351
|
+
},
|
|
11352
|
+
{
|
|
11353
|
+
"label": "GitHub",
|
|
11354
|
+
"href": "https://github.com/olonjs/core"
|
|
11355
|
+
}
|
|
11356
|
+
],
|
|
11357
|
+
"ctaLabel": "",
|
|
11358
|
+
"ctaHref": "",
|
|
11359
|
+
"signinHref": ""
|
|
10126
11360
|
}
|
|
10127
11361
|
},
|
|
10128
11362
|
"footer": {
|
|
10129
11363
|
"id": "global-footer",
|
|
10130
11364
|
"type": "footer",
|
|
10131
11365
|
"data": {
|
|
10132
|
-
"brandText": "
|
|
10133
|
-
"copyright": "©
|
|
11366
|
+
"brandText": "OlonJS",
|
|
11367
|
+
"copyright": "© 2026 OlonJS · v1.5 · Guido Serio",
|
|
10134
11368
|
"links": [
|
|
10135
11369
|
{
|
|
10136
11370
|
"label": "GitHub",
|
|
10137
|
-
"href": "
|
|
10138
|
-
},
|
|
10139
|
-
{
|
|
10140
|
-
"label": "Privacy",
|
|
10141
|
-
"href": "#"
|
|
10142
|
-
},
|
|
10143
|
-
{
|
|
10144
|
-
"label": "Terms",
|
|
10145
|
-
"href": "#"
|
|
11371
|
+
"href": "https://github.com/olonjs/core"
|
|
10146
11372
|
}
|
|
10147
11373
|
],
|
|
10148
|
-
"designSystemHref": "
|
|
11374
|
+
"designSystemHref": ""
|
|
10149
11375
|
},
|
|
10150
11376
|
"settings": {
|
|
10151
11377
|
"showLogo": true
|
|
@@ -10160,168 +11386,164 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/theme.json"
|
|
|
10160
11386
|
"name": "Olon",
|
|
10161
11387
|
"tokens": {
|
|
10162
11388
|
"colors": {
|
|
10163
|
-
"background": "
|
|
10164
|
-
"card": "
|
|
10165
|
-
"elevated": "#
|
|
10166
|
-
"overlay": "#
|
|
10167
|
-
"popover": "
|
|
10168
|
-
"popover-foreground": "
|
|
10169
|
-
"foreground": "
|
|
10170
|
-
"card-foreground": "
|
|
10171
|
-
"muted-foreground": "
|
|
10172
|
-
"placeholder": "#
|
|
10173
|
-
"primary": "
|
|
10174
|
-
"primary-foreground": "
|
|
10175
|
-
"primary-light": "#
|
|
10176
|
-
"primary-dark": "#
|
|
10177
|
-
"primary-50": "#
|
|
10178
|
-
"primary-100": "#
|
|
10179
|
-
"primary-200": "#
|
|
10180
|
-
"primary-300": "#
|
|
10181
|
-
"primary-400": "#
|
|
10182
|
-
"primary-500": "#
|
|
10183
|
-
"primary-600": "#
|
|
10184
|
-
"primary-700": "#
|
|
10185
|
-
"primary-800": "#
|
|
10186
|
-
"primary-900": "#
|
|
10187
|
-
"accent": "
|
|
10188
|
-
"accent-foreground": "
|
|
10189
|
-
"secondary": "
|
|
10190
|
-
"secondary-foreground": "
|
|
10191
|
-
"muted": "
|
|
10192
|
-
"border": "
|
|
10193
|
-
"border-strong": "#
|
|
10194
|
-
"input": "
|
|
10195
|
-
"ring": "
|
|
10196
|
-
"destructive": "
|
|
10197
|
-
"destructive-foreground": "
|
|
10198
|
-
"destructive-border": "#
|
|
10199
|
-
"destructive-ring": "#
|
|
10200
|
-
"success": "
|
|
10201
|
-
"success-foreground": "
|
|
10202
|
-
"success-border": "#
|
|
10203
|
-
"success-indicator": "#
|
|
10204
|
-
"warning": "
|
|
10205
|
-
"warning-foreground": "
|
|
10206
|
-
"warning-border": "#
|
|
10207
|
-
"info": "
|
|
10208
|
-
"info-foreground": "
|
|
10209
|
-
"info-border": "#
|
|
10210
|
-
},
|
|
11389
|
+
"background": "hsl(215 28% 7%)",
|
|
11390
|
+
"card": "hsl(218 44% 9%)",
|
|
11391
|
+
"elevated": "#141B24",
|
|
11392
|
+
"overlay": "#1C2433",
|
|
11393
|
+
"popover": "hsl(218 44% 9%)",
|
|
11394
|
+
"popover-foreground": "hsl(214 33% 84%)",
|
|
11395
|
+
"foreground": "hsl(214 33% 84%)",
|
|
11396
|
+
"card-foreground": "hsl(214 33% 84%)",
|
|
11397
|
+
"muted-foreground": "hsl(215 23% 57%)",
|
|
11398
|
+
"placeholder": "#4A5C78",
|
|
11399
|
+
"primary": "hsl(222 100% 54%)",
|
|
11400
|
+
"primary-foreground": "hsl(0 0% 100%)",
|
|
11401
|
+
"primary-light": "#84ABFF",
|
|
11402
|
+
"primary-dark": "#0F52E0",
|
|
11403
|
+
"primary-50": "#EEF3FF",
|
|
11404
|
+
"primary-100": "#D6E4FF",
|
|
11405
|
+
"primary-200": "#ADC8FF",
|
|
11406
|
+
"primary-300": "#84ABFF",
|
|
11407
|
+
"primary-400": "#5B8EFF",
|
|
11408
|
+
"primary-500": "#1763FF",
|
|
11409
|
+
"primary-600": "#0F52E0",
|
|
11410
|
+
"primary-700": "#0940B8",
|
|
11411
|
+
"primary-800": "#063090",
|
|
11412
|
+
"primary-900": "#031E68",
|
|
11413
|
+
"accent": "hsl(216 28% 15%)",
|
|
11414
|
+
"accent-foreground": "hsl(214 33% 84%)",
|
|
11415
|
+
"secondary": "hsl(217 30% 11%)",
|
|
11416
|
+
"secondary-foreground": "hsl(214 33% 84%)",
|
|
11417
|
+
"muted": "hsl(217 30% 11%)",
|
|
11418
|
+
"border": "hsl(216 27% 21%)",
|
|
11419
|
+
"border-strong": "#2F3D55",
|
|
11420
|
+
"input": "hsl(216 27% 21%)",
|
|
11421
|
+
"ring": "hsl(222 100% 54%)",
|
|
11422
|
+
"destructive": "hsl(0 40% 46%)",
|
|
11423
|
+
"destructive-foreground": "hsl(210 58% 93%)",
|
|
11424
|
+
"destructive-border": "#7F2626",
|
|
11425
|
+
"destructive-ring": "#E06060",
|
|
11426
|
+
"success": "hsl(152 83% 26%)",
|
|
11427
|
+
"success-foreground": "hsl(210 58% 93%)",
|
|
11428
|
+
"success-border": "#1DB87A",
|
|
11429
|
+
"success-indicator": "#1DB87A",
|
|
11430
|
+
"warning": "hsl(46 100% 21%)",
|
|
11431
|
+
"warning-foreground": "hsl(210 58% 93%)",
|
|
11432
|
+
"warning-border": "#C49A00",
|
|
11433
|
+
"info": "hsl(214 100% 40%)",
|
|
11434
|
+
"info-foreground": "hsl(210 58% 93%)",
|
|
11435
|
+
"info-border": "#4D9FE0"
|
|
11436
|
+
},
|
|
10211
11437
|
"modes": {
|
|
10212
11438
|
"light": {
|
|
10213
11439
|
"colors": {
|
|
10214
|
-
"background": "
|
|
10215
|
-
"card": "
|
|
10216
|
-
"elevated": "#
|
|
10217
|
-
"overlay": "#
|
|
10218
|
-
"popover": "
|
|
10219
|
-
"popover-foreground": "
|
|
10220
|
-
"foreground": "
|
|
10221
|
-
"card-foreground": "
|
|
10222
|
-
"muted-foreground": "
|
|
10223
|
-
"placeholder": "#
|
|
10224
|
-
"primary": "
|
|
10225
|
-
"primary-foreground": "
|
|
10226
|
-
"primary-light": "#
|
|
10227
|
-
"primary-dark": "#
|
|
10228
|
-
"primary-50": "#
|
|
10229
|
-
"primary-100": "#
|
|
10230
|
-
"primary-200": "#
|
|
10231
|
-
"primary-300": "#
|
|
10232
|
-
"primary-400": "#
|
|
10233
|
-
"primary-500": "#
|
|
10234
|
-
"primary-600": "#
|
|
10235
|
-
"primary-700": "#
|
|
10236
|
-
"primary-800": "#
|
|
10237
|
-
"primary-900": "#
|
|
10238
|
-
"accent": "
|
|
10239
|
-
"accent-foreground": "
|
|
10240
|
-
"secondary": "
|
|
10241
|
-
"secondary-foreground": "
|
|
10242
|
-
"muted": "
|
|
10243
|
-
"border": "
|
|
10244
|
-
"border-strong": "#
|
|
10245
|
-
"input": "
|
|
10246
|
-
"ring": "
|
|
10247
|
-
"destructive": "
|
|
10248
|
-
"destructive-foreground": "
|
|
11440
|
+
"background": "hsl(0 0% 96%)",
|
|
11441
|
+
"card": "hsl(0 0% 100%)",
|
|
11442
|
+
"elevated": "#F4F3EF",
|
|
11443
|
+
"overlay": "#E5E3DC",
|
|
11444
|
+
"popover": "hsl(0 0% 100%)",
|
|
11445
|
+
"popover-foreground": "hsl(0 0% 3%)",
|
|
11446
|
+
"foreground": "hsl(0 0% 3%)",
|
|
11447
|
+
"card-foreground": "hsl(0 0% 3%)",
|
|
11448
|
+
"muted-foreground": "hsl(0 0% 42%)",
|
|
11449
|
+
"placeholder": "#B4B2AD",
|
|
11450
|
+
"primary": "hsl(222 100% 54%)",
|
|
11451
|
+
"primary-foreground": "hsl(0 0% 100%)",
|
|
11452
|
+
"primary-light": "#5B8EFF",
|
|
11453
|
+
"primary-dark": "#0F52E0",
|
|
11454
|
+
"primary-50": "#EEF3FF",
|
|
11455
|
+
"primary-100": "#D6E4FF",
|
|
11456
|
+
"primary-200": "#ADC8FF",
|
|
11457
|
+
"primary-300": "#84ABFF",
|
|
11458
|
+
"primary-400": "#5B8EFF",
|
|
11459
|
+
"primary-500": "#1763FF",
|
|
11460
|
+
"primary-600": "#0F52E0",
|
|
11461
|
+
"primary-700": "#0940B8",
|
|
11462
|
+
"primary-800": "#063090",
|
|
11463
|
+
"primary-900": "#031E68",
|
|
11464
|
+
"accent": "hsl(222 100% 92%)",
|
|
11465
|
+
"accent-foreground": "hsl(222 100% 54%)",
|
|
11466
|
+
"secondary": "hsl(0 0% 92%)",
|
|
11467
|
+
"secondary-foreground": "hsl(0 0% 3%)",
|
|
11468
|
+
"muted": "hsl(0 0% 92%)",
|
|
11469
|
+
"border": "hsl(0 0% 84%)",
|
|
11470
|
+
"border-strong": "#B4B2AD",
|
|
11471
|
+
"input": "hsl(0 0% 84%)",
|
|
11472
|
+
"ring": "hsl(222 100% 54%)",
|
|
11473
|
+
"destructive": "hsl(0 72% 51%)",
|
|
11474
|
+
"destructive-foreground": "hsl(0 0% 100%)",
|
|
10249
11475
|
"destructive-border": "#FECACA",
|
|
10250
11476
|
"destructive-ring": "#EF4444",
|
|
10251
|
-
"success": "
|
|
10252
|
-
"success-foreground": "
|
|
10253
|
-
"success-border": "#
|
|
10254
|
-
"success-indicator": "#
|
|
10255
|
-
"warning": "
|
|
10256
|
-
"warning-foreground": "
|
|
10257
|
-
"warning-border": "#
|
|
10258
|
-
"info": "
|
|
10259
|
-
"info-foreground": "
|
|
10260
|
-
"info-border": "#
|
|
11477
|
+
"success": "hsl(160 84% 39%)",
|
|
11478
|
+
"success-foreground": "hsl(0 0% 100%)",
|
|
11479
|
+
"success-border": "#D4F0E2",
|
|
11480
|
+
"success-indicator": "#0A7C4E",
|
|
11481
|
+
"warning": "hsl(38 92% 50%)",
|
|
11482
|
+
"warning-foreground": "hsl(0 0% 3%)",
|
|
11483
|
+
"warning-border": "#F5EAD4",
|
|
11484
|
+
"info": "hsl(222 100% 54%)",
|
|
11485
|
+
"info-foreground": "hsl(0 0% 100%)",
|
|
11486
|
+
"info-border": "#D4E5F5"
|
|
10261
11487
|
}
|
|
10262
11488
|
}
|
|
10263
11489
|
},
|
|
10264
11490
|
"typography": {
|
|
10265
11491
|
"fontFamily": {
|
|
10266
|
-
"primary": "
|
|
10267
|
-
"mono": "
|
|
10268
|
-
"display": "
|
|
11492
|
+
"primary": "\"Instrument Sans\", Helvetica, Arial, sans-serif",
|
|
11493
|
+
"mono": "\"JetBrains Mono\", \"Fira Code\", monospace",
|
|
11494
|
+
"display": "\"Instrument Sans\", Helvetica, Arial, sans-serif"
|
|
10269
11495
|
},
|
|
10270
11496
|
"wordmark": {
|
|
10271
|
-
"fontFamily": "
|
|
10272
|
-
"weight": "
|
|
10273
|
-
"
|
|
11497
|
+
"fontFamily": "\"Instrument Sans\", Helvetica, Arial, sans-serif",
|
|
11498
|
+
"weight": "700",
|
|
11499
|
+
"tracking": "-0.05em"
|
|
11500
|
+
|
|
10274
11501
|
},
|
|
10275
11502
|
"scale": {
|
|
10276
|
-
"xs": "
|
|
10277
|
-
"sm": "
|
|
11503
|
+
"xs": "0.75rem",
|
|
11504
|
+
"sm": "0.875rem",
|
|
10278
11505
|
"base": "1rem",
|
|
10279
|
-
"
|
|
10280
|
-
"
|
|
10281
|
-
"
|
|
10282
|
-
"
|
|
10283
|
-
"
|
|
10284
|
-
"
|
|
10285
|
-
"5xl": "2.5rem",
|
|
11506
|
+
"lg": "1.125rem",
|
|
11507
|
+
"xl": "1.25rem",
|
|
11508
|
+
"2xl": "1.5rem",
|
|
11509
|
+
"3xl": "1.875rem",
|
|
11510
|
+
"4xl": "2.25rem",
|
|
11511
|
+
"5xl": "3rem",
|
|
10286
11512
|
"6xl": "3rem",
|
|
10287
11513
|
"7xl": "4.5rem"
|
|
10288
11514
|
},
|
|
10289
11515
|
"tracking": {
|
|
10290
|
-
"tight": "-0.
|
|
10291
|
-
"display": "-0.035em",
|
|
11516
|
+
"tight": "-0.04em",
|
|
10292
11517
|
"normal": "0em",
|
|
10293
11518
|
"wide": "0.04em",
|
|
10294
|
-
"
|
|
11519
|
+
"widest": "0.14em"
|
|
10295
11520
|
},
|
|
10296
11521
|
"leading": {
|
|
10297
|
-
"none": "1",
|
|
10298
11522
|
"tight": "1.2",
|
|
10299
|
-
"
|
|
10300
|
-
"
|
|
10301
|
-
"relaxed": "1.75"
|
|
11523
|
+
"normal": "1.5",
|
|
11524
|
+
"relaxed": "1.7"
|
|
10302
11525
|
}
|
|
10303
11526
|
},
|
|
10304
11527
|
"borderRadius": {
|
|
10305
|
-
"xl": "
|
|
10306
|
-
"lg": "
|
|
10307
|
-
"md": "
|
|
10308
|
-
"sm": "
|
|
11528
|
+
"xl": "1rem",
|
|
11529
|
+
"lg": "0.75rem",
|
|
11530
|
+
"md": "0.5rem",
|
|
11531
|
+
"sm": "0.25rem",
|
|
10309
11532
|
"full": "9999px"
|
|
10310
11533
|
},
|
|
10311
11534
|
"spacing": {
|
|
10312
|
-
"container-max": "
|
|
10313
|
-
"section-y": "
|
|
10314
|
-
"header-h": "
|
|
10315
|
-
"sidebar-w": "240px"
|
|
11535
|
+
"container-max": "72rem",
|
|
11536
|
+
"section-y": "4rem",
|
|
11537
|
+
"header-h": "4rem"
|
|
10316
11538
|
},
|
|
10317
11539
|
"zIndex": {
|
|
10318
11540
|
"base": "0",
|
|
10319
11541
|
"elevated": "10",
|
|
10320
|
-
"dropdown": "
|
|
10321
|
-
"sticky": "
|
|
10322
|
-
"overlay": "
|
|
10323
|
-
"modal": "
|
|
10324
|
-
"toast": "
|
|
11542
|
+
"dropdown": "20",
|
|
11543
|
+
"sticky": "40",
|
|
11544
|
+
"overlay": "50",
|
|
11545
|
+
"modal": "60",
|
|
11546
|
+
"toast": "100"
|
|
10325
11547
|
}
|
|
10326
11548
|
}
|
|
10327
11549
|
}
|
|
@@ -10350,7 +11572,6 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/design-system.json"
|
|
|
10350
11572
|
"global-header": false
|
|
10351
11573
|
}
|
|
10352
11574
|
END_OF_FILE_CONTENT
|
|
10353
|
-
# SKIP: src/data/pages/design-system.json:Zone.Identifier is binary and cannot be embedded as text.
|
|
10354
11575
|
echo "Creating src/data/pages/docs.json..."
|
|
10355
11576
|
cat << 'END_OF_FILE_CONTENT' > "src/data/pages/docs.json"
|
|
10356
11577
|
{
|
|
@@ -10379,185 +11600,418 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
|
|
|
10379
11600
|
"id": "home-page",
|
|
10380
11601
|
"slug": "home",
|
|
10381
11602
|
"meta": {
|
|
10382
|
-
"title": "OlonJS —
|
|
10383
|
-
"description": "OlonJS
|
|
11603
|
+
"title": "OlonJS — Contract Layer for the Agentic Web",
|
|
11604
|
+
"description": "OlonJS is a TypeScript framework for building JSON-driven websites with a deterministic data contract. Every section is typed, validated, and structurally addressable."
|
|
10384
11605
|
},
|
|
10385
11606
|
"sections": [
|
|
10386
11607
|
{
|
|
10387
11608
|
"id": "hero-main",
|
|
10388
|
-
"type": "hero",
|
|
11609
|
+
"type": "olon-hero",
|
|
10389
11610
|
"data": {
|
|
10390
|
-
"
|
|
10391
|
-
"
|
|
10392
|
-
"
|
|
10393
|
-
"
|
|
10394
|
-
"
|
|
10395
|
-
|
|
10396
|
-
|
|
11611
|
+
"id": "hero-main",
|
|
11612
|
+
"eyebrow": "CONTRACT LAYER · V1.5 · OPEN SOURCE",
|
|
11613
|
+
"headline": "Contract Layer",
|
|
11614
|
+
"subline": "for the agentic web.",
|
|
11615
|
+
"body": "AI agents are becoming operational actors in commerce, marketing, and support. They need more than content — they need a contract. OlonJS is the deterministic machine contract for websites: every site typed, structured, and addressable by design. No custom glue. No fragile integrations. Just a contract any agent can read and operate.",
|
|
11616
|
+
"cta": {
|
|
11617
|
+
"primary": {
|
|
10397
11618
|
"label": "Get started",
|
|
10398
|
-
"href": "#
|
|
10399
|
-
"variant": "accent"
|
|
11619
|
+
"href": "#getstarted"
|
|
10400
11620
|
},
|
|
10401
|
-
{
|
|
10402
|
-
"id": "cta-github",
|
|
11621
|
+
"secondary": {
|
|
10403
11622
|
"label": "GitHub",
|
|
10404
|
-
"href": "
|
|
10405
|
-
|
|
11623
|
+
"href": "https://github.com/olonjs/core"
|
|
11624
|
+
},
|
|
11625
|
+
"ghost": {
|
|
11626
|
+
"label": "Explore platform",
|
|
11627
|
+
"href": "#architecture"
|
|
10406
11628
|
}
|
|
10407
|
-
],
|
|
10408
|
-
"docsLabel": "Explore platform",
|
|
10409
|
-
"docsHref": "/platform/overview",
|
|
10410
|
-
"heroImage": {
|
|
10411
|
-
"url": "https://bat5elmxofxdroan.public.blob.vercel-storage.com/tenant-assets/511f18d7-d8ac-4292-ad8a-b0efa99401a3/1774286598548-adac7c36-9001-451d-9b16-c3787ac27f57-signup-hero-olon-graded_1_.png",
|
|
10412
|
-
"alt": ""
|
|
10413
11629
|
}
|
|
10414
|
-
},
|
|
10415
|
-
"settings": {
|
|
10416
|
-
"showCode": false
|
|
10417
11630
|
}
|
|
10418
11631
|
},
|
|
10419
11632
|
{
|
|
10420
|
-
"id": "
|
|
10421
|
-
"type": "
|
|
11633
|
+
"id": "why-olon",
|
|
11634
|
+
"type": "olon-why",
|
|
10422
11635
|
"data": {
|
|
11636
|
+
"id": "why-olon",
|
|
10423
11637
|
"label": "Why OlonJS",
|
|
10424
|
-
"
|
|
10425
|
-
"
|
|
10426
|
-
"
|
|
10427
|
-
"
|
|
11638
|
+
"headline": "A Meaningful Web",
|
|
11639
|
+
"subline": "Whole in itself, part of something greater.",
|
|
11640
|
+
"body": "Most web frameworks separate concerns across layers — data, UI, validation, metadata — with no shared contract between them. OlonJS inverts this: the JSON data structure is the contract. Every layer — rendering, editing, validation, machine access — is a deterministic projection of the same typed source. The result is a site that is structurally coherent by construction, not by convention. Every site built with OlonJS is a holon: complete in itself, intelligible to the network around it. The meaningful web doesn't happen all at once. It grows one site at a time.",
|
|
11641
|
+
"pillars": [
|
|
10428
11642
|
{
|
|
10429
|
-
"id": "
|
|
10430
|
-
"icon":
|
|
10431
|
-
|
|
10432
|
-
|
|
10433
|
-
},
|
|
10434
|
-
"title": "Canonical JSON endpoints",
|
|
10435
|
-
"description": "Every page available at /{slug}.json — deterministic, typed, agent-readable. No custom integration per tenant."
|
|
11643
|
+
"id": "pillar-contract",
|
|
11644
|
+
"icon": "contract",
|
|
11645
|
+
"title": "The data is the contract",
|
|
11646
|
+
"body": "One typed JSON source. Every layer — UI, editor, agent, SEO — is a projection. No translation, no drift."
|
|
10436
11647
|
},
|
|
10437
11648
|
{
|
|
10438
|
-
"id": "
|
|
10439
|
-
"icon":
|
|
10440
|
-
|
|
10441
|
-
|
|
10442
|
-
},
|
|
10443
|
-
"title": "Schema-driven contracts",
|
|
10444
|
-
"description": "Typed components validated against your schema. Shared conventions eliminate prompt ambiguity across teams."
|
|
11649
|
+
"id": "pillar-holon",
|
|
11650
|
+
"icon": "holon",
|
|
11651
|
+
"title": "Every site is a holon",
|
|
11652
|
+
"body": "Autonomous, complete, structurally intelligible. Each site is whole in itself and part of a network that understands it."
|
|
10445
11653
|
},
|
|
10446
11654
|
{
|
|
10447
|
-
"id": "
|
|
10448
|
-
"icon":
|
|
10449
|
-
|
|
10450
|
-
|
|
10451
|
-
|
|
10452
|
-
|
|
10453
|
-
|
|
11655
|
+
"id": "pillar-generated",
|
|
11656
|
+
"icon": "generated",
|
|
11657
|
+
"title": "Built to be generated",
|
|
11658
|
+
"body": "Every constraint is also an instruction. The spec is precise enough for AI agents to scaffold a fully compliant tenant from scratch."
|
|
11659
|
+
}
|
|
11660
|
+
],
|
|
11661
|
+
"anchorId": "Why"
|
|
11662
|
+
}
|
|
11663
|
+
},
|
|
11664
|
+
{
|
|
11665
|
+
"id": "architecture-protocols",
|
|
11666
|
+
"type": "olon-architecture",
|
|
11667
|
+
"data": {
|
|
11668
|
+
"id": "architecture-protocols",
|
|
11669
|
+
"label": "Architecture",
|
|
11670
|
+
"headline": "Six governing protocols.",
|
|
11671
|
+
"body": "OlonJS is specified as a versioned set of architectural protocols. Each protocol is independently versioned and mandatory for compliant tenants.",
|
|
11672
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md",
|
|
11673
|
+
"protocols": [
|
|
11674
|
+
{
|
|
11675
|
+
"id": "proto-mtrp",
|
|
11676
|
+
"icon": "mtrp",
|
|
11677
|
+
"acronym": "MTRP",
|
|
11678
|
+
"version": "v1.2",
|
|
11679
|
+
"name": "Modular Type Registry",
|
|
11680
|
+
"desc": "Core exports an empty SectionDataRegistry. Tenants extend it via module augmentation. Full TypeScript inference across all section types at compile-time, zero Core changes.",
|
|
11681
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md#1--modular-type-registry-pattern-mtrp-v12"
|
|
10454
11682
|
},
|
|
10455
11683
|
{
|
|
10456
|
-
"id": "
|
|
10457
|
-
"icon":
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
|
|
10461
|
-
"
|
|
10462
|
-
"
|
|
11684
|
+
"id": "proto-tbp",
|
|
11685
|
+
"icon": "tbp",
|
|
11686
|
+
"acronym": "TBP",
|
|
11687
|
+
"version": "v1.0",
|
|
11688
|
+
"name": "Tenant Block Protocol",
|
|
11689
|
+
"desc": "Each section type is a self-contained capsule: View.tsx, schema.ts, types.ts, index.ts. Renderable, validatable, and ingestible by the engine without additional configuration.",
|
|
11690
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md#3--tenant-block-protocol-tbp-v10"
|
|
10463
11691
|
},
|
|
10464
11692
|
{
|
|
10465
|
-
"id": "
|
|
10466
|
-
"icon":
|
|
10467
|
-
|
|
10468
|
-
|
|
10469
|
-
|
|
10470
|
-
"
|
|
10471
|
-
"
|
|
11693
|
+
"id": "proto-jsp",
|
|
11694
|
+
"icon": "jsp",
|
|
11695
|
+
"acronym": "JSP",
|
|
11696
|
+
"version": "v1.8",
|
|
11697
|
+
"name": "JsonPages Site Protocol",
|
|
11698
|
+
"desc": "Deterministic file system ontology and CLI projection engine. config/ separates global governance from per-page content. Reproducible across every environment.",
|
|
11699
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md#2--jsonpages-site-protocol-jsp-v18"
|
|
11700
|
+
},
|
|
11701
|
+
{
|
|
11702
|
+
"id": "proto-idac",
|
|
11703
|
+
"icon": "idac",
|
|
11704
|
+
"acronym": "IDAC",
|
|
11705
|
+
"version": "v1.0",
|
|
11706
|
+
"name": "ICE Data Contract",
|
|
11707
|
+
"desc": "Mandatory data-jp-* DOM attributes bind every section to its data. Any consumer that can traverse the DOM can identify and operate any content node — human or agent.",
|
|
11708
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md"
|
|
11709
|
+
},
|
|
11710
|
+
{
|
|
11711
|
+
"id": "proto-bsds",
|
|
11712
|
+
"icon": "bsds",
|
|
11713
|
+
"acronym": "BSDS",
|
|
11714
|
+
"version": "v1.0",
|
|
11715
|
+
"name": "Base Schema Fragments",
|
|
11716
|
+
"desc": "BaseSectionData and BaseArrayItem enforce anchor IDs and stable React keys across all capsules. The foundation that doesn't move so your content never drifts.",
|
|
11717
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md"
|
|
11718
|
+
},
|
|
11719
|
+
{
|
|
11720
|
+
"id": "proto-pss",
|
|
11721
|
+
"icon": "pss",
|
|
11722
|
+
"acronym": "PSS",
|
|
11723
|
+
"version": "v1.4",
|
|
11724
|
+
"name": "Path-Based Selection",
|
|
11725
|
+
"desc": "Every node has an address. Content selection uses strict root-to-leaf path semantics — unambiguous, stable, operable by any consumer that knows the contract.",
|
|
11726
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md"
|
|
11727
|
+
}
|
|
11728
|
+
],
|
|
11729
|
+
"anchorId": "Architecture"
|
|
11730
|
+
}
|
|
11731
|
+
},
|
|
11732
|
+
{
|
|
11733
|
+
"id": "example-steps",
|
|
11734
|
+
"type": "olon-example",
|
|
11735
|
+
"data": {
|
|
11736
|
+
"id": "example-steps",
|
|
11737
|
+
"label": "Quick Example",
|
|
11738
|
+
"headline": "Two steps. One contract.",
|
|
11739
|
+
"body": "Scaffold a fully compliant tenant in under three minutes. Then read any page via the OlonJS protocol — from a browser, a script, or an AI agent.",
|
|
11740
|
+
"note": "Every OlonJS tenant exposes a machine-readable manifest at",
|
|
11741
|
+
"noteHref": "http://localhost:5173/mcp-manifest.json",
|
|
11742
|
+
"steps": [
|
|
11743
|
+
{
|
|
11744
|
+
"number": 1,
|
|
11745
|
+
"title": "Scaffold a tenant",
|
|
11746
|
+
"meta": "~3 min",
|
|
11747
|
+
"code": "# Install the CLI\nnpm install -g @olonjs/cli\n\n# Scaffold a new tenant\nnpx @olonjs/cli new tenant\n\n✓ Projecting infrastructure...\n✓ Projecting source (src_tenant_alpha.sh)\n✓ Resolving dependencies\n✓ Tenant scaffolded\n\nsrc/\n components/hero/\n View.tsx\n schema.ts\n types.ts\n index.ts\n data/config/\n site.json\n theme.json\n menu.json\n lib/\n schemas.ts\n base-schemas.ts"
|
|
11748
|
+
},
|
|
11749
|
+
{
|
|
11750
|
+
"number": 2,
|
|
11751
|
+
"title": "Read via OlonJS protocol",
|
|
11752
|
+
"meta": "Any consumer",
|
|
11753
|
+
"code": "// Read any page via the contract\n// Works from browser, script, or AI agent\n\nconst page = await\n navigator.modelContextProtocol\n .readResource(\n 'olon://pages/home'\n );\n\n// Returns the full typed contract\n// { slug, meta, sections: Section[] }\n// No DOM scraping. No layout knowledge.\n// Just the contract.\n\n// {\n// \"slug\": \"home\",\n// \"sections\": [\n// { \"type\": \"hero\", \"data\": {...} },\n// { \"type\": \"features\", \"data\": {...} }\n// ]\n// }"
|
|
11754
|
+
}
|
|
11755
|
+
],
|
|
11756
|
+
"anchorId": "Example"
|
|
11757
|
+
}
|
|
11758
|
+
},
|
|
11759
|
+
{
|
|
11760
|
+
"id": "getstarted-cards",
|
|
11761
|
+
"type": "olon-getstarted",
|
|
11762
|
+
"data": {
|
|
11763
|
+
"id": "getstarted-cards",
|
|
11764
|
+
"label": "Get Started",
|
|
11765
|
+
"headline": "Three paths in.",
|
|
11766
|
+
"body": "Start with the Core package, scaffold a full tenant with the CLI, or deploy a working example in one click.",
|
|
11767
|
+
"cards": [
|
|
11768
|
+
{
|
|
11769
|
+
"id": "card-core",
|
|
11770
|
+
"badge": "Open Core",
|
|
11771
|
+
"badgeStyle": "oss",
|
|
11772
|
+
"title": "Install Core",
|
|
11773
|
+
"body": "The Core package is free and open — forever. The contract, the protocols, the CLI. No lock-in on the foundation.",
|
|
11774
|
+
"code": "npm install @olonjs/core",
|
|
11775
|
+
"linkLabel": "View on GitHub",
|
|
11776
|
+
"linkHref": "https://github.com/olonjs/core"
|
|
11777
|
+
},
|
|
11778
|
+
{
|
|
11779
|
+
"id": "card-cli",
|
|
11780
|
+
"badge": "CLI",
|
|
11781
|
+
"badgeStyle": "cli",
|
|
11782
|
+
"title": "Scaffold a tenant",
|
|
11783
|
+
"body": "The CLI scaffolds a fully compliant tenant from a canonical script. Same result on every machine, every run.",
|
|
11784
|
+
"code": "npx @olonjs/cli new tenant",
|
|
11785
|
+
"linkLabel": "View on npm",
|
|
11786
|
+
"linkHref": "https://www.npmjs.com/package/@olonjs/cli"
|
|
10472
11787
|
},
|
|
10473
11788
|
{
|
|
10474
11789
|
"id": "card-deploy",
|
|
10475
|
-
"
|
|
10476
|
-
|
|
10477
|
-
|
|
10478
|
-
|
|
10479
|
-
"
|
|
10480
|
-
"
|
|
11790
|
+
"badge": "Deploy",
|
|
11791
|
+
"badgeStyle": "deploy",
|
|
11792
|
+
"title": "Deploy a template",
|
|
11793
|
+
"body": "Clone a working OlonJS tenant and deploy it with one click. Explore the full capsule structure in a real project.",
|
|
11794
|
+
"deployLabel": "Deploy template →",
|
|
11795
|
+
"deployHref": "https://github.com/olonjs/core",
|
|
11796
|
+
"linkLabel": "View on npm",
|
|
11797
|
+
"linkHref": "https://www.npmjs.com/package/@olonjs/core"
|
|
10481
11798
|
}
|
|
10482
11799
|
],
|
|
10483
|
-
"
|
|
10484
|
-
|
|
10485
|
-
|
|
11800
|
+
"anchorId": "Getstarted"
|
|
11801
|
+
}
|
|
11802
|
+
}
|
|
11803
|
+
]
|
|
11804
|
+
}
|
|
11805
|
+
END_OF_FILE_CONTENT
|
|
11806
|
+
echo "Creating src/data/pages/home_.json..."
|
|
11807
|
+
cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home_.json"
|
|
11808
|
+
{
|
|
11809
|
+
"id": "home-page",
|
|
11810
|
+
"slug": "home",
|
|
11811
|
+
"meta": {
|
|
11812
|
+
"title": "OlonJS — Contract Layer for the Agentic Web",
|
|
11813
|
+
"description": "OlonJS is a TypeScript framework for building JSON-driven websites with a deterministic data contract. Every section is typed, validated, and structurally addressable."
|
|
11814
|
+
},
|
|
11815
|
+
"sections": [
|
|
11816
|
+
{
|
|
11817
|
+
"id": "hero-main",
|
|
11818
|
+
"type": "olon-hero",
|
|
11819
|
+
"data": {
|
|
11820
|
+
"eyebrow": "AI GENERATED 🤖",
|
|
11821
|
+
"headline": "Contract Layer",
|
|
11822
|
+
"subline": "for the agentic web.",
|
|
11823
|
+
"body": "AI agents are becoming operational actors in commerce, marketing, and support. They need more than content — they need a contract. OlonJS is the deterministic machine contract for websites: every site typed, structured, and addressable by design. No custom glue. No fragile integrations. Just a contract any agent can read and operate.",
|
|
11824
|
+
"cta": {
|
|
11825
|
+
"primary": {
|
|
11826
|
+
"label": "Inizia Ora",
|
|
11827
|
+
"href": "/docs"
|
|
11828
|
+
},
|
|
11829
|
+
"secondary": {
|
|
11830
|
+
"label": "GitHub",
|
|
11831
|
+
"href": "https://github.com"
|
|
11832
|
+
},
|
|
11833
|
+
"ghost": {
|
|
11834
|
+
"label": "Contatti",
|
|
11835
|
+
"href": "/contact"
|
|
11836
|
+
}
|
|
11837
|
+
}
|
|
11838
|
+
}
|
|
11839
|
+
},
|
|
11840
|
+
{
|
|
11841
|
+
"id": "why-olon",
|
|
11842
|
+
"type": "olon-why",
|
|
11843
|
+
"data": {
|
|
11844
|
+
"id": "why-olon",
|
|
11845
|
+
"label": "Why OlonJS",
|
|
11846
|
+
"headline": "A Meaningful Web",
|
|
11847
|
+
"subline": "Whole in itself, part of something greater.",
|
|
11848
|
+
"body": "Most web frameworks separate concerns across layers — data, UI, validation, metadata — with no shared contract between them. OlonJS inverts this: the JSON data structure is the contract. Every layer — rendering, editing, validation, machine access — is a deterministic projection of the same typed source. The result is a site that is structurally coherent by construction, not by convention. Every site built with OlonJS is a holon: complete in itself, intelligible to the network around it. The meaningful web doesn't happen all at once. It grows one site at a time.",
|
|
11849
|
+
"pillars": [
|
|
10486
11850
|
{
|
|
10487
|
-
"id": "
|
|
10488
|
-
"
|
|
11851
|
+
"id": "pillar-contract",
|
|
11852
|
+
"icon": "contract",
|
|
11853
|
+
"title": "The data is the contract",
|
|
11854
|
+
"body": "One typed JSON source. Every layer — UI, editor, agent, SEO — is a projection. No translation, no drift."
|
|
10489
11855
|
},
|
|
10490
11856
|
{
|
|
10491
|
-
"id": "
|
|
10492
|
-
"
|
|
11857
|
+
"id": "pillar-holon",
|
|
11858
|
+
"icon": "holon",
|
|
11859
|
+
"title": "Every site is a holon",
|
|
11860
|
+
"body": "Autonomous, complete, structurally intelligible. Each site is whole in itself and part of a network that understands it."
|
|
10493
11861
|
},
|
|
10494
11862
|
{
|
|
10495
|
-
"id": "
|
|
10496
|
-
"
|
|
11863
|
+
"id": "pillar-generated",
|
|
11864
|
+
"icon": "generated",
|
|
11865
|
+
"title": "Built to be generated",
|
|
11866
|
+
"body": "Every constraint is also an instruction. The spec is precise enough for AI agents to scaffold a fully compliant tenant from scratch."
|
|
10497
11867
|
}
|
|
10498
|
-
]
|
|
10499
|
-
|
|
10500
|
-
"settings": {
|
|
10501
|
-
"columns": 3
|
|
11868
|
+
],
|
|
11869
|
+
"anchorId": "Why"
|
|
10502
11870
|
}
|
|
10503
11871
|
},
|
|
10504
11872
|
{
|
|
10505
|
-
"id": "
|
|
10506
|
-
"type": "
|
|
11873
|
+
"id": "architecture-protocols",
|
|
11874
|
+
"type": "olon-architecture",
|
|
10507
11875
|
"data": {
|
|
10508
|
-
"
|
|
10509
|
-
"
|
|
10510
|
-
"
|
|
10511
|
-
"
|
|
10512
|
-
"
|
|
11876
|
+
"id": "architecture-protocols",
|
|
11877
|
+
"label": "Architecture",
|
|
11878
|
+
"headline": "Six governing protocols.",
|
|
11879
|
+
"body": "OlonJS is specified as a versioned set of architectural protocols. Each protocol is independently versioned and mandatory for compliant tenants.",
|
|
11880
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md",
|
|
11881
|
+
"protocols": [
|
|
10513
11882
|
{
|
|
10514
|
-
"id": "
|
|
10515
|
-
"
|
|
10516
|
-
"
|
|
10517
|
-
"
|
|
11883
|
+
"id": "proto-mtrp",
|
|
11884
|
+
"icon": "mtrp",
|
|
11885
|
+
"acronym": "MTRP",
|
|
11886
|
+
"version": "v1.2",
|
|
11887
|
+
"name": "Modular Type Registry",
|
|
11888
|
+
"desc": "Core exports an empty SectionDataRegistry. Tenants extend it via module augmentation. Full TypeScript inference across all section types at compile-time, zero Core changes.",
|
|
11889
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md#1--modular-type-registry-pattern-mtrp-v12"
|
|
10518
11890
|
},
|
|
10519
11891
|
{
|
|
10520
|
-
"id": "
|
|
10521
|
-
"
|
|
10522
|
-
"
|
|
10523
|
-
"
|
|
11892
|
+
"id": "proto-tbp",
|
|
11893
|
+
"icon": "tbp",
|
|
11894
|
+
"acronym": "TBP",
|
|
11895
|
+
"version": "v1.0",
|
|
11896
|
+
"name": "Tenant Block Protocol",
|
|
11897
|
+
"desc": "Each section type is a self-contained capsule: View.tsx, schema.ts, types.ts, index.ts. Renderable, validatable, and ingestible by the engine without additional configuration.",
|
|
11898
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md#3--tenant-block-protocol-tbp-v10"
|
|
10524
11899
|
},
|
|
10525
11900
|
{
|
|
10526
|
-
"id": "
|
|
10527
|
-
"
|
|
10528
|
-
"
|
|
10529
|
-
"
|
|
11901
|
+
"id": "proto-jsp",
|
|
11902
|
+
"icon": "jsp",
|
|
11903
|
+
"acronym": "JSP",
|
|
11904
|
+
"version": "v1.8",
|
|
11905
|
+
"name": "JsonPages Site Protocol",
|
|
11906
|
+
"desc": "Deterministic file system ontology and CLI projection engine. config/ separates global governance from per-page content. Reproducible across every environment.",
|
|
11907
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md#2--jsonpages-site-protocol-jsp-v18"
|
|
11908
|
+
},
|
|
11909
|
+
{
|
|
11910
|
+
"id": "proto-idac",
|
|
11911
|
+
"icon": "idac",
|
|
11912
|
+
"acronym": "IDAC",
|
|
11913
|
+
"version": "v1.0",
|
|
11914
|
+
"name": "ICE Data Contract",
|
|
11915
|
+
"desc": "Mandatory data-jp-* DOM attributes bind every section to its data. Any consumer that can traverse the DOM can identify and operate any content node — human or agent.",
|
|
11916
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md"
|
|
11917
|
+
},
|
|
11918
|
+
{
|
|
11919
|
+
"id": "proto-bsds",
|
|
11920
|
+
"icon": "bsds",
|
|
11921
|
+
"acronym": "BSDS",
|
|
11922
|
+
"version": "v1.0",
|
|
11923
|
+
"name": "Base Schema Fragments",
|
|
11924
|
+
"desc": "BaseSectionData and BaseArrayItem enforce anchor IDs and stable React keys across all capsules. The foundation that doesn't move so your content never drifts.",
|
|
11925
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md"
|
|
11926
|
+
},
|
|
11927
|
+
{
|
|
11928
|
+
"id": "proto-pss",
|
|
11929
|
+
"icon": "pss",
|
|
11930
|
+
"acronym": "PSS",
|
|
11931
|
+
"version": "v1.4",
|
|
11932
|
+
"name": "Path-Based Selection",
|
|
11933
|
+
"desc": "Every node has an address. Content selection uses strict root-to-leaf path semantics — unambiguous, stable, operable by any consumer that knows the contract.",
|
|
11934
|
+
"specHref": "https://github.com/olonjs/core/blob/main/specs/olonjsSpecs_V_1_5.md"
|
|
10530
11935
|
}
|
|
10531
11936
|
],
|
|
10532
|
-
"
|
|
10533
|
-
"successTitle": "Message received",
|
|
10534
|
-
"successBody": "We'll respond within one business day.",
|
|
10535
|
-
"disclaimer": "No spam. Unsubscribe at any time."
|
|
10536
|
-
},
|
|
10537
|
-
"settings": {
|
|
10538
|
-
"showTiers": true
|
|
11937
|
+
"anchorId": "Architecture"
|
|
10539
11938
|
}
|
|
10540
11939
|
},
|
|
10541
11940
|
{
|
|
10542
|
-
"id": "
|
|
10543
|
-
"type": "
|
|
11941
|
+
"id": "example-steps",
|
|
11942
|
+
"type": "olon-example",
|
|
10544
11943
|
"data": {
|
|
10545
|
-
"
|
|
10546
|
-
"
|
|
10547
|
-
"
|
|
10548
|
-
"
|
|
10549
|
-
"
|
|
10550
|
-
"
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
11944
|
+
"id": "example-steps",
|
|
11945
|
+
"label": "Quick Example",
|
|
11946
|
+
"headline": "Two steps. One contract.",
|
|
11947
|
+
"body": "Scaffold a fully compliant tenant in under three minutes. Then read any page via the OlonJS protocol — from a browser, a script, or an AI agent.",
|
|
11948
|
+
"note": "Every OlonJS tenant exposes a machine-readable manifest at",
|
|
11949
|
+
"noteHref": "http://localhost:5173/mcp-manifest.json",
|
|
11950
|
+
"steps": [
|
|
11951
|
+
{
|
|
11952
|
+
"number": 1,
|
|
11953
|
+
"title": "Scaffold a tenant",
|
|
11954
|
+
"meta": "~3 min",
|
|
11955
|
+
"code": "# Install the CLI\nnpm install -g @olonjs/cli\n\n# Scaffold a new tenant\nnpx @olonjs/cli new tenant\n\n✓ Projecting infrastructure...\n✓ Projecting source (src_tenant_alpha.sh)\n✓ Resolving dependencies\n✓ Tenant scaffolded\n\nsrc/\n components/hero/\n View.tsx\n schema.ts\n types.ts\n index.ts\n data/config/\n site.json\n theme.json\n menu.json\n lib/\n schemas.ts\n base-schemas.ts"
|
|
11956
|
+
},
|
|
11957
|
+
{
|
|
11958
|
+
"number": 2,
|
|
11959
|
+
"title": "Read via OlonJS protocol",
|
|
11960
|
+
"meta": "Any consumer",
|
|
11961
|
+
"code": "// Read any page via the contract\n// Works from browser, script, or AI agent\n\nconst page = await\n navigator.modelContextProtocol\n .readResource(\n 'olon://pages/home'\n );\n\n// Returns the full typed contract\n// { slug, meta, sections: Section[] }\n// No DOM scraping. No layout knowledge.\n// Just the contract.\n\n// {\n// \"slug\": \"home\",\n// \"sections\": [\n// { \"type\": \"hero\", \"data\": {...} },\n// { \"type\": \"features\", \"data\": {...} }\n// ]\n// }"
|
|
11962
|
+
}
|
|
11963
|
+
],
|
|
11964
|
+
"anchorId": "Example"
|
|
11965
|
+
}
|
|
11966
|
+
},
|
|
11967
|
+
{
|
|
11968
|
+
"id": "getstarted-cards",
|
|
11969
|
+
"type": "olon-getstarted",
|
|
11970
|
+
"data": {
|
|
11971
|
+
"id": "getstarted-cards",
|
|
11972
|
+
"label": "Get Started",
|
|
11973
|
+
"headline": "Three paths in.",
|
|
11974
|
+
"body": "Start with the Core package, scaffold a full tenant with the CLI, or deploy a working example in one click.",
|
|
11975
|
+
"cards": [
|
|
11976
|
+
{
|
|
11977
|
+
"id": "card-core",
|
|
11978
|
+
"badge": "Open Core",
|
|
11979
|
+
"badgeStyle": "oss",
|
|
11980
|
+
"title": "Install Core",
|
|
11981
|
+
"body": "The Core package is free and open — forever. The contract, the protocols, the CLI. No lock-in on the foundation.",
|
|
11982
|
+
"code": "npm install @olonjs/core",
|
|
11983
|
+
"linkLabel": "View on GitHub",
|
|
11984
|
+
"linkHref": "https://github.com/olonjs/core"
|
|
11985
|
+
},
|
|
11986
|
+
{
|
|
11987
|
+
"id": "card-cli",
|
|
11988
|
+
"badge": "CLI",
|
|
11989
|
+
"badgeStyle": "cli",
|
|
11990
|
+
"title": "Scaffold a tenant",
|
|
11991
|
+
"body": "The CLI scaffolds a fully compliant tenant from a canonical script. Same result on every machine, every run.",
|
|
11992
|
+
"code": "npx @olonjs/cli new tenant",
|
|
11993
|
+
"linkLabel": "View on npm",
|
|
11994
|
+
"linkHref": "https://www.npmjs.com/package/@olonjs/cli"
|
|
11995
|
+
},
|
|
11996
|
+
{
|
|
11997
|
+
"id": "card-deploy",
|
|
11998
|
+
"badge": "Deploy",
|
|
11999
|
+
"badgeStyle": "deploy",
|
|
12000
|
+
"title": "Deploy a template",
|
|
12001
|
+
"body": "Clone a working OlonJS tenant and deploy it with one click. Explore the full capsule structure in a real project.",
|
|
12002
|
+
"deployLabel": "Deploy template →",
|
|
12003
|
+
"deployHref": "https://github.com/olonjs/core",
|
|
12004
|
+
"linkLabel": "View on npm",
|
|
12005
|
+
"linkHref": "https://www.npmjs.com/package/@olonjs/core"
|
|
12006
|
+
}
|
|
12007
|
+
],
|
|
12008
|
+
"anchorId": "Getstarted"
|
|
10554
12009
|
}
|
|
10555
12010
|
}
|
|
10556
12011
|
]
|
|
10557
12012
|
}
|
|
10558
12013
|
END_OF_FILE_CONTENT
|
|
10559
12014
|
mkdir -p "src/data/pages/platform"
|
|
10560
|
-
# SKIP: src/data/pages/platform.json:Zone.Identifier is binary and cannot be embedded as text.
|
|
10561
12015
|
echo "Creating src/data/pages/platform/overview.json..."
|
|
10562
12016
|
cat << 'END_OF_FILE_CONTENT' > "src/data/pages/platform/overview.json"
|
|
10563
12017
|
{
|
|
@@ -12049,6 +13503,13 @@ import { CloudAiNativeGridView } from '@/components/cloud-ai-native-grid';
|
|
|
12049
13503
|
import { PageHero } from '@/components/page-hero';
|
|
12050
13504
|
import { Tiptap } from '@/components/tiptap';
|
|
12051
13505
|
|
|
13506
|
+
|
|
13507
|
+
import { View as OlonHeroView } from '@/components/olon-hero';
|
|
13508
|
+
import { View as OlonWhyView } from '@/components/olon-why';
|
|
13509
|
+
import { View as OlonArchitectureView } from '@/components/olon-architecture';
|
|
13510
|
+
import { View as OlonExampleView } from '@/components/olon-example';
|
|
13511
|
+
import { View as OlonGetStartedView } from '@/components/olon-getstarted';
|
|
13512
|
+
|
|
12052
13513
|
export const ComponentRegistry: {
|
|
12053
13514
|
[K in SectionType]: React.FC<SectionComponentPropsMap[K]>;
|
|
12054
13515
|
} = {
|
|
@@ -12062,6 +13523,13 @@ export const ComponentRegistry: {
|
|
|
12062
13523
|
'cloud-ai-native-grid': CloudAiNativeGridView as React.FC<SectionComponentPropsMap['cloud-ai-native-grid']>,
|
|
12063
13524
|
'page-hero': PageHero as React.FC<SectionComponentPropsMap['page-hero']>,
|
|
12064
13525
|
'tiptap': Tiptap as React.FC<SectionComponentPropsMap['tiptap']>,
|
|
13526
|
+
|
|
13527
|
+
|
|
13528
|
+
'olon-hero': OlonHeroView,
|
|
13529
|
+
'olon-why': OlonWhyView,
|
|
13530
|
+
'olon-architecture': OlonArchitectureView,
|
|
13531
|
+
'olon-example': OlonExampleView,
|
|
13532
|
+
'olon-getstarted': OlonGetStartedView,
|
|
12065
13533
|
};
|
|
12066
13534
|
|
|
12067
13535
|
END_OF_FILE_CONTENT
|
|
@@ -12182,6 +13650,7 @@ export const ImageSelectionSchema = z
|
|
|
12182
13650
|
* Capsules extend these for consistent anchorId, array items, and settings.
|
|
12183
13651
|
*/
|
|
12184
13652
|
export const BaseSectionData = z.object({
|
|
13653
|
+
id: z.string().optional(),
|
|
12185
13654
|
anchorId: z.string().optional().describe('ui:text'),
|
|
12186
13655
|
});
|
|
12187
13656
|
|
|
@@ -12463,6 +13932,12 @@ import { CloudAiNativeGridSchema } from '@/components/cloud-ai-native-grid';
|
|
|
12463
13932
|
import { PageHeroSchema } from '@/components/page-hero';
|
|
12464
13933
|
import { TiptapSchema } from '@/components/tiptap';
|
|
12465
13934
|
|
|
13935
|
+
import { OlonHeroSchema } from '@/components/olon-hero';
|
|
13936
|
+
import { OlonWhySchema } from '@/components/olon-why';
|
|
13937
|
+
import { OlonArchitectureSchema } from '@/components/olon-architecture';
|
|
13938
|
+
import { OlonExampleSchema } from '@/components/olon-example';
|
|
13939
|
+
import { OlonGetStartedSchema } from '@/components/olon-getstarted';
|
|
13940
|
+
|
|
12466
13941
|
export const SECTION_SCHEMAS = {
|
|
12467
13942
|
'header': HeaderSchema,
|
|
12468
13943
|
'footer': FooterSchema,
|
|
@@ -12473,7 +13948,13 @@ export const SECTION_SCHEMAS = {
|
|
|
12473
13948
|
'design-system': DesignSystemSchema,
|
|
12474
13949
|
'cloud-ai-native-grid': CloudAiNativeGridSchema,
|
|
12475
13950
|
'page-hero': PageHeroSchema,
|
|
12476
|
-
'tiptap':
|
|
13951
|
+
'tiptap': TiptapSchema,
|
|
13952
|
+
|
|
13953
|
+
'olon-hero': OlonHeroSchema,
|
|
13954
|
+
'olon-why': OlonWhySchema,
|
|
13955
|
+
'olon-architecture': OlonArchitectureSchema,
|
|
13956
|
+
'olon-example': OlonExampleSchema,
|
|
13957
|
+
'olon-getstarted': OlonGetStartedSchema,
|
|
12477
13958
|
} as const;
|
|
12478
13959
|
|
|
12479
13960
|
export type SectionType = keyof typeof SECTION_SCHEMAS;
|
|
@@ -12620,6 +14101,13 @@ import type { CloudAiNativeGridData, CloudAiNativeGridSettings } from '@/com
|
|
|
12620
14101
|
import type { PageHeroData, PageHeroSettings } from '@/components/page-hero';
|
|
12621
14102
|
import type { TiptapData, TiptapSettings } from '@/components/tiptap';
|
|
12622
14103
|
|
|
14104
|
+
|
|
14105
|
+
import type { OlonHeroData } from '@/components/olon-hero';
|
|
14106
|
+
import type { OlonWhyData } from '@/components/olon-why';
|
|
14107
|
+
import type { OlonArchitectureData } from '@/components/olon-architecture';
|
|
14108
|
+
import type { OlonExampleData } from '@/components/olon-example';
|
|
14109
|
+
import type { OlonGetStartedData } from '@/components/olon-getstarted';
|
|
14110
|
+
|
|
12623
14111
|
export type SectionComponentPropsMap = {
|
|
12624
14112
|
'header': { data: HeaderData; settings?: HeaderSettings; menu: MenuItem[] };
|
|
12625
14113
|
'footer': { data: FooterData; settings?: FooterSettings };
|
|
@@ -12631,6 +14119,13 @@ export type SectionComponentPropsMap = {
|
|
|
12631
14119
|
'cloud-ai-native-grid': { data: CloudAiNativeGridData; settings?: CloudAiNativeGridSettings };
|
|
12632
14120
|
'page-hero': { data: PageHeroData; settings?: PageHeroSettings };
|
|
12633
14121
|
'tiptap': { data: TiptapData; settings?: TiptapSettings };
|
|
14122
|
+
|
|
14123
|
+
|
|
14124
|
+
'olon-hero': { data: OlonHeroData };
|
|
14125
|
+
'olon-why': { data: OlonWhyData };
|
|
14126
|
+
'olon-architecture': { data: OlonArchitectureData };
|
|
14127
|
+
'olon-example': { data: OlonExampleData };
|
|
14128
|
+
'olon-getstarted': { data: OlonGetStartedData };
|
|
12634
14129
|
};
|
|
12635
14130
|
|
|
12636
14131
|
declare module '@olonjs/core' {
|
|
@@ -12645,6 +14140,11 @@ declare module '@olonjs/core' {
|
|
|
12645
14140
|
'cloud-ai-native-grid': CloudAiNativeGridData;
|
|
12646
14141
|
'page-hero': PageHeroData;
|
|
12647
14142
|
'tiptap': TiptapData;
|
|
14143
|
+
'olon-hero': OlonHeroData;
|
|
14144
|
+
'olon-why': OlonWhyData;
|
|
14145
|
+
'olon-architecture': OlonArchitectureData;
|
|
14146
|
+
'olon-example': OlonExampleData;
|
|
14147
|
+
'olon-getstarted': OlonGetStartedData;
|
|
12648
14148
|
}
|
|
12649
14149
|
export interface SectionSettingsRegistry {
|
|
12650
14150
|
'header': HeaderSettings;
|
|
@@ -12887,22 +14387,23 @@ export default defineConfig({
|
|
|
12887
14387
|
}
|
|
12888
14388
|
|
|
12889
14389
|
const schemaMatch = pathname.match(/^\/schemas\/(.+)\.schema\.json$/i);
|
|
12890
|
-
if (
|
|
14390
|
+
if (schemaMatch && req.method === 'GET') {
|
|
14391
|
+
const slug = normalizeManifestSlug(schemaMatch[1]);
|
|
14392
|
+
const pageConfig = buildState.pages[slug];
|
|
14393
|
+
if (!pageConfig) {
|
|
14394
|
+
sendJson(res, 404, { error: 'Schema contract not found' });
|
|
14395
|
+
return true;
|
|
14396
|
+
}
|
|
12891
14397
|
|
|
12892
|
-
|
|
12893
|
-
|
|
12894
|
-
|
|
12895
|
-
|
|
14398
|
+
sendJson(res, 200, buildPageContract({
|
|
14399
|
+
slug,
|
|
14400
|
+
pageConfig,
|
|
14401
|
+
schemas: buildState.schemas,
|
|
14402
|
+
siteConfig: buildState.siteConfig,
|
|
14403
|
+
}));
|
|
12896
14404
|
return true;
|
|
12897
14405
|
}
|
|
12898
|
-
|
|
12899
|
-
sendJson(res, 200, buildPageContract({
|
|
12900
|
-
slug,
|
|
12901
|
-
pageConfig,
|
|
12902
|
-
schemas: buildState.schemas,
|
|
12903
|
-
siteConfig: buildState.siteConfig,
|
|
12904
|
-
}));
|
|
12905
|
-
return true;
|
|
14406
|
+
return false;
|
|
12906
14407
|
};
|
|
12907
14408
|
|
|
12908
14409
|
if (
|
|
@@ -12915,7 +14416,11 @@ export default defineConfig({
|
|
|
12915
14416
|
) {
|
|
12916
14417
|
void handleManifestRequest()
|
|
12917
14418
|
.then((handled) => {
|
|
12918
|
-
if (!handled)
|
|
14419
|
+
if (!handled) {
|
|
14420
|
+
// Se handleManifestRequest fallisce a trovare qualcosa ma l'URL era giusto,
|
|
14421
|
+
// forziamo un 404 JSON per evitare che Vite serva l'index.html
|
|
14422
|
+
sendJson(res, 404, { error: 'Manifest or schema not found' });
|
|
14423
|
+
}
|
|
12919
14424
|
})
|
|
12920
14425
|
.catch((error) => {
|
|
12921
14426
|
sendJson(res, 500, { error: error?.message || 'Manifest generation failed' });
|