create-crm-tmp 1.1.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/.prettierignore +2 -0
- package/template/README.md +53 -67
- package/template/components.json +22 -0
- package/template/exemple-contacts.csv +54 -0
- package/template/next.config.ts +27 -1
- package/template/package.json +64 -27
- package/template/prisma/schema.prisma +821 -72
- package/template/skills-lock.json +25 -0
- package/template/src/app/(auth)/invite/[token]/page.tsx +21 -24
- package/template/src/app/(auth)/reset-password/complete/page.tsx +12 -21
- package/template/src/app/(auth)/reset-password/page.tsx +12 -8
- package/template/src/app/(auth)/reset-password/verify/page.tsx +12 -8
- package/template/src/app/(auth)/signin/page.tsx +20 -17
- package/template/src/app/(dashboard)/agenda/page.tsx +2231 -2188
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +10 -7
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +680 -323
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +11 -8
- package/template/src/app/(dashboard)/automatisation/page.tsx +473 -180
- package/template/src/app/(dashboard)/closing/page.tsx +500 -468
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +5035 -4126
- package/template/src/app/(dashboard)/contacts/companies/[id]/page.tsx +1703 -0
- package/template/src/app/(dashboard)/contacts/loading.tsx +13 -0
- package/template/src/app/(dashboard)/contacts/page.tsx +3776 -2064
- package/template/src/app/(dashboard)/dashboard/page.tsx +37 -519
- package/template/src/app/(dashboard)/error.tsx +37 -0
- package/template/src/app/(dashboard)/layout.tsx +1 -1
- package/template/src/app/(dashboard)/loading.tsx +5 -0
- package/template/src/app/(dashboard)/settings/loading.tsx +19 -0
- package/template/src/app/(dashboard)/settings/page.tsx +2685 -2489
- package/template/src/app/(dashboard)/templates/page.tsx +500 -300
- package/template/src/app/(dashboard)/users/list/page.tsx +356 -350
- package/template/src/app/(dashboard)/users/page.tsx +279 -310
- package/template/src/app/(dashboard)/users/permissions/page.tsx +104 -99
- package/template/src/app/(dashboard)/users/roles/page.tsx +164 -137
- package/template/src/app/api/audit-logs/route.ts +1 -1
- package/template/src/app/api/auth/google/callback/route.ts +8 -5
- package/template/src/app/api/auth/google/disconnect/route.ts +2 -2
- package/template/src/app/api/companies/[id]/activities/route.ts +131 -0
- package/template/src/app/api/companies/[id]/route.ts +195 -0
- package/template/src/app/api/companies/export/route.ts +206 -0
- package/template/src/app/api/companies/route.ts +166 -0
- package/template/src/app/api/contact-views/[id]/pin/route.ts +69 -0
- package/template/src/app/api/contact-views/[id]/route.ts +197 -0
- package/template/src/app/api/contact-views/route.ts +146 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/preview/route.ts +77 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +7 -17
- package/template/src/app/api/contacts/[id]/files/route.ts +83 -44
- package/template/src/app/api/contacts/[id]/interactions/route.ts +37 -0
- package/template/src/app/api/contacts/[id]/kyc/route.ts +71 -0
- package/template/src/app/api/contacts/[id]/meet/route.ts +38 -29
- package/template/src/app/api/contacts/[id]/route.ts +111 -20
- package/template/src/app/api/contacts/[id]/send-email/route.ts +6 -0
- package/template/src/app/api/contacts/[id]/workflows/run/route.ts +61 -0
- package/template/src/app/api/contacts/export/route.ts +12 -17
- package/template/src/app/api/contacts/import/route.ts +22 -19
- package/template/src/app/api/contacts/import-preview/route.ts +139 -0
- package/template/src/app/api/contacts/route.ts +202 -49
- package/template/src/app/api/dashboard/stats/route.ts +9 -292
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +203 -185
- package/template/src/app/api/invite/complete/route.ts +20 -23
- package/template/src/app/api/reminders/route.ts +1 -0
- package/template/src/app/api/reset-password/complete/route.ts +11 -13
- package/template/src/app/api/send/route.ts +9 -85
- package/template/src/app/api/settings/closing-reasons/[id]/route.ts +10 -21
- package/template/src/app/api/settings/closing-reasons/route.ts +10 -21
- package/template/src/app/api/settings/company/route.ts +19 -26
- package/template/src/app/api/settings/google-ads/[id]/route.ts +20 -23
- package/template/src/app/api/settings/google-ads/route.ts +20 -23
- package/template/src/app/api/settings/google-sheet/[id]/route.ts +20 -23
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +23 -32
- package/template/src/app/api/settings/google-sheet/preview/route.ts +104 -0
- package/template/src/app/api/settings/google-sheet/route.ts +20 -23
- package/template/src/app/api/settings/meta-leads/[id]/route.ts +20 -23
- package/template/src/app/api/settings/meta-leads/route.ts +20 -23
- package/template/src/app/api/settings/statuses/[id]/route.ts +33 -23
- package/template/src/app/api/settings/statuses/route.ts +24 -22
- package/template/src/app/api/statuses/route.ts +2 -5
- package/template/src/app/api/tasks/[id]/attendees/route.ts +14 -7
- package/template/src/app/api/tasks/[id]/route.ts +161 -137
- package/template/src/app/api/tasks/meet/route.ts +11 -8
- package/template/src/app/api/tasks/route.ts +155 -95
- package/template/src/app/api/templates/[id]/route.ts +22 -13
- package/template/src/app/api/templates/route.ts +22 -5
- package/template/src/app/api/users/[id]/resend-invite/route.ts +95 -0
- package/template/src/app/api/users/[id]/route.ts +16 -1
- package/template/src/app/api/users/commercials/route.ts +38 -0
- package/template/src/app/api/users/for-agenda/route.ts +1 -2
- package/template/src/app/api/users/route.ts +94 -55
- package/template/src/app/api/webhooks/google-ads/route.ts +20 -1
- package/template/src/app/api/webhooks/meta-leads/route.ts +18 -1
- package/template/src/app/api/workflows/[id]/route.ts +33 -6
- package/template/src/app/api/workflows/process/route.ts +509 -146
- package/template/src/app/api/workflows/route.ts +46 -4
- package/template/src/app/globals.css +210 -101
- package/template/src/app/layout.tsx +19 -8
- package/template/src/app/page.tsx +37 -7
- package/template/src/components/address-autocomplete.tsx +232 -0
- package/template/src/components/contacts/filter-bar.tsx +181 -0
- package/template/src/components/contacts/filter-builder.tsx +589 -0
- package/template/src/components/contacts/save-view-dialog.tsx +160 -0
- package/template/src/components/contacts/views-tab-bar.tsx +440 -0
- package/template/src/components/dashboard/activity-chart.tsx +31 -39
- package/template/src/components/dashboard/dashboard-content.tsx +79 -0
- package/template/src/components/dashboard/stat-card.tsx +40 -42
- package/template/src/components/dashboard/tasks-pie-chart.tsx +34 -37
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +78 -72
- package/template/src/components/date-picker.tsx +396 -0
- package/template/src/components/editor.tsx +27 -13
- package/template/src/components/email-template.tsx +4 -2
- package/template/src/components/global-search.tsx +358 -0
- package/template/src/components/header.tsx +57 -62
- package/template/src/components/invitation-email-template.tsx +4 -2
- package/template/src/components/lazy-editor.tsx +11 -0
- package/template/src/components/meet-cancellation-email-template.tsx +11 -3
- package/template/src/components/meet-confirmation-email-template.tsx +10 -3
- package/template/src/components/meet-update-email-template.tsx +10 -3
- package/template/src/components/page-header.tsx +19 -15
- package/template/src/components/protected-page.tsx +94 -0
- package/template/src/components/reset-password-email-template.tsx +4 -2
- package/template/src/components/sidebar.tsx +92 -94
- package/template/src/components/skeleton.tsx +128 -42
- package/template/src/components/ui/accordion.tsx +64 -0
- package/template/src/components/ui/alert-dialog.tsx +139 -0
- package/template/src/components/ui/button.tsx +60 -0
- package/template/src/components/view-as-banner.tsx +1 -1
- package/template/src/components/view-as-modal.tsx +21 -16
- package/template/src/config/nav-pages.ts +108 -0
- package/template/src/contexts/app-toast-context.tsx +174 -0
- package/template/src/contexts/sidebar-context.tsx +16 -47
- package/template/src/contexts/task-reminder-context.tsx +6 -6
- package/template/src/contexts/view-as-context.tsx +11 -16
- package/template/src/hooks/use-alert.tsx +65 -0
- package/template/src/hooks/use-confirm.tsx +87 -0
- package/template/src/hooks/use-contact-views.ts +140 -0
- package/template/src/hooks/use-contacts.ts +69 -0
- package/template/src/hooks/use-fetch.ts +17 -0
- package/template/src/hooks/use-focus-trap.ts +73 -0
- package/template/src/hooks/use-statuses.ts +22 -0
- package/template/src/lib/address-api.ts +155 -0
- package/template/src/lib/cache.ts +73 -0
- package/template/src/lib/check-permission.ts +12 -177
- package/template/src/lib/contact-interactions.ts +3 -1
- package/template/src/lib/contact-view-filters.ts +341 -0
- package/template/src/lib/dashboard-stats.ts +224 -0
- package/template/src/lib/date-utils.ts +49 -0
- package/template/src/lib/get-auth-user.ts +25 -0
- package/template/src/lib/google-calendar.ts +54 -12
- package/template/src/lib/google-drive.ts +796 -75
- package/template/src/lib/google-fetch.ts +63 -0
- package/template/src/lib/local-storage.ts +34 -0
- package/template/src/lib/permissions.ts +245 -47
- package/template/src/lib/prisma.ts +11 -11
- package/template/src/lib/roles.ts +14 -39
- package/template/src/lib/template-variables.ts +67 -33
- package/template/src/lib/utils.ts +26 -2
- package/template/src/lib/workflow-executor.ts +445 -229
- package/template/src/proxy.ts +34 -73
- package/template/src/types/contact-views.ts +351 -0
- package/template/src/types/yousign.ts +52 -0
- package/template/vercel.json +12 -0
- package/template/WORKFLOWS_CRON.md +0 -185
- package/template/prisma/migrations/20251126144728_init/migration.sql +0 -78
- package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +0 -5
- package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +0 -19
- package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +0 -22
- package/template/prisma/migrations/20251128132303_add_status/migration.sql +0 -23
- package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +0 -75
- package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +0 -2
- package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +0 -45
- package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +0 -2
- package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +0 -27
- package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +0 -20
- package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +0 -18
- package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +0 -32
- package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +0 -20
- package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +0 -12
- package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +0 -21
- package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +0 -11
- package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +0 -12
- package/template/prisma/migrations/20251208094843_mg/migration.sql +0 -14
- package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +0 -14
- package/template/prisma/migrations/20251208110000_add_templates/migration.sql +0 -26
- package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +0 -2
- package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +0 -2
- package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +0 -2
- package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +0 -3
- package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +0 -21
- package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +0 -2
- package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +0 -10
- package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +0 -26
- package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +0 -24
- package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +0 -11
- package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +0 -12
- package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +0 -25
- package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +0 -8
- package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +0 -2
- package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +0 -80
- package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +0 -32
- package/template/prisma/migrations/20251220000000_add_task_interaction_type/migration.sql +0 -4
- package/template/prisma/migrations/20251221000000_add_task_type/migration.sql +0 -3
- package/template/prisma/migrations/20251221000001_add_event_color/migration.sql +0 -23
- package/template/prisma/migrations/20260210114913_add_dashboard_widget/migration.sql +0 -20
- package/template/prisma/migrations/migration_lock.toml +0 -3
- package/template/src/app/(dashboard)/users/layout.tsx +0 -30
- package/template/src/app/api/dashboard/widgets/[id]/route.ts +0 -47
- package/template/src/app/api/dashboard/widgets/route.ts +0 -181
- package/template/src/components/dashboard/add-widget-dialog.tsx +0 -161
- package/template/src/components/dashboard/color-picker.tsx +0 -65
- package/template/src/components/dashboard/contacts-chart.tsx +0 -69
- package/template/src/components/dashboard/interactions-by-type-chart.tsx +0 -121
- package/template/src/components/dashboard/recent-activity.tsx +0 -157
- package/template/src/components/dashboard/sales-analytics-chart.tsx +0 -77
- package/template/src/components/dashboard/status-distribution-chart.tsx +0 -82
- package/template/src/components/dashboard/top-contacts-list.tsx +0 -119
- package/template/src/components/dashboard/widget-wrapper.tsx +0 -39
- package/template/src/contexts/dashboard-theme-context.tsx +0 -58
- package/template/src/lib/dashboard-themes.ts +0 -140
- package/template/src/lib/default-widgets.ts +0 -14
- package/template/src/lib/widget-registry.ts +0 -177
|
@@ -1,59 +1,145 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Composants Skeleton pour les états de chargement
|
|
2
|
+
* Composants Skeleton, Spinner et PageLoader pour les états de chargement
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { cn } from '@/lib/utils';
|
|
6
|
+
import { Loader2 } from 'lucide-react';
|
|
6
7
|
|
|
7
8
|
export function Skeleton({ className }: { className?: string }) {
|
|
8
9
|
return (
|
|
9
10
|
<div
|
|
10
|
-
className={cn('animate-pulse rounded bg-
|
|
11
|
+
className={cn('animate-pulse rounded bg-muted', className)}
|
|
11
12
|
aria-label="Chargement..."
|
|
12
13
|
/>
|
|
13
14
|
);
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
const SPINNER_SIZES = {
|
|
18
|
+
xs: 'h-3 w-3',
|
|
19
|
+
sm: 'h-4 w-4',
|
|
20
|
+
md: 'h-5 w-5',
|
|
21
|
+
lg: 'h-8 w-8',
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
interface SpinnerProps {
|
|
25
|
+
size?: keyof typeof SPINNER_SIZES;
|
|
26
|
+
className?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function Spinner({ size = 'lg', className }: Readonly<SpinnerProps>) {
|
|
30
|
+
return <Loader2 className={cn('animate-spin text-primary', SPINNER_SIZES[size], className)} />;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface PageLoaderProps {
|
|
34
|
+
text?: string;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function PageLoader({ text = 'Chargement...', className }: Readonly<PageLoaderProps>) {
|
|
39
|
+
return (
|
|
40
|
+
<div className={cn('flex h-full items-center justify-center py-12', className)}>
|
|
41
|
+
<div className="text-center">
|
|
42
|
+
<Spinner size="lg" className="mx-auto" />
|
|
43
|
+
<p className="mt-3 text-sm text-muted-foreground">{text}</p>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface ListPageSkeletonProps {
|
|
50
|
+
headerWidth?: string;
|
|
51
|
+
descriptionWidth?: string;
|
|
52
|
+
buttonWidth?: string;
|
|
53
|
+
itemCount?: number;
|
|
54
|
+
itemHeight?: string;
|
|
55
|
+
hasSearchBar?: boolean;
|
|
56
|
+
layout?: 'list' | 'grid';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function ListPageSkeleton({
|
|
60
|
+
headerWidth = 'w-32',
|
|
61
|
+
descriptionWidth = 'w-48',
|
|
62
|
+
buttonWidth = 'w-36',
|
|
63
|
+
itemCount = 6,
|
|
64
|
+
itemHeight = 'h-16',
|
|
65
|
+
hasSearchBar = true,
|
|
66
|
+
layout = 'list',
|
|
67
|
+
}: Readonly<ListPageSkeletonProps>) {
|
|
68
|
+
return (
|
|
69
|
+
<div className="h-full">
|
|
70
|
+
<div className="flex items-center justify-between border-b border-border bg-card px-4 py-4 sm:px-6">
|
|
71
|
+
<div>
|
|
72
|
+
<Skeleton className={cn('h-7', headerWidth)} />
|
|
73
|
+
<Skeleton className={cn('mt-1 h-4', descriptionWidth)} />
|
|
74
|
+
</div>
|
|
75
|
+
<Skeleton className={cn('h-10 rounded-lg', buttonWidth)} />
|
|
76
|
+
</div>
|
|
77
|
+
<div className="p-4 sm:p-6">
|
|
78
|
+
{hasSearchBar && (
|
|
79
|
+
<div className="mb-4 flex gap-3">
|
|
80
|
+
<Skeleton className="h-10 flex-1 rounded-lg" />
|
|
81
|
+
<Skeleton className="h-10 w-28 rounded-lg" />
|
|
82
|
+
</div>
|
|
83
|
+
)}
|
|
84
|
+
{layout === 'list' ? (
|
|
85
|
+
<div className="space-y-3">
|
|
86
|
+
{Array.from({ length: itemCount }).map((_, i) => (
|
|
87
|
+
<Skeleton key={i} className={cn('rounded-lg', itemHeight)} />
|
|
88
|
+
))}
|
|
89
|
+
</div>
|
|
90
|
+
) : (
|
|
91
|
+
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
92
|
+
{Array.from({ length: itemCount }).map((_, i) => (
|
|
93
|
+
<Skeleton key={i} className={cn('rounded-lg', itemHeight)} />
|
|
94
|
+
))}
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
16
102
|
export function ContactTableSkeleton() {
|
|
17
103
|
return (
|
|
18
|
-
<div className="overflow-x-auto rounded-lg bg-
|
|
19
|
-
<table className="min-w-full divide-y divide-
|
|
20
|
-
<thead className="bg-
|
|
104
|
+
<div className="overflow-x-auto rounded-lg border border-border bg-card shadow-(--shadow-card)">
|
|
105
|
+
<table className="min-w-full divide-y divide-border">
|
|
106
|
+
<thead className="bg-muted">
|
|
21
107
|
<tr>
|
|
22
108
|
<th className="px-3 py-3 sm:px-6">
|
|
23
109
|
<Skeleton className="h-4 w-4" />
|
|
24
110
|
</th>
|
|
25
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
111
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
26
112
|
Contact
|
|
27
113
|
</th>
|
|
28
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
114
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
29
115
|
Téléphone
|
|
30
116
|
</th>
|
|
31
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
117
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
32
118
|
Email
|
|
33
119
|
</th>
|
|
34
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
120
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
35
121
|
Statut
|
|
36
122
|
</th>
|
|
37
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
123
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
38
124
|
Origine
|
|
39
125
|
</th>
|
|
40
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
126
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
41
127
|
COMMERCIAL
|
|
42
128
|
</th>
|
|
43
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
129
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
44
130
|
TÉLÉPRO
|
|
45
131
|
</th>
|
|
46
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
132
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
47
133
|
CRÉÉ LE
|
|
48
134
|
</th>
|
|
49
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
135
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
50
136
|
MODIFIÉ LE
|
|
51
137
|
</th>
|
|
52
138
|
</tr>
|
|
53
139
|
</thead>
|
|
54
|
-
<tbody className="divide-y divide-
|
|
140
|
+
<tbody className="divide-y divide-border bg-card">
|
|
55
141
|
{Array.from({ length: 8 }).map((_, i) => (
|
|
56
|
-
<tr key={i} className="hover:bg-
|
|
142
|
+
<tr key={i} className="hover:bg-muted/70">
|
|
57
143
|
<td className="px-3 py-4 whitespace-nowrap sm:px-6">
|
|
58
144
|
<Skeleton className="h-4 w-4" />
|
|
59
145
|
</td>
|
|
@@ -102,7 +188,7 @@ export function ContactCardsSkeleton() {
|
|
|
102
188
|
return (
|
|
103
189
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
104
190
|
{Array.from({ length: 9 }).map((_, i) => (
|
|
105
|
-
<div key={i} className="rounded-lg border border-
|
|
191
|
+
<div key={i} className="rounded-lg border border-border bg-card p-6 shadow-(--shadow-card)">
|
|
106
192
|
{/* En-tête */}
|
|
107
193
|
<div className="mb-4 flex items-start justify-between">
|
|
108
194
|
<div className="flex items-center gap-3">
|
|
@@ -140,7 +226,7 @@ export function ContactCardsSkeleton() {
|
|
|
140
226
|
</div>
|
|
141
227
|
|
|
142
228
|
{/* Pied de carte avec utilisateurs assignés */}
|
|
143
|
-
<div className="flex items-start justify-between border-t border-
|
|
229
|
+
<div className="flex items-start justify-between border-t border-border/70 pt-4">
|
|
144
230
|
<div className="space-y-2">
|
|
145
231
|
<div className="flex items-center gap-2">
|
|
146
232
|
<Skeleton className="h-7 w-7 rounded-full" />
|
|
@@ -164,12 +250,12 @@ export function ContactCardsSkeleton() {
|
|
|
164
250
|
|
|
165
251
|
export function AgendaMonthSkeleton() {
|
|
166
252
|
return (
|
|
167
|
-
<div className="rounded-lg bg-
|
|
168
|
-
<div className="grid grid-cols-7 border-b border-
|
|
253
|
+
<div className="rounded-lg border border-border bg-card shadow-(--shadow-card)">
|
|
254
|
+
<div className="grid grid-cols-7 border-b border-border">
|
|
169
255
|
{['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'].map((day) => (
|
|
170
256
|
<div
|
|
171
257
|
key={day}
|
|
172
|
-
className="border-r border-
|
|
258
|
+
className="border-r border-border p-3 text-center text-sm font-semibold text-foreground last:border-r-0"
|
|
173
259
|
>
|
|
174
260
|
{day}
|
|
175
261
|
</div>
|
|
@@ -179,7 +265,7 @@ export function AgendaMonthSkeleton() {
|
|
|
179
265
|
{Array.from({ length: 42 }).map((_, i) => (
|
|
180
266
|
<div
|
|
181
267
|
key={i}
|
|
182
|
-
className="min-h-[100px] border-r border-b border-
|
|
268
|
+
className="min-h-[100px] border-r border-b border-border p-2 last:border-r-0"
|
|
183
269
|
>
|
|
184
270
|
<Skeleton className="mb-2 h-5 w-6" />
|
|
185
271
|
<div className="space-y-1">
|
|
@@ -202,31 +288,31 @@ export function AgendaWeekSkeleton() {
|
|
|
202
288
|
};
|
|
203
289
|
|
|
204
290
|
return (
|
|
205
|
-
<div className="overflow-auto rounded-lg bg-
|
|
206
|
-
<div className="grid grid-cols-8 border-b border-
|
|
291
|
+
<div className="overflow-auto rounded-lg border border-border bg-card shadow-(--shadow-card)">
|
|
292
|
+
<div className="grid grid-cols-8 border-b border-border bg-muted text-xs font-medium text-muted-foreground">
|
|
207
293
|
<div className="px-3 py-2 text-right">(UTC+01:00) Hr</div>
|
|
208
294
|
{Array.from({ length: 7 }).map((_, i) => (
|
|
209
|
-
<div key={i} className="border-l border-
|
|
295
|
+
<div key={i} className="border-l border-border px-3 py-2 text-center">
|
|
210
296
|
<Skeleton className="mx-auto h-4 w-12" />
|
|
211
297
|
<Skeleton className="mx-auto mt-1 h-8 w-8 rounded-full" />
|
|
212
298
|
</div>
|
|
213
299
|
))}
|
|
214
300
|
</div>
|
|
215
301
|
<div className="grid grid-cols-8 text-xs">
|
|
216
|
-
<div className="border-r border-
|
|
302
|
+
<div className="border-r border-border bg-muted">
|
|
217
303
|
{HOURS.map((hour) => (
|
|
218
304
|
<div
|
|
219
305
|
key={hour}
|
|
220
|
-
className="flex h-16 items-start justify-end border-b border-
|
|
306
|
+
className="flex h-16 items-start justify-end border-b border-border pr-2"
|
|
221
307
|
>
|
|
222
308
|
<Skeleton className="h-3 w-10" />
|
|
223
309
|
</div>
|
|
224
310
|
))}
|
|
225
311
|
</div>
|
|
226
312
|
{Array.from({ length: 7 }).map((_, dayIndex) => (
|
|
227
|
-
<div key={dayIndex} className="border-l border-
|
|
313
|
+
<div key={dayIndex} className="border-l border-border">
|
|
228
314
|
{HOURS.map((hour, hourIndex) => (
|
|
229
|
-
<div key={hour} className="relative h-16 border-b border-
|
|
315
|
+
<div key={hour} className="relative h-16 border-b border-border/70 px-1.5 py-0.5">
|
|
230
316
|
{shouldShowSkeleton(dayIndex, hourIndex) && (
|
|
231
317
|
<Skeleton className="h-12 w-full rounded" />
|
|
232
318
|
)}
|
|
@@ -243,7 +329,7 @@ export function AgendaDaySkeleton() {
|
|
|
243
329
|
return (
|
|
244
330
|
<div className="space-y-4">
|
|
245
331
|
{Array.from({ length: 5 }).map((_, i) => (
|
|
246
|
-
<div key={i} className="rounded-lg border border-
|
|
332
|
+
<div key={i} className="rounded-lg border border-border bg-card p-4 shadow-(--shadow-card)">
|
|
247
333
|
<div className="flex items-start justify-between">
|
|
248
334
|
<div className="flex-1">
|
|
249
335
|
<div className="flex items-center gap-2">
|
|
@@ -271,30 +357,30 @@ export function AgendaDaySkeleton() {
|
|
|
271
357
|
|
|
272
358
|
export function UsersTableSkeleton() {
|
|
273
359
|
return (
|
|
274
|
-
<div className="overflow-x-auto rounded-lg bg-
|
|
275
|
-
<table className="min-w-full divide-y divide-
|
|
276
|
-
<thead className="bg-
|
|
360
|
+
<div className="overflow-x-auto rounded-lg border border-border bg-card shadow-(--shadow-card)">
|
|
361
|
+
<table className="min-w-full divide-y divide-border">
|
|
362
|
+
<thead className="bg-muted">
|
|
277
363
|
<tr>
|
|
278
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
364
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
279
365
|
Utilisateur
|
|
280
366
|
</th>
|
|
281
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
367
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
282
368
|
Email
|
|
283
369
|
</th>
|
|
284
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
370
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
285
371
|
Rôle
|
|
286
372
|
</th>
|
|
287
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
373
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
288
374
|
Email vérifié
|
|
289
375
|
</th>
|
|
290
|
-
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-
|
|
376
|
+
<th className="px-3 py-3 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase sm:px-6">
|
|
291
377
|
Compte
|
|
292
378
|
</th>
|
|
293
379
|
</tr>
|
|
294
380
|
</thead>
|
|
295
|
-
<tbody className="divide-y divide-
|
|
381
|
+
<tbody className="divide-y divide-border bg-card">
|
|
296
382
|
{Array.from({ length: 6 }).map((_, i) => (
|
|
297
|
-
<tr key={i} className="hover:bg-
|
|
383
|
+
<tr key={i} className="hover:bg-muted/70">
|
|
298
384
|
<td className="px-3 py-4 whitespace-nowrap sm:px-6">
|
|
299
385
|
<div className="flex items-center">
|
|
300
386
|
<Skeleton className="h-8 w-8 rounded-full sm:h-10 sm:w-10" />
|
|
@@ -330,7 +416,7 @@ export function TemplatesPageSkeleton() {
|
|
|
330
416
|
return (
|
|
331
417
|
<div className="h-full">
|
|
332
418
|
{/* Header Skeleton */}
|
|
333
|
-
<div className="border-b border-
|
|
419
|
+
<div className="border-b border-border bg-card px-4 py-4 sm:px-6 lg:px-8">
|
|
334
420
|
<div className="flex items-center justify-between">
|
|
335
421
|
<div className="space-y-2">
|
|
336
422
|
<Skeleton className="h-8 w-48" />
|
|
@@ -353,7 +439,7 @@ export function TemplatesPageSkeleton() {
|
|
|
353
439
|
{Array.from({ length: 6 }).map((_, i) => (
|
|
354
440
|
<div
|
|
355
441
|
key={i}
|
|
356
|
-
className="rounded-lg border border-
|
|
442
|
+
className="rounded-lg border border-border bg-card p-4 shadow-(--shadow-card) transition-shadow"
|
|
357
443
|
>
|
|
358
444
|
<div className="flex items-start justify-between">
|
|
359
445
|
<div className="flex-1">
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
5
|
+
import { ChevronDownIcon } from 'lucide-react';
|
|
6
|
+
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
8
|
+
|
|
9
|
+
function Accordion({ ...props }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
|
|
10
|
+
return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function AccordionItem({
|
|
14
|
+
className,
|
|
15
|
+
...props
|
|
16
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
|
|
17
|
+
return (
|
|
18
|
+
<AccordionPrimitive.Item
|
|
19
|
+
data-slot="accordion-item"
|
|
20
|
+
className={cn('border-b last:border-b-0', className)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function AccordionTrigger({
|
|
27
|
+
className,
|
|
28
|
+
children,
|
|
29
|
+
...props
|
|
30
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
|
|
31
|
+
return (
|
|
32
|
+
<AccordionPrimitive.Header className="flex">
|
|
33
|
+
<AccordionPrimitive.Trigger
|
|
34
|
+
data-slot="accordion-trigger"
|
|
35
|
+
className={cn(
|
|
36
|
+
'focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180',
|
|
37
|
+
className,
|
|
38
|
+
)}
|
|
39
|
+
{...props}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
|
|
43
|
+
</AccordionPrimitive.Trigger>
|
|
44
|
+
</AccordionPrimitive.Header>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function AccordionContent({
|
|
49
|
+
className,
|
|
50
|
+
children,
|
|
51
|
+
...props
|
|
52
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
|
|
53
|
+
return (
|
|
54
|
+
<AccordionPrimitive.Content
|
|
55
|
+
data-slot="accordion-content"
|
|
56
|
+
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
|
|
57
|
+
{...props}
|
|
58
|
+
>
|
|
59
|
+
<div className={cn('pt-0 pb-4', className)}>{children}</div>
|
|
60
|
+
</AccordionPrimitive.Content>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
|
|
5
|
+
|
|
6
|
+
import { cn } from '@/lib/utils';
|
|
7
|
+
import { buttonVariants } from '@/components/ui/button';
|
|
8
|
+
|
|
9
|
+
function AlertDialog({
|
|
10
|
+
...props
|
|
11
|
+
}: Readonly<React.ComponentProps<typeof AlertDialogPrimitive.Root>>) {
|
|
12
|
+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function AlertDialogTrigger({
|
|
16
|
+
...props
|
|
17
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
|
|
18
|
+
return <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function AlertDialogPortal({
|
|
22
|
+
...props
|
|
23
|
+
}: Readonly<React.ComponentProps<typeof AlertDialogPrimitive.Portal>>) {
|
|
24
|
+
return <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function AlertDialogOverlay({
|
|
28
|
+
className,
|
|
29
|
+
...props
|
|
30
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
|
|
31
|
+
return (
|
|
32
|
+
<AlertDialogPrimitive.Overlay
|
|
33
|
+
data-slot="alert-dialog-overlay"
|
|
34
|
+
className={cn(
|
|
35
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
|
|
36
|
+
className,
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function AlertDialogContent({
|
|
44
|
+
className,
|
|
45
|
+
...props
|
|
46
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
|
|
47
|
+
return (
|
|
48
|
+
<AlertDialogPortal>
|
|
49
|
+
<AlertDialogOverlay />
|
|
50
|
+
<AlertDialogPrimitive.Content
|
|
51
|
+
data-slot="alert-dialog-content"
|
|
52
|
+
className={cn(
|
|
53
|
+
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
|
|
54
|
+
className,
|
|
55
|
+
)}
|
|
56
|
+
{...props}
|
|
57
|
+
/>
|
|
58
|
+
</AlertDialogPortal>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function AlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
data-slot="alert-dialog-header"
|
|
66
|
+
className={cn('flex flex-col gap-2 text-center sm:text-left', className)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function AlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
data-slot="alert-dialog-footer"
|
|
76
|
+
className={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function AlertDialogTitle({
|
|
83
|
+
className,
|
|
84
|
+
...props
|
|
85
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
86
|
+
return (
|
|
87
|
+
<AlertDialogPrimitive.Title
|
|
88
|
+
data-slot="alert-dialog-title"
|
|
89
|
+
className={cn('text-lg font-semibold', className)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function AlertDialogDescription({
|
|
96
|
+
className,
|
|
97
|
+
...props
|
|
98
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
99
|
+
return (
|
|
100
|
+
<AlertDialogPrimitive.Description
|
|
101
|
+
data-slot="alert-dialog-description"
|
|
102
|
+
className={cn('text-muted-foreground text-sm', className)}
|
|
103
|
+
{...props}
|
|
104
|
+
/>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function AlertDialogAction({
|
|
109
|
+
className,
|
|
110
|
+
...props
|
|
111
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
|
|
112
|
+
return <AlertDialogPrimitive.Action className={cn(buttonVariants(), className)} {...props} />;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function AlertDialogCancel({
|
|
116
|
+
className,
|
|
117
|
+
...props
|
|
118
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
|
|
119
|
+
return (
|
|
120
|
+
<AlertDialogPrimitive.Cancel
|
|
121
|
+
className={cn(buttonVariants({ variant: 'outline' }), className)}
|
|
122
|
+
{...props}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
AlertDialog,
|
|
129
|
+
AlertDialogPortal,
|
|
130
|
+
AlertDialogOverlay,
|
|
131
|
+
AlertDialogTrigger,
|
|
132
|
+
AlertDialogContent,
|
|
133
|
+
AlertDialogHeader,
|
|
134
|
+
AlertDialogFooter,
|
|
135
|
+
AlertDialogTitle,
|
|
136
|
+
AlertDialogDescription,
|
|
137
|
+
AlertDialogAction,
|
|
138
|
+
AlertDialogCancel,
|
|
139
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
13
|
+
destructive:
|
|
14
|
+
'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
|
15
|
+
outline:
|
|
16
|
+
'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
|
|
17
|
+
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
18
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
|
19
|
+
link: 'text-primary underline-offset-4 hover:underline',
|
|
20
|
+
},
|
|
21
|
+
size: {
|
|
22
|
+
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
|
|
23
|
+
sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
|
|
24
|
+
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
|
|
25
|
+
icon: 'size-9',
|
|
26
|
+
'icon-sm': 'size-8',
|
|
27
|
+
'icon-lg': 'size-10',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
variant: 'default',
|
|
32
|
+
size: 'default',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
function Button({
|
|
38
|
+
className,
|
|
39
|
+
variant = 'default',
|
|
40
|
+
size = 'default',
|
|
41
|
+
asChild = false,
|
|
42
|
+
...props
|
|
43
|
+
}: React.ComponentProps<'button'> &
|
|
44
|
+
VariantProps<typeof buttonVariants> & {
|
|
45
|
+
asChild?: boolean;
|
|
46
|
+
}) {
|
|
47
|
+
const Comp = asChild ? Slot : 'button';
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Comp
|
|
51
|
+
data-slot="button"
|
|
52
|
+
data-variant={variant}
|
|
53
|
+
data-size={size}
|
|
54
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { Button, buttonVariants };
|
|
@@ -16,7 +16,7 @@ export function ViewAsBanner() {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
<div className="shrink-0 bg-
|
|
19
|
+
<div className="shrink-0 bg-blue-600 px-4 py-3 text-white shadow-md">
|
|
20
20
|
<div className="flex items-center justify-between gap-4">
|
|
21
21
|
<div className="flex items-center gap-3">
|
|
22
22
|
<Eye className="h-5 w-5 shrink-0" />
|