@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.
Files changed (285) hide show
  1. package/dist/index.js +212 -0
  2. package/dist/registry/about-page.json +45 -0
  3. package/dist/registry/about-section.json +40 -0
  4. package/dist/registry/animations.json +69 -0
  5. package/dist/registry/bento-grid-section.json +42 -0
  6. package/dist/registry/blog-core.json +74 -0
  7. package/dist/registry/blog-list-page.json +48 -0
  8. package/dist/registry/blog-section.json +43 -0
  9. package/dist/registry/cards-carousel-section.json +46 -0
  10. package/dist/registry/cart-drawer.json +43 -0
  11. package/dist/registry/cart-page.json +47 -0
  12. package/dist/registry/category-section.json +43 -0
  13. package/dist/registry/checkout-page.json +47 -0
  14. package/dist/registry/contact-info-grid.json +40 -0
  15. package/dist/registry/contact-page-centered.json +50 -0
  16. package/dist/registry/contact-page-map-overlay.json +54 -0
  17. package/dist/registry/contact-page-map-split.json +54 -0
  18. package/dist/registry/contact-page-split.json +49 -0
  19. package/dist/registry/contact-page.json +45 -0
  20. package/dist/registry/content-section.json +40 -0
  21. package/dist/registry/cookies-page.json +45 -0
  22. package/dist/registry/cta-section.json +40 -0
  23. package/dist/registry/docs/about-page.md +32 -0
  24. package/dist/registry/docs/about-section.md +33 -0
  25. package/dist/registry/docs/animations.md +44 -0
  26. package/dist/registry/docs/bento-grid-section.md +40 -0
  27. package/dist/registry/docs/blog-core.md +37 -0
  28. package/dist/registry/docs/blog-list-page.md +38 -0
  29. package/dist/registry/docs/blog-section.md +39 -0
  30. package/dist/registry/docs/cards-carousel-section.md +39 -0
  31. package/dist/registry/docs/cart-drawer.md +42 -0
  32. package/dist/registry/docs/cart-page.md +37 -0
  33. package/dist/registry/docs/category-section.md +34 -0
  34. package/dist/registry/docs/checkout-page.md +38 -0
  35. package/dist/registry/docs/contact-info-grid.md +33 -0
  36. package/dist/registry/docs/contact-page-centered.md +41 -0
  37. package/dist/registry/docs/contact-page-map-overlay.md +44 -0
  38. package/dist/registry/docs/contact-page-map-split.md +44 -0
  39. package/dist/registry/docs/contact-page-split.md +40 -0
  40. package/dist/registry/docs/contact-page.md +33 -0
  41. package/dist/registry/docs/content-section.md +35 -0
  42. package/dist/registry/docs/cookies-page.md +32 -0
  43. package/dist/registry/docs/cta-section.md +32 -0
  44. package/dist/registry/docs/ecommerce-core.md +41 -0
  45. package/dist/registry/docs/empty-page.md +31 -0
  46. package/dist/registry/docs/faq-categorized.md +38 -0
  47. package/dist/registry/docs/faq-simple.md +38 -0
  48. package/dist/registry/docs/favorites-blog-block.md +38 -0
  49. package/dist/registry/docs/favorites-ecommerce-block.md +38 -0
  50. package/dist/registry/docs/feature-section.md +33 -0
  51. package/dist/registry/docs/featured-products.md +38 -0
  52. package/dist/registry/docs/footer-detailed.md +33 -0
  53. package/dist/registry/docs/footer-minimal.md +32 -0
  54. package/dist/registry/docs/footer.md +32 -0
  55. package/dist/registry/docs/google-map.md +36 -0
  56. package/dist/registry/docs/header-centered-pill.md +37 -0
  57. package/dist/registry/docs/header-ecommerce.md +38 -0
  58. package/dist/registry/docs/header-mega.md +40 -0
  59. package/dist/registry/docs/header-minimal.md +38 -0
  60. package/dist/registry/docs/header-simple.md +32 -0
  61. package/dist/registry/docs/hero-cta.md +38 -0
  62. package/dist/registry/docs/hero-gradient.md +33 -0
  63. package/dist/registry/docs/hero-grid.md +40 -0
  64. package/dist/registry/docs/hero-profile.md +33 -0
  65. package/dist/registry/docs/hero.md +32 -0
  66. package/dist/registry/docs/login-page-split.md +40 -0
  67. package/dist/registry/docs/login-page.md +39 -0
  68. package/dist/registry/docs/newsletter-section.md +40 -0
  69. package/dist/registry/docs/order-card-compact.md +37 -0
  70. package/dist/registry/docs/order-detail-block.md +37 -0
  71. package/dist/registry/docs/orders-list-block.md +40 -0
  72. package/dist/registry/docs/payment-success-block.md +32 -0
  73. package/dist/registry/docs/post-card.md +37 -0
  74. package/dist/registry/docs/post-detail-block.md +37 -0
  75. package/dist/registry/docs/pricing-card.md +37 -0
  76. package/dist/registry/docs/pricing-section.md +39 -0
  77. package/dist/registry/docs/privacy-page.md +32 -0
  78. package/dist/registry/docs/product-card-detailed.md +42 -0
  79. package/dist/registry/docs/product-card-hover.md +35 -0
  80. package/dist/registry/docs/product-card.md +37 -0
  81. package/dist/registry/docs/product-detail-block.md +37 -0
  82. package/dist/registry/docs/product-detail-section.md +45 -0
  83. package/dist/registry/docs/products-page.md +39 -0
  84. package/dist/registry/docs/related-posts-block.md +38 -0
  85. package/dist/registry/docs/related-products-block.md +38 -0
  86. package/dist/registry/docs/service-card.md +34 -0
  87. package/dist/registry/docs/skill-card.md +33 -0
  88. package/dist/registry/docs/terms-page.md +32 -0
  89. package/dist/registry/docs/testimonials-carousel.md +40 -0
  90. package/dist/registry/docs/testimonials-grid.md +39 -0
  91. package/dist/registry/ecommerce-core.json +95 -0
  92. package/dist/registry/empty-page.json +45 -0
  93. package/dist/registry/faq-categorized.json +42 -0
  94. package/dist/registry/faq-simple.json +42 -0
  95. package/dist/registry/favorites-blog-block.json +43 -0
  96. package/dist/registry/favorites-ecommerce-block.json +43 -0
  97. package/dist/registry/feature-section.json +40 -0
  98. package/dist/registry/featured-products.json +43 -0
  99. package/dist/registry/footer-detailed.json +43 -0
  100. package/dist/registry/footer-minimal.json +40 -0
  101. package/dist/registry/footer.json +40 -0
  102. package/dist/registry/google-map.json +31 -0
  103. package/dist/registry/header-centered-pill.json +45 -0
  104. package/dist/registry/header-ecommerce.json +42 -0
  105. package/dist/registry/header-mega.json +47 -0
  106. package/dist/registry/header-minimal.json +45 -0
  107. package/dist/registry/header-simple.json +43 -0
  108. package/dist/registry/hero-cta.json +42 -0
  109. package/dist/registry/hero-gradient.json +40 -0
  110. package/dist/registry/hero-grid.json +42 -0
  111. package/dist/registry/hero-profile.json +62 -0
  112. package/dist/registry/hero.json +40 -0
  113. package/dist/registry/index.json +70 -0
  114. package/dist/registry/login-page-split.json +47 -0
  115. package/dist/registry/login-page.json +49 -0
  116. package/dist/registry/newsletter-section.json +44 -0
  117. package/dist/registry/order-card-compact.json +42 -0
  118. package/dist/registry/order-detail-block.json +42 -0
  119. package/dist/registry/orders-list-block.json +45 -0
  120. package/dist/registry/payment-success-block.json +40 -0
  121. package/dist/registry/post-card.json +42 -0
  122. package/dist/registry/post-detail-block.json +42 -0
  123. package/dist/registry/pricing-card.json +40 -0
  124. package/dist/registry/pricing-section.json +43 -0
  125. package/dist/registry/privacy-page.json +45 -0
  126. package/dist/registry/product-card-detailed.json +45 -0
  127. package/dist/registry/product-card-hover.json +40 -0
  128. package/dist/registry/product-card.json +42 -0
  129. package/dist/registry/product-detail-block.json +42 -0
  130. package/dist/registry/product-detail-section.json +46 -0
  131. package/dist/registry/products-page.json +48 -0
  132. package/dist/registry/related-posts-block.json +43 -0
  133. package/dist/registry/related-products-block.json +43 -0
  134. package/dist/registry/service-card.json +28 -0
  135. package/dist/registry/skill-card.json +28 -0
  136. package/dist/registry/terms-page.json +45 -0
  137. package/dist/registry/testimonials-carousel.json +44 -0
  138. package/dist/registry/testimonials-grid.json +43 -0
  139. package/package.json +52 -0
  140. package/template/.env +6 -0
  141. package/template/.prettierignore +3 -0
  142. package/template/.prettierrc +1 -0
  143. package/template/README.md +73 -0
  144. package/template/bun.lock +1007 -0
  145. package/template/components.json +22 -0
  146. package/template/eslint.config.js +32 -0
  147. package/template/index.html +285 -0
  148. package/template/package.json +92 -0
  149. package/template/promake.json +6 -0
  150. package/template/public/_redirects +1 -0
  151. package/template/public/data/database.db +0 -0
  152. package/template/public/favicon.svg +1 -0
  153. package/template/public/images/placeholder.png +0 -0
  154. package/template/public/robots.txt +14 -0
  155. package/template/scripts/init-db.ts +131 -0
  156. package/template/src/App.tsx +33 -0
  157. package/template/src/components/Footer.tsx +100 -0
  158. package/template/src/components/Header.tsx +79 -0
  159. package/template/src/components/Hero.tsx +69 -0
  160. package/template/src/components/LanguageSwitcher.tsx +47 -0
  161. package/template/src/components/Layout.tsx +25 -0
  162. package/template/src/components/Logo.tsx +64 -0
  163. package/template/src/components/ThemeSwitcher.tsx +58 -0
  164. package/template/src/components/ui/accordion.tsx +64 -0
  165. package/template/src/components/ui/alert-dialog.tsx +155 -0
  166. package/template/src/components/ui/alert.tsx +66 -0
  167. package/template/src/components/ui/aspect-ratio.tsx +11 -0
  168. package/template/src/components/ui/avatar.tsx +51 -0
  169. package/template/src/components/ui/badge.tsx +46 -0
  170. package/template/src/components/ui/breadcrumb.tsx +109 -0
  171. package/template/src/components/ui/button-group.tsx +83 -0
  172. package/template/src/components/ui/button.tsx +62 -0
  173. package/template/src/components/ui/calendar.tsx +220 -0
  174. package/template/src/components/ui/card.tsx +92 -0
  175. package/template/src/components/ui/carousel.tsx +239 -0
  176. package/template/src/components/ui/chart.tsx +357 -0
  177. package/template/src/components/ui/checkbox.tsx +32 -0
  178. package/template/src/components/ui/collapsible.tsx +31 -0
  179. package/template/src/components/ui/command.tsx +182 -0
  180. package/template/src/components/ui/context-menu.tsx +252 -0
  181. package/template/src/components/ui/dialog.tsx +141 -0
  182. package/template/src/components/ui/drawer.tsx +135 -0
  183. package/template/src/components/ui/dropdown-menu.tsx +255 -0
  184. package/template/src/components/ui/empty.tsx +104 -0
  185. package/template/src/components/ui/field.tsx +246 -0
  186. package/template/src/components/ui/form.tsx +168 -0
  187. package/template/src/components/ui/hover-card.tsx +44 -0
  188. package/template/src/components/ui/input-group.tsx +170 -0
  189. package/template/src/components/ui/input-otp.tsx +75 -0
  190. package/template/src/components/ui/input.tsx +21 -0
  191. package/template/src/components/ui/item.tsx +193 -0
  192. package/template/src/components/ui/kbd.tsx +28 -0
  193. package/template/src/components/ui/label.tsx +24 -0
  194. package/template/src/components/ui/menubar.tsx +274 -0
  195. package/template/src/components/ui/navigation-menu.tsx +168 -0
  196. package/template/src/components/ui/pagination.tsx +127 -0
  197. package/template/src/components/ui/popover.tsx +48 -0
  198. package/template/src/components/ui/progress.tsx +29 -0
  199. package/template/src/components/ui/radio-group.tsx +45 -0
  200. package/template/src/components/ui/resizable.tsx +54 -0
  201. package/template/src/components/ui/scroll-area.tsx +58 -0
  202. package/template/src/components/ui/select.tsx +188 -0
  203. package/template/src/components/ui/separator.tsx +28 -0
  204. package/template/src/components/ui/sheet.tsx +137 -0
  205. package/template/src/components/ui/sidebar.tsx +726 -0
  206. package/template/src/components/ui/skeleton.tsx +13 -0
  207. package/template/src/components/ui/slider.tsx +63 -0
  208. package/template/src/components/ui/sonner.tsx +38 -0
  209. package/template/src/components/ui/spinner.tsx +16 -0
  210. package/template/src/components/ui/switch.tsx +31 -0
  211. package/template/src/components/ui/table.tsx +114 -0
  212. package/template/src/components/ui/tabs.tsx +66 -0
  213. package/template/src/components/ui/textarea.tsx +18 -0
  214. package/template/src/components/ui/toggle-group.tsx +81 -0
  215. package/template/src/components/ui/toggle.tsx +45 -0
  216. package/template/src/components/ui/tooltip.tsx +61 -0
  217. package/template/src/constants/constants.json +58 -0
  218. package/template/src/hooks/use-is-mobile.ts +21 -0
  219. package/template/src/hooks/use-page-title.ts +49 -0
  220. package/template/src/hooks/use-theme.ts +57 -0
  221. package/template/src/index.css +128 -0
  222. package/template/src/lang/en/about.json +4 -0
  223. package/template/src/lang/en/contact.json +39 -0
  224. package/template/src/lang/en/cookies.json +4 -0
  225. package/template/src/lang/en/footer.json +12 -0
  226. package/template/src/lang/en/forgotPassword.json +37 -0
  227. package/template/src/lang/en/header.json +10 -0
  228. package/template/src/lang/en/hero.json +8 -0
  229. package/template/src/lang/en/index.json +30 -0
  230. package/template/src/lang/en/login.json +18 -0
  231. package/template/src/lang/en/notfound.json +7 -0
  232. package/template/src/lang/en/privacy.json +4 -0
  233. package/template/src/lang/en/register.json +25 -0
  234. package/template/src/lang/en/terms.json +4 -0
  235. package/template/src/lang/index.ts +86 -0
  236. package/template/src/lang/tr/about.json +4 -0
  237. package/template/src/lang/tr/contact.json +39 -0
  238. package/template/src/lang/tr/cookies.json +4 -0
  239. package/template/src/lang/tr/footer.json +12 -0
  240. package/template/src/lang/tr/forgotPassword.json +37 -0
  241. package/template/src/lang/tr/header.json +10 -0
  242. package/template/src/lang/tr/hero.json +8 -0
  243. package/template/src/lang/tr/index.json +30 -0
  244. package/template/src/lang/tr/login.json +18 -0
  245. package/template/src/lang/tr/notfound.json +7 -0
  246. package/template/src/lang/tr/privacy.json +4 -0
  247. package/template/src/lang/tr/register.json +25 -0
  248. package/template/src/lang/tr/terms.json +4 -0
  249. package/template/src/lib/api.ts +237 -0
  250. package/template/src/lib/storage.ts +109 -0
  251. package/template/src/lib/utils.ts +15 -0
  252. package/template/src/main.tsx +13 -0
  253. package/template/src/modules/api/USAGE.md +515 -0
  254. package/template/src/modules/api/customer-client.ts +20 -0
  255. package/template/src/modules/api/get-error-message.ts +18 -0
  256. package/template/src/modules/api/validation/en.json +29 -0
  257. package/template/src/modules/api/validation/tr.json +29 -0
  258. package/template/src/modules/auth/USAGE.md +248 -0
  259. package/template/src/modules/auth/auth-header-menu.tsx +123 -0
  260. package/template/src/modules/auth/auth-store.ts +57 -0
  261. package/template/src/modules/auth/forgot-password-page.tsx +371 -0
  262. package/template/src/modules/auth/login-page.tsx +183 -0
  263. package/template/src/modules/auth/register-page.tsx +252 -0
  264. package/template/src/modules/auth/use-auth.ts +273 -0
  265. package/template/src/modules/db/adapters/IDataAdapter.ts +26 -0
  266. package/template/src/modules/db/adapters/SqliteAdapter.ts +364 -0
  267. package/template/src/modules/db/adapters/index.ts +2 -0
  268. package/template/src/modules/db/config.ts +59 -0
  269. package/template/src/modules/db/core/DataManager.ts +125 -0
  270. package/template/src/modules/db/core/types.ts +101 -0
  271. package/template/src/modules/db/index.ts +42 -0
  272. package/template/src/modules/db/react/QueryProvider.tsx +16 -0
  273. package/template/src/modules/db/react/index.ts +23 -0
  274. package/template/src/modules/db/react/queryClient.ts +64 -0
  275. package/template/src/modules/db/react/useRepository.ts +400 -0
  276. package/template/src/modules/db/utils/parsers.ts +96 -0
  277. package/template/src/pages/Index.tsx +108 -0
  278. package/template/src/pages/NotFound.tsx +35 -0
  279. package/template/src/router.tsx +14 -0
  280. package/template/src/types/index.ts +0 -0
  281. package/template/src/vite-env.d.ts +1 -0
  282. package/template/tsconfig.app.json +32 -0
  283. package/template/tsconfig.json +17 -0
  284. package/template/tsconfig.node.json +26 -0
  285. 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
+ };