@promakeai/cli 0.0.5
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/dist/index.js +212 -0
- package/dist/registry/about-page.json +45 -0
- package/dist/registry/about-section.json +40 -0
- package/dist/registry/animations.json +69 -0
- package/dist/registry/bento-grid-section.json +42 -0
- package/dist/registry/blog-core.json +74 -0
- package/dist/registry/blog-list-page.json +48 -0
- package/dist/registry/blog-section.json +43 -0
- package/dist/registry/cards-carousel-section.json +46 -0
- package/dist/registry/cart-drawer.json +43 -0
- package/dist/registry/cart-page.json +47 -0
- package/dist/registry/category-section.json +43 -0
- package/dist/registry/checkout-page.json +47 -0
- package/dist/registry/contact-info-grid.json +40 -0
- package/dist/registry/contact-page-centered.json +50 -0
- package/dist/registry/contact-page-map-overlay.json +54 -0
- package/dist/registry/contact-page-map-split.json +54 -0
- package/dist/registry/contact-page-split.json +49 -0
- package/dist/registry/contact-page.json +45 -0
- package/dist/registry/content-section.json +40 -0
- package/dist/registry/cookies-page.json +45 -0
- package/dist/registry/cta-section.json +40 -0
- package/dist/registry/docs/about-page.md +32 -0
- package/dist/registry/docs/about-section.md +33 -0
- package/dist/registry/docs/animations.md +44 -0
- package/dist/registry/docs/bento-grid-section.md +40 -0
- package/dist/registry/docs/blog-core.md +37 -0
- package/dist/registry/docs/blog-list-page.md +38 -0
- package/dist/registry/docs/blog-section.md +39 -0
- package/dist/registry/docs/cards-carousel-section.md +39 -0
- package/dist/registry/docs/cart-drawer.md +42 -0
- package/dist/registry/docs/cart-page.md +37 -0
- package/dist/registry/docs/category-section.md +34 -0
- package/dist/registry/docs/checkout-page.md +38 -0
- package/dist/registry/docs/contact-info-grid.md +33 -0
- package/dist/registry/docs/contact-page-centered.md +41 -0
- package/dist/registry/docs/contact-page-map-overlay.md +44 -0
- package/dist/registry/docs/contact-page-map-split.md +44 -0
- package/dist/registry/docs/contact-page-split.md +40 -0
- package/dist/registry/docs/contact-page.md +33 -0
- package/dist/registry/docs/content-section.md +35 -0
- package/dist/registry/docs/cookies-page.md +32 -0
- package/dist/registry/docs/cta-section.md +32 -0
- package/dist/registry/docs/ecommerce-core.md +41 -0
- package/dist/registry/docs/empty-page.md +31 -0
- package/dist/registry/docs/faq-categorized.md +38 -0
- package/dist/registry/docs/faq-simple.md +38 -0
- package/dist/registry/docs/favorites-blog-block.md +38 -0
- package/dist/registry/docs/favorites-ecommerce-block.md +38 -0
- package/dist/registry/docs/feature-section.md +33 -0
- package/dist/registry/docs/featured-products.md +38 -0
- package/dist/registry/docs/footer-detailed.md +33 -0
- package/dist/registry/docs/footer-minimal.md +32 -0
- package/dist/registry/docs/footer.md +32 -0
- package/dist/registry/docs/google-map.md +36 -0
- package/dist/registry/docs/header-centered-pill.md +37 -0
- package/dist/registry/docs/header-ecommerce.md +38 -0
- package/dist/registry/docs/header-mega.md +40 -0
- package/dist/registry/docs/header-minimal.md +38 -0
- package/dist/registry/docs/header-simple.md +32 -0
- package/dist/registry/docs/hero-cta.md +38 -0
- package/dist/registry/docs/hero-gradient.md +33 -0
- package/dist/registry/docs/hero-grid.md +40 -0
- package/dist/registry/docs/hero-profile.md +33 -0
- package/dist/registry/docs/hero.md +32 -0
- package/dist/registry/docs/login-page-split.md +40 -0
- package/dist/registry/docs/login-page.md +39 -0
- package/dist/registry/docs/newsletter-section.md +40 -0
- package/dist/registry/docs/order-card-compact.md +37 -0
- package/dist/registry/docs/order-detail-block.md +37 -0
- package/dist/registry/docs/orders-list-block.md +40 -0
- package/dist/registry/docs/payment-success-block.md +32 -0
- package/dist/registry/docs/post-card.md +37 -0
- package/dist/registry/docs/post-detail-block.md +37 -0
- package/dist/registry/docs/pricing-card.md +37 -0
- package/dist/registry/docs/pricing-section.md +39 -0
- package/dist/registry/docs/privacy-page.md +32 -0
- package/dist/registry/docs/product-card-detailed.md +42 -0
- package/dist/registry/docs/product-card-hover.md +35 -0
- package/dist/registry/docs/product-card.md +37 -0
- package/dist/registry/docs/product-detail-block.md +37 -0
- package/dist/registry/docs/product-detail-section.md +45 -0
- package/dist/registry/docs/products-page.md +39 -0
- package/dist/registry/docs/related-posts-block.md +38 -0
- package/dist/registry/docs/related-products-block.md +38 -0
- package/dist/registry/docs/service-card.md +34 -0
- package/dist/registry/docs/skill-card.md +33 -0
- package/dist/registry/docs/terms-page.md +32 -0
- package/dist/registry/docs/testimonials-carousel.md +40 -0
- package/dist/registry/docs/testimonials-grid.md +39 -0
- package/dist/registry/ecommerce-core.json +95 -0
- package/dist/registry/empty-page.json +45 -0
- package/dist/registry/faq-categorized.json +42 -0
- package/dist/registry/faq-simple.json +42 -0
- package/dist/registry/favorites-blog-block.json +43 -0
- package/dist/registry/favorites-ecommerce-block.json +43 -0
- package/dist/registry/feature-section.json +40 -0
- package/dist/registry/featured-products.json +43 -0
- package/dist/registry/footer-detailed.json +43 -0
- package/dist/registry/footer-minimal.json +40 -0
- package/dist/registry/footer.json +40 -0
- package/dist/registry/google-map.json +31 -0
- package/dist/registry/header-centered-pill.json +45 -0
- package/dist/registry/header-ecommerce.json +42 -0
- package/dist/registry/header-mega.json +47 -0
- package/dist/registry/header-minimal.json +45 -0
- package/dist/registry/header-simple.json +43 -0
- package/dist/registry/hero-cta.json +42 -0
- package/dist/registry/hero-gradient.json +40 -0
- package/dist/registry/hero-grid.json +42 -0
- package/dist/registry/hero-profile.json +62 -0
- package/dist/registry/hero.json +40 -0
- package/dist/registry/index.json +70 -0
- package/dist/registry/login-page-split.json +47 -0
- package/dist/registry/login-page.json +49 -0
- package/dist/registry/newsletter-section.json +44 -0
- package/dist/registry/order-card-compact.json +42 -0
- package/dist/registry/order-detail-block.json +42 -0
- package/dist/registry/orders-list-block.json +45 -0
- package/dist/registry/payment-success-block.json +40 -0
- package/dist/registry/post-card.json +42 -0
- package/dist/registry/post-detail-block.json +42 -0
- package/dist/registry/pricing-card.json +40 -0
- package/dist/registry/pricing-section.json +43 -0
- package/dist/registry/privacy-page.json +45 -0
- package/dist/registry/product-card-detailed.json +45 -0
- package/dist/registry/product-card-hover.json +40 -0
- package/dist/registry/product-card.json +42 -0
- package/dist/registry/product-detail-block.json +42 -0
- package/dist/registry/product-detail-section.json +46 -0
- package/dist/registry/products-page.json +48 -0
- package/dist/registry/related-posts-block.json +43 -0
- package/dist/registry/related-products-block.json +43 -0
- package/dist/registry/service-card.json +28 -0
- package/dist/registry/skill-card.json +28 -0
- package/dist/registry/terms-page.json +45 -0
- package/dist/registry/testimonials-carousel.json +44 -0
- package/dist/registry/testimonials-grid.json +43 -0
- package/package.json +52 -0
- package/template/.env +6 -0
- package/template/.prettierignore +3 -0
- package/template/.prettierrc +1 -0
- package/template/README.md +73 -0
- package/template/bun.lock +1007 -0
- package/template/components.json +22 -0
- package/template/eslint.config.js +32 -0
- package/template/index.html +285 -0
- package/template/package.json +92 -0
- package/template/promake.json +6 -0
- package/template/public/_redirects +1 -0
- package/template/public/data/database.db +0 -0
- package/template/public/favicon.svg +1 -0
- package/template/public/images/placeholder.png +0 -0
- package/template/public/robots.txt +14 -0
- package/template/scripts/init-db.ts +131 -0
- package/template/src/App.tsx +33 -0
- package/template/src/components/Footer.tsx +100 -0
- package/template/src/components/Header.tsx +79 -0
- package/template/src/components/Hero.tsx +69 -0
- package/template/src/components/LanguageSwitcher.tsx +47 -0
- package/template/src/components/Layout.tsx +25 -0
- package/template/src/components/Logo.tsx +64 -0
- package/template/src/components/ThemeSwitcher.tsx +58 -0
- package/template/src/components/ui/accordion.tsx +64 -0
- package/template/src/components/ui/alert-dialog.tsx +155 -0
- package/template/src/components/ui/alert.tsx +66 -0
- package/template/src/components/ui/aspect-ratio.tsx +11 -0
- package/template/src/components/ui/avatar.tsx +51 -0
- package/template/src/components/ui/badge.tsx +46 -0
- package/template/src/components/ui/breadcrumb.tsx +109 -0
- package/template/src/components/ui/button-group.tsx +83 -0
- package/template/src/components/ui/button.tsx +62 -0
- package/template/src/components/ui/calendar.tsx +220 -0
- package/template/src/components/ui/card.tsx +92 -0
- package/template/src/components/ui/carousel.tsx +239 -0
- package/template/src/components/ui/chart.tsx +357 -0
- package/template/src/components/ui/checkbox.tsx +32 -0
- package/template/src/components/ui/collapsible.tsx +31 -0
- package/template/src/components/ui/command.tsx +182 -0
- package/template/src/components/ui/context-menu.tsx +252 -0
- package/template/src/components/ui/dialog.tsx +141 -0
- package/template/src/components/ui/drawer.tsx +135 -0
- package/template/src/components/ui/dropdown-menu.tsx +255 -0
- package/template/src/components/ui/empty.tsx +104 -0
- package/template/src/components/ui/field.tsx +246 -0
- package/template/src/components/ui/form.tsx +168 -0
- package/template/src/components/ui/hover-card.tsx +44 -0
- package/template/src/components/ui/input-group.tsx +170 -0
- package/template/src/components/ui/input-otp.tsx +75 -0
- package/template/src/components/ui/input.tsx +21 -0
- package/template/src/components/ui/item.tsx +193 -0
- package/template/src/components/ui/kbd.tsx +28 -0
- package/template/src/components/ui/label.tsx +24 -0
- package/template/src/components/ui/menubar.tsx +274 -0
- package/template/src/components/ui/navigation-menu.tsx +168 -0
- package/template/src/components/ui/pagination.tsx +127 -0
- package/template/src/components/ui/popover.tsx +48 -0
- package/template/src/components/ui/progress.tsx +29 -0
- package/template/src/components/ui/radio-group.tsx +45 -0
- package/template/src/components/ui/resizable.tsx +54 -0
- package/template/src/components/ui/scroll-area.tsx +58 -0
- package/template/src/components/ui/select.tsx +188 -0
- package/template/src/components/ui/separator.tsx +28 -0
- package/template/src/components/ui/sheet.tsx +137 -0
- package/template/src/components/ui/sidebar.tsx +726 -0
- package/template/src/components/ui/skeleton.tsx +13 -0
- package/template/src/components/ui/slider.tsx +63 -0
- package/template/src/components/ui/sonner.tsx +38 -0
- package/template/src/components/ui/spinner.tsx +16 -0
- package/template/src/components/ui/switch.tsx +31 -0
- package/template/src/components/ui/table.tsx +114 -0
- package/template/src/components/ui/tabs.tsx +66 -0
- package/template/src/components/ui/textarea.tsx +18 -0
- package/template/src/components/ui/toggle-group.tsx +81 -0
- package/template/src/components/ui/toggle.tsx +45 -0
- package/template/src/components/ui/tooltip.tsx +61 -0
- package/template/src/constants/constants.json +58 -0
- package/template/src/hooks/use-is-mobile.ts +21 -0
- package/template/src/hooks/use-page-title.ts +49 -0
- package/template/src/hooks/use-theme.ts +57 -0
- package/template/src/index.css +128 -0
- package/template/src/lang/en/about.json +4 -0
- package/template/src/lang/en/contact.json +39 -0
- package/template/src/lang/en/cookies.json +4 -0
- package/template/src/lang/en/footer.json +12 -0
- package/template/src/lang/en/forgotPassword.json +37 -0
- package/template/src/lang/en/header.json +10 -0
- package/template/src/lang/en/hero.json +8 -0
- package/template/src/lang/en/index.json +30 -0
- package/template/src/lang/en/login.json +18 -0
- package/template/src/lang/en/notfound.json +7 -0
- package/template/src/lang/en/privacy.json +4 -0
- package/template/src/lang/en/register.json +25 -0
- package/template/src/lang/en/terms.json +4 -0
- package/template/src/lang/index.ts +86 -0
- package/template/src/lang/tr/about.json +4 -0
- package/template/src/lang/tr/contact.json +39 -0
- package/template/src/lang/tr/cookies.json +4 -0
- package/template/src/lang/tr/footer.json +12 -0
- package/template/src/lang/tr/forgotPassword.json +37 -0
- package/template/src/lang/tr/header.json +10 -0
- package/template/src/lang/tr/hero.json +8 -0
- package/template/src/lang/tr/index.json +30 -0
- package/template/src/lang/tr/login.json +18 -0
- package/template/src/lang/tr/notfound.json +7 -0
- package/template/src/lang/tr/privacy.json +4 -0
- package/template/src/lang/tr/register.json +25 -0
- package/template/src/lang/tr/terms.json +4 -0
- package/template/src/lib/api.ts +237 -0
- package/template/src/lib/storage.ts +109 -0
- package/template/src/lib/utils.ts +15 -0
- package/template/src/main.tsx +13 -0
- package/template/src/modules/api/USAGE.md +515 -0
- package/template/src/modules/api/customer-client.ts +20 -0
- package/template/src/modules/api/get-error-message.ts +18 -0
- package/template/src/modules/api/validation/en.json +29 -0
- package/template/src/modules/api/validation/tr.json +29 -0
- package/template/src/modules/auth/USAGE.md +248 -0
- package/template/src/modules/auth/auth-header-menu.tsx +123 -0
- package/template/src/modules/auth/auth-store.ts +57 -0
- package/template/src/modules/auth/forgot-password-page.tsx +371 -0
- package/template/src/modules/auth/login-page.tsx +183 -0
- package/template/src/modules/auth/register-page.tsx +252 -0
- package/template/src/modules/auth/use-auth.ts +273 -0
- package/template/src/modules/db/adapters/IDataAdapter.ts +26 -0
- package/template/src/modules/db/adapters/SqliteAdapter.ts +364 -0
- package/template/src/modules/db/adapters/index.ts +2 -0
- package/template/src/modules/db/config.ts +59 -0
- package/template/src/modules/db/core/DataManager.ts +125 -0
- package/template/src/modules/db/core/types.ts +101 -0
- package/template/src/modules/db/index.ts +42 -0
- package/template/src/modules/db/react/QueryProvider.tsx +16 -0
- package/template/src/modules/db/react/index.ts +23 -0
- package/template/src/modules/db/react/queryClient.ts +64 -0
- package/template/src/modules/db/react/useRepository.ts +400 -0
- package/template/src/modules/db/utils/parsers.ts +96 -0
- package/template/src/pages/Index.tsx +108 -0
- package/template/src/pages/NotFound.tsx +35 -0
- package/template/src/router.tsx +14 -0
- package/template/src/types/index.ts +0 -0
- package/template/src/vite-env.d.ts +1 -0
- package/template/tsconfig.app.json +32 -0
- package/template/tsconfig.json +17 -0
- package/template/tsconfig.node.json +26 -0
- package/template/vite.config.ts +74 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { Link } from "react-router";
|
|
3
|
+
import { Facebook, Twitter, Instagram, Linkedin } from "lucide-react";
|
|
4
|
+
import constants from "@/constants/constants.json";
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
6
|
+
|
|
7
|
+
const socialIcons: Record<string, React.ElementType> = {
|
|
8
|
+
facebook: Facebook,
|
|
9
|
+
twitter: Twitter,
|
|
10
|
+
instagram: Instagram,
|
|
11
|
+
linkedin: Linkedin,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function Footer() {
|
|
15
|
+
const { t } = useTranslation("footer");
|
|
16
|
+
|
|
17
|
+
const socialLinks = useMemo(() => {
|
|
18
|
+
const socialMedia = constants?.socialMedia as
|
|
19
|
+
| Record<string, string>
|
|
20
|
+
| undefined;
|
|
21
|
+
if (!socialMedia) return [];
|
|
22
|
+
return Object.entries(socialMedia)
|
|
23
|
+
.filter(([platform, url]) => url && socialIcons[platform])
|
|
24
|
+
.map(([platform, url]) => ({
|
|
25
|
+
platform,
|
|
26
|
+
url,
|
|
27
|
+
Icon: socialIcons[platform],
|
|
28
|
+
}));
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
// Loading state
|
|
32
|
+
if (!constants) {
|
|
33
|
+
return (
|
|
34
|
+
<footer className="bg-muted/30 border-t">
|
|
35
|
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
36
|
+
<div className="animate-pulse text-center">
|
|
37
|
+
<div className="h-4 bg-muted rounded w-48 mx-auto"></div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</footer>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<footer className="bg-muted/30 border-t">
|
|
46
|
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
47
|
+
{/* Centered Content */}
|
|
48
|
+
<div className="text-center space-y-4">
|
|
49
|
+
{/* Social Media Links */}
|
|
50
|
+
{socialLinks.length > 0 && (
|
|
51
|
+
<div className="flex justify-center gap-2">
|
|
52
|
+
{socialLinks.map(({ platform, url, Icon }) => (
|
|
53
|
+
<a
|
|
54
|
+
key={platform}
|
|
55
|
+
href={url}
|
|
56
|
+
target="_blank"
|
|
57
|
+
rel="noopener noreferrer"
|
|
58
|
+
className="h-9 w-9 flex items-center justify-center rounded-md text-muted-foreground hover:text-primary hover:bg-accent transition-colors"
|
|
59
|
+
>
|
|
60
|
+
<Icon className="h-4 w-4" />
|
|
61
|
+
</a>
|
|
62
|
+
))}
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
|
|
66
|
+
{/* Copyright */}
|
|
67
|
+
<div>
|
|
68
|
+
<p className="text-sm text-muted-foreground">
|
|
69
|
+
{t("copyright", {
|
|
70
|
+
siteName: constants?.site?.name,
|
|
71
|
+
})}
|
|
72
|
+
</p>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
{/* Legal Links */}
|
|
76
|
+
<div className="flex flex-wrap justify-center gap-6">
|
|
77
|
+
<Link
|
|
78
|
+
to="/privacy"
|
|
79
|
+
className="text-sm text-muted-foreground hover:text-primary transition-colors"
|
|
80
|
+
>
|
|
81
|
+
{t("privacyPolicy", "Privacy")}
|
|
82
|
+
</Link>
|
|
83
|
+
<Link
|
|
84
|
+
to="/terms"
|
|
85
|
+
className="text-sm text-muted-foreground hover:text-primary transition-colors"
|
|
86
|
+
>
|
|
87
|
+
{t("termsOfService", "Terms")}
|
|
88
|
+
</Link>
|
|
89
|
+
<Link
|
|
90
|
+
to="/cookies"
|
|
91
|
+
className="text-sm text-muted-foreground hover:text-primary transition-colors"
|
|
92
|
+
>
|
|
93
|
+
{t("cookiePolicy", "Cookies")}
|
|
94
|
+
</Link>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</footer>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Link } from "react-router";
|
|
3
|
+
import { Menu } from "lucide-react";
|
|
4
|
+
import { Button } from "@/components/ui/button";
|
|
5
|
+
import {
|
|
6
|
+
Sheet,
|
|
7
|
+
SheetHeader,
|
|
8
|
+
SheetTitle,
|
|
9
|
+
SheetContent,
|
|
10
|
+
SheetTrigger,
|
|
11
|
+
} from "@/components/ui/sheet";
|
|
12
|
+
import { Logo } from "@/components/Logo";
|
|
13
|
+
import { useTranslation } from "react-i18next";
|
|
14
|
+
|
|
15
|
+
export function Header() {
|
|
16
|
+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
17
|
+
const { t } = useTranslation("header");
|
|
18
|
+
|
|
19
|
+
const navigation = [
|
|
20
|
+
{ name: t("home", "Home"), href: "/" },
|
|
21
|
+
{ name: t("about", "About"), href: "/about" },
|
|
22
|
+
{ name: t("contact", "Contact"), href: "/contact" },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<header className="sticky top-0 z-50 w-full border-b border-border/20 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
27
|
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
28
|
+
<div className="flex h-16 sm:h-20 items-center justify-between">
|
|
29
|
+
{/* Logo */}
|
|
30
|
+
<div className="flex-shrink-0 min-w-0">
|
|
31
|
+
<Logo size="sm" className="text-base sm:text-xl lg:text-2xl" />
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
{/* Desktop Navigation - Right Aligned */}
|
|
35
|
+
<nav className="hidden lg:flex items-center space-x-8">
|
|
36
|
+
{navigation.map((item) => (
|
|
37
|
+
<Link
|
|
38
|
+
key={item.name}
|
|
39
|
+
to={item.href}
|
|
40
|
+
className="text-base font-medium transition-colors hover:text-primary relative group py-2"
|
|
41
|
+
>
|
|
42
|
+
{item.name}
|
|
43
|
+
<span className="absolute -bottom-1 left-0 w-0 h-0.5 bg-primary transition-all duration-300 group-hover:w-full"></span>
|
|
44
|
+
</Link>
|
|
45
|
+
))}
|
|
46
|
+
</nav>
|
|
47
|
+
|
|
48
|
+
{/* Mobile Menu - Right Aligned */}
|
|
49
|
+
<div className="lg:hidden flex-shrink-0">
|
|
50
|
+
<Sheet open={mobileMenuOpen} onOpenChange={setMobileMenuOpen}>
|
|
51
|
+
<SheetTrigger asChild>
|
|
52
|
+
<Button variant="ghost" size="icon">
|
|
53
|
+
<Menu className="h-5 w-5" />
|
|
54
|
+
</Button>
|
|
55
|
+
</SheetTrigger>
|
|
56
|
+
<SheetContent side="right" className="w-[300px] sm:w-[400px]">
|
|
57
|
+
<SheetHeader>
|
|
58
|
+
<SheetTitle>{t("menu")}</SheetTitle>
|
|
59
|
+
</SheetHeader>
|
|
60
|
+
<div className="flex flex-col space-y-4 mt-8">
|
|
61
|
+
{navigation.map((item) => (
|
|
62
|
+
<Link
|
|
63
|
+
key={item.name}
|
|
64
|
+
to={item.href}
|
|
65
|
+
className="text-lg font-medium hover:text-primary transition-colors"
|
|
66
|
+
onClick={() => setMobileMenuOpen(false)}
|
|
67
|
+
>
|
|
68
|
+
{item.name}
|
|
69
|
+
</Link>
|
|
70
|
+
))}
|
|
71
|
+
</div>
|
|
72
|
+
</SheetContent>
|
|
73
|
+
</Sheet>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</header>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useTranslation } from "react-i18next";
|
|
2
|
+
import constants from "@/constants/constants.json";
|
|
3
|
+
export function Hero() {
|
|
4
|
+
const { t } = useTranslation("hero");
|
|
5
|
+
|
|
6
|
+
if (!constants) {
|
|
7
|
+
return (
|
|
8
|
+
<section className="relative overflow-hidden bg-gradient-to-br from-background via-muted/20 to-background">
|
|
9
|
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 lg:py-24 relative">
|
|
10
|
+
<div className="text-center space-y-8">
|
|
11
|
+
<div className="animate-pulse">
|
|
12
|
+
<div className="h-16 bg-muted rounded w-96 mx-auto mb-4"></div>
|
|
13
|
+
<div className="h-6 bg-muted rounded w-64 mx-auto mb-8"></div>
|
|
14
|
+
<div className="h-12 bg-muted rounded w-32 mx-auto"></div>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</section>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<section className="relative min-h-[60vh] flex items-center overflow-hidden bg-gradient-to-br from-background via-muted/10 to-background">
|
|
24
|
+
{/* Background Image */}
|
|
25
|
+
<div className="absolute inset-0">
|
|
26
|
+
{/* Background image will be placed here */}
|
|
27
|
+
<img
|
|
28
|
+
src="/images/hero-bg.jpg"
|
|
29
|
+
alt="Hero Background"
|
|
30
|
+
className="w-full h-full object-cover"
|
|
31
|
+
onError={(e) => {
|
|
32
|
+
// Hide broken image and keep gradient background
|
|
33
|
+
e.currentTarget.style.display = "none";
|
|
34
|
+
}}
|
|
35
|
+
/>
|
|
36
|
+
|
|
37
|
+
{/* Dark overlay for text readability */}
|
|
38
|
+
<div className="absolute inset-0 bg-gradient-to-r from-black/60 via-black/30 to-transparent"></div>
|
|
39
|
+
|
|
40
|
+
{/* Fallback gradient background */}
|
|
41
|
+
<div className="absolute inset-0 bg-gradient-to-r from-primary/5 via-transparent to-primary/5"></div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
{/* Content - Left Aligned with better contrast */}
|
|
45
|
+
<div className="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
|
|
46
|
+
<div className="max-w-2xl text-left">
|
|
47
|
+
{/* Main Headline */}
|
|
48
|
+
<div className="space-y-6 mb-8">
|
|
49
|
+
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold leading-normal text-white drop-shadow-lg pb-1">
|
|
50
|
+
<span>{t("discover", "Discover")} </span>
|
|
51
|
+
<span className="bg-gradient-to-r from-primary to-primary/80 bg-clip-text text-transparent">
|
|
52
|
+
{t("amazing", "Inspiring")}
|
|
53
|
+
</span>
|
|
54
|
+
<br />
|
|
55
|
+
<span>{t("content", "Stories")}</span>
|
|
56
|
+
</h1>
|
|
57
|
+
|
|
58
|
+
<p className="text-xl text-white/90 max-w-lg leading-relaxed drop-shadow-md">
|
|
59
|
+
{t(
|
|
60
|
+
"subtitle",
|
|
61
|
+
"Dive into a world of captivating narratives, expert insights, and thought-provoking content that inspires and educates.",
|
|
62
|
+
)}
|
|
63
|
+
</p>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</section>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useTranslation } from "react-i18next";
|
|
2
|
+
import { Button } from "@/components/ui/button";
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenu,
|
|
5
|
+
DropdownMenuContent,
|
|
6
|
+
DropdownMenuItem,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
} from "@/components/ui/dropdown-menu";
|
|
9
|
+
import { changeLanguage } from "@/lang";
|
|
10
|
+
import { cn } from "@/lib/utils";
|
|
11
|
+
import constants from "@/constants/constants.json";
|
|
12
|
+
|
|
13
|
+
const languages: Record<string, string> =
|
|
14
|
+
constants?.site?.availableLanguages || {};
|
|
15
|
+
|
|
16
|
+
export function LanguageSwitcher() {
|
|
17
|
+
const { i18n } = useTranslation();
|
|
18
|
+
const currentLang = i18n.language;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<DropdownMenu>
|
|
22
|
+
<DropdownMenuTrigger asChild>
|
|
23
|
+
<Button
|
|
24
|
+
variant="ghost"
|
|
25
|
+
size="sm"
|
|
26
|
+
className="h-9 px-2 text-sm font-medium"
|
|
27
|
+
>
|
|
28
|
+
{languages?.[currentLang] || currentLang.toUpperCase()}
|
|
29
|
+
</Button>
|
|
30
|
+
</DropdownMenuTrigger>
|
|
31
|
+
<DropdownMenuContent align="end">
|
|
32
|
+
{Object.entries(languages).map(([lang, label]) => (
|
|
33
|
+
<DropdownMenuItem
|
|
34
|
+
key={lang}
|
|
35
|
+
onClick={() => changeLanguage(lang)}
|
|
36
|
+
className={cn(
|
|
37
|
+
currentLang === lang ? "bg-accent" : "",
|
|
38
|
+
"hover:text-primary focus:text-primary",
|
|
39
|
+
)}
|
|
40
|
+
>
|
|
41
|
+
{label || lang.toUpperCase()}
|
|
42
|
+
</DropdownMenuItem>
|
|
43
|
+
))}
|
|
44
|
+
</DropdownMenuContent>
|
|
45
|
+
</DropdownMenu>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ReactNode, useEffect } from "react";
|
|
2
|
+
import { useLocation } from "react-router";
|
|
3
|
+
import { Header } from "./Header";
|
|
4
|
+
import { Footer } from "./Footer";
|
|
5
|
+
|
|
6
|
+
interface LayoutProps {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function Layout({ children }: LayoutProps) {
|
|
11
|
+
const location = useLocation();
|
|
12
|
+
|
|
13
|
+
// Scroll to top when route changes
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
window.scrollTo(0, 0);
|
|
16
|
+
}, [location.pathname]);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div className="min-h-screen flex flex-col">
|
|
20
|
+
<Header />
|
|
21
|
+
<main className="flex-1">{children}</main>
|
|
22
|
+
<Footer />
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Link } from "react-router";
|
|
2
|
+
import constants from "@/constants/constants.json";
|
|
3
|
+
|
|
4
|
+
interface LogoProps {
|
|
5
|
+
className?: string;
|
|
6
|
+
size?: "sm" | "md" | "lg" | "xl";
|
|
7
|
+
variant?: "default" | "light" | "dark";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function Logo({
|
|
11
|
+
className = "",
|
|
12
|
+
size = "md",
|
|
13
|
+
variant = "default",
|
|
14
|
+
}: LogoProps) {
|
|
15
|
+
// Text boyutları
|
|
16
|
+
const textSizes = {
|
|
17
|
+
sm: "text-base sm:text-lg",
|
|
18
|
+
md: "text-lg sm:text-xl",
|
|
19
|
+
lg: "text-xl sm:text-2xl",
|
|
20
|
+
xl: "text-2xl sm:text-3xl",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Image boyutları
|
|
24
|
+
const imageSizes = {
|
|
25
|
+
sm: "h-6 sm:h-8",
|
|
26
|
+
md: "h-8 sm:h-10",
|
|
27
|
+
lg: "h-10 sm:h-12",
|
|
28
|
+
xl: "h-12 sm:h-16",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Renk varyantları
|
|
32
|
+
const variants = {
|
|
33
|
+
default: "text-primary",
|
|
34
|
+
light: "text-white",
|
|
35
|
+
dark: "text-foreground",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const currentVariant = variants[variant];
|
|
39
|
+
const siteName = constants.site.name;
|
|
40
|
+
const logoImage = constants.site.logo;
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Link
|
|
44
|
+
to="/"
|
|
45
|
+
className={`flex items-center gap-1.5 sm:gap-2 md:gap-3 ${className}`}
|
|
46
|
+
>
|
|
47
|
+
{/* Logo Image (if exists) */}
|
|
48
|
+
{logoImage && (
|
|
49
|
+
<img
|
|
50
|
+
src={logoImage}
|
|
51
|
+
alt={`${siteName} Logo`}
|
|
52
|
+
className={`${imageSizes[size]} w-auto object-contain flex-shrink-0`}
|
|
53
|
+
/>
|
|
54
|
+
)}
|
|
55
|
+
|
|
56
|
+
{/* Site Name */}
|
|
57
|
+
<span
|
|
58
|
+
className={`${textSizes[size]} font-bold ${currentVariant} truncate`}
|
|
59
|
+
>
|
|
60
|
+
{siteName}
|
|
61
|
+
</span>
|
|
62
|
+
</Link>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Moon, Sun, Monitor } from "lucide-react";
|
|
2
|
+
import { Button } from "@/components/ui/button";
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenu,
|
|
5
|
+
DropdownMenuContent,
|
|
6
|
+
DropdownMenuItem,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
} from "@/components/ui/dropdown-menu";
|
|
9
|
+
import { useTheme, type Theme } from "@/hooks/use-theme";
|
|
10
|
+
import { cn } from "@/lib/utils";
|
|
11
|
+
|
|
12
|
+
const themes: {
|
|
13
|
+
value: Theme;
|
|
14
|
+
label: string;
|
|
15
|
+
icon: React.ComponentType<{ className?: string }>;
|
|
16
|
+
}[] = [
|
|
17
|
+
{ value: "light", label: "Light", icon: Sun },
|
|
18
|
+
{ value: "dark", label: "Dark", icon: Moon },
|
|
19
|
+
{ value: "system", label: "System", icon: Monitor },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
export function ThemeSwitcher() {
|
|
23
|
+
const { theme, setTheme, effectiveTheme } = useTheme();
|
|
24
|
+
|
|
25
|
+
const currentTheme = themes.find((t) => t.value === theme);
|
|
26
|
+
const CurrentIcon =
|
|
27
|
+
theme === "system"
|
|
28
|
+
? effectiveTheme === "dark"
|
|
29
|
+
? themes[1].icon
|
|
30
|
+
: themes[0].icon
|
|
31
|
+
: currentTheme?.icon || Sun;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<DropdownMenu>
|
|
35
|
+
<DropdownMenuTrigger asChild>
|
|
36
|
+
<Button variant="ghost" size="sm" className="h-9 w-9 px-0">
|
|
37
|
+
<CurrentIcon className="h-4 w-4" />
|
|
38
|
+
<span className="sr-only">Toggle theme</span>
|
|
39
|
+
</Button>
|
|
40
|
+
</DropdownMenuTrigger>
|
|
41
|
+
<DropdownMenuContent align="end">
|
|
42
|
+
{themes.map(({ value, label, icon: Icon }) => (
|
|
43
|
+
<DropdownMenuItem
|
|
44
|
+
key={value}
|
|
45
|
+
onClick={() => setTheme(value)}
|
|
46
|
+
className={cn(
|
|
47
|
+
theme === value ? "bg-accent" : "",
|
|
48
|
+
"hover:text-primary focus:text-primary flex items-center gap-2 group",
|
|
49
|
+
)}
|
|
50
|
+
>
|
|
51
|
+
<Icon className="h-4 w-4 transition-colors group-hover:text-primary" />
|
|
52
|
+
<span>{label}</span>
|
|
53
|
+
</DropdownMenuItem>
|
|
54
|
+
))}
|
|
55
|
+
</DropdownMenuContent>
|
|
56
|
+
</DropdownMenu>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
|
3
|
+
import { ChevronDownIcon } from "lucide-react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
function Accordion({
|
|
8
|
+
...props
|
|
9
|
+
}: 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,155 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
import { buttonVariants } from "@/components/ui/button";
|
|
6
|
+
|
|
7
|
+
function AlertDialog({
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
|
10
|
+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function AlertDialogTrigger({
|
|
14
|
+
...props
|
|
15
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
|
|
16
|
+
return (
|
|
17
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function AlertDialogPortal({
|
|
22
|
+
...props
|
|
23
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
|
|
24
|
+
return (
|
|
25
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function AlertDialogOverlay({
|
|
30
|
+
className,
|
|
31
|
+
...props
|
|
32
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
|
|
33
|
+
return (
|
|
34
|
+
<AlertDialogPrimitive.Overlay
|
|
35
|
+
data-slot="alert-dialog-overlay"
|
|
36
|
+
className={cn(
|
|
37
|
+
"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",
|
|
38
|
+
className,
|
|
39
|
+
)}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function AlertDialogContent({
|
|
46
|
+
className,
|
|
47
|
+
...props
|
|
48
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
|
|
49
|
+
return (
|
|
50
|
+
<AlertDialogPortal>
|
|
51
|
+
<AlertDialogOverlay />
|
|
52
|
+
<AlertDialogPrimitive.Content
|
|
53
|
+
data-slot="alert-dialog-content"
|
|
54
|
+
className={cn(
|
|
55
|
+
"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",
|
|
56
|
+
className,
|
|
57
|
+
)}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
</AlertDialogPortal>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function AlertDialogHeader({
|
|
65
|
+
className,
|
|
66
|
+
...props
|
|
67
|
+
}: React.ComponentProps<"div">) {
|
|
68
|
+
return (
|
|
69
|
+
<div
|
|
70
|
+
data-slot="alert-dialog-header"
|
|
71
|
+
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
|
72
|
+
{...props}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function AlertDialogFooter({
|
|
78
|
+
className,
|
|
79
|
+
...props
|
|
80
|
+
}: React.ComponentProps<"div">) {
|
|
81
|
+
return (
|
|
82
|
+
<div
|
|
83
|
+
data-slot="alert-dialog-footer"
|
|
84
|
+
className={cn(
|
|
85
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
86
|
+
className,
|
|
87
|
+
)}
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function AlertDialogTitle({
|
|
94
|
+
className,
|
|
95
|
+
...props
|
|
96
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
97
|
+
return (
|
|
98
|
+
<AlertDialogPrimitive.Title
|
|
99
|
+
data-slot="alert-dialog-title"
|
|
100
|
+
className={cn("text-lg font-semibold", className)}
|
|
101
|
+
{...props}
|
|
102
|
+
/>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function AlertDialogDescription({
|
|
107
|
+
className,
|
|
108
|
+
...props
|
|
109
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
110
|
+
return (
|
|
111
|
+
<AlertDialogPrimitive.Description
|
|
112
|
+
data-slot="alert-dialog-description"
|
|
113
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
114
|
+
{...props}
|
|
115
|
+
/>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function AlertDialogAction({
|
|
120
|
+
className,
|
|
121
|
+
...props
|
|
122
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
|
|
123
|
+
return (
|
|
124
|
+
<AlertDialogPrimitive.Action
|
|
125
|
+
className={cn(buttonVariants(), className)}
|
|
126
|
+
{...props}
|
|
127
|
+
/>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function AlertDialogCancel({
|
|
132
|
+
className,
|
|
133
|
+
...props
|
|
134
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
|
|
135
|
+
return (
|
|
136
|
+
<AlertDialogPrimitive.Cancel
|
|
137
|
+
className={cn(buttonVariants({ variant: "outline" }), className)}
|
|
138
|
+
{...props}
|
|
139
|
+
/>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export {
|
|
144
|
+
AlertDialog,
|
|
145
|
+
AlertDialogPortal,
|
|
146
|
+
AlertDialogOverlay,
|
|
147
|
+
AlertDialogTrigger,
|
|
148
|
+
AlertDialogContent,
|
|
149
|
+
AlertDialogHeader,
|
|
150
|
+
AlertDialogFooter,
|
|
151
|
+
AlertDialogTitle,
|
|
152
|
+
AlertDialogDescription,
|
|
153
|
+
AlertDialogAction,
|
|
154
|
+
AlertDialogCancel,
|
|
155
|
+
};
|