@olonjs/cli 3.0.124 → 3.0.125
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 +3311 -483
- package/assets/templates/agritourism/src_tenant.sh +1 -1
- package/assets/templates/alpha/src_tenant.sh +3311 -483
- package/package.json +1 -1
|
@@ -1445,7 +1445,6 @@ When you receive a OlonJS tenant task:
|
|
|
1445
1445
|
5. State assumptions when inferring intended branded output from examples.
|
|
1446
1446
|
|
|
1447
1447
|
END_OF_FILE_CONTENT
|
|
1448
|
-
# SKIP: .cursor/skills-cursor/olonjs/SKILL.md:Zone.Identifier is binary and cannot be embedded as text.
|
|
1449
1448
|
mkdir -p ".cursor/skills-cursor/shell"
|
|
1450
1449
|
echo "Creating .cursor/skills-cursor/shell/SKILL.md..."
|
|
1451
1450
|
cat << 'END_OF_FILE_CONTENT' > ".cursor/skills-cursor/shell/SKILL.md"
|
|
@@ -1644,7 +1643,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
|
|
|
1644
1643
|
"@tiptap/extension-link": "^2.11.5",
|
|
1645
1644
|
"@tiptap/react": "^2.11.5",
|
|
1646
1645
|
"@tiptap/starter-kit": "^2.11.5",
|
|
1647
|
-
"@olonjs/core": "^1.0.
|
|
1646
|
+
"@olonjs/core": "^1.0.114",
|
|
1648
1647
|
"class-variance-authority": "^0.7.1",
|
|
1649
1648
|
"clsx": "^2.1.1",
|
|
1650
1649
|
"lucide-react": "^0.474.0",
|
|
@@ -2553,6 +2552,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/App.tsx"
|
|
|
2553
2552
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2554
2553
|
import { JsonPagesEngine } from '@olonjs/core';
|
|
2555
2554
|
import type { JsonPagesConfig, LibraryImageEntry, ProjectState } from '@olonjs/core';
|
|
2555
|
+
import { normalizeBasePath, withBasePath } from '@olonjs/core';
|
|
2556
2556
|
import { ComponentRegistry } from '@/lib/ComponentRegistry';
|
|
2557
2557
|
import { SECTION_SCHEMAS } from '@/lib/schemas';
|
|
2558
2558
|
import { addSectionConfig } from '@/lib/addSectionConfig';
|
|
@@ -2577,14 +2577,16 @@ const CLOUD_API_URL =
|
|
|
2577
2577
|
const CLOUD_API_KEY =
|
|
2578
2578
|
import.meta.env.VITE_OLONJS_API_KEY ?? import.meta.env.VITE_JSONPAGES_API_KEY;
|
|
2579
2579
|
const SAVE2REPO_ENABLED = import.meta.env.VITE_SAVE2REPO === 'true';
|
|
2580
|
+
const APP_BASE_PATH = normalizeBasePath(import.meta.env.BASE_URL || '/');
|
|
2580
2581
|
|
|
2581
2582
|
const themeConfig = themeData as unknown as ThemeConfig;
|
|
2582
|
-
const menuConfig
|
|
2583
|
+
const menuConfig = menuData as unknown as MenuConfig;
|
|
2583
2584
|
const refDocuments = {
|
|
2584
|
-
'menu.json':
|
|
2585
|
-
'config/menu.json':
|
|
2586
|
-
'src/data/config/menu.json':
|
|
2585
|
+
'menu.json': menuConfig,
|
|
2586
|
+
'config/menu.json': menuConfig,
|
|
2587
|
+
'src/data/config/menu.json': menuConfig,
|
|
2587
2588
|
} satisfies NonNullable<JsonPagesConfig['refDocuments']>;
|
|
2589
|
+
|
|
2588
2590
|
const TENANT_ID = 'alpha';
|
|
2589
2591
|
|
|
2590
2592
|
const filePages = getFilePages();
|
|
@@ -2844,13 +2846,13 @@ function normalizeSlugForCache(slug: string): string {
|
|
|
2844
2846
|
}
|
|
2845
2847
|
|
|
2846
2848
|
function buildPublishedPageHref(slug: string): string {
|
|
2847
|
-
return `/pages/${normalizeSlugForCache(slug)}.json
|
|
2849
|
+
return withBasePath(`/pages/${normalizeSlugForCache(slug)}.json`, APP_BASE_PATH);
|
|
2848
2850
|
}
|
|
2849
2851
|
|
|
2850
2852
|
async function loadPublishedStaticContent(
|
|
2851
2853
|
knownSlugs: string[]
|
|
2852
2854
|
): Promise<{ pages: Record<string, PageConfig>; siteConfig: SiteConfig }> {
|
|
2853
|
-
const siteResponse = await fetch('/config/site.json', { cache: 'no-store' });
|
|
2855
|
+
const siteResponse = await fetch(withBasePath('/config/site.json', APP_BASE_PATH), { cache: 'no-store' });
|
|
2854
2856
|
if (!siteResponse.ok) {
|
|
2855
2857
|
throw new Error(`Static site config unavailable: ${siteResponse.status}`);
|
|
2856
2858
|
}
|
|
@@ -3330,6 +3332,7 @@ function App() {
|
|
|
3330
3332
|
|
|
3331
3333
|
const config: JsonPagesConfig = {
|
|
3332
3334
|
tenantId: TENANT_ID,
|
|
3335
|
+
basePath: APP_BASE_PATH,
|
|
3333
3336
|
registry: ComponentRegistry as JsonPagesConfig['registry'],
|
|
3334
3337
|
schemas: SECTION_SCHEMAS as unknown as JsonPagesConfig['schemas'],
|
|
3335
3338
|
pages,
|
|
@@ -3398,7 +3401,7 @@ function App() {
|
|
|
3398
3401
|
showColdSave: isSave2RepoMode,
|
|
3399
3402
|
},
|
|
3400
3403
|
assets: {
|
|
3401
|
-
assetsBaseUrl: '/assets',
|
|
3404
|
+
assetsBaseUrl: withBasePath('/assets', APP_BASE_PATH),
|
|
3402
3405
|
assetsManifest,
|
|
3403
3406
|
async onAssetUpload(file: File): Promise<string> {
|
|
3404
3407
|
if (!file.type.startsWith('image/')) throw new Error('Invalid file type.');
|
|
@@ -3814,7 +3817,6 @@ export function useTheme() {
|
|
|
3814
3817
|
}
|
|
3815
3818
|
|
|
3816
3819
|
END_OF_FILE_CONTENT
|
|
3817
|
-
# SKIP: src/components/ThemeProvider.tsx:Zone.Identifier is binary and cannot be embedded as text.
|
|
3818
3820
|
echo "Creating src/components/ThemeToggle.tsx..."
|
|
3819
3821
|
cat << 'END_OF_FILE_CONTENT' > "src/components/ThemeToggle.tsx"
|
|
3820
3822
|
import { Sun, Moon } from 'lucide-react'
|
|
@@ -3845,7 +3847,243 @@ export function ThemeToggle({ className }: ThemeToggleProps) {
|
|
|
3845
3847
|
}
|
|
3846
3848
|
|
|
3847
3849
|
END_OF_FILE_CONTENT
|
|
3848
|
-
|
|
3850
|
+
mkdir -p "src/components/accommodations-section"
|
|
3851
|
+
echo "Creating src/components/accommodations-section/View.tsx..."
|
|
3852
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/accommodations-section/View.tsx"
|
|
3853
|
+
// Layout: Hero=N/A, Features=HORIZONTAL SCROLL (cards in scrollable row)
|
|
3854
|
+
import React from 'react';
|
|
3855
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
3856
|
+
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
3857
|
+
import { Check } from 'lucide-react';
|
|
3858
|
+
import type { AccommodationsSectionData, AccommodationsSectionSettings } from './types';
|
|
3859
|
+
|
|
3860
|
+
export const AccommodationsSection: React.FC<{ data: AccommodationsSectionData; settings: AccommodationsSectionSettings }> = ({ data }) => {
|
|
3861
|
+
return (
|
|
3862
|
+
<section
|
|
3863
|
+
style={{
|
|
3864
|
+
'--local-bg': 'var(--elevated)',
|
|
3865
|
+
'--local-text': 'var(--foreground)',
|
|
3866
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
3867
|
+
'--local-primary': 'var(--primary)',
|
|
3868
|
+
'--local-accent': 'var(--accent)',
|
|
3869
|
+
'--local-border': 'var(--border)',
|
|
3870
|
+
'--local-surface': 'var(--card)',
|
|
3871
|
+
'--local-radius-lg': 'var(--theme-radius-lg)',
|
|
3872
|
+
'--local-radius-md': 'var(--theme-radius-md)',
|
|
3873
|
+
} as React.CSSProperties}
|
|
3874
|
+
className="relative z-0 py-28 bg-[var(--local-bg)]"
|
|
3875
|
+
>
|
|
3876
|
+
<div className="max-w-[var(--theme-spacing-container-max)] mx-auto px-6">
|
|
3877
|
+
{/* Header */}
|
|
3878
|
+
<div className="text-center mb-12">
|
|
3879
|
+
{data.label && (
|
|
3880
|
+
<div className="inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase tracking-[0.12em] text-[var(--local-accent)] mb-4" data-jp-field="label">
|
|
3881
|
+
<span className="w-5 h-px bg-[var(--local-primary)]" />
|
|
3882
|
+
{data.label}
|
|
3883
|
+
</div>
|
|
3884
|
+
)}
|
|
3885
|
+
<h2 className="font-display font-black text-[clamp(2rem,4.5vw,3.8rem)] leading-[1.05] tracking-tight text-[var(--local-text)] mb-4" data-jp-field="title">
|
|
3886
|
+
{data.title}
|
|
3887
|
+
</h2>
|
|
3888
|
+
{data.subtitle && (
|
|
3889
|
+
<p className="text-lg text-[var(--local-text-muted)] max-w-2xl mx-auto" data-jp-field="subtitle">
|
|
3890
|
+
{data.subtitle}
|
|
3891
|
+
</p>
|
|
3892
|
+
)}
|
|
3893
|
+
</div>
|
|
3894
|
+
|
|
3895
|
+
{/* Horizontal Scrolling Cards */}
|
|
3896
|
+
<ScrollArea className="w-full">
|
|
3897
|
+
<div className="flex gap-6 pb-4" style={{ width: 'max-content' }}>
|
|
3898
|
+
{data.accommodations.map((accommodation, idx) => (
|
|
3899
|
+
<Card
|
|
3900
|
+
key={accommodation.id || `legacy-${idx}`}
|
|
3901
|
+
className="w-80 flex-shrink-0 bg-[var(--local-surface)] border-[var(--local-border)] rounded-[var(--local-radius-lg)] overflow-hidden group hover:shadow-lg transition-all duration-300"
|
|
3902
|
+
data-jp-item-id={accommodation.id || `legacy-${idx}`}
|
|
3903
|
+
data-jp-item-field="accommodations"
|
|
3904
|
+
>
|
|
3905
|
+
{accommodation.image?.url && (
|
|
3906
|
+
<div className="relative h-48 overflow-hidden">
|
|
3907
|
+
<img
|
|
3908
|
+
src={accommodation.image.url}
|
|
3909
|
+
alt={accommodation.image.alt}
|
|
3910
|
+
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
|
|
3911
|
+
/>
|
|
3912
|
+
<div className="absolute inset-0 bg-gradient-to-t from-black/50 via-transparent to-transparent" />
|
|
3913
|
+
</div>
|
|
3914
|
+
)}
|
|
3915
|
+
|
|
3916
|
+
<CardHeader className="pb-3">
|
|
3917
|
+
<CardTitle className="font-display text-xl text-[var(--local-text)]">
|
|
3918
|
+
{accommodation.title}
|
|
3919
|
+
</CardTitle>
|
|
3920
|
+
</CardHeader>
|
|
3921
|
+
|
|
3922
|
+
<CardContent className="space-y-4">
|
|
3923
|
+
<p className="text-[var(--local-text-muted)] leading-relaxed">
|
|
3924
|
+
{accommodation.description}
|
|
3925
|
+
</p>
|
|
3926
|
+
|
|
3927
|
+
{accommodation.features.length > 0 && (
|
|
3928
|
+
<div className="space-y-2">
|
|
3929
|
+
<h4 className="font-semibold text-sm text-[var(--local-text)]">Caratteristiche:</h4>
|
|
3930
|
+
<div className="space-y-1">
|
|
3931
|
+
{accommodation.features.map((feature, featureIdx) => (
|
|
3932
|
+
<div key={featureIdx} className="flex items-center gap-2">
|
|
3933
|
+
<Check className="w-4 h-4 text-[var(--local-primary)] flex-shrink-0" />
|
|
3934
|
+
<span className="text-sm text-[var(--local-text-muted)]">{feature}</span>
|
|
3935
|
+
</div>
|
|
3936
|
+
))}
|
|
3937
|
+
</div>
|
|
3938
|
+
</div>
|
|
3939
|
+
)}
|
|
3940
|
+
</CardContent>
|
|
3941
|
+
</Card>
|
|
3942
|
+
))}
|
|
3943
|
+
</div>
|
|
3944
|
+
</ScrollArea>
|
|
3945
|
+
|
|
3946
|
+
{data.accommodations.length > 3 && (
|
|
3947
|
+
<div className="text-center mt-6">
|
|
3948
|
+
<p className="text-sm text-[var(--local-text-muted)]">
|
|
3949
|
+
Scorri orizzontalmente per vedere tutte le sistemazioni
|
|
3950
|
+
</p>
|
|
3951
|
+
</div>
|
|
3952
|
+
)}
|
|
3953
|
+
</div>
|
|
3954
|
+
</section>
|
|
3955
|
+
);
|
|
3956
|
+
};
|
|
3957
|
+
|
|
3958
|
+
END_OF_FILE_CONTENT
|
|
3959
|
+
echo "Creating src/components/accommodations-section/index.ts..."
|
|
3960
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/accommodations-section/index.ts"
|
|
3961
|
+
export { AccommodationsSection } from './View';
|
|
3962
|
+
export { AccommodationsSectionSchema } from './schema';
|
|
3963
|
+
export type { AccommodationsSectionData, AccommodationsSectionSettings } from './types';
|
|
3964
|
+
|
|
3965
|
+
|
|
3966
|
+
END_OF_FILE_CONTENT
|
|
3967
|
+
echo "Creating src/components/accommodations-section/schema.ts..."
|
|
3968
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/accommodations-section/schema.ts"
|
|
3969
|
+
import { z } from 'zod';
|
|
3970
|
+
import { BaseSectionData, BaseArrayItem, ImageSelectionSchema } from '@/lib/base-schemas';
|
|
3971
|
+
|
|
3972
|
+
const AccommodationItem = BaseArrayItem.extend({
|
|
3973
|
+
title: z.string().describe('ui:text'),
|
|
3974
|
+
description: z.string().describe('ui:textarea'),
|
|
3975
|
+
features: z.array(z.string()).describe('ui:list'),
|
|
3976
|
+
image: ImageSelectionSchema,
|
|
3977
|
+
});
|
|
3978
|
+
|
|
3979
|
+
export const AccommodationsSectionSchema = BaseSectionData.extend({
|
|
3980
|
+
label: z.string().optional().describe('ui:text'),
|
|
3981
|
+
title: z.string().describe('ui:text'),
|
|
3982
|
+
subtitle: z.string().optional().describe('ui:textarea'),
|
|
3983
|
+
accommodations: z.array(AccommodationItem).describe('ui:list'),
|
|
3984
|
+
});
|
|
3985
|
+
|
|
3986
|
+
|
|
3987
|
+
END_OF_FILE_CONTENT
|
|
3988
|
+
echo "Creating src/components/accommodations-section/types.ts..."
|
|
3989
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/accommodations-section/types.ts"
|
|
3990
|
+
import { z } from 'zod';
|
|
3991
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
3992
|
+
import { AccommodationsSectionSchema } from './schema';
|
|
3993
|
+
|
|
3994
|
+
export type AccommodationsSectionData = z.infer<typeof AccommodationsSectionSchema>;
|
|
3995
|
+
export type AccommodationsSectionSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
3996
|
+
|
|
3997
|
+
|
|
3998
|
+
END_OF_FILE_CONTENT
|
|
3999
|
+
mkdir -p "src/components/activities-section"
|
|
4000
|
+
echo "Creating src/components/activities-section/View.tsx..."
|
|
4001
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/activities-section/View.tsx"
|
|
4002
|
+
// Layout: Hero=F (MINIMAL HERO), Features=D (ACCORDION)
|
|
4003
|
+
import React from 'react';
|
|
4004
|
+
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
|
|
4005
|
+
import type { ActivitiesSectionData, ActivitiesSectionSettings } from './types';
|
|
4006
|
+
|
|
4007
|
+
export const ActivitiesSectionComponent: React.FC<{ data: ActivitiesSectionData; settings: ActivitiesSectionSettings }> = ({ data }) => (
|
|
4008
|
+
<section
|
|
4009
|
+
style={{
|
|
4010
|
+
'--local-bg': 'var(--background)',
|
|
4011
|
+
'--local-text': 'var(--foreground)',
|
|
4012
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
4013
|
+
'--local-primary': 'var(--primary)',
|
|
4014
|
+
'--local-accent': 'var(--accent)',
|
|
4015
|
+
'--local-border': 'var(--border)',
|
|
4016
|
+
'--local-surface': 'var(--card)',
|
|
4017
|
+
'--local-radius-lg': 'var(--theme-radius-lg)',
|
|
4018
|
+
} as React.CSSProperties}
|
|
4019
|
+
className="relative z-0 py-24"
|
|
4020
|
+
>
|
|
4021
|
+
<div className="max-w-[900px] mx-auto px-8">
|
|
4022
|
+
{data.label && (
|
|
4023
|
+
<div className="jp-section-label inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase text-[var(--local-accent)] mb-4" data-jp-field="label">
|
|
4024
|
+
<span className="w-5 h-px bg-[var(--local-primary)]" />
|
|
4025
|
+
{data.label}
|
|
4026
|
+
</div>
|
|
4027
|
+
)}
|
|
4028
|
+
<h2 className="font-display font-black text-[clamp(2rem,4.5vw,3.8rem)] leading-[1.05] tracking-tight text-[var(--local-text)]" data-jp-field="title">{data.title}</h2>
|
|
4029
|
+
<p className="mt-5 text-[var(--local-text-muted)] max-w-2xl" data-jp-field="description">{data.description}</p>
|
|
4030
|
+
<Accordion type="single" collapsible className="mt-8 rounded-[var(--local-radius-lg)] border border-[var(--local-border)] bg-[var(--local-surface)] px-6">
|
|
4031
|
+
{data.items.map((item, idx) => (
|
|
4032
|
+
<AccordionItem
|
|
4033
|
+
key={item.id || 'legacy-' + idx}
|
|
4034
|
+
value={item.id || 'legacy-' + idx}
|
|
4035
|
+
data-jp-item-id={item.id || 'legacy-' + idx}
|
|
4036
|
+
data-jp-item-field="items"
|
|
4037
|
+
>
|
|
4038
|
+
<AccordionTrigger className="font-display text-left text-[var(--local-text)]">{item.title}</AccordionTrigger>
|
|
4039
|
+
<AccordionContent className="text-[var(--local-text-muted)]">{item.body}</AccordionContent>
|
|
4040
|
+
</AccordionItem>
|
|
4041
|
+
))}
|
|
4042
|
+
</Accordion>
|
|
4043
|
+
</div>
|
|
4044
|
+
</section>
|
|
4045
|
+
);
|
|
4046
|
+
|
|
4047
|
+
|
|
4048
|
+
END_OF_FILE_CONTENT
|
|
4049
|
+
echo "Creating src/components/activities-section/index.ts..."
|
|
4050
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/activities-section/index.ts"
|
|
4051
|
+
export { ActivitiesSectionComponent } from './View';
|
|
4052
|
+
export { ActivitiesSectionSchema } from './schema';
|
|
4053
|
+
export type { ActivitiesSectionData, ActivitiesSectionSettings } from './types';
|
|
4054
|
+
|
|
4055
|
+
|
|
4056
|
+
END_OF_FILE_CONTENT
|
|
4057
|
+
echo "Creating src/components/activities-section/schema.ts..."
|
|
4058
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/activities-section/schema.ts"
|
|
4059
|
+
import { z } from 'zod';
|
|
4060
|
+
import { BaseSectionData, BaseArrayItem } from '@/lib/base-schemas';
|
|
4061
|
+
|
|
4062
|
+
const ActivitySchema = BaseArrayItem.extend({
|
|
4063
|
+
title: z.string().describe('ui:text'),
|
|
4064
|
+
body: z.string().describe('ui:textarea'),
|
|
4065
|
+
});
|
|
4066
|
+
|
|
4067
|
+
export const ActivitiesSectionSchema = BaseSectionData.extend({
|
|
4068
|
+
label: z.string().optional().describe('ui:text'),
|
|
4069
|
+
title: z.string().describe('ui:text'),
|
|
4070
|
+
description: z.string().describe('ui:textarea'),
|
|
4071
|
+
items: z.array(ActivitySchema).describe('ui:list'),
|
|
4072
|
+
});
|
|
4073
|
+
|
|
4074
|
+
|
|
4075
|
+
END_OF_FILE_CONTENT
|
|
4076
|
+
echo "Creating src/components/activities-section/types.ts..."
|
|
4077
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/activities-section/types.ts"
|
|
4078
|
+
import { z } from 'zod';
|
|
4079
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
4080
|
+
import { ActivitiesSectionSchema } from './schema';
|
|
4081
|
+
|
|
4082
|
+
export type ActivitiesSectionData = z.infer<typeof ActivitiesSectionSchema>;
|
|
4083
|
+
export type ActivitiesSectionSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
4084
|
+
|
|
4085
|
+
|
|
4086
|
+
END_OF_FILE_CONTENT
|
|
3849
4087
|
mkdir -p "src/components/cloud-ai-native-grid"
|
|
3850
4088
|
echo "Creating src/components/cloud-ai-native-grid/View.tsx..."
|
|
3851
4089
|
cat << 'END_OF_FILE_CONTENT' > "src/components/cloud-ai-native-grid/View.tsx"
|
|
@@ -3944,6 +4182,104 @@ export type CloudAiNativeGridSettings = z.infer<typeof CloudAiNativeGridSettings
|
|
|
3944
4182
|
|
|
3945
4183
|
END_OF_FILE_CONTENT
|
|
3946
4184
|
mkdir -p "src/components/contact"
|
|
4185
|
+
mkdir -p "src/components/contact-section"
|
|
4186
|
+
echo "Creating src/components/contact-section/View.tsx..."
|
|
4187
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/contact-section/View.tsx"
|
|
4188
|
+
// Layout: Hero=E (MAGAZINE), Features=C (TIMELINE)
|
|
4189
|
+
import React from 'react';
|
|
4190
|
+
import { ArrowRight, MapPin } from 'lucide-react';
|
|
4191
|
+
import { Button } from '@/components/ui/button';
|
|
4192
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
4193
|
+
import type { ContactSectionData, ContactSectionSettings } from './types';
|
|
4194
|
+
|
|
4195
|
+
export const ContactSectionComponent: React.FC<{ data: ContactSectionData; settings: ContactSectionSettings }> = ({ data }) => (
|
|
4196
|
+
<section
|
|
4197
|
+
style={{
|
|
4198
|
+
'--local-bg': 'var(--background)',
|
|
4199
|
+
'--local-text': 'var(--foreground)',
|
|
4200
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
4201
|
+
'--local-primary': 'var(--primary)',
|
|
4202
|
+
'--local-primary-foreground': 'var(--primary-foreground)',
|
|
4203
|
+
'--local-accent': 'var(--accent)',
|
|
4204
|
+
'--local-border': 'var(--border)',
|
|
4205
|
+
'--local-surface': 'var(--card)',
|
|
4206
|
+
'--local-radius-md': 'var(--theme-radius-md)',
|
|
4207
|
+
'--local-radius-lg': 'var(--theme-radius-lg)',
|
|
4208
|
+
} as React.CSSProperties}
|
|
4209
|
+
className="relative z-0 py-24"
|
|
4210
|
+
>
|
|
4211
|
+
<div className="max-w-[1200px] mx-auto px-8 grid gap-8 lg:grid-cols-[0.9fr_1.1fr]">
|
|
4212
|
+
<div>
|
|
4213
|
+
{data.label && (
|
|
4214
|
+
<div className="jp-section-label inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase text-[var(--local-accent)] mb-4" data-jp-field="label">
|
|
4215
|
+
<span className="w-5 h-px bg-[var(--local-primary)]" />
|
|
4216
|
+
{data.label}
|
|
4217
|
+
</div>
|
|
4218
|
+
)}
|
|
4219
|
+
<h2 className="font-display font-black text-[clamp(2rem,4.5vw,3.8rem)] leading-[1.05] tracking-tight text-[var(--local-text)]" data-jp-field="title">{data.title}</h2>
|
|
4220
|
+
<p className="mt-4 max-w-lg text-[var(--local-text-muted)]" data-jp-field="description">{data.description}</p>
|
|
4221
|
+
<Button asChild variant="default" className="mt-6 bg-[var(--local-primary)] text-[var(--local-primary-foreground)] hover:opacity-90 rounded-[var(--local-radius-md)]">
|
|
4222
|
+
<a href={data.primaryCta.href}>{data.primaryCta.label} <ArrowRight className="h-4 w-4" /></a>
|
|
4223
|
+
</Button>
|
|
4224
|
+
</div>
|
|
4225
|
+
<div className="grid gap-4">
|
|
4226
|
+
{data.details.map((item, idx) => (
|
|
4227
|
+
<Card key={item.id || 'legacy-' + idx} className="border-[var(--local-border)] bg-[var(--local-surface)] rounded-[var(--local-radius-lg)]" data-jp-item-id={item.id || 'legacy-' + idx} data-jp-item-field="details">
|
|
4228
|
+
<CardContent className="p-6 flex gap-4">
|
|
4229
|
+
<MapPin className="h-5 w-5 mt-1 text-[var(--local-accent)]" />
|
|
4230
|
+
<div>
|
|
4231
|
+
<h3 className="font-display font-bold text-[1.2rem] text-[var(--local-text)]">{item.title}</h3>
|
|
4232
|
+
<p className="mt-2 text-sm text-[var(--local-text-muted)] whitespace-pre-line">{item.body}</p>
|
|
4233
|
+
</div>
|
|
4234
|
+
</CardContent>
|
|
4235
|
+
</Card>
|
|
4236
|
+
))}
|
|
4237
|
+
</div>
|
|
4238
|
+
</div>
|
|
4239
|
+
</section>
|
|
4240
|
+
);
|
|
4241
|
+
|
|
4242
|
+
|
|
4243
|
+
END_OF_FILE_CONTENT
|
|
4244
|
+
echo "Creating src/components/contact-section/index.ts..."
|
|
4245
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/contact-section/index.ts"
|
|
4246
|
+
export { ContactSectionComponent } from './View';
|
|
4247
|
+
export { ContactSectionSchema } from './schema';
|
|
4248
|
+
export type { ContactSectionData, ContactSectionSettings } from './types';
|
|
4249
|
+
|
|
4250
|
+
|
|
4251
|
+
END_OF_FILE_CONTENT
|
|
4252
|
+
echo "Creating src/components/contact-section/schema.ts..."
|
|
4253
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/contact-section/schema.ts"
|
|
4254
|
+
import { z } from 'zod';
|
|
4255
|
+
import { BaseSectionData, BaseArrayItem, CtaSchema } from '@/lib/base-schemas';
|
|
4256
|
+
|
|
4257
|
+
const DetailSchema = BaseArrayItem.extend({
|
|
4258
|
+
title: z.string().describe('ui:text'),
|
|
4259
|
+
body: z.string().describe('ui:textarea'),
|
|
4260
|
+
});
|
|
4261
|
+
|
|
4262
|
+
export const ContactSectionSchema = BaseSectionData.extend({
|
|
4263
|
+
label: z.string().optional().describe('ui:text'),
|
|
4264
|
+
title: z.string().describe('ui:text'),
|
|
4265
|
+
description: z.string().describe('ui:textarea'),
|
|
4266
|
+
details: z.array(DetailSchema).describe('ui:list'),
|
|
4267
|
+
primaryCta: CtaSchema,
|
|
4268
|
+
});
|
|
4269
|
+
|
|
4270
|
+
|
|
4271
|
+
END_OF_FILE_CONTENT
|
|
4272
|
+
echo "Creating src/components/contact-section/types.ts..."
|
|
4273
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/contact-section/types.ts"
|
|
4274
|
+
import { z } from 'zod';
|
|
4275
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
4276
|
+
import { ContactSectionSchema } from './schema';
|
|
4277
|
+
|
|
4278
|
+
export type ContactSectionData = z.infer<typeof ContactSectionSchema>;
|
|
4279
|
+
export type ContactSectionSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
4280
|
+
|
|
4281
|
+
|
|
4282
|
+
END_OF_FILE_CONTENT
|
|
3947
4283
|
echo "Creating src/components/contact/View.tsx..."
|
|
3948
4284
|
cat << 'END_OF_FILE_CONTENT' > "src/components/contact/View.tsx"
|
|
3949
4285
|
import { useState, type CSSProperties } from 'react';
|
|
@@ -4270,6 +4606,103 @@ import { CtaBannerSchema } from './schema';
|
|
|
4270
4606
|
export type CtaBannerData = z.infer<typeof CtaBannerSchema>;
|
|
4271
4607
|
export type CtaBannerSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
4272
4608
|
|
|
4609
|
+
END_OF_FILE_CONTENT
|
|
4610
|
+
mkdir -p "src/components/cuisine-section"
|
|
4611
|
+
echo "Creating src/components/cuisine-section/View.tsx..."
|
|
4612
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/cuisine-section/View.tsx"
|
|
4613
|
+
// Layout: Hero=B (BENTO GRID), Features=A (BENTO)
|
|
4614
|
+
import React from 'react';
|
|
4615
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
4616
|
+
import type { CuisineSectionData, CuisineSectionSettings } from './types';
|
|
4617
|
+
|
|
4618
|
+
export const CuisineSectionComponent: React.FC<{ data: CuisineSectionData; settings: CuisineSectionSettings }> = ({ data }) => (
|
|
4619
|
+
<section
|
|
4620
|
+
style={{
|
|
4621
|
+
'--local-bg': 'var(--card)',
|
|
4622
|
+
'--local-text': 'var(--foreground)',
|
|
4623
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
4624
|
+
'--local-primary': 'var(--primary)',
|
|
4625
|
+
'--local-accent': 'var(--accent)',
|
|
4626
|
+
'--local-border': 'var(--border)',
|
|
4627
|
+
'--local-surface': 'var(--background)',
|
|
4628
|
+
'--local-radius-md': 'var(--theme-radius-md)',
|
|
4629
|
+
'--local-radius-lg': 'var(--theme-radius-lg)',
|
|
4630
|
+
} as React.CSSProperties}
|
|
4631
|
+
className="relative z-0 py-24 bg-[var(--local-bg)]"
|
|
4632
|
+
>
|
|
4633
|
+
<div className="max-w-[1200px] mx-auto px-8">
|
|
4634
|
+
{data.label && (
|
|
4635
|
+
<div className="jp-section-label inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase text-[var(--local-accent)] mb-4" data-jp-field="label">
|
|
4636
|
+
<span className="w-5 h-px bg-[var(--local-primary)]" />
|
|
4637
|
+
{data.label}
|
|
4638
|
+
</div>
|
|
4639
|
+
)}
|
|
4640
|
+
<div className="grid gap-8 lg:grid-cols-[1fr_1.1fr] items-start">
|
|
4641
|
+
<div>
|
|
4642
|
+
<h2 className="font-display font-black text-[clamp(2rem,4.5vw,3.8rem)] leading-[1.05] tracking-tight text-[var(--local-text)]" data-jp-field="title">{data.title}</h2>
|
|
4643
|
+
<p className="mt-5 text-[var(--local-text-muted)] max-w-lg" data-jp-field="description">{data.description}</p>
|
|
4644
|
+
<img src={data.image?.url} alt={data.image?.alt || ''} className="mt-8 w-full h-[360px] object-cover rounded-[var(--local-radius-lg)] border border-[var(--local-border)]" />
|
|
4645
|
+
</div>
|
|
4646
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
4647
|
+
{data.products.map((item, idx) => (
|
|
4648
|
+
<Card
|
|
4649
|
+
key={item.id || 'legacy-' + idx}
|
|
4650
|
+
className={'border-[var(--local-border)] bg-[var(--local-surface)] rounded-[var(--local-radius-lg)] ' + (idx === 0 ? 'md:col-span-2' : '')}
|
|
4651
|
+
data-jp-item-id={item.id || 'legacy-' + idx}
|
|
4652
|
+
data-jp-item-field="products"
|
|
4653
|
+
>
|
|
4654
|
+
<CardContent className="p-6">
|
|
4655
|
+
<h3 className="font-display font-bold text-[1.2rem] text-[var(--local-text)]">{item.title}</h3>
|
|
4656
|
+
<p className="mt-2 text-sm text-[var(--local-text-muted)]">{item.body}</p>
|
|
4657
|
+
</CardContent>
|
|
4658
|
+
</Card>
|
|
4659
|
+
))}
|
|
4660
|
+
</div>
|
|
4661
|
+
</div>
|
|
4662
|
+
</div>
|
|
4663
|
+
</section>
|
|
4664
|
+
);
|
|
4665
|
+
|
|
4666
|
+
|
|
4667
|
+
END_OF_FILE_CONTENT
|
|
4668
|
+
echo "Creating src/components/cuisine-section/index.ts..."
|
|
4669
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/cuisine-section/index.ts"
|
|
4670
|
+
export { CuisineSectionComponent } from './View';
|
|
4671
|
+
export { CuisineSectionSchema } from './schema';
|
|
4672
|
+
export type { CuisineSectionData, CuisineSectionSettings } from './types';
|
|
4673
|
+
|
|
4674
|
+
|
|
4675
|
+
END_OF_FILE_CONTENT
|
|
4676
|
+
echo "Creating src/components/cuisine-section/schema.ts..."
|
|
4677
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/cuisine-section/schema.ts"
|
|
4678
|
+
import { z } from 'zod';
|
|
4679
|
+
import { BaseSectionData, BaseArrayItem, ImageSelectionSchema } from '@/lib/base-schemas';
|
|
4680
|
+
|
|
4681
|
+
const ProductSchema = BaseArrayItem.extend({
|
|
4682
|
+
title: z.string().describe('ui:text'),
|
|
4683
|
+
body: z.string().describe('ui:textarea'),
|
|
4684
|
+
});
|
|
4685
|
+
|
|
4686
|
+
export const CuisineSectionSchema = BaseSectionData.extend({
|
|
4687
|
+
label: z.string().optional().describe('ui:text'),
|
|
4688
|
+
title: z.string().describe('ui:text'),
|
|
4689
|
+
description: z.string().describe('ui:textarea'),
|
|
4690
|
+
image: ImageSelectionSchema.optional().default({ url: '', alt: '' }),
|
|
4691
|
+
products: z.array(ProductSchema).describe('ui:list'),
|
|
4692
|
+
});
|
|
4693
|
+
|
|
4694
|
+
|
|
4695
|
+
END_OF_FILE_CONTENT
|
|
4696
|
+
echo "Creating src/components/cuisine-section/types.ts..."
|
|
4697
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/cuisine-section/types.ts"
|
|
4698
|
+
import { z } from 'zod';
|
|
4699
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
4700
|
+
import { CuisineSectionSchema } from './schema';
|
|
4701
|
+
|
|
4702
|
+
export type CuisineSectionData = z.infer<typeof CuisineSectionSchema>;
|
|
4703
|
+
export type CuisineSectionSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
4704
|
+
|
|
4705
|
+
|
|
4273
4706
|
END_OF_FILE_CONTENT
|
|
4274
4707
|
mkdir -p "src/components/design-system"
|
|
4275
4708
|
echo "Creating src/components/design-system/View.tsx..."
|
|
@@ -5128,6 +5561,111 @@ import { DevexSchema } from './schema';
|
|
|
5128
5561
|
export type DevexData = z.infer<typeof DevexSchema>;
|
|
5129
5562
|
export type DevexSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
5130
5563
|
|
|
5564
|
+
END_OF_FILE_CONTENT
|
|
5565
|
+
mkdir -p "src/components/docs-layout"
|
|
5566
|
+
mkdir -p "src/components/experiences-section"
|
|
5567
|
+
echo "Creating src/components/experiences-section/View.tsx..."
|
|
5568
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/experiences-section/View.tsx"
|
|
5569
|
+
// Layout: Hero=B (BENTO GRID), Features=A (BENTO)
|
|
5570
|
+
import React from 'react';
|
|
5571
|
+
import { ArrowRight } from 'lucide-react';
|
|
5572
|
+
import { Button } from '@/components/ui/button';
|
|
5573
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
5574
|
+
import type { ExperiencesSectionData, ExperiencesSectionSettings } from './types';
|
|
5575
|
+
|
|
5576
|
+
export const ExperiencesSectionComponent: React.FC<{ data: ExperiencesSectionData; settings: ExperiencesSectionSettings }> = ({ data }) => (
|
|
5577
|
+
<section
|
|
5578
|
+
style={{
|
|
5579
|
+
'--local-bg': 'var(--card)',
|
|
5580
|
+
'--local-text': 'var(--foreground)',
|
|
5581
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
5582
|
+
'--local-primary': 'var(--primary)',
|
|
5583
|
+
'--local-primary-foreground': 'var(--primary-foreground)',
|
|
5584
|
+
'--local-accent': 'var(--accent)',
|
|
5585
|
+
'--local-border': 'var(--border)',
|
|
5586
|
+
'--local-surface': 'var(--background)',
|
|
5587
|
+
'--local-radius-md': 'var(--theme-radius-md)',
|
|
5588
|
+
'--local-radius-lg': 'var(--theme-radius-lg)',
|
|
5589
|
+
} as React.CSSProperties}
|
|
5590
|
+
className="relative z-0 py-24 bg-[var(--local-bg)]"
|
|
5591
|
+
>
|
|
5592
|
+
<div className="max-w-[1200px] mx-auto px-8">
|
|
5593
|
+
{data.label && (
|
|
5594
|
+
<div className="jp-section-label inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase text-[var(--local-accent)] mb-4" data-jp-field="label">
|
|
5595
|
+
<span className="w-5 h-px bg-[var(--local-primary)]" />
|
|
5596
|
+
{data.label}
|
|
5597
|
+
</div>
|
|
5598
|
+
)}
|
|
5599
|
+
<div className="flex flex-col lg:flex-row lg:items-end lg:justify-between gap-6">
|
|
5600
|
+
<div>
|
|
5601
|
+
<h2 className="font-display font-black text-[clamp(2rem,4.5vw,3.8rem)] leading-[1.05] tracking-tight text-[var(--local-text)]" data-jp-field="title">{data.title}</h2>
|
|
5602
|
+
<p className="mt-4 max-w-2xl text-[var(--local-text-muted)]" data-jp-field="description">{data.description}</p>
|
|
5603
|
+
</div>
|
|
5604
|
+
<Button asChild variant="default" className="bg-[var(--local-primary)] text-[var(--local-primary-foreground)] hover:opacity-90 rounded-[var(--local-radius-md)]">
|
|
5605
|
+
<a href={data.primaryCta.href}>{data.primaryCta.label} <ArrowRight className="h-4 w-4" /></a>
|
|
5606
|
+
</Button>
|
|
5607
|
+
</div>
|
|
5608
|
+
<div className="mt-10 grid gap-5 md:grid-cols-2 xl:grid-cols-3">
|
|
5609
|
+
{data.items.map((item, idx) => (
|
|
5610
|
+
<Card
|
|
5611
|
+
key={item.id || 'legacy-' + idx}
|
|
5612
|
+
className={'border-[var(--local-border)] bg-[var(--local-surface)] rounded-[var(--local-radius-lg)] ' + (idx === 0 ? 'xl:col-span-2' : '')}
|
|
5613
|
+
data-jp-item-id={item.id || 'legacy-' + idx}
|
|
5614
|
+
data-jp-item-field="items"
|
|
5615
|
+
>
|
|
5616
|
+
<CardContent className="p-6">
|
|
5617
|
+
<h3 className="font-display font-bold text-[1.2rem] text-[var(--local-text)]">{item.title}</h3>
|
|
5618
|
+
<p className="mt-2 text-sm text-[var(--local-text-muted)]">{item.body}</p>
|
|
5619
|
+
<p className="mt-4 text-sm text-[var(--local-text)]">{item.details}</p>
|
|
5620
|
+
</CardContent>
|
|
5621
|
+
</Card>
|
|
5622
|
+
))}
|
|
5623
|
+
</div>
|
|
5624
|
+
</div>
|
|
5625
|
+
</section>
|
|
5626
|
+
);
|
|
5627
|
+
|
|
5628
|
+
|
|
5629
|
+
END_OF_FILE_CONTENT
|
|
5630
|
+
echo "Creating src/components/experiences-section/index.ts..."
|
|
5631
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/experiences-section/index.ts"
|
|
5632
|
+
export { ExperiencesSectionComponent } from './View';
|
|
5633
|
+
export { ExperiencesSectionSchema } from './schema';
|
|
5634
|
+
export type { ExperiencesSectionData, ExperiencesSectionSettings } from './types';
|
|
5635
|
+
|
|
5636
|
+
|
|
5637
|
+
END_OF_FILE_CONTENT
|
|
5638
|
+
echo "Creating src/components/experiences-section/schema.ts..."
|
|
5639
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/experiences-section/schema.ts"
|
|
5640
|
+
import { z } from 'zod';
|
|
5641
|
+
import { BaseSectionData, BaseArrayItem, CtaSchema } from '@/lib/base-schemas';
|
|
5642
|
+
|
|
5643
|
+
const ExperienceSchema = BaseArrayItem.extend({
|
|
5644
|
+
title: z.string().describe('ui:text'),
|
|
5645
|
+
body: z.string().describe('ui:textarea'),
|
|
5646
|
+
details: z.string().describe('ui:textarea'),
|
|
5647
|
+
});
|
|
5648
|
+
|
|
5649
|
+
export const ExperiencesSectionSchema = BaseSectionData.extend({
|
|
5650
|
+
label: z.string().optional().describe('ui:text'),
|
|
5651
|
+
title: z.string().describe('ui:text'),
|
|
5652
|
+
description: z.string().describe('ui:textarea'),
|
|
5653
|
+
items: z.array(ExperienceSchema).describe('ui:list'),
|
|
5654
|
+
primaryCta: CtaSchema,
|
|
5655
|
+
});
|
|
5656
|
+
|
|
5657
|
+
|
|
5658
|
+
END_OF_FILE_CONTENT
|
|
5659
|
+
echo "Creating src/components/experiences-section/types.ts..."
|
|
5660
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/experiences-section/types.ts"
|
|
5661
|
+
import { z } from 'zod';
|
|
5662
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
5663
|
+
import { ExperiencesSectionSchema } from './schema';
|
|
5664
|
+
|
|
5665
|
+
export type ExperiencesSectionData = z.infer<typeof ExperiencesSectionSchema>;
|
|
5666
|
+
export type ExperiencesSectionSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
5667
|
+
|
|
5668
|
+
|
|
5131
5669
|
END_OF_FILE_CONTENT
|
|
5132
5670
|
mkdir -p "src/components/feature-grid"
|
|
5133
5671
|
echo "Creating src/components/feature-grid/View.tsx..."
|
|
@@ -5302,47 +5840,188 @@ export type FeatureGridData = z.infer<typeof FeatureGridSchema>;
|
|
|
5302
5840
|
export type FeatureGridSettings = z.infer<typeof FeatureGridSettingsSchema>;
|
|
5303
5841
|
|
|
5304
5842
|
END_OF_FILE_CONTENT
|
|
5305
|
-
mkdir -p "src/components/
|
|
5306
|
-
echo "Creating src/components/
|
|
5307
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/
|
|
5308
|
-
|
|
5309
|
-
import
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
}
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5843
|
+
mkdir -p "src/components/features-overview"
|
|
5844
|
+
echo "Creating src/components/features-overview/View.tsx..."
|
|
5845
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/features-overview/View.tsx"
|
|
5846
|
+
// Layout: Hero=N/A, Features=BENTO (irregular grid)
|
|
5847
|
+
import React from 'react';
|
|
5848
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
5849
|
+
import { Leaf, Mountain, Utensils } from 'lucide-react';
|
|
5850
|
+
import type { FeaturesOverviewData, FeaturesOverviewSettings } from './types';
|
|
5851
|
+
|
|
5852
|
+
export const FeaturesOverview: React.FC<{ data: FeaturesOverviewData; settings: FeaturesOverviewSettings }> = ({ data }) => {
|
|
5853
|
+
const getIcon = (iconName: string) => {
|
|
5854
|
+
switch (iconName) {
|
|
5855
|
+
case 'leaf': return <Leaf className="w-6 h-6" />;
|
|
5856
|
+
case 'mountain': return <Mountain className="w-6 h-6" />;
|
|
5857
|
+
case 'utensils': return <Utensils className="w-6 h-6" />;
|
|
5858
|
+
default: return <Leaf className="w-6 h-6" />;
|
|
5859
|
+
}
|
|
5860
|
+
};
|
|
5861
|
+
|
|
5862
|
+
return (
|
|
5863
|
+
<section
|
|
5864
|
+
style={{
|
|
5865
|
+
'--local-bg': 'var(--background)',
|
|
5866
|
+
'--local-text': 'var(--foreground)',
|
|
5867
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
5868
|
+
'--local-primary': 'var(--primary)',
|
|
5869
|
+
'--local-accent': 'var(--accent)',
|
|
5870
|
+
'--local-border': 'var(--border)',
|
|
5871
|
+
'--local-surface': 'var(--card)',
|
|
5872
|
+
'--local-radius-lg': 'var(--theme-radius-lg)',
|
|
5873
|
+
'--local-radius-md': 'var(--theme-radius-md)',
|
|
5874
|
+
} as React.CSSProperties}
|
|
5875
|
+
className="relative z-0 py-28 bg-[var(--local-bg)]"
|
|
5876
|
+
>
|
|
5877
|
+
<div className="max-w-[var(--theme-spacing-container-max)] mx-auto px-6">
|
|
5878
|
+
{/* Header */}
|
|
5879
|
+
<div className="text-center mb-16">
|
|
5880
|
+
{data.label && (
|
|
5881
|
+
<div className="inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase tracking-[0.12em] text-[var(--local-accent)] mb-4" data-jp-field="label">
|
|
5882
|
+
<span className="w-5 h-px bg-[var(--local-primary)]" />
|
|
5883
|
+
{data.label}
|
|
5884
|
+
</div>
|
|
5885
|
+
)}
|
|
5886
|
+
<h2 className="font-display font-black text-[clamp(2rem,4.5vw,3.8rem)] leading-[1.05] tracking-tight text-[var(--local-text)] mb-4" data-jp-field="title">
|
|
5887
|
+
{data.title}
|
|
5888
|
+
</h2>
|
|
5889
|
+
{data.description && (
|
|
5890
|
+
<p className="text-lg text-[var(--local-text-muted)] max-w-2xl mx-auto" data-jp-field="description">
|
|
5891
|
+
{data.description}
|
|
5892
|
+
</p>
|
|
5893
|
+
)}
|
|
5894
|
+
</div>
|
|
5895
|
+
|
|
5896
|
+
{/* Bento Grid */}
|
|
5897
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 auto-rows-fr">
|
|
5898
|
+
{data.features.map((feature, idx) => (
|
|
5899
|
+
<Card
|
|
5900
|
+
key={feature.id || `legacy-${idx}`}
|
|
5901
|
+
className={`
|
|
5902
|
+
bg-[var(--local-surface)] border-[var(--local-border)] rounded-[var(--local-radius-lg)]
|
|
5903
|
+
overflow-hidden group hover:shadow-lg transition-all duration-300
|
|
5904
|
+
${idx === 0 ? 'lg:col-span-2' : ''}
|
|
5905
|
+
${idx === 1 ? 'lg:row-span-2' : ''}
|
|
5906
|
+
`}
|
|
5907
|
+
data-jp-item-id={feature.id || `legacy-${idx}`}
|
|
5908
|
+
data-jp-item-field="features"
|
|
5909
|
+
>
|
|
5910
|
+
{feature.image?.url && (
|
|
5911
|
+
<div className="relative h-48 overflow-hidden">
|
|
5912
|
+
<img
|
|
5913
|
+
src={feature.image.url}
|
|
5914
|
+
alt={feature.image.alt}
|
|
5915
|
+
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
|
|
5916
|
+
/>
|
|
5917
|
+
<div className="absolute inset-0 bg-gradient-to-t from-black/50 via-transparent to-transparent" />
|
|
5918
|
+
{feature.icon && (
|
|
5919
|
+
<div className="absolute top-4 left-4 p-3 bg-[var(--local-primary)] rounded-[var(--local-radius-md)] text-white">
|
|
5920
|
+
{getIcon(feature.icon)}
|
|
5921
|
+
</div>
|
|
5922
|
+
)}
|
|
5923
|
+
</div>
|
|
5924
|
+
)}
|
|
5925
|
+
|
|
5926
|
+
<CardContent className="p-6">
|
|
5927
|
+
<h3 className="font-display font-bold text-xl text-[var(--local-text)] mb-3">
|
|
5928
|
+
{feature.title}
|
|
5929
|
+
</h3>
|
|
5930
|
+
<p className="text-[var(--local-text-muted)] leading-relaxed">
|
|
5931
|
+
{feature.description}
|
|
5932
|
+
</p>
|
|
5933
|
+
</CardContent>
|
|
5934
|
+
</Card>
|
|
5935
|
+
))}
|
|
5936
|
+
</div>
|
|
5937
|
+
</div>
|
|
5938
|
+
</section>
|
|
5939
|
+
);
|
|
5940
|
+
};
|
|
5941
|
+
|
|
5942
|
+
|
|
5943
|
+
END_OF_FILE_CONTENT
|
|
5944
|
+
echo "Creating src/components/features-overview/index.ts..."
|
|
5945
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/features-overview/index.ts"
|
|
5946
|
+
export { FeaturesOverview } from './View';
|
|
5947
|
+
export { FeaturesOverviewSchema } from './schema';
|
|
5948
|
+
export type { FeaturesOverviewData, FeaturesOverviewSettings } from './types';
|
|
5949
|
+
|
|
5950
|
+
|
|
5951
|
+
END_OF_FILE_CONTENT
|
|
5952
|
+
echo "Creating src/components/features-overview/schema.ts..."
|
|
5953
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/features-overview/schema.ts"
|
|
5954
|
+
import { z } from 'zod';
|
|
5955
|
+
import { BaseSectionData, BaseArrayItem, ImageSelectionSchema } from '@/lib/base-schemas';
|
|
5956
|
+
|
|
5957
|
+
const FeatureItem = BaseArrayItem.extend({
|
|
5958
|
+
title: z.string().describe('ui:text'),
|
|
5959
|
+
description: z.string().describe('ui:textarea'),
|
|
5960
|
+
icon: z.string().optional().describe('ui:text'),
|
|
5961
|
+
image: ImageSelectionSchema,
|
|
5962
|
+
});
|
|
5963
|
+
|
|
5964
|
+
export const FeaturesOverviewSchema = BaseSectionData.extend({
|
|
5965
|
+
label: z.string().optional().describe('ui:text'),
|
|
5966
|
+
title: z.string().describe('ui:text'),
|
|
5967
|
+
description: z.string().optional().describe('ui:textarea'),
|
|
5968
|
+
features: z.array(FeatureItem).describe('ui:list'),
|
|
5969
|
+
});
|
|
5970
|
+
|
|
5971
|
+
|
|
5972
|
+
END_OF_FILE_CONTENT
|
|
5973
|
+
echo "Creating src/components/features-overview/types.ts..."
|
|
5974
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/features-overview/types.ts"
|
|
5975
|
+
import { z } from 'zod';
|
|
5976
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
5977
|
+
import { FeaturesOverviewSchema } from './schema';
|
|
5978
|
+
|
|
5979
|
+
export type FeaturesOverviewData = z.infer<typeof FeaturesOverviewSchema>;
|
|
5980
|
+
export type FeaturesOverviewSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
5981
|
+
|
|
5982
|
+
|
|
5983
|
+
END_OF_FILE_CONTENT
|
|
5984
|
+
mkdir -p "src/components/footer"
|
|
5985
|
+
echo "Creating src/components/footer/View.tsx..."
|
|
5986
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/footer/View.tsx"
|
|
5987
|
+
import { OlonMark } from '@/components/OlonWordmark';
|
|
5988
|
+
import type { FooterData, FooterSettings } from './types';
|
|
5989
|
+
|
|
5990
|
+
interface FooterViewProps {
|
|
5991
|
+
data: FooterData;
|
|
5992
|
+
settings?: FooterSettings;
|
|
5993
|
+
}
|
|
5994
|
+
|
|
5995
|
+
export function Footer({ data, settings }: FooterViewProps) {
|
|
5996
|
+
const showLogo = settings?.showLogo ?? true;
|
|
5997
|
+
const links = data.links ?? [];
|
|
5998
|
+
|
|
5999
|
+
return (
|
|
6000
|
+
<footer className="border-t border-border px-6 py-8">
|
|
6001
|
+
<div className="max-w-6xl px-6 mx-auto flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
|
|
6002
|
+
<div className="flex items-center gap-6">
|
|
6003
|
+
{showLogo && (
|
|
6004
|
+
<div className="flex items-center gap-2.5">
|
|
6005
|
+
<OlonMark size={18} />
|
|
6006
|
+
<span className="text-base font-display text-foreground tracking-[-0.02em]">
|
|
6007
|
+
{data.brandText}
|
|
6008
|
+
</span>
|
|
6009
|
+
</div>
|
|
6010
|
+
)}
|
|
6011
|
+
{links.length > 0 && (
|
|
6012
|
+
<div className="flex items-center gap-4">
|
|
6013
|
+
{links.map((link) => (
|
|
6014
|
+
<a
|
|
6015
|
+
key={link.label}
|
|
6016
|
+
href={link.href}
|
|
6017
|
+
className="text-[12px] text-muted-foreground hover:text-foreground transition-colors"
|
|
6018
|
+
>
|
|
6019
|
+
{link.label}
|
|
6020
|
+
</a>
|
|
6021
|
+
))}
|
|
6022
|
+
{data.designSystemHref && (
|
|
6023
|
+
<a
|
|
6024
|
+
href={data.designSystemHref}
|
|
5346
6025
|
className="text-[12px] text-muted-foreground hover:text-foreground transition-colors"
|
|
5347
6026
|
>
|
|
5348
6027
|
Design System
|
|
@@ -5374,7 +6053,7 @@ import { z } from 'zod';
|
|
|
5374
6053
|
export const FooterSchema = z.object({
|
|
5375
6054
|
brandText: z.string().describe('ui:text'),
|
|
5376
6055
|
copyright: z.string().describe('ui:text'),
|
|
5377
|
-
|
|
6056
|
+
links: z.array(z.object({
|
|
5378
6057
|
label: z.string().describe('ui:text'),
|
|
5379
6058
|
href: z.string().describe('ui:text'),
|
|
5380
6059
|
})).optional().describe('ui:list'),
|
|
@@ -5564,7 +6243,7 @@ export function Header({ data, settings, menu }: HeaderViewProps) {
|
|
|
5564
6243
|
const isSticky = settings?.sticky ?? true;
|
|
5565
6244
|
const navRef = useRef<HTMLElement>(null);
|
|
5566
6245
|
|
|
5567
|
-
const linksField = data.
|
|
6246
|
+
const linksField = data.links as unknown;
|
|
5568
6247
|
const rawLinks = Array.isArray(linksField) ? linksField : [];
|
|
5569
6248
|
const menuItems = Array.isArray(menu) ? (menu as unknown[]) : [];
|
|
5570
6249
|
// If tenant explicitly uses a JSON ref for links, resolve from menu config.
|
|
@@ -5846,7 +6525,6 @@ export function Header({ data, settings, menu }: HeaderViewProps) {
|
|
|
5846
6525
|
}
|
|
5847
6526
|
|
|
5848
6527
|
END_OF_FILE_CONTENT
|
|
5849
|
-
# SKIP: src/components/header/View.tsx:Zone.Identifier is binary and cannot be embedded as text.
|
|
5850
6528
|
echo "Creating src/components/header/View_.tsx..."
|
|
5851
6529
|
cat << 'END_OF_FILE_CONTENT' > "src/components/header/View_.tsx"
|
|
5852
6530
|
import React, { useState } from 'react';
|
|
@@ -5990,7 +6668,6 @@ export * from './View';
|
|
|
5990
6668
|
export * from './schema';
|
|
5991
6669
|
export * from './types';
|
|
5992
6670
|
END_OF_FILE_CONTENT
|
|
5993
|
-
# SKIP: src/components/header/index.ts:Zone.Identifier is binary and cannot be embedded as text.
|
|
5994
6671
|
echo "Creating src/components/header/schema.ts..."
|
|
5995
6672
|
cat << 'END_OF_FILE_CONTENT' > "src/components/header/schema.ts"
|
|
5996
6673
|
import { z } from 'zod';
|
|
@@ -6007,7 +6684,7 @@ export const HeaderSchema = z.object({
|
|
|
6007
6684
|
signinHref: z.string().optional().describe('ui:text'),
|
|
6008
6685
|
ctaHref: z.string().optional().describe('ui:text'),
|
|
6009
6686
|
ctaLabel: z.string().optional().describe('ui:text'),
|
|
6010
|
-
|
|
6687
|
+
links: z.array(z.object({
|
|
6011
6688
|
label: z.string().describe('ui:text'),
|
|
6012
6689
|
href: z.string().describe('ui:text'),
|
|
6013
6690
|
isCta: z.boolean().default(false).describe('ui:checkbox'),
|
|
@@ -6023,7 +6700,6 @@ export const HeaderSettingsSchema = z.object({
|
|
|
6023
6700
|
sticky: z.boolean().default(true).describe('ui:checkbox'),
|
|
6024
6701
|
});
|
|
6025
6702
|
END_OF_FILE_CONTENT
|
|
6026
|
-
# SKIP: src/components/header/schema.ts:Zone.Identifier is binary and cannot be embedded as text.
|
|
6027
6703
|
echo "Creating src/components/header/types.ts..."
|
|
6028
6704
|
cat << 'END_OF_FILE_CONTENT' > "src/components/header/types.ts"
|
|
6029
6705
|
import { z } from 'zod';
|
|
@@ -6043,9 +6719,139 @@ export type HeaderData = z.infer<typeof HeaderSchema>;
|
|
|
6043
6719
|
*/
|
|
6044
6720
|
export type HeaderSettings = z.infer<typeof HeaderSettingsSchema>;
|
|
6045
6721
|
END_OF_FILE_CONTENT
|
|
6046
|
-
# SKIP: src/components/header/types.ts:Zone.Identifier is binary and cannot be embedded as text.
|
|
6047
6722
|
mkdir -p "src/components/hero"
|
|
6048
|
-
|
|
6723
|
+
mkdir -p "src/components/hero-section"
|
|
6724
|
+
echo "Creating src/components/hero-section/View.tsx..."
|
|
6725
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/hero-section/View.tsx"
|
|
6726
|
+
// Layout: Hero=FULLSCREEN CINEMATIC, Features=N/A
|
|
6727
|
+
import React from 'react';
|
|
6728
|
+
import { Button } from '@/components/ui/button';
|
|
6729
|
+
import type { HeroSectionData, HeroSectionSettings } from './types';
|
|
6730
|
+
|
|
6731
|
+
export const HeroSection: React.FC<{ data: HeroSectionData; settings: HeroSectionSettings }> = ({ data }) => {
|
|
6732
|
+
return (
|
|
6733
|
+
<section
|
|
6734
|
+
style={{
|
|
6735
|
+
'--local-bg': 'var(--background)',
|
|
6736
|
+
'--local-text': 'var(--foreground)',
|
|
6737
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
6738
|
+
'--local-primary': 'var(--primary)',
|
|
6739
|
+
'--local-primary-foreground': 'var(--primary-foreground)',
|
|
6740
|
+
'--local-accent': 'var(--accent)',
|
|
6741
|
+
'--local-border': 'var(--border)',
|
|
6742
|
+
'--local-radius-md': 'var(--theme-radius-md)',
|
|
6743
|
+
} as React.CSSProperties}
|
|
6744
|
+
className="relative z-0 min-h-screen flex items-center justify-center bg-[var(--local-bg)] overflow-hidden"
|
|
6745
|
+
>
|
|
6746
|
+
{/* Background Image */}
|
|
6747
|
+
{data.heroImage?.url && (
|
|
6748
|
+
<div
|
|
6749
|
+
className="absolute inset-0 bg-cover bg-center bg-no-repeat"
|
|
6750
|
+
style={{ backgroundImage: `url(${data.heroImage.url})` }}
|
|
6751
|
+
>
|
|
6752
|
+
<div className="absolute inset-0 bg-gradient-to-b from-black/40 via-black/20 to-black/60" />
|
|
6753
|
+
</div>
|
|
6754
|
+
)}
|
|
6755
|
+
|
|
6756
|
+
{/* Decorative Background */}
|
|
6757
|
+
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_50%_0%,color-mix(in_oklch,var(--local-accent)_15%,transparent)_35%,transparent_70%)] pointer-events-none" />
|
|
6758
|
+
|
|
6759
|
+
{/* Content */}
|
|
6760
|
+
<div className="relative z-10 max-w-4xl mx-auto px-6 text-center">
|
|
6761
|
+
{data.label && (
|
|
6762
|
+
<div className="inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase tracking-[0.12em] text-white/90 mb-6 jp-animate-in" data-jp-field="label">
|
|
6763
|
+
<span className="w-8 h-px bg-white/60" />
|
|
6764
|
+
{data.label}
|
|
6765
|
+
<span className="w-8 h-px bg-white/60" />
|
|
6766
|
+
</div>
|
|
6767
|
+
)}
|
|
6768
|
+
|
|
6769
|
+
<h1 className="font-display font-black text-[clamp(3rem,6vw,5.5rem)] leading-[1.0] tracking-tight text-white mb-6 jp-animate-in jp-d1" data-jp-field="title">
|
|
6770
|
+
{data.title}
|
|
6771
|
+
{data.titleHighlight && (
|
|
6772
|
+
<>
|
|
6773
|
+
{' '}
|
|
6774
|
+
<em className="not-italic bg-gradient-to-br from-[var(--local-accent)] to-orange-300 bg-clip-text text-transparent" data-jp-field="titleHighlight">
|
|
6775
|
+
{data.titleHighlight}
|
|
6776
|
+
</em>
|
|
6777
|
+
</>
|
|
6778
|
+
)}
|
|
6779
|
+
</h1>
|
|
6780
|
+
|
|
6781
|
+
<p className="text-xl leading-relaxed text-white/90 max-w-2xl mx-auto mb-8 jp-animate-in jp-d2" data-jp-field="description">
|
|
6782
|
+
{data.description}
|
|
6783
|
+
</p>
|
|
6784
|
+
|
|
6785
|
+
<div className="flex flex-col sm:flex-row gap-4 justify-center jp-animate-in jp-d3">
|
|
6786
|
+
<Button
|
|
6787
|
+
asChild
|
|
6788
|
+
variant="default"
|
|
6789
|
+
size="lg"
|
|
6790
|
+
className="bg-[var(--local-primary)] text-[var(--local-primary-foreground)] hover:opacity-90 px-8 py-4 text-base font-semibold rounded-[var(--local-radius-md)]"
|
|
6791
|
+
>
|
|
6792
|
+
<a href={data.primaryCta.href}>{data.primaryCta.label}</a>
|
|
6793
|
+
</Button>
|
|
6794
|
+
|
|
6795
|
+
{data.secondaryCta && (
|
|
6796
|
+
<Button
|
|
6797
|
+
asChild
|
|
6798
|
+
variant="outline"
|
|
6799
|
+
size="lg"
|
|
6800
|
+
className="border-white/30 text-white hover:bg-white/10 px-8 py-4 text-base font-semibold rounded-[var(--local-radius-md)]"
|
|
6801
|
+
>
|
|
6802
|
+
<a href={data.secondaryCta.href}>{data.secondaryCta.label}</a>
|
|
6803
|
+
</Button>
|
|
6804
|
+
)}
|
|
6805
|
+
</div>
|
|
6806
|
+
</div>
|
|
6807
|
+
|
|
6808
|
+
{/* Scroll Indicator */}
|
|
6809
|
+
<div className="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2 text-white/70">
|
|
6810
|
+
<span className="text-xs uppercase tracking-widest">Scopri di più</span>
|
|
6811
|
+
<div className="w-px h-12 bg-gradient-to-b from-white/40 to-transparent" />
|
|
6812
|
+
</div>
|
|
6813
|
+
</section>
|
|
6814
|
+
);
|
|
6815
|
+
};
|
|
6816
|
+
|
|
6817
|
+
|
|
6818
|
+
END_OF_FILE_CONTENT
|
|
6819
|
+
echo "Creating src/components/hero-section/index.ts..."
|
|
6820
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/hero-section/index.ts"
|
|
6821
|
+
export { HeroSection } from './View';
|
|
6822
|
+
export { HeroSectionSchema } from './schema';
|
|
6823
|
+
export type { HeroSectionData, HeroSectionSettings } from './types';
|
|
6824
|
+
|
|
6825
|
+
|
|
6826
|
+
END_OF_FILE_CONTENT
|
|
6827
|
+
echo "Creating src/components/hero-section/schema.ts..."
|
|
6828
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/hero-section/schema.ts"
|
|
6829
|
+
import { z } from 'zod';
|
|
6830
|
+
import { BaseSectionData, CtaSchema, ImageSelectionSchema } from '@/lib/base-schemas';
|
|
6831
|
+
|
|
6832
|
+
export const HeroSectionSchema = BaseSectionData.extend({
|
|
6833
|
+
label: z.string().optional().describe('ui:text'),
|
|
6834
|
+
title: z.string().describe('ui:text'),
|
|
6835
|
+
titleHighlight: z.string().optional().describe('ui:text'),
|
|
6836
|
+
description: z.string().describe('ui:textarea'),
|
|
6837
|
+
primaryCta: CtaSchema,
|
|
6838
|
+
secondaryCta: CtaSchema.optional(),
|
|
6839
|
+
heroImage: ImageSelectionSchema,
|
|
6840
|
+
});
|
|
6841
|
+
|
|
6842
|
+
|
|
6843
|
+
END_OF_FILE_CONTENT
|
|
6844
|
+
echo "Creating src/components/hero-section/types.ts..."
|
|
6845
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/hero-section/types.ts"
|
|
6846
|
+
import { z } from 'zod';
|
|
6847
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
6848
|
+
import { HeroSectionSchema } from './schema';
|
|
6849
|
+
|
|
6850
|
+
export type HeroSectionData = z.infer<typeof HeroSectionSchema>;
|
|
6851
|
+
export type HeroSectionSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
6852
|
+
|
|
6853
|
+
|
|
6854
|
+
END_OF_FILE_CONTENT
|
|
6049
6855
|
echo "Creating src/components/hero/RadialBackground.tsx..."
|
|
6050
6856
|
cat << 'END_OF_FILE_CONTENT' > "src/components/hero/RadialBackground.tsx"
|
|
6051
6857
|
import { useEffect, useRef, useState } from 'react';
|
|
@@ -6413,6 +7219,101 @@ import { HeroSchema, HeroSettingsSchema } from './schema';
|
|
|
6413
7219
|
export type HeroData = z.infer<typeof HeroSchema>;
|
|
6414
7220
|
export type HeroSettings = z.infer<typeof HeroSettingsSchema>;
|
|
6415
7221
|
|
|
7222
|
+
END_OF_FILE_CONTENT
|
|
7223
|
+
mkdir -p "src/components/hospitality-section"
|
|
7224
|
+
echo "Creating src/components/hospitality-section/View.tsx..."
|
|
7225
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/hospitality-section/View.tsx"
|
|
7226
|
+
// Layout: Hero=A (SPLIT 60/40), Features=A (BENTO)
|
|
7227
|
+
import React from 'react';
|
|
7228
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
7229
|
+
import type { HospitalitySectionData, HospitalitySectionSettings } from './types';
|
|
7230
|
+
|
|
7231
|
+
export const HospitalitySectionComponent: React.FC<{ data: HospitalitySectionData; settings: HospitalitySectionSettings }> = ({ data }) => (
|
|
7232
|
+
<section
|
|
7233
|
+
style={{
|
|
7234
|
+
'--local-bg': 'var(--background)',
|
|
7235
|
+
'--local-text': 'var(--foreground)',
|
|
7236
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
7237
|
+
'--local-primary': 'var(--primary)',
|
|
7238
|
+
'--local-accent': 'var(--accent)',
|
|
7239
|
+
'--local-border': 'var(--border)',
|
|
7240
|
+
'--local-surface': 'var(--card)',
|
|
7241
|
+
'--local-radius-md': 'var(--theme-radius-md)',
|
|
7242
|
+
'--local-radius-lg': 'var(--theme-radius-lg)',
|
|
7243
|
+
} as React.CSSProperties}
|
|
7244
|
+
className="relative z-0 py-24"
|
|
7245
|
+
>
|
|
7246
|
+
<div className="max-w-[1200px] mx-auto px-8 grid gap-10 lg:grid-cols-[0.9fr_1.1fr] items-center">
|
|
7247
|
+
<img src={data.image?.url} alt={data.image?.alt || ''} className="w-full h-[520px] object-cover rounded-[var(--local-radius-lg)] border border-[var(--local-border)]" />
|
|
7248
|
+
<div>
|
|
7249
|
+
{data.label && (
|
|
7250
|
+
<div className="jp-section-label inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase text-[var(--local-accent)] mb-4" data-jp-field="label">
|
|
7251
|
+
<span className="w-5 h-px bg-[var(--local-primary)]" />
|
|
7252
|
+
{data.label}
|
|
7253
|
+
</div>
|
|
7254
|
+
)}
|
|
7255
|
+
<h2 className="font-display font-black text-[clamp(2rem,4.5vw,3.8rem)] leading-[1.05] tracking-tight text-[var(--local-text)]" data-jp-field="title">{data.title}</h2>
|
|
7256
|
+
<p className="mt-5 max-w-xl text-[var(--local-text-muted)]" data-jp-field="description">{data.description}</p>
|
|
7257
|
+
<div className="grid md:grid-cols-2 gap-4 mt-8">
|
|
7258
|
+
{data.items.map((item, idx) => (
|
|
7259
|
+
<Card
|
|
7260
|
+
key={item.id || 'legacy-' + idx}
|
|
7261
|
+
className="rounded-[var(--local-radius-md)] border-[var(--local-border)] bg-[var(--local-surface)]"
|
|
7262
|
+
data-jp-item-id={item.id || 'legacy-' + idx}
|
|
7263
|
+
data-jp-item-field="items"
|
|
7264
|
+
>
|
|
7265
|
+
<CardContent className="p-5">
|
|
7266
|
+
<h3 className="font-display font-bold text-[1.2rem] text-[var(--local-text)]">{item.title}</h3>
|
|
7267
|
+
<p className="mt-2 text-sm text-[var(--local-text-muted)]">{item.body}</p>
|
|
7268
|
+
</CardContent>
|
|
7269
|
+
</Card>
|
|
7270
|
+
))}
|
|
7271
|
+
</div>
|
|
7272
|
+
</div>
|
|
7273
|
+
</div>
|
|
7274
|
+
</section>
|
|
7275
|
+
);
|
|
7276
|
+
|
|
7277
|
+
|
|
7278
|
+
END_OF_FILE_CONTENT
|
|
7279
|
+
echo "Creating src/components/hospitality-section/index.ts..."
|
|
7280
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/hospitality-section/index.ts"
|
|
7281
|
+
export { HospitalitySectionComponent } from './View';
|
|
7282
|
+
export { HospitalitySectionSchema } from './schema';
|
|
7283
|
+
export type { HospitalitySectionData, HospitalitySectionSettings } from './types';
|
|
7284
|
+
|
|
7285
|
+
|
|
7286
|
+
END_OF_FILE_CONTENT
|
|
7287
|
+
echo "Creating src/components/hospitality-section/schema.ts..."
|
|
7288
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/hospitality-section/schema.ts"
|
|
7289
|
+
import { z } from 'zod';
|
|
7290
|
+
import { BaseSectionData, BaseArrayItem, ImageSelectionSchema } from '@/lib/base-schemas';
|
|
7291
|
+
|
|
7292
|
+
const ItemSchema = BaseArrayItem.extend({
|
|
7293
|
+
title: z.string().describe('ui:text'),
|
|
7294
|
+
body: z.string().describe('ui:textarea'),
|
|
7295
|
+
});
|
|
7296
|
+
|
|
7297
|
+
export const HospitalitySectionSchema = BaseSectionData.extend({
|
|
7298
|
+
label: z.string().optional().describe('ui:text'),
|
|
7299
|
+
title: z.string().describe('ui:text'),
|
|
7300
|
+
description: z.string().describe('ui:textarea'),
|
|
7301
|
+
image: ImageSelectionSchema.optional().default({ url: '', alt: '' }),
|
|
7302
|
+
items: z.array(ItemSchema).describe('ui:list'),
|
|
7303
|
+
});
|
|
7304
|
+
|
|
7305
|
+
|
|
7306
|
+
END_OF_FILE_CONTENT
|
|
7307
|
+
echo "Creating src/components/hospitality-section/types.ts..."
|
|
7308
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/hospitality-section/types.ts"
|
|
7309
|
+
import { z } from 'zod';
|
|
7310
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
7311
|
+
import { HospitalitySectionSchema } from './schema';
|
|
7312
|
+
|
|
7313
|
+
export type HospitalitySectionData = z.infer<typeof HospitalitySectionSchema>;
|
|
7314
|
+
export type HospitalitySectionSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
7315
|
+
|
|
7316
|
+
|
|
6416
7317
|
END_OF_FILE_CONTENT
|
|
6417
7318
|
mkdir -p "src/components/login"
|
|
6418
7319
|
echo "Creating src/components/login/View.tsx..."
|
|
@@ -7574,6 +8475,124 @@ import { PageHeroSchema } from './schema';
|
|
|
7574
8475
|
export type PageHeroData = z.infer<typeof PageHeroSchema>;
|
|
7575
8476
|
export type PageHeroSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
7576
8477
|
|
|
8478
|
+
END_OF_FILE_CONTENT
|
|
8479
|
+
mkdir -p "src/components/pricing-section"
|
|
8480
|
+
echo "Creating src/components/pricing-section/View.tsx..."
|
|
8481
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/pricing-section/View.tsx"
|
|
8482
|
+
// Layout: Hero=E (MAGAZINE), Features=C (TIMELINE)
|
|
8483
|
+
import React from 'react';
|
|
8484
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
8485
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
|
8486
|
+
import type { PricingSectionData, PricingSectionSettings } from './types';
|
|
8487
|
+
|
|
8488
|
+
export const PricingSectionComponent: React.FC<{ data: PricingSectionData; settings: PricingSectionSettings }> = ({ data }) => (
|
|
8489
|
+
<section
|
|
8490
|
+
style={{
|
|
8491
|
+
'--local-bg': 'var(--background)',
|
|
8492
|
+
'--local-text': 'var(--foreground)',
|
|
8493
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
8494
|
+
'--local-primary': 'var(--primary)',
|
|
8495
|
+
'--local-accent': 'var(--accent)',
|
|
8496
|
+
'--local-border': 'var(--border)',
|
|
8497
|
+
'--local-surface': 'var(--card)',
|
|
8498
|
+
'--local-radius-md': 'var(--theme-radius-md)',
|
|
8499
|
+
'--local-radius-lg': 'var(--theme-radius-lg)',
|
|
8500
|
+
} as React.CSSProperties}
|
|
8501
|
+
className="relative z-0 py-24"
|
|
8502
|
+
>
|
|
8503
|
+
<div className="max-w-[1200px] mx-auto px-8">
|
|
8504
|
+
{data.label && (
|
|
8505
|
+
<div className="jp-section-label inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase text-[var(--local-accent)] mb-4" data-jp-field="label">
|
|
8506
|
+
<span className="w-5 h-px bg-[var(--local-primary)]" />
|
|
8507
|
+
{data.label}
|
|
8508
|
+
</div>
|
|
8509
|
+
)}
|
|
8510
|
+
<h2 className="font-display font-black text-[clamp(2rem,4.5vw,3.8rem)] leading-[1.05] tracking-tight text-[var(--local-text)]" data-jp-field="title">{data.title}</h2>
|
|
8511
|
+
<p className="mt-4 max-w-2xl text-[var(--local-text-muted)]" data-jp-field="description">{data.description}</p>
|
|
8512
|
+
|
|
8513
|
+
<Card className="mt-8 border-[var(--local-border)] bg-[var(--local-surface)] rounded-[var(--local-radius-lg)]">
|
|
8514
|
+
<CardContent className="p-0">
|
|
8515
|
+
<Table>
|
|
8516
|
+
<TableHeader>
|
|
8517
|
+
<TableRow>
|
|
8518
|
+
<TableHead>Treatment</TableHead>
|
|
8519
|
+
<TableHead>Rate</TableHead>
|
|
8520
|
+
<TableHead>Details</TableHead>
|
|
8521
|
+
</TableRow>
|
|
8522
|
+
</TableHeader>
|
|
8523
|
+
<TableBody>
|
|
8524
|
+
{data.rows.map((item, idx) => (
|
|
8525
|
+
<TableRow key={item.id || 'legacy-' + idx} data-jp-item-id={item.id || 'legacy-' + idx} data-jp-item-field="rows">
|
|
8526
|
+
<TableCell className="font-medium">{item.treatment}</TableCell>
|
|
8527
|
+
<TableCell>{item.price}</TableCell>
|
|
8528
|
+
<TableCell>{item.details}</TableCell>
|
|
8529
|
+
</TableRow>
|
|
8530
|
+
))}
|
|
8531
|
+
</TableBody>
|
|
8532
|
+
</Table>
|
|
8533
|
+
</CardContent>
|
|
8534
|
+
</Card>
|
|
8535
|
+
|
|
8536
|
+
<div className="grid gap-4 md:grid-cols-3 mt-6">
|
|
8537
|
+
{data.notes.map((item, idx) => (
|
|
8538
|
+
<Card key={item.id || 'legacy-' + idx} className="border-[var(--local-border)] bg-[var(--local-surface)] rounded-[var(--local-radius-md)]" data-jp-item-id={item.id || 'legacy-' + idx} data-jp-item-field="notes">
|
|
8539
|
+
<CardContent className="p-5">
|
|
8540
|
+
<h3 className="font-display font-bold text-[1.1rem] text-[var(--local-text)]">{item.title}</h3>
|
|
8541
|
+
<p className="mt-2 text-sm text-[var(--local-text-muted)]">{item.body}</p>
|
|
8542
|
+
</CardContent>
|
|
8543
|
+
</Card>
|
|
8544
|
+
))}
|
|
8545
|
+
</div>
|
|
8546
|
+
</div>
|
|
8547
|
+
</section>
|
|
8548
|
+
);
|
|
8549
|
+
|
|
8550
|
+
|
|
8551
|
+
END_OF_FILE_CONTENT
|
|
8552
|
+
echo "Creating src/components/pricing-section/index.ts..."
|
|
8553
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/pricing-section/index.ts"
|
|
8554
|
+
export { PricingSectionComponent } from './View';
|
|
8555
|
+
export { PricingSectionSchema } from './schema';
|
|
8556
|
+
export type { PricingSectionData, PricingSectionSettings } from './types';
|
|
8557
|
+
|
|
8558
|
+
|
|
8559
|
+
END_OF_FILE_CONTENT
|
|
8560
|
+
echo "Creating src/components/pricing-section/schema.ts..."
|
|
8561
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/pricing-section/schema.ts"
|
|
8562
|
+
import { z } from 'zod';
|
|
8563
|
+
import { BaseSectionData, BaseArrayItem } from '@/lib/base-schemas';
|
|
8564
|
+
|
|
8565
|
+
const RowSchema = BaseArrayItem.extend({
|
|
8566
|
+
treatment: z.string().describe('ui:text'),
|
|
8567
|
+
price: z.string().describe('ui:text'),
|
|
8568
|
+
details: z.string().describe('ui:textarea'),
|
|
8569
|
+
});
|
|
8570
|
+
|
|
8571
|
+
const NoteSchema = BaseArrayItem.extend({
|
|
8572
|
+
title: z.string().describe('ui:text'),
|
|
8573
|
+
body: z.string().describe('ui:textarea'),
|
|
8574
|
+
});
|
|
8575
|
+
|
|
8576
|
+
export const PricingSectionSchema = BaseSectionData.extend({
|
|
8577
|
+
label: z.string().optional().describe('ui:text'),
|
|
8578
|
+
title: z.string().describe('ui:text'),
|
|
8579
|
+
description: z.string().describe('ui:textarea'),
|
|
8580
|
+
rows: z.array(RowSchema).describe('ui:list'),
|
|
8581
|
+
notes: z.array(NoteSchema).describe('ui:list'),
|
|
8582
|
+
});
|
|
8583
|
+
|
|
8584
|
+
|
|
8585
|
+
END_OF_FILE_CONTENT
|
|
8586
|
+
echo "Creating src/components/pricing-section/types.ts..."
|
|
8587
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/pricing-section/types.ts"
|
|
8588
|
+
import { z } from 'zod';
|
|
8589
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
8590
|
+
import { PricingSectionSchema } from './schema';
|
|
8591
|
+
|
|
8592
|
+
export type PricingSectionData = z.infer<typeof PricingSectionSchema>;
|
|
8593
|
+
export type PricingSectionSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
8594
|
+
|
|
8595
|
+
|
|
7577
8596
|
END_OF_FILE_CONTENT
|
|
7578
8597
|
mkdir -p "src/components/problem-statement"
|
|
7579
8598
|
echo "Creating src/components/problem-statement/View.tsx..."
|
|
@@ -8786,13 +9805,107 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/save-drawer/saverStyle.css"
|
|
|
8786
9805
|
|
|
8787
9806
|
|
|
8788
9807
|
END_OF_FILE_CONTENT
|
|
8789
|
-
mkdir -p "src/components/
|
|
8790
|
-
echo "Creating src/components/
|
|
8791
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
|
|
9808
|
+
mkdir -p "src/components/testimonials-section"
|
|
9809
|
+
echo "Creating src/components/testimonials-section/View.tsx..."
|
|
9810
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/testimonials-section/View.tsx"
|
|
9811
|
+
// Layout: Hero=B (BENTO GRID), Features=B (HORIZONTAL SCROLL)
|
|
9812
|
+
import React from 'react';
|
|
9813
|
+
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
9814
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
9815
|
+
import type { TestimonialsSectionData, TestimonialsSectionSettings } from './types';
|
|
9816
|
+
|
|
9817
|
+
export const TestimonialsSectionComponent: React.FC<{ data: TestimonialsSectionData; settings: TestimonialsSectionSettings }> = ({ data }) => (
|
|
9818
|
+
<section
|
|
9819
|
+
style={{
|
|
9820
|
+
'--local-bg': 'var(--card)',
|
|
9821
|
+
'--local-text': 'var(--foreground)',
|
|
9822
|
+
'--local-text-muted': 'var(--muted-foreground)',
|
|
9823
|
+
'--local-primary': 'var(--primary)',
|
|
9824
|
+
'--local-accent': 'var(--accent)',
|
|
9825
|
+
'--local-border': 'var(--border)',
|
|
9826
|
+
'--local-surface': 'var(--background)',
|
|
9827
|
+
'--local-radius-md': 'var(--theme-radius-md)',
|
|
9828
|
+
'--local-radius-lg': 'var(--theme-radius-lg)',
|
|
9829
|
+
} as React.CSSProperties}
|
|
9830
|
+
className="relative z-0 py-24 bg-[var(--local-bg)]"
|
|
9831
|
+
>
|
|
9832
|
+
<div className="max-w-[1200px] mx-auto px-8">
|
|
9833
|
+
{data.label && (
|
|
9834
|
+
<div className="jp-section-label inline-flex items-center gap-2 text-[0.72rem] font-bold uppercase text-[var(--local-accent)] mb-4" data-jp-field="label">
|
|
9835
|
+
<span className="w-5 h-px bg-[var(--local-primary)]" />
|
|
9836
|
+
{data.label}
|
|
9837
|
+
</div>
|
|
9838
|
+
)}
|
|
9839
|
+
<h2 className="font-display font-black text-[clamp(2rem,4.5vw,3.8rem)] leading-[1.05] tracking-tight text-[var(--local-text)]" data-jp-field="title">{data.title}</h2>
|
|
9840
|
+
<ScrollArea className="w-full mt-8">
|
|
9841
|
+
<div className="flex gap-5 pb-4">
|
|
9842
|
+
{data.items.map((item, idx) => (
|
|
9843
|
+
<Card
|
|
9844
|
+
key={item.id || 'legacy-' + idx}
|
|
9845
|
+
className="min-w-[320px] max-w-[360px] border-[var(--local-border)] bg-[var(--local-surface)] rounded-[var(--local-radius-lg)]"
|
|
9846
|
+
data-jp-item-id={item.id || 'legacy-' + idx}
|
|
9847
|
+
data-jp-item-field="items"
|
|
9848
|
+
>
|
|
9849
|
+
<CardContent className="p-6">
|
|
9850
|
+
<p className="text-[var(--local-text)] leading-relaxed">“{item.quote}”</p>
|
|
9851
|
+
<div className="mt-5 font-display text-xl text-[var(--local-text)]">{item.name}</div>
|
|
9852
|
+
<div className="text-sm text-[var(--local-text-muted)]">{item.meta}</div>
|
|
9853
|
+
</CardContent>
|
|
9854
|
+
</Card>
|
|
9855
|
+
))}
|
|
9856
|
+
</div>
|
|
9857
|
+
</ScrollArea>
|
|
9858
|
+
</div>
|
|
9859
|
+
</section>
|
|
9860
|
+
);
|
|
9861
|
+
|
|
9862
|
+
|
|
9863
|
+
END_OF_FILE_CONTENT
|
|
9864
|
+
echo "Creating src/components/testimonials-section/index.ts..."
|
|
9865
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/testimonials-section/index.ts"
|
|
9866
|
+
export { TestimonialsSectionComponent } from './View';
|
|
9867
|
+
export { TestimonialsSectionSchema } from './schema';
|
|
9868
|
+
export type { TestimonialsSectionData, TestimonialsSectionSettings } from './types';
|
|
9869
|
+
|
|
9870
|
+
|
|
9871
|
+
END_OF_FILE_CONTENT
|
|
9872
|
+
echo "Creating src/components/testimonials-section/schema.ts..."
|
|
9873
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/testimonials-section/schema.ts"
|
|
9874
|
+
import { z } from 'zod';
|
|
9875
|
+
import { BaseSectionData, BaseArrayItem } from '@/lib/base-schemas';
|
|
9876
|
+
|
|
9877
|
+
const TestimonialSchema = BaseArrayItem.extend({
|
|
9878
|
+
name: z.string().describe('ui:text'),
|
|
9879
|
+
quote: z.string().describe('ui:textarea'),
|
|
9880
|
+
meta: z.string().describe('ui:text'),
|
|
9881
|
+
});
|
|
9882
|
+
|
|
9883
|
+
export const TestimonialsSectionSchema = BaseSectionData.extend({
|
|
9884
|
+
label: z.string().optional().describe('ui:text'),
|
|
9885
|
+
title: z.string().describe('ui:text'),
|
|
9886
|
+
items: z.array(TestimonialSchema).describe('ui:list'),
|
|
9887
|
+
});
|
|
9888
|
+
|
|
9889
|
+
|
|
9890
|
+
END_OF_FILE_CONTENT
|
|
9891
|
+
echo "Creating src/components/testimonials-section/types.ts..."
|
|
9892
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/testimonials-section/types.ts"
|
|
9893
|
+
import { z } from 'zod';
|
|
9894
|
+
import { BaseSectionSettingsSchema } from '@/lib/base-schemas';
|
|
9895
|
+
import { TestimonialsSectionSchema } from './schema';
|
|
9896
|
+
|
|
9897
|
+
export type TestimonialsSectionData = z.infer<typeof TestimonialsSectionSchema>;
|
|
9898
|
+
export type TestimonialsSectionSettings = z.infer<typeof BaseSectionSettingsSchema>;
|
|
9899
|
+
|
|
9900
|
+
|
|
9901
|
+
END_OF_FILE_CONTENT
|
|
9902
|
+
mkdir -p "src/components/tiptap"
|
|
9903
|
+
echo "Creating src/components/tiptap/INTEGRATION.md..."
|
|
9904
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/tiptap/INTEGRATION.md"
|
|
9905
|
+
# Tiptap Editorial — Integration Guide
|
|
9906
|
+
|
|
9907
|
+
How to add the `tiptap` section to a new tenant.
|
|
9908
|
+
|
|
8796
9909
|
---
|
|
8797
9910
|
|
|
8798
9911
|
## 1. Copy the component
|
|
@@ -9992,6 +11105,223 @@ export function OlonLogo({
|
|
|
9992
11105
|
)
|
|
9993
11106
|
}
|
|
9994
11107
|
|
|
11108
|
+
END_OF_FILE_CONTENT
|
|
11109
|
+
echo "Creating src/components/ui/accordion.tsx..."
|
|
11110
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/accordion.tsx"
|
|
11111
|
+
import * as React from "react"
|
|
11112
|
+
import { Accordion as AccordionPrimitive } from "radix-ui"
|
|
11113
|
+
|
|
11114
|
+
import { cn } from "@/lib/utils"
|
|
11115
|
+
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
|
11116
|
+
|
|
11117
|
+
function Accordion({
|
|
11118
|
+
className,
|
|
11119
|
+
...props
|
|
11120
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
|
|
11121
|
+
return (
|
|
11122
|
+
<AccordionPrimitive.Root
|
|
11123
|
+
data-slot="accordion"
|
|
11124
|
+
className={cn("flex w-full flex-col", className)}
|
|
11125
|
+
{...props}
|
|
11126
|
+
/>
|
|
11127
|
+
)
|
|
11128
|
+
}
|
|
11129
|
+
|
|
11130
|
+
function AccordionItem({
|
|
11131
|
+
className,
|
|
11132
|
+
...props
|
|
11133
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
|
|
11134
|
+
return (
|
|
11135
|
+
<AccordionPrimitive.Item
|
|
11136
|
+
data-slot="accordion-item"
|
|
11137
|
+
className={cn("not-last:border-b", className)}
|
|
11138
|
+
{...props}
|
|
11139
|
+
/>
|
|
11140
|
+
)
|
|
11141
|
+
}
|
|
11142
|
+
|
|
11143
|
+
function AccordionTrigger({
|
|
11144
|
+
className,
|
|
11145
|
+
children,
|
|
11146
|
+
...props
|
|
11147
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
|
|
11148
|
+
return (
|
|
11149
|
+
<AccordionPrimitive.Header className="flex">
|
|
11150
|
+
<AccordionPrimitive.Trigger
|
|
11151
|
+
data-slot="accordion-trigger"
|
|
11152
|
+
className={cn(
|
|
11153
|
+
"group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring disabled:pointer-events-none disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
|
|
11154
|
+
className
|
|
11155
|
+
)}
|
|
11156
|
+
{...props}
|
|
11157
|
+
>
|
|
11158
|
+
{children}
|
|
11159
|
+
<ChevronDownIcon data-slot="accordion-trigger-icon" className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden" />
|
|
11160
|
+
<ChevronUpIcon data-slot="accordion-trigger-icon" className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline" />
|
|
11161
|
+
</AccordionPrimitive.Trigger>
|
|
11162
|
+
</AccordionPrimitive.Header>
|
|
11163
|
+
)
|
|
11164
|
+
}
|
|
11165
|
+
|
|
11166
|
+
function AccordionContent({
|
|
11167
|
+
className,
|
|
11168
|
+
children,
|
|
11169
|
+
...props
|
|
11170
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
|
|
11171
|
+
return (
|
|
11172
|
+
<AccordionPrimitive.Content
|
|
11173
|
+
data-slot="accordion-content"
|
|
11174
|
+
className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
|
|
11175
|
+
{...props}
|
|
11176
|
+
>
|
|
11177
|
+
<div
|
|
11178
|
+
className={cn(
|
|
11179
|
+
"h-(--radix-accordion-content-height) pt-0 pb-2.5 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
|
|
11180
|
+
className
|
|
11181
|
+
)}
|
|
11182
|
+
>
|
|
11183
|
+
{children}
|
|
11184
|
+
</div>
|
|
11185
|
+
</AccordionPrimitive.Content>
|
|
11186
|
+
)
|
|
11187
|
+
}
|
|
11188
|
+
|
|
11189
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
|
11190
|
+
|
|
11191
|
+
|
|
11192
|
+
END_OF_FILE_CONTENT
|
|
11193
|
+
echo "Creating src/components/ui/aspect-ratio.tsx..."
|
|
11194
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/aspect-ratio.tsx"
|
|
11195
|
+
"use client"
|
|
11196
|
+
|
|
11197
|
+
import { AspectRatio as AspectRatioPrimitive } from "radix-ui"
|
|
11198
|
+
|
|
11199
|
+
function AspectRatio({
|
|
11200
|
+
...props
|
|
11201
|
+
}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
|
|
11202
|
+
return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />
|
|
11203
|
+
}
|
|
11204
|
+
|
|
11205
|
+
export { AspectRatio }
|
|
11206
|
+
|
|
11207
|
+
|
|
11208
|
+
END_OF_FILE_CONTENT
|
|
11209
|
+
echo "Creating src/components/ui/avatar.tsx..."
|
|
11210
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/avatar.tsx"
|
|
11211
|
+
"use client"
|
|
11212
|
+
|
|
11213
|
+
import * as React from "react"
|
|
11214
|
+
import { Avatar as AvatarPrimitive } from "radix-ui"
|
|
11215
|
+
|
|
11216
|
+
import { cn } from "@/lib/utils"
|
|
11217
|
+
|
|
11218
|
+
function Avatar({
|
|
11219
|
+
className,
|
|
11220
|
+
size = "default",
|
|
11221
|
+
...props
|
|
11222
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Root> & {
|
|
11223
|
+
size?: "default" | "sm" | "lg"
|
|
11224
|
+
}) {
|
|
11225
|
+
return (
|
|
11226
|
+
<AvatarPrimitive.Root
|
|
11227
|
+
data-slot="avatar"
|
|
11228
|
+
data-size={size}
|
|
11229
|
+
className={cn(
|
|
11230
|
+
"group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten",
|
|
11231
|
+
className
|
|
11232
|
+
)}
|
|
11233
|
+
{...props}
|
|
11234
|
+
/>
|
|
11235
|
+
)
|
|
11236
|
+
}
|
|
11237
|
+
|
|
11238
|
+
function AvatarImage({
|
|
11239
|
+
className,
|
|
11240
|
+
...props
|
|
11241
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
|
11242
|
+
return (
|
|
11243
|
+
<AvatarPrimitive.Image
|
|
11244
|
+
data-slot="avatar-image"
|
|
11245
|
+
className={cn(
|
|
11246
|
+
"aspect-square size-full rounded-full object-cover",
|
|
11247
|
+
className
|
|
11248
|
+
)}
|
|
11249
|
+
{...props}
|
|
11250
|
+
/>
|
|
11251
|
+
)
|
|
11252
|
+
}
|
|
11253
|
+
|
|
11254
|
+
function AvatarFallback({
|
|
11255
|
+
className,
|
|
11256
|
+
...props
|
|
11257
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
|
11258
|
+
return (
|
|
11259
|
+
<AvatarPrimitive.Fallback
|
|
11260
|
+
data-slot="avatar-fallback"
|
|
11261
|
+
className={cn(
|
|
11262
|
+
"flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs",
|
|
11263
|
+
className
|
|
11264
|
+
)}
|
|
11265
|
+
{...props}
|
|
11266
|
+
/>
|
|
11267
|
+
)
|
|
11268
|
+
}
|
|
11269
|
+
|
|
11270
|
+
function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
|
|
11271
|
+
return (
|
|
11272
|
+
<span
|
|
11273
|
+
data-slot="avatar-badge"
|
|
11274
|
+
className={cn(
|
|
11275
|
+
"absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none",
|
|
11276
|
+
"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
|
|
11277
|
+
"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
|
|
11278
|
+
"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
|
|
11279
|
+
className
|
|
11280
|
+
)}
|
|
11281
|
+
{...props}
|
|
11282
|
+
/>
|
|
11283
|
+
)
|
|
11284
|
+
}
|
|
11285
|
+
|
|
11286
|
+
function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
11287
|
+
return (
|
|
11288
|
+
<div
|
|
11289
|
+
data-slot="avatar-group"
|
|
11290
|
+
className={cn(
|
|
11291
|
+
"group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background",
|
|
11292
|
+
className
|
|
11293
|
+
)}
|
|
11294
|
+
{...props}
|
|
11295
|
+
/>
|
|
11296
|
+
)
|
|
11297
|
+
}
|
|
11298
|
+
|
|
11299
|
+
function AvatarGroupCount({
|
|
11300
|
+
className,
|
|
11301
|
+
...props
|
|
11302
|
+
}: React.ComponentProps<"div">) {
|
|
11303
|
+
return (
|
|
11304
|
+
<div
|
|
11305
|
+
data-slot="avatar-group-count"
|
|
11306
|
+
className={cn(
|
|
11307
|
+
"relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",
|
|
11308
|
+
className
|
|
11309
|
+
)}
|
|
11310
|
+
{...props}
|
|
11311
|
+
/>
|
|
11312
|
+
)
|
|
11313
|
+
}
|
|
11314
|
+
|
|
11315
|
+
export {
|
|
11316
|
+
Avatar,
|
|
11317
|
+
AvatarImage,
|
|
11318
|
+
AvatarFallback,
|
|
11319
|
+
AvatarGroup,
|
|
11320
|
+
AvatarGroupCount,
|
|
11321
|
+
AvatarBadge,
|
|
11322
|
+
}
|
|
11323
|
+
|
|
11324
|
+
|
|
9995
11325
|
END_OF_FILE_CONTENT
|
|
9996
11326
|
echo "Creating src/components/ui/badge.tsx..."
|
|
9997
11327
|
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/badge.tsx"
|
|
@@ -10025,6 +11355,133 @@ function Badge({ className, variant, ...props }: BadgeProps) {
|
|
|
10025
11355
|
|
|
10026
11356
|
export { Badge, badgeVariants }
|
|
10027
11357
|
|
|
11358
|
+
END_OF_FILE_CONTENT
|
|
11359
|
+
echo "Creating src/components/ui/breadcrumb.tsx..."
|
|
11360
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/breadcrumb.tsx"
|
|
11361
|
+
import * as React from "react"
|
|
11362
|
+
import { Slot } from "radix-ui"
|
|
11363
|
+
|
|
11364
|
+
import { cn } from "@/lib/utils"
|
|
11365
|
+
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
|
|
11366
|
+
|
|
11367
|
+
function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
|
|
11368
|
+
return (
|
|
11369
|
+
<nav
|
|
11370
|
+
aria-label="breadcrumb"
|
|
11371
|
+
data-slot="breadcrumb"
|
|
11372
|
+
className={cn(className)}
|
|
11373
|
+
{...props}
|
|
11374
|
+
/>
|
|
11375
|
+
)
|
|
11376
|
+
}
|
|
11377
|
+
|
|
11378
|
+
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
|
|
11379
|
+
return (
|
|
11380
|
+
<ol
|
|
11381
|
+
data-slot="breadcrumb-list"
|
|
11382
|
+
className={cn(
|
|
11383
|
+
"flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground",
|
|
11384
|
+
className
|
|
11385
|
+
)}
|
|
11386
|
+
{...props}
|
|
11387
|
+
/>
|
|
11388
|
+
)
|
|
11389
|
+
}
|
|
11390
|
+
|
|
11391
|
+
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
|
|
11392
|
+
return (
|
|
11393
|
+
<li
|
|
11394
|
+
data-slot="breadcrumb-item"
|
|
11395
|
+
className={cn("inline-flex items-center gap-1", className)}
|
|
11396
|
+
{...props}
|
|
11397
|
+
/>
|
|
11398
|
+
)
|
|
11399
|
+
}
|
|
11400
|
+
|
|
11401
|
+
function BreadcrumbLink({
|
|
11402
|
+
asChild,
|
|
11403
|
+
className,
|
|
11404
|
+
...props
|
|
11405
|
+
}: React.ComponentProps<"a"> & {
|
|
11406
|
+
asChild?: boolean
|
|
11407
|
+
}) {
|
|
11408
|
+
const Comp = asChild ? Slot.Root : "a"
|
|
11409
|
+
|
|
11410
|
+
return (
|
|
11411
|
+
<Comp
|
|
11412
|
+
data-slot="breadcrumb-link"
|
|
11413
|
+
className={cn("transition-colors hover:text-foreground", className)}
|
|
11414
|
+
{...props}
|
|
11415
|
+
/>
|
|
11416
|
+
)
|
|
11417
|
+
}
|
|
11418
|
+
|
|
11419
|
+
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
|
|
11420
|
+
return (
|
|
11421
|
+
<span
|
|
11422
|
+
data-slot="breadcrumb-page"
|
|
11423
|
+
role="link"
|
|
11424
|
+
aria-disabled="true"
|
|
11425
|
+
aria-current="page"
|
|
11426
|
+
className={cn("font-normal text-foreground", className)}
|
|
11427
|
+
{...props}
|
|
11428
|
+
/>
|
|
11429
|
+
)
|
|
11430
|
+
}
|
|
11431
|
+
|
|
11432
|
+
function BreadcrumbSeparator({
|
|
11433
|
+
children,
|
|
11434
|
+
className,
|
|
11435
|
+
...props
|
|
11436
|
+
}: React.ComponentProps<"li">) {
|
|
11437
|
+
return (
|
|
11438
|
+
<li
|
|
11439
|
+
data-slot="breadcrumb-separator"
|
|
11440
|
+
role="presentation"
|
|
11441
|
+
aria-hidden="true"
|
|
11442
|
+
className={cn("[&>svg]:size-3.5", className)}
|
|
11443
|
+
{...props}
|
|
11444
|
+
>
|
|
11445
|
+
{children ?? (
|
|
11446
|
+
<ChevronRightIcon />
|
|
11447
|
+
)}
|
|
11448
|
+
</li>
|
|
11449
|
+
)
|
|
11450
|
+
}
|
|
11451
|
+
|
|
11452
|
+
function BreadcrumbEllipsis({
|
|
11453
|
+
className,
|
|
11454
|
+
...props
|
|
11455
|
+
}: React.ComponentProps<"span">) {
|
|
11456
|
+
return (
|
|
11457
|
+
<span
|
|
11458
|
+
data-slot="breadcrumb-ellipsis"
|
|
11459
|
+
role="presentation"
|
|
11460
|
+
aria-hidden="true"
|
|
11461
|
+
className={cn(
|
|
11462
|
+
"flex size-5 items-center justify-center [&>svg]:size-4",
|
|
11463
|
+
className
|
|
11464
|
+
)}
|
|
11465
|
+
{...props}
|
|
11466
|
+
>
|
|
11467
|
+
<MoreHorizontalIcon
|
|
11468
|
+
/>
|
|
11469
|
+
<span className="sr-only">More</span>
|
|
11470
|
+
</span>
|
|
11471
|
+
)
|
|
11472
|
+
}
|
|
11473
|
+
|
|
11474
|
+
export {
|
|
11475
|
+
Breadcrumb,
|
|
11476
|
+
BreadcrumbList,
|
|
11477
|
+
BreadcrumbItem,
|
|
11478
|
+
BreadcrumbLink,
|
|
11479
|
+
BreadcrumbPage,
|
|
11480
|
+
BreadcrumbSeparator,
|
|
11481
|
+
BreadcrumbEllipsis,
|
|
11482
|
+
}
|
|
11483
|
+
|
|
11484
|
+
|
|
10028
11485
|
END_OF_FILE_CONTENT
|
|
10029
11486
|
echo "Creating src/components/ui/button.tsx..."
|
|
10030
11487
|
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/button.tsx"
|
|
@@ -10182,509 +11639,1870 @@ export { Checkbox }
|
|
|
10182
11639
|
|
|
10183
11640
|
|
|
10184
11641
|
END_OF_FILE_CONTENT
|
|
10185
|
-
echo "Creating src/components/ui/
|
|
10186
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/
|
|
10187
|
-
import * as React from
|
|
10188
|
-
import {
|
|
11642
|
+
echo "Creating src/components/ui/dialog.tsx..."
|
|
11643
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/dialog.tsx"
|
|
11644
|
+
import * as React from "react"
|
|
11645
|
+
import { Dialog as DialogPrimitive } from "radix-ui"
|
|
10189
11646
|
|
|
10190
|
-
|
|
11647
|
+
import { cn } from "@/lib/utils"
|
|
11648
|
+
import { Button } from "@/components/ui/button"
|
|
11649
|
+
import { XIcon } from "lucide-react"
|
|
10191
11650
|
|
|
10192
|
-
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
className={cn(
|
|
10198
|
-
'flex h-9 w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground',
|
|
10199
|
-
'focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary',
|
|
10200
|
-
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
10201
|
-
'transition-colors duration-150',
|
|
10202
|
-
className
|
|
10203
|
-
)}
|
|
10204
|
-
ref={ref}
|
|
10205
|
-
{...props}
|
|
10206
|
-
/>
|
|
10207
|
-
)
|
|
10208
|
-
}
|
|
10209
|
-
)
|
|
10210
|
-
Input.displayName = 'Input'
|
|
10211
|
-
|
|
10212
|
-
export { Input }
|
|
10213
|
-
|
|
10214
|
-
END_OF_FILE_CONTENT
|
|
10215
|
-
echo "Creating src/components/ui/label.tsx..."
|
|
10216
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/label.tsx"
|
|
10217
|
-
import * as React from 'react'
|
|
10218
|
-
import { cn } from '@/lib/utils'
|
|
10219
|
-
|
|
10220
|
-
const Label = React.forwardRef<
|
|
10221
|
-
HTMLLabelElement,
|
|
10222
|
-
React.LabelHTMLAttributes<HTMLLabelElement>
|
|
10223
|
-
>(({ className, ...props }, ref) => (
|
|
10224
|
-
<label
|
|
10225
|
-
ref={ref}
|
|
10226
|
-
className={cn('block text-xs font-medium text-foreground mb-1.5 cursor-default', className)}
|
|
10227
|
-
{...props}
|
|
10228
|
-
/>
|
|
10229
|
-
))
|
|
10230
|
-
Label.displayName = 'Label'
|
|
10231
|
-
|
|
10232
|
-
export { Label }
|
|
10233
|
-
|
|
10234
|
-
END_OF_FILE_CONTENT
|
|
10235
|
-
echo "Creating src/components/ui/select.tsx..."
|
|
10236
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/select.tsx"
|
|
10237
|
-
import * as React from "react"
|
|
10238
|
-
import { Select as SelectPrimitive } from "radix-ui"
|
|
10239
|
-
|
|
10240
|
-
import { cn } from "@/lib/utils"
|
|
10241
|
-
import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
|
|
11651
|
+
function Dialog({
|
|
11652
|
+
...props
|
|
11653
|
+
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
11654
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />
|
|
11655
|
+
}
|
|
10242
11656
|
|
|
10243
|
-
function
|
|
11657
|
+
function DialogTrigger({
|
|
10244
11658
|
...props
|
|
10245
|
-
}: React.ComponentProps<typeof
|
|
10246
|
-
return <
|
|
11659
|
+
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
11660
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
10247
11661
|
}
|
|
10248
11662
|
|
|
10249
|
-
function
|
|
10250
|
-
className,
|
|
11663
|
+
function DialogPortal({
|
|
10251
11664
|
...props
|
|
10252
|
-
}: React.ComponentProps<typeof
|
|
10253
|
-
return
|
|
10254
|
-
<SelectPrimitive.Group
|
|
10255
|
-
data-slot="select-group"
|
|
10256
|
-
className={cn("scroll-my-1 p-1", className)}
|
|
10257
|
-
{...props}
|
|
10258
|
-
/>
|
|
10259
|
-
)
|
|
11665
|
+
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
11666
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
|
10260
11667
|
}
|
|
10261
11668
|
|
|
10262
|
-
function
|
|
11669
|
+
function DialogClose({
|
|
10263
11670
|
...props
|
|
10264
|
-
}: React.ComponentProps<typeof
|
|
10265
|
-
return <
|
|
11671
|
+
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
11672
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
|
|
10266
11673
|
}
|
|
10267
11674
|
|
|
10268
|
-
function
|
|
11675
|
+
function DialogOverlay({
|
|
10269
11676
|
className,
|
|
10270
|
-
size = "default",
|
|
10271
|
-
children,
|
|
10272
11677
|
...props
|
|
10273
|
-
}: React.ComponentProps<typeof
|
|
10274
|
-
size?: "sm" | "default"
|
|
10275
|
-
}) {
|
|
11678
|
+
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
10276
11679
|
return (
|
|
10277
|
-
<
|
|
10278
|
-
data-slot="
|
|
10279
|
-
data-size={size}
|
|
11680
|
+
<DialogPrimitive.Overlay
|
|
11681
|
+
data-slot="dialog-overlay"
|
|
10280
11682
|
className={cn(
|
|
10281
|
-
"
|
|
11683
|
+
"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
10282
11684
|
className
|
|
10283
11685
|
)}
|
|
10284
11686
|
{...props}
|
|
10285
|
-
|
|
10286
|
-
{children}
|
|
10287
|
-
<SelectPrimitive.Icon asChild>
|
|
10288
|
-
<ChevronDownIcon className="text-muted-foreground size-4 pointer-events-none" />
|
|
10289
|
-
</SelectPrimitive.Icon>
|
|
10290
|
-
</SelectPrimitive.Trigger>
|
|
11687
|
+
/>
|
|
10291
11688
|
)
|
|
10292
11689
|
}
|
|
10293
11690
|
|
|
10294
|
-
function
|
|
11691
|
+
function DialogContent({
|
|
10295
11692
|
className,
|
|
10296
11693
|
children,
|
|
10297
|
-
|
|
10298
|
-
align = "center",
|
|
11694
|
+
showCloseButton = true,
|
|
10299
11695
|
...props
|
|
10300
|
-
}: React.ComponentProps<typeof
|
|
11696
|
+
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
11697
|
+
showCloseButton?: boolean
|
|
11698
|
+
}) {
|
|
10301
11699
|
return (
|
|
10302
|
-
<
|
|
10303
|
-
<
|
|
10304
|
-
|
|
10305
|
-
data-
|
|
11700
|
+
<DialogPortal>
|
|
11701
|
+
<DialogOverlay />
|
|
11702
|
+
<DialogPrimitive.Content
|
|
11703
|
+
data-slot="dialog-content"
|
|
10306
11704
|
className={cn(
|
|
10307
|
-
"
|
|
10308
|
-
|
|
10309
|
-
className
|
|
11705
|
+
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
11706
|
+
className
|
|
10310
11707
|
)}
|
|
10311
|
-
position={position}
|
|
10312
|
-
align={align}
|
|
10313
11708
|
{...props}
|
|
10314
11709
|
>
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
data-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
11710
|
+
{children}
|
|
11711
|
+
{showCloseButton && (
|
|
11712
|
+
<DialogPrimitive.Close data-slot="dialog-close" asChild>
|
|
11713
|
+
<Button
|
|
11714
|
+
variant="ghost"
|
|
11715
|
+
className="absolute top-2 right-2"
|
|
11716
|
+
size="sm"
|
|
11717
|
+
>
|
|
11718
|
+
<XIcon
|
|
11719
|
+
/>
|
|
11720
|
+
<span className="sr-only">Close</span>
|
|
11721
|
+
</Button>
|
|
11722
|
+
</DialogPrimitive.Close>
|
|
11723
|
+
)}
|
|
11724
|
+
</DialogPrimitive.Content>
|
|
11725
|
+
</DialogPortal>
|
|
10328
11726
|
)
|
|
10329
11727
|
}
|
|
10330
11728
|
|
|
10331
|
-
function
|
|
10332
|
-
className,
|
|
10333
|
-
...props
|
|
10334
|
-
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
|
11729
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
10335
11730
|
return (
|
|
10336
|
-
<
|
|
10337
|
-
data-slot="
|
|
10338
|
-
className={cn("
|
|
11731
|
+
<div
|
|
11732
|
+
data-slot="dialog-header"
|
|
11733
|
+
className={cn("flex flex-col gap-2", className)}
|
|
10339
11734
|
{...props}
|
|
10340
11735
|
/>
|
|
10341
11736
|
)
|
|
10342
11737
|
}
|
|
10343
11738
|
|
|
10344
|
-
function
|
|
11739
|
+
function DialogFooter({
|
|
10345
11740
|
className,
|
|
11741
|
+
showCloseButton = false,
|
|
10346
11742
|
children,
|
|
10347
11743
|
...props
|
|
10348
|
-
}: React.ComponentProps<
|
|
11744
|
+
}: React.ComponentProps<"div"> & {
|
|
11745
|
+
showCloseButton?: boolean
|
|
11746
|
+
}) {
|
|
10349
11747
|
return (
|
|
10350
|
-
<
|
|
10351
|
-
data-slot="
|
|
11748
|
+
<div
|
|
11749
|
+
data-slot="dialog-footer"
|
|
10352
11750
|
className={cn(
|
|
10353
|
-
"
|
|
11751
|
+
"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",
|
|
10354
11752
|
className
|
|
10355
11753
|
)}
|
|
10356
11754
|
{...props}
|
|
10357
11755
|
>
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
</
|
|
11756
|
+
{children}
|
|
11757
|
+
{showCloseButton && (
|
|
11758
|
+
<DialogPrimitive.Close asChild>
|
|
11759
|
+
<Button variant="outline">Close</Button>
|
|
11760
|
+
</DialogPrimitive.Close>
|
|
11761
|
+
)}
|
|
11762
|
+
</div>
|
|
10365
11763
|
)
|
|
10366
11764
|
}
|
|
10367
11765
|
|
|
10368
|
-
function
|
|
11766
|
+
function DialogTitle({
|
|
10369
11767
|
className,
|
|
10370
11768
|
...props
|
|
10371
|
-
}: React.ComponentProps<typeof
|
|
11769
|
+
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
10372
11770
|
return (
|
|
10373
|
-
<
|
|
10374
|
-
data-slot="
|
|
10375
|
-
className={cn(
|
|
11771
|
+
<DialogPrimitive.Title
|
|
11772
|
+
data-slot="dialog-title"
|
|
11773
|
+
className={cn(
|
|
11774
|
+
"text-base leading-none font-medium",
|
|
11775
|
+
className
|
|
11776
|
+
)}
|
|
10376
11777
|
{...props}
|
|
10377
11778
|
/>
|
|
10378
11779
|
)
|
|
10379
11780
|
}
|
|
10380
11781
|
|
|
10381
|
-
function
|
|
10382
|
-
className,
|
|
10383
|
-
...props
|
|
10384
|
-
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
|
10385
|
-
return (
|
|
10386
|
-
<SelectPrimitive.ScrollUpButton
|
|
10387
|
-
data-slot="select-scroll-up-button"
|
|
10388
|
-
className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4", className)}
|
|
10389
|
-
{...props}
|
|
10390
|
-
>
|
|
10391
|
-
<ChevronUpIcon />
|
|
10392
|
-
</SelectPrimitive.ScrollUpButton>
|
|
10393
|
-
)
|
|
10394
|
-
}
|
|
10395
|
-
|
|
10396
|
-
function SelectScrollDownButton({
|
|
11782
|
+
function DialogDescription({
|
|
10397
11783
|
className,
|
|
10398
11784
|
...props
|
|
10399
|
-
}: React.ComponentProps<typeof
|
|
11785
|
+
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
10400
11786
|
return (
|
|
10401
|
-
<
|
|
10402
|
-
data-slot="
|
|
10403
|
-
className={cn(
|
|
11787
|
+
<DialogPrimitive.Description
|
|
11788
|
+
data-slot="dialog-description"
|
|
11789
|
+
className={cn(
|
|
11790
|
+
"text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
11791
|
+
className
|
|
11792
|
+
)}
|
|
10404
11793
|
{...props}
|
|
10405
|
-
|
|
10406
|
-
<ChevronDownIcon />
|
|
10407
|
-
</SelectPrimitive.ScrollDownButton>
|
|
11794
|
+
/>
|
|
10408
11795
|
)
|
|
10409
11796
|
}
|
|
10410
11797
|
|
|
10411
11798
|
export {
|
|
10412
|
-
|
|
10413
|
-
|
|
10414
|
-
|
|
10415
|
-
|
|
10416
|
-
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
|
|
10421
|
-
|
|
11799
|
+
Dialog,
|
|
11800
|
+
DialogClose,
|
|
11801
|
+
DialogContent,
|
|
11802
|
+
DialogDescription,
|
|
11803
|
+
DialogFooter,
|
|
11804
|
+
DialogHeader,
|
|
11805
|
+
DialogOverlay,
|
|
11806
|
+
DialogPortal,
|
|
11807
|
+
DialogTitle,
|
|
11808
|
+
DialogTrigger,
|
|
10422
11809
|
}
|
|
10423
11810
|
|
|
10424
11811
|
|
|
10425
|
-
|
|
10426
|
-
|
|
10427
11812
|
END_OF_FILE_CONTENT
|
|
10428
|
-
echo "Creating src/components/ui/
|
|
10429
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/
|
|
11813
|
+
echo "Creating src/components/ui/dropdown-menu.tsx..."
|
|
11814
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/dropdown-menu.tsx"
|
|
10430
11815
|
import * as React from "react"
|
|
10431
|
-
import {
|
|
11816
|
+
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
|
|
10432
11817
|
|
|
10433
11818
|
import { cn } from "@/lib/utils"
|
|
10434
|
-
import {
|
|
11819
|
+
import { CheckIcon, ChevronRightIcon } from "lucide-react"
|
|
10435
11820
|
|
|
10436
|
-
function
|
|
11821
|
+
function DropdownMenu({
|
|
10437
11822
|
...props
|
|
10438
|
-
}: React.ComponentProps<typeof
|
|
10439
|
-
return <
|
|
11823
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
11824
|
+
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
10440
11825
|
}
|
|
10441
11826
|
|
|
10442
|
-
function
|
|
10443
|
-
className,
|
|
11827
|
+
function DropdownMenuPortal({
|
|
10444
11828
|
...props
|
|
10445
|
-
}: React.ComponentProps<typeof
|
|
11829
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
10446
11830
|
return (
|
|
10447
|
-
<
|
|
10448
|
-
|
|
10449
|
-
|
|
11831
|
+
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
11832
|
+
)
|
|
11833
|
+
}
|
|
11834
|
+
|
|
11835
|
+
function DropdownMenuTrigger({
|
|
11836
|
+
...props
|
|
11837
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
11838
|
+
return (
|
|
11839
|
+
<DropdownMenuPrimitive.Trigger
|
|
11840
|
+
data-slot="dropdown-menu-trigger"
|
|
10450
11841
|
{...props}
|
|
10451
11842
|
/>
|
|
10452
11843
|
)
|
|
10453
11844
|
}
|
|
10454
11845
|
|
|
10455
|
-
function
|
|
11846
|
+
function DropdownMenuContent({
|
|
11847
|
+
className,
|
|
11848
|
+
align = "start",
|
|
11849
|
+
sideOffset = 4,
|
|
10456
11850
|
...props
|
|
10457
|
-
}: React.ComponentProps<typeof
|
|
10458
|
-
return
|
|
11851
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
11852
|
+
return (
|
|
11853
|
+
<DropdownMenuPrimitive.Portal>
|
|
11854
|
+
<DropdownMenuPrimitive.Content
|
|
11855
|
+
data-slot="dropdown-menu-content"
|
|
11856
|
+
sideOffset={sideOffset}
|
|
11857
|
+
align={align}
|
|
11858
|
+
className={cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:overflow-hidden data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
|
|
11859
|
+
{...props}
|
|
11860
|
+
/>
|
|
11861
|
+
</DropdownMenuPrimitive.Portal>
|
|
11862
|
+
)
|
|
10459
11863
|
}
|
|
10460
11864
|
|
|
10461
|
-
function
|
|
11865
|
+
function DropdownMenuGroup({
|
|
11866
|
+
...props
|
|
11867
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
11868
|
+
return (
|
|
11869
|
+
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
11870
|
+
)
|
|
11871
|
+
}
|
|
11872
|
+
|
|
11873
|
+
function DropdownMenuItem({
|
|
11874
|
+
className,
|
|
11875
|
+
inset,
|
|
11876
|
+
variant = "default",
|
|
11877
|
+
...props
|
|
11878
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
11879
|
+
inset?: boolean
|
|
11880
|
+
variant?: "default" | "destructive"
|
|
11881
|
+
}) {
|
|
11882
|
+
return (
|
|
11883
|
+
<DropdownMenuPrimitive.Item
|
|
11884
|
+
data-slot="dropdown-menu-item"
|
|
11885
|
+
data-inset={inset}
|
|
11886
|
+
data-variant={variant}
|
|
11887
|
+
className={cn(
|
|
11888
|
+
"group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
|
|
11889
|
+
className
|
|
11890
|
+
)}
|
|
11891
|
+
{...props}
|
|
11892
|
+
/>
|
|
11893
|
+
)
|
|
11894
|
+
}
|
|
11895
|
+
|
|
11896
|
+
function DropdownMenuCheckboxItem({
|
|
10462
11897
|
className,
|
|
10463
|
-
size = "default",
|
|
10464
11898
|
children,
|
|
11899
|
+
checked,
|
|
11900
|
+
inset,
|
|
10465
11901
|
...props
|
|
10466
|
-
}: React.ComponentProps<typeof
|
|
10467
|
-
|
|
11902
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {
|
|
11903
|
+
inset?: boolean
|
|
10468
11904
|
}) {
|
|
10469
11905
|
return (
|
|
10470
|
-
<
|
|
10471
|
-
data-slot="
|
|
10472
|
-
data-
|
|
11906
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
11907
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
11908
|
+
data-inset={inset}
|
|
10473
11909
|
className={cn(
|
|
10474
|
-
"
|
|
11910
|
+
"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
10475
11911
|
className
|
|
10476
11912
|
)}
|
|
11913
|
+
checked={checked}
|
|
10477
11914
|
{...props}
|
|
10478
11915
|
>
|
|
11916
|
+
<span
|
|
11917
|
+
className="pointer-events-none absolute right-2 flex items-center justify-center"
|
|
11918
|
+
data-slot="dropdown-menu-checkbox-item-indicator"
|
|
11919
|
+
>
|
|
11920
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
11921
|
+
<CheckIcon
|
|
11922
|
+
/>
|
|
11923
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
11924
|
+
</span>
|
|
10479
11925
|
{children}
|
|
10480
|
-
|
|
10481
|
-
<ChevronDownIcon className="text-muted-foreground size-4 pointer-events-none" />
|
|
10482
|
-
</SelectPrimitive.Icon>
|
|
10483
|
-
</SelectPrimitive.Trigger>
|
|
11926
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
10484
11927
|
)
|
|
10485
11928
|
}
|
|
10486
11929
|
|
|
10487
|
-
function
|
|
10488
|
-
className,
|
|
10489
|
-
children,
|
|
10490
|
-
position = "popper",
|
|
10491
|
-
align = "center",
|
|
11930
|
+
function DropdownMenuRadioGroup({
|
|
10492
11931
|
...props
|
|
10493
|
-
}: React.ComponentProps<typeof
|
|
11932
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
10494
11933
|
return (
|
|
10495
|
-
<
|
|
10496
|
-
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
11934
|
+
<DropdownMenuPrimitive.RadioGroup
|
|
11935
|
+
data-slot="dropdown-menu-radio-group"
|
|
11936
|
+
{...props}
|
|
11937
|
+
/>
|
|
11938
|
+
)
|
|
11939
|
+
}
|
|
11940
|
+
|
|
11941
|
+
function DropdownMenuRadioItem({
|
|
11942
|
+
className,
|
|
11943
|
+
children,
|
|
11944
|
+
inset,
|
|
11945
|
+
...props
|
|
11946
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {
|
|
11947
|
+
inset?: boolean
|
|
11948
|
+
}) {
|
|
11949
|
+
return (
|
|
11950
|
+
<DropdownMenuPrimitive.RadioItem
|
|
11951
|
+
data-slot="dropdown-menu-radio-item"
|
|
11952
|
+
data-inset={inset}
|
|
11953
|
+
className={cn(
|
|
11954
|
+
"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
11955
|
+
className
|
|
11956
|
+
)}
|
|
11957
|
+
{...props}
|
|
11958
|
+
>
|
|
11959
|
+
<span
|
|
11960
|
+
className="pointer-events-none absolute right-2 flex items-center justify-center"
|
|
11961
|
+
data-slot="dropdown-menu-radio-item-indicator"
|
|
10507
11962
|
>
|
|
10508
|
-
<
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
>
|
|
10516
|
-
{children}
|
|
10517
|
-
</SelectPrimitive.Viewport>
|
|
10518
|
-
<SelectScrollDownButton />
|
|
10519
|
-
</SelectPrimitive.Content>
|
|
10520
|
-
</SelectPrimitive.Portal>
|
|
11963
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
11964
|
+
<CheckIcon
|
|
11965
|
+
/>
|
|
11966
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
11967
|
+
</span>
|
|
11968
|
+
{children}
|
|
11969
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
10521
11970
|
)
|
|
10522
11971
|
}
|
|
10523
11972
|
|
|
10524
|
-
function
|
|
11973
|
+
function DropdownMenuLabel({
|
|
10525
11974
|
className,
|
|
11975
|
+
inset,
|
|
10526
11976
|
...props
|
|
10527
|
-
}: React.ComponentProps<typeof
|
|
11977
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
11978
|
+
inset?: boolean
|
|
11979
|
+
}) {
|
|
10528
11980
|
return (
|
|
10529
|
-
<
|
|
10530
|
-
data-slot="
|
|
10531
|
-
|
|
11981
|
+
<DropdownMenuPrimitive.Label
|
|
11982
|
+
data-slot="dropdown-menu-label"
|
|
11983
|
+
data-inset={inset}
|
|
11984
|
+
className={cn(
|
|
11985
|
+
"px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
|
|
11986
|
+
className
|
|
11987
|
+
)}
|
|
10532
11988
|
{...props}
|
|
10533
11989
|
/>
|
|
10534
11990
|
)
|
|
10535
11991
|
}
|
|
10536
11992
|
|
|
10537
|
-
function
|
|
11993
|
+
function DropdownMenuSeparator({
|
|
11994
|
+
className,
|
|
11995
|
+
...props
|
|
11996
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
11997
|
+
return (
|
|
11998
|
+
<DropdownMenuPrimitive.Separator
|
|
11999
|
+
data-slot="dropdown-menu-separator"
|
|
12000
|
+
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
|
12001
|
+
{...props}
|
|
12002
|
+
/>
|
|
12003
|
+
)
|
|
12004
|
+
}
|
|
12005
|
+
|
|
12006
|
+
function DropdownMenuShortcut({
|
|
12007
|
+
className,
|
|
12008
|
+
...props
|
|
12009
|
+
}: React.ComponentProps<"span">) {
|
|
12010
|
+
return (
|
|
12011
|
+
<span
|
|
12012
|
+
data-slot="dropdown-menu-shortcut"
|
|
12013
|
+
className={cn(
|
|
12014
|
+
"ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
|
|
12015
|
+
className
|
|
12016
|
+
)}
|
|
12017
|
+
{...props}
|
|
12018
|
+
/>
|
|
12019
|
+
)
|
|
12020
|
+
}
|
|
12021
|
+
|
|
12022
|
+
function DropdownMenuSub({
|
|
12023
|
+
...props
|
|
12024
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
12025
|
+
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
|
|
12026
|
+
}
|
|
12027
|
+
|
|
12028
|
+
function DropdownMenuSubTrigger({
|
|
10538
12029
|
className,
|
|
12030
|
+
inset,
|
|
10539
12031
|
children,
|
|
10540
12032
|
...props
|
|
10541
|
-
}: React.ComponentProps<typeof
|
|
12033
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
12034
|
+
inset?: boolean
|
|
12035
|
+
}) {
|
|
10542
12036
|
return (
|
|
10543
|
-
<
|
|
10544
|
-
data-slot="
|
|
12037
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
12038
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
12039
|
+
data-inset={inset}
|
|
10545
12040
|
className={cn(
|
|
10546
|
-
"
|
|
12041
|
+
"flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
10547
12042
|
className
|
|
10548
12043
|
)}
|
|
10549
12044
|
{...props}
|
|
10550
12045
|
>
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10554
|
-
</SelectPrimitive.ItemIndicator>
|
|
10555
|
-
</span>
|
|
10556
|
-
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
10557
|
-
</SelectPrimitive.Item>
|
|
12046
|
+
{children}
|
|
12047
|
+
<ChevronRightIcon className="ml-auto" />
|
|
12048
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
10558
12049
|
)
|
|
10559
12050
|
}
|
|
10560
12051
|
|
|
10561
|
-
function
|
|
12052
|
+
function DropdownMenuSubContent({
|
|
10562
12053
|
className,
|
|
10563
12054
|
...props
|
|
10564
|
-
}: React.ComponentProps<typeof
|
|
12055
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
10565
12056
|
return (
|
|
10566
|
-
<
|
|
10567
|
-
data-slot="
|
|
10568
|
-
className={cn("bg-
|
|
12057
|
+
<DropdownMenuPrimitive.SubContent
|
|
12058
|
+
data-slot="dropdown-menu-sub-content"
|
|
12059
|
+
className={cn("z-50 min-w-[96px] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
|
|
12060
|
+
{...props}
|
|
12061
|
+
/>
|
|
12062
|
+
)
|
|
12063
|
+
}
|
|
12064
|
+
|
|
12065
|
+
export {
|
|
12066
|
+
DropdownMenu,
|
|
12067
|
+
DropdownMenuPortal,
|
|
12068
|
+
DropdownMenuTrigger,
|
|
12069
|
+
DropdownMenuContent,
|
|
12070
|
+
DropdownMenuGroup,
|
|
12071
|
+
DropdownMenuLabel,
|
|
12072
|
+
DropdownMenuItem,
|
|
12073
|
+
DropdownMenuCheckboxItem,
|
|
12074
|
+
DropdownMenuRadioGroup,
|
|
12075
|
+
DropdownMenuRadioItem,
|
|
12076
|
+
DropdownMenuSeparator,
|
|
12077
|
+
DropdownMenuShortcut,
|
|
12078
|
+
DropdownMenuSub,
|
|
12079
|
+
DropdownMenuSubTrigger,
|
|
12080
|
+
DropdownMenuSubContent,
|
|
12081
|
+
}
|
|
12082
|
+
|
|
12083
|
+
|
|
12084
|
+
END_OF_FILE_CONTENT
|
|
12085
|
+
echo "Creating src/components/ui/hover-card.tsx..."
|
|
12086
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/hover-card.tsx"
|
|
12087
|
+
"use client"
|
|
12088
|
+
|
|
12089
|
+
import * as React from "react"
|
|
12090
|
+
import { HoverCard as HoverCardPrimitive } from "radix-ui"
|
|
12091
|
+
|
|
12092
|
+
import { cn } from "@/lib/utils"
|
|
12093
|
+
|
|
12094
|
+
function HoverCard({
|
|
12095
|
+
...props
|
|
12096
|
+
}: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
|
|
12097
|
+
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
|
|
12098
|
+
}
|
|
12099
|
+
|
|
12100
|
+
function HoverCardTrigger({
|
|
12101
|
+
...props
|
|
12102
|
+
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
|
|
12103
|
+
return (
|
|
12104
|
+
<HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
|
|
12105
|
+
)
|
|
12106
|
+
}
|
|
12107
|
+
|
|
12108
|
+
function HoverCardContent({
|
|
12109
|
+
className,
|
|
12110
|
+
align = "center",
|
|
12111
|
+
sideOffset = 4,
|
|
12112
|
+
...props
|
|
12113
|
+
}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
|
|
12114
|
+
return (
|
|
12115
|
+
<HoverCardPrimitive.Portal data-slot="hover-card-portal">
|
|
12116
|
+
<HoverCardPrimitive.Content
|
|
12117
|
+
data-slot="hover-card-content"
|
|
12118
|
+
align={align}
|
|
12119
|
+
sideOffset={sideOffset}
|
|
12120
|
+
className={cn(
|
|
12121
|
+
"z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
12122
|
+
className
|
|
12123
|
+
)}
|
|
12124
|
+
{...props}
|
|
12125
|
+
/>
|
|
12126
|
+
</HoverCardPrimitive.Portal>
|
|
12127
|
+
)
|
|
12128
|
+
}
|
|
12129
|
+
|
|
12130
|
+
export { HoverCard, HoverCardTrigger, HoverCardContent }
|
|
12131
|
+
|
|
12132
|
+
|
|
12133
|
+
END_OF_FILE_CONTENT
|
|
12134
|
+
echo "Creating src/components/ui/input.tsx..."
|
|
12135
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/input.tsx"
|
|
12136
|
+
import * as React from 'react'
|
|
12137
|
+
import { cn } from '@/lib/utils'
|
|
12138
|
+
|
|
12139
|
+
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
12140
|
+
|
|
12141
|
+
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
12142
|
+
({ className, type, ...props }, ref) => {
|
|
12143
|
+
return (
|
|
12144
|
+
<input
|
|
12145
|
+
type={type}
|
|
12146
|
+
className={cn(
|
|
12147
|
+
'flex h-9 w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground',
|
|
12148
|
+
'focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary',
|
|
12149
|
+
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
12150
|
+
'transition-colors duration-150',
|
|
12151
|
+
className
|
|
12152
|
+
)}
|
|
12153
|
+
ref={ref}
|
|
12154
|
+
{...props}
|
|
12155
|
+
/>
|
|
12156
|
+
)
|
|
12157
|
+
}
|
|
12158
|
+
)
|
|
12159
|
+
Input.displayName = 'Input'
|
|
12160
|
+
|
|
12161
|
+
export { Input }
|
|
12162
|
+
|
|
12163
|
+
END_OF_FILE_CONTENT
|
|
12164
|
+
echo "Creating src/components/ui/label.tsx..."
|
|
12165
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/label.tsx"
|
|
12166
|
+
import * as React from 'react'
|
|
12167
|
+
import { cn } from '@/lib/utils'
|
|
12168
|
+
|
|
12169
|
+
const Label = React.forwardRef<
|
|
12170
|
+
HTMLLabelElement,
|
|
12171
|
+
React.LabelHTMLAttributes<HTMLLabelElement>
|
|
12172
|
+
>(({ className, ...props }, ref) => (
|
|
12173
|
+
<label
|
|
12174
|
+
ref={ref}
|
|
12175
|
+
className={cn('block text-xs font-medium text-foreground mb-1.5 cursor-default', className)}
|
|
12176
|
+
{...props}
|
|
12177
|
+
/>
|
|
12178
|
+
))
|
|
12179
|
+
Label.displayName = 'Label'
|
|
12180
|
+
|
|
12181
|
+
export { Label }
|
|
12182
|
+
|
|
12183
|
+
END_OF_FILE_CONTENT
|
|
12184
|
+
echo "Creating src/components/ui/navigation-menu.tsx..."
|
|
12185
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/navigation-menu.tsx"
|
|
12186
|
+
import * as React from "react"
|
|
12187
|
+
import { cva } from "class-variance-authority"
|
|
12188
|
+
import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui"
|
|
12189
|
+
|
|
12190
|
+
import { cn } from "@/lib/utils"
|
|
12191
|
+
import { ChevronDownIcon } from "lucide-react"
|
|
12192
|
+
|
|
12193
|
+
function NavigationMenu({
|
|
12194
|
+
className,
|
|
12195
|
+
children,
|
|
12196
|
+
viewport = true,
|
|
12197
|
+
...props
|
|
12198
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
|
|
12199
|
+
viewport?: boolean
|
|
12200
|
+
}) {
|
|
12201
|
+
return (
|
|
12202
|
+
<NavigationMenuPrimitive.Root
|
|
12203
|
+
data-slot="navigation-menu"
|
|
12204
|
+
data-viewport={viewport}
|
|
12205
|
+
className={cn(
|
|
12206
|
+
"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
|
|
12207
|
+
className
|
|
12208
|
+
)}
|
|
12209
|
+
{...props}
|
|
12210
|
+
>
|
|
12211
|
+
{children}
|
|
12212
|
+
{viewport && <NavigationMenuViewport />}
|
|
12213
|
+
</NavigationMenuPrimitive.Root>
|
|
12214
|
+
)
|
|
12215
|
+
}
|
|
12216
|
+
|
|
12217
|
+
function NavigationMenuList({
|
|
12218
|
+
className,
|
|
12219
|
+
...props
|
|
12220
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
|
|
12221
|
+
return (
|
|
12222
|
+
<NavigationMenuPrimitive.List
|
|
12223
|
+
data-slot="navigation-menu-list"
|
|
12224
|
+
className={cn(
|
|
12225
|
+
"group flex flex-1 list-none items-center justify-center gap-0",
|
|
12226
|
+
className
|
|
12227
|
+
)}
|
|
12228
|
+
{...props}
|
|
12229
|
+
/>
|
|
12230
|
+
)
|
|
12231
|
+
}
|
|
12232
|
+
|
|
12233
|
+
function NavigationMenuItem({
|
|
12234
|
+
className,
|
|
12235
|
+
...props
|
|
12236
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
|
|
12237
|
+
return (
|
|
12238
|
+
<NavigationMenuPrimitive.Item
|
|
12239
|
+
data-slot="navigation-menu-item"
|
|
12240
|
+
className={cn("relative", className)}
|
|
12241
|
+
{...props}
|
|
12242
|
+
/>
|
|
12243
|
+
)
|
|
12244
|
+
}
|
|
12245
|
+
|
|
12246
|
+
const navigationMenuTriggerStyle = cva(
|
|
12247
|
+
"group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center rounded-lg px-2.5 py-1.5 text-sm font-medium transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-popup-open:bg-muted/50 data-popup-open:hover:bg-muted data-open:bg-muted/50 data-open:hover:bg-muted data-open:focus:bg-muted"
|
|
12248
|
+
)
|
|
12249
|
+
|
|
12250
|
+
function NavigationMenuTrigger({
|
|
12251
|
+
className,
|
|
12252
|
+
children,
|
|
12253
|
+
...props
|
|
12254
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
|
|
12255
|
+
return (
|
|
12256
|
+
<NavigationMenuPrimitive.Trigger
|
|
12257
|
+
data-slot="navigation-menu-trigger"
|
|
12258
|
+
className={cn(navigationMenuTriggerStyle(), "group", className)}
|
|
12259
|
+
{...props}
|
|
12260
|
+
>
|
|
12261
|
+
{children}{" "}
|
|
12262
|
+
<ChevronDownIcon className="relative top-px ml-1 size-3 transition duration-300 group-data-popup-open/navigation-menu-trigger:rotate-180 group-data-open/navigation-menu-trigger:rotate-180" aria-hidden="true" />
|
|
12263
|
+
</NavigationMenuPrimitive.Trigger>
|
|
12264
|
+
)
|
|
12265
|
+
}
|
|
12266
|
+
|
|
12267
|
+
function NavigationMenuContent({
|
|
12268
|
+
className,
|
|
12269
|
+
...props
|
|
12270
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
|
|
12271
|
+
return (
|
|
12272
|
+
<NavigationMenuPrimitive.Content
|
|
12273
|
+
data-slot="navigation-menu-content"
|
|
12274
|
+
className={cn(
|
|
12275
|
+
"top-0 left-0 w-full p-1 ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-lg group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:ring-foreground/10 group-data-[viewport=false]/navigation-menu:duration-300 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none md:absolute md:w-auto group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95",
|
|
12276
|
+
className
|
|
12277
|
+
)}
|
|
10569
12278
|
{...props}
|
|
10570
12279
|
/>
|
|
10571
12280
|
)
|
|
10572
12281
|
}
|
|
10573
12282
|
|
|
10574
|
-
function
|
|
12283
|
+
function NavigationMenuViewport({
|
|
12284
|
+
className,
|
|
12285
|
+
...props
|
|
12286
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
|
|
12287
|
+
return (
|
|
12288
|
+
<div
|
|
12289
|
+
className={cn(
|
|
12290
|
+
"absolute top-full left-0 isolate z-50 flex justify-center"
|
|
12291
|
+
)}
|
|
12292
|
+
>
|
|
12293
|
+
<NavigationMenuPrimitive.Viewport
|
|
12294
|
+
data-slot="navigation-menu-viewport"
|
|
12295
|
+
className={cn(
|
|
12296
|
+
"origin-top-center relative mt-1.5 h-(--radix-navigation-menu-viewport-height) w-full overflow-hidden rounded-lg bg-popover text-popover-foreground shadow ring-1 ring-foreground/10 duration-100 md:w-(--radix-navigation-menu-viewport-width) data-open:animate-in data-open:zoom-in-90 data-closed:animate-out data-closed:zoom-out-90",
|
|
12297
|
+
className
|
|
12298
|
+
)}
|
|
12299
|
+
{...props}
|
|
12300
|
+
/>
|
|
12301
|
+
</div>
|
|
12302
|
+
)
|
|
12303
|
+
}
|
|
12304
|
+
|
|
12305
|
+
function NavigationMenuLink({
|
|
12306
|
+
className,
|
|
12307
|
+
...props
|
|
12308
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
|
|
12309
|
+
return (
|
|
12310
|
+
<NavigationMenuPrimitive.Link
|
|
12311
|
+
data-slot="navigation-menu-link"
|
|
12312
|
+
className={cn(
|
|
12313
|
+
"flex items-center gap-2 rounded-lg p-2 text-sm transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 in-data-[slot=navigation-menu-content]:rounded-md data-active:bg-muted/50 data-active:hover:bg-muted data-active:focus:bg-muted [&_svg:not([class*='size-'])]:size-4",
|
|
12314
|
+
className
|
|
12315
|
+
)}
|
|
12316
|
+
{...props}
|
|
12317
|
+
/>
|
|
12318
|
+
)
|
|
12319
|
+
}
|
|
12320
|
+
|
|
12321
|
+
function NavigationMenuIndicator({
|
|
12322
|
+
className,
|
|
12323
|
+
...props
|
|
12324
|
+
}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
|
|
12325
|
+
return (
|
|
12326
|
+
<NavigationMenuPrimitive.Indicator
|
|
12327
|
+
data-slot="navigation-menu-indicator"
|
|
12328
|
+
className={cn(
|
|
12329
|
+
"top-full z-1 flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in",
|
|
12330
|
+
className
|
|
12331
|
+
)}
|
|
12332
|
+
{...props}
|
|
12333
|
+
>
|
|
12334
|
+
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
|
|
12335
|
+
</NavigationMenuPrimitive.Indicator>
|
|
12336
|
+
)
|
|
12337
|
+
}
|
|
12338
|
+
|
|
12339
|
+
export {
|
|
12340
|
+
NavigationMenu,
|
|
12341
|
+
NavigationMenuList,
|
|
12342
|
+
NavigationMenuItem,
|
|
12343
|
+
NavigationMenuContent,
|
|
12344
|
+
NavigationMenuTrigger,
|
|
12345
|
+
NavigationMenuLink,
|
|
12346
|
+
NavigationMenuIndicator,
|
|
12347
|
+
NavigationMenuViewport,
|
|
12348
|
+
navigationMenuTriggerStyle,
|
|
12349
|
+
}
|
|
12350
|
+
|
|
12351
|
+
|
|
12352
|
+
END_OF_FILE_CONTENT
|
|
12353
|
+
echo "Creating src/components/ui/progress.tsx..."
|
|
12354
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/progress.tsx"
|
|
12355
|
+
import * as React from "react"
|
|
12356
|
+
import { Progress as ProgressPrimitive } from "radix-ui"
|
|
12357
|
+
|
|
12358
|
+
import { cn } from "@/lib/utils"
|
|
12359
|
+
|
|
12360
|
+
function Progress({
|
|
12361
|
+
className,
|
|
12362
|
+
value,
|
|
12363
|
+
...props
|
|
12364
|
+
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
|
|
12365
|
+
return (
|
|
12366
|
+
<ProgressPrimitive.Root
|
|
12367
|
+
data-slot="progress"
|
|
12368
|
+
className={cn(
|
|
12369
|
+
"relative flex h-1 w-full items-center overflow-x-hidden rounded-full bg-muted",
|
|
12370
|
+
className
|
|
12371
|
+
)}
|
|
12372
|
+
{...props}
|
|
12373
|
+
>
|
|
12374
|
+
<ProgressPrimitive.Indicator
|
|
12375
|
+
data-slot="progress-indicator"
|
|
12376
|
+
className="size-full flex-1 bg-primary transition-all"
|
|
12377
|
+
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
|
12378
|
+
/>
|
|
12379
|
+
</ProgressPrimitive.Root>
|
|
12380
|
+
)
|
|
12381
|
+
}
|
|
12382
|
+
|
|
12383
|
+
export { Progress }
|
|
12384
|
+
|
|
12385
|
+
|
|
12386
|
+
END_OF_FILE_CONTENT
|
|
12387
|
+
echo "Creating src/components/ui/scroll-area.tsx..."
|
|
12388
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/scroll-area.tsx"
|
|
12389
|
+
import * as React from "react"
|
|
12390
|
+
import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
|
|
12391
|
+
|
|
12392
|
+
import { cn } from "@/lib/utils"
|
|
12393
|
+
|
|
12394
|
+
function ScrollArea({
|
|
12395
|
+
className,
|
|
12396
|
+
children,
|
|
12397
|
+
...props
|
|
12398
|
+
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
|
12399
|
+
return (
|
|
12400
|
+
<ScrollAreaPrimitive.Root
|
|
12401
|
+
data-slot="scroll-area"
|
|
12402
|
+
className={cn("relative", className)}
|
|
12403
|
+
{...props}
|
|
12404
|
+
>
|
|
12405
|
+
<ScrollAreaPrimitive.Viewport
|
|
12406
|
+
data-slot="scroll-area-viewport"
|
|
12407
|
+
className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
|
|
12408
|
+
>
|
|
12409
|
+
{children}
|
|
12410
|
+
</ScrollAreaPrimitive.Viewport>
|
|
12411
|
+
<ScrollBar />
|
|
12412
|
+
<ScrollAreaPrimitive.Corner />
|
|
12413
|
+
</ScrollAreaPrimitive.Root>
|
|
12414
|
+
)
|
|
12415
|
+
}
|
|
12416
|
+
|
|
12417
|
+
function ScrollBar({
|
|
12418
|
+
className,
|
|
12419
|
+
orientation = "vertical",
|
|
12420
|
+
...props
|
|
12421
|
+
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
|
|
12422
|
+
return (
|
|
12423
|
+
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
12424
|
+
data-slot="scroll-area-scrollbar"
|
|
12425
|
+
data-orientation={orientation}
|
|
12426
|
+
orientation={orientation}
|
|
12427
|
+
className={cn(
|
|
12428
|
+
"flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent",
|
|
12429
|
+
className
|
|
12430
|
+
)}
|
|
12431
|
+
{...props}
|
|
12432
|
+
>
|
|
12433
|
+
<ScrollAreaPrimitive.ScrollAreaThumb
|
|
12434
|
+
data-slot="scroll-area-thumb"
|
|
12435
|
+
className="relative flex-1 rounded-full bg-border"
|
|
12436
|
+
/>
|
|
12437
|
+
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
12438
|
+
)
|
|
12439
|
+
}
|
|
12440
|
+
|
|
12441
|
+
export { ScrollArea, ScrollBar }
|
|
12442
|
+
|
|
12443
|
+
|
|
12444
|
+
END_OF_FILE_CONTENT
|
|
12445
|
+
echo "Creating src/components/ui/select.tsx..."
|
|
12446
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/select.tsx"
|
|
12447
|
+
import * as React from "react"
|
|
12448
|
+
import { Select as SelectPrimitive } from "radix-ui"
|
|
12449
|
+
|
|
12450
|
+
import { cn } from "@/lib/utils"
|
|
12451
|
+
import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
|
|
12452
|
+
|
|
12453
|
+
function Select({
|
|
12454
|
+
...props
|
|
12455
|
+
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
|
12456
|
+
return <SelectPrimitive.Root data-slot="select" {...props} />
|
|
12457
|
+
}
|
|
12458
|
+
|
|
12459
|
+
function SelectGroup({
|
|
12460
|
+
className,
|
|
12461
|
+
...props
|
|
12462
|
+
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
|
12463
|
+
return (
|
|
12464
|
+
<SelectPrimitive.Group
|
|
12465
|
+
data-slot="select-group"
|
|
12466
|
+
className={cn("scroll-my-1 p-1", className)}
|
|
12467
|
+
{...props}
|
|
12468
|
+
/>
|
|
12469
|
+
)
|
|
12470
|
+
}
|
|
12471
|
+
|
|
12472
|
+
function SelectValue({
|
|
12473
|
+
...props
|
|
12474
|
+
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
|
12475
|
+
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
|
12476
|
+
}
|
|
12477
|
+
|
|
12478
|
+
function SelectTrigger({
|
|
12479
|
+
className,
|
|
12480
|
+
size = "default",
|
|
12481
|
+
children,
|
|
12482
|
+
...props
|
|
12483
|
+
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
12484
|
+
size?: "sm" | "default"
|
|
12485
|
+
}) {
|
|
12486
|
+
return (
|
|
12487
|
+
<SelectPrimitive.Trigger
|
|
12488
|
+
data-slot="select-trigger"
|
|
12489
|
+
data-size={size}
|
|
12490
|
+
className={cn(
|
|
12491
|
+
"border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-lg border bg-transparent py-2 pr-2 pl-2.5 text-sm transition-colors select-none focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-4 flex w-full items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
12492
|
+
className
|
|
12493
|
+
)}
|
|
12494
|
+
{...props}
|
|
12495
|
+
>
|
|
12496
|
+
{children}
|
|
12497
|
+
<SelectPrimitive.Icon asChild>
|
|
12498
|
+
<ChevronDownIcon className="text-muted-foreground size-4 pointer-events-none" />
|
|
12499
|
+
</SelectPrimitive.Icon>
|
|
12500
|
+
</SelectPrimitive.Trigger>
|
|
12501
|
+
)
|
|
12502
|
+
}
|
|
12503
|
+
|
|
12504
|
+
function SelectContent({
|
|
12505
|
+
className,
|
|
12506
|
+
children,
|
|
12507
|
+
position = "popper",
|
|
12508
|
+
align = "center",
|
|
12509
|
+
...props
|
|
12510
|
+
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
|
12511
|
+
return (
|
|
12512
|
+
<SelectPrimitive.Portal>
|
|
12513
|
+
<SelectPrimitive.Content
|
|
12514
|
+
data-slot="select-content"
|
|
12515
|
+
data-align-trigger={position === "item-aligned"}
|
|
12516
|
+
className={cn(
|
|
12517
|
+
"bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 min-w-36 rounded-lg shadow-md ring-1 duration-100 relative z-[110] max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto data-[align-trigger=true]:animate-none",
|
|
12518
|
+
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
12519
|
+
className
|
|
12520
|
+
)}
|
|
12521
|
+
position={position}
|
|
12522
|
+
align={align}
|
|
12523
|
+
{...props}
|
|
12524
|
+
>
|
|
12525
|
+
<SelectScrollUpButton />
|
|
12526
|
+
<SelectPrimitive.Viewport
|
|
12527
|
+
data-position={position}
|
|
12528
|
+
className={cn(
|
|
12529
|
+
"p-1",
|
|
12530
|
+
position === "popper" && "h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width)"
|
|
12531
|
+
)}
|
|
12532
|
+
>
|
|
12533
|
+
{children}
|
|
12534
|
+
</SelectPrimitive.Viewport>
|
|
12535
|
+
<SelectScrollDownButton />
|
|
12536
|
+
</SelectPrimitive.Content>
|
|
12537
|
+
</SelectPrimitive.Portal>
|
|
12538
|
+
)
|
|
12539
|
+
}
|
|
12540
|
+
|
|
12541
|
+
function SelectLabel({
|
|
12542
|
+
className,
|
|
12543
|
+
...props
|
|
12544
|
+
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
|
12545
|
+
return (
|
|
12546
|
+
<SelectPrimitive.Label
|
|
12547
|
+
data-slot="select-label"
|
|
12548
|
+
className={cn("text-muted-foreground px-1.5 py-1 text-xs", className)}
|
|
12549
|
+
{...props}
|
|
12550
|
+
/>
|
|
12551
|
+
)
|
|
12552
|
+
}
|
|
12553
|
+
|
|
12554
|
+
function SelectItem({
|
|
12555
|
+
className,
|
|
12556
|
+
children,
|
|
12557
|
+
...props
|
|
12558
|
+
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
|
12559
|
+
return (
|
|
12560
|
+
<SelectPrimitive.Item
|
|
12561
|
+
data-slot="select-item"
|
|
12562
|
+
className={cn(
|
|
12563
|
+
"focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
12564
|
+
className
|
|
12565
|
+
)}
|
|
12566
|
+
{...props}
|
|
12567
|
+
>
|
|
12568
|
+
<span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center">
|
|
12569
|
+
<SelectPrimitive.ItemIndicator>
|
|
12570
|
+
<CheckIcon className="pointer-events-none" />
|
|
12571
|
+
</SelectPrimitive.ItemIndicator>
|
|
12572
|
+
</span>
|
|
12573
|
+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
12574
|
+
</SelectPrimitive.Item>
|
|
12575
|
+
)
|
|
12576
|
+
}
|
|
12577
|
+
|
|
12578
|
+
function SelectSeparator({
|
|
12579
|
+
className,
|
|
12580
|
+
...props
|
|
12581
|
+
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
|
12582
|
+
return (
|
|
12583
|
+
<SelectPrimitive.Separator
|
|
12584
|
+
data-slot="select-separator"
|
|
12585
|
+
className={cn("bg-border -mx-1 my-1 h-px pointer-events-none", className)}
|
|
12586
|
+
{...props}
|
|
12587
|
+
/>
|
|
12588
|
+
)
|
|
12589
|
+
}
|
|
12590
|
+
|
|
12591
|
+
function SelectScrollUpButton({
|
|
12592
|
+
className,
|
|
12593
|
+
...props
|
|
12594
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
|
12595
|
+
return (
|
|
12596
|
+
<SelectPrimitive.ScrollUpButton
|
|
12597
|
+
data-slot="select-scroll-up-button"
|
|
12598
|
+
className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4", className)}
|
|
12599
|
+
{...props}
|
|
12600
|
+
>
|
|
12601
|
+
<ChevronUpIcon />
|
|
12602
|
+
</SelectPrimitive.ScrollUpButton>
|
|
12603
|
+
)
|
|
12604
|
+
}
|
|
12605
|
+
|
|
12606
|
+
function SelectScrollDownButton({
|
|
12607
|
+
className,
|
|
12608
|
+
...props
|
|
12609
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
|
12610
|
+
return (
|
|
12611
|
+
<SelectPrimitive.ScrollDownButton
|
|
12612
|
+
data-slot="select-scroll-down-button"
|
|
12613
|
+
className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4", className)}
|
|
12614
|
+
{...props}
|
|
12615
|
+
>
|
|
12616
|
+
<ChevronDownIcon />
|
|
12617
|
+
</SelectPrimitive.ScrollDownButton>
|
|
12618
|
+
)
|
|
12619
|
+
}
|
|
12620
|
+
|
|
12621
|
+
export {
|
|
12622
|
+
Select,
|
|
12623
|
+
SelectContent,
|
|
12624
|
+
SelectGroup,
|
|
12625
|
+
SelectItem,
|
|
12626
|
+
SelectLabel,
|
|
12627
|
+
SelectScrollDownButton,
|
|
12628
|
+
SelectScrollUpButton,
|
|
12629
|
+
SelectSeparator,
|
|
12630
|
+
SelectTrigger,
|
|
12631
|
+
SelectValue,
|
|
12632
|
+
}
|
|
12633
|
+
|
|
12634
|
+
|
|
12635
|
+
|
|
12636
|
+
|
|
12637
|
+
END_OF_FILE_CONTENT
|
|
12638
|
+
echo "Creating src/components/ui/select.txt..."
|
|
12639
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/select.txt"
|
|
12640
|
+
import * as React from "react"
|
|
12641
|
+
import { Select as SelectPrimitive } from "radix-ui"
|
|
12642
|
+
|
|
12643
|
+
import { cn } from "@/lib/utils"
|
|
12644
|
+
import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
|
|
12645
|
+
|
|
12646
|
+
function Select({
|
|
12647
|
+
...props
|
|
12648
|
+
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
|
12649
|
+
return <SelectPrimitive.Root data-slot="select" {...props} />
|
|
12650
|
+
}
|
|
12651
|
+
|
|
12652
|
+
function SelectGroup({
|
|
12653
|
+
className,
|
|
12654
|
+
...props
|
|
12655
|
+
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
|
12656
|
+
return (
|
|
12657
|
+
<SelectPrimitive.Group
|
|
12658
|
+
data-slot="select-group"
|
|
12659
|
+
className={cn("scroll-my-1 p-1", className)}
|
|
12660
|
+
{...props}
|
|
12661
|
+
/>
|
|
12662
|
+
)
|
|
12663
|
+
}
|
|
12664
|
+
|
|
12665
|
+
function SelectValue({
|
|
12666
|
+
...props
|
|
12667
|
+
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
|
12668
|
+
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
|
12669
|
+
}
|
|
12670
|
+
|
|
12671
|
+
function SelectTrigger({
|
|
12672
|
+
className,
|
|
12673
|
+
size = "default",
|
|
12674
|
+
children,
|
|
12675
|
+
...props
|
|
12676
|
+
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
12677
|
+
size?: "sm" | "default"
|
|
12678
|
+
}) {
|
|
12679
|
+
return (
|
|
12680
|
+
<SelectPrimitive.Trigger
|
|
12681
|
+
data-slot="select-trigger"
|
|
12682
|
+
data-size={size}
|
|
12683
|
+
className={cn(
|
|
12684
|
+
"border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-lg border bg-transparent py-2 pr-2 pl-2.5 text-sm transition-colors select-none focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-4 flex w-full items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
12685
|
+
className
|
|
12686
|
+
)}
|
|
12687
|
+
{...props}
|
|
12688
|
+
>
|
|
12689
|
+
{children}
|
|
12690
|
+
<SelectPrimitive.Icon asChild>
|
|
12691
|
+
<ChevronDownIcon className="text-muted-foreground size-4 pointer-events-none" />
|
|
12692
|
+
</SelectPrimitive.Icon>
|
|
12693
|
+
</SelectPrimitive.Trigger>
|
|
12694
|
+
)
|
|
12695
|
+
}
|
|
12696
|
+
|
|
12697
|
+
function SelectContent({
|
|
12698
|
+
className,
|
|
12699
|
+
children,
|
|
12700
|
+
position = "popper",
|
|
12701
|
+
align = "center",
|
|
12702
|
+
...props
|
|
12703
|
+
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
|
12704
|
+
return (
|
|
12705
|
+
<SelectPrimitive.Portal>
|
|
12706
|
+
<SelectPrimitive.Content
|
|
12707
|
+
data-slot="select-content"
|
|
12708
|
+
data-align-trigger={position === "item-aligned"}
|
|
12709
|
+
className={cn(
|
|
12710
|
+
"bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 min-w-36 rounded-lg shadow-md ring-1 duration-100 relative z-[110] max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto data-[align-trigger=true]:animate-none",
|
|
12711
|
+
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
12712
|
+
className
|
|
12713
|
+
)}
|
|
12714
|
+
position={position}
|
|
12715
|
+
align={align}
|
|
12716
|
+
{...props}
|
|
12717
|
+
>
|
|
12718
|
+
<SelectScrollUpButton />
|
|
12719
|
+
<SelectPrimitive.Viewport
|
|
12720
|
+
data-position={position}
|
|
12721
|
+
className={cn(
|
|
12722
|
+
"p-1",
|
|
12723
|
+
position === "popper" && "h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width)"
|
|
12724
|
+
)}
|
|
12725
|
+
>
|
|
12726
|
+
{children}
|
|
12727
|
+
</SelectPrimitive.Viewport>
|
|
12728
|
+
<SelectScrollDownButton />
|
|
12729
|
+
</SelectPrimitive.Content>
|
|
12730
|
+
</SelectPrimitive.Portal>
|
|
12731
|
+
)
|
|
12732
|
+
}
|
|
12733
|
+
|
|
12734
|
+
function SelectLabel({
|
|
12735
|
+
className,
|
|
12736
|
+
...props
|
|
12737
|
+
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
|
12738
|
+
return (
|
|
12739
|
+
<SelectPrimitive.Label
|
|
12740
|
+
data-slot="select-label"
|
|
12741
|
+
className={cn("text-muted-foreground px-1.5 py-1 text-xs", className)}
|
|
12742
|
+
{...props}
|
|
12743
|
+
/>
|
|
12744
|
+
)
|
|
12745
|
+
}
|
|
12746
|
+
|
|
12747
|
+
function SelectItem({
|
|
12748
|
+
className,
|
|
12749
|
+
children,
|
|
12750
|
+
...props
|
|
12751
|
+
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
|
12752
|
+
return (
|
|
12753
|
+
<SelectPrimitive.Item
|
|
12754
|
+
data-slot="select-item"
|
|
12755
|
+
className={cn(
|
|
12756
|
+
"focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
12757
|
+
className
|
|
12758
|
+
)}
|
|
12759
|
+
{...props}
|
|
12760
|
+
>
|
|
12761
|
+
<span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center">
|
|
12762
|
+
<SelectPrimitive.ItemIndicator>
|
|
12763
|
+
<CheckIcon className="pointer-events-none" />
|
|
12764
|
+
</SelectPrimitive.ItemIndicator>
|
|
12765
|
+
</span>
|
|
12766
|
+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
12767
|
+
</SelectPrimitive.Item>
|
|
12768
|
+
)
|
|
12769
|
+
}
|
|
12770
|
+
|
|
12771
|
+
function SelectSeparator({
|
|
12772
|
+
className,
|
|
12773
|
+
...props
|
|
12774
|
+
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
|
12775
|
+
return (
|
|
12776
|
+
<SelectPrimitive.Separator
|
|
12777
|
+
data-slot="select-separator"
|
|
12778
|
+
className={cn("bg-border -mx-1 my-1 h-px pointer-events-none", className)}
|
|
12779
|
+
{...props}
|
|
12780
|
+
/>
|
|
12781
|
+
)
|
|
12782
|
+
}
|
|
12783
|
+
|
|
12784
|
+
function SelectScrollUpButton({
|
|
12785
|
+
className,
|
|
12786
|
+
...props
|
|
12787
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
|
12788
|
+
return (
|
|
12789
|
+
<SelectPrimitive.ScrollUpButton
|
|
12790
|
+
data-slot="select-scroll-up-button"
|
|
12791
|
+
className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4", className)}
|
|
12792
|
+
{...props}
|
|
12793
|
+
>
|
|
12794
|
+
<ChevronUpIcon />
|
|
12795
|
+
</SelectPrimitive.ScrollUpButton>
|
|
12796
|
+
)
|
|
12797
|
+
}
|
|
12798
|
+
|
|
12799
|
+
function SelectScrollDownButton({
|
|
12800
|
+
className,
|
|
12801
|
+
...props
|
|
12802
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
|
12803
|
+
return (
|
|
12804
|
+
<SelectPrimitive.ScrollDownButton
|
|
12805
|
+
data-slot="select-scroll-down-button"
|
|
12806
|
+
className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4", className)}
|
|
12807
|
+
{...props}
|
|
12808
|
+
>
|
|
12809
|
+
<ChevronDownIcon />
|
|
12810
|
+
</SelectPrimitive.ScrollDownButton>
|
|
12811
|
+
)
|
|
12812
|
+
}
|
|
12813
|
+
|
|
12814
|
+
export {
|
|
12815
|
+
Select,
|
|
12816
|
+
SelectContent,
|
|
12817
|
+
SelectGroup,
|
|
12818
|
+
SelectItem,
|
|
12819
|
+
SelectLabel,
|
|
12820
|
+
SelectScrollDownButton,
|
|
12821
|
+
SelectScrollUpButton,
|
|
12822
|
+
SelectSeparator,
|
|
12823
|
+
SelectTrigger,
|
|
12824
|
+
SelectValue,
|
|
12825
|
+
}
|
|
12826
|
+
|
|
12827
|
+
|
|
12828
|
+
|
|
12829
|
+
|
|
12830
|
+
END_OF_FILE_CONTENT
|
|
12831
|
+
echo "Creating src/components/ui/separator.tsx..."
|
|
12832
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/separator.tsx"
|
|
12833
|
+
import * as React from 'react'
|
|
12834
|
+
import { cn } from '@/lib/utils'
|
|
12835
|
+
|
|
12836
|
+
const Separator = React.forwardRef<
|
|
12837
|
+
HTMLDivElement,
|
|
12838
|
+
React.HTMLAttributes<HTMLDivElement> & { orientation?: 'horizontal' | 'vertical' }
|
|
12839
|
+
>(({ className, orientation = 'horizontal', ...props }, ref) => (
|
|
12840
|
+
<div
|
|
12841
|
+
ref={ref}
|
|
12842
|
+
className={cn(
|
|
12843
|
+
'shrink-0 bg-border',
|
|
12844
|
+
orientation === 'horizontal' ? 'h-[0.5px] w-full' : 'h-full w-[0.5px]',
|
|
12845
|
+
className
|
|
12846
|
+
)}
|
|
12847
|
+
{...props}
|
|
12848
|
+
/>
|
|
12849
|
+
))
|
|
12850
|
+
Separator.displayName = 'Separator'
|
|
12851
|
+
|
|
12852
|
+
export { Separator }
|
|
12853
|
+
|
|
12854
|
+
END_OF_FILE_CONTENT
|
|
12855
|
+
echo "Creating src/components/ui/sheet.tsx..."
|
|
12856
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/sheet.tsx"
|
|
12857
|
+
"use client"
|
|
12858
|
+
|
|
12859
|
+
import * as React from "react"
|
|
12860
|
+
import { Dialog as SheetPrimitive } from "radix-ui"
|
|
12861
|
+
|
|
12862
|
+
import { cn } from "@/lib/utils"
|
|
12863
|
+
import { Button } from "@/components/ui/button"
|
|
12864
|
+
import { XIcon } from "lucide-react"
|
|
12865
|
+
|
|
12866
|
+
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
|
12867
|
+
return <SheetPrimitive.Root data-slot="sheet" {...props} />
|
|
12868
|
+
}
|
|
12869
|
+
|
|
12870
|
+
function SheetTrigger({
|
|
12871
|
+
...props
|
|
12872
|
+
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
|
|
12873
|
+
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
|
|
12874
|
+
}
|
|
12875
|
+
|
|
12876
|
+
function SheetClose({
|
|
12877
|
+
...props
|
|
12878
|
+
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
|
|
12879
|
+
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
|
|
12880
|
+
}
|
|
12881
|
+
|
|
12882
|
+
function SheetPortal({
|
|
12883
|
+
...props
|
|
12884
|
+
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
|
|
12885
|
+
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
|
|
12886
|
+
}
|
|
12887
|
+
|
|
12888
|
+
function SheetOverlay({
|
|
12889
|
+
className,
|
|
12890
|
+
...props
|
|
12891
|
+
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
|
|
12892
|
+
return (
|
|
12893
|
+
<SheetPrimitive.Overlay
|
|
12894
|
+
data-slot="sheet-overlay"
|
|
12895
|
+
className={cn(
|
|
12896
|
+
"fixed inset-0 z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
12897
|
+
className
|
|
12898
|
+
)}
|
|
12899
|
+
{...props}
|
|
12900
|
+
/>
|
|
12901
|
+
)
|
|
12902
|
+
}
|
|
12903
|
+
|
|
12904
|
+
function SheetContent({
|
|
12905
|
+
className,
|
|
12906
|
+
children,
|
|
12907
|
+
side = "right",
|
|
12908
|
+
showCloseButton = true,
|
|
12909
|
+
...props
|
|
12910
|
+
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
|
12911
|
+
side?: "top" | "right" | "bottom" | "left"
|
|
12912
|
+
showCloseButton?: boolean
|
|
12913
|
+
}) {
|
|
12914
|
+
return (
|
|
12915
|
+
<SheetPortal>
|
|
12916
|
+
<SheetOverlay />
|
|
12917
|
+
<SheetPrimitive.Content
|
|
12918
|
+
data-slot="sheet-content"
|
|
12919
|
+
data-side={side}
|
|
12920
|
+
className={cn(
|
|
12921
|
+
"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-[side=bottom]:data-open:slide-in-from-bottom-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:animate-out data-closed:fade-out-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=right]:data-closed:slide-out-to-right-10 data-[side=top]:data-closed:slide-out-to-top-10",
|
|
12922
|
+
className
|
|
12923
|
+
)}
|
|
12924
|
+
{...props}
|
|
12925
|
+
>
|
|
12926
|
+
{children}
|
|
12927
|
+
{showCloseButton && (
|
|
12928
|
+
<SheetPrimitive.Close data-slot="sheet-close" asChild>
|
|
12929
|
+
<Button
|
|
12930
|
+
variant="ghost"
|
|
12931
|
+
className="absolute top-3 right-3"
|
|
12932
|
+
size="sm"
|
|
12933
|
+
>
|
|
12934
|
+
<XIcon
|
|
12935
|
+
/>
|
|
12936
|
+
<span className="sr-only">Close</span>
|
|
12937
|
+
</Button>
|
|
12938
|
+
</SheetPrimitive.Close>
|
|
12939
|
+
)}
|
|
12940
|
+
</SheetPrimitive.Content>
|
|
12941
|
+
</SheetPortal>
|
|
12942
|
+
)
|
|
12943
|
+
}
|
|
12944
|
+
|
|
12945
|
+
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
12946
|
+
return (
|
|
12947
|
+
<div
|
|
12948
|
+
data-slot="sheet-header"
|
|
12949
|
+
className={cn("flex flex-col gap-0.5 p-4", className)}
|
|
12950
|
+
{...props}
|
|
12951
|
+
/>
|
|
12952
|
+
)
|
|
12953
|
+
}
|
|
12954
|
+
|
|
12955
|
+
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
12956
|
+
return (
|
|
12957
|
+
<div
|
|
12958
|
+
data-slot="sheet-footer"
|
|
12959
|
+
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
|
12960
|
+
{...props}
|
|
12961
|
+
/>
|
|
12962
|
+
)
|
|
12963
|
+
}
|
|
12964
|
+
|
|
12965
|
+
function SheetTitle({
|
|
12966
|
+
className,
|
|
12967
|
+
...props
|
|
12968
|
+
}: React.ComponentProps<typeof SheetPrimitive.Title>) {
|
|
12969
|
+
return (
|
|
12970
|
+
<SheetPrimitive.Title
|
|
12971
|
+
data-slot="sheet-title"
|
|
12972
|
+
className={cn(
|
|
12973
|
+
"text-base font-medium text-foreground",
|
|
12974
|
+
className
|
|
12975
|
+
)}
|
|
12976
|
+
{...props}
|
|
12977
|
+
/>
|
|
12978
|
+
)
|
|
12979
|
+
}
|
|
12980
|
+
|
|
12981
|
+
function SheetDescription({
|
|
12982
|
+
className,
|
|
12983
|
+
...props
|
|
12984
|
+
}: React.ComponentProps<typeof SheetPrimitive.Description>) {
|
|
12985
|
+
return (
|
|
12986
|
+
<SheetPrimitive.Description
|
|
12987
|
+
data-slot="sheet-description"
|
|
12988
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
12989
|
+
{...props}
|
|
12990
|
+
/>
|
|
12991
|
+
)
|
|
12992
|
+
}
|
|
12993
|
+
|
|
12994
|
+
export {
|
|
12995
|
+
Sheet,
|
|
12996
|
+
SheetTrigger,
|
|
12997
|
+
SheetClose,
|
|
12998
|
+
SheetContent,
|
|
12999
|
+
SheetHeader,
|
|
13000
|
+
SheetFooter,
|
|
13001
|
+
SheetTitle,
|
|
13002
|
+
SheetDescription,
|
|
13003
|
+
}
|
|
13004
|
+
|
|
13005
|
+
|
|
13006
|
+
END_OF_FILE_CONTENT
|
|
13007
|
+
echo "Creating src/components/ui/skeleton.tsx..."
|
|
13008
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/skeleton.tsx"
|
|
13009
|
+
import { cn } from '@/lib/utils';
|
|
13010
|
+
import type { HTMLAttributes } from 'react';
|
|
13011
|
+
|
|
13012
|
+
function Skeleton({
|
|
13013
|
+
className,
|
|
13014
|
+
...props
|
|
13015
|
+
}: HTMLAttributes<HTMLDivElement>) {
|
|
13016
|
+
return (
|
|
13017
|
+
<div
|
|
13018
|
+
className={cn('animate-pulse rounded-md bg-muted', className)}
|
|
13019
|
+
{...props}
|
|
13020
|
+
/>
|
|
13021
|
+
);
|
|
13022
|
+
}
|
|
13023
|
+
|
|
13024
|
+
export { Skeleton };
|
|
13025
|
+
|
|
13026
|
+
END_OF_FILE_CONTENT
|
|
13027
|
+
echo "Creating src/components/ui/switch.tsx..."
|
|
13028
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/switch.tsx"
|
|
13029
|
+
import * as React from "react"
|
|
13030
|
+
import { Switch as SwitchPrimitive } from "radix-ui"
|
|
13031
|
+
|
|
13032
|
+
import { cn } from "@/lib/utils"
|
|
13033
|
+
|
|
13034
|
+
function Switch({
|
|
13035
|
+
className,
|
|
13036
|
+
size = "default",
|
|
13037
|
+
...props
|
|
13038
|
+
}: React.ComponentProps<typeof SwitchPrimitive.Root> & {
|
|
13039
|
+
size?: "sm" | "default"
|
|
13040
|
+
}) {
|
|
13041
|
+
return (
|
|
13042
|
+
<SwitchPrimitive.Root
|
|
13043
|
+
data-slot="switch"
|
|
13044
|
+
data-size={size}
|
|
13045
|
+
className={cn(
|
|
13046
|
+
"peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
13047
|
+
className
|
|
13048
|
+
)}
|
|
13049
|
+
{...props}
|
|
13050
|
+
>
|
|
13051
|
+
<SwitchPrimitive.Thumb
|
|
13052
|
+
data-slot="switch-thumb"
|
|
13053
|
+
className="pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground"
|
|
13054
|
+
/>
|
|
13055
|
+
</SwitchPrimitive.Root>
|
|
13056
|
+
)
|
|
13057
|
+
}
|
|
13058
|
+
|
|
13059
|
+
export { Switch }
|
|
13060
|
+
|
|
13061
|
+
|
|
13062
|
+
END_OF_FILE_CONTENT
|
|
13063
|
+
echo "Creating src/components/ui/table.tsx..."
|
|
13064
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/table.tsx"
|
|
13065
|
+
import * as React from "react"
|
|
13066
|
+
|
|
13067
|
+
import { cn } from "@/lib/utils"
|
|
13068
|
+
|
|
13069
|
+
function Table({ className, ...props }: React.ComponentProps<"table">) {
|
|
13070
|
+
return (
|
|
13071
|
+
<div
|
|
13072
|
+
data-slot="table-container"
|
|
13073
|
+
className="relative w-full overflow-x-auto"
|
|
13074
|
+
>
|
|
13075
|
+
<table
|
|
13076
|
+
data-slot="table"
|
|
13077
|
+
className={cn("w-full caption-bottom text-sm", className)}
|
|
13078
|
+
{...props}
|
|
13079
|
+
/>
|
|
13080
|
+
</div>
|
|
13081
|
+
)
|
|
13082
|
+
}
|
|
13083
|
+
|
|
13084
|
+
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
|
|
13085
|
+
return (
|
|
13086
|
+
<thead
|
|
13087
|
+
data-slot="table-header"
|
|
13088
|
+
className={cn("[&_tr]:border-b", className)}
|
|
13089
|
+
{...props}
|
|
13090
|
+
/>
|
|
13091
|
+
)
|
|
13092
|
+
}
|
|
13093
|
+
|
|
13094
|
+
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
|
|
13095
|
+
return (
|
|
13096
|
+
<tbody
|
|
13097
|
+
data-slot="table-body"
|
|
13098
|
+
className={cn("[&_tr:last-child]:border-0", className)}
|
|
13099
|
+
{...props}
|
|
13100
|
+
/>
|
|
13101
|
+
)
|
|
13102
|
+
}
|
|
13103
|
+
|
|
13104
|
+
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
|
|
13105
|
+
return (
|
|
13106
|
+
<tfoot
|
|
13107
|
+
data-slot="table-footer"
|
|
13108
|
+
className={cn(
|
|
13109
|
+
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
|
13110
|
+
className
|
|
13111
|
+
)}
|
|
13112
|
+
{...props}
|
|
13113
|
+
/>
|
|
13114
|
+
)
|
|
13115
|
+
}
|
|
13116
|
+
|
|
13117
|
+
function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
|
|
13118
|
+
return (
|
|
13119
|
+
<tr
|
|
13120
|
+
data-slot="table-row"
|
|
13121
|
+
className={cn(
|
|
13122
|
+
"border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted",
|
|
13123
|
+
className
|
|
13124
|
+
)}
|
|
13125
|
+
{...props}
|
|
13126
|
+
/>
|
|
13127
|
+
)
|
|
13128
|
+
}
|
|
13129
|
+
|
|
13130
|
+
function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
|
13131
|
+
return (
|
|
13132
|
+
<th
|
|
13133
|
+
data-slot="table-head"
|
|
13134
|
+
className={cn(
|
|
13135
|
+
"h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
|
|
13136
|
+
className
|
|
13137
|
+
)}
|
|
13138
|
+
{...props}
|
|
13139
|
+
/>
|
|
13140
|
+
)
|
|
13141
|
+
}
|
|
13142
|
+
|
|
13143
|
+
function TableCell({ className, ...props }: React.ComponentProps<"td">) {
|
|
13144
|
+
return (
|
|
13145
|
+
<td
|
|
13146
|
+
data-slot="table-cell"
|
|
13147
|
+
className={cn(
|
|
13148
|
+
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
|
|
13149
|
+
className
|
|
13150
|
+
)}
|
|
13151
|
+
{...props}
|
|
13152
|
+
/>
|
|
13153
|
+
)
|
|
13154
|
+
}
|
|
13155
|
+
|
|
13156
|
+
function TableCaption({
|
|
13157
|
+
className,
|
|
13158
|
+
...props
|
|
13159
|
+
}: React.ComponentProps<"caption">) {
|
|
13160
|
+
return (
|
|
13161
|
+
<caption
|
|
13162
|
+
data-slot="table-caption"
|
|
13163
|
+
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
|
13164
|
+
{...props}
|
|
13165
|
+
/>
|
|
13166
|
+
)
|
|
13167
|
+
}
|
|
13168
|
+
|
|
13169
|
+
export {
|
|
13170
|
+
Table,
|
|
13171
|
+
TableHeader,
|
|
13172
|
+
TableBody,
|
|
13173
|
+
TableFooter,
|
|
13174
|
+
TableHead,
|
|
13175
|
+
TableRow,
|
|
13176
|
+
TableCell,
|
|
13177
|
+
TableCaption,
|
|
13178
|
+
}
|
|
13179
|
+
|
|
13180
|
+
|
|
13181
|
+
END_OF_FILE_CONTENT
|
|
13182
|
+
echo "Creating src/components/ui/tabs.tsx..."
|
|
13183
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/tabs.tsx"
|
|
13184
|
+
"use client"
|
|
13185
|
+
|
|
13186
|
+
import * as React from "react"
|
|
13187
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
13188
|
+
import { Tabs as TabsPrimitive } from "radix-ui"
|
|
13189
|
+
|
|
13190
|
+
import { cn } from "@/lib/utils"
|
|
13191
|
+
|
|
13192
|
+
function Tabs({
|
|
13193
|
+
className,
|
|
13194
|
+
orientation = "horizontal",
|
|
13195
|
+
...props
|
|
13196
|
+
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
|
13197
|
+
return (
|
|
13198
|
+
<TabsPrimitive.Root
|
|
13199
|
+
data-slot="tabs"
|
|
13200
|
+
data-orientation={orientation}
|
|
13201
|
+
className={cn(
|
|
13202
|
+
"group/tabs flex gap-2 data-horizontal:flex-col",
|
|
13203
|
+
className
|
|
13204
|
+
)}
|
|
13205
|
+
{...props}
|
|
13206
|
+
/>
|
|
13207
|
+
)
|
|
13208
|
+
}
|
|
13209
|
+
|
|
13210
|
+
const tabsListVariants = cva(
|
|
13211
|
+
"group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
|
|
13212
|
+
{
|
|
13213
|
+
variants: {
|
|
13214
|
+
variant: {
|
|
13215
|
+
default: "bg-muted",
|
|
13216
|
+
line: "gap-1 bg-transparent",
|
|
13217
|
+
},
|
|
13218
|
+
},
|
|
13219
|
+
defaultVariants: {
|
|
13220
|
+
variant: "default",
|
|
13221
|
+
},
|
|
13222
|
+
}
|
|
13223
|
+
)
|
|
13224
|
+
|
|
13225
|
+
function TabsList({
|
|
13226
|
+
className,
|
|
13227
|
+
variant = "default",
|
|
13228
|
+
...props
|
|
13229
|
+
}: React.ComponentProps<typeof TabsPrimitive.List> &
|
|
13230
|
+
VariantProps<typeof tabsListVariants>) {
|
|
13231
|
+
return (
|
|
13232
|
+
<TabsPrimitive.List
|
|
13233
|
+
data-slot="tabs-list"
|
|
13234
|
+
data-variant={variant}
|
|
13235
|
+
className={cn(tabsListVariants({ variant }), className)}
|
|
13236
|
+
{...props}
|
|
13237
|
+
/>
|
|
13238
|
+
)
|
|
13239
|
+
}
|
|
13240
|
+
|
|
13241
|
+
function TabsTrigger({
|
|
13242
|
+
className,
|
|
13243
|
+
...props
|
|
13244
|
+
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
|
13245
|
+
return (
|
|
13246
|
+
<TabsPrimitive.Trigger
|
|
13247
|
+
data-slot="tabs-trigger"
|
|
13248
|
+
className={cn(
|
|
13249
|
+
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
13250
|
+
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
|
|
13251
|
+
"data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
|
|
13252
|
+
"after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
|
|
13253
|
+
className
|
|
13254
|
+
)}
|
|
13255
|
+
{...props}
|
|
13256
|
+
/>
|
|
13257
|
+
)
|
|
13258
|
+
}
|
|
13259
|
+
|
|
13260
|
+
function TabsContent({
|
|
13261
|
+
className,
|
|
13262
|
+
...props
|
|
13263
|
+
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
|
13264
|
+
return (
|
|
13265
|
+
<TabsPrimitive.Content
|
|
13266
|
+
data-slot="tabs-content"
|
|
13267
|
+
className={cn("flex-1 text-sm outline-none", className)}
|
|
13268
|
+
{...props}
|
|
13269
|
+
/>
|
|
13270
|
+
)
|
|
13271
|
+
}
|
|
13272
|
+
|
|
13273
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
|
|
13274
|
+
|
|
13275
|
+
|
|
13276
|
+
END_OF_FILE_CONTENT
|
|
13277
|
+
echo "Creating src/components/ui/textarea.tsx..."
|
|
13278
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/textarea.tsx"
|
|
13279
|
+
import * as React from "react"
|
|
13280
|
+
|
|
13281
|
+
import { cn } from "@/lib/utils"
|
|
13282
|
+
|
|
13283
|
+
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
13284
|
+
return (
|
|
13285
|
+
<textarea
|
|
13286
|
+
data-slot="textarea"
|
|
13287
|
+
className={cn(
|
|
13288
|
+
"border-input dark:bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 rounded-lg border bg-transparent px-2.5 py-2 text-base transition-colors focus-visible:ring-3 aria-invalid:ring-3 md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
13289
|
+
className
|
|
13290
|
+
)}
|
|
13291
|
+
{...props}
|
|
13292
|
+
/>
|
|
13293
|
+
)
|
|
13294
|
+
}
|
|
13295
|
+
|
|
13296
|
+
export { Textarea }
|
|
13297
|
+
|
|
13298
|
+
|
|
13299
|
+
|
|
13300
|
+
|
|
13301
|
+
|
|
13302
|
+
END_OF_FILE_CONTENT
|
|
13303
|
+
echo "Creating src/components/ui/toggle-group.tsx..."
|
|
13304
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/toggle-group.tsx"
|
|
13305
|
+
import * as React from "react"
|
|
13306
|
+
import { type VariantProps } from "class-variance-authority"
|
|
13307
|
+
import { ToggleGroup as ToggleGroupPrimitive } from "radix-ui"
|
|
13308
|
+
|
|
13309
|
+
import { cn } from "@/lib/utils"
|
|
13310
|
+
import { toggleVariants } from "@/components/ui/toggle"
|
|
13311
|
+
|
|
13312
|
+
const ToggleGroupContext = React.createContext<
|
|
13313
|
+
VariantProps<typeof toggleVariants> & {
|
|
13314
|
+
spacing?: number
|
|
13315
|
+
orientation?: "horizontal" | "vertical"
|
|
13316
|
+
}
|
|
13317
|
+
>({
|
|
13318
|
+
size: "default",
|
|
13319
|
+
variant: "default",
|
|
13320
|
+
spacing: 0,
|
|
13321
|
+
orientation: "horizontal",
|
|
13322
|
+
})
|
|
13323
|
+
|
|
13324
|
+
function ToggleGroup({
|
|
10575
13325
|
className,
|
|
13326
|
+
variant,
|
|
13327
|
+
size,
|
|
13328
|
+
spacing = 0,
|
|
13329
|
+
orientation = "horizontal",
|
|
13330
|
+
children,
|
|
10576
13331
|
...props
|
|
10577
|
-
}: React.ComponentProps<typeof
|
|
13332
|
+
}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
|
|
13333
|
+
VariantProps<typeof toggleVariants> & {
|
|
13334
|
+
spacing?: number
|
|
13335
|
+
orientation?: "horizontal" | "vertical"
|
|
13336
|
+
}) {
|
|
10578
13337
|
return (
|
|
10579
|
-
<
|
|
10580
|
-
data-slot="
|
|
10581
|
-
|
|
13338
|
+
<ToggleGroupPrimitive.Root
|
|
13339
|
+
data-slot="toggle-group"
|
|
13340
|
+
data-variant={variant}
|
|
13341
|
+
data-size={size}
|
|
13342
|
+
data-spacing={spacing}
|
|
13343
|
+
data-orientation={orientation}
|
|
13344
|
+
style={{ "--gap": spacing } as React.CSSProperties}
|
|
13345
|
+
className={cn(
|
|
13346
|
+
"group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-lg data-[size=sm]:rounded-[min(var(--radius-md),10px)] data-vertical:flex-col data-vertical:items-stretch",
|
|
13347
|
+
className
|
|
13348
|
+
)}
|
|
10582
13349
|
{...props}
|
|
10583
13350
|
>
|
|
10584
|
-
<
|
|
10585
|
-
|
|
13351
|
+
<ToggleGroupContext.Provider
|
|
13352
|
+
value={{ variant, size, spacing, orientation }}
|
|
13353
|
+
>
|
|
13354
|
+
{children}
|
|
13355
|
+
</ToggleGroupContext.Provider>
|
|
13356
|
+
</ToggleGroupPrimitive.Root>
|
|
10586
13357
|
)
|
|
10587
13358
|
}
|
|
10588
13359
|
|
|
10589
|
-
function
|
|
13360
|
+
function ToggleGroupItem({
|
|
10590
13361
|
className,
|
|
13362
|
+
children,
|
|
13363
|
+
variant = "default",
|
|
13364
|
+
size = "default",
|
|
10591
13365
|
...props
|
|
10592
|
-
}: React.ComponentProps<typeof
|
|
13366
|
+
}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
|
|
13367
|
+
VariantProps<typeof toggleVariants>) {
|
|
13368
|
+
const context = React.useContext(ToggleGroupContext)
|
|
13369
|
+
|
|
10593
13370
|
return (
|
|
10594
|
-
<
|
|
10595
|
-
data-slot="
|
|
10596
|
-
|
|
13371
|
+
<ToggleGroupPrimitive.Item
|
|
13372
|
+
data-slot="toggle-group-item"
|
|
13373
|
+
data-variant={context.variant || variant}
|
|
13374
|
+
data-size={context.size || size}
|
|
13375
|
+
data-spacing={context.spacing}
|
|
13376
|
+
className={cn(
|
|
13377
|
+
"shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t",
|
|
13378
|
+
toggleVariants({
|
|
13379
|
+
variant: context.variant || variant,
|
|
13380
|
+
size: context.size || size,
|
|
13381
|
+
}),
|
|
13382
|
+
className
|
|
13383
|
+
)}
|
|
10597
13384
|
{...props}
|
|
10598
13385
|
>
|
|
10599
|
-
|
|
10600
|
-
</
|
|
13386
|
+
{children}
|
|
13387
|
+
</ToggleGroupPrimitive.Item>
|
|
10601
13388
|
)
|
|
10602
13389
|
}
|
|
10603
13390
|
|
|
10604
|
-
export {
|
|
10605
|
-
Select,
|
|
10606
|
-
SelectContent,
|
|
10607
|
-
SelectGroup,
|
|
10608
|
-
SelectItem,
|
|
10609
|
-
SelectLabel,
|
|
10610
|
-
SelectScrollDownButton,
|
|
10611
|
-
SelectScrollUpButton,
|
|
10612
|
-
SelectSeparator,
|
|
10613
|
-
SelectTrigger,
|
|
10614
|
-
SelectValue,
|
|
10615
|
-
}
|
|
13391
|
+
export { ToggleGroup, ToggleGroupItem }
|
|
10616
13392
|
|
|
10617
13393
|
|
|
13394
|
+
END_OF_FILE_CONTENT
|
|
13395
|
+
echo "Creating src/components/ui/toggle.tsx..."
|
|
13396
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/toggle.tsx"
|
|
13397
|
+
"use client"
|
|
10618
13398
|
|
|
13399
|
+
import * as React from "react"
|
|
13400
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
13401
|
+
import { Toggle as TogglePrimitive } from "radix-ui"
|
|
10619
13402
|
|
|
10620
|
-
|
|
10621
|
-
echo "Creating src/components/ui/separator.tsx..."
|
|
10622
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/separator.tsx"
|
|
10623
|
-
import * as React from 'react'
|
|
10624
|
-
import { cn } from '@/lib/utils'
|
|
13403
|
+
import { cn } from "@/lib/utils"
|
|
10625
13404
|
|
|
10626
|
-
const
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
|
|
10632
|
-
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
13405
|
+
const toggleVariants = cva(
|
|
13406
|
+
"group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
13407
|
+
{
|
|
13408
|
+
variants: {
|
|
13409
|
+
variant: {
|
|
13410
|
+
default: "bg-transparent",
|
|
13411
|
+
outline: "border border-input bg-transparent hover:bg-muted",
|
|
13412
|
+
},
|
|
13413
|
+
size: {
|
|
13414
|
+
default:
|
|
13415
|
+
"h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
13416
|
+
sm: "h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
|
13417
|
+
lg: "h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
13418
|
+
},
|
|
13419
|
+
},
|
|
13420
|
+
defaultVariants: {
|
|
13421
|
+
variant: "default",
|
|
13422
|
+
size: "default",
|
|
13423
|
+
},
|
|
13424
|
+
}
|
|
13425
|
+
)
|
|
10641
13426
|
|
|
10642
|
-
|
|
13427
|
+
function Toggle({
|
|
13428
|
+
className,
|
|
13429
|
+
variant = "default",
|
|
13430
|
+
size = "default",
|
|
13431
|
+
...props
|
|
13432
|
+
}: React.ComponentProps<typeof TogglePrimitive.Root> &
|
|
13433
|
+
VariantProps<typeof toggleVariants>) {
|
|
13434
|
+
return (
|
|
13435
|
+
<TogglePrimitive.Root
|
|
13436
|
+
data-slot="toggle"
|
|
13437
|
+
className={cn(toggleVariants({ variant, size, className }))}
|
|
13438
|
+
{...props}
|
|
13439
|
+
/>
|
|
13440
|
+
)
|
|
13441
|
+
}
|
|
13442
|
+
|
|
13443
|
+
export { Toggle, toggleVariants }
|
|
10643
13444
|
|
|
10644
|
-
END_OF_FILE_CONTENT
|
|
10645
|
-
echo "Creating src/components/ui/skeleton.tsx..."
|
|
10646
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/skeleton.tsx"
|
|
10647
|
-
import { cn } from '@/lib/utils';
|
|
10648
|
-
import type { HTMLAttributes } from 'react';
|
|
10649
|
-
|
|
10650
|
-
function Skeleton({
|
|
10651
|
-
className,
|
|
10652
|
-
...props
|
|
10653
|
-
}: HTMLAttributes<HTMLDivElement>) {
|
|
10654
|
-
return (
|
|
10655
|
-
<div
|
|
10656
|
-
className={cn('animate-pulse rounded-md bg-muted', className)}
|
|
10657
|
-
{...props}
|
|
10658
|
-
/>
|
|
10659
|
-
);
|
|
10660
|
-
}
|
|
10661
|
-
|
|
10662
|
-
export { Skeleton };
|
|
10663
13445
|
|
|
10664
13446
|
END_OF_FILE_CONTENT
|
|
10665
|
-
echo "Creating src/components/ui/
|
|
10666
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/
|
|
13447
|
+
echo "Creating src/components/ui/tooltip.tsx..."
|
|
13448
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/tooltip.tsx"
|
|
13449
|
+
"use client"
|
|
13450
|
+
|
|
10667
13451
|
import * as React from "react"
|
|
13452
|
+
import { Tooltip as TooltipPrimitive } from "radix-ui"
|
|
10668
13453
|
|
|
10669
13454
|
import { cn } from "@/lib/utils"
|
|
10670
13455
|
|
|
10671
|
-
function
|
|
13456
|
+
function TooltipProvider({
|
|
13457
|
+
delayDuration = 0,
|
|
13458
|
+
...props
|
|
13459
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
10672
13460
|
return (
|
|
10673
|
-
<
|
|
10674
|
-
data-slot="
|
|
10675
|
-
|
|
10676
|
-
"border-input dark:bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 rounded-lg border bg-transparent px-2.5 py-2 text-base transition-colors focus-visible:ring-3 aria-invalid:ring-3 md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
10677
|
-
className
|
|
10678
|
-
)}
|
|
13461
|
+
<TooltipPrimitive.Provider
|
|
13462
|
+
data-slot="tooltip-provider"
|
|
13463
|
+
delayDuration={delayDuration}
|
|
10679
13464
|
{...props}
|
|
10680
13465
|
/>
|
|
10681
13466
|
)
|
|
10682
13467
|
}
|
|
10683
13468
|
|
|
10684
|
-
|
|
13469
|
+
function Tooltip({
|
|
13470
|
+
...props
|
|
13471
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
13472
|
+
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
13473
|
+
}
|
|
10685
13474
|
|
|
13475
|
+
function TooltipTrigger({
|
|
13476
|
+
...props
|
|
13477
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
13478
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
|
13479
|
+
}
|
|
10686
13480
|
|
|
13481
|
+
function TooltipContent({
|
|
13482
|
+
className,
|
|
13483
|
+
sideOffset = 0,
|
|
13484
|
+
children,
|
|
13485
|
+
...props
|
|
13486
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
13487
|
+
return (
|
|
13488
|
+
<TooltipPrimitive.Portal>
|
|
13489
|
+
<TooltipPrimitive.Content
|
|
13490
|
+
data-slot="tooltip-content"
|
|
13491
|
+
sideOffset={sideOffset}
|
|
13492
|
+
className={cn(
|
|
13493
|
+
"z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
13494
|
+
className
|
|
13495
|
+
)}
|
|
13496
|
+
{...props}
|
|
13497
|
+
>
|
|
13498
|
+
{children}
|
|
13499
|
+
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
|
|
13500
|
+
</TooltipPrimitive.Content>
|
|
13501
|
+
</TooltipPrimitive.Portal>
|
|
13502
|
+
)
|
|
13503
|
+
}
|
|
10687
13504
|
|
|
13505
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
|
|
10688
13506
|
|
|
10689
13507
|
|
|
10690
13508
|
END_OF_FILE_CONTENT
|
|
@@ -10695,12 +13513,12 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/menu.json"
|
|
|
10695
13513
|
{
|
|
10696
13514
|
"main": [
|
|
10697
13515
|
{
|
|
10698
|
-
"label": "
|
|
10699
|
-
"href": "#
|
|
13516
|
+
"label": "Why",
|
|
13517
|
+
"href": "#Why"
|
|
10700
13518
|
},
|
|
10701
13519
|
{
|
|
10702
|
-
"label": "
|
|
10703
|
-
"href": "#
|
|
13520
|
+
"label": "Architecture",
|
|
13521
|
+
"href": "#Architecture"
|
|
10704
13522
|
},
|
|
10705
13523
|
{
|
|
10706
13524
|
"label": "Example",
|
|
@@ -10714,52 +13532,6 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/menu.json"
|
|
|
10714
13532
|
"label": "GitHub",
|
|
10715
13533
|
"href": "https://github.com/olonjs/core"
|
|
10716
13534
|
}
|
|
10717
|
-
],
|
|
10718
|
-
"footer": [
|
|
10719
|
-
{
|
|
10720
|
-
"label": "GitHubs",
|
|
10721
|
-
"href": "https://github.com/olonjs/core"
|
|
10722
|
-
}
|
|
10723
|
-
],
|
|
10724
|
-
"nested": [
|
|
10725
|
-
{
|
|
10726
|
-
"label": "Why",
|
|
10727
|
-
"href": "/why",
|
|
10728
|
-
"children": [
|
|
10729
|
-
{
|
|
10730
|
-
"label": "Overview",
|
|
10731
|
-
"href": "/platform/overview"
|
|
10732
|
-
},
|
|
10733
|
-
{
|
|
10734
|
-
"label": "Architecture",
|
|
10735
|
-
"href": "/platform/architecture"
|
|
10736
|
-
},
|
|
10737
|
-
{
|
|
10738
|
-
"label": "Security",
|
|
10739
|
-
"href": "/platform/security"
|
|
10740
|
-
},
|
|
10741
|
-
{
|
|
10742
|
-
"label": "Integrations",
|
|
10743
|
-
"href": "/platform/integrations"
|
|
10744
|
-
},
|
|
10745
|
-
{
|
|
10746
|
-
"label": "Roadmap",
|
|
10747
|
-
"href": "/platform/roadmap"
|
|
10748
|
-
}
|
|
10749
|
-
]
|
|
10750
|
-
},
|
|
10751
|
-
{
|
|
10752
|
-
"label": "Solutions",
|
|
10753
|
-
"href": "/solutions"
|
|
10754
|
-
},
|
|
10755
|
-
{
|
|
10756
|
-
"label": "Pricing",
|
|
10757
|
-
"href": "/pricing"
|
|
10758
|
-
},
|
|
10759
|
-
{
|
|
10760
|
-
"label": "Resources",
|
|
10761
|
-
"href": "/resources"
|
|
10762
|
-
}
|
|
10763
13535
|
]
|
|
10764
13536
|
}
|
|
10765
13537
|
END_OF_FILE_CONTENT
|
|
@@ -10811,15 +13583,51 @@ END_OF_FILE_CONTENT
|
|
|
10811
13583
|
echo "Creating src/data/config/site.json..."
|
|
10812
13584
|
cat << 'END_OF_FILE_CONTENT' > "src/data/config/site.json"
|
|
10813
13585
|
{
|
|
13586
|
+
"identity": {
|
|
13587
|
+
"title": "OlonJS",
|
|
13588
|
+
"logoUrl": "/brand/mark/olon-mark-dark.svg"
|
|
13589
|
+
},
|
|
13590
|
+
"pages": [
|
|
13591
|
+
{
|
|
13592
|
+
"slug": "home",
|
|
13593
|
+
"label": "Home"
|
|
13594
|
+
},
|
|
13595
|
+
{
|
|
13596
|
+
"slug": "design-system",
|
|
13597
|
+
"label": "Design System"
|
|
13598
|
+
}
|
|
13599
|
+
],
|
|
10814
13600
|
"header": {
|
|
10815
13601
|
"id": "global-header",
|
|
10816
13602
|
"type": "header",
|
|
10817
13603
|
"data": {
|
|
10818
13604
|
"logoText": "Olon",
|
|
10819
13605
|
"badge": "JS",
|
|
10820
|
-
"
|
|
10821
|
-
|
|
10822
|
-
|
|
13606
|
+
"links": [
|
|
13607
|
+
{
|
|
13608
|
+
"label": "Why",
|
|
13609
|
+
"href": "#Why"
|
|
13610
|
+
},
|
|
13611
|
+
{
|
|
13612
|
+
"label": "Architecture",
|
|
13613
|
+
"href": "#Architecture"
|
|
13614
|
+
},
|
|
13615
|
+
{
|
|
13616
|
+
"label": "Example",
|
|
13617
|
+
"href": "#Example"
|
|
13618
|
+
},
|
|
13619
|
+
{
|
|
13620
|
+
"label": "Get started",
|
|
13621
|
+
"href": "#Getstarted"
|
|
13622
|
+
},
|
|
13623
|
+
{
|
|
13624
|
+
"label": "GitHub",
|
|
13625
|
+
"href": "https://github.com/olonjs/core"
|
|
13626
|
+
}
|
|
13627
|
+
],
|
|
13628
|
+
"ctaLabel": "",
|
|
13629
|
+
"ctaHref": "",
|
|
13630
|
+
"signinHref": ""
|
|
10823
13631
|
}
|
|
10824
13632
|
},
|
|
10825
13633
|
"footer": {
|
|
@@ -10828,15 +13636,18 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/site.json"
|
|
|
10828
13636
|
"data": {
|
|
10829
13637
|
"brandText": "OlonJS",
|
|
10830
13638
|
"copyright": "© 2026 OlonJS · v1.5 · Guido Serio",
|
|
10831
|
-
"
|
|
10832
|
-
|
|
10833
|
-
|
|
13639
|
+
"links": [
|
|
13640
|
+
{
|
|
13641
|
+
"label": "GitHub",
|
|
13642
|
+
"href": "https://github.com/olonjs/core"
|
|
13643
|
+
}
|
|
13644
|
+
],
|
|
13645
|
+
"designSystemHref": ""
|
|
13646
|
+
},
|
|
13647
|
+
"settings": {
|
|
13648
|
+
"showLogo": true
|
|
10834
13649
|
}
|
|
10835
|
-
}
|
|
10836
|
-
"identity": {
|
|
10837
|
-
"title": "Site"
|
|
10838
|
-
},
|
|
10839
|
-
"pages": []
|
|
13650
|
+
}
|
|
10840
13651
|
}
|
|
10841
13652
|
END_OF_FILE_CONTENT
|
|
10842
13653
|
echo "Creating src/data/config/theme.json..."
|
|
@@ -11066,9 +13877,9 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
|
|
|
11066
13877
|
"data": {
|
|
11067
13878
|
"id": "hero-main",
|
|
11068
13879
|
"eyebrow": "CONTRACT LAYER · V1.5 · OPEN SOURCE",
|
|
11069
|
-
"headline": "
|
|
11070
|
-
"subline": "
|
|
11071
|
-
"body": "
|
|
13880
|
+
"headline": "Contract Layer",
|
|
13881
|
+
"subline": "for the agentic web.",
|
|
13882
|
+
"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.",
|
|
11072
13883
|
"primaryCta": {
|
|
11073
13884
|
"label": "Get started",
|
|
11074
13885
|
"href": "#getstarted"
|
|
@@ -11842,26 +14653,13 @@ cat << 'END_OF_FILE_CONTENT' > "src/entry-ssg.tsx"
|
|
|
11842
14653
|
import { renderToString } from 'react-dom/server';
|
|
11843
14654
|
import { StaticRouter } from 'react-router-dom/server';
|
|
11844
14655
|
import { ConfigProvider, PageRenderer, StudioProvider, resolveRuntimeConfig } from '@olonjs/core';
|
|
11845
|
-
import type { JsonPagesConfig,
|
|
14656
|
+
import type { JsonPagesConfig, PageConfig, SiteConfig, ThemeConfig } from '@/types';
|
|
11846
14657
|
import { ThemeProvider } from '@/components/ThemeProvider';
|
|
11847
14658
|
import { ComponentRegistry } from '@/lib/ComponentRegistry';
|
|
11848
14659
|
import { SECTION_SCHEMAS } from '@/lib/schemas';
|
|
11849
|
-
import {
|
|
11850
|
-
import siteData from '@/data/config/site.json';
|
|
11851
|
-
import menuData from '@/data/config/menu.json';
|
|
11852
|
-
import themeData from '@/data/config/theme.json';
|
|
14660
|
+
import { menuConfig, pages, refDocuments, siteConfig, themeConfig } from '@/runtime';
|
|
11853
14661
|
import tenantCss from '@/index.css?inline';
|
|
11854
14662
|
|
|
11855
|
-
const siteConfig = siteData as unknown as SiteConfig;
|
|
11856
|
-
const menuConfig: MenuConfig = { main: [] };
|
|
11857
|
-
const themeConfig = themeData as unknown as ThemeConfig;
|
|
11858
|
-
const pages = getFilePages();
|
|
11859
|
-
const refDocuments = {
|
|
11860
|
-
'menu.json': menuData,
|
|
11861
|
-
'config/menu.json': menuData,
|
|
11862
|
-
'src/data/config/menu.json': menuData,
|
|
11863
|
-
} satisfies NonNullable<JsonPagesConfig['refDocuments']>;
|
|
11864
|
-
|
|
11865
14663
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
11866
14664
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
11867
14665
|
}
|
|
@@ -13542,6 +16340,38 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
13542
16340
|
|
|
13543
16341
|
|
|
13544
16342
|
|
|
16343
|
+
END_OF_FILE_CONTENT
|
|
16344
|
+
echo "Creating src/runtime.ts..."
|
|
16345
|
+
cat << 'END_OF_FILE_CONTENT' > "src/runtime.ts"
|
|
16346
|
+
import type { JsonPagesConfig, MenuConfig, PageConfig, SiteConfig, ThemeConfig } from '@/types';
|
|
16347
|
+
import { SECTION_SCHEMAS } from '@/lib/schemas';
|
|
16348
|
+
import { getFilePages } from '@/lib/getFilePages';
|
|
16349
|
+
import siteData from '@/data/config/site.json';
|
|
16350
|
+
import menuData from '@/data/config/menu.json';
|
|
16351
|
+
import themeData from '@/data/config/theme.json';
|
|
16352
|
+
|
|
16353
|
+
export const siteConfig = siteData as unknown as SiteConfig;
|
|
16354
|
+
export const themeConfig = themeData as unknown as ThemeConfig;
|
|
16355
|
+
export const menuConfig = menuData as unknown as MenuConfig;
|
|
16356
|
+
export const pages = getFilePages();
|
|
16357
|
+
export const refDocuments = {
|
|
16358
|
+
'menu.json': menuConfig,
|
|
16359
|
+
'config/menu.json': menuConfig,
|
|
16360
|
+
'src/data/config/menu.json': menuConfig,
|
|
16361
|
+
} satisfies NonNullable<JsonPagesConfig['refDocuments']>;
|
|
16362
|
+
|
|
16363
|
+
export function getWebMcpBuildState(): {
|
|
16364
|
+
pages: Record<string, PageConfig>;
|
|
16365
|
+
schemas: JsonPagesConfig['schemas'];
|
|
16366
|
+
siteConfig: SiteConfig;
|
|
16367
|
+
} {
|
|
16368
|
+
return {
|
|
16369
|
+
pages,
|
|
16370
|
+
schemas: SECTION_SCHEMAS as unknown as JsonPagesConfig['schemas'],
|
|
16371
|
+
siteConfig,
|
|
16372
|
+
};
|
|
16373
|
+
}
|
|
16374
|
+
|
|
13545
16375
|
END_OF_FILE_CONTENT
|
|
13546
16376
|
mkdir -p "src/types"
|
|
13547
16377
|
echo "Creating src/types.ts..."
|
|
@@ -13739,7 +16569,7 @@ import react from '@vitejs/plugin-react';
|
|
|
13739
16569
|
import tailwindcss from '@tailwindcss/vite';
|
|
13740
16570
|
import path from 'path';
|
|
13741
16571
|
import fs from 'fs';
|
|
13742
|
-
import { fileURLToPath
|
|
16572
|
+
import { fileURLToPath } from 'url';
|
|
13743
16573
|
|
|
13744
16574
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13745
16575
|
|
|
@@ -13796,8 +16626,7 @@ function normalizeManifestSlug(raw) {
|
|
|
13796
16626
|
}
|
|
13797
16627
|
|
|
13798
16628
|
async function loadWebMcpBuilders() {
|
|
13799
|
-
const
|
|
13800
|
-
const moduleUrl = pathToFileURL(path.resolve(corePkgPath, 'src', 'lib', 'webmcp-contracts.mjs')).href;
|
|
16629
|
+
const moduleUrl = import.meta.resolve('@olonjs/core');
|
|
13801
16630
|
return import(moduleUrl);
|
|
13802
16631
|
}
|
|
13803
16632
|
export default defineConfig({
|
|
@@ -13812,9 +16641,10 @@ export default defineConfig({
|
|
|
13812
16641
|
const isPageJsonRequest = isTenantPageJsonRequest(req, pathname);
|
|
13813
16642
|
|
|
13814
16643
|
const handleManifestRequest = async () => {
|
|
13815
|
-
const
|
|
13816
|
-
const
|
|
13817
|
-
const
|
|
16644
|
+
const core = await loadWebMcpBuilders();
|
|
16645
|
+
const { buildPageContract, buildPageManifest, buildSiteManifest, buildLlmsTxt } = core.webmcp;
|
|
16646
|
+
const runtime = await server.ssrLoadModule('/src/runtime.ts');
|
|
16647
|
+
const buildState = runtime.getWebMcpBuildState();
|
|
13818
16648
|
|
|
13819
16649
|
if (req.method === 'GET' && pathname === '/llms.txt') {
|
|
13820
16650
|
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
@@ -13984,6 +16814,4 @@ export default defineConfig({
|
|
|
13984
16814
|
});
|
|
13985
16815
|
|
|
13986
16816
|
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
16817
|
END_OF_FILE_CONTENT
|