@olonjs/cli 3.0.123 → 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 +3111 -280
- package/assets/templates/agritourism/src_tenant.sh +1 -1
- package/assets/templates/alpha/src_tenant.sh +3111 -280
- 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,46 +5840,187 @@ 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
|
-
|
|
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
|
|
5345
6024
|
href={data.designSystemHref}
|
|
5346
6025
|
className="text-[12px] text-muted-foreground hover:text-foreground transition-colors"
|
|
5347
6026
|
>
|
|
@@ -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';
|
|
@@ -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,44 +11639,536 @@ 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
|
-
|
|
11651
|
+
function Dialog({
|
|
11652
|
+
...props
|
|
11653
|
+
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
11654
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />
|
|
11655
|
+
}
|
|
11656
|
+
|
|
11657
|
+
function DialogTrigger({
|
|
11658
|
+
...props
|
|
11659
|
+
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
11660
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
11661
|
+
}
|
|
11662
|
+
|
|
11663
|
+
function DialogPortal({
|
|
11664
|
+
...props
|
|
11665
|
+
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
11666
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
|
11667
|
+
}
|
|
11668
|
+
|
|
11669
|
+
function DialogClose({
|
|
11670
|
+
...props
|
|
11671
|
+
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
11672
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
|
|
11673
|
+
}
|
|
11674
|
+
|
|
11675
|
+
function DialogOverlay({
|
|
11676
|
+
className,
|
|
11677
|
+
...props
|
|
11678
|
+
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
11679
|
+
return (
|
|
11680
|
+
<DialogPrimitive.Overlay
|
|
11681
|
+
data-slot="dialog-overlay"
|
|
11682
|
+
className={cn(
|
|
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",
|
|
11684
|
+
className
|
|
11685
|
+
)}
|
|
11686
|
+
{...props}
|
|
11687
|
+
/>
|
|
11688
|
+
)
|
|
11689
|
+
}
|
|
11690
|
+
|
|
11691
|
+
function DialogContent({
|
|
11692
|
+
className,
|
|
11693
|
+
children,
|
|
11694
|
+
showCloseButton = true,
|
|
11695
|
+
...props
|
|
11696
|
+
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
11697
|
+
showCloseButton?: boolean
|
|
11698
|
+
}) {
|
|
11699
|
+
return (
|
|
11700
|
+
<DialogPortal>
|
|
11701
|
+
<DialogOverlay />
|
|
11702
|
+
<DialogPrimitive.Content
|
|
11703
|
+
data-slot="dialog-content"
|
|
10197
11704
|
className={cn(
|
|
10198
|
-
|
|
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',
|
|
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",
|
|
10202
11706
|
className
|
|
10203
11707
|
)}
|
|
10204
|
-
|
|
11708
|
+
{...props}
|
|
11709
|
+
>
|
|
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>
|
|
11726
|
+
)
|
|
11727
|
+
}
|
|
11728
|
+
|
|
11729
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
11730
|
+
return (
|
|
11731
|
+
<div
|
|
11732
|
+
data-slot="dialog-header"
|
|
11733
|
+
className={cn("flex flex-col gap-2", className)}
|
|
11734
|
+
{...props}
|
|
11735
|
+
/>
|
|
11736
|
+
)
|
|
11737
|
+
}
|
|
11738
|
+
|
|
11739
|
+
function DialogFooter({
|
|
11740
|
+
className,
|
|
11741
|
+
showCloseButton = false,
|
|
11742
|
+
children,
|
|
11743
|
+
...props
|
|
11744
|
+
}: React.ComponentProps<"div"> & {
|
|
11745
|
+
showCloseButton?: boolean
|
|
11746
|
+
}) {
|
|
11747
|
+
return (
|
|
11748
|
+
<div
|
|
11749
|
+
data-slot="dialog-footer"
|
|
11750
|
+
className={cn(
|
|
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",
|
|
11752
|
+
className
|
|
11753
|
+
)}
|
|
11754
|
+
{...props}
|
|
11755
|
+
>
|
|
11756
|
+
{children}
|
|
11757
|
+
{showCloseButton && (
|
|
11758
|
+
<DialogPrimitive.Close asChild>
|
|
11759
|
+
<Button variant="outline">Close</Button>
|
|
11760
|
+
</DialogPrimitive.Close>
|
|
11761
|
+
)}
|
|
11762
|
+
</div>
|
|
11763
|
+
)
|
|
11764
|
+
}
|
|
11765
|
+
|
|
11766
|
+
function DialogTitle({
|
|
11767
|
+
className,
|
|
11768
|
+
...props
|
|
11769
|
+
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
11770
|
+
return (
|
|
11771
|
+
<DialogPrimitive.Title
|
|
11772
|
+
data-slot="dialog-title"
|
|
11773
|
+
className={cn(
|
|
11774
|
+
"text-base leading-none font-medium",
|
|
11775
|
+
className
|
|
11776
|
+
)}
|
|
11777
|
+
{...props}
|
|
11778
|
+
/>
|
|
11779
|
+
)
|
|
11780
|
+
}
|
|
11781
|
+
|
|
11782
|
+
function DialogDescription({
|
|
11783
|
+
className,
|
|
11784
|
+
...props
|
|
11785
|
+
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
11786
|
+
return (
|
|
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
|
+
)}
|
|
11793
|
+
{...props}
|
|
11794
|
+
/>
|
|
11795
|
+
)
|
|
11796
|
+
}
|
|
11797
|
+
|
|
11798
|
+
export {
|
|
11799
|
+
Dialog,
|
|
11800
|
+
DialogClose,
|
|
11801
|
+
DialogContent,
|
|
11802
|
+
DialogDescription,
|
|
11803
|
+
DialogFooter,
|
|
11804
|
+
DialogHeader,
|
|
11805
|
+
DialogOverlay,
|
|
11806
|
+
DialogPortal,
|
|
11807
|
+
DialogTitle,
|
|
11808
|
+
DialogTrigger,
|
|
11809
|
+
}
|
|
11810
|
+
|
|
11811
|
+
|
|
11812
|
+
END_OF_FILE_CONTENT
|
|
11813
|
+
echo "Creating src/components/ui/dropdown-menu.tsx..."
|
|
11814
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/dropdown-menu.tsx"
|
|
11815
|
+
import * as React from "react"
|
|
11816
|
+
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
|
|
11817
|
+
|
|
11818
|
+
import { cn } from "@/lib/utils"
|
|
11819
|
+
import { CheckIcon, ChevronRightIcon } from "lucide-react"
|
|
11820
|
+
|
|
11821
|
+
function DropdownMenu({
|
|
11822
|
+
...props
|
|
11823
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
11824
|
+
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
11825
|
+
}
|
|
11826
|
+
|
|
11827
|
+
function DropdownMenuPortal({
|
|
11828
|
+
...props
|
|
11829
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
11830
|
+
return (
|
|
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"
|
|
11841
|
+
{...props}
|
|
11842
|
+
/>
|
|
11843
|
+
)
|
|
11844
|
+
}
|
|
11845
|
+
|
|
11846
|
+
function DropdownMenuContent({
|
|
11847
|
+
className,
|
|
11848
|
+
align = "start",
|
|
11849
|
+
sideOffset = 4,
|
|
11850
|
+
...props
|
|
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 )}
|
|
10205
11859
|
{...props}
|
|
10206
11860
|
/>
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
|
|
10210
|
-
|
|
11861
|
+
</DropdownMenuPrimitive.Portal>
|
|
11862
|
+
)
|
|
11863
|
+
}
|
|
11864
|
+
|
|
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({
|
|
11897
|
+
className,
|
|
11898
|
+
children,
|
|
11899
|
+
checked,
|
|
11900
|
+
inset,
|
|
11901
|
+
...props
|
|
11902
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {
|
|
11903
|
+
inset?: boolean
|
|
11904
|
+
}) {
|
|
11905
|
+
return (
|
|
11906
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
11907
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
11908
|
+
data-inset={inset}
|
|
11909
|
+
className={cn(
|
|
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",
|
|
11911
|
+
className
|
|
11912
|
+
)}
|
|
11913
|
+
checked={checked}
|
|
11914
|
+
{...props}
|
|
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>
|
|
11925
|
+
{children}
|
|
11926
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
11927
|
+
)
|
|
11928
|
+
}
|
|
11929
|
+
|
|
11930
|
+
function DropdownMenuRadioGroup({
|
|
11931
|
+
...props
|
|
11932
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
11933
|
+
return (
|
|
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"
|
|
11962
|
+
>
|
|
11963
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
11964
|
+
<CheckIcon
|
|
11965
|
+
/>
|
|
11966
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
11967
|
+
</span>
|
|
11968
|
+
{children}
|
|
11969
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
11970
|
+
)
|
|
11971
|
+
}
|
|
11972
|
+
|
|
11973
|
+
function DropdownMenuLabel({
|
|
11974
|
+
className,
|
|
11975
|
+
inset,
|
|
11976
|
+
...props
|
|
11977
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
11978
|
+
inset?: boolean
|
|
11979
|
+
}) {
|
|
11980
|
+
return (
|
|
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
|
+
)}
|
|
11988
|
+
{...props}
|
|
11989
|
+
/>
|
|
11990
|
+
)
|
|
11991
|
+
}
|
|
11992
|
+
|
|
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({
|
|
12029
|
+
className,
|
|
12030
|
+
inset,
|
|
12031
|
+
children,
|
|
12032
|
+
...props
|
|
12033
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
12034
|
+
inset?: boolean
|
|
12035
|
+
}) {
|
|
12036
|
+
return (
|
|
12037
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
12038
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
12039
|
+
data-inset={inset}
|
|
12040
|
+
className={cn(
|
|
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",
|
|
12042
|
+
className
|
|
12043
|
+
)}
|
|
12044
|
+
{...props}
|
|
12045
|
+
>
|
|
12046
|
+
{children}
|
|
12047
|
+
<ChevronRightIcon className="ml-auto" />
|
|
12048
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
12049
|
+
)
|
|
12050
|
+
}
|
|
12051
|
+
|
|
12052
|
+
function DropdownMenuSubContent({
|
|
12053
|
+
className,
|
|
12054
|
+
...props
|
|
12055
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
12056
|
+
return (
|
|
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
|
+
}
|
|
10211
12082
|
|
|
10212
|
-
export { Input }
|
|
10213
12083
|
|
|
10214
12084
|
END_OF_FILE_CONTENT
|
|
10215
|
-
echo "Creating src/components/ui/
|
|
10216
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/
|
|
10217
|
-
|
|
10218
|
-
import { cn } from '@/lib/utils'
|
|
12085
|
+
echo "Creating src/components/ui/hover-card.tsx..."
|
|
12086
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/hover-card.tsx"
|
|
12087
|
+
"use client"
|
|
10219
12088
|
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
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>
|
|
10223
12172
|
>(({ className, ...props }, ref) => (
|
|
10224
12173
|
<label
|
|
10225
12174
|
ref={ref}
|
|
@@ -10229,11 +12178,465 @@ const Label = React.forwardRef<
|
|
|
10229
12178
|
))
|
|
10230
12179
|
Label.displayName = 'Label'
|
|
10231
12180
|
|
|
10232
|
-
export { Label }
|
|
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
|
+
)}
|
|
12278
|
+
{...props}
|
|
12279
|
+
/>
|
|
12280
|
+
)
|
|
12281
|
+
}
|
|
12282
|
+
|
|
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
|
+
|
|
10233
12636
|
|
|
10234
12637
|
END_OF_FILE_CONTENT
|
|
10235
|
-
echo "Creating src/components/ui/select.
|
|
10236
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/select.
|
|
12638
|
+
echo "Creating src/components/ui/select.txt..."
|
|
12639
|
+
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/select.txt"
|
|
10237
12640
|
import * as React from "react"
|
|
10238
12641
|
import { Select as SelectPrimitive } from "radix-ui"
|
|
10239
12642
|
|
|
@@ -10425,266 +12828,681 @@ export {
|
|
|
10425
12828
|
|
|
10426
12829
|
|
|
10427
12830
|
END_OF_FILE_CONTENT
|
|
10428
|
-
echo "Creating src/components/ui/
|
|
10429
|
-
cat << 'END_OF_FILE_CONTENT' > "src/components/ui/
|
|
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
|
+
|
|
10430
12859
|
import * as React from "react"
|
|
10431
|
-
import {
|
|
12860
|
+
import { Dialog as SheetPrimitive } from "radix-ui"
|
|
10432
12861
|
|
|
10433
12862
|
import { cn } from "@/lib/utils"
|
|
10434
|
-
import {
|
|
12863
|
+
import { Button } from "@/components/ui/button"
|
|
12864
|
+
import { XIcon } from "lucide-react"
|
|
10435
12865
|
|
|
10436
|
-
function
|
|
12866
|
+
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
|
12867
|
+
return <SheetPrimitive.Root data-slot="sheet" {...props} />
|
|
12868
|
+
}
|
|
12869
|
+
|
|
12870
|
+
function SheetTrigger({
|
|
10437
12871
|
...props
|
|
10438
|
-
}: React.ComponentProps<typeof
|
|
10439
|
-
return <
|
|
12872
|
+
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
|
|
12873
|
+
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
|
|
10440
12874
|
}
|
|
10441
12875
|
|
|
10442
|
-
function
|
|
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({
|
|
10443
12889
|
className,
|
|
10444
12890
|
...props
|
|
10445
|
-
}: React.ComponentProps<typeof
|
|
12891
|
+
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
|
|
10446
12892
|
return (
|
|
10447
|
-
<
|
|
10448
|
-
data-slot="
|
|
10449
|
-
className={cn(
|
|
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
|
+
)}
|
|
10450
12899
|
{...props}
|
|
10451
12900
|
/>
|
|
10452
12901
|
)
|
|
10453
12902
|
}
|
|
10454
12903
|
|
|
10455
|
-
function
|
|
12904
|
+
function SheetContent({
|
|
12905
|
+
className,
|
|
12906
|
+
children,
|
|
12907
|
+
side = "right",
|
|
12908
|
+
showCloseButton = true,
|
|
10456
12909
|
...props
|
|
10457
|
-
}: React.ComponentProps<typeof
|
|
10458
|
-
|
|
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
|
+
)
|
|
10459
12943
|
}
|
|
10460
12944
|
|
|
10461
|
-
function
|
|
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({
|
|
10462
13035
|
className,
|
|
10463
13036
|
size = "default",
|
|
10464
|
-
children,
|
|
10465
13037
|
...props
|
|
10466
|
-
}: React.ComponentProps<typeof
|
|
13038
|
+
}: React.ComponentProps<typeof SwitchPrimitive.Root> & {
|
|
10467
13039
|
size?: "sm" | "default"
|
|
10468
13040
|
}) {
|
|
10469
13041
|
return (
|
|
10470
|
-
<
|
|
10471
|
-
data-slot="
|
|
13042
|
+
<SwitchPrimitive.Root
|
|
13043
|
+
data-slot="switch"
|
|
10472
13044
|
data-size={size}
|
|
10473
13045
|
className={cn(
|
|
10474
|
-
"
|
|
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",
|
|
10475
13047
|
className
|
|
10476
13048
|
)}
|
|
10477
13049
|
{...props}
|
|
10478
13050
|
>
|
|
10479
|
-
|
|
10480
|
-
|
|
10481
|
-
|
|
10482
|
-
|
|
10483
|
-
</
|
|
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>
|
|
10484
13056
|
)
|
|
10485
13057
|
}
|
|
10486
13058
|
|
|
10487
|
-
|
|
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({
|
|
10488
13157
|
className,
|
|
10489
|
-
children,
|
|
10490
|
-
position = "popper",
|
|
10491
|
-
align = "center",
|
|
10492
13158
|
...props
|
|
10493
|
-
}: React.ComponentProps<
|
|
13159
|
+
}: React.ComponentProps<"caption">) {
|
|
10494
13160
|
return (
|
|
10495
|
-
<
|
|
10496
|
-
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
|
|
10516
|
-
|
|
10517
|
-
|
|
10518
|
-
|
|
10519
|
-
|
|
10520
|
-
|
|
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
|
+
/>
|
|
10521
13207
|
)
|
|
10522
13208
|
}
|
|
10523
13209
|
|
|
10524
|
-
|
|
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({
|
|
10525
13226
|
className,
|
|
13227
|
+
variant = "default",
|
|
10526
13228
|
...props
|
|
10527
|
-
}: React.ComponentProps<typeof
|
|
13229
|
+
}: React.ComponentProps<typeof TabsPrimitive.List> &
|
|
13230
|
+
VariantProps<typeof tabsListVariants>) {
|
|
10528
13231
|
return (
|
|
10529
|
-
<
|
|
10530
|
-
data-slot="
|
|
10531
|
-
|
|
13232
|
+
<TabsPrimitive.List
|
|
13233
|
+
data-slot="tabs-list"
|
|
13234
|
+
data-variant={variant}
|
|
13235
|
+
className={cn(tabsListVariants({ variant }), className)}
|
|
10532
13236
|
{...props}
|
|
10533
13237
|
/>
|
|
10534
13238
|
)
|
|
10535
13239
|
}
|
|
10536
13240
|
|
|
10537
|
-
function
|
|
13241
|
+
function TabsTrigger({
|
|
10538
13242
|
className,
|
|
10539
|
-
children,
|
|
10540
13243
|
...props
|
|
10541
|
-
}: React.ComponentProps<typeof
|
|
13244
|
+
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
|
10542
13245
|
return (
|
|
10543
|
-
<
|
|
10544
|
-
data-slot="
|
|
13246
|
+
<TabsPrimitive.Trigger
|
|
13247
|
+
data-slot="tabs-trigger"
|
|
10545
13248
|
className={cn(
|
|
10546
|
-
"
|
|
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",
|
|
10547
13253
|
className
|
|
10548
13254
|
)}
|
|
10549
13255
|
{...props}
|
|
10550
|
-
|
|
10551
|
-
<span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center">
|
|
10552
|
-
<SelectPrimitive.ItemIndicator>
|
|
10553
|
-
<CheckIcon className="pointer-events-none" />
|
|
10554
|
-
</SelectPrimitive.ItemIndicator>
|
|
10555
|
-
</span>
|
|
10556
|
-
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
10557
|
-
</SelectPrimitive.Item>
|
|
13256
|
+
/>
|
|
10558
13257
|
)
|
|
10559
13258
|
}
|
|
10560
13259
|
|
|
10561
|
-
function
|
|
13260
|
+
function TabsContent({
|
|
10562
13261
|
className,
|
|
10563
13262
|
...props
|
|
10564
|
-
}: React.ComponentProps<typeof
|
|
13263
|
+
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
|
10565
13264
|
return (
|
|
10566
|
-
<
|
|
10567
|
-
data-slot="
|
|
10568
|
-
className={cn("
|
|
13265
|
+
<TabsPrimitive.Content
|
|
13266
|
+
data-slot="tabs-content"
|
|
13267
|
+
className={cn("flex-1 text-sm outline-none", className)}
|
|
10569
13268
|
{...props}
|
|
10570
13269
|
/>
|
|
10571
13270
|
)
|
|
10572
13271
|
}
|
|
10573
13272
|
|
|
10574
|
-
|
|
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
|
|
@@ -10694,10 +13512,9 @@ echo "Creating src/data/config/menu.json..."
|
|
|
10694
13512
|
cat << 'END_OF_FILE_CONTENT' > "src/data/config/menu.json"
|
|
10695
13513
|
{
|
|
10696
13514
|
"main": [
|
|
10697
|
-
{
|
|
13515
|
+
{
|
|
10698
13516
|
"label": "Why",
|
|
10699
13517
|
"href": "#Why"
|
|
10700
|
-
|
|
10701
13518
|
},
|
|
10702
13519
|
{
|
|
10703
13520
|
"label": "Architecture",
|
|
@@ -10711,14 +13528,13 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/menu.json"
|
|
|
10711
13528
|
"label": "Get started",
|
|
10712
13529
|
"href": "#Getstarted"
|
|
10713
13530
|
},
|
|
10714
|
-
|
|
13531
|
+
{
|
|
10715
13532
|
"label": "GitHub",
|
|
10716
13533
|
"href": "https://github.com/olonjs/core"
|
|
10717
13534
|
}
|
|
10718
13535
|
]
|
|
10719
13536
|
}
|
|
10720
13537
|
END_OF_FILE_CONTENT
|
|
10721
|
-
# SKIP: src/data/config/menu.json:Zone.Identifier is binary and cannot be embedded as text.
|
|
10722
13538
|
echo "Creating src/data/config/menu_example_for_schema.json..."
|
|
10723
13539
|
cat << 'END_OF_FILE_CONTENT' > "src/data/config/menu_example_for_schema.json"
|
|
10724
13540
|
{
|
|
@@ -10834,7 +13650,6 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/site.json"
|
|
|
10834
13650
|
}
|
|
10835
13651
|
}
|
|
10836
13652
|
END_OF_FILE_CONTENT
|
|
10837
|
-
# SKIP: src/data/config/site.json:Zone.Identifier is binary and cannot be embedded as text.
|
|
10838
13653
|
echo "Creating src/data/config/theme.json..."
|
|
10839
13654
|
cat << 'END_OF_FILE_CONTENT' > "src/data/config/theme.json"
|
|
10840
13655
|
{
|
|
@@ -11002,7 +13817,6 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/theme.json"
|
|
|
11002
13817
|
}
|
|
11003
13818
|
}
|
|
11004
13819
|
END_OF_FILE_CONTENT
|
|
11005
|
-
# SKIP: src/data/config/theme.json:Zone.Identifier is binary and cannot be embedded as text.
|
|
11006
13820
|
mkdir -p "src/data/pages"
|
|
11007
13821
|
echo "Creating src/data/pages/design-system.json..."
|
|
11008
13822
|
cat << 'END_OF_FILE_CONTENT' > "src/data/pages/design-system.json"
|
|
@@ -11839,26 +14653,13 @@ cat << 'END_OF_FILE_CONTENT' > "src/entry-ssg.tsx"
|
|
|
11839
14653
|
import { renderToString } from 'react-dom/server';
|
|
11840
14654
|
import { StaticRouter } from 'react-router-dom/server';
|
|
11841
14655
|
import { ConfigProvider, PageRenderer, StudioProvider, resolveRuntimeConfig } from '@olonjs/core';
|
|
11842
|
-
import type { JsonPagesConfig,
|
|
14656
|
+
import type { JsonPagesConfig, PageConfig, SiteConfig, ThemeConfig } from '@/types';
|
|
11843
14657
|
import { ThemeProvider } from '@/components/ThemeProvider';
|
|
11844
14658
|
import { ComponentRegistry } from '@/lib/ComponentRegistry';
|
|
11845
14659
|
import { SECTION_SCHEMAS } from '@/lib/schemas';
|
|
11846
|
-
import {
|
|
11847
|
-
import siteData from '@/data/config/site.json';
|
|
11848
|
-
import menuData from '@/data/config/menu.json';
|
|
11849
|
-
import themeData from '@/data/config/theme.json';
|
|
14660
|
+
import { menuConfig, pages, refDocuments, siteConfig, themeConfig } from '@/runtime';
|
|
11850
14661
|
import tenantCss from '@/index.css?inline';
|
|
11851
14662
|
|
|
11852
|
-
const siteConfig = siteData as unknown as SiteConfig;
|
|
11853
|
-
const menuConfig: MenuConfig = { main: [] };
|
|
11854
|
-
const themeConfig = themeData as unknown as ThemeConfig;
|
|
11855
|
-
const pages = getFilePages();
|
|
11856
|
-
const refDocuments = {
|
|
11857
|
-
'menu.json': menuData,
|
|
11858
|
-
'config/menu.json': menuData,
|
|
11859
|
-
'src/data/config/menu.json': menuData,
|
|
11860
|
-
} satisfies NonNullable<JsonPagesConfig['refDocuments']>;
|
|
11861
|
-
|
|
11862
14663
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
11863
14664
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
11864
14665
|
}
|
|
@@ -13539,6 +16340,38 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
13539
16340
|
|
|
13540
16341
|
|
|
13541
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
|
+
|
|
13542
16375
|
END_OF_FILE_CONTENT
|
|
13543
16376
|
mkdir -p "src/types"
|
|
13544
16377
|
echo "Creating src/types.ts..."
|
|
@@ -13736,7 +16569,7 @@ import react from '@vitejs/plugin-react';
|
|
|
13736
16569
|
import tailwindcss from '@tailwindcss/vite';
|
|
13737
16570
|
import path from 'path';
|
|
13738
16571
|
import fs from 'fs';
|
|
13739
|
-
import { fileURLToPath
|
|
16572
|
+
import { fileURLToPath } from 'url';
|
|
13740
16573
|
|
|
13741
16574
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13742
16575
|
|
|
@@ -13793,8 +16626,7 @@ function normalizeManifestSlug(raw) {
|
|
|
13793
16626
|
}
|
|
13794
16627
|
|
|
13795
16628
|
async function loadWebMcpBuilders() {
|
|
13796
|
-
const
|
|
13797
|
-
const moduleUrl = pathToFileURL(path.resolve(corePkgPath, 'src', 'lib', 'webmcp-contracts.mjs')).href;
|
|
16629
|
+
const moduleUrl = import.meta.resolve('@olonjs/core');
|
|
13798
16630
|
return import(moduleUrl);
|
|
13799
16631
|
}
|
|
13800
16632
|
export default defineConfig({
|
|
@@ -13809,9 +16641,10 @@ export default defineConfig({
|
|
|
13809
16641
|
const isPageJsonRequest = isTenantPageJsonRequest(req, pathname);
|
|
13810
16642
|
|
|
13811
16643
|
const handleManifestRequest = async () => {
|
|
13812
|
-
const
|
|
13813
|
-
const
|
|
13814
|
-
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();
|
|
13815
16648
|
|
|
13816
16649
|
if (req.method === 'GET' && pathname === '/llms.txt') {
|
|
13817
16650
|
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
@@ -13927,6 +16760,7 @@ export default defineConfig({
|
|
|
13927
16760
|
if (!fs.existsSync(DATA_CONFIG_DIR)) fs.mkdirSync(DATA_CONFIG_DIR, { recursive: true });
|
|
13928
16761
|
if (!fs.existsSync(DATA_PAGES_DIR)) fs.mkdirSync(DATA_PAGES_DIR, { recursive: true });
|
|
13929
16762
|
if (projectState.site != null) fs.writeFileSync(path.join(DATA_CONFIG_DIR, 'site.json'), JSON.stringify(projectState.site, null, 2), 'utf8');
|
|
16763
|
+
if (projectState.menu != null) fs.writeFileSync(path.join(DATA_CONFIG_DIR, 'menu.json'), JSON.stringify(projectState.menu, null, 2), 'utf8');
|
|
13930
16764
|
if (projectState.theme != null) fs.writeFileSync(path.join(DATA_CONFIG_DIR, 'theme.json'), JSON.stringify(projectState.theme, null, 2), 'utf8');
|
|
13931
16765
|
if (projectState.page != null) {
|
|
13932
16766
|
const safeSlug = (slug.replace(/[^a-zA-Z0-9-_]/g, '_') || 'page');
|
|
@@ -13980,7 +16814,4 @@ export default defineConfig({
|
|
|
13980
16814
|
});
|
|
13981
16815
|
|
|
13982
16816
|
|
|
13983
|
-
|
|
13984
|
-
|
|
13985
|
-
|
|
13986
16817
|
END_OF_FILE_CONTENT
|