@promakeai/cli 0.9.9 → 0.9.10

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 (137) hide show
  1. package/README.md +111 -111
  2. package/dist/index.js +142 -142
  3. package/dist/registry/about-page.json +3 -3
  4. package/dist/registry/about-section.json +4 -4
  5. package/dist/registry/animations.json +2 -2
  6. package/dist/registry/announcement-bar.json +4 -4
  7. package/dist/registry/api.json +1 -1
  8. package/dist/registry/auth-core.json +2 -2
  9. package/dist/registry/bento-grid-section.json +4 -4
  10. package/dist/registry/blog-core.json +5 -5
  11. package/dist/registry/blog-list-page.json +4 -4
  12. package/dist/registry/blog-section.json +4 -4
  13. package/dist/registry/cards-carousel-section.json +4 -4
  14. package/dist/registry/cart-drawer.json +4 -4
  15. package/dist/registry/cart-page.json +4 -4
  16. package/dist/registry/case-study-page.json +3 -3
  17. package/dist/registry/category-section.json +4 -4
  18. package/dist/registry/checkout-page.json +4 -4
  19. package/dist/registry/coming-soon-page-minimal.json +4 -4
  20. package/dist/registry/coming-soon-page.json +4 -4
  21. package/dist/registry/contact-info-grid.json +4 -4
  22. package/dist/registry/contact-page-centered.json +4 -4
  23. package/dist/registry/contact-page-map-overlay.json +3 -3
  24. package/dist/registry/contact-page-map-split.json +3 -3
  25. package/dist/registry/contact-page-split.json +4 -4
  26. package/dist/registry/contact-page.json +4 -4
  27. package/dist/registry/content-section.json +4 -4
  28. package/dist/registry/cookie-consent.json +4 -4
  29. package/dist/registry/cookies-page.json +3 -3
  30. package/dist/registry/cta-section.json +3 -3
  31. package/dist/registry/ecommerce-core.json +8 -8
  32. package/dist/registry/empty-page.json +3 -3
  33. package/dist/registry/faq-categorized.json +4 -4
  34. package/dist/registry/faq-simple.json +4 -4
  35. package/dist/registry/favorites-blog-block.json +1 -1
  36. package/dist/registry/favorites-blog-page.json +4 -4
  37. package/dist/registry/favorites-ecommerce-block.json +1 -1
  38. package/dist/registry/favorites-ecommerce-page.json +4 -4
  39. package/dist/registry/feature-section.json +3 -3
  40. package/dist/registry/featured-products.json +4 -4
  41. package/dist/registry/footer-detailed.json +4 -4
  42. package/dist/registry/footer-minimal.json +3 -3
  43. package/dist/registry/footer.json +3 -3
  44. package/dist/registry/forgot-password-page-split.json +4 -4
  45. package/dist/registry/forgot-password-page.json +4 -4
  46. package/dist/registry/google-adsense.json +4 -4
  47. package/dist/registry/google-map.json +2 -2
  48. package/dist/registry/header-centered-pill.json +4 -4
  49. package/dist/registry/header-ecommerce.json +4 -4
  50. package/dist/registry/header-mega.json +4 -4
  51. package/dist/registry/header-minimal.json +4 -4
  52. package/dist/registry/header-simple.json +3 -3
  53. package/dist/registry/hero-carousel.json +3 -3
  54. package/dist/registry/hero-cta.json +4 -4
  55. package/dist/registry/hero-gradient.json +4 -4
  56. package/dist/registry/hero-grid.json +4 -4
  57. package/dist/registry/hero-profile.json +3 -3
  58. package/dist/registry/hero.json +3 -3
  59. package/dist/registry/index.json +103 -103
  60. package/dist/registry/landing-page-app.json +3 -3
  61. package/dist/registry/landing-page-saas.json +3 -3
  62. package/dist/registry/login-page-split.json +4 -4
  63. package/dist/registry/login-page.json +4 -4
  64. package/dist/registry/logo-cloud.json +4 -4
  65. package/dist/registry/masonry-grid.json +3 -3
  66. package/dist/registry/my-orders-page.json +4 -4
  67. package/dist/registry/newsletter-section.json +4 -4
  68. package/dist/registry/order-card-compact.json +3 -3
  69. package/dist/registry/order-confirmation-page.json +4 -4
  70. package/dist/registry/order-detail-block.json +1 -1
  71. package/dist/registry/orders-list-block.json +1 -1
  72. package/dist/registry/payment-success-block.json +2 -2
  73. package/dist/registry/portfolio-page.json +4 -4
  74. package/dist/registry/post-card.json +4 -4
  75. package/dist/registry/post-detail-block.json +4 -4
  76. package/dist/registry/post-detail-page.json +4 -4
  77. package/dist/registry/pricing-card.json +3 -3
  78. package/dist/registry/pricing-page.json +4 -4
  79. package/dist/registry/pricing-section.json +4 -4
  80. package/dist/registry/privacy-page.json +3 -3
  81. package/dist/registry/product-card-detailed.json +4 -4
  82. package/dist/registry/product-card-hover.json +4 -4
  83. package/dist/registry/product-card.json +4 -4
  84. package/dist/registry/product-detail-block.json +2 -2
  85. package/dist/registry/product-detail-page.json +4 -4
  86. package/dist/registry/product-detail-section.json +4 -4
  87. package/dist/registry/product-quick-view.json +4 -4
  88. package/dist/registry/products-page.json +4 -4
  89. package/dist/registry/reading-progress.json +4 -4
  90. package/dist/registry/register-page-split.json +4 -4
  91. package/dist/registry/register-page.json +4 -4
  92. package/dist/registry/related-posts-block.json +1 -1
  93. package/dist/registry/related-products-block.json +2 -2
  94. package/dist/registry/reset-password-page-split.json +4 -4
  95. package/dist/registry/reset-password-page.json +4 -4
  96. package/dist/registry/service-card.json +1 -1
  97. package/dist/registry/share-buttons.json +4 -4
  98. package/dist/registry/skill-card.json +1 -1
  99. package/dist/registry/team-page.json +4 -4
  100. package/dist/registry/terms-page.json +3 -3
  101. package/dist/registry/testimonials-carousel.json +4 -4
  102. package/dist/registry/testimonials-grid.json +4 -4
  103. package/dist/registry/timeline-section.json +4 -4
  104. package/dist/registry/verify-email-page.json +4 -4
  105. package/dist/registry/video-hero.json +4 -4
  106. package/dist/registry/youtube-embed.json +4 -4
  107. package/package.json +1 -1
  108. package/template/.env +5 -5
  109. package/template/README.md +54 -54
  110. package/template/eslint.config.js +41 -41
  111. package/template/index.html +237 -237
  112. package/template/package.json +96 -96
  113. package/template/public/_redirects +1 -1
  114. package/template/public/robots.txt +14 -14
  115. package/template/scripts/init-db.ts +18 -18
  116. package/template/src/App.tsx +21 -21
  117. package/template/src/components/FormField.tsx +48 -48
  118. package/template/src/components/FormFileInput.tsx +75 -75
  119. package/template/src/components/GoogleAnalytics.tsx +34 -34
  120. package/template/src/components/LanguageSwitcher.tsx +53 -53
  121. package/template/src/components/MetriaAnalytics.tsx +68 -68
  122. package/template/src/components/PasswordInput.tsx +60 -60
  123. package/template/src/components/ScriptInjector.tsx +62 -62
  124. package/template/src/components/Stack.tsx +39 -39
  125. package/template/src/constants/constants.json +71 -71
  126. package/template/src/db/index.ts +21 -21
  127. package/template/src/db/provider.tsx +106 -106
  128. package/template/src/db/schema.json +278 -278
  129. package/template/src/db/types.ts +195 -195
  130. package/template/src/hooks/use-debounced-value.ts +12 -12
  131. package/template/src/hooks/use-page-title.ts +55 -55
  132. package/template/src/lang/index.ts +90 -90
  133. package/template/src/lib/api.ts +345 -345
  134. package/template/src/lib/env.ts +19 -19
  135. package/template/src/router.tsx +14 -14
  136. package/template/src/vite-env.d.ts +1 -1
  137. package/template/vite.config.ts +194 -199
@@ -17,25 +17,25 @@
17
17
  "path": "verify-email-page/index.ts",
18
18
  "type": "registry:index",
19
19
  "target": "$modules$/verify-email-page/index.ts",
20
- "content": "export * from \"./verify-email-page\";\r\nexport { default } from \"./verify-email-page\";\r\n"
20
+ "content": "export * from \"./verify-email-page\";\nexport { default } from \"./verify-email-page\";\n"
21
21
  },
22
22
  {
23
23
  "path": "verify-email-page/verify-email-page.tsx",
24
24
  "type": "registry:page",
25
25
  "target": "$modules$/verify-email-page/verify-email-page.tsx",
26
- "content": "import { useState } from \"react\";\r\nimport { Link } from \"react-router\";\r\nimport { toast } from \"sonner\";\r\nimport { Layout } from \"@/components/Layout\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { useAuth } from \"@/modules/auth-core\";\r\nimport { getErrorMessage } from \"@/modules/api\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n CardTitle,\r\n CardDescription,\r\n} from \"@/components/ui/card\";\r\nimport { MailCheck, ArrowLeft, CheckCircle2 } from \"lucide-react\";\r\nimport { FormField } from \"@/components/FormField\";\r\n\r\ntype Step = \"request\" | \"verify\" | \"success\";\r\n\r\nexport function VerifyEmailPage() {\r\n const { t } = useTranslation(\"verify-email-page\");\r\n usePageTitle({ title: t(\"title\", \"Verify Email\") });\r\n\r\n const { confirmEmail, resendCode } = useAuth();\r\n\r\n const [step, setStep] = useState<Step>(\"request\");\r\n const [username, setUsername] = useState(\"\");\r\n const [code, setCode] = useState(\"\");\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const handleSendCode = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setIsSubmitting(true);\r\n setError(null);\r\n\r\n try {\r\n await resendCode(username);\r\n toast.success(t(\"codeSentTitle\", \"Code Sent!\"), {\r\n description: t(\r\n \"codeSentDesc\",\r\n \"A verification code has been sent to your email.\",\r\n ),\r\n });\r\n setStep(\"verify\");\r\n } catch (err) {\r\n const errorMessage = getErrorMessage(\r\n err,\r\n t(\"errorSendGeneric\", \"Failed to send verification code. Please try again.\"),\r\n );\r\n setError(errorMessage);\r\n toast.error(t(\"errorTitle\", \"Error\"), {\r\n description: errorMessage,\r\n });\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n const handleVerify = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setIsSubmitting(true);\r\n setError(null);\r\n\r\n try {\r\n await confirmEmail(username, code);\r\n toast.success(t(\"verifiedTitle\", \"Email Verified!\"), {\r\n description: t(\r\n \"verifiedDesc\",\r\n \"Your email has been successfully verified.\",\r\n ),\r\n });\r\n setStep(\"success\");\r\n } catch (err) {\r\n const errorMessage = getErrorMessage(\r\n err,\r\n t(\"errorVerifyGeneric\", \"Failed to verify email. Please check your code and try again.\"),\r\n );\r\n setError(errorMessage);\r\n toast.error(t(\"errorTitle\", \"Error\"), {\r\n description: errorMessage,\r\n });\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n // Success step\r\n if (step === \"success\") {\r\n return (\r\n <Layout>\r\n <div className=\"min-h-screen bg-muted/30 py-12\">\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\r\n <div className=\"max-w-md mx-auto\">\r\n <Card>\r\n <CardContent className=\"pt-8 pb-8 text-center\">\r\n <CheckCircle2 className=\"w-16 h-16 text-green-500 mx-auto mb-4\" />\r\n <h1 className=\"text-2xl font-bold mb-2\">\r\n {t(\"successTitle\", \"Email Verified!\")}\r\n </h1>\r\n <p className=\"text-muted-foreground mb-6\">\r\n {t(\r\n \"successDescription\",\r\n \"Your email has been verified. You can now login to your account.\",\r\n )}\r\n </p>\r\n <Button asChild className=\"w-full\">\r\n <Link to=\"/login\">{t(\"goToLogin\", \"Go to Login\")}</Link>\r\n </Button>\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n }\r\n\r\n return (\r\n <Layout>\r\n <div className=\"min-h-screen bg-muted/30 py-12\">\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\r\n {/* Hero Section */}\r\n <div className=\"text-center mb-12\">\r\n <h1 className=\"text-4xl font-bold text-foreground mb-4\">\r\n {t(\"title\", \"Verify Email\")}\r\n </h1>\r\n <div className=\"w-16 h-1 bg-primary mx-auto mb-6\"></div>\r\n <p className=\"text-lg text-muted-foreground max-w-xl mx-auto\">\r\n {step === \"request\"\r\n ? t(\r\n \"descriptionRequest\",\r\n \"Enter your username and we'll send you a verification code.\",\r\n )\r\n : t(\r\n \"descriptionVerify\",\r\n \"Enter the verification code sent to your email.\",\r\n )}\r\n </p>\r\n </div>\r\n\r\n <div className=\"max-w-md mx-auto\">\r\n <Card>\r\n <CardHeader>\r\n <CardTitle className=\"flex items-center gap-2\">\r\n <MailCheck className=\"w-5 h-5 text-primary\" />\r\n {step === \"request\"\r\n ? t(\"cardTitleRequest\", \"Request Verification Code\")\r\n : t(\"cardTitleVerify\", \"Enter Verification Code\")}\r\n </CardTitle>\r\n <CardDescription>\r\n {step === \"request\"\r\n ? t(\"cardDescRequest\", \"Step 1 of 2: Request a verification code\")\r\n : t(\r\n \"cardDescVerify\",\r\n \"Step 2 of 2: Enter the code to verify your email\",\r\n )}\r\n </CardDescription>\r\n </CardHeader>\r\n <CardContent>\r\n {step === \"request\" ? (\r\n // Step 1: Request Code\r\n <form onSubmit={handleSendCode} className=\"space-y-6\">\r\n <FormField label={t(\"username\", \"Username\")} htmlFor=\"username\" required>\r\n <Input\r\n id=\"username\"\r\n type=\"text\"\r\n value={username}\r\n onChange={(e) => setUsername(e.target.value)}\r\n placeholder={t(\"usernamePlaceholder\", \"Enter your username\")}\r\n required\r\n className=\"mt-1\"\r\n autoComplete=\"username\"\r\n />\r\n </FormField>\r\n\r\n {error && (\r\n <div className=\"p-4 bg-red-50 border border-red-200 rounded-lg\">\r\n <p className=\"text-red-800 text-sm font-medium\">\r\n {error}\r\n </p>\r\n </div>\r\n )}\r\n\r\n <Button\r\n type=\"submit\"\r\n size=\"lg\"\r\n className=\"w-full\"\r\n disabled={isSubmitting}\r\n >\r\n {isSubmitting ? (\r\n <>\r\n <div className=\"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2\" />\r\n {t(\"sending\", \"Sending...\")}\r\n </>\r\n ) : (\r\n t(\"sendCode\", \"Send Verification Code\")\r\n )}\r\n </Button>\r\n\r\n <div className=\"text-center\">\r\n <Link\r\n to=\"/login\"\r\n className=\"text-sm text-muted-foreground hover:text-primary inline-flex items-center gap-1\"\r\n >\r\n <ArrowLeft className=\"w-4 h-4\" />\r\n {t(\"backToLogin\", \"Back to Login\")}\r\n </Link>\r\n </div>\r\n </form>\r\n ) : (\r\n // Step 2: Verify Code\r\n <form onSubmit={handleVerify} className=\"space-y-6\">\r\n <div className=\"p-3 bg-muted rounded-lg text-sm\">\r\n <span className=\"text-muted-foreground\">\r\n {t(\"codeFor\", \"Verification code for:\")}{\" \"}\r\n </span>\r\n <span className=\"font-medium\">{username}</span>\r\n </div>\r\n <FormField label={t(\"code\", \"Verification Code\")} htmlFor=\"code\" required>\r\n <Input\r\n id=\"code\"\r\n type=\"text\"\r\n value={code}\r\n onChange={(e) => setCode(e.target.value)}\r\n placeholder={t(\"codePlaceholder\", \"Enter 6-digit code\")}\r\n required\r\n className=\"mt-1\"\r\n maxLength={6}\r\n />\r\n </FormField>\r\n\r\n {error && (\r\n <div className=\"p-4 bg-red-50 border border-red-200 rounded-lg\">\r\n <p className=\"text-red-800 text-sm font-medium\">\r\n {error}\r\n </p>\r\n </div>\r\n )}\r\n\r\n <Button\r\n type=\"submit\"\r\n size=\"lg\"\r\n className=\"w-full\"\r\n disabled={isSubmitting}\r\n >\r\n {isSubmitting ? (\r\n <>\r\n <div className=\"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2\" />\r\n {t(\"verifying\", \"Verifying...\")}\r\n </>\r\n ) : (\r\n t(\"verifyEmail\", \"Verify Email\")\r\n )}\r\n </Button>\r\n\r\n <div className=\"flex justify-between\">\r\n <button\r\n type=\"button\"\r\n onClick={() => {\r\n setStep(\"request\");\r\n setCode(\"\");\r\n setError(null);\r\n }}\r\n className=\"text-sm text-muted-foreground hover:text-primary\"\r\n >\r\n {t(\"changeUsername\", \"Change username\")}\r\n </button>\r\n <button\r\n type=\"button\"\r\n onClick={() =>\r\n handleSendCode({\r\n preventDefault: () => {},\r\n } as React.FormEvent)\r\n }\r\n className=\"text-sm text-primary hover:underline\"\r\n disabled={isSubmitting}\r\n >\r\n {t(\"resendCode\", \"Resend code\")}\r\n </button>\r\n </div>\r\n </form>\r\n )}\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n}\r\n\r\nexport default VerifyEmailPage;\r\n"
26
+ "content": "import { useState } from \"react\";\nimport { Link } from \"react-router\";\nimport { toast } from \"sonner\";\nimport { Layout } from \"@/components/Layout\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { useTranslation } from \"react-i18next\";\nimport { useAuth } from \"@/modules/auth-core\";\nimport { getErrorMessage } from \"@/modules/api\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n CardDescription,\n} from \"@/components/ui/card\";\nimport { MailCheck, ArrowLeft, CheckCircle2 } from \"lucide-react\";\nimport { FormField } from \"@/components/FormField\";\n\ntype Step = \"request\" | \"verify\" | \"success\";\n\nexport function VerifyEmailPage() {\n const { t } = useTranslation(\"verify-email-page\");\n usePageTitle({ title: t(\"title\", \"Verify Email\") });\n\n const { confirmEmail, resendCode } = useAuth();\n\n const [step, setStep] = useState<Step>(\"request\");\n const [username, setUsername] = useState(\"\");\n const [code, setCode] = useState(\"\");\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleSendCode = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitting(true);\n setError(null);\n\n try {\n await resendCode(username);\n toast.success(t(\"codeSentTitle\", \"Code Sent!\"), {\n description: t(\n \"codeSentDesc\",\n \"A verification code has been sent to your email.\",\n ),\n });\n setStep(\"verify\");\n } catch (err) {\n const errorMessage = getErrorMessage(\n err,\n t(\"errorSendGeneric\", \"Failed to send verification code. Please try again.\"),\n );\n setError(errorMessage);\n toast.error(t(\"errorTitle\", \"Error\"), {\n description: errorMessage,\n });\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleVerify = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitting(true);\n setError(null);\n\n try {\n await confirmEmail(username, code);\n toast.success(t(\"verifiedTitle\", \"Email Verified!\"), {\n description: t(\n \"verifiedDesc\",\n \"Your email has been successfully verified.\",\n ),\n });\n setStep(\"success\");\n } catch (err) {\n const errorMessage = getErrorMessage(\n err,\n t(\"errorVerifyGeneric\", \"Failed to verify email. Please check your code and try again.\"),\n );\n setError(errorMessage);\n toast.error(t(\"errorTitle\", \"Error\"), {\n description: errorMessage,\n });\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // Success step\n if (step === \"success\") {\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 <div className=\"max-w-md mx-auto\">\n <Card>\n <CardContent className=\"pt-8 pb-8 text-center\">\n <CheckCircle2 className=\"w-16 h-16 text-green-500 mx-auto mb-4\" />\n <h1 className=\"text-2xl font-bold mb-2\">\n {t(\"successTitle\", \"Email Verified!\")}\n </h1>\n <p className=\"text-muted-foreground mb-6\">\n {t(\n \"successDescription\",\n \"Your email has been verified. You can now login to your account.\",\n )}\n </p>\n <Button asChild className=\"w-full\">\n <Link to=\"/login\">{t(\"goToLogin\", \"Go to Login\")}</Link>\n </Button>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n </Layout>\n );\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 {/* Hero Section */}\n <div className=\"text-center mb-12\">\n <h1 className=\"text-4xl font-bold text-foreground mb-4\">\n {t(\"title\", \"Verify Email\")}\n </h1>\n <div className=\"w-16 h-1 bg-primary mx-auto mb-6\"></div>\n <p className=\"text-lg text-muted-foreground max-w-xl mx-auto\">\n {step === \"request\"\n ? t(\n \"descriptionRequest\",\n \"Enter your username and we'll send you a verification code.\",\n )\n : t(\n \"descriptionVerify\",\n \"Enter the verification code sent to your email.\",\n )}\n </p>\n </div>\n\n <div className=\"max-w-md mx-auto\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <MailCheck className=\"w-5 h-5 text-primary\" />\n {step === \"request\"\n ? t(\"cardTitleRequest\", \"Request Verification Code\")\n : t(\"cardTitleVerify\", \"Enter Verification Code\")}\n </CardTitle>\n <CardDescription>\n {step === \"request\"\n ? t(\"cardDescRequest\", \"Step 1 of 2: Request a verification code\")\n : t(\n \"cardDescVerify\",\n \"Step 2 of 2: Enter the code to verify your email\",\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {step === \"request\" ? (\n // Step 1: Request Code\n <form onSubmit={handleSendCode} className=\"space-y-6\">\n <FormField label={t(\"username\", \"Username\")} htmlFor=\"username\" required>\n <Input\n id=\"username\"\n type=\"text\"\n value={username}\n onChange={(e) => setUsername(e.target.value)}\n placeholder={t(\"usernamePlaceholder\", \"Enter your username\")}\n required\n className=\"mt-1\"\n autoComplete=\"username\"\n />\n </FormField>\n\n {error && (\n <div className=\"p-4 bg-red-50 border border-red-200 rounded-lg\">\n <p className=\"text-red-800 text-sm font-medium\">\n {error}\n </p>\n </div>\n )}\n\n <Button\n type=\"submit\"\n size=\"lg\"\n className=\"w-full\"\n disabled={isSubmitting}\n >\n {isSubmitting ? (\n <>\n <div className=\"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2\" />\n {t(\"sending\", \"Sending...\")}\n </>\n ) : (\n t(\"sendCode\", \"Send Verification Code\")\n )}\n </Button>\n\n <div className=\"text-center\">\n <Link\n to=\"/login\"\n className=\"text-sm text-muted-foreground hover:text-primary inline-flex items-center gap-1\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {t(\"backToLogin\", \"Back to Login\")}\n </Link>\n </div>\n </form>\n ) : (\n // Step 2: Verify Code\n <form onSubmit={handleVerify} className=\"space-y-6\">\n <div className=\"p-3 bg-muted rounded-lg text-sm\">\n <span className=\"text-muted-foreground\">\n {t(\"codeFor\", \"Verification code for:\")}{\" \"}\n </span>\n <span className=\"font-medium\">{username}</span>\n </div>\n <FormField label={t(\"code\", \"Verification Code\")} htmlFor=\"code\" required>\n <Input\n id=\"code\"\n type=\"text\"\n value={code}\n onChange={(e) => setCode(e.target.value)}\n placeholder={t(\"codePlaceholder\", \"Enter 6-digit code\")}\n required\n className=\"mt-1\"\n maxLength={6}\n />\n </FormField>\n\n {error && (\n <div className=\"p-4 bg-red-50 border border-red-200 rounded-lg\">\n <p className=\"text-red-800 text-sm font-medium\">\n {error}\n </p>\n </div>\n )}\n\n <Button\n type=\"submit\"\n size=\"lg\"\n className=\"w-full\"\n disabled={isSubmitting}\n >\n {isSubmitting ? (\n <>\n <div className=\"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2\" />\n {t(\"verifying\", \"Verifying...\")}\n </>\n ) : (\n t(\"verifyEmail\", \"Verify Email\")\n )}\n </Button>\n\n <div className=\"flex justify-between\">\n <button\n type=\"button\"\n onClick={() => {\n setStep(\"request\");\n setCode(\"\");\n setError(null);\n }}\n className=\"text-sm text-muted-foreground hover:text-primary\"\n >\n {t(\"changeUsername\", \"Change username\")}\n </button>\n <button\n type=\"button\"\n onClick={() =>\n handleSendCode({\n preventDefault: () => {},\n } as React.FormEvent)\n }\n className=\"text-sm text-primary hover:underline\"\n disabled={isSubmitting}\n >\n {t(\"resendCode\", \"Resend code\")}\n </button>\n </div>\n </form>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n </Layout>\n );\n}\n\nexport default VerifyEmailPage;\n"
27
27
  },
28
28
  {
29
29
  "path": "verify-email-page/lang/en.json",
30
30
  "type": "registry:lang",
31
31
  "target": "$modules$/verify-email-page/lang/en.json",
32
- "content": "{\r\n \"title\": \"Verify Email\",\r\n \"descriptionRequest\": \"Enter your username and we'll send you a verification code.\",\r\n \"descriptionVerify\": \"Enter the verification code sent to your email.\",\r\n \"cardTitleRequest\": \"Request Verification Code\",\r\n \"cardTitleVerify\": \"Enter Verification Code\",\r\n \"cardDescRequest\": \"Step 1 of 2: Request a verification code\",\r\n \"cardDescVerify\": \"Step 2 of 2: Enter the code to verify your email\",\r\n \"username\": \"Username\",\r\n \"usernamePlaceholder\": \"Enter your username\",\r\n \"code\": \"Verification Code\",\r\n \"codePlaceholder\": \"Enter 6-digit code\",\r\n \"sendCode\": \"Send Verification Code\",\r\n \"sending\": \"Sending...\",\r\n \"verifyEmail\": \"Verify Email\",\r\n \"verifying\": \"Verifying...\",\r\n \"codeSentTitle\": \"Code Sent!\",\r\n \"codeSentDesc\": \"A verification code has been sent to your email.\",\r\n \"verifiedTitle\": \"Email Verified!\",\r\n \"verifiedDesc\": \"Your email has been successfully verified.\",\r\n \"errorTitle\": \"Error\",\r\n \"errorSendGeneric\": \"Failed to send verification code. Please try again.\",\r\n \"errorVerifyGeneric\": \"Failed to verify email. Please check your code and try again.\",\r\n \"successTitle\": \"Email Verified!\",\r\n \"successDescription\": \"Your email has been verified. You can now login to your account.\",\r\n \"goToLogin\": \"Go to Login\",\r\n \"codeFor\": \"Verification code for:\",\r\n \"changeUsername\": \"Change username\",\r\n \"resendCode\": \"Resend code\",\r\n \"backToLogin\": \"Back to Login\"\r\n}\r\n"
32
+ "content": "{\n \"title\": \"Verify Email\",\n \"descriptionRequest\": \"Enter your username and we'll send you a verification code.\",\n \"descriptionVerify\": \"Enter the verification code sent to your email.\",\n \"cardTitleRequest\": \"Request Verification Code\",\n \"cardTitleVerify\": \"Enter Verification Code\",\n \"cardDescRequest\": \"Step 1 of 2: Request a verification code\",\n \"cardDescVerify\": \"Step 2 of 2: Enter the code to verify your email\",\n \"username\": \"Username\",\n \"usernamePlaceholder\": \"Enter your username\",\n \"code\": \"Verification Code\",\n \"codePlaceholder\": \"Enter 6-digit code\",\n \"sendCode\": \"Send Verification Code\",\n \"sending\": \"Sending...\",\n \"verifyEmail\": \"Verify Email\",\n \"verifying\": \"Verifying...\",\n \"codeSentTitle\": \"Code Sent!\",\n \"codeSentDesc\": \"A verification code has been sent to your email.\",\n \"verifiedTitle\": \"Email Verified!\",\n \"verifiedDesc\": \"Your email has been successfully verified.\",\n \"errorTitle\": \"Error\",\n \"errorSendGeneric\": \"Failed to send verification code. Please try again.\",\n \"errorVerifyGeneric\": \"Failed to verify email. Please check your code and try again.\",\n \"successTitle\": \"Email Verified!\",\n \"successDescription\": \"Your email has been verified. You can now login to your account.\",\n \"goToLogin\": \"Go to Login\",\n \"codeFor\": \"Verification code for:\",\n \"changeUsername\": \"Change username\",\n \"resendCode\": \"Resend code\",\n \"backToLogin\": \"Back to Login\"\n}\n"
33
33
  },
34
34
  {
35
35
  "path": "verify-email-page/lang/tr.json",
36
36
  "type": "registry:lang",
37
37
  "target": "$modules$/verify-email-page/lang/tr.json",
38
- "content": "{\r\n \"title\": \"E-posta Doğrulama\",\r\n \"descriptionRequest\": \"Kullanıcı adınızı girin, size bir doğrulama kodu göndereceğiz.\",\r\n \"descriptionVerify\": \"E-postanıza gönderilen doğrulama kodunu girin.\",\r\n \"cardTitleRequest\": \"Doğrulama Kodu İste\",\r\n \"cardTitleVerify\": \"Doğrulama Kodunu Gir\",\r\n \"cardDescRequest\": \"Adım 1/2: Doğrulama kodu isteyin\",\r\n \"cardDescVerify\": \"Adım 2/2: E-postanızı doğrulamak için kodu girin\",\r\n \"username\": \"Kullanıcı Adı\",\r\n \"usernamePlaceholder\": \"Kullanıcı adınızı girin\",\r\n \"code\": \"Doğrulama Kodu\",\r\n \"codePlaceholder\": \"6 haneli kodu girin\",\r\n \"sendCode\": \"Doğrulama Kodu Gönder\",\r\n \"sending\": \"Gönderiliyor...\",\r\n \"verifyEmail\": \"E-postayı Doğrula\",\r\n \"verifying\": \"Doğrulanıyor...\",\r\n \"codeSentTitle\": \"Kod Gönderildi!\",\r\n \"codeSentDesc\": \"E-posta adresinize bir doğrulama kodu gönderildi.\",\r\n \"verifiedTitle\": \"E-posta Doğrulandı!\",\r\n \"verifiedDesc\": \"E-postanız başarıyla doğrulandı.\",\r\n \"errorTitle\": \"Hata\",\r\n \"errorSendGeneric\": \"Doğrulama kodu gönderilemedi. Lütfen tekrar deneyin.\",\r\n \"errorVerifyGeneric\": \"E-posta doğrulanamadı. Lütfen kodunuzu kontrol edip tekrar deneyin.\",\r\n \"successTitle\": \"E-posta Doğrulandı!\",\r\n \"successDescription\": \"E-postanız doğrulandı. Artık hesabınıza giriş yapabilirsiniz.\",\r\n \"goToLogin\": \"Girişe Git\",\r\n \"codeFor\": \"Doğrulama kodu:\",\r\n \"changeUsername\": \"Kullanıcı adını değiştir\",\r\n \"resendCode\": \"Kodu tekrar gönder\",\r\n \"backToLogin\": \"Girişe Dön\"\r\n}\r\n"
38
+ "content": "{\n \"title\": \"E-posta Doğrulama\",\n \"descriptionRequest\": \"Kullanıcı adınızı girin, size bir doğrulama kodu göndereceğiz.\",\n \"descriptionVerify\": \"E-postanıza gönderilen doğrulama kodunu girin.\",\n \"cardTitleRequest\": \"Doğrulama Kodu İste\",\n \"cardTitleVerify\": \"Doğrulama Kodunu Gir\",\n \"cardDescRequest\": \"Adım 1/2: Doğrulama kodu isteyin\",\n \"cardDescVerify\": \"Adım 2/2: E-postanızı doğrulamak için kodu girin\",\n \"username\": \"Kullanıcı Adı\",\n \"usernamePlaceholder\": \"Kullanıcı adınızı girin\",\n \"code\": \"Doğrulama Kodu\",\n \"codePlaceholder\": \"6 haneli kodu girin\",\n \"sendCode\": \"Doğrulama Kodu Gönder\",\n \"sending\": \"Gönderiliyor...\",\n \"verifyEmail\": \"E-postayı Doğrula\",\n \"verifying\": \"Doğrulanıyor...\",\n \"codeSentTitle\": \"Kod Gönderildi!\",\n \"codeSentDesc\": \"E-posta adresinize bir doğrulama kodu gönderildi.\",\n \"verifiedTitle\": \"E-posta Doğrulandı!\",\n \"verifiedDesc\": \"E-postanız başarıyla doğrulandı.\",\n \"errorTitle\": \"Hata\",\n \"errorSendGeneric\": \"Doğrulama kodu gönderilemedi. Lütfen tekrar deneyin.\",\n \"errorVerifyGeneric\": \"E-posta doğrulanamadı. Lütfen kodunuzu kontrol edip tekrar deneyin.\",\n \"successTitle\": \"E-posta Doğrulandı!\",\n \"successDescription\": \"E-postanız doğrulandı. Artık hesabınıza giriş yapabilirsiniz.\",\n \"goToLogin\": \"Girişe Git\",\n \"codeFor\": \"Doğrulama kodu:\",\n \"changeUsername\": \"Kullanıcı adını değiştir\",\n \"resendCode\": \"Kodu tekrar gönder\",\n \"backToLogin\": \"Girişe Dön\"\n}\n"
39
39
  }
40
40
  ],
41
41
  "exports": {
@@ -12,25 +12,25 @@
12
12
  "path": "video-hero/index.ts",
13
13
  "type": "registry:index",
14
14
  "target": "$modules$/video-hero/index.ts",
15
- "content": "export { VideoHero } from \"./video-hero\";\r\n"
15
+ "content": "export { VideoHero } from \"./video-hero\";\n"
16
16
  },
17
17
  {
18
18
  "path": "video-hero/video-hero.tsx",
19
19
  "type": "registry:block",
20
20
  "target": "$modules$/video-hero/video-hero.tsx",
21
- "content": "import { Link } from \"react-router\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { Play, ArrowRight } from \"lucide-react\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { FadeIn } from \"@/modules/animations\";\r\n\r\ninterface VideoHeroProps {\r\n videoSrc?: string;\r\n posterSrc?: string;\r\n className?: string;\r\n}\r\n\r\nexport function VideoHero({\r\n videoSrc = \"https://assets.mixkit.co/videos/preview/mixkit-clouds-and-blue-sky-2408-large.mp4\",\r\n posterSrc = \"/images/placeholder.png\",\r\n className,\r\n}: VideoHeroProps) {\r\n const { t } = useTranslation(\"video-hero\");\r\n\r\n return (\r\n <section className={cn(\"relative min-h-[600px] md:min-h-[700px] lg:min-h-screen flex items-center overflow-hidden\", className)}>\r\n {/* Video Background */}\r\n <div className=\"absolute inset-0 z-0\">\r\n <video\r\n autoPlay\r\n muted\r\n loop\r\n playsInline\r\n poster={posterSrc}\r\n className=\"w-full h-full object-cover\"\r\n >\r\n <source src={videoSrc} type=\"video/mp4\" />\r\n </video>\r\n {/* Overlay */}\r\n <div className=\"absolute inset-0 bg-gradient-to-r from-background/95 via-background/80 to-background/60\" />\r\n <div className=\"absolute inset-0 bg-gradient-to-t from-background via-transparent to-transparent\" />\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"relative z-10 w-full max-w-[var(--container-max-width)] mx-auto px-4 py-20\">\r\n <div className=\"max-w-2xl\">\r\n <FadeIn>\r\n <span className=\"inline-flex items-center gap-2 px-4 py-2 rounded-full bg-primary/10 border border-primary/20 text-primary text-sm font-medium mb-6\">\r\n <Play className=\"h-4 w-4\" />\r\n {t(\"badge\", \"Watch the Story\")}\r\n </span>\r\n </FadeIn>\r\n\r\n <FadeIn delay={0.1}>\r\n <h1 className=\"text-4xl md:text-5xl lg:text-6xl xl:text-7xl font-bold text-foreground mb-6 leading-tight\">\r\n {t(\"heading\", \"Experience the Future of Innovation\")}\r\n </h1>\r\n </FadeIn>\r\n\r\n <FadeIn delay={0.2}>\r\n <p className=\"text-lg md:text-xl text-muted-foreground mb-8 max-w-xl\">\r\n {t(\"description\", \"Discover how our cutting-edge solutions are transforming industries and creating new possibilities for businesses worldwide.\")}\r\n </p>\r\n </FadeIn>\r\n\r\n <FadeIn delay={0.3}>\r\n <div className=\"flex flex-col sm:flex-row gap-4\">\r\n <Button asChild size=\"lg\" className=\"text-base\">\r\n <Link to=\"/register\">\r\n {t(\"primaryCta\", \"Get Started\")}\r\n <ArrowRight className=\"ml-2 h-5 w-5\" />\r\n </Link>\r\n </Button>\r\n <Button asChild variant=\"outline\" size=\"lg\" className=\"text-base bg-background/50 backdrop-blur-sm\">\r\n <Link to=\"/about\">\r\n {t(\"secondaryCta\", \"Learn More\")}\r\n </Link>\r\n </Button>\r\n </div>\r\n </FadeIn>\r\n\r\n {/* Stats */}\r\n <FadeIn delay={0.4}>\r\n <div className=\"flex flex-wrap gap-8 mt-12 pt-8 border-t border-border/50\">\r\n <div>\r\n <div className=\"text-3xl md:text-4xl font-bold text-foreground\">10K+</div>\r\n <div className=\"text-sm text-muted-foreground\">{t(\"stat1\", \"Active Users\")}</div>\r\n </div>\r\n <div>\r\n <div className=\"text-3xl md:text-4xl font-bold text-foreground\">98%</div>\r\n <div className=\"text-sm text-muted-foreground\">{t(\"stat2\", \"Satisfaction\")}</div>\r\n </div>\r\n <div>\r\n <div className=\"text-3xl md:text-4xl font-bold text-foreground\">24/7</div>\r\n <div className=\"text-sm text-muted-foreground\">{t(\"stat3\", \"Support\")}</div>\r\n </div>\r\n </div>\r\n </FadeIn>\r\n </div>\r\n </div>\r\n\r\n </section>\r\n );\r\n}\r\n"
21
+ "content": "import { Link } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\nimport { Play, ArrowRight } from \"lucide-react\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport { FadeIn } from \"@/modules/animations\";\n\ninterface VideoHeroProps {\n videoSrc?: string;\n posterSrc?: string;\n className?: string;\n}\n\nexport function VideoHero({\n videoSrc = \"https://assets.mixkit.co/videos/preview/mixkit-clouds-and-blue-sky-2408-large.mp4\",\n posterSrc = \"/images/placeholder.png\",\n className,\n}: VideoHeroProps) {\n const { t } = useTranslation(\"video-hero\");\n\n return (\n <section className={cn(\"relative min-h-[600px] md:min-h-[700px] lg:min-h-screen flex items-center overflow-hidden\", className)}>\n {/* Video Background */}\n <div className=\"absolute inset-0 z-0\">\n <video\n autoPlay\n muted\n loop\n playsInline\n poster={posterSrc}\n className=\"w-full h-full object-cover\"\n >\n <source src={videoSrc} type=\"video/mp4\" />\n </video>\n {/* Overlay */}\n <div className=\"absolute inset-0 bg-gradient-to-r from-background/95 via-background/80 to-background/60\" />\n <div className=\"absolute inset-0 bg-gradient-to-t from-background via-transparent to-transparent\" />\n </div>\n\n {/* Content */}\n <div className=\"relative z-10 w-full max-w-[var(--container-max-width)] mx-auto px-4 py-20\">\n <div className=\"max-w-2xl\">\n <FadeIn>\n <span className=\"inline-flex items-center gap-2 px-4 py-2 rounded-full bg-primary/10 border border-primary/20 text-primary text-sm font-medium mb-6\">\n <Play className=\"h-4 w-4\" />\n {t(\"badge\", \"Watch the Story\")}\n </span>\n </FadeIn>\n\n <FadeIn delay={0.1}>\n <h1 className=\"text-4xl md:text-5xl lg:text-6xl xl:text-7xl font-bold text-foreground mb-6 leading-tight\">\n {t(\"heading\", \"Experience the Future of Innovation\")}\n </h1>\n </FadeIn>\n\n <FadeIn delay={0.2}>\n <p className=\"text-lg md:text-xl text-muted-foreground mb-8 max-w-xl\">\n {t(\"description\", \"Discover how our cutting-edge solutions are transforming industries and creating new possibilities for businesses worldwide.\")}\n </p>\n </FadeIn>\n\n <FadeIn delay={0.3}>\n <div className=\"flex flex-col sm:flex-row gap-4\">\n <Button asChild size=\"lg\" className=\"text-base\">\n <Link to=\"/register\">\n {t(\"primaryCta\", \"Get Started\")}\n <ArrowRight className=\"ml-2 h-5 w-5\" />\n </Link>\n </Button>\n <Button asChild variant=\"outline\" size=\"lg\" className=\"text-base bg-background/50 backdrop-blur-sm\">\n <Link to=\"/about\">\n {t(\"secondaryCta\", \"Learn More\")}\n </Link>\n </Button>\n </div>\n </FadeIn>\n\n {/* Stats */}\n <FadeIn delay={0.4}>\n <div className=\"flex flex-wrap gap-8 mt-12 pt-8 border-t border-border/50\">\n <div>\n <div className=\"text-3xl md:text-4xl font-bold text-foreground\">10K+</div>\n <div className=\"text-sm text-muted-foreground\">{t(\"stat1\", \"Active Users\")}</div>\n </div>\n <div>\n <div className=\"text-3xl md:text-4xl font-bold text-foreground\">98%</div>\n <div className=\"text-sm text-muted-foreground\">{t(\"stat2\", \"Satisfaction\")}</div>\n </div>\n <div>\n <div className=\"text-3xl md:text-4xl font-bold text-foreground\">24/7</div>\n <div className=\"text-sm text-muted-foreground\">{t(\"stat3\", \"Support\")}</div>\n </div>\n </div>\n </FadeIn>\n </div>\n </div>\n\n </section>\n );\n}\n"
22
22
  },
23
23
  {
24
24
  "path": "video-hero/lang/en.json",
25
25
  "type": "registry:lang",
26
26
  "target": "$modules$/video-hero/lang/en.json",
27
- "content": "{\r\n \"badge\": \"Watch the Story\",\r\n \"heading\": \"Your Headline Here\",\r\n \"description\": \"This text appears over your video background. It should be concise yet compelling, clearly stating your value proposition. Use Promake to craft a message that works well with your video content.\",\r\n \"primaryCta\": \"Get Started\",\r\n \"secondaryCta\": \"Learn More\",\r\n \"stat1\": \"Active Users\",\r\n \"stat2\": \"Satisfaction\",\r\n \"stat3\": \"Support\"\r\n}\r\n"
27
+ "content": "{\n \"badge\": \"Watch the Story\",\n \"heading\": \"Your Headline Here\",\n \"description\": \"This text appears over your video background. It should be concise yet compelling, clearly stating your value proposition. Use Promake to craft a message that works well with your video content.\",\n \"primaryCta\": \"Get Started\",\n \"secondaryCta\": \"Learn More\",\n \"stat1\": \"Active Users\",\n \"stat2\": \"Satisfaction\",\n \"stat3\": \"Support\"\n}\n"
28
28
  },
29
29
  {
30
30
  "path": "video-hero/lang/tr.json",
31
31
  "type": "registry:lang",
32
32
  "target": "$modules$/video-hero/lang/tr.json",
33
- "content": "{\r\n \"badge\": \"Hikayeyi İzle\",\r\n \"heading\": \"İnovasyonun Geleceğini Deneyimleyin\",\r\n \"description\": \"Bu metin video arka planınızın üzerinde görünür. Kısa ama etkili olmalı, değer önerinizi net bir şekilde belirtmelidir. Promake ile video içeriğinizle uyumlu bir mesaj oluşturun.\",\r\n \"primaryCta\": \"Başlayın\",\r\n \"secondaryCta\": \"Daha Fazla Bilgi\",\r\n \"stat1\": \"Aktif Kullanıcı\",\r\n \"stat2\": \"Memnuniyet\",\r\n \"stat3\": \"Destek\"\r\n}\r\n"
33
+ "content": "{\n \"badge\": \"Hikayeyi İzle\",\n \"heading\": \"İnovasyonun Geleceğini Deneyimleyin\",\n \"description\": \"Bu metin video arka planınızın üzerinde görünür. Kısa ama etkili olmalı, değer önerinizi net bir şekilde belirtmelidir. Promake ile video içeriğinizle uyumlu bir mesaj oluşturun.\",\n \"primaryCta\": \"Başlayın\",\n \"secondaryCta\": \"Daha Fazla Bilgi\",\n \"stat1\": \"Aktif Kullanıcı\",\n \"stat2\": \"Memnuniyet\",\n \"stat3\": \"Destek\"\n}\n"
34
34
  }
35
35
  ],
36
36
  "exports": {
@@ -10,25 +10,25 @@
10
10
  "path": "youtube-embed/index.ts",
11
11
  "type": "registry:index",
12
12
  "target": "$modules$/youtube-embed/index.ts",
13
- "content": "export * from './youtube-embed';\r\n"
13
+ "content": "export * from './youtube-embed';\n"
14
14
  },
15
15
  {
16
16
  "path": "youtube-embed/youtube-embed.tsx",
17
17
  "type": "registry:component",
18
18
  "target": "$modules$/youtube-embed/youtube-embed.tsx",
19
- "content": "import { useState } from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Play } from \"lucide-react\";\r\n\r\ninterface YouTubeEmbedProps {\r\n videoId: string;\r\n title?: string;\r\n autoplay?: boolean;\r\n mute?: boolean;\r\n loop?: boolean;\r\n controls?: boolean;\r\n start?: number;\r\n aspectRatio?: \"16/9\" | \"4/3\" | \"1/1\";\r\n className?: string;\r\n}\r\n\r\nexport function YouTubeEmbed({\r\n videoId,\r\n title,\r\n autoplay = false,\r\n mute = false,\r\n loop = false,\r\n controls = true,\r\n start,\r\n aspectRatio = \"16/9\",\r\n className,\r\n}: YouTubeEmbedProps) {\r\n const { t } = useTranslation(\"youtube-embed\");\r\n const [isLoading, setIsLoading] = useState(true);\r\n const [hasError, setHasError] = useState(false);\r\n\r\n // Validate videoId\r\n const isValidVideoId = /^[a-zA-Z0-9_-]{11}$/.test(videoId);\r\n\r\n // Build embed URL with parameters\r\n const buildEmbedUrl = () => {\r\n const params = new URLSearchParams();\r\n\r\n if (autoplay) params.set(\"autoplay\", \"1\");\r\n if (mute) params.set(\"mute\", \"1\");\r\n if (loop) {\r\n params.set(\"loop\", \"1\");\r\n params.set(\"playlist\", videoId);\r\n }\r\n if (!controls) params.set(\"controls\", \"0\");\r\n if (start) params.set(\"start\", start.toString());\r\n\r\n params.set(\"rel\", \"0\");\r\n\r\n const queryString = params.toString();\r\n return `https://www.youtube.com/embed/${videoId}${queryString ? `?${queryString}` : \"\"}`;\r\n };\r\n\r\n const handleLoad = () => {\r\n setIsLoading(false);\r\n };\r\n\r\n const handleError = () => {\r\n setIsLoading(false);\r\n setHasError(true);\r\n };\r\n\r\n // Invalid videoId\r\n if (!isValidVideoId) {\r\n return (\r\n <div\r\n className={cn(\r\n \"flex flex-col items-center justify-center bg-muted rounded-lg border\",\r\n className\r\n )}\r\n style={{ aspectRatio }}\r\n >\r\n <Play className=\"h-12 w-12 text-muted-foreground mb-3\" />\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"invalidId\", \"Invalid video ID\")}\r\n </p>\r\n </div>\r\n );\r\n }\r\n\r\n // Error state\r\n if (hasError) {\r\n return (\r\n <div\r\n className={cn(\r\n \"flex flex-col items-center justify-center bg-muted rounded-lg border\",\r\n className\r\n )}\r\n style={{ aspectRatio }}\r\n >\r\n <Play className=\"h-12 w-12 text-muted-foreground mb-3\" />\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t(\"error\", \"Failed to load video\")}\r\n </p>\r\n <a\r\n href={`https://www.youtube.com/watch?v=${videoId}`}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"text-sm text-primary hover:underline mt-2\"\r\n >\r\n {t(\"watchOnYouTube\", \"Watch on YouTube\")}\r\n </a>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n className={cn(\"relative rounded-lg overflow-hidden\", className)}\r\n style={{ aspectRatio }}\r\n >\r\n {isLoading && (\r\n <div className=\"absolute inset-0 flex items-center justify-center bg-muted\">\r\n <div className=\"flex flex-col items-center gap-3\">\r\n <div className=\"h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent\" />\r\n <span className=\"text-sm text-muted-foreground\">\r\n {t(\"loading\", \"Loading video...\")}\r\n </span>\r\n </div>\r\n </div>\r\n )}\r\n <iframe\r\n src={buildEmbedUrl()}\r\n width=\"100%\"\r\n height=\"100%\"\r\n style={{ border: 0 }}\r\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\r\n allowFullScreen\r\n loading=\"lazy\"\r\n title={title || t(\"defaultTitle\", \"YouTube video player\")}\r\n onLoad={handleLoad}\r\n onError={handleError}\r\n className={cn(\"absolute inset-0\", isLoading && \"invisible\")}\r\n />\r\n </div>\r\n );\r\n}\r\n"
19
+ "content": "import { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { cn } from \"@/lib/utils\";\nimport { Play } from \"lucide-react\";\n\ninterface YouTubeEmbedProps {\n videoId: string;\n title?: string;\n autoplay?: boolean;\n mute?: boolean;\n loop?: boolean;\n controls?: boolean;\n start?: number;\n aspectRatio?: \"16/9\" | \"4/3\" | \"1/1\";\n className?: string;\n}\n\nexport function YouTubeEmbed({\n videoId,\n title,\n autoplay = false,\n mute = false,\n loop = false,\n controls = true,\n start,\n aspectRatio = \"16/9\",\n className,\n}: YouTubeEmbedProps) {\n const { t } = useTranslation(\"youtube-embed\");\n const [isLoading, setIsLoading] = useState(true);\n const [hasError, setHasError] = useState(false);\n\n // Validate videoId\n const isValidVideoId = /^[a-zA-Z0-9_-]{11}$/.test(videoId);\n\n // Build embed URL with parameters\n const buildEmbedUrl = () => {\n const params = new URLSearchParams();\n\n if (autoplay) params.set(\"autoplay\", \"1\");\n if (mute) params.set(\"mute\", \"1\");\n if (loop) {\n params.set(\"loop\", \"1\");\n params.set(\"playlist\", videoId);\n }\n if (!controls) params.set(\"controls\", \"0\");\n if (start) params.set(\"start\", start.toString());\n\n params.set(\"rel\", \"0\");\n\n const queryString = params.toString();\n return `https://www.youtube.com/embed/${videoId}${queryString ? `?${queryString}` : \"\"}`;\n };\n\n const handleLoad = () => {\n setIsLoading(false);\n };\n\n const handleError = () => {\n setIsLoading(false);\n setHasError(true);\n };\n\n // Invalid videoId\n if (!isValidVideoId) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center bg-muted rounded-lg border\",\n className\n )}\n style={{ aspectRatio }}\n >\n <Play className=\"h-12 w-12 text-muted-foreground mb-3\" />\n <p className=\"text-sm text-muted-foreground\">\n {t(\"invalidId\", \"Invalid video ID\")}\n </p>\n </div>\n );\n }\n\n // Error state\n if (hasError) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center bg-muted rounded-lg border\",\n className\n )}\n style={{ aspectRatio }}\n >\n <Play className=\"h-12 w-12 text-muted-foreground mb-3\" />\n <p className=\"text-sm text-muted-foreground\">\n {t(\"error\", \"Failed to load video\")}\n </p>\n <a\n href={`https://www.youtube.com/watch?v=${videoId}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-primary hover:underline mt-2\"\n >\n {t(\"watchOnYouTube\", \"Watch on YouTube\")}\n </a>\n </div>\n );\n }\n\n return (\n <div\n className={cn(\"relative rounded-lg overflow-hidden\", className)}\n style={{ aspectRatio }}\n >\n {isLoading && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-muted\">\n <div className=\"flex flex-col items-center gap-3\">\n <div className=\"h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent\" />\n <span className=\"text-sm text-muted-foreground\">\n {t(\"loading\", \"Loading video...\")}\n </span>\n </div>\n </div>\n )}\n <iframe\n src={buildEmbedUrl()}\n width=\"100%\"\n height=\"100%\"\n style={{ border: 0 }}\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowFullScreen\n loading=\"lazy\"\n title={title || t(\"defaultTitle\", \"YouTube video player\")}\n onLoad={handleLoad}\n onError={handleError}\n className={cn(\"absolute inset-0\", isLoading && \"invisible\")}\n />\n </div>\n );\n}\n"
20
20
  },
21
21
  {
22
22
  "path": "youtube-embed/lang/en.json",
23
23
  "type": "registry:lang",
24
24
  "target": "$modules$/youtube-embed/lang/en.json",
25
- "content": "{\r\n \"loading\": \"Loading video...\",\r\n \"error\": \"Failed to load video\",\r\n \"invalidId\": \"Invalid video ID\",\r\n \"watchOnYouTube\": \"Watch on YouTube\",\r\n \"defaultTitle\": \"YouTube video player\"\r\n}\r\n"
25
+ "content": "{\n \"loading\": \"Loading video...\",\n \"error\": \"Failed to load video\",\n \"invalidId\": \"Invalid video ID\",\n \"watchOnYouTube\": \"Watch on YouTube\",\n \"defaultTitle\": \"YouTube video player\"\n}\n"
26
26
  },
27
27
  {
28
28
  "path": "youtube-embed/lang/tr.json",
29
29
  "type": "registry:lang",
30
30
  "target": "$modules$/youtube-embed/lang/tr.json",
31
- "content": "{\r\n \"loading\": \"Video yükleniyor...\",\r\n \"error\": \"Video yüklenemedi\",\r\n \"invalidId\": \"Geçersiz video ID\",\r\n \"watchOnYouTube\": \"YouTube'da izle\",\r\n \"defaultTitle\": \"YouTube video oynatıcı\"\r\n}\r\n"
31
+ "content": "{\n \"loading\": \"Video yükleniyor...\",\n \"error\": \"Video yüklenemedi\",\n \"invalidId\": \"Geçersiz video ID\",\n \"watchOnYouTube\": \"YouTube'da izle\",\n \"defaultTitle\": \"YouTube video oynatıcı\"\n}\n"
32
32
  }
33
33
  ],
34
34
  "exports": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promakeai/cli",
3
- "version": "0.9.9",
3
+ "version": "0.9.10",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "promake": "dist/index.js"
package/template/.env CHANGED
@@ -1,6 +1,6 @@
1
- VITE_TENANT_UUID=""
2
- VITE_MAIL_SERVICE_URL="https://mail.promake.ai/api/v1/send-mail"
3
- VITE_TENANT_MAIL=""
4
- VITE_ONLINE_PAYMENT_METHODS="stripe,iyzico"
5
- VITE_AVAILABLE_PAYMENT_METHODS="card,transfer,cash"
1
+ VITE_TENANT_UUID=""
2
+ VITE_MAIL_SERVICE_URL="https://mail.promake.ai/api/v1/send-mail"
3
+ VITE_TENANT_MAIL=""
4
+ VITE_ONLINE_PAYMENT_METHODS="stripe,iyzico"
5
+ VITE_AVAILABLE_PAYMENT_METHODS="card,transfer,cash"
6
6
  VITE_PROMAKE_ENV="testb"
@@ -1,54 +1,54 @@
1
- # Promake React Template
2
-
3
- This template is the runtime target for `@promakeai/cli`. It includes a
4
- multi-language, schema-driven database setup powered by `@promakeai/dbreact`.
5
-
6
- ## What You Get
7
-
8
- - Vite + React + TypeScript
9
- - Module-based architecture (`src/modules`)
10
- - Built-in DB layer via `@/db` (dbreact hooks + schema)
11
- - Multi-language content with translation fallback
12
-
13
- ## Database Layout
14
-
15
- - Schema: `src/db/schema.json`
16
- - Types: `src/db/types.ts`
17
- - Provider: `src/db/provider.tsx`
18
- - DB file: `public/data/database.db`
19
-
20
- The app wraps your UI with `AppDbProvider` in `src/App.tsx` and syncs DB language
21
- with i18n.
22
-
23
- ## Regenerate Database
24
-
25
- ```bash
26
- # From schema.json
27
- dbcli generate --schema ./src/db/schema.json \
28
- --database ./public/data/database.db \
29
- --output ./src/db
30
- ```
31
-
32
- Or run the helper:
33
-
34
- ```bash
35
- bun run init-db
36
- ```
37
-
38
- ## Using the DB in Modules
39
-
40
- ```tsx
41
- import { useDbList } from "@/db";
42
- import type { DbProduct } from "@/db";
43
-
44
- const { data: products } = useDbList<DbProduct>("products", {
45
- where: { price: { $gt: 50 } },
46
- limit: 12,
47
- });
48
- ```
49
-
50
- ## Language Behavior
51
-
52
- - `defaultLanguage` is defined in `schema.json`.
53
- - `DbProvider` uses `lang` + `fallbackLang` for translation resolution.
54
- - Changing i18n language triggers refetch of db queries.
1
+ # Promake React Template
2
+
3
+ This template is the runtime target for `@promakeai/cli`. It includes a
4
+ multi-language, schema-driven database setup powered by `@promakeai/dbreact`.
5
+
6
+ ## What You Get
7
+
8
+ - Vite + React + TypeScript
9
+ - Module-based architecture (`src/modules`)
10
+ - Built-in DB layer via `@/db` (dbreact hooks + schema)
11
+ - Multi-language content with translation fallback
12
+
13
+ ## Database Layout
14
+
15
+ - Schema: `src/db/schema.json`
16
+ - Types: `src/db/types.ts`
17
+ - Provider: `src/db/provider.tsx`
18
+ - DB file: `public/data/database.db`
19
+
20
+ The app wraps your UI with `AppDbProvider` in `src/App.tsx` and syncs DB language
21
+ with i18n.
22
+
23
+ ## Regenerate Database
24
+
25
+ ```bash
26
+ # From schema.json
27
+ dbcli generate --schema ./src/db/schema.json \
28
+ --database ./public/data/database.db \
29
+ --output ./src/db
30
+ ```
31
+
32
+ Or run the helper:
33
+
34
+ ```bash
35
+ bun run init-db
36
+ ```
37
+
38
+ ## Using the DB in Modules
39
+
40
+ ```tsx
41
+ import { useDbList } from "@/db";
42
+ import type { DbProduct } from "@/db";
43
+
44
+ const { data: products } = useDbList<DbProduct>("products", {
45
+ where: { price: { $gt: 50 } },
46
+ limit: 12,
47
+ });
48
+ ```
49
+
50
+ ## Language Behavior
51
+
52
+ - `defaultLanguage` is defined in `schema.json`.
53
+ - `DbProvider` uses `lang` + `fallbackLang` for translation resolution.
54
+ - Changing i18n language triggers refetch of db queries.
@@ -1,41 +1,41 @@
1
- import js from '@eslint/js';
2
- import globals from 'globals';
3
- import reactHooks from 'eslint-plugin-react-hooks';
4
- import reactRefresh from 'eslint-plugin-react-refresh';
5
- import tseslint from 'typescript-eslint';
6
- import { defineConfig, globalIgnores } from 'eslint/config';
7
- import eslintConfigPrettier from 'eslint-config-prettier/flat';
8
-
9
- export default defineConfig([
10
- globalIgnores(['dist']),
11
- {
12
- files: ['**/*.{ts,tsx}'],
13
- extends: [
14
- js.configs.recommended,
15
- tseslint.configs.recommended,
16
- reactHooks.configs.flat.recommended,
17
- reactRefresh.configs.vite,
18
- eslintConfigPrettier,
19
- ],
20
- languageOptions: {
21
- ecmaVersion: 2020,
22
- globals: globals.browser,
23
- },
24
- rules: {
25
- '@typescript-eslint/consistent-type-imports': ['warn', {
26
- prefer: 'type-imports',
27
- fixStyle: 'inline-type-imports',
28
- }],
29
- '@typescript-eslint/no-explicit-any': 'off',
30
- '@typescript-eslint/no-unused-vars': 'off',
31
- '@typescript-eslint/no-unused-expressions': 'off',
32
- 'react-refresh/only-export-components': 'off',
33
- 'react-hooks/purity': 'off',
34
- 'react-hooks/exhaustive-deps': 'off',
35
- 'react-hooks/set-state-in-effect': 'off',
36
- 'no-unused-vars': 'off',
37
- 'prefer-const': 'warn',
38
- '@typescript-eslint/no-empty-object-type': 'off',
39
- },
40
- },
41
- ]);
1
+ import js from '@eslint/js';
2
+ import globals from 'globals';
3
+ import reactHooks from 'eslint-plugin-react-hooks';
4
+ import reactRefresh from 'eslint-plugin-react-refresh';
5
+ import tseslint from 'typescript-eslint';
6
+ import { defineConfig, globalIgnores } from 'eslint/config';
7
+ import eslintConfigPrettier from 'eslint-config-prettier/flat';
8
+
9
+ export default defineConfig([
10
+ globalIgnores(['dist']),
11
+ {
12
+ files: ['**/*.{ts,tsx}'],
13
+ extends: [
14
+ js.configs.recommended,
15
+ tseslint.configs.recommended,
16
+ reactHooks.configs.flat.recommended,
17
+ reactRefresh.configs.vite,
18
+ eslintConfigPrettier,
19
+ ],
20
+ languageOptions: {
21
+ ecmaVersion: 2020,
22
+ globals: globals.browser,
23
+ },
24
+ rules: {
25
+ '@typescript-eslint/consistent-type-imports': ['warn', {
26
+ prefer: 'type-imports',
27
+ fixStyle: 'inline-type-imports',
28
+ }],
29
+ '@typescript-eslint/no-explicit-any': 'off',
30
+ '@typescript-eslint/no-unused-vars': 'off',
31
+ '@typescript-eslint/no-unused-expressions': 'off',
32
+ 'react-refresh/only-export-components': 'off',
33
+ 'react-hooks/purity': 'off',
34
+ 'react-hooks/exhaustive-deps': 'off',
35
+ 'react-hooks/set-state-in-effect': 'off',
36
+ 'no-unused-vars': 'off',
37
+ 'prefer-const': 'warn',
38
+ '@typescript-eslint/no-empty-object-type': 'off',
39
+ },
40
+ },
41
+ ]);