@promakeai/cli 0.0.5 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/dist/index.js +214 -135
  2. package/dist/registry/about-page.json +5 -3
  3. package/dist/registry/about-section.json +2 -2
  4. package/dist/registry/announcement-bar.json +43 -0
  5. package/dist/registry/api.json +55 -0
  6. package/dist/registry/auth-core.json +43 -0
  7. package/dist/registry/auth.json +70 -0
  8. package/dist/registry/bento-grid-section.json +1 -1
  9. package/dist/registry/blog-list-page.json +3 -2
  10. package/dist/registry/blog-section.json +2 -2
  11. package/dist/registry/cart-drawer.json +1 -1
  12. package/dist/registry/cart-page.json +5 -4
  13. package/dist/registry/case-study-page.json +48 -0
  14. package/dist/registry/category-section.json +1 -1
  15. package/dist/registry/checkout-page.json +7 -5
  16. package/dist/registry/coming-soon-page-minimal.json +45 -0
  17. package/dist/registry/coming-soon-page.json +47 -0
  18. package/dist/registry/contact-info-grid.json +2 -2
  19. package/dist/registry/contact-page-centered.json +2 -2
  20. package/dist/registry/contact-page-map-overlay.json +4 -3
  21. package/dist/registry/contact-page-map-split.json +4 -3
  22. package/dist/registry/contact-page-split.json +3 -3
  23. package/dist/registry/contact-page.json +5 -3
  24. package/dist/registry/cookie-consent.json +43 -0
  25. package/dist/registry/cookies-page.json +4 -2
  26. package/dist/registry/cta-section.json +2 -2
  27. package/dist/registry/db.json +129 -0
  28. package/dist/registry/docs/about-page.md +5 -0
  29. package/dist/registry/docs/announcement-bar.md +38 -0
  30. package/dist/registry/docs/auth-core.md +64 -0
  31. package/dist/registry/docs/blog-list-page.md +1 -0
  32. package/dist/registry/docs/cart-page.md +1 -0
  33. package/dist/registry/docs/case-study-page.md +39 -0
  34. package/dist/registry/docs/checkout-page.md +3 -1
  35. package/dist/registry/docs/coming-soon-page-minimal.md +32 -0
  36. package/dist/registry/docs/coming-soon-page.md +37 -0
  37. package/dist/registry/docs/contact-page-map-overlay.md +2 -2
  38. package/dist/registry/docs/contact-page-map-split.md +2 -2
  39. package/dist/registry/docs/contact-page.md +5 -0
  40. package/dist/registry/docs/cookie-consent.md +37 -0
  41. package/dist/registry/docs/cookies-page.md +5 -0
  42. package/dist/registry/docs/ecommerce-core.md +4 -3
  43. package/dist/registry/docs/forgot-password-page-split.md +45 -0
  44. package/dist/registry/docs/forgot-password-page.md +46 -0
  45. package/dist/registry/docs/header-ecommerce.md +2 -0
  46. package/dist/registry/docs/hero-carousel.md +37 -0
  47. package/dist/registry/docs/landing-page-app.md +43 -0
  48. package/dist/registry/docs/landing-page-saas.md +41 -0
  49. package/dist/registry/docs/login-page-split.md +13 -4
  50. package/dist/registry/docs/login-page.md +17 -4
  51. package/dist/registry/docs/logo-cloud.md +33 -0
  52. package/dist/registry/docs/masonry-grid.md +37 -0
  53. package/dist/registry/docs/my-orders-page.md +44 -0
  54. package/dist/registry/docs/order-confirmation-page.md +41 -0
  55. package/dist/registry/docs/portfolio-page.md +38 -0
  56. package/dist/registry/docs/pricing-page.md +38 -0
  57. package/dist/registry/docs/privacy-page.md +5 -0
  58. package/dist/registry/docs/product-quick-view.md +37 -0
  59. package/dist/registry/docs/products-page.md +1 -0
  60. package/dist/registry/docs/reading-progress.md +31 -0
  61. package/dist/registry/docs/register-page-split.md +45 -0
  62. package/dist/registry/docs/register-page.md +46 -0
  63. package/dist/registry/docs/reset-password-page-split.md +45 -0
  64. package/dist/registry/docs/reset-password-page.md +36 -0
  65. package/dist/registry/docs/share-buttons.md +37 -0
  66. package/dist/registry/docs/team-page.md +38 -0
  67. package/dist/registry/docs/terms-page.md +5 -0
  68. package/dist/registry/docs/timeline-section.md +37 -0
  69. package/dist/registry/docs/video-hero.md +41 -0
  70. package/dist/registry/ecommerce-core.json +18 -2
  71. package/dist/registry/empty-page.json +1 -1
  72. package/dist/registry/faq-categorized.json +2 -2
  73. package/dist/registry/faq-simple.json +2 -2
  74. package/dist/registry/favorites-blog-block.json +1 -1
  75. package/dist/registry/favorites-ecommerce-block.json +1 -1
  76. package/dist/registry/feature-section.json +2 -2
  77. package/dist/registry/featured-products.json +1 -1
  78. package/dist/registry/footer-detailed.json +1 -1
  79. package/dist/registry/footer-minimal.json +3 -3
  80. package/dist/registry/footer.json +2 -2
  81. package/dist/registry/forgot-password-page-split.json +50 -0
  82. package/dist/registry/forgot-password-page.json +51 -0
  83. package/dist/registry/header-ecommerce.json +4 -2
  84. package/dist/registry/header-mega.json +2 -2
  85. package/dist/registry/header-minimal.json +1 -1
  86. package/dist/registry/header-simple.json +1 -1
  87. package/dist/registry/hero-carousel.json +45 -0
  88. package/dist/registry/hero-cta.json +2 -2
  89. package/dist/registry/hero-gradient.json +2 -2
  90. package/dist/registry/hero-profile.json +1 -1
  91. package/dist/registry/hero.json +2 -2
  92. package/dist/registry/index.json +24 -1
  93. package/dist/registry/landing-page-app.json +47 -0
  94. package/dist/registry/landing-page-saas.json +47 -0
  95. package/dist/registry/login-page-split.json +11 -7
  96. package/dist/registry/login-page.json +4 -4
  97. package/dist/registry/logo-cloud.json +41 -0
  98. package/dist/registry/masonry-grid.json +43 -0
  99. package/dist/registry/my-orders-page.json +52 -0
  100. package/dist/registry/order-confirmation-page.json +49 -0
  101. package/dist/registry/orders-list-block.json +1 -1
  102. package/dist/registry/payment-success-block.json +1 -1
  103. package/dist/registry/portfolio-page.json +45 -0
  104. package/dist/registry/post-detail-block.json +1 -1
  105. package/dist/registry/pricing-page.json +47 -0
  106. package/dist/registry/pricing-section.json +2 -2
  107. package/dist/registry/privacy-page.json +4 -2
  108. package/dist/registry/product-detail-block.json +1 -1
  109. package/dist/registry/product-quick-view.json +46 -0
  110. package/dist/registry/products-page.json +5 -4
  111. package/dist/registry/reading-progress.json +43 -0
  112. package/dist/registry/register-page-split.json +50 -0
  113. package/dist/registry/register-page.json +51 -0
  114. package/dist/registry/related-posts-block.json +1 -1
  115. package/dist/registry/reset-password-page-split.json +50 -0
  116. package/dist/registry/reset-password-page.json +39 -0
  117. package/dist/registry/share-buttons.json +46 -0
  118. package/dist/registry/team-page.json +47 -0
  119. package/dist/registry/terms-page.json +4 -2
  120. package/dist/registry/testimonials-carousel.json +2 -2
  121. package/dist/registry/testimonials-grid.json +2 -2
  122. package/dist/registry/timeline-section.json +43 -0
  123. package/dist/registry/video-hero.json +42 -0
  124. package/package.json +1 -1
  125. package/template/index.html +5 -5
  126. package/template/src/App.tsx +7 -24
  127. package/template/src/components/GoogleAnalytics.tsx +34 -0
  128. package/template/src/components/Layout.tsx +1 -5
  129. package/template/src/components/ScriptInjector.tsx +62 -0
  130. package/template/src/constants/constants.json +8 -2
  131. package/template/src/index.css +1 -0
  132. package/template/src/lang/en/index.json +1 -28
  133. package/template/src/lang/tr/index.json +1 -28
  134. package/template/src/pages/Index.tsx +1 -98
  135. package/template/src/components/Footer.tsx +0 -100
  136. package/template/src/components/Header.tsx +0 -79
  137. package/template/src/components/Hero.tsx +0 -69
  138. package/template/src/modules/api/USAGE.md +0 -515
  139. package/template/src/modules/api/customer-client.ts +0 -20
  140. package/template/src/modules/api/get-error-message.ts +0 -18
  141. package/template/src/modules/api/validation/en.json +0 -29
  142. package/template/src/modules/api/validation/tr.json +0 -29
  143. package/template/src/modules/auth/USAGE.md +0 -248
  144. package/template/src/modules/auth/auth-header-menu.tsx +0 -123
  145. package/template/src/modules/auth/auth-store.ts +0 -57
  146. package/template/src/modules/auth/forgot-password-page.tsx +0 -371
  147. package/template/src/modules/auth/login-page.tsx +0 -183
  148. package/template/src/modules/auth/register-page.tsx +0 -252
  149. package/template/src/modules/auth/use-auth.ts +0 -273
  150. package/template/src/modules/db/adapters/IDataAdapter.ts +0 -26
  151. package/template/src/modules/db/adapters/SqliteAdapter.ts +0 -364
  152. package/template/src/modules/db/adapters/index.ts +0 -2
  153. package/template/src/modules/db/config.ts +0 -59
  154. package/template/src/modules/db/core/DataManager.ts +0 -125
  155. package/template/src/modules/db/core/types.ts +0 -101
  156. package/template/src/modules/db/index.ts +0 -42
  157. package/template/src/modules/db/react/QueryProvider.tsx +0 -16
  158. package/template/src/modules/db/react/index.ts +0 -23
  159. package/template/src/modules/db/react/queryClient.ts +0 -64
  160. package/template/src/modules/db/react/useRepository.ts +0 -400
  161. package/template/src/modules/db/utils/parsers.ts +0 -96
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "cookie-consent",
3
+ "type": "registry:component",
4
+ "title": "Cookie Consent Banner",
5
+ "description": "GDPR-compliant cookie consent banner with Accept, Decline, and Customize buttons. Features slide-up animation, localStorage persistence, and customizable links to privacy/cookie policy pages.",
6
+ "dependencies": [
7
+ "motion"
8
+ ],
9
+ "registryDependencies": [],
10
+ "usage": "import { CookieConsent } from '@/modules/cookie-consent';\n\n// Add to your App or Layout component\n<CookieConsent\n onAccept={() => console.log('Accepted')}\n onDecline={() => console.log('Declined')}\n onCustomize={() => openPreferencesModal()}\n/>\n\n• Auto-hides after user decision\n• localStorage persistence\n• Customizable policy URLs",
11
+ "files": [
12
+ {
13
+ "path": "cookie-consent/index.ts",
14
+ "type": "registry:index",
15
+ "target": "$modules$/cookie-consent/index.ts",
16
+ "content": "export { CookieConsent } from \"./cookie-consent\";\r\n"
17
+ },
18
+ {
19
+ "path": "cookie-consent/cookie-consent.tsx",
20
+ "type": "registry:component",
21
+ "target": "$modules$/cookie-consent/cookie-consent.tsx",
22
+ "content": "import { useState, useEffect } from \"react\";\r\nimport { Link } from \"react-router\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { X } from \"lucide-react\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { motion, AnimatePresence } from \"motion/react\";\r\n\r\ninterface CookieConsentProps {\r\n className?: string;\r\n privacyPolicyUrl?: string;\r\n cookiePolicyUrl?: string;\r\n onAccept?: () => void;\r\n onDecline?: () => void;\r\n width?: \"full\" | \"compact\" | \"auto\";\r\n position?: \"left\" | \"right\" | \"center\";\r\n storageKey?: string;\r\n}\r\n\r\nconst DEFAULT_STORAGE_KEY = \"cookie-consent\";\r\n\r\nexport function CookieConsent({\r\n className,\r\n privacyPolicyUrl = \"/privacy\",\r\n cookiePolicyUrl = \"/cookies\",\r\n onAccept,\r\n onDecline,\r\n width = \"full\",\r\n position = \"center\",\r\n storageKey = DEFAULT_STORAGE_KEY,\r\n}: CookieConsentProps) {\r\n const { t } = useTranslation(\"cookie-consent\");\r\n const [isVisible, setIsVisible] = useState(false);\r\n const [isClosing, setIsClosing] = useState(false);\r\n\r\n useEffect(() => {\r\n const consent = localStorage.getItem(storageKey);\r\n if (!consent) {\r\n // Small delay for better UX\r\n const timer = setTimeout(() => setIsVisible(true), 1000);\r\n return () => clearTimeout(timer);\r\n }\r\n }, [storageKey]);\r\n\r\n const handleAccept = () => {\r\n localStorage.setItem(storageKey, \"accepted\");\r\n setIsClosing(true);\r\n setTimeout(() => {\r\n setIsVisible(false);\r\n onAccept?.();\r\n }, 300);\r\n };\r\n\r\n const handleDecline = () => {\r\n localStorage.setItem(storageKey, \"declined\");\r\n setIsClosing(true);\r\n setTimeout(() => {\r\n setIsVisible(false);\r\n onDecline?.();\r\n }, 300);\r\n };\r\n\r\n const handleClose = () => {\r\n setIsClosing(true);\r\n setTimeout(() => setIsVisible(false), 300);\r\n };\r\n\r\n if (!isVisible) return null;\r\n\r\n return (\r\n <AnimatePresence>\r\n {isVisible && (\r\n <motion.div\r\n initial={{ y: 100, opacity: 0 }}\r\n animate={{ y: isClosing ? 100 : 0, opacity: isClosing ? 0 : 1 }}\r\n exit={{ y: 100, opacity: 0 }}\r\n transition={{ type: \"spring\", damping: 25, stiffness: 300 }}\r\n className={cn(\r\n \"fixed bottom-0 z-50 p-4 md:p-6 left-0 right-0\",\r\n position === \"left\" && \"md:right-auto\",\r\n position === \"right\" && \"md:left-auto\",\r\n className\r\n )}\r\n >\r\n <div className={cn(\r\n \"w-full mx-auto\",\r\n width === \"full\" && \"max-w-[var(--container-max-width)]\",\r\n width === \"compact\" && \"md:max-w-md\",\r\n width === \"auto\" && \"md:w-auto\"\r\n )}>\r\n <div className=\"bg-card border border-border rounded-2xl shadow-2xl p-5 relative\">\r\n {/* Close button */}\r\n <button\r\n onClick={handleClose}\r\n className=\"absolute top-3 right-3 p-1 text-muted-foreground hover:text-foreground transition-colors\"\r\n aria-label={t(\"close\", \"Close\")}\r\n >\r\n <X className=\"h-4 w-4\" />\r\n </button>\r\n\r\n {/* Title & Description */}\r\n <div className=\"mb-4 pr-6\">\r\n <h3 className=\"text-base font-semibold text-foreground mb-1\">\r\n {t(\"title\", \"Cookie Notice\")}\r\n </h3>\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"description\", \"We use cookies to improve your experience.\")}{\" \"}\r\n <Link to={privacyPolicyUrl} className=\"text-primary hover:underline\">\r\n {t(\"privacyPolicy\", \"Privacy\")}\r\n </Link>\r\n {\" · \"}\r\n <Link to={cookiePolicyUrl} className=\"text-primary hover:underline\">\r\n {t(\"cookiePolicy\", \"Cookies\")}\r\n </Link>\r\n </p>\r\n </div>\r\n\r\n {/* Buttons */}\r\n <div className=\"flex flex-row gap-3\">\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={handleDecline}\r\n className=\"flex-1\"\r\n >\r\n {t(\"decline\", \"Decline\")}\r\n </Button>\r\n <Button\r\n size=\"sm\"\r\n onClick={handleAccept}\r\n className=\"flex-1\"\r\n >\r\n {t(\"accept\", \"Accept\")}\r\n </Button>\r\n </div>\r\n </div>\r\n </div>\r\n </motion.div>\r\n )}\r\n </AnimatePresence>\r\n );\r\n}\r\n"
23
+ },
24
+ {
25
+ "path": "cookie-consent/lang/en.json",
26
+ "type": "registry:lang",
27
+ "target": "$modules$/cookie-consent/lang/en.json",
28
+ "content": "{\r\n \"title\": \"Cookie Notice\",\r\n \"description\": \"We use cookies to improve your experience.\",\r\n \"privacyPolicy\": \"Privacy\",\r\n \"cookiePolicy\": \"Cookies\",\r\n \"accept\": \"Accept\",\r\n \"decline\": \"Decline\",\r\n \"close\": \"Close\"\r\n}\r\n"
29
+ },
30
+ {
31
+ "path": "cookie-consent/lang/tr.json",
32
+ "type": "registry:lang",
33
+ "target": "$modules$/cookie-consent/lang/tr.json",
34
+ "content": "{\r\n \"title\": \"Gizliliğinize değer veriyoruz\",\r\n \"description\": \"Göz atma deneyiminizi geliştirmek, kişiselleştirilmiş içerik sunmak ve trafiğimizi analiz etmek için çerezler kullanıyoruz. \\\"Tümünü Kabul Et\\\"e tıklayarak çerez kullanımımıza onay verirsiniz.\",\r\n \"privacyPolicy\": \"Gizlilik Politikası\",\r\n \"cookiePolicy\": \"Çerez Politikası\",\r\n \"accept\": \"Tümünü Kabul Et\",\r\n \"decline\": \"Reddet\",\r\n \"customize\": \"Özelleştir\",\r\n \"close\": \"Kapat\"\r\n}\r\n"
35
+ }
36
+ ],
37
+ "exports": {
38
+ "types": [],
39
+ "variables": [
40
+ "CookieConsent"
41
+ ]
42
+ }
43
+ }
@@ -3,7 +3,9 @@
3
3
  "type": "registry:page",
4
4
  "title": "Cookie Policy Page",
5
5
  "description": "Cookie policy page explaining cookie types (essential, analytics, marketing), purposes, third-party cookies, and user controls. Includes cookie table with name, purpose, and expiration. GDPR/ePrivacy compliant formatting with clear explanations for non-technical users.",
6
- "registryDependencies": [],
6
+ "registryDependencies": [
7
+ "animations"
8
+ ],
7
9
  "usage": "import { CookiesPage } from '@/modules/cookies-page';\n\n<Route path=\"/cookies\" element={<CookiesPage />} />\n\n• Cookie types: essential, analytics, marketing\n• Cookie table with name, purpose, expiration\n• GDPR/ePrivacy compliant",
8
10
  "route": {
9
11
  "path": "/cookies",
@@ -20,7 +22,7 @@
20
22
  "path": "cookies-page/cookies-page.tsx",
21
23
  "type": "registry:page",
22
24
  "target": "$modules$/cookies-page/cookies-page.tsx",
23
- "content": "import { useTranslation } from \"react-i18next\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { Layout } from \"@/components/Layout\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { Cookie, Settings, BarChart, Megaphone, Shield, Info } from \"lucide-react\";\nimport { FadeIn, StaggerContainer, StaggerItem } from \"@/modules/animations\";\n\nexport function CookiesPage() {\n const { t } = useTranslation(\"cookies-page\");\n usePageTitle({ title: t(\"title\") });\n\n const cookieTypes = [\n { icon: Shield, titleKey: \"essentialTitle\", descKey: \"essentialDesc\" },\n { icon: BarChart, titleKey: \"analyticsTitle\", descKey: \"analyticsDesc\" },\n { icon: Settings, titleKey: \"functionalTitle\", descKey: \"functionalDesc\" },\n { icon: Megaphone, titleKey: \"marketingTitle\", descKey: \"marketingDesc\" },\n ];\n\n return (\n <Layout>\n <div className=\"min-h-screen bg-muted/30 py-12\">\n <div className=\"container mx-auto px-4\">\n {/* Header */}\n <FadeIn className=\"text-center mb-12\">\n <div className=\"w-16 h-16 bg-primary/10 rounded-full flex items-center justify-center mx-auto mb-4\">\n <Cookie className=\"w-8 h-8 text-primary\" />\n </div>\n <h1 className=\"text-4xl font-bold text-foreground mb-4\">\n {t(\"title\")}\n </h1>\n <p className=\"text-muted-foreground\">\n {t(\"lastUpdated\")}: {t(\"updateDate\")}\n </p>\n </FadeIn>\n\n {/* Introduction */}\n <FadeIn delay={0.1} className=\"max-w-4xl mx-auto mb-12\">\n <Card>\n <CardContent className=\"p-8\">\n <p className=\"text-muted-foreground leading-relaxed\">\n {t(\"introduction\")}\n </p>\n </CardContent>\n </Card>\n </FadeIn>\n\n {/* What Are Cookies */}\n <FadeIn delay={0.2} className=\"max-w-4xl mx-auto mb-8\">\n <Card>\n <CardContent className=\"p-8\">\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0\">\n <Info className=\"w-5 h-5 text-primary\" />\n </div>\n <div className=\"flex-1\">\n <h2 className=\"text-xl font-semibold mb-3\">{t(\"whatTitle\")}</h2>\n <p className=\"text-muted-foreground\">{t(\"whatContent\")}</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </FadeIn>\n\n {/* Cookie Types */}\n <div className=\"max-w-4xl mx-auto mb-8\">\n <FadeIn className=\"text-center mb-6\">\n <h2 className=\"text-2xl font-semibold\">{t(\"typesTitle\")}</h2>\n </FadeIn>\n <StaggerContainer className=\"grid md:grid-cols-2 gap-6\">\n {cookieTypes.map(({ icon: Icon, titleKey, descKey }) => (\n <StaggerItem key={titleKey}>\n <Card className=\"h-full\">\n <CardContent className=\"p-6\">\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0\">\n <Icon className=\"w-5 h-5 text-primary\" />\n </div>\n <div className=\"flex-1\">\n <h3 className=\"font-semibold mb-2\">{t(titleKey)}</h3>\n <p className=\"text-sm text-muted-foreground\">{t(descKey)}</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </StaggerItem>\n ))}\n </StaggerContainer>\n </div>\n\n {/* Management */}\n <FadeIn className=\"max-w-4xl mx-auto mb-12\">\n <Card>\n <CardContent className=\"p-8\">\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0\">\n <Settings className=\"w-5 h-5 text-primary\" />\n </div>\n <div className=\"flex-1\">\n <h2 className=\"text-xl font-semibold mb-3\">{t(\"managementTitle\")}</h2>\n <p className=\"text-muted-foreground\">{t(\"managementContent\")}</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </FadeIn>\n\n {/* Footer Note */}\n <FadeIn className=\"max-w-4xl mx-auto text-center\">\n <p className=\"text-sm text-muted-foreground\">{t(\"footerNote\")}</p>\n </FadeIn>\n </div>\n </div>\n </Layout>\n );\n}\n\nexport default CookiesPage;\n"
25
+ "content": "import { useTranslation } from \"react-i18next\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { Layout } from \"@/components/Layout\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { Cookie, Settings, BarChart, Megaphone, Shield, Info } from \"lucide-react\";\nimport { FadeIn, StaggerContainer, StaggerItem } from \"@/modules/animations\";\n\nexport function CookiesPage() {\n const { t } = useTranslation(\"cookies-page\");\n usePageTitle({ title: t(\"title\") });\n\n const cookieTypes = [\n { icon: Shield, titleKey: \"essentialTitle\", descKey: \"essentialDesc\" },\n { icon: BarChart, titleKey: \"analyticsTitle\", descKey: \"analyticsDesc\" },\n { icon: Settings, titleKey: \"functionalTitle\", descKey: \"functionalDesc\" },\n { icon: Megaphone, titleKey: \"marketingTitle\", descKey: \"marketingDesc\" },\n ];\n\n return (\n <Layout>\n <div className=\"min-h-screen bg-muted/30 py-12\">\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\n {/* Header */}\n <FadeIn className=\"text-center mb-12\">\n <div className=\"w-16 h-16 bg-primary/10 rounded-full flex items-center justify-center mx-auto mb-4\">\n <Cookie className=\"w-8 h-8 text-primary\" />\n </div>\n <h1 className=\"text-4xl font-bold text-foreground mb-4\">\n {t(\"title\")}\n </h1>\n <p className=\"text-muted-foreground\">\n {t(\"lastUpdated\")}: {t(\"updateDate\")}\n </p>\n </FadeIn>\n\n {/* Introduction */}\n <FadeIn delay={0.1} className=\"max-w-4xl mx-auto mb-12\">\n <Card>\n <CardContent className=\"p-8\">\n <p className=\"text-muted-foreground leading-relaxed\">\n {t(\"introduction\")}\n </p>\n </CardContent>\n </Card>\n </FadeIn>\n\n {/* What Are Cookies */}\n <FadeIn delay={0.2} className=\"max-w-4xl mx-auto mb-8\">\n <Card>\n <CardContent className=\"p-8\">\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0\">\n <Info className=\"w-5 h-5 text-primary\" />\n </div>\n <div className=\"flex-1\">\n <h2 className=\"text-xl font-semibold mb-3\">{t(\"whatTitle\")}</h2>\n <p className=\"text-muted-foreground\">{t(\"whatContent\")}</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </FadeIn>\n\n {/* Cookie Types */}\n <div className=\"max-w-4xl mx-auto mb-8\">\n <FadeIn className=\"text-center mb-6\">\n <h2 className=\"text-2xl font-semibold\">{t(\"typesTitle\")}</h2>\n </FadeIn>\n <StaggerContainer className=\"grid md:grid-cols-2 gap-6\">\n {cookieTypes.map(({ icon: Icon, titleKey, descKey }) => (\n <StaggerItem key={titleKey}>\n <Card className=\"h-full\">\n <CardContent className=\"p-6\">\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0\">\n <Icon className=\"w-5 h-5 text-primary\" />\n </div>\n <div className=\"flex-1\">\n <h3 className=\"font-semibold mb-2\">{t(titleKey)}</h3>\n <p className=\"text-sm text-muted-foreground\">{t(descKey)}</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </StaggerItem>\n ))}\n </StaggerContainer>\n </div>\n\n {/* Management */}\n <FadeIn className=\"max-w-4xl mx-auto mb-12\">\n <Card>\n <CardContent className=\"p-8\">\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0\">\n <Settings className=\"w-5 h-5 text-primary\" />\n </div>\n <div className=\"flex-1\">\n <h2 className=\"text-xl font-semibold mb-3\">{t(\"managementTitle\")}</h2>\n <p className=\"text-muted-foreground\">{t(\"managementContent\")}</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </FadeIn>\n\n {/* Footer Note */}\n <FadeIn className=\"max-w-4xl mx-auto text-center\">\n <p className=\"text-sm text-muted-foreground\">{t(\"footerNote\")}</p>\n </FadeIn>\n </div>\n </div>\n </Layout>\n );\n}\n\nexport default CookiesPage;\n"
24
26
  },
25
27
  {
26
28
  "path": "cookies-page/lang/en.json",
@@ -16,13 +16,13 @@
16
16
  "path": "cta-section/cta-section.tsx",
17
17
  "type": "registry:component",
18
18
  "target": "$modules$/cta-section/cta-section.tsx",
19
- "content": "import { Link } from \"react-router\";\nimport { Button } from \"@/components/ui/button\";\nimport { useTranslation } from \"react-i18next\";\n\nexport function CtaSection() {\n const { t } = useTranslation(\"cta-section\");\n\n return (\n <section className=\"py-20 bg-primary text-primary-foreground\">\n <div className=\"container mx-auto px-4 text-center\">\n <h2 className=\"text-3xl lg:text-4xl font-bold mb-6\">\n {t(\"title\", \"Ready to Start Your Project?\")}\n </h2>\n <p className=\"text-xl opacity-90 max-w-2xl mx-auto mb-8\">\n {t(\n \"description\",\n \"Let's discuss your needs and create a solution that drives results for your business.\"\n )}\n </p>\n <div className=\"flex flex-col sm:flex-row gap-4 justify-center\">\n <Button\n size=\"lg\"\n variant=\"secondary\"\n className=\"px-8 py-3 text-lg\"\n asChild\n >\n <Link to=\"/contact\">{t(\"primaryButton\", \"Get Free Quote\")}</Link>\n </Button>\n <Button\n size=\"lg\"\n variant=\"outline\"\n className=\"px-8 py-3 text-lg border-primary-foreground text-primary-foreground bg-transparent hover:bg-primary-foreground hover:text-primary transition-all duration-300\"\n asChild\n >\n <Link to=\"/about\" className=\"text-primary-foreground hover:text-primary\">\n {t(\"secondaryButton\", \"Learn About Us\")}\n </Link>\n </Button>\n </div>\n </div>\n </section>\n );\n}\n"
19
+ "content": "import { Link } from \"react-router\";\nimport { Button } from \"@/components/ui/button\";\nimport { useTranslation } from \"react-i18next\";\n\nexport function CtaSection() {\n const { t } = useTranslation(\"cta-section\");\n\n return (\n <section className=\"py-20 bg-primary text-primary-foreground\">\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4 text-center\">\n <h2 className=\"text-3xl lg:text-4xl font-bold mb-6\">\n {t(\"title\", \"Ready to Start Your Project?\")}\n </h2>\n <p className=\"text-xl opacity-90 max-w-2xl mx-auto mb-8\">\n {t(\n \"description\",\n \"Let's discuss your needs and create a solution that drives results for your business.\"\n )}\n </p>\n <div className=\"flex flex-col sm:flex-row gap-4 justify-center\">\n <Button\n size=\"lg\"\n variant=\"secondary\"\n className=\"px-8 py-3 text-lg\"\n asChild\n >\n <Link to=\"/contact\">{t(\"primaryButton\", \"Get Free Quote\")}</Link>\n </Button>\n <Button\n size=\"lg\"\n variant=\"outline\"\n className=\"px-8 py-3 text-lg border-primary-foreground text-primary-foreground bg-transparent hover:bg-primary-foreground hover:text-primary transition-all duration-300\"\n asChild\n >\n <Link to=\"/about\" className=\"text-primary-foreground hover:text-primary\">\n {t(\"secondaryButton\", \"Learn About Us\")}\n </Link>\n </Button>\n </div>\n </div>\n </section>\n );\n}\n"
20
20
  },
21
21
  {
22
22
  "path": "cta-section/lang/en.json",
23
23
  "type": "registry:lang",
24
24
  "target": "$modules$/cta-section/lang/en.json",
25
- "content": "{\r\n \"title\": \"Ready to Start Your Project?\",\r\n \"description\": \"AI will customize this CTA description based on your site goals. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\",\r\n \"primaryButton\": \"Get Free Quote\",\r\n \"secondaryButton\": \"Learn About Us\"\r\n}\r\n"
25
+ "content": "{\r\n \"title\": \"Ready to Start Your Project?\",\r\n \"description\": \"Ask Promake to customize this CTA description based on your site goals. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\",\r\n \"primaryButton\": \"Get Free Quote\",\r\n \"secondaryButton\": \"Learn About Us\"\r\n}\r\n"
26
26
  },
27
27
  {
28
28
  "path": "cta-section/lang/tr.json",
@@ -0,0 +1,129 @@
1
+ {
2
+ "name": "db",
3
+ "type": "registry:module",
4
+ "title": "Database Module",
5
+ "description": "Universal data management with adapter pattern and React Query integration. Includes SQLite adapter for client-side persistence, DataManager for CRUD operations, and useRepository hook for React components. Supports complex queries, pagination, joins, and type-safe operations.",
6
+ "dependencies": [
7
+ "sql.js",
8
+ "@tanstack/react-query"
9
+ ],
10
+ "registryDependencies": [],
11
+ "files": [
12
+ {
13
+ "path": "db/index.ts",
14
+ "type": "registry:index",
15
+ "target": "$modules$/db/index.ts",
16
+ "content": "/**\n * DB Module\n * Universal data management with adapter pattern + React Query\n */\n\n// Core\nexport { DataManager } from \"./core/DataManager\";\nexport type {\n QueryOptions,\n OrderBy,\n PaginatedResult,\n // Complex query types\n WhereOperator,\n WhereCondition,\n WhereGroup,\n JoinType,\n JoinClause,\n} from \"./core/types\";\n\n// Adapters\nexport type { IDataAdapter } from \"./adapters/IDataAdapter\";\nexport { SqliteAdapter } from \"./adapters/SqliteAdapter\";\n\n// Config\nexport { getAdapter, createAdapter, resetAdapter } from \"./config\";\nexport type { DataConfig, AdapterType } from \"./config\";\n\n// React exports (re-export from react/index.ts)\nexport * from \"./react\";\n\n// Re-export for convenience\nexport { DBQueryProvider as QueryProvider } from \"./react\";\n\n// Utility exports (parsers for client-side data transformation)\nexport {\n parseCommaSeparatedString,\n parseJSONStringToArray,\n parseStringToArray,\n parseJSONString,\n parseSQLiteBoolean,\n parseNumberSafe,\n} from \"./utils/parsers\";\n"
17
+ },
18
+ {
19
+ "path": "db/config.ts",
20
+ "type": "registry:lib",
21
+ "target": "$modules$/db/config.ts",
22
+ "content": "import type { IDataAdapter } from \"./adapters/IDataAdapter\";\nimport { SqliteAdapter } from \"./adapters/SqliteAdapter\";\n\nexport type AdapterType = \"sqlite\";\n\nexport interface DataConfig {\n adapter: AdapterType;\n options?: {\n dbPath?: string;\n };\n}\n\n/**\n * Get configuration from environment variables\n */\nfunction getConfig(): DataConfig {\n const adapter =\n (import.meta.env.VITE_DATA_ADAPTER as AdapterType) || \"sqlite\";\n\n return {\n adapter,\n options: {\n dbPath: import.meta.env.VITE_DB_PATH || \"/data/database.db\",\n },\n };\n}\n\n/**\n * Create adapter instance based on configuration\n */\nexport function createAdapter(config: DataConfig): IDataAdapter {\n switch (config.adapter) {\n case \"sqlite\":\n return new SqliteAdapter(config.options?.dbPath);\n\n default:\n throw new Error(`Unknown adapter: ${config.adapter}`);\n }\n}\n\n/**\n * Get the configured adapter instance (singleton)\n */\nlet adapterInstance: IDataAdapter | null = null;\n\nexport function getAdapter(): IDataAdapter {\n if (!adapterInstance) {\n const config = getConfig();\n adapterInstance = createAdapter(config);\n }\n return adapterInstance;\n}\n\n/**\n * Reset adapter instance (useful for testing or switching adapters)\n */\nexport function resetAdapter(): void {\n adapterInstance = null;\n}\n"
23
+ },
24
+ {
25
+ "path": "db/core/DataManager.ts",
26
+ "type": "registry:lib",
27
+ "target": "$modules$/db/core/DataManager.ts",
28
+ "content": "import type { IDataAdapter } from \"../adapters/IDataAdapter\";\nimport type { QueryOptions, PaginatedResult } from \"./types\";\n\n/**\n * DataManager - Simple proxy to adapter\n */\nexport class DataManager {\n private static instance: DataManager;\n private adapter: IDataAdapter;\n\n private constructor(adapter: IDataAdapter) {\n this.adapter = adapter;\n }\n\n static getInstance(adapter: IDataAdapter): DataManager {\n if (!DataManager.instance) {\n DataManager.instance = new DataManager(adapter);\n }\n return DataManager.instance;\n }\n\n // Simple pass-through methods - no cache logic\n async query<T = any>(table: string, options?: QueryOptions): Promise<T[]> {\n return this.adapter.findMany<T>(table, options);\n }\n\n async queryOne<T = any>(\n table: string,\n options?: QueryOptions,\n ): Promise<T | null> {\n const results = await this.query<T>(table, { ...options, limit: 1 });\n return results[0] || null;\n }\n\n async queryById<T = any>(\n table: string,\n id: number | string,\n ): Promise<T | null> {\n return this.adapter.findById<T>(table, id);\n }\n\n async count(table: string, options?: QueryOptions): Promise<number> {\n return this.adapter.count(table, options);\n }\n\n async paginate<T = any>(\n table: string,\n page: number = 1,\n limit: number = 10,\n options?: QueryOptions,\n ): Promise<PaginatedResult<T>> {\n const offset = (page - 1) * limit;\n\n const [data, total] = await Promise.all([\n this.query<T>(table, { ...options, limit, offset }),\n this.count(table, options),\n ]);\n\n return {\n data,\n page,\n limit,\n total,\n totalPages: Math.ceil(total / limit),\n hasMore: page * limit < total,\n };\n }\n\n // Mutations - no cache invalidation here (React Query handles it)\n async create<T = any>(table: string, data: Partial<T>): Promise<T> {\n return this.adapter.create<T>(table, data);\n }\n\n async update<T = any>(\n table: string,\n id: number | string,\n data: Partial<T>,\n ): Promise<T> {\n return this.adapter.update<T>(table, id, data);\n }\n\n async delete(table: string, id: number | string): Promise<boolean> {\n return this.adapter.delete(table, id);\n }\n\n // Direct adapter access for advanced use cases\n getAdapter(): IDataAdapter {\n return this.adapter;\n }\n\n // ============================================\n // RAW SQL QUERIES\n // ============================================\n\n /**\n * Execute raw SQL query - returns multiple rows\n * Use for complex queries that can't be expressed with QueryOptions\n *\n * @example\n * const posts = await dm.raw<Post>(`\n * SELECT DISTINCT p.*, c.name as category_name\n * FROM posts p\n * JOIN post_categories pc ON p.id = pc.post_id\n * JOIN blog_categories c ON pc.category_id = c.id\n * WHERE c.slug = ? AND p.published = 1\n * `, [categorySlug]);\n */\n async raw<T = any>(sql: string, params?: any[]): Promise<T[]> {\n return this.adapter.raw<T>(sql, params);\n }\n\n /**\n * Execute raw SQL query - returns single row or null\n * Use for aggregations, single record lookups\n *\n * @example\n * const priceRange = await dm.rawOne<{min: number, max: number}>(`\n * SELECT MIN(price) as min, MAX(price) as max\n * FROM products WHERE published = 1\n * `);\n */\n async rawOne<T = any>(sql: string, params?: any[]): Promise<T | null> {\n return this.adapter.rawOne<T>(sql, params);\n }\n}\n"
29
+ },
30
+ {
31
+ "path": "db/core/types.ts",
32
+ "type": "registry:type",
33
+ "target": "$modules$/db/core/types.ts",
34
+ "content": "/**\n * Core type definitions for data-access module\n */\n\n// ============================================\n// WHERE CONDITIONS\n// ============================================\n\n/** WHERE condition operators */\nexport type WhereOperator =\n | \"=\"\n | \"!=\"\n | \"<>\"\n | \">\"\n | \"<\"\n | \">=\"\n | \"<=\"\n | \"LIKE\"\n | \"NOT LIKE\"\n | \"IN\"\n | \"NOT IN\"\n | \"BETWEEN\"\n | \"NOT BETWEEN\"\n | \"IS NULL\"\n | \"IS NOT NULL\";\n\n/** Single WHERE condition */\nexport interface WhereCondition {\n field: string;\n operator: WhereOperator;\n value: any;\n}\n\n/** WHERE groups (AND/OR) - recursive structure */\nexport interface WhereGroup {\n type: \"AND\" | \"OR\";\n conditions: (WhereCondition | WhereGroup)[];\n}\n\n// ============================================\n// JOIN DEFINITIONS\n// ============================================\n\n/** JOIN types */\nexport type JoinType = \"INNER\" | \"LEFT\" | \"RIGHT\" | \"CROSS\";\n\n/** JOIN definition */\nexport interface JoinClause {\n type: JoinType;\n table: string;\n alias?: string;\n on: {\n leftField: string;\n rightField: string;\n };\n}\n\n// ============================================\n// QUERY OPTIONS\n// ============================================\n\n/** Order definition */\nexport interface OrderBy {\n field: string;\n direction: \"ASC\" | \"DESC\";\n}\n\n/** Extended Query Options */\nexport interface QueryOptions {\n // Existing (backwards compatible)\n where?: Record<string, any>;\n limit?: number;\n offset?: number;\n orderBy?: OrderBy[];\n include?: string[];\n\n // New features\n select?: string[]; // SELECT fields: ['p.*', 'c.name as category_name']\n distinct?: boolean; // DISTINCT usage\n joins?: JoinClause[]; // JOIN definitions\n whereAdvanced?: WhereGroup; // Complex WHERE conditions (AND/OR groups)\n groupBy?: string[]; // GROUP BY fields\n having?: WhereGroup; // HAVING conditions\n}\n\n// ============================================\n// RESULT TYPES\n// ============================================\n\n/** Paginated result */\nexport interface PaginatedResult<T> {\n data: T[];\n page: number;\n limit: number;\n total: number;\n totalPages: number;\n hasMore: boolean;\n}\n\n/** Query key (for cache) */\nexport type QueryKey = (string | number | object)[];\n"
35
+ },
36
+ {
37
+ "path": "db/adapters/IDataAdapter.ts",
38
+ "type": "registry:type",
39
+ "target": "$modules$/db/adapters/IDataAdapter.ts",
40
+ "content": "import type { QueryOptions } from \"../core/types\";\n\n/**\n * Data Adapter Interface\n * Implement this interface to create custom data sources\n */\nexport interface IDataAdapter {\n // Connection\n connect(): Promise<void>;\n disconnect(): Promise<void>;\n\n // CRUD operations\n findMany<T>(table: string, options?: QueryOptions): Promise<T[]>;\n findOne<T>(table: string, options: QueryOptions): Promise<T | null>;\n findById<T>(table: string, id: number | string): Promise<T | null>;\n create<T>(table: string, data: Partial<T>): Promise<T>;\n update<T>(table: string, id: number | string, data: Partial<T>): Promise<T>;\n delete(table: string, id: number | string): Promise<boolean>;\n\n // Utilities\n count(table: string, options?: QueryOptions): Promise<number>;\n\n // Raw SQL queries - for complex queries that can't be expressed with QueryOptions\n raw<T>(sql: string, params?: any[]): Promise<T[]>;\n rawOne<T>(sql: string, params?: any[]): Promise<T | null>;\n}\n"
41
+ },
42
+ {
43
+ "path": "db/adapters/index.ts",
44
+ "type": "registry:index",
45
+ "target": "$modules$/db/adapters/index.ts",
46
+ "content": "export type { IDataAdapter } from \"./IDataAdapter\";\nexport { SqliteAdapter } from \"./SqliteAdapter\";\n"
47
+ },
48
+ {
49
+ "path": "db/adapters/SqliteAdapter.ts",
50
+ "type": "registry:lib",
51
+ "target": "$modules$/db/adapters/SqliteAdapter.ts",
52
+ "content": "import initSqlJs from \"sql.js\";\nimport type { Database } from \"sql.js\";\nimport type { IDataAdapter } from \"./IDataAdapter\";\nimport type {\n QueryOptions,\n WhereCondition,\n WhereGroup,\n JoinClause,\n} from \"../core/types\";\n\n/**\n * SQLite Adapter\n * Loads database from file using sql.js\n * Supports complex queries: JOIN, WHERE groups, LIKE, IN, BETWEEN\n */\nexport class SqliteAdapter implements IDataAdapter {\n private db: Database | null = null;\n private dbPath: string;\n\n constructor(dbPath: string = \"/data/database.db\") {\n this.dbPath = dbPath;\n }\n\n // ============================================\n // CONNECTION\n // ============================================\n\n async connect(): Promise<void> {\n if (this.db) return;\n\n try {\n const SQL = await initSqlJs({\n locateFile: (file: string) => `https://sql.js.org/dist/${file}`,\n });\n\n const response = await fetch(this.dbPath);\n if (!response.ok) {\n throw new Error(`Database file not found: ${this.dbPath}`);\n }\n\n const buffer = await response.arrayBuffer();\n this.db = new SQL.Database(new Uint8Array(buffer));\n console.log(\"SQLite adapter connected\");\n } catch (error) {\n console.error(\"SQLite adapter connection failed:\", error);\n throw error;\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n\n // ============================================\n // CRUD OPERATIONS\n // ============================================\n\n async findMany<T>(table: string, options?: QueryOptions): Promise<T[]> {\n await this.connect();\n if (!this.db) {\n console.warn(\"Database not connected\");\n return [];\n }\n try {\n const { sql, params } = this.buildSelectQuery(table, options);\n return this.executeQuery<T>(sql, params);\n } catch (error) {\n console.error(`Error querying table ${table}:`, error);\n return [];\n }\n }\n\n async findOne<T>(table: string, options: QueryOptions): Promise<T | null> {\n const results = await this.findMany<T>(table, { ...options, limit: 1 });\n return results[0] || null;\n }\n\n async findById<T>(table: string, id: number | string): Promise<T | null> {\n return this.findOne<T>(table, { where: { id } });\n }\n\n async create<T>(table: string, data: Partial<T>): Promise<T> {\n await this.connect();\n\n // Otomatik timestamp - sadece yoksa ekle\n const dataWithTimestamps: any = { ...data };\n\n if (!dataWithTimestamps.created_at) {\n dataWithTimestamps.created_at = new Date().toISOString();\n }\n\n if (!dataWithTimestamps.updated_at) {\n dataWithTimestamps.updated_at = new Date().toISOString();\n }\n\n const keys = Object.keys(dataWithTimestamps);\n const values = Object.values(dataWithTimestamps) as any[];\n const placeholders = keys.map(() => \"?\").join(\", \");\n\n const sql = `INSERT INTO ${table} (${keys.join(\", \")}) VALUES (${placeholders})`;\n this.db!.run(sql, values);\n\n const lastIdResult = this.db!.exec(\"SELECT last_insert_rowid() as id\");\n const lastId = lastIdResult[0]?.values[0]?.[0] as number;\n\n return this.findById<T>(table, lastId) as Promise<T>;\n }\n\n async update<T>(\n table: string,\n id: number | string,\n data: Partial<T>,\n ): Promise<T> {\n await this.connect();\n\n // Otomatik updated_at - her zaman güncelle\n const dataWithTimestamp = {\n ...data,\n updated_at: new Date().toISOString(),\n };\n\n const keys = Object.keys(dataWithTimestamp);\n const values = Object.values(dataWithTimestamp) as any[];\n const setClause = keys.map((key) => `${key} = ?`).join(\", \");\n\n const sql = `UPDATE ${table} SET ${setClause} WHERE id = ?`;\n this.db!.run(sql, [...values, id]);\n\n return this.findById<T>(table, id) as Promise<T>;\n }\n\n async delete(table: string, id: number | string): Promise<boolean> {\n await this.connect();\n const sql = `DELETE FROM ${table} WHERE id = ?`;\n this.db!.run(sql, [id]);\n return true;\n }\n\n async count(table: string, options?: QueryOptions): Promise<number> {\n await this.connect();\n const { sql, params } = this.buildCountQuery(table, options);\n const results = await this.executeQuery<{ count: number }>(sql, params);\n return results[0]?.count || 0;\n }\n\n // ============================================\n // RAW SQL QUERIES\n // ============================================\n\n async raw<T>(sql: string, params?: any[]): Promise<T[]> {\n await this.connect();\n return this.executeQuery<T>(sql, params);\n }\n\n async rawOne<T>(sql: string, params?: any[]): Promise<T | null> {\n const results = await this.raw<T>(sql, params);\n return results[0] || null;\n }\n\n // ============================================\n // PRIVATE: QUERY EXECUTION\n // ============================================\n\n private async executeQuery<T>(sql: string, params?: any[]): Promise<T[]> {\n if (!this.db) {\n console.warn(\"Database not connected\");\n return [];\n }\n try {\n const stmt = this.db.prepare(sql);\n if (params && params.length > 0) stmt.bind(params);\n\n const results: T[] = [];\n while (stmt.step()) {\n results.push(stmt.getAsObject() as T);\n }\n stmt.free();\n return results;\n } catch (error) {\n console.error(`Query error: ${sql}`, error);\n return [];\n }\n }\n\n // ============================================\n // PRIVATE: QUERY BUILDERS\n // ============================================\n\n private buildSelectQuery(\n table: string,\n options?: QueryOptions,\n ): { sql: string; params: any[] } {\n const params: any[] = [];\n\n // SELECT clause\n const selectFields = options?.select?.join(\", \") || \"*\";\n const distinct = options?.distinct ? \"DISTINCT \" : \"\";\n let sql = `SELECT ${distinct}${selectFields} FROM ${table}`;\n\n // JOIN clauses\n if (options?.joins && options.joins.length > 0) {\n sql += this.buildJoinClause(options.joins);\n }\n\n // WHERE clause\n const whereClause = this.buildWhereClause(options, params);\n if (whereClause) {\n sql += ` WHERE ${whereClause}`;\n }\n\n // GROUP BY clause\n if (options?.groupBy && options.groupBy.length > 0) {\n sql += ` GROUP BY ${options.groupBy.join(\", \")}`;\n }\n\n // HAVING clause\n if (options?.having) {\n const havingClause = this.buildWhereGroupClause(options.having, params);\n if (havingClause) {\n sql += ` HAVING ${havingClause}`;\n }\n }\n\n // ORDER BY clause\n if (options?.orderBy && options.orderBy.length > 0) {\n const orderClauses = options.orderBy.map(\n (o) => `${o.field} ${o.direction}`,\n );\n sql += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n // LIMIT & OFFSET\n if (options?.limit) {\n sql += ` LIMIT ?`;\n params.push(options.limit);\n }\n\n if (options?.offset) {\n sql += ` OFFSET ?`;\n params.push(options.offset);\n }\n\n return { sql, params };\n }\n\n private buildCountQuery(\n table: string,\n options?: QueryOptions,\n ): { sql: string; params: any[] } {\n const params: any[] = [];\n let sql = `SELECT COUNT(*) as count FROM ${table}`;\n\n // JOIN clauses\n if (options?.joins && options.joins.length > 0) {\n sql += this.buildJoinClause(options.joins);\n }\n\n // WHERE clause\n const whereClause = this.buildWhereClause(options, params);\n if (whereClause) {\n sql += ` WHERE ${whereClause}`;\n }\n\n return { sql, params };\n }\n\n private buildJoinClause(joins: JoinClause[]): string {\n return joins\n .map((join) => {\n const alias = join.alias ? ` ${join.alias}` : \"\";\n const leftField = join.on.leftField;\n const rightField = join.on.rightField;\n return ` ${join.type} JOIN ${join.table}${alias} ON ${leftField} = ${rightField}`;\n })\n .join(\"\");\n }\n\n private buildWhereClause(\n options: QueryOptions | undefined,\n params: any[],\n ): string {\n const clauses: string[] = [];\n\n // Simple where (backwards compatible)\n if (options?.where) {\n const simpleConditions = Object.entries(options.where).map(\n ([key, value]) => {\n params.push(value);\n return `${key} = ?`;\n },\n );\n if (simpleConditions.length > 0) {\n clauses.push(simpleConditions.join(\" AND \"));\n }\n }\n\n // Advanced where (new feature)\n if (options?.whereAdvanced) {\n const advancedClause = this.buildWhereGroupClause(\n options.whereAdvanced,\n params,\n );\n if (advancedClause) {\n clauses.push(advancedClause);\n }\n }\n\n return clauses.length > 0 ? clauses.join(\" AND \") : \"\";\n }\n\n private buildWhereGroupClause(group: WhereGroup, params: any[]): string {\n const conditions = group.conditions\n .map((condition) => {\n // Recursive: WhereGroup\n if (\"type\" in condition && \"conditions\" in condition) {\n return `(${this.buildWhereGroupClause(condition as WhereGroup, params)})`;\n }\n // WhereCondition\n return this.buildConditionClause(condition as WhereCondition, params);\n })\n .filter(Boolean);\n\n return conditions.join(` ${group.type} `);\n }\n\n private buildConditionClause(\n condition: WhereCondition,\n params: any[],\n ): string {\n const { field, operator, value } = condition;\n\n switch (operator) {\n case \"IS NULL\":\n return `${field} IS NULL`;\n\n case \"IS NOT NULL\":\n return `${field} IS NOT NULL`;\n\n case \"IN\":\n case \"NOT IN\":\n if (Array.isArray(value)) {\n const placeholders = value.map(() => \"?\").join(\", \");\n params.push(...value);\n return `${field} ${operator} (${placeholders})`;\n }\n return \"\";\n\n case \"BETWEEN\":\n case \"NOT BETWEEN\":\n if (Array.isArray(value) && value.length === 2) {\n params.push(value[0], value[1]);\n return `${field} ${operator} ? AND ?`;\n }\n return \"\";\n\n default:\n // =, !=, <>, >, <, >=, <=, LIKE, NOT LIKE\n params.push(value);\n return `${field} ${operator} ?`;\n }\n }\n}\n"
53
+ },
54
+ {
55
+ "path": "db/react/index.ts",
56
+ "type": "registry:index",
57
+ "target": "$modules$/db/react/index.ts",
58
+ "content": "// Provider\nexport { DBQueryProvider } from \"./QueryProvider\";\n\n// Query client and utilities\nexport { queryClient, queryKeys, cacheUtils } from \"./queryClient\";\n\n// Generic repository hooks\nexport {\n useRepositoryQuery,\n useRepositoryQueryOne,\n useRepositoryQueryById,\n useRepositoryPagination,\n useRepositoryInfiniteQuery,\n useRepositoryCreate,\n useRepositoryUpdate,\n useRepositoryDelete,\n // Raw SQL hooks\n useRawQuery,\n useRawQueryOne,\n} from \"./useRepository\";\n\n// Types\nexport type { RepositoryQueryOptions } from \"./useRepository\";\n"
59
+ },
60
+ {
61
+ "path": "db/react/queryClient.ts",
62
+ "type": "registry:lib",
63
+ "target": "$modules$/db/react/queryClient.ts",
64
+ "content": "import { QueryClient } from \"@tanstack/react-query\";\n\n/**\n * React Query handles ALL caching, refetching, and invalidation\n * No custom cache needed!\n */\nexport const queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 30 * 1000, // 30 seconds fresh\n gcTime: 5 * 60 * 1000, // 5 minutes in cache (was cacheTime)\n retry: 1,\n refetchOnWindowFocus: false, // Don't auto-refetch on window focus\n refetchOnReconnect: false, // Don't refetch on reconnect\n refetchOnMount: false, // Don't refetch on component mount (prevent loops)\n },\n mutations: {\n retry: 0,\n },\n },\n});\n\n/**\n * Query key factory - for cache management\n * React Query uses these keys to cache and invalidate queries\n */\nexport const queryKeys = {\n all: (table: string) => [table] as const,\n lists: (table: string) => [table, \"list\"] as const,\n list: (table: string, options?: any) => [table, \"list\", options] as const,\n details: (table: string) => [table, \"detail\"] as const,\n detail: (table: string, id: number | string) =>\n [table, \"detail\", id] as const,\n paginated: (table: string, page: number, limit: number, options?: any) =>\n [table, \"paginated\", page, limit, options] as const,\n infinite: (table: string, limit: number, options?: any) =>\n [table, \"infinite\", limit, options] as const,\n count: (table: string, options?: any) => [table, \"count\", options] as const,\n};\n\n/**\n * Manual cache utilities (rarely needed)\n */\nexport const cacheUtils = {\n // Invalidate all queries for a table\n invalidateTable: (table: string) => {\n return queryClient.invalidateQueries({ queryKey: queryKeys.all(table) });\n },\n\n // Clear all cache\n clearAll: () => {\n return queryClient.clear();\n },\n\n // Get cached data\n getCachedData: <T>(queryKey: any[]) => {\n return queryClient.getQueryData<T>(queryKey);\n },\n\n // Set cached data manually\n setCachedData: <T>(queryKey: any[], data: T) => {\n return queryClient.setQueryData<T>(queryKey, data);\n },\n};\n"
65
+ },
66
+ {
67
+ "path": "db/react/QueryProvider.tsx",
68
+ "type": "registry:component",
69
+ "target": "$modules$/db/react/QueryProvider.tsx",
70
+ "content": "import { QueryClientProvider } from \"@tanstack/react-query\";\nimport { queryClient } from \"./queryClient\";\n\ninterface DBQueryProviderProps {\n children: React.ReactNode;\n}\n\n/**\n * DBQueryProvider - DB module's React Query provider\n * Wraps components that use db module hooks\n */\nexport function DBQueryProvider({ children }: DBQueryProviderProps) {\n return (\n <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>\n );\n}\n"
71
+ },
72
+ {
73
+ "path": "db/react/useRepository.ts",
74
+ "type": "registry:hook",
75
+ "target": "$modules$/db/react/useRepository.ts",
76
+ "content": "import {\n useQuery,\n useMutation,\n useQueryClient,\n useInfiniteQuery,\n type UseQueryOptions,\n type UseMutationOptions,\n type UseInfiniteQueryOptions,\n} from \"@tanstack/react-query\";\nimport { DataManager } from \"../core/DataManager\";\nimport { getAdapter } from \"../config\";\nimport { queryKeys } from \"./queryClient\";\nimport type { QueryOptions } from \"../core/types\";\n\n// Singleton manager\nlet managerInstance: DataManager | null = null;\nfunction getManager() {\n if (!managerInstance) {\n managerInstance = DataManager.getInstance(getAdapter());\n }\n return managerInstance;\n}\n\n// ==========================================\n// QUERY HOOKS\n// ==========================================\n\n// Omit 'select' from QueryOptions to avoid conflict with React Query's select\nexport interface RepositoryQueryOptions<T> extends Omit<\n QueryOptions,\n \"select\"\n> {\n // SQL SELECT fields (renamed to avoid conflict)\n selectFields?: string[];\n\n // React Query options\n enabled?: boolean;\n staleTime?: number;\n gcTime?: number;\n refetchOnWindowFocus?: boolean;\n refetchInterval?: number | false;\n select?: (data: T[]) => any; // React Query data transformation\n}\n\n/**\n * Generic query hook - React Query handles all caching\n * @example\n * // Simple query\n * const { data: posts, isLoading } = useRepositoryQuery('posts', {\n * where: { published: 1 },\n * orderBy: [{ field: 'created_at', direction: 'DESC' }],\n * staleTime: 60000\n * });\n *\n * // With JOIN\n * const { data: posts } = useRepositoryQuery('posts', {\n * selectFields: ['posts.*', 'c.name as category_name'],\n * joins: [{\n * type: 'INNER',\n * table: 'post_categories',\n * alias: 'pc',\n * on: { leftField: 'posts.id', rightField: 'pc.post_id' }\n * }],\n * distinct: true\n * });\n *\n * // With complex WHERE\n * const { data: products } = useRepositoryQuery('products', {\n * whereAdvanced: {\n * type: 'AND',\n * conditions: [\n * { field: 'published', operator: '=', value: 1 },\n * { type: 'OR', conditions: [\n * { field: 'name', operator: 'LIKE', value: '%phone%' },\n * { field: 'description', operator: 'LIKE', value: '%phone%' }\n * ]}\n * ]\n * }\n * });\n */\nexport function useRepositoryQuery<T = any>(\n table: string,\n options: RepositoryQueryOptions<T> = {},\n queryOptions?: Omit<UseQueryOptions<T[], Error>, \"queryKey\" | \"queryFn\">,\n) {\n const manager = getManager();\n const {\n // QueryOptions fields\n where,\n limit,\n offset,\n orderBy,\n include,\n // New complex query fields\n selectFields,\n distinct,\n joins,\n whereAdvanced,\n groupBy,\n having,\n // React Query options\n select,\n enabled,\n staleTime,\n gcTime,\n refetchOnWindowFocus,\n refetchInterval,\n } = options;\n\n const queryOpts: QueryOptions = {\n where,\n limit,\n offset,\n orderBy,\n include,\n select: selectFields,\n distinct,\n joins,\n whereAdvanced,\n groupBy,\n having,\n };\n\n return useQuery<T[], Error>({\n queryKey: queryKeys.list(table, queryOpts),\n queryFn: () => manager.query<T>(table, queryOpts),\n select,\n enabled,\n staleTime,\n gcTime,\n refetchOnWindowFocus,\n refetchInterval,\n ...queryOptions,\n });\n}\n\n/**\n * Query single record\n * @example\n * const { data: post } = useRepositoryQueryOne('posts', {\n * where: { slug: 'my-post' }\n * });\n */\nexport function useRepositoryQueryOne<T = any>(\n table: string,\n options: RepositoryQueryOptions<T> = {},\n) {\n const result = useRepositoryQuery<T>(table, { ...options, limit: 1 });\n\n return {\n ...result,\n data: result.data?.[0] || null,\n };\n}\n\n/**\n * Query by ID - React Query caches by ID automatically\n * @example\n * const { data: post, isLoading } = useRepositoryQueryById('posts', postId);\n */\nexport function useRepositoryQueryById<T = any>(\n table: string,\n id: number | string | null | undefined,\n options: Omit<UseQueryOptions<T | null, Error>, \"queryKey\" | \"queryFn\"> = {},\n) {\n const manager = getManager();\n\n return useQuery<T | null, Error>({\n queryKey: queryKeys.detail(table, id as any),\n queryFn: () => manager.queryById<T>(table, id as any),\n enabled: options.enabled !== false && id != null,\n ...options,\n });\n}\n\n/**\n * Paginated query - React Query caches each page\n * @example\n * const { data, totalPages, hasMore } = useRepositoryPagination('products', page, 20);\n */\nexport function useRepositoryPagination<T = any>(\n table: string,\n page: number = 1,\n limit: number = 10,\n options: QueryOptions = {},\n) {\n const manager = getManager();\n\n return useQuery({\n queryKey: queryKeys.paginated(table, page, limit, options),\n queryFn: () => manager.paginate<T>(table, page, limit, options),\n });\n}\n\n/**\n * Infinite query for infinite scroll / load more\n * @example\n * const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =\n * useRepositoryInfiniteQuery('posts', 20, {\n * where: { published: 1 },\n * orderBy: [{ field: 'created_at', direction: 'DESC' }]\n * });\n *\n * // data.pages = [page1Data, page2Data, page3Data, ...]\n * const allPosts = data?.pages.flatMap(page => page.data) ?? [];\n */\nexport function useRepositoryInfiniteQuery<T = any>(\n table: string,\n pageSize: number = 20,\n options: QueryOptions = {},\n queryOptions?: Omit<\n UseInfiniteQueryOptions<\n { data: T[]; page: number; totalPages: number; hasMore: boolean },\n Error\n >,\n \"queryKey\" | \"queryFn\" | \"getNextPageParam\" | \"initialPageParam\"\n >,\n) {\n const manager = getManager();\n\n return useInfiniteQuery({\n queryKey: queryKeys.infinite(table, pageSize, options),\n queryFn: ({ pageParam }) =>\n manager.paginate<T>(table, pageParam as number, pageSize, options),\n initialPageParam: 1,\n getNextPageParam: (lastPage) => {\n if (!lastPage.hasMore) return undefined;\n return lastPage.page + 1;\n },\n ...queryOptions,\n });\n}\n\n// ==========================================\n// MUTATION HOOKS (Auto-invalidation via React Query)\n// ==========================================\n\n/**\n * Create mutation - React Query handles cache invalidation\n * @example\n * const { mutate: createPost } = useRepositoryCreate('posts', {\n * onSuccess: () => toast.success('Created!')\n * });\n */\nexport function useRepositoryCreate<T = any>(\n table: string,\n options: Omit<UseMutationOptions<T, Error, Partial<T>>, \"mutationFn\"> & {\n invalidate?: string[];\n } = {},\n) {\n const manager = getManager();\n const queryClient = useQueryClient();\n const { invalidate = [table], ...mutationOptions } = options;\n\n return useMutation<T, Error, Partial<T>>({\n mutationFn: (data) => manager.create<T>(table, data),\n onSuccess: () => {\n // React Query automatically invalidates and refetches\n invalidate.forEach((t) => {\n queryClient.invalidateQueries({ queryKey: queryKeys.all(t) });\n });\n },\n ...mutationOptions,\n });\n}\n\n/**\n * Update mutation - Optimistic update via React Query\n * @example\n * const { mutate: updatePost } = useRepositoryUpdate('posts', {\n * onSuccess: () => toast.success('Updated!')\n * });\n * updatePost({ id: 1, data: { title: 'New Title' } });\n */\nexport function useRepositoryUpdate<T = any>(\n table: string,\n options: Omit<\n UseMutationOptions<T, Error, { id: number | string; data: Partial<T> }>,\n \"mutationFn\"\n > = {},\n) {\n const manager = getManager();\n const queryClient = useQueryClient();\n\n return useMutation<T, Error, { id: number | string; data: Partial<T> }>({\n mutationFn: ({ id, data }) => manager.update<T>(table, id, data),\n onSuccess: (data, variables) => {\n // Invalidate list queries\n queryClient.invalidateQueries({ queryKey: queryKeys.all(table) });\n\n // Update detail cache optimistically\n queryClient.setQueryData(queryKeys.detail(table, variables.id), data);\n },\n ...options,\n });\n}\n\n/**\n * Delete mutation\n * @example\n * const { mutate: deletePost } = useRepositoryDelete('posts', {\n * onSuccess: () => toast.success('Deleted!')\n * });\n * deletePost(postId);\n */\nexport function useRepositoryDelete(\n table: string,\n options: Omit<\n UseMutationOptions<boolean, Error, number | string>,\n \"mutationFn\"\n > = {},\n) {\n const manager = getManager();\n const queryClient = useQueryClient();\n\n return useMutation<boolean, Error, number | string>({\n mutationFn: (id) => manager.delete(table, id),\n onSuccess: (_data, id) => {\n // Invalidate and remove from cache\n queryClient.invalidateQueries({ queryKey: queryKeys.all(table) });\n queryClient.removeQueries({ queryKey: queryKeys.detail(table, id) });\n },\n ...options,\n });\n}\n\n// ==========================================\n// RAW SQL QUERY HOOKS\n// ==========================================\n\n/**\n * Raw SQL query hook - for complex queries that can't be expressed with QueryOptions\n * @example\n * // Complex JOIN query\n * const { data: posts } = useRawQuery<Post>(\n * ['posts-with-categories', categorySlug],\n * `SELECT DISTINCT p.*, c.name as category_name\n * FROM posts p\n * JOIN post_categories pc ON p.id = pc.post_id\n * JOIN blog_categories c ON pc.category_id = c.id\n * WHERE c.slug = ? AND p.published = 1\n * ORDER BY p.published_at DESC`,\n * [categorySlug]\n * );\n *\n * // Aggregation query\n * const { data: stats } = useRawQuery<{total: number, avg: number}>(\n * ['product-stats'],\n * `SELECT COUNT(*) as total, AVG(price) as avg FROM products WHERE published = 1`\n * );\n */\nexport function useRawQuery<T = any>(\n queryKey: any[],\n sql: string,\n params?: any[],\n options?: Omit<UseQueryOptions<T[], Error>, \"queryKey\" | \"queryFn\">,\n) {\n const manager = getManager();\n\n return useQuery<T[], Error>({\n queryKey: [\"raw\", ...queryKey],\n queryFn: () => manager.raw<T>(sql, params),\n ...options,\n });\n}\n\n/**\n * Raw SQL query hook for single result - aggregations, single lookups\n * @example\n * // Get price range\n * const { data: priceRange } = useRawQueryOne<{min: number, max: number}>(\n * ['price-range'],\n * `SELECT MIN(price) as min, MAX(price) as max FROM products WHERE published = 1`\n * );\n *\n * // Get single post with category\n * const { data: post } = useRawQueryOne<Post>(\n * ['post-detail', slug],\n * `SELECT p.*, c.name as category_name\n * FROM posts p\n * LEFT JOIN post_categories pc ON p.id = pc.post_id\n * LEFT JOIN blog_categories c ON pc.category_id = c.id\n * WHERE p.slug = ?`,\n * [slug]\n * );\n */\nexport function useRawQueryOne<T = any>(\n queryKey: any[],\n sql: string,\n params?: any[],\n options?: Omit<UseQueryOptions<T | null, Error>, \"queryKey\" | \"queryFn\">,\n) {\n const manager = getManager();\n\n return useQuery<T | null, Error>({\n queryKey: [\"raw\", ...queryKey],\n queryFn: () => manager.rawOne<T>(sql, params),\n ...options,\n });\n}\n"
77
+ },
78
+ {
79
+ "path": "db/utils/parsers.ts",
80
+ "type": "registry:lib",
81
+ "target": "$modules$/db/utils/parsers.ts",
82
+ "content": "/**\n * Database field parsers - Client-side utilities\n * NO automatic parsing - client decides what to parse and when\n */\n\n/**\n * Parse comma-separated string to array\n * @example \"tag1,tag2,tag3\" -> [\"tag1\", \"tag2\", \"tag3\"]\n */\nexport const parseCommaSeparatedString = (value: string): string[] => {\n if (!value || typeof value !== \"string\") return [];\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n};\n\n/**\n * Parse JSON string to array\n * @example '[\"img1.jpg\",\"img2.jpg\"]' -> [\"img1.jpg\", \"img2.jpg\"]\n */\nexport const parseJSONStringToArray = (value: string): string[] => {\n if (!value || typeof value !== \"string\") return [];\n try {\n const parsed = JSON.parse(value);\n return Array.isArray(parsed) ? parsed : [];\n } catch (e) {\n console.warn(\"Failed to parse JSON array:\", value);\n return [];\n }\n};\n\n/**\n * Smart array parser - tries JSON first, falls back to comma-separated\n * @example '[\"a\",\"b\"]' -> [\"a\", \"b\"] OR \"a,b\" -> [\"a\", \"b\"]\n */\nexport const parseStringToArray = (value: any): string[] => {\n if (!value) return [];\n if (Array.isArray(value)) return value;\n if (typeof value !== \"string\") return [];\n\n // Try JSON first\n if (value.trim().startsWith(\"[\")) {\n const jsonResult = parseJSONStringToArray(value);\n if (jsonResult.length > 0) return jsonResult;\n }\n\n // Fall back to comma-separated\n return parseCommaSeparatedString(value);\n};\n\n/**\n * Parse JSON string to object\n * @example '{\"key\":\"value\"}' -> {key: \"value\"}\n */\nexport const parseJSONString = <T = any>(\n value: any,\n defaultValue: T | null = null,\n): T | null => {\n if (!value) return defaultValue;\n if (typeof value === \"object\") return value; // Already parsed\n if (typeof value !== \"string\") return defaultValue;\n\n try {\n return JSON.parse(value);\n } catch (e) {\n console.warn(\"Failed to parse JSON:\", value);\n return defaultValue;\n }\n};\n\n/**\n * Parse SQLite boolean (0/1) to JavaScript boolean\n * @example 1 -> true, 0 -> false\n */\nexport const parseSQLiteBoolean = (value: any): boolean => {\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"number\") return value !== 0;\n if (typeof value === \"string\") {\n const lower = value.toLowerCase();\n return lower === \"true\" || lower === \"1\" || lower === \"yes\";\n }\n return Boolean(value);\n};\n\n/**\n * Parse number safely with default fallback\n * @example \"123\" -> 123, \"invalid\" -> 0 (or provided default)\n */\nexport const parseNumberSafe = (\n value: any,\n defaultValue: number = 0,\n): number => {\n const num = Number(value);\n return isNaN(num) ? defaultValue : num;\n};\n"
83
+ }
84
+ ],
85
+ "exports": {
86
+ "types": [
87
+ "AdapterType",
88
+ "DataConfig",
89
+ "IDataAdapter",
90
+ "JoinClause",
91
+ "JoinType",
92
+ "OrderBy",
93
+ "PaginatedResult",
94
+ "QueryOptions",
95
+ "RepositoryQueryOptions",
96
+ "WhereCondition",
97
+ "WhereGroup",
98
+ "WhereOperator"
99
+ ],
100
+ "variables": [
101
+ "DBQueryProvider",
102
+ "DataManager",
103
+ "QueryProvider",
104
+ "SqliteAdapter",
105
+ "cacheUtils",
106
+ "createAdapter",
107
+ "getAdapter",
108
+ "parseCommaSeparatedString",
109
+ "parseJSONString",
110
+ "parseJSONStringToArray",
111
+ "parseNumberSafe",
112
+ "parseSQLiteBoolean",
113
+ "parseStringToArray",
114
+ "queryClient",
115
+ "queryKeys",
116
+ "resetAdapter",
117
+ "useRawQuery",
118
+ "useRawQueryOne",
119
+ "useRepositoryCreate",
120
+ "useRepositoryDelete",
121
+ "useRepositoryInfiniteQuery",
122
+ "useRepositoryPagination",
123
+ "useRepositoryQuery",
124
+ "useRepositoryQueryById",
125
+ "useRepositoryQueryOne",
126
+ "useRepositoryUpdate"
127
+ ]
128
+ }
129
+ }
@@ -30,3 +30,8 @@ import { AboutPage } from '@/modules/about-page';
30
30
  • Edit content in lang/en.json
31
31
  • Wrapped with Layout component
32
32
  ```
33
+
34
+ ## Dependencies
35
+
36
+ This component requires:
37
+ - `animations`
@@ -0,0 +1,38 @@
1
+ # Announcement Bar
2
+
3
+ Top notification bar with multiple style variants (default, primary, warning, success, gradient), dismissible with localStorage persistence, customizable icon, and link support. Slide animation.
4
+
5
+ ## Files
6
+
7
+ | Target | Type |
8
+ |--------|------|
9
+ | `$modules$/announcement-bar/index.ts` | index |
10
+ | `$modules$/announcement-bar/announcement-bar.tsx` | component |
11
+ | `$modules$/announcement-bar/lang/en.json` | lang |
12
+ | `$modules$/announcement-bar/lang/tr.json` | lang |
13
+
14
+ ## Exports
15
+
16
+ **Components/Functions:** `AnnouncementBar`
17
+
18
+ ```typescript
19
+ import { AnnouncementBar } from '@/modules/announcement-bar';
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```
25
+ import { AnnouncementBar } from '@/modules/announcement-bar';
26
+
27
+ <AnnouncementBar
28
+ message="New features available!"
29
+ linkText="Learn more"
30
+ linkUrl="/blog/new-features"
31
+ variant="gradient"
32
+ icon="sparkles"
33
+ />
34
+
35
+ • Variants: default, primary, warning, success, gradient
36
+ • Icons: sparkles, megaphone, gift, zap, none
37
+ • Dismissible with storage key
38
+ ```
@@ -0,0 +1,64 @@
1
+ # Auth Core
2
+
3
+ Core authentication system with Zustand store, JWT token management with auto-refresh. No pages included - use separate page modules (login-page, register-page, etc.) for UI.
4
+
5
+ ## Files
6
+
7
+ | Target | Type |
8
+ |--------|------|
9
+ | `$modules$/auth-core/index.ts` | index |
10
+ | `$modules$/auth-core/auth-store.ts` | store |
11
+ | `$modules$/auth-core/use-auth.ts` | hook |
12
+
13
+ ## Exports
14
+
15
+ **Types:** `AuthTokens`, `User`
16
+
17
+ **Components/Functions:** `useAuth`, `useAuthStore`
18
+
19
+ ```typescript
20
+ import { useAuth, useAuthStore, AuthTokens, ... } from '@/modules/auth-core';
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```
26
+ import { useAuth, useAuthStore } from '@/modules/auth-core';
27
+
28
+ // Use the hook for auth operations
29
+ const {
30
+ user,
31
+ tokens,
32
+ isAuthenticated,
33
+ login,
34
+ register,
35
+ confirmEmail,
36
+ forgotPassword,
37
+ resetPassword,
38
+ logout,
39
+ api,
40
+ } = useAuth();
41
+
42
+ // Auth operations
43
+ await login(username, password);
44
+ await register(username, email, password);
45
+ await confirmEmail(username, code);
46
+ await forgotPassword(username);
47
+ await resetPassword(username, code, newPassword);
48
+ logout();
49
+
50
+ // Direct store access for state management
51
+ const setAuth = useAuthStore((state) => state.setAuth);
52
+ const clearAuth = useAuthStore((state) => state.clearAuth);
53
+
54
+ • Installed at: src/modules/auth-core/
55
+ • Provides: useAuth hook, useAuthStore
56
+ • Auto token refresh before expiry
57
+ • 401 interceptor with automatic retry
58
+ • Uses customerClient from api module internally
59
+ ```
60
+
61
+ ## Dependencies
62
+
63
+ This component requires:
64
+ - `api`
@@ -36,3 +36,4 @@ import { BlogListPage } from '@/modules/blog-list-page';
36
36
  This component requires:
37
37
  - `blog-core`
38
38
  - `post-card`
39
+ - `animations`
@@ -35,3 +35,4 @@ import CartPage from '@/modules/cart-page';
35
35
 
36
36
  This component requires:
37
37
  - `ecommerce-core`
38
+ - `animations`
@@ -0,0 +1,39 @@
1
+ # Case Study Page
2
+
3
+ Detailed project case study with challenge/solution/results sections. Includes hero image, gallery, project details sidebar, and share buttons.
4
+
5
+ ## Files
6
+
7
+ | Target | Type |
8
+ |--------|------|
9
+ | `$modules$/case-study-page/case-study-page.tsx` | component |
10
+ | `$modules$/case-study-page/index.ts` | index |
11
+ | `$modules$/case-study-page/lang/en.json` | lang |
12
+ | `$modules$/case-study-page/lang/tr.json` | lang |
13
+
14
+ ## Exports
15
+
16
+ **Components/Functions:** `CaseStudyPage`, `default`
17
+
18
+ ```typescript
19
+ import { CaseStudyPage, default } from '@/modules/case-study-page';
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```
25
+ import { CaseStudyPage } from '@/modules/case-study-page';
26
+
27
+ <CaseStudyPage />
28
+
29
+ • Installed at: src/modules/case-study-page/
30
+ • Customize content: lang/en/case-study-page.json
31
+ • Props: title, heroImage, gallery[], challenge, solution, results, details
32
+ ```
33
+
34
+ ## Dependencies
35
+
36
+ This component requires:
37
+ - `button`
38
+ - `animations`
39
+ - `share-buttons`
@@ -1,6 +1,6 @@
1
1
  # Checkout Page
2
2
 
3
- Multi-step checkout page with customer information form (name, email, phone, address), shipping method selection, payment method options (credit card, PayPal, bank transfer), and order review. Features form validation, order summary sidebar, shipping cost calculation, and place order button. Includes progress indicator for checkout steps.
3
+ Full-featured checkout page with customer information form, payment method selection (card, bank transfer, cash on delivery), and online payment provider selection (Stripe, iyzico). Integrates with payment API for creating checkout sessions and fetching bank transfer info. Features form validation, order summary sidebar, and skeleton loading states.
4
4
 
5
5
  ## Files
6
6
 
@@ -36,3 +36,5 @@ import CheckoutPage from '@/modules/checkout-page';
36
36
 
37
37
  This component requires:
38
38
  - `ecommerce-core`
39
+ - `animations`
40
+ - `api`
@@ -0,0 +1,32 @@
1
+ # Coming Soon Page (Minimal)
2
+
3
+ Minimalist coming soon page with large typography, days countdown, and simple email input. Clean design with focus on the launch date number.
4
+
5
+ ## Files
6
+
7
+ | Target | Type |
8
+ |--------|------|
9
+ | `$modules$/coming-soon-page-minimal/index.ts` | index |
10
+ | `$modules$/coming-soon-page-minimal/coming-soon-page-minimal.tsx` | page |
11
+ | `$modules$/coming-soon-page-minimal/lang/en.json` | lang |
12
+ | `$modules$/coming-soon-page-minimal/lang/tr.json` | lang |
13
+
14
+ ## Exports
15
+
16
+ **Components/Functions:** `ComingSoonPageMinimal`, `default`
17
+
18
+ ```typescript
19
+ import { ComingSoonPageMinimal, default } from '@/modules/coming-soon-page-minimal';
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```
25
+ import { ComingSoonPageMinimal } from '@/modules/coming-soon-page-minimal';
26
+
27
+ <Route path="/coming-soon" element={<ComingSoonPageMinimal />} />
28
+
29
+ • Large countdown number display
30
+ • Minimal email signup
31
+ • Customizable launch date
32
+ ```
@@ -0,0 +1,37 @@
1
+ # Coming Soon Page
2
+
3
+ Full-featured coming soon page with countdown timer, email signup form, social links, and gradient background. Includes FadeIn and ScaleUp animations. Perfect for product launches and pre-release marketing.
4
+
5
+ ## Files
6
+
7
+ | Target | Type |
8
+ |--------|------|
9
+ | `$modules$/coming-soon-page/index.ts` | index |
10
+ | `$modules$/coming-soon-page/coming-soon-page.tsx` | page |
11
+ | `$modules$/coming-soon-page/lang/en.json` | lang |
12
+ | `$modules$/coming-soon-page/lang/tr.json` | lang |
13
+
14
+ ## Exports
15
+
16
+ **Components/Functions:** `ComingSoonPage`, `default`
17
+
18
+ ```typescript
19
+ import { ComingSoonPage, default } from '@/modules/coming-soon-page';
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```
25
+ import { ComingSoonPage } from '@/modules/coming-soon-page';
26
+
27
+ <Route path="/coming-soon" element={<ComingSoonPage />} />
28
+
29
+ • Customizable launch date via launchDate prop
30
+ • Email signup with success state
31
+ • Social links (Twitter, Instagram, GitHub, LinkedIn)
32
+ ```
33
+
34
+ ## Dependencies
35
+
36
+ This component requires:
37
+ - `animations`
@@ -13,10 +13,10 @@ Stunning full-screen Google Map background with glassmorphism contact form and i
13
13
 
14
14
  ## Exports
15
15
 
16
- **Components/Functions:** `ContactPageMapOverlay`
16
+ **Components/Functions:** `ContactPageMapOverlay`, `default`
17
17
 
18
18
  ```typescript
19
- import { ContactPageMapOverlay } from '@/modules/contact-page-map-overlay';
19
+ import { ContactPageMapOverlay, default } from '@/modules/contact-page-map-overlay';
20
20
  ```
21
21
 
22
22
  ## Usage
@@ -13,10 +13,10 @@ Modern 50/50 split layout contact page with contact form on the left and full-he
13
13
 
14
14
  ## Exports
15
15
 
16
- **Components/Functions:** `ContactPageMapSplit`
16
+ **Components/Functions:** `ContactPageMapSplit`, `default`
17
17
 
18
18
  ```typescript
19
- import { ContactPageMapSplit } from '@/modules/contact-page-map-split';
19
+ import { ContactPageMapSplit, default } from '@/modules/contact-page-map-split';
20
20
  ```
21
21
 
22
22
  ## Usage
@@ -31,3 +31,8 @@ import { ContactPage } from '@/modules/contact-page';
31
31
  • Info: address, phone, email, hours, map
32
32
  • Toast notifications on submit
33
33
  ```
34
+
35
+ ## Dependencies
36
+
37
+ This component requires:
38
+ - `animations`