nextworks 0.0.1 → 0.1.0-alpha.1
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/README.md +209 -30
- package/dist/.gitkeep +0 -0
- package/dist/cli_manifests/auth_manifest.json +86 -0
- package/dist/cli_manifests/blocks_manifest.json +185 -0
- package/dist/cli_manifests/data_manifest.json +51 -0
- package/dist/cli_manifests/forms_manifest.json +61 -0
- package/dist/commands/admin-posts.d.ts +2 -0
- package/dist/commands/admin-posts.d.ts.map +1 -0
- package/dist/commands/admin-posts.js +15 -0
- package/dist/commands/admin-posts.js.map +1 -0
- package/dist/commands/admin-users.d.ts +2 -0
- package/dist/commands/admin-users.d.ts.map +1 -0
- package/dist/commands/admin-users.js +15 -0
- package/dist/commands/admin-users.js.map +1 -0
- package/dist/commands/auth-core.d.ts +2 -0
- package/dist/commands/auth-core.d.ts.map +1 -0
- package/dist/commands/auth-core.js +83 -0
- package/dist/commands/auth-core.js.map +1 -0
- package/dist/commands/auth-forms.d.ts +2 -0
- package/dist/commands/auth-forms.d.ts.map +1 -0
- package/dist/commands/auth-forms.js +15 -0
- package/dist/commands/auth-forms.js.map +1 -0
- package/dist/commands/blocks-options.d.ts +7 -0
- package/dist/commands/blocks-options.d.ts.map +1 -0
- package/dist/commands/blocks-options.js +19 -0
- package/dist/commands/blocks-options.js.map +1 -0
- package/dist/commands/blocks.d.ts +7 -0
- package/dist/commands/blocks.d.ts.map +1 -0
- package/dist/commands/blocks.js +145 -0
- package/dist/commands/blocks.js.map +1 -0
- package/dist/commands/data.d.ts +3 -0
- package/dist/commands/data.d.ts.map +1 -0
- package/dist/commands/data.js +88 -0
- package/dist/commands/data.js.map +1 -0
- package/dist/commands/forms.d.ts +6 -0
- package/dist/commands/forms.d.ts.map +1 -0
- package/dist/commands/forms.js +107 -0
- package/dist/commands/forms.js.map +1 -0
- package/dist/commands/remove-auth-core.d.ts +2 -0
- package/dist/commands/remove-auth-core.d.ts.map +1 -0
- package/dist/commands/remove-auth-core.js +69 -0
- package/dist/commands/remove-auth-core.js.map +1 -0
- package/dist/commands/remove-blocks.d.ts +2 -0
- package/dist/commands/remove-blocks.d.ts.map +1 -0
- package/dist/commands/remove-blocks.js +36 -0
- package/dist/commands/remove-blocks.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/kits/auth-core/README.md +106 -0
- package/dist/kits/auth-core/app/(protected)/dashboard/page.tsx +8 -0
- package/dist/kits/auth-core/app/(protected)/layout.tsx +18 -0
- package/dist/kits/auth-core/app/(protected)/settings/profile/page.tsx +15 -0
- package/dist/kits/auth-core/app/(protected)/settings/profile/profile-form.tsx +114 -0
- package/dist/kits/auth-core/app/api/auth/[...nextauth]/route.ts +1 -0
- package/dist/kits/auth-core/app/api/auth/forgot-password/route.ts +114 -0
- package/dist/kits/auth-core/app/api/auth/providers/route.ts +6 -0
- package/dist/kits/auth-core/app/api/auth/reset-password/route.ts +63 -0
- package/dist/kits/auth-core/app/api/auth/send-verify-email/route.ts +6 -0
- package/dist/kits/auth-core/app/api/signup/route.ts +41 -0
- package/dist/kits/auth-core/app/auth/forgot-password/page.tsx +21 -0
- package/dist/kits/auth-core/app/auth/login/page.tsx +5 -0
- package/dist/kits/auth-core/app/auth/reset-password/page.tsx +187 -0
- package/dist/kits/auth-core/app/auth/signup/page.tsx +5 -0
- package/dist/kits/auth-core/app/auth/verify-email/page.tsx +11 -0
- package/dist/kits/auth-core/components/admin/admin-header.tsx +57 -0
- package/dist/kits/auth-core/components/auth/dashboard.tsx +237 -0
- package/dist/kits/auth-core/components/auth/forgot-password-form.tsx +90 -0
- package/dist/kits/auth-core/components/auth/login-form.tsx +467 -0
- package/dist/kits/auth-core/components/auth/logout-button.tsx +50 -0
- package/dist/kits/auth-core/components/auth/minimal-logout-button.tsx +40 -0
- package/dist/kits/auth-core/components/auth/signup-form.tsx +468 -0
- package/dist/kits/auth-core/components/require-auth.tsx +59 -0
- package/dist/kits/auth-core/components/session-provider.tsx +11 -0
- package/dist/kits/auth-core/components/ui/README.txt +1 -0
- package/dist/kits/auth-core/components/ui/button.tsx +55 -0
- package/dist/kits/auth-core/components/ui/input.tsx +25 -0
- package/dist/kits/auth-core/components/ui/label.tsx +23 -0
- package/dist/kits/auth-core/lib/api/errors.ts +14 -0
- package/dist/kits/auth-core/lib/auth-helpers.ts +29 -0
- package/dist/kits/auth-core/lib/auth.ts +142 -0
- package/dist/kits/auth-core/lib/email/dev-transport.ts +42 -0
- package/dist/kits/auth-core/lib/email/index.ts +28 -0
- package/dist/kits/auth-core/lib/email/provider-smtp.ts +36 -0
- package/dist/kits/auth-core/lib/forms/map-errors.ts +11 -0
- package/dist/kits/auth-core/lib/hash.ts +6 -0
- package/dist/kits/auth-core/lib/prisma.ts +15 -0
- package/dist/kits/auth-core/lib/server/result.ts +45 -0
- package/dist/kits/auth-core/lib/utils.ts +6 -0
- package/dist/kits/auth-core/lib/validation/forms.ts +88 -0
- package/dist/kits/auth-core/package-deps.json +19 -0
- package/dist/kits/auth-core/prisma/auth-models.prisma +81 -0
- package/dist/kits/auth-core/prisma/schema.prisma +81 -0
- package/dist/kits/auth-core/scripts/populate-tokenhash.mjs +26 -0
- package/dist/kits/auth-core/scripts/promote-admin.mjs +33 -0
- package/dist/kits/auth-core/scripts/seed-demo.mjs +40 -0
- package/dist/kits/auth-core/types/next-auth.d.ts +25 -0
- package/dist/kits/blocks/README.md +53 -0
- package/dist/kits/blocks/app/globals.css +175 -0
- package/dist/kits/blocks/app/templates/digitalagency/PresetThemeVars.tsx +80 -0
- package/dist/kits/blocks/app/templates/digitalagency/README.md +36 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/About.tsx +99 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/CTA.tsx +74 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Contact.tsx +227 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Footer.tsx +89 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Hero.tsx +90 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Navbar.tsx +168 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/NetworkPattern.tsx +297 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Portfolio.tsx +157 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Pricing.tsx +114 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Process.tsx +59 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Services.tsx +55 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Team.tsx +28 -0
- package/dist/kits/blocks/app/templates/digitalagency/components/Testimonials.tsx +65 -0
- package/dist/kits/blocks/app/templates/digitalagency/page.tsx +38 -0
- package/dist/kits/blocks/app/templates/gallery/PresetThemeVars.tsx +85 -0
- package/dist/kits/blocks/app/templates/gallery/page.tsx +303 -0
- package/dist/kits/blocks/app/templates/productlaunch/PresetThemeVars.tsx +74 -0
- package/dist/kits/blocks/app/templates/productlaunch/README.md +55 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/About.tsx +178 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/CTA.tsx +93 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/Contact.tsx +231 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/FAQ.tsx +93 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/Features.tsx +84 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/Footer.tsx +132 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/Hero.tsx +89 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/Navbar.tsx +162 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/Pricing.tsx +106 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/ProcessTimeline.tsx +110 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/ServicesGrid.tsx +68 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/Team.tsx +104 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/Testimonials.tsx +89 -0
- package/dist/kits/blocks/app/templates/productlaunch/components/TrustBadges.tsx +76 -0
- package/dist/kits/blocks/app/templates/productlaunch/page.tsx +45 -0
- package/dist/kits/blocks/app/templates/saasdashboard/PresetThemeVars.tsx +80 -0
- package/dist/kits/blocks/app/templates/saasdashboard/README.md +38 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/Contact.tsx +176 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/Dashboard.tsx +293 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/FAQ.tsx +55 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/Features.tsx +91 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/Footer.tsx +77 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/Hero.tsx +105 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/Hero_mask.tsx +127 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/Navbar.tsx +159 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/Pricing.tsx +90 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/SmoothScroll.tsx +97 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/Testimonials.tsx +72 -0
- package/dist/kits/blocks/app/templates/saasdashboard/components/TrustBadges.tsx +53 -0
- package/dist/kits/blocks/app/templates/saasdashboard/page.tsx +39 -0
- package/dist/kits/blocks/components/app-providers.tsx +1 -0
- package/dist/kits/blocks/components/enhanced-theme-provider.tsx +195 -0
- package/dist/kits/blocks/components/sections/About.tsx +291 -0
- package/dist/kits/blocks/components/sections/CTA.tsx +258 -0
- package/dist/kits/blocks/components/sections/Contact.tsx +267 -0
- package/dist/kits/blocks/components/sections/FAQ.tsx +226 -0
- package/dist/kits/blocks/components/sections/Features.tsx +269 -0
- package/dist/kits/blocks/components/sections/Footer.tsx +302 -0
- package/dist/kits/blocks/components/sections/HeroMotion.tsx +307 -0
- package/dist/kits/blocks/components/sections/HeroOverlay.tsx +358 -0
- package/dist/kits/blocks/components/sections/HeroSplit.tsx +352 -0
- package/dist/kits/blocks/components/sections/Navbar.tsx +353 -0
- package/dist/kits/blocks/components/sections/Newsletter.tsx +156 -0
- package/dist/kits/blocks/components/sections/PortfolioSimple.tsx +550 -0
- package/dist/kits/blocks/components/sections/Pricing.tsx +264 -0
- package/dist/kits/blocks/components/sections/ProcessTimeline.tsx +325 -0
- package/dist/kits/blocks/components/sections/ServicesGrid.tsx +210 -0
- package/dist/kits/blocks/components/sections/Team.tsx +309 -0
- package/dist/kits/blocks/components/sections/Testimonials.tsx +158 -0
- package/dist/kits/blocks/components/sections/TrustBadges.tsx +162 -0
- package/dist/kits/blocks/components/theme-provider.tsx +34 -0
- package/dist/kits/blocks/components/ui/alert-dialog.tsx +134 -0
- package/dist/kits/blocks/components/ui/brand-node.tsx +121 -0
- package/dist/kits/blocks/components/ui/button.tsx +122 -0
- package/dist/kits/blocks/components/ui/button_bck.tsx +93 -0
- package/dist/kits/blocks/components/ui/card.tsx +95 -0
- package/dist/kits/blocks/components/ui/checkbox.tsx +30 -0
- package/dist/kits/blocks/components/ui/cta-button.tsx +125 -0
- package/dist/kits/blocks/components/ui/dropdown-menu.tsx +201 -0
- package/dist/kits/blocks/components/ui/feature-card.tsx +91 -0
- package/dist/kits/blocks/components/ui/input.tsx +27 -0
- package/dist/kits/blocks/components/ui/label.tsx +29 -0
- package/dist/kits/blocks/components/ui/pricing-card.tsx +120 -0
- package/dist/kits/blocks/components/ui/select.tsx +25 -0
- package/dist/kits/blocks/components/ui/skeleton.tsx +13 -0
- package/dist/kits/blocks/components/ui/switch.tsx +78 -0
- package/dist/kits/blocks/components/ui/table.tsx +98 -0
- package/dist/kits/blocks/components/ui/testimonial-card.tsx +108 -0
- package/dist/kits/blocks/components/ui/textarea.tsx +26 -0
- package/dist/kits/blocks/components/ui/theme-selector.tsx +247 -0
- package/dist/kits/blocks/components/ui/theme-toggle.tsx +74 -0
- package/dist/kits/blocks/components/ui/toaster.tsx +7 -0
- package/dist/kits/blocks/lib/themes.ts +399 -0
- package/dist/kits/blocks/lib/themes_old.ts +37 -0
- package/dist/kits/blocks/lib/utils.ts +9 -0
- package/dist/kits/blocks/next.config.ts +11 -0
- package/dist/kits/blocks/notes/THEME_GUIDE.md +29 -0
- package/dist/kits/blocks/notes/THEMING_CONVERSION_SUMMARY.md +14 -0
- package/dist/kits/blocks/package-deps.json +22 -0
- package/dist/kits/blocks/public/placeholders/gallery/hero-pexels-broken-9945014.avif +0 -0
- package/dist/kits/blocks/public/placeholders/gallery/pexels-googledeepmind-25626431.jpg +0 -0
- package/dist/kits/blocks/public/placeholders/gallery/pexels-googledeepmind-25626432.jpg +0 -0
- package/dist/kits/blocks/public/placeholders/gallery/pexels-googledeepmind-25626434.jpg +0 -0
- package/dist/kits/blocks/public/placeholders/gallery/pexels-googledeepmind-25626436.jpg +0 -0
- package/dist/kits/blocks/public/placeholders/product_launch/feature_1.png +0 -0
- package/dist/kits/blocks/public/placeholders/product_launch/feature_2.png +0 -0
- package/dist/kits/blocks/public/placeholders/product_launch/feature_3.png +0 -0
- package/dist/kits/blocks/public/placeholders/product_launch/feature_4.png +0 -0
- package/dist/kits/blocks/public/placeholders/product_launch/hero.png +0 -0
- package/dist/kits/blocks/public/placeholders/saas_dashboard/analytics.png +0 -0
- package/dist/kits/blocks/public/placeholders/saas_dashboard/chat.png +0 -0
- package/dist/kits/blocks/public/placeholders/saas_dashboard/projectBoard.png +0 -0
- package/dist/kits/data/.gitkeep +0 -0
- package/dist/kits/data/README.md +104 -0
- package/dist/kits/data/app/(protected)/admin/posts/page.tsx +5 -0
- package/dist/kits/data/app/(protected)/admin/users/page.tsx +5 -0
- package/dist/kits/data/app/api/posts/[id]/route.ts +83 -0
- package/dist/kits/data/app/api/posts/route.ts +138 -0
- package/dist/kits/data/app/api/seed-demo/route.ts +45 -0
- package/dist/kits/data/app/api/users/[id]/route.ts +127 -0
- package/dist/kits/data/app/api/users/check-email/route.ts +18 -0
- package/dist/kits/data/app/api/users/check-unique/route.ts +27 -0
- package/dist/kits/data/app/api/users/route.ts +79 -0
- package/dist/kits/data/app/examples/demo/README.md +4 -0
- package/dist/kits/data/app/examples/demo/create-post-form.tsx +106 -0
- package/dist/kits/data/app/examples/demo/page.tsx +118 -0
- package/dist/kits/data/app/examples/demo/seed-demo-button.tsx +37 -0
- package/dist/kits/data/components/admin/posts-manager.tsx +719 -0
- package/dist/kits/data/components/admin/users-manager.tsx +432 -0
- package/dist/kits/data/lib/prisma.ts +15 -0
- package/dist/kits/data/lib/server/result.ts +90 -0
- package/dist/kits/data/package-deps.json +11 -0
- package/dist/kits/data/scripts/seed-demo.mjs +41 -0
- package/dist/kits/forms/.gitkeep +0 -0
- package/dist/kits/forms/README.md +49 -0
- package/dist/kits/forms/app/.gitkeep +0 -0
- package/dist/kits/forms/app/api/wizard/route.ts +71 -0
- package/dist/kits/forms/app/examples/forms/basic/page.tsx +124 -0
- package/dist/kits/forms/app/examples/forms/server-action/form-client.tsx +28 -0
- package/dist/kits/forms/app/examples/forms/server-action/page.tsx +71 -0
- package/dist/kits/forms/app/examples/forms/wizard/page.tsx +15 -0
- package/dist/kits/forms/app/examples/forms/wizard/wizard-client.tsx +2 -0
- package/dist/kits/forms/components/.gitkeep +0 -0
- package/dist/kits/forms/components/examples/wizard-client.tsx +231 -0
- package/dist/kits/forms/components/hooks/useCheckUnique.ts +79 -0
- package/dist/kits/forms/components/ui/button.tsx +122 -0
- package/dist/kits/forms/components/ui/checkbox.tsx +30 -0
- package/dist/kits/forms/components/ui/form/context.ts +33 -0
- package/dist/kits/forms/components/ui/form/form-control.tsx +28 -0
- package/dist/kits/forms/components/ui/form/form-description.tsx +22 -0
- package/dist/kits/forms/components/ui/form/form-field.tsx +36 -0
- package/dist/kits/forms/components/ui/form/form-item.tsx +21 -0
- package/dist/kits/forms/components/ui/form/form-label.tsx +24 -0
- package/dist/kits/forms/components/ui/form/form-message.tsx +29 -0
- package/dist/kits/forms/components/ui/form/form.tsx +26 -0
- package/dist/kits/forms/components/ui/input.tsx +27 -0
- package/dist/kits/forms/components/ui/label.tsx +29 -0
- package/dist/kits/forms/components/ui/select.tsx +25 -0
- package/dist/kits/forms/components/ui/switch.tsx +78 -0
- package/dist/kits/forms/components/ui/textarea.tsx +26 -0
- package/dist/kits/forms/lib/.gitkeep +0 -0
- package/dist/kits/forms/lib/forms/map-errors.ts +29 -0
- package/dist/kits/forms/lib/prisma.ts +16 -0
- package/dist/kits/forms/lib/utils.ts +9 -0
- package/dist/kits/forms/lib/validation/forms.ts +88 -0
- package/dist/kits/forms/lib/validation/wizard.ts +32 -0
- package/dist/kits/forms/package-deps.json +17 -0
- package/dist/utils/file-operations.d.ts +18 -0
- package/dist/utils/file-operations.d.ts.map +1 -0
- package/dist/utils/file-operations.js +327 -0
- package/dist/utils/file-operations.js.map +1 -0
- package/dist/utils/installation-tracker.d.ts +26 -0
- package/dist/utils/installation-tracker.d.ts.map +1 -0
- package/dist/utils/installation-tracker.js +98 -0
- package/dist/utils/installation-tracker.js.map +1 -0
- package/package.json +51 -21
- package/index.js +0 -1
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A single trust badge (stat or certification).
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export interface TrustBadgeData {
|
|
11
|
+
/** Main badge text (e.g., "99.9% Uptime") */
|
|
12
|
+
badgeText: string;
|
|
13
|
+
/** Optional short descriptor above/below the text */
|
|
14
|
+
badgeDescription?: string;
|
|
15
|
+
/** Optional icon/emoji representation */
|
|
16
|
+
badgeIcon?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Props for the TrustBadges section component.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* - Layout: choose horizontal row or vertical stack via layout.
|
|
24
|
+
* - Styling: slot-style overrides are merged after defaults via cn().
|
|
25
|
+
* - Motion: enableMotion toggles hover scale.
|
|
26
|
+
*/
|
|
27
|
+
export interface TrustBadgesProps {
|
|
28
|
+
/** Optional id on root. @defaultValue "trust-badges" */
|
|
29
|
+
id?: string;
|
|
30
|
+
/** Root className merged into section slot */
|
|
31
|
+
className?: string;
|
|
32
|
+
|
|
33
|
+
/** Badges to display. @defaultValue defaultTrustBadgeData */
|
|
34
|
+
badges?: TrustBadgeData[];
|
|
35
|
+
/** Optional heading above badges */
|
|
36
|
+
trustBadgesSectionHeader?: string;
|
|
37
|
+
|
|
38
|
+
/** Slot-style overrides */
|
|
39
|
+
section?: { className?: string };
|
|
40
|
+
container?: { className?: string };
|
|
41
|
+
header?: { className?: string };
|
|
42
|
+
heading?: { className?: string };
|
|
43
|
+
badgesContainer?: { className?: string };
|
|
44
|
+
badge?: { className?: string };
|
|
45
|
+
badgeContent?: { className?: string };
|
|
46
|
+
icon?: { className?: string };
|
|
47
|
+
description?: { className?: string };
|
|
48
|
+
text?: { className?: string };
|
|
49
|
+
|
|
50
|
+
/** Layout orientation. @defaultValue "horizontal" */
|
|
51
|
+
layout?: "horizontal" | "vertical";
|
|
52
|
+
/** When false, disables hover scale */
|
|
53
|
+
enableMotion?: boolean;
|
|
54
|
+
/** ARIA label for the section. @defaultValue "Trust badges section" */
|
|
55
|
+
ariaLabel?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const defaultTrustBadgeData: TrustBadgeData[] = [
|
|
59
|
+
{
|
|
60
|
+
badgeText: "10,000+ businesses",
|
|
61
|
+
badgeDescription: "Trusted by",
|
|
62
|
+
badgeIcon: "📊",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
badgeText: "SOC 2 Compliant",
|
|
66
|
+
badgeDescription: "Enterprise security",
|
|
67
|
+
badgeIcon: "🔒",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
badgeText: "99.9% Uptime",
|
|
71
|
+
badgeDescription: "Reliable service",
|
|
72
|
+
badgeIcon: "⚡",
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Compact section to showcase trust signals like usage stats and compliance.
|
|
78
|
+
*
|
|
79
|
+
* @remarks
|
|
80
|
+
* - Horizontal by default; switch to vertical with layout="vertical".
|
|
81
|
+
* - Hover motion can be disabled via enableMotion.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* <TrustBadges badges={[{ badgeText: 'SOC 2', badgeDescription: 'Security', badgeIcon: '🔒' }]} />
|
|
85
|
+
*/
|
|
86
|
+
export function TrustBadges({
|
|
87
|
+
id,
|
|
88
|
+
className,
|
|
89
|
+
badges = defaultTrustBadgeData,
|
|
90
|
+
trustBadgesSectionHeader,
|
|
91
|
+
section = { className: "py-8 px-6 bg-muted" },
|
|
92
|
+
container = { className: "max-w-7xl mx-auto" },
|
|
93
|
+
header = { className: "text-center mb-6" },
|
|
94
|
+
heading = {
|
|
95
|
+
className: "text-xl font-semibold text-foreground text-[var(--heading-fg)]",
|
|
96
|
+
},
|
|
97
|
+
badgesContainer = {
|
|
98
|
+
className:
|
|
99
|
+
"flex flex-col md:flex-row justify-center items-center gap-8 flex-wrap",
|
|
100
|
+
},
|
|
101
|
+
badge = {
|
|
102
|
+
className:
|
|
103
|
+
"flex flex-col items-center text-center min-w-[200px] transition-all duration-300 ease-in-out hover:scale-[1.02]",
|
|
104
|
+
},
|
|
105
|
+
badgeContent = { className: "flex flex-col items-center space-y-2" },
|
|
106
|
+
icon = { className: "text-2xl mb-2" },
|
|
107
|
+
description = {
|
|
108
|
+
className:
|
|
109
|
+
"text-sm font-medium text-muted-foreground text-[var(--card-muted-fg)]",
|
|
110
|
+
},
|
|
111
|
+
text = {
|
|
112
|
+
className: "text-lg font-bold text-foreground text-[var(--card-fg)]",
|
|
113
|
+
},
|
|
114
|
+
layout = "horizontal",
|
|
115
|
+
enableMotion = true,
|
|
116
|
+
ariaLabel = "Trust badges section",
|
|
117
|
+
}: TrustBadgesProps) {
|
|
118
|
+
const containerClasses =
|
|
119
|
+
layout === "vertical"
|
|
120
|
+
? "flex flex-col justify-center items-center gap-8"
|
|
121
|
+
: badgesContainer.className;
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<section
|
|
125
|
+
id={id || "trust-badges"}
|
|
126
|
+
className={cn(section.className, className)}
|
|
127
|
+
aria-label={ariaLabel}
|
|
128
|
+
>
|
|
129
|
+
<div className={container.className}>
|
|
130
|
+
{trustBadgesSectionHeader && (
|
|
131
|
+
<div className={header.className}>
|
|
132
|
+
<h2 className={heading.className}>{trustBadgesSectionHeader}</h2>
|
|
133
|
+
</div>
|
|
134
|
+
)}
|
|
135
|
+
|
|
136
|
+
<div className={containerClasses}>
|
|
137
|
+
{badges.map((badgeData, index) => (
|
|
138
|
+
<div
|
|
139
|
+
key={index}
|
|
140
|
+
className={cn(
|
|
141
|
+
badge.className,
|
|
142
|
+
!enableMotion && "transition-none hover:!scale-100",
|
|
143
|
+
)}
|
|
144
|
+
>
|
|
145
|
+
<div className={badgeContent.className}>
|
|
146
|
+
{badgeData.badgeIcon && (
|
|
147
|
+
<div className={icon.className}>{badgeData.badgeIcon}</div>
|
|
148
|
+
)}
|
|
149
|
+
{badgeData.badgeDescription && (
|
|
150
|
+
<p className={description.className}>
|
|
151
|
+
{badgeData.badgeDescription}
|
|
152
|
+
</p>
|
|
153
|
+
)}
|
|
154
|
+
<p className={text.className}>{badgeData.badgeText}</p>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
))}
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</section>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export { ThemeProvider } from "@nextworks/blocks-core";
|
|
2
|
+
|
|
3
|
+
// "use client";
|
|
4
|
+
|
|
5
|
+
// import * as React from "react";
|
|
6
|
+
// import { ThemeProvider as NextThemesProvider } from "next-themes";
|
|
7
|
+
// import type { ThemeProviderProps as NextThemesProviderProps } from "next-themes";
|
|
8
|
+
|
|
9
|
+
// interface ThemeProviderProps {
|
|
10
|
+
// children: React.ReactNode;
|
|
11
|
+
// attribute?: NextThemesProviderProps["attribute"];
|
|
12
|
+
// defaultTheme?: NextThemesProviderProps["defaultTheme"];
|
|
13
|
+
// enableSystem?: NextThemesProviderProps["enableSystem"];
|
|
14
|
+
// disableTransitionOnChange?: NextThemesProviderProps["disableTransitionOnChange"];
|
|
15
|
+
// }
|
|
16
|
+
|
|
17
|
+
// export function ThemeProvider({
|
|
18
|
+
// children,
|
|
19
|
+
// attribute = "class",
|
|
20
|
+
// defaultTheme = "system",
|
|
21
|
+
// enableSystem = true,
|
|
22
|
+
// disableTransitionOnChange = false,
|
|
23
|
+
// }: ThemeProviderProps) {
|
|
24
|
+
// return (
|
|
25
|
+
// <NextThemesProvider
|
|
26
|
+
// attribute={attribute}
|
|
27
|
+
// defaultTheme={defaultTheme}
|
|
28
|
+
// enableSystem={enableSystem}
|
|
29
|
+
// disableTransitionOnChange={disableTransitionOnChange}
|
|
30
|
+
// >
|
|
31
|
+
// {children}
|
|
32
|
+
// </NextThemesProvider>
|
|
33
|
+
// );
|
|
34
|
+
// }
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const AlertDialog = AlertDialogPrimitive.Root;
|
|
8
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
|
|
9
|
+
const AlertDialogPortal = AlertDialogPrimitive.Portal;
|
|
10
|
+
const AlertDialogOverlay = React.forwardRef<
|
|
11
|
+
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
|
12
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
|
13
|
+
>(({ className, ...props }, ref) => (
|
|
14
|
+
<AlertDialogPrimitive.Overlay
|
|
15
|
+
ref={ref}
|
|
16
|
+
className={cn("fixed inset-0 z-50 bg-black/50 backdrop-blur-sm", className)}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
));
|
|
20
|
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
|
|
21
|
+
|
|
22
|
+
const AlertDialogContent = React.forwardRef<
|
|
23
|
+
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
|
24
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
|
25
|
+
>(({ className, ...props }, ref) => (
|
|
26
|
+
<AlertDialogPortal>
|
|
27
|
+
<AlertDialogOverlay />
|
|
28
|
+
<AlertDialogPrimitive.Content
|
|
29
|
+
ref={ref}
|
|
30
|
+
className={cn(
|
|
31
|
+
"bg-background fixed top-1/2 left-1/2 z-50 grid w-full max-w-md -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg border p-6 shadow-lg",
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
</AlertDialogPortal>
|
|
37
|
+
));
|
|
38
|
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
|
|
39
|
+
|
|
40
|
+
function AlertDialogHeader({
|
|
41
|
+
className,
|
|
42
|
+
...props
|
|
43
|
+
}: React.HTMLAttributes<HTMLDivElement>) {
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
className={cn("flex flex-col space-y-1 text-center", className)}
|
|
47
|
+
{...props}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function AlertDialogFooter({
|
|
53
|
+
className,
|
|
54
|
+
...props
|
|
55
|
+
}: React.HTMLAttributes<HTMLDivElement>) {
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
58
|
+
className={cn(
|
|
59
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
60
|
+
className,
|
|
61
|
+
)}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const AlertDialogTitle = React.forwardRef<
|
|
68
|
+
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
|
69
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
|
70
|
+
>(({ className, ...props }, ref) => (
|
|
71
|
+
<AlertDialogPrimitive.Title
|
|
72
|
+
ref={ref}
|
|
73
|
+
className={cn("text-lg font-semibold", className)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
));
|
|
77
|
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
|
|
78
|
+
|
|
79
|
+
const AlertDialogDescription = React.forwardRef<
|
|
80
|
+
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
|
81
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
|
82
|
+
>(({ className, ...props }, ref) => (
|
|
83
|
+
<AlertDialogPrimitive.Description
|
|
84
|
+
ref={ref}
|
|
85
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
86
|
+
{...props}
|
|
87
|
+
/>
|
|
88
|
+
));
|
|
89
|
+
AlertDialogDescription.displayName =
|
|
90
|
+
AlertDialogPrimitive.Description.displayName;
|
|
91
|
+
|
|
92
|
+
const AlertDialogAction = React.forwardRef<
|
|
93
|
+
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
|
94
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
|
95
|
+
>(({ className, ...props }, ref) => (
|
|
96
|
+
<AlertDialogPrimitive.Action
|
|
97
|
+
ref={ref}
|
|
98
|
+
className={cn(
|
|
99
|
+
"bg-destructive text-destructive-foreground inline-flex h-9 items-center justify-center rounded-md px-4 text-sm font-medium shadow transition-colors hover:opacity-90 focus:outline-none",
|
|
100
|
+
className,
|
|
101
|
+
)}
|
|
102
|
+
{...props}
|
|
103
|
+
/>
|
|
104
|
+
));
|
|
105
|
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
|
|
106
|
+
|
|
107
|
+
const AlertDialogCancel = React.forwardRef<
|
|
108
|
+
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
|
109
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
|
110
|
+
>(({ className, ...props }, ref) => (
|
|
111
|
+
<AlertDialogPrimitive.Cancel
|
|
112
|
+
ref={ref}
|
|
113
|
+
className={cn(
|
|
114
|
+
"bg-background hover:bg-muted inline-flex h-9 items-center justify-center rounded-md border px-4 text-sm font-medium shadow focus:outline-none",
|
|
115
|
+
className,
|
|
116
|
+
)}
|
|
117
|
+
{...props}
|
|
118
|
+
/>
|
|
119
|
+
));
|
|
120
|
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
AlertDialog,
|
|
124
|
+
AlertDialogAction,
|
|
125
|
+
AlertDialogCancel,
|
|
126
|
+
AlertDialogContent,
|
|
127
|
+
AlertDialogDescription,
|
|
128
|
+
AlertDialogFooter,
|
|
129
|
+
AlertDialogHeader,
|
|
130
|
+
AlertDialogOverlay,
|
|
131
|
+
AlertDialogPortal,
|
|
132
|
+
AlertDialogTitle,
|
|
133
|
+
AlertDialogTrigger,
|
|
134
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import type { ComponentType } from "react";
|
|
5
|
+
import { Sparkles } from "lucide-react";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
export interface BrandNodeProps {
|
|
9
|
+
/** Optional wrapper className to override size/colors (merged with defaults) */
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface BrandNodeIconBadgeProps extends BrandNodeProps {
|
|
14
|
+
/** Icon component to render inside the badge */
|
|
15
|
+
icon?: ComponentType<{ className?: string }>;
|
|
16
|
+
/** Tailwind classes to control icon size; default `h-4 w-4` */
|
|
17
|
+
iconClassName?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function BrandNodeIconBadge({
|
|
21
|
+
className,
|
|
22
|
+
icon: Icon = Sparkles,
|
|
23
|
+
iconClassName = "h-4 w-4",
|
|
24
|
+
}: BrandNodeIconBadgeProps) {
|
|
25
|
+
const base = "grid h-8 w-8 place-items-center rounded-md bg-primary/10 ring-1 ring-primary/30 text-primary";
|
|
26
|
+
return (
|
|
27
|
+
<div className={cn(base, className)} aria-label="Brand icon badge">
|
|
28
|
+
<Icon className={iconClassName} />
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface BrandNodeGradientRingProps extends BrandNodeProps {
|
|
34
|
+
/** CSS conic-gradient string; provide two or more colors */
|
|
35
|
+
gradient?: string;
|
|
36
|
+
/** Inner fill background (center disc) */
|
|
37
|
+
innerBgClassName?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function BrandNodeGradientRing({
|
|
41
|
+
className,
|
|
42
|
+
gradient = "conic-gradient(hsl(var(--primary)), hsl(var(--accent)), hsl(var(--primary)))",
|
|
43
|
+
innerBgClassName = "h-full w-full rounded-full bg-background",
|
|
44
|
+
}: BrandNodeGradientRingProps) {
|
|
45
|
+
const base = "relative h-8 w-8";
|
|
46
|
+
return (
|
|
47
|
+
<div className={cn(base, className)} aria-label="Brand gradient ring">
|
|
48
|
+
<div className="absolute inset-0 rounded-full p-[2px]" style={{ background: gradient }}>
|
|
49
|
+
<div className={innerBgClassName} />
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function BrandNodeGeometricMark({ className }: BrandNodeProps) {
|
|
56
|
+
const base = "grid h-8 w-8 place-items-center rounded-md bg-gradient-to-br from-primary/10 to-accent/10 ring-1 ring-border";
|
|
57
|
+
return (
|
|
58
|
+
<div className={cn(base, className)} aria-label="Brand geometric mark">
|
|
59
|
+
<svg viewBox="0 0 24 24" className="fill-primary h-4 w-4">
|
|
60
|
+
<path d="M12 4l8 14H4l8-14z" />
|
|
61
|
+
</svg>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface BrandNodeEmojiBadgeProps extends BrandNodeProps {
|
|
67
|
+
emoji?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function BrandNodeEmojiBadge({ className, emoji = "⚡" }: BrandNodeEmojiBadgeProps) {
|
|
71
|
+
const base = "grid h-8 w-8 place-items-center rounded-md bg-card/60 backdrop-blur ring-1 ring-border";
|
|
72
|
+
return (
|
|
73
|
+
<div className={cn(base, className)} aria-label="Brand emoji badge">
|
|
74
|
+
<span className="text-base" aria-hidden>
|
|
75
|
+
{emoji}
|
|
76
|
+
</span>
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface BrandNodeDiagonalAppIconProps extends BrandNodeProps {
|
|
82
|
+
/** Base and overlay colors */
|
|
83
|
+
baseColorClass?: string;
|
|
84
|
+
overlayColorClass?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function BrandNodeDiagonalAppIcon({
|
|
88
|
+
className,
|
|
89
|
+
baseColorClass = "bg-primary",
|
|
90
|
+
overlayColorClass = "bg-accent",
|
|
91
|
+
}: BrandNodeDiagonalAppIconProps) {
|
|
92
|
+
const base = "relative h-8 w-8 overflow-hidden rounded-md ring-1 ring-black/5 dark:ring-white/10";
|
|
93
|
+
return (
|
|
94
|
+
<div className={cn(base, className)} aria-label="Brand diagonal app icon">
|
|
95
|
+
<div className={cn("absolute inset-0", baseColorClass)} />
|
|
96
|
+
<div className={cn("absolute inset-0 translate-y-1/3 -skew-y-12", overlayColorClass)} />
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function BrandNodeCubeOutline({ className }: BrandNodeProps) {
|
|
102
|
+
const base = "grid h-8 w-8 place-items-center rounded-md bg-foreground text-background ring-1 ring-border";
|
|
103
|
+
return (
|
|
104
|
+
<div className={cn(base, className)} aria-label="Brand cube outline">
|
|
105
|
+
<svg viewBox="0 0 24 24" className="h-4 w-4">
|
|
106
|
+
<path d="M12 2l8 4.5v9L12 20 4 15.5v-9L12 2z" fill="none" stroke="currentColor" strokeWidth="1.6" />
|
|
107
|
+
<path d="M12 20v-9M4 6l8 5 8-5" fill="none" stroke="currentColor" strokeWidth="1.6" />
|
|
108
|
+
</svg>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Registry for quick swapping by name */
|
|
114
|
+
export const BrandNodes = {
|
|
115
|
+
IconBadge: BrandNodeIconBadge,
|
|
116
|
+
GradientRing: BrandNodeGradientRing,
|
|
117
|
+
GeometricMark: BrandNodeGeometricMark,
|
|
118
|
+
EmojiBadge: BrandNodeEmojiBadge,
|
|
119
|
+
DiagonalAppIcon: BrandNodeDiagonalAppIcon,
|
|
120
|
+
CubeOutline: BrandNodeCubeOutline,
|
|
121
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
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
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"bg-primary text-primary-foreground hover:bg-primary/90 shadow-xs",
|
|
14
|
+
destructive:
|
|
15
|
+
"bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 shadow-xs",
|
|
16
|
+
outline:
|
|
17
|
+
"bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border shadow-xs",
|
|
18
|
+
secondary:
|
|
19
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-xs",
|
|
20
|
+
ghost:
|
|
21
|
+
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
22
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
26
|
+
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
27
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
28
|
+
icon: "size-9",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
variant: "default",
|
|
33
|
+
size: "default",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
type ButtonProps = React.ComponentProps<"button"> &
|
|
39
|
+
VariantProps<typeof buttonVariants> & {
|
|
40
|
+
asChild?: boolean;
|
|
41
|
+
/** When true, bypasses tokenized buttonVariants so callers fully control classes */
|
|
42
|
+
unstyled?: boolean;
|
|
43
|
+
/** Opt-in: force inline CSS var styles for color/bg/border/ring */
|
|
44
|
+
forceInlineVars?: boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
48
|
+
(
|
|
49
|
+
{
|
|
50
|
+
className,
|
|
51
|
+
variant,
|
|
52
|
+
size,
|
|
53
|
+
asChild = false,
|
|
54
|
+
unstyled = false,
|
|
55
|
+
forceInlineVars = false,
|
|
56
|
+
...props
|
|
57
|
+
},
|
|
58
|
+
ref,
|
|
59
|
+
) => {
|
|
60
|
+
const Comp = asChild ? Slot : "button";
|
|
61
|
+
|
|
62
|
+
// Use caller-provided style; only inject inline var-driven colors when explicitly requested
|
|
63
|
+
const incomingStyle =
|
|
64
|
+
(props.style as React.CSSProperties | undefined) ?? undefined;
|
|
65
|
+
const finalStyle =
|
|
66
|
+
forceInlineVars && !unstyled
|
|
67
|
+
? {
|
|
68
|
+
...incomingStyle,
|
|
69
|
+
color: "var(--btn-fg)",
|
|
70
|
+
backgroundColor: "var(--btn-bg)",
|
|
71
|
+
borderColor: "var(--btn-border)",
|
|
72
|
+
"--tw-ring-color": "var(--btn-ring)",
|
|
73
|
+
}
|
|
74
|
+
: incomingStyle;
|
|
75
|
+
|
|
76
|
+
// Only enable CSS variable hooks when explicitly requested via inline vars
|
|
77
|
+
// or when the caller sets any [--btn-*] classes in className.
|
|
78
|
+
const wantsVarHooks =
|
|
79
|
+
!unstyled &&
|
|
80
|
+
(forceInlineVars ||
|
|
81
|
+
(typeof className === "string" && className.includes("[--btn-")));
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<Comp
|
|
85
|
+
ref={ref}
|
|
86
|
+
data-slot="button"
|
|
87
|
+
className={
|
|
88
|
+
unstyled
|
|
89
|
+
? cn(
|
|
90
|
+
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap disabled:pointer-events-none disabled:opacity-50",
|
|
91
|
+
className,
|
|
92
|
+
)
|
|
93
|
+
: cn(
|
|
94
|
+
buttonVariants({ variant, size }),
|
|
95
|
+
wantsVarHooks && [
|
|
96
|
+
// Color var hooks (apply only when CSS vars are provided)
|
|
97
|
+
"text-[var(--btn-fg)]",
|
|
98
|
+
"bg-[var(--btn-bg)]",
|
|
99
|
+
"hover:bg-[var(--btn-hover-bg)]",
|
|
100
|
+
"hover:text-[var(--btn-hover-fg)]",
|
|
101
|
+
// explicit dark variants to compete with dark: utilities from variants like outline
|
|
102
|
+
"dark:bg-[var(--btn-bg)]",
|
|
103
|
+
"dark:hover:bg-[var(--btn-hover-bg)]",
|
|
104
|
+
"dark:hover:text-[var(--btn-hover-fg)]",
|
|
105
|
+
// Focus ring and border hooks
|
|
106
|
+
"focus-visible:ring-[var(--btn-ring)]",
|
|
107
|
+
"border-[var(--btn-border)]",
|
|
108
|
+
"dark:border-[var(--btn-border)]",
|
|
109
|
+
],
|
|
110
|
+
className,
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
style={finalStyle}
|
|
114
|
+
{...props}
|
|
115
|
+
/>
|
|
116
|
+
);
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
Button.displayName = "Button";
|
|
121
|
+
|
|
122
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"bg-primary text-primary-foreground hover:bg-primary/90 shadow-xs",
|
|
14
|
+
destructive:
|
|
15
|
+
"bg-destructive hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 text-white shadow-xs",
|
|
16
|
+
outline:
|
|
17
|
+
"bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border shadow-xs",
|
|
18
|
+
secondary:
|
|
19
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-xs",
|
|
20
|
+
ghost:
|
|
21
|
+
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
22
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
26
|
+
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
27
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
28
|
+
icon: "size-9",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
variant: "default",
|
|
33
|
+
size: "default",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
function Button({
|
|
39
|
+
className,
|
|
40
|
+
variant,
|
|
41
|
+
size,
|
|
42
|
+
asChild = false,
|
|
43
|
+
unstyled = false,
|
|
44
|
+
...props
|
|
45
|
+
}: React.ComponentProps<"button"> &
|
|
46
|
+
VariantProps<typeof buttonVariants> & {
|
|
47
|
+
asChild?: boolean;
|
|
48
|
+
/** When true, bypasses tokenized buttonVariants so callers fully control classes */
|
|
49
|
+
unstyled?: boolean;
|
|
50
|
+
}) {
|
|
51
|
+
const Comp = asChild ? Slot : "button";
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Comp
|
|
55
|
+
data-slot="button"
|
|
56
|
+
className={
|
|
57
|
+
unstyled
|
|
58
|
+
? cn(
|
|
59
|
+
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap disabled:pointer-events-none disabled:opacity-50",
|
|
60
|
+
className,
|
|
61
|
+
)
|
|
62
|
+
: cn(
|
|
63
|
+
buttonVariants({ variant, size }),
|
|
64
|
+
// Color var hooks (ignored when vars are unset; tokens from variants apply)
|
|
65
|
+
"text-[var(--btn-fg)]",
|
|
66
|
+
"bg-[var(--btn-bg)]",
|
|
67
|
+
"hover:bg-[var(--btn-hover-bg)]",
|
|
68
|
+
"hover:text-[var(--btn-hover-fg)]",
|
|
69
|
+
// explicit dark variants to compete with dark: utilities from variants like outline
|
|
70
|
+
"dark:bg-[var(--btn-bg)]",
|
|
71
|
+
"dark:hover:bg-[var(--btn-hover-bg)]",
|
|
72
|
+
"dark:hover:text-[var(--btn-hover-fg)]",
|
|
73
|
+
// Focus ring and border hooks
|
|
74
|
+
"focus-visible:ring-[var(--btn-ring)]",
|
|
75
|
+
"border-[var(--btn-border)]",
|
|
76
|
+
"dark:border-[var(--btn-border)]",
|
|
77
|
+
className,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
style={{
|
|
81
|
+
...(props.style as React.CSSProperties),
|
|
82
|
+
color: "var(--btn-fg)",
|
|
83
|
+
backgroundColor: "var(--btn-bg)",
|
|
84
|
+
borderColor: "var(--btn-border)",
|
|
85
|
+
// @ts-expect-error custom CSS var for Tailwind ring color
|
|
86
|
+
"--tw-ring-color": "var(--btn-ring)",
|
|
87
|
+
}}
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export { Button, buttonVariants };
|