@promakeai/cli 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +209 -415
- package/dist/registry/about-page.json +3 -3
- package/dist/registry/about-section.json +4 -4
- package/dist/registry/animations.json +2 -2
- package/dist/registry/announcement-bar.json +4 -4
- package/dist/registry/api.json +1 -1
- package/dist/registry/auth-core.json +3 -3
- package/dist/registry/bento-grid-section.json +4 -4
- package/dist/registry/blog-core.json +5 -5
- package/dist/registry/blog-list-page.json +3 -3
- package/dist/registry/blog-section.json +4 -4
- package/dist/registry/cards-carousel-section.json +4 -4
- package/dist/registry/cart-drawer.json +3 -3
- package/dist/registry/cart-page.json +3 -3
- package/dist/registry/case-study-page.json +3 -3
- package/dist/registry/category-section.json +3 -3
- package/dist/registry/checkout-page.json +3 -3
- package/dist/registry/coming-soon-page-minimal.json +4 -4
- package/dist/registry/coming-soon-page.json +4 -4
- package/dist/registry/contact-info-grid.json +4 -4
- package/dist/registry/contact-page-centered.json +4 -4
- package/dist/registry/contact-page-split.json +4 -4
- package/dist/registry/contact-page.json +3 -3
- package/dist/registry/content-section.json +4 -4
- package/dist/registry/cookie-consent.json +4 -4
- package/dist/registry/cookies-page.json +3 -3
- package/dist/registry/cta-section.json +3 -3
- package/dist/registry/ecommerce-core.json +10 -10
- package/dist/registry/empty-page.json +3 -3
- package/dist/registry/faq-categorized.json +4 -4
- package/dist/registry/faq-simple.json +4 -4
- package/dist/registry/favorites-blog-block.json +1 -1
- package/dist/registry/favorites-blog-page.json +4 -4
- package/dist/registry/favorites-ecommerce-block.json +1 -1
- package/dist/registry/favorites-ecommerce-page.json +4 -4
- package/dist/registry/feature-section.json +3 -3
- package/dist/registry/featured-products.json +3 -3
- package/dist/registry/footer-detailed.json +4 -4
- package/dist/registry/footer-minimal.json +3 -3
- package/dist/registry/footer.json +3 -3
- package/dist/registry/forgot-password-page-split.json +4 -4
- package/dist/registry/forgot-password-page.json +4 -4
- package/dist/registry/google-adsense.json +4 -4
- package/dist/registry/google-map.json +2 -2
- package/dist/registry/header-centered-pill.json +4 -4
- package/dist/registry/header-ecommerce.json +3 -3
- package/dist/registry/header-mega.json +4 -4
- package/dist/registry/header-minimal.json +4 -4
- package/dist/registry/header-simple.json +3 -3
- package/dist/registry/hero-carousel.json +3 -3
- package/dist/registry/hero-cta.json +4 -4
- package/dist/registry/hero-gradient.json +4 -4
- package/dist/registry/hero-grid.json +4 -4
- package/dist/registry/hero-profile.json +3 -3
- package/dist/registry/hero.json +3 -3
- package/dist/registry/landing-page-app.json +3 -3
- package/dist/registry/landing-page-saas.json +3 -3
- package/dist/registry/login-page-split.json +4 -4
- package/dist/registry/login-page.json +4 -4
- package/dist/registry/logo-cloud.json +4 -4
- package/dist/registry/masonry-grid.json +3 -3
- package/dist/registry/my-orders-page.json +4 -4
- package/dist/registry/newsletter-section.json +4 -4
- package/dist/registry/order-card-compact.json +1 -1
- package/dist/registry/order-confirmation-page.json +4 -4
- package/dist/registry/order-detail-block.json +1 -1
- package/dist/registry/orders-list-block.json +1 -1
- package/dist/registry/payment-success-block.json +1 -1
- package/dist/registry/portfolio-page.json +4 -4
- package/dist/registry/post-card.json +3 -3
- package/dist/registry/post-detail-block.json +1 -1
- package/dist/registry/post-detail-page.json +4 -4
- package/dist/registry/pricing-card.json +3 -3
- package/dist/registry/pricing-page.json +4 -4
- package/dist/registry/pricing-section.json +4 -4
- package/dist/registry/privacy-page.json +3 -3
- package/dist/registry/product-card-detailed.json +4 -4
- package/dist/registry/product-card-hover.json +4 -4
- package/dist/registry/product-card.json +3 -3
- package/dist/registry/product-detail-block.json +1 -1
- package/dist/registry/product-detail-page.json +4 -4
- package/dist/registry/product-detail-section.json +4 -4
- package/dist/registry/product-quick-view.json +4 -4
- package/dist/registry/products-page.json +3 -3
- package/dist/registry/reading-progress.json +4 -4
- package/dist/registry/register-page-split.json +4 -4
- package/dist/registry/register-page.json +4 -4
- package/dist/registry/related-posts-block.json +1 -1
- package/dist/registry/related-products-block.json +1 -1
- package/dist/registry/reset-password-page-split.json +4 -4
- package/dist/registry/service-card.json +1 -1
- package/dist/registry/share-buttons.json +4 -4
- package/dist/registry/skill-card.json +1 -1
- package/dist/registry/team-page.json +4 -4
- package/dist/registry/terms-page.json +3 -3
- package/dist/registry/testimonials-carousel.json +4 -4
- package/dist/registry/testimonials-grid.json +4 -4
- package/dist/registry/timeline-section.json +4 -4
- package/dist/registry/video-hero.json +4 -4
- package/dist/registry/youtube-embed.json +4 -4
- package/package.json +2 -2
- package/template/.env +6 -6
- package/template/public/_redirects +1 -1
- package/template/public/robots.txt +14 -14
- package/template/src/components/GoogleAnalytics.tsx +34 -34
- package/template/src/components/LanguageSwitcher.tsx +53 -53
- package/template/src/components/ScriptInjector.tsx +62 -62
- package/template/src/lib/env.ts +19 -19
- package/template/src/router.tsx +14 -14
- package/template/src/vite-env.d.ts +1 -1
- package/dist/registry/auth.json +0 -70
- package/dist/registry/docs/reset-password-page.md +0 -36
- package/dist/registry/reset-password-page.json +0 -39
|
@@ -18,25 +18,25 @@
|
|
|
18
18
|
"path": "contact-page-split/index.ts",
|
|
19
19
|
"type": "registry:index",
|
|
20
20
|
"target": "$modules$/contact-page-split/index.ts",
|
|
21
|
-
"content": "export * from './contact-page-split';\
|
|
21
|
+
"content": "export * from './contact-page-split';\nexport { ContactPageSplit as default } from './contact-page-split';\n"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"path": "contact-page-split/contact-page-split.tsx",
|
|
25
25
|
"type": "registry:component",
|
|
26
26
|
"target": "$modules$/contact-page-split/contact-page-split.tsx",
|
|
27
|
-
"content": "import React, { useState } from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { Mail, Phone, MapPin, Clock } from \"lucide-react\";\r\nimport { Layout } from \"@/components/Layout\";\r\nimport { useApiService } from \"@/lib/api\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Textarea } from \"@/components/ui/textarea\";\r\nimport { Label } from \"@/components/ui/label\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport constants from \"@/constants/constants.json\";\r\n\r\ninterface ContactPageSplitProps {\r\n className?: string;\r\n}\r\n\r\nexport function ContactPageSplit({ className }: ContactPageSplitProps) {\r\n const { t } = useTranslation(\"contact-page-split\");\r\n usePageTitle({ title: t(\"pageTitle\", \"Contact Us\") });\r\n const apiService = useApiService();\r\n\r\n const [formData, setFormData] = useState({\r\n name: \"\",\r\n email: \"\",\r\n phone: \"\",\r\n message: \"\",\r\n });\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [submitStatus, setSubmitStatus] = useState<\"idle\" | \"success\" | \"error\">(\"idle\");\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setIsSubmitting(true);\r\n setSubmitStatus(\"idle\");\r\n\r\n try {\r\n await apiService.submitForm(\r\n formData,\r\n {\r\n email_subject1: \"Thank you for contacting us\",\r\n email_subject2: \"New Contact Form Submission\",\r\n fields: [\r\n { name: \"name\", required: true },\r\n { name: \"email\", required: true },\r\n { name: \"phone\", required: false },\r\n { name: \"message\", required: true },\r\n ],\r\n },\r\n constants.site.defaultLanguage\r\n );\r\n\r\n setSubmitStatus(\"success\");\r\n setFormData({ name: \"\", email: \"\", phone: \"\", message: \"\" });\r\n setTimeout(() => setSubmitStatus(\"idle\"), 5000);\r\n } catch {\r\n setSubmitStatus(\"error\");\r\n setTimeout(() => setSubmitStatus(\"idle\"), 5000);\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n };\r\n\r\n const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\r\n setFormData((prev) => ({ ...prev, [e.target.name]: e.target.value }));\r\n };\r\n\r\n return (\r\n <Layout>\r\n <div className={cn(\"min-h-[calc(100vh-200px)] py-8 md:py-12\", className)}>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\r\n <div className=\"grid lg:grid-cols-2 h-full rounded-xl overflow-hidden shadow-lg\">\r\n {/* Left Side - Info & Image */}\r\n <div className=\"relative bg-primary text-primary-foreground p-8 lg:p-12 flex flex-col justify-center\">\r\n {/* Background Pattern */}\r\n <div className=\"absolute inset-0 bg-[linear-gradient(to_right,rgba(255,255,255,0.1)_1px,transparent_1px),linear-gradient(to_bottom,rgba(255,255,255,0.1)_1px,transparent_1px)] bg-[size:4rem_4rem]\" />\r\n\r\n <div className=\"relative z-10 max-w-lg\">\r\n <h1 className=\"text-3xl lg:text-4xl font-bold mb-4\">\r\n {t(\"title\", \"Let's Start a Conversation\")}\r\n </h1>\r\n <p className=\"text-primary-foreground/80 mb-8\">\r\n {t(\"subtitle\", \"Have a project in mind? We'd love to hear about it. Get in touch and let's create something amazing together.\")}\r\n </p>\r\n\r\n <div className=\"space-y-6\">\r\n <div className=\"flex items-start gap-4\">\r\n <div className=\"w-10 h-10 rounded-full bg-primary-foreground/10 flex items-center justify-center flex-shrink-0\">\r\n <Mail className=\"h-5 w-5\" />\r\n </div>\r\n <div>\r\n <p className=\"font-semibold\">{t(\"emailLabel\", \"Email\")}</p>\r\n <p className=\"text-primary-foreground/70\">{constants.email || \"hello@example.com\"}</p>\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-start gap-4\">\r\n <div className=\"w-10 h-10 rounded-full bg-primary-foreground/10 flex items-center justify-center flex-shrink-0\">\r\n <Phone className=\"h-5 w-5\" />\r\n </div>\r\n <div>\r\n <p className=\"font-semibold\">{t(\"phoneLabel\", \"Phone\")}</p>\r\n <p className=\"text-primary-foreground/70\">{constants.phone || \"+1 234 567 890\"}</p>\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-start gap-4\">\r\n <div className=\"w-10 h-10 rounded-full bg-primary-foreground/10 flex items-center justify-center flex-shrink-0\">\r\n <MapPin className=\"h-5 w-5\" />\r\n </div>\r\n <div>\r\n <p className=\"font-semibold\">{t(\"addressLabel\", \"Address\")}</p>\r\n <p className=\"text-primary-foreground/70\">\r\n {constants.address?.line1 || \"123 Main Street\"}<br />\r\n {constants.address?.city || \"New York\"}, {constants.address?.country || \"USA\"}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-start gap-4\">\r\n <div className=\"w-10 h-10 rounded-full bg-primary-foreground/10 flex items-center justify-center flex-shrink-0\">\r\n <Clock className=\"h-5 w-5\" />\r\n </div>\r\n <div>\r\n <p className=\"font-semibold\">{t(\"hoursLabel\", \"Business Hours\")}</p>\r\n <p className=\"text-primary-foreground/70\">{t(\"hours\", \"Mon - Fri: 9:00 AM - 6:00 PM\")}</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Right Side - Form */}\r\n <div className=\"p-8 lg:p-12 flex items-center justify-center bg-background\">\r\n <div className=\"w-full max-w-md\">\r\n <h2 className=\"text-2xl font-bold mb-2\">{t(\"formTitle\", \"Send us a message\")}</h2>\r\n <p className=\"text-muted-foreground mb-8\">\r\n {t(\"formSubtitle\", \"Fill out the form below and we'll get back to you as soon as possible.\")}\r\n </p>\r\n\r\n <form onSubmit={handleSubmit} className=\"space-y-5\">\r\n <div>\r\n <Label htmlFor=\"name\">{t(\"nameLabel\", \"Full Name\")} *</Label>\r\n <Input\r\n id=\"name\"\r\n name=\"name\"\r\n value={formData.name}\r\n onChange={handleChange}\r\n placeholder={t(\"namePlaceholder\", \"John Doe\")}\r\n required\r\n className=\"mt-1\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <Label htmlFor=\"email\">{t(\"emailInputLabel\", \"Email\")} *</Label>\r\n <Input\r\n id=\"email\"\r\n name=\"email\"\r\n type=\"email\"\r\n value={formData.email}\r\n onChange={handleChange}\r\n placeholder={t(\"emailPlaceholder\", \"john@example.com\")}\r\n required\r\n className=\"mt-1\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <Label htmlFor=\"phone\">{t(\"phoneInputLabel\", \"Phone\")}</Label>\r\n <Input\r\n id=\"phone\"\r\n name=\"phone\"\r\n type=\"tel\"\r\n value={formData.phone}\r\n onChange={handleChange}\r\n placeholder={t(\"phonePlaceholder\", \"+1 234 567 890\")}\r\n className=\"mt-1\"\r\n />\r\n </div>\r\n\r\n <div>\r\n <Label htmlFor=\"message\">{t(\"messageLabel\", \"Message\")} *</Label>\r\n <Textarea\r\n id=\"message\"\r\n name=\"message\"\r\n value={formData.message}\r\n onChange={handleChange}\r\n placeholder={t(\"messagePlaceholder\", \"Tell us about your project...\")}\r\n required\r\n rows={5}\r\n className=\"mt-1 resize-none\"\r\n />\r\n </div>\r\n\r\n {submitStatus === \"success\" && (\r\n <div className=\"p-4 bg-green-500/10 border border-green-500/30 rounded-lg\">\r\n <p className=\"text-green-600 dark:text-green-400 text-sm font-medium\">\r\n {t(\"success\", \"Message sent! We'll be in touch soon.\")}\r\n </p>\r\n </div>\r\n )}\r\n\r\n {submitStatus === \"error\" && (\r\n <div className=\"p-4 bg-destructive/10 border border-destructive/30 rounded-lg\">\r\n <p className=\"text-destructive text-sm font-medium\">\r\n {t(\"error\", \"Something went wrong. Please try again.\")}\r\n </p>\r\n </div>\r\n )}\r\n\r\n <Button type=\"submit\" size=\"lg\" className=\"w-full\" disabled={isSubmitting}>\r\n {isSubmitting ? t(\"sending\", \"Sending...\") : t(\"submit\", \"Send Message\")}\r\n </Button>\r\n </form>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n}\r\n\r\nexport default ContactPageSplit;\r\n"
|
|
27
|
+
"content": "import React, { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { Mail, Phone, MapPin, Clock } from \"lucide-react\";\nimport { Layout } from \"@/components/Layout\";\nimport { useApiService } from \"@/lib/api\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { Label } from \"@/components/ui/label\";\nimport { cn } from \"@/lib/utils\";\nimport constants from \"@/constants/constants.json\";\n\ninterface ContactPageSplitProps {\n className?: string;\n}\n\nexport function ContactPageSplit({ className }: ContactPageSplitProps) {\n const { t } = useTranslation(\"contact-page-split\");\n usePageTitle({ title: t(\"pageTitle\", \"Contact Us\") });\n const apiService = useApiService();\n\n const [formData, setFormData] = useState({\n name: \"\",\n email: \"\",\n phone: \"\",\n message: \"\",\n });\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitStatus, setSubmitStatus] = useState<\"idle\" | \"success\" | \"error\">(\"idle\");\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitting(true);\n setSubmitStatus(\"idle\");\n\n try {\n await apiService.submitForm(\n formData,\n {\n email_subject1: \"Thank you for contacting us\",\n email_subject2: \"New Contact Form Submission\",\n fields: [\n { name: \"name\", required: true },\n { name: \"email\", required: true },\n { name: \"phone\", required: false },\n { name: \"message\", required: true },\n ],\n },\n constants.site.defaultLanguage\n );\n\n setSubmitStatus(\"success\");\n setFormData({ name: \"\", email: \"\", phone: \"\", message: \"\" });\n setTimeout(() => setSubmitStatus(\"idle\"), 5000);\n } catch {\n setSubmitStatus(\"error\");\n setTimeout(() => setSubmitStatus(\"idle\"), 5000);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n setFormData((prev) => ({ ...prev, [e.target.name]: e.target.value }));\n };\n\n return (\n <Layout>\n <div className={cn(\"min-h-[calc(100vh-200px)] py-8 md:py-12\", className)}>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\n <div className=\"grid lg:grid-cols-2 h-full rounded-xl overflow-hidden shadow-lg\">\n {/* Left Side - Info & Image */}\n <div className=\"relative bg-primary text-primary-foreground p-8 lg:p-12 flex flex-col justify-center\">\n {/* Background Pattern */}\n <div className=\"absolute inset-0 bg-[linear-gradient(to_right,rgba(255,255,255,0.1)_1px,transparent_1px),linear-gradient(to_bottom,rgba(255,255,255,0.1)_1px,transparent_1px)] bg-[size:4rem_4rem]\" />\n\n <div className=\"relative z-10 max-w-lg\">\n <h1 className=\"text-3xl lg:text-4xl font-bold mb-4\">\n {t(\"title\", \"Let's Start a Conversation\")}\n </h1>\n <p className=\"text-primary-foreground/80 mb-8\">\n {t(\"subtitle\", \"Have a project in mind? We'd love to hear about it. Get in touch and let's create something amazing together.\")}\n </p>\n\n <div className=\"space-y-6\">\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 rounded-full bg-primary-foreground/10 flex items-center justify-center flex-shrink-0\">\n <Mail className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"font-semibold\">{t(\"emailLabel\", \"Email\")}</p>\n <p className=\"text-primary-foreground/70\">{constants.email || \"hello@example.com\"}</p>\n </div>\n </div>\n\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 rounded-full bg-primary-foreground/10 flex items-center justify-center flex-shrink-0\">\n <Phone className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"font-semibold\">{t(\"phoneLabel\", \"Phone\")}</p>\n <p className=\"text-primary-foreground/70\">{constants.phone || \"+1 234 567 890\"}</p>\n </div>\n </div>\n\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 rounded-full bg-primary-foreground/10 flex items-center justify-center flex-shrink-0\">\n <MapPin className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"font-semibold\">{t(\"addressLabel\", \"Address\")}</p>\n <p className=\"text-primary-foreground/70\">\n {constants.address?.line1 || \"123 Main Street\"}<br />\n {constants.address?.city || \"New York\"}, {constants.address?.country || \"USA\"}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-start gap-4\">\n <div className=\"w-10 h-10 rounded-full bg-primary-foreground/10 flex items-center justify-center flex-shrink-0\">\n <Clock className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"font-semibold\">{t(\"hoursLabel\", \"Business Hours\")}</p>\n <p className=\"text-primary-foreground/70\">{t(\"hours\", \"Mon - Fri: 9:00 AM - 6:00 PM\")}</p>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Right Side - Form */}\n <div className=\"p-8 lg:p-12 flex items-center justify-center bg-background\">\n <div className=\"w-full max-w-md\">\n <h2 className=\"text-2xl font-bold mb-2\">{t(\"formTitle\", \"Send us a message\")}</h2>\n <p className=\"text-muted-foreground mb-8\">\n {t(\"formSubtitle\", \"Fill out the form below and we'll get back to you as soon as possible.\")}\n </p>\n\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n <div>\n <Label htmlFor=\"name\">{t(\"nameLabel\", \"Full Name\")} *</Label>\n <Input\n id=\"name\"\n name=\"name\"\n value={formData.name}\n onChange={handleChange}\n placeholder={t(\"namePlaceholder\", \"John Doe\")}\n required\n className=\"mt-1\"\n />\n </div>\n\n <div>\n <Label htmlFor=\"email\">{t(\"emailInputLabel\", \"Email\")} *</Label>\n <Input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n value={formData.email}\n onChange={handleChange}\n placeholder={t(\"emailPlaceholder\", \"john@example.com\")}\n required\n className=\"mt-1\"\n />\n </div>\n\n <div>\n <Label htmlFor=\"phone\">{t(\"phoneInputLabel\", \"Phone\")}</Label>\n <Input\n id=\"phone\"\n name=\"phone\"\n type=\"tel\"\n value={formData.phone}\n onChange={handleChange}\n placeholder={t(\"phonePlaceholder\", \"+1 234 567 890\")}\n className=\"mt-1\"\n />\n </div>\n\n <div>\n <Label htmlFor=\"message\">{t(\"messageLabel\", \"Message\")} *</Label>\n <Textarea\n id=\"message\"\n name=\"message\"\n value={formData.message}\n onChange={handleChange}\n placeholder={t(\"messagePlaceholder\", \"Tell us about your project...\")}\n required\n rows={5}\n className=\"mt-1 resize-none\"\n />\n </div>\n\n {submitStatus === \"success\" && (\n <div className=\"p-4 bg-green-500/10 border border-green-500/30 rounded-lg\">\n <p className=\"text-green-600 dark:text-green-400 text-sm font-medium\">\n {t(\"success\", \"Message sent! We'll be in touch soon.\")}\n </p>\n </div>\n )}\n\n {submitStatus === \"error\" && (\n <div className=\"p-4 bg-destructive/10 border border-destructive/30 rounded-lg\">\n <p className=\"text-destructive text-sm font-medium\">\n {t(\"error\", \"Something went wrong. Please try again.\")}\n </p>\n </div>\n )}\n\n <Button type=\"submit\" size=\"lg\" className=\"w-full\" disabled={isSubmitting}>\n {isSubmitting ? t(\"sending\", \"Sending...\") : t(\"submit\", \"Send Message\")}\n </Button>\n </form>\n </div>\n </div>\n </div>\n </div>\n </div>\n </Layout>\n );\n}\n\nexport default ContactPageSplit;\n"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"path": "contact-page-split/lang/en.json",
|
|
31
31
|
"type": "registry:lang",
|
|
32
32
|
"target": "$modules$/contact-page-split/lang/en.json",
|
|
33
|
-
"content": "{\
|
|
33
|
+
"content": "{\n \"pageTitle\": \"Contact Us\",\n \"title\": \"Let's Start a Conversation\",\n \"subtitle\": \"This welcoming message sets the tone for visitor communication. Explain why they should contact you, what kind of help you can provide, or your typical response time. Use Promake to create an inviting message that encourages engagement.\",\n \"emailLabel\": \"Email\",\n \"phoneLabel\": \"Phone\",\n \"addressLabel\": \"Address\",\n \"hoursLabel\": \"Hours\",\n \"hours\": \"Mon - Fri: 9:00 AM - 6:00 PM\",\n \"formTitle\": \"Send us a message\",\n \"formSubtitle\": \"Fill out the form below and we'll get back to you as soon as possible.\",\n \"nameLabel\": \"Full Name\",\n \"namePlaceholder\": \"John Doe\",\n \"emailInputLabel\": \"Email\",\n \"emailPlaceholder\": \"john@example.com\",\n \"phoneInputLabel\": \"Phone\",\n \"phonePlaceholder\": \"+1 234 567 890\",\n \"messageLabel\": \"Message\",\n \"messagePlaceholder\": \"Tell us about your project...\",\n \"submit\": \"Send Message\",\n \"sending\": \"Sending...\",\n \"success\": \"Message sent! We'll be in touch soon.\",\n \"error\": \"Something went wrong. Please try again.\"\n}\n"
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
"path": "contact-page-split/lang/tr.json",
|
|
37
37
|
"type": "registry:lang",
|
|
38
38
|
"target": "$modules$/contact-page-split/lang/tr.json",
|
|
39
|
-
"content": "{\
|
|
39
|
+
"content": "{\n \"pageTitle\": \"İletişim\",\n \"title\": \"Bir Sohbet Başlatalım\",\n \"subtitle\": \"Bu karşılama mesajı ziyaretçi iletişimi için tonu belirler. Neden sizinle iletişime geçmeleri gerektiğini, ne tür yardım sağlayabileceğinizi veya tipik yanıt sürenizi açıklayın. Promake ile etkileşimi teşvik eden davetkar bir mesaj oluşturun.\",\n \"emailLabel\": \"E-posta\",\n \"phoneLabel\": \"Telefon\",\n \"addressLabel\": \"Adres\",\n \"hoursLabel\": \"Çalışma Saatleri\",\n \"hours\": \"Pazartesi - Cuma: 09:00 - 18:00\",\n \"formTitle\": \"Bize mesaj gönderin\",\n \"formSubtitle\": \"Aşağıdaki formu doldurun, en kısa sürede size döneceğiz.\",\n \"nameLabel\": \"Ad Soyad\",\n \"namePlaceholder\": \"Ahmet Yılmaz\",\n \"emailInputLabel\": \"E-posta\",\n \"emailPlaceholder\": \"ahmet@ornek.com\",\n \"phoneInputLabel\": \"Telefon\",\n \"phonePlaceholder\": \"+90 532 123 4567\",\n \"messageLabel\": \"Mesaj\",\n \"messagePlaceholder\": \"Projeniz hakkında bize bilgi verin...\",\n \"submit\": \"Mesaj Gönder\",\n \"sending\": \"Gönderiliyor...\",\n \"success\": \"Mesaj gönderildi! En kısa sürede iletişime geçeceğiz.\",\n \"error\": \"Bir şeyler yanlış gitti. Lütfen tekrar deneyin.\"\n}\n"
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
42
|
"exports": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"path": "contact-page/index.ts",
|
|
17
17
|
"type": "registry:index",
|
|
18
18
|
"target": "$modules$/contact-page/index.ts",
|
|
19
|
-
"content": "export * from './contact-page';\
|
|
19
|
+
"content": "export * from './contact-page';\nexport { ContactPage as default } from './contact-page';\n"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"path": "contact-page/contact-page.tsx",
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"path": "contact-page/lang/en.json",
|
|
29
29
|
"type": "registry:lang",
|
|
30
30
|
"target": "$modules$/contact-page/lang/en.json",
|
|
31
|
-
"content": "{\
|
|
31
|
+
"content": "{\n \"title\": \"Contact Us\",\n \"getInTouch\": \"Get in Touch\",\n \"emailUs\": \"Email Us\",\n \"callUs\": \"Call Us\",\n \"visitUs\": \"Visit Us\",\n \"businessHours\": \"Hours\",\n \"sendMessage\": \"Send us a Message\",\n \"formNotAvailable\": \"Form is not available at the moment.\",\n \"fullName\": \"Full Name\",\n \"emailAddress\": \"Email Address\",\n \"phoneNumber\": \"Phone Number\",\n \"subject\": \"Subject\",\n \"message\": \"Message\",\n \"submit\": \"Send Message\",\n \"sending\": \"Sending...\",\n \"success\": \"Thank you for your message! We will get back to you soon.\",\n \"error\": \"Failed to send message. Please try again later.\",\n \"description\": \"Have a question or need support? We're here to help and typically respond within 24 hours.\",\n \"email\": \"Email\",\n \"phone\": \"Phone\",\n \"address\": \"Address\",\n \"fullNamePlaceholder\": \"Your full name\",\n \"emailPlaceholder\": \"your@email.com\",\n \"phonePlaceholder\": \"+1 (555) 123-4567\",\n \"subjectPlaceholder\": \"What is this regarding?\",\n \"messagePlaceholder\": \"Tell us how we can help you...\",\n \"loading\": \"Loading contact information...\",\n \"emailResponse\": \"We typically respond within 24 hours\",\n \"needSupport\": \"Need Support?\",\n \"supportDescription\": \"For technical support or general inquiries, contact our dedicated support team:\",\n \"supportEmail\": \"Support Email\",\n \"monday_friday\": \"Monday - Friday\",\n \"saturday\": \"Saturday\",\n \"sunday\": \"Sunday\",\n \"closed\": \"Closed\",\n \"am\": \"AM\",\n \"pm\": \"PM\"\n}"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"path": "contact-page/lang/tr.json",
|
|
35
35
|
"type": "registry:lang",
|
|
36
36
|
"target": "$modules$/contact-page/lang/tr.json",
|
|
37
|
-
"content": "{\
|
|
37
|
+
"content": "{\n \"title\": \"İletişim\",\n \"getInTouch\": \"Bize Ulaşın\",\n \"emailUs\": \"E-posta Gönderin\",\n \"callUs\": \"Bizi Arayın\",\n \"visitUs\": \"Bizi Ziyaret Edin\",\n \"businessHours\": \"Çalışma Saatleri\",\n \"sendMessage\": \"Bize Mesaj Gönderin\",\n \"formNotAvailable\": \"Form şu anda kullanılamıyor.\",\n \"fullName\": \"Ad Soyad\",\n \"emailAddress\": \"E-posta Adresi\",\n \"phoneNumber\": \"Telefon Numarası\",\n \"subject\": \"Konu\",\n \"message\": \"Mesaj\",\n \"submit\": \"Mesaj Gönder\",\n \"sending\": \"Gönderiliyor...\",\n \"success\": \"Mesajınız için teşekkürler! En kısa sürede size dönüş yapacağız.\",\n \"error\": \"Mesaj gönderilemedi. Lütfen tekrar deneyin.\",\n \"description\": \"İletişim seçenekleri ve müsaitlik bilgisi. Yanıt süreleri ve soru türlerini ekleyin.\",\n \"email\": \"E-posta\",\n \"phone\": \"Telefon\",\n \"address\": \"Adres\",\n \"fullNamePlaceholder\": \"Adınız ve soyadınız\",\n \"emailPlaceholder\": \"eposta@adresiniz.com\",\n \"phonePlaceholder\": \"+90 5XX XXX XX XX\",\n \"subjectPlaceholder\": \"Konu nedir?\",\n \"messagePlaceholder\": \"Size nasıl yardımcı olabiliriz...\",\n \"loading\": \"İletişim bilgileri yükleniyor...\",\n \"emailResponse\": \"Genellikle 24 saat içinde yanıt veririz\",\n \"needSupport\": \"Desteğe İhtiyacınız mı Var?\",\n \"supportDescription\": \"Teknik destek veya sipariş sorularınız için özel destek ekibimizle iletişime geçin:\",\n \"supportEmail\": \"Destek E-postası\",\n \"monday_friday\": \"Pazartesi - Cuma\",\n \"saturday\": \"Cumartesi\",\n \"sunday\": \"Pazar\",\n \"closed\": \"Kapalı\",\n \"am\": \"\",\n \"pm\": \"\"\n}"
|
|
38
38
|
}
|
|
39
39
|
],
|
|
40
40
|
"exports": {
|
|
@@ -10,25 +10,25 @@
|
|
|
10
10
|
"path": "content-section/index.ts",
|
|
11
11
|
"type": "registry:index",
|
|
12
12
|
"target": "$modules$/content-section/index.ts",
|
|
13
|
-
"content": "export * from './content-section';\
|
|
13
|
+
"content": "export * from './content-section';\n"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"path": "content-section/content-section.tsx",
|
|
17
17
|
"type": "registry:component",
|
|
18
18
|
"target": "$modules$/content-section/content-section.tsx",
|
|
19
|
-
"content": "import { Link } from \"react-router\";\
|
|
19
|
+
"content": "import { Link } from \"react-router\";\nimport { ChevronRight } from \"lucide-react\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\ninterface ContentSectionProps {\n image: string;\n imageAlt?: string;\n title: string;\n description: string;\n ctaText?: string;\n ctaLink?: string;\n grayscale?: boolean;\n className?: string;\n}\n\nexport function ContentSection({\n image,\n imageAlt,\n title,\n description,\n ctaText,\n ctaLink = \"#\",\n grayscale = false,\n className,\n}: ContentSectionProps) {\n\n return (\n <section className={cn(\"py-16 md:py-32\", className)}>\n <div className=\"mx-auto max-w-5xl space-y-8 px-6 md:space-y-12\">\n <img\n className={cn(\"rounded-lg w-full\", grayscale && \"grayscale\")}\n src={image}\n alt={imageAlt || title}\n loading=\"lazy\"\n />\n\n <div className=\"grid gap-6 md:grid-cols-2 md:gap-12\">\n <h2 className=\"text-3xl md:text-4xl font-medium leading-tight\">\n {title}\n </h2>\n <div className=\"space-y-6\">\n <p className=\"text-muted-foreground leading-relaxed\">\n {description}\n </p>\n\n {ctaText && (\n <Button asChild variant=\"secondary\" size=\"sm\" className=\"gap-1 pr-1.5\">\n <Link to={ctaLink}>\n <span>{ctaText}</span>\n <ChevronRight className=\"size-4\" />\n </Link>\n </Button>\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"path": "content-section/lang/en.json",
|
|
23
23
|
"type": "registry:lang",
|
|
24
24
|
"target": "$modules$/content-section/lang/en.json",
|
|
25
|
-
"content": "{\
|
|
25
|
+
"content": "{\n \"learnMore\": \"Learn More\"\n}\n"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"path": "content-section/lang/tr.json",
|
|
29
29
|
"type": "registry:lang",
|
|
30
30
|
"target": "$modules$/content-section/lang/tr.json",
|
|
31
|
-
"content": "{\
|
|
31
|
+
"content": "{\n \"learnMore\": \"Daha Fazla\"\n}\n"
|
|
32
32
|
}
|
|
33
33
|
],
|
|
34
34
|
"exports": {
|
|
@@ -13,25 +13,25 @@
|
|
|
13
13
|
"path": "cookie-consent/index.ts",
|
|
14
14
|
"type": "registry:index",
|
|
15
15
|
"target": "$modules$/cookie-consent/index.ts",
|
|
16
|
-
"content": "export { CookieConsent } from \"./cookie-consent\";\
|
|
16
|
+
"content": "export { CookieConsent } from \"./cookie-consent\";\n"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "cookie-consent/cookie-consent.tsx",
|
|
20
20
|
"type": "registry:component",
|
|
21
21
|
"target": "$modules$/cookie-consent/cookie-consent.tsx",
|
|
22
|
-
"content": "import { useState, useEffect } from \"react\";\
|
|
22
|
+
"content": "import { useState, useEffect } from \"react\";\nimport { Link } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\nimport { X } from \"lucide-react\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport { motion, AnimatePresence } from \"motion/react\";\n\ninterface CookieConsentProps {\n className?: string;\n privacyPolicyUrl?: string;\n cookiePolicyUrl?: string;\n onAccept?: () => void;\n onDecline?: () => void;\n width?: \"full\" | \"compact\" | \"auto\";\n position?: \"left\" | \"right\" | \"center\";\n storageKey?: string;\n}\n\nconst DEFAULT_STORAGE_KEY = \"cookie-consent\";\n\nexport function CookieConsent({\n className,\n privacyPolicyUrl = \"/privacy\",\n cookiePolicyUrl = \"/cookies\",\n onAccept,\n onDecline,\n width = \"full\",\n position = \"center\",\n storageKey = DEFAULT_STORAGE_KEY,\n}: CookieConsentProps) {\n const { t } = useTranslation(\"cookie-consent\");\n const [isVisible, setIsVisible] = useState(false);\n const [isClosing, setIsClosing] = useState(false);\n\n useEffect(() => {\n const consent = localStorage.getItem(storageKey);\n if (!consent) {\n // Small delay for better UX\n const timer = setTimeout(() => setIsVisible(true), 1000);\n return () => clearTimeout(timer);\n }\n }, [storageKey]);\n\n const handleAccept = () => {\n localStorage.setItem(storageKey, \"accepted\");\n setIsClosing(true);\n setTimeout(() => {\n setIsVisible(false);\n onAccept?.();\n }, 300);\n };\n\n const handleDecline = () => {\n localStorage.setItem(storageKey, \"declined\");\n setIsClosing(true);\n setTimeout(() => {\n setIsVisible(false);\n onDecline?.();\n }, 300);\n };\n\n const handleClose = () => {\n setIsClosing(true);\n setTimeout(() => setIsVisible(false), 300);\n };\n\n if (!isVisible) return null;\n\n return (\n <AnimatePresence>\n {isVisible && (\n <motion.div\n initial={{ y: 100, opacity: 0 }}\n animate={{ y: isClosing ? 100 : 0, opacity: isClosing ? 0 : 1 }}\n exit={{ y: 100, opacity: 0 }}\n transition={{ type: \"spring\", damping: 25, stiffness: 300 }}\n className={cn(\n \"fixed bottom-0 z-50 p-4 md:p-6 left-0 right-0\",\n position === \"left\" && \"md:right-auto\",\n position === \"right\" && \"md:left-auto\",\n className\n )}\n >\n <div className={cn(\n \"w-full mx-auto\",\n width === \"full\" && \"max-w-[var(--container-max-width)]\",\n width === \"compact\" && \"md:max-w-md\",\n width === \"auto\" && \"md:w-auto\"\n )}>\n <div className=\"bg-card border border-border rounded-2xl shadow-2xl p-5 relative\">\n {/* Close button */}\n <button\n onClick={handleClose}\n className=\"absolute top-3 right-3 p-1 text-muted-foreground hover:text-foreground transition-colors\"\n aria-label={t(\"close\", \"Close\")}\n >\n <X className=\"h-4 w-4\" />\n </button>\n\n {/* Title & Description */}\n <div className=\"mb-4 pr-6\">\n <h3 className=\"text-base font-semibold text-foreground mb-1\">\n {t(\"title\", \"Cookie Notice\")}\n </h3>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"description\", \"We use cookies to improve your experience.\")}{\" \"}\n <Link to={privacyPolicyUrl} className=\"text-primary hover:underline\">\n {t(\"privacyPolicy\", \"Privacy\")}\n </Link>\n {\" · \"}\n <Link to={cookiePolicyUrl} className=\"text-primary hover:underline\">\n {t(\"cookiePolicy\", \"Cookies\")}\n </Link>\n </p>\n </div>\n\n {/* Buttons */}\n <div className=\"flex flex-row gap-3\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleDecline}\n className=\"flex-1\"\n >\n {t(\"decline\", \"Decline\")}\n </Button>\n <Button\n size=\"sm\"\n onClick={handleAccept}\n className=\"flex-1\"\n >\n {t(\"accept\", \"Accept\")}\n </Button>\n </div>\n </div>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n );\n}\n"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"path": "cookie-consent/lang/en.json",
|
|
26
26
|
"type": "registry:lang",
|
|
27
27
|
"target": "$modules$/cookie-consent/lang/en.json",
|
|
28
|
-
"content": "{\
|
|
28
|
+
"content": "{\n \"title\": \"Cookie Notice\",\n \"description\": \"We use cookies to improve your experience.\",\n \"privacyPolicy\": \"Privacy\",\n \"cookiePolicy\": \"Cookies\",\n \"accept\": \"Accept\",\n \"decline\": \"Decline\",\n \"close\": \"Close\"\n}\n"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"path": "cookie-consent/lang/tr.json",
|
|
32
32
|
"type": "registry:lang",
|
|
33
33
|
"target": "$modules$/cookie-consent/lang/tr.json",
|
|
34
|
-
"content": "{\
|
|
34
|
+
"content": "{\n \"title\": \"Gizliliğinize değer veriyoruz\",\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.\",\n \"privacyPolicy\": \"Gizlilik Politikası\",\n \"cookiePolicy\": \"Çerez Politikası\",\n \"accept\": \"Tümünü Kabul Et\",\n \"decline\": \"Reddet\",\n \"customize\": \"Özelleştir\",\n \"close\": \"Kapat\"\n}\n"
|
|
35
35
|
}
|
|
36
36
|
],
|
|
37
37
|
"exports": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"path": "cookies-page/index.ts",
|
|
17
17
|
"type": "registry:index",
|
|
18
18
|
"target": "$modules$/cookies-page/index.ts",
|
|
19
|
-
"content": "export * from './cookies-page';\
|
|
19
|
+
"content": "export * from './cookies-page';\nexport { CookiesPage as default } from './cookies-page';\n"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"path": "cookies-page/cookies-page.tsx",
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"path": "cookies-page/lang/en.json",
|
|
29
29
|
"type": "registry:lang",
|
|
30
30
|
"target": "$modules$/cookies-page/lang/en.json",
|
|
31
|
-
"content": "{\
|
|
31
|
+
"content": "{\n \"title\": \"Cookie Policy\",\n \"lastUpdated\": \"Last Updated\",\n \"updateDate\": \"January 2026\",\n \"introduction\": \"This Cookie Policy explains how we use cookies and similar tracking technologies when you visit our website. We use these technologies to enhance your browsing experience, analyze site traffic, and understand where our visitors are coming from.\",\n \"whatTitle\": \"What Are Cookies?\",\n \"whatContent\": \"Cookies are small text files that are stored on your device when you visit a website. They help the website remember your preferences and understand how you interact with the site. Cookies are widely used to make websites work more efficiently and provide useful information to website owners.\",\n \"typesTitle\": \"Types of Cookies We Use\",\n \"essentialTitle\": \"Essential Cookies\",\n \"essentialDesc\": \"These cookies are necessary for the website to function properly. They enable basic features like page navigation, secure area access, and shopping cart functionality. The website cannot function properly without these cookies.\",\n \"analyticsTitle\": \"Analytics Cookies\",\n \"analyticsDesc\": \"These cookies help us understand how visitors interact with our website by collecting and reporting information anonymously. This helps us improve our website and provide a better user experience.\",\n \"functionalTitle\": \"Functional Cookies\",\n \"functionalDesc\": \"These cookies enable enhanced functionality and personalization, such as remembering your preferences, language settings, and login information. They may be set by us or by third-party providers.\",\n \"marketingTitle\": \"Marketing Cookies\",\n \"marketingDesc\": \"These cookies are used to track visitors across websites to display relevant and personalized advertisements. They help measure the effectiveness of advertising campaigns and limit the number of times you see an ad.\",\n \"managementTitle\": \"Managing Your Cookie Preferences\",\n \"managementContent\": \"You can manage your cookie preferences through your browser settings. Most browsers allow you to block or delete cookies, set preferences for certain websites, or browse in private mode. Please note that blocking essential cookies may affect the functionality of our website.\",\n \"footerNote\": \"This cookie policy may be updated periodically. We encourage you to review this page regularly for any changes. Your continued use of our website constitutes acceptance of our cookie practices.\"\n}\n"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"path": "cookies-page/lang/tr.json",
|
|
35
35
|
"type": "registry:lang",
|
|
36
36
|
"target": "$modules$/cookies-page/lang/tr.json",
|
|
37
|
-
"content": "{\
|
|
37
|
+
"content": "{\n \"title\": \"Çerez Politikası\",\n \"lastUpdated\": \"Son Güncelleme\",\n \"updateDate\": \"Ocak 2026\",\n \"introduction\": \"Bu Çerez Politikası, web sitemizi ziyaret ettiğinizde çerezleri ve benzer izleme teknolojilerini nasıl kullandığımızı açıklamaktadır. Bu teknolojileri tarama deneyiminizi geliştirmek, site trafiğini analiz etmek ve ziyaretçilerimizin nereden geldiğini anlamak için kullanıyoruz.\",\n \"whatTitle\": \"Çerez Nedir?\",\n \"whatContent\": \"Çerezler, bir web sitesini ziyaret ettiğinizde cihazınızda saklanan küçük metin dosyalarıdır. Web sitesinin tercihlerinizi hatırlamasına ve siteyle nasıl etkileşim kurduğunuzu anlamasına yardımcı olurlar. Çerezler, web sitelerinin daha verimli çalışmasını sağlamak ve site sahiplerine yararlı bilgiler sunmak için yaygın olarak kullanılır.\",\n \"typesTitle\": \"Kullandığımız Çerez Türleri\",\n \"essentialTitle\": \"Temel Çerezler\",\n \"essentialDesc\": \"Bu çerezler web sitesinin düzgün çalışması için gereklidir. Sayfa gezintisi, güvenli alan erişimi ve alışveriş sepeti işlevselliği gibi temel özellikleri etkinleştirirler. Web sitesi bu çerezler olmadan düzgün çalışamaz.\",\n \"analyticsTitle\": \"Analitik Çerezler\",\n \"analyticsDesc\": \"Bu çerezler, bilgileri anonim olarak toplayıp raporlayarak ziyaretçilerin web sitemizle nasıl etkileşim kurduğunu anlamamıza yardımcı olur. Bu, web sitemizi iyileştirmemize ve daha iyi bir kullanıcı deneyimi sunmamıza olanak tanır.\",\n \"functionalTitle\": \"İşlevsel Çerezler\",\n \"functionalDesc\": \"Bu çerezler, tercihlerinizi, dil ayarlarınızı ve oturum açma bilgilerinizi hatırlama gibi gelişmiş işlevsellik ve kişiselleştirme sağlar. Tarafımızdan veya üçüncü taraf sağlayıcılar tarafından ayarlanabilirler.\",\n \"marketingTitle\": \"Pazarlama Çerezleri\",\n \"marketingDesc\": \"Bu çerezler, ilgili ve kişiselleştirilmiş reklamlar görüntülemek için ziyaretçileri web siteleri arasında izlemek için kullanılır. Reklam kampanyalarının etkinliğini ölçmeye ve bir reklamı görme sayınızı sınırlamaya yardımcı olurlar.\",\n \"managementTitle\": \"Çerez Tercihlerinizi Yönetme\",\n \"managementContent\": \"Çerez tercihlerinizi tarayıcı ayarlarınız aracılığıyla yönetebilirsiniz. Çoğu tarayıcı, çerezleri engellemenize veya silmenize, belirli web siteleri için tercihler belirlemenize veya gizli modda gezinmenize olanak tanır. Temel çerezleri engellemenin web sitemizin işlevselliğini etkileyebileceğini lütfen unutmayın.\",\n \"footerNote\": \"Bu çerez politikası periyodik olarak güncellenebilir. Herhangi bir değişiklik için bu sayfayı düzenli olarak incelemenizi öneririz. Web sitemizi kullanmaya devam etmeniz çerez uygulamalarımızı kabul ettiğiniz anlamına gelir.\"\n}\n"
|
|
38
38
|
}
|
|
39
39
|
],
|
|
40
40
|
"exports": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"path": "cta-section/index.ts",
|
|
11
11
|
"type": "registry:index",
|
|
12
12
|
"target": "$modules$/cta-section/index.ts",
|
|
13
|
-
"content": "export * from './cta-section';\
|
|
13
|
+
"content": "export * from './cta-section';\n"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"path": "cta-section/cta-section.tsx",
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"path": "cta-section/lang/en.json",
|
|
23
23
|
"type": "registry:lang",
|
|
24
24
|
"target": "$modules$/cta-section/lang/en.json",
|
|
25
|
-
"content": "{\
|
|
25
|
+
"content": "{\n \"title\": \"Ready to Start Your Project?\",\n \"description\": \"Join thousands of satisfied customers. Start your free trial today and see the difference.\",\n \"primaryButton\": \"Get Free Quote\",\n \"secondaryButton\": \"Learn About Us\"\n}"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"path": "cta-section/lang/tr.json",
|
|
29
29
|
"type": "registry:lang",
|
|
30
30
|
"target": "$modules$/cta-section/lang/tr.json",
|
|
31
|
-
"content": "{\
|
|
31
|
+
"content": "{\n \"title\": \"Projenizi Başlatmaya Hazır mısınız?\",\n \"description\": \"Binlerce memnun müşteriye katılın. Ücretsiz denemenizi bugün başlatın ve farkı görün.\",\n \"primaryButton\": \"Ücretsiz Teklif Al\",\n \"secondaryButton\": \"Hakkımızda\"\n}"
|
|
32
32
|
}
|
|
33
33
|
],
|
|
34
34
|
"exports": {
|
|
@@ -13,61 +13,61 @@
|
|
|
13
13
|
"path": "ecommerce-core/index.ts",
|
|
14
14
|
"type": "registry:index",
|
|
15
15
|
"target": "$modules$/ecommerce-core/index.ts",
|
|
16
|
-
"content": "// Types\
|
|
16
|
+
"content": "// Types\nexport * from './types';\n\n// Stores (Zustand)\nexport { useCartStore, useCart } from './stores/cart-store';\nexport { useFavoritesStore, useFavorites } from './stores/favorites-store';\n\n// Hooks\nexport { useProducts, useProductBySlug, useFeaturedProducts, useCategories } from './useProducts';\nexport { useSearch } from './useSearch';\n\n// Utilities\nexport { formatPrice } from './format-price';\n\n// Payment Config\nexport {\n type PaymentMethod,\n type OnlinePaymentProvider,\n type PaymentMethodConfig,\n PAYMENT_METHOD_CONFIGS,\n ONLINE_PROVIDER_CONFIGS,\n getAvailablePaymentMethods,\n getOnlinePaymentProviders,\n getFilteredPaymentMethodConfigs,\n isPaymentMethodAvailable,\n isOnlineProviderAvailable,\n} from './payment-config';\n"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "ecommerce-core/types.ts",
|
|
20
20
|
"type": "registry:type",
|
|
21
21
|
"target": "$modules$/ecommerce-core/types.ts",
|
|
22
|
-
"content": "export interface ProductCategory {\
|
|
22
|
+
"content": "export interface ProductCategory {\n id: number;\n name: string;\n slug: string;\n is_primary: boolean;\n}\n\nexport interface Product {\n id: number;\n name: string;\n slug: string;\n description: string;\n price: number;\n sale_price?: number;\n on_sale: boolean;\n images: string[];\n category: string; // Primary category slug (backward compatibility)\n category_name?: string; // Primary category name (backward compatibility)\n categories: ProductCategory[]; // NEW: Multi-category support\n brand?: string;\n sku?: string;\n stock: number;\n tags: string[];\n rating: number;\n review_count: number;\n featured: boolean;\n is_new: boolean;\n published: boolean;\n specifications?: Record<string, any>;\n variants?: any;\n created_at?: string;\n updated_at?: string;\n meta_description?: string;\n meta_keywords?: string;\n}\n\nexport interface ProductVariant {\n id: string;\n name: string;\n value: string;\n price?: number;\n image?: string;\n stockQuantity: number;\n}\n\nexport interface CartItem {\n id: string | number;\n product: Product;\n quantity: number;\n}\n\nexport interface CartState {\n items: CartItem[];\n total: number;\n}\n\nexport interface CartContextType {\n state: CartState;\n addItem: (product: Product) => void;\n removeItem: (id: string | number) => void;\n updateQuantity: (id: string | number, quantity: number) => void;\n clearCart: () => void;\n itemCount: number;\n}\n\nexport interface FavoritesContextType {\n favorites: Product[];\n addToFavorites: (product: Product) => void;\n removeFromFavorites: (productId: string | number) => void;\n isFavorite: (productId: string | number) => boolean;\n favoriteCount: number;\n clearFavorites: () => void;\n}\n\nexport interface Category {\n id: number;\n name: string;\n slug: string;\n description?: string;\n image?: string;\n}\n\nexport interface User {\n id: string;\n email: string;\n name: string;\n avatar?: string;\n addresses?: Address[];\n orders?: Order[];\n}\n\nexport interface Address {\n name: string;\n line1: string;\n line2?: string;\n city: string;\n state: string;\n postalCode: string;\n country: string;\n}\n\nexport interface Order {\n id: number;\n user_id: string;\n total_price: number;\n status: 'pending' | 'confirmed' | 'shipped' | 'delivered' | 'cancelled';\n payment_method: string;\n shipping_address: Address;\n notes?: string;\n created_at?: string;\n}\n\nexport interface OrderItem {\n id: number;\n order_id: number;\n product_id: number;\n quantity: number;\n price: number;\n product?: {\n name: string;\n slug: string;\n images: string[];\n price: number;\n };\n}\n"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"path": "ecommerce-core/stores/cart-store.ts",
|
|
26
26
|
"type": "registry:store",
|
|
27
27
|
"target": "$modules$/ecommerce-core/stores/cart-store.ts",
|
|
28
|
-
"content": "import { create } from \"zustand\";\
|
|
28
|
+
"content": "import { create } from \"zustand\";\nimport { persist } from \"zustand/middleware\";\nimport type { Product, CartItem, CartState, CartContextType } from \"../types\";\n\nconst getProductPrice = (product: Product): number => {\n return product.on_sale && product.sale_price ? product.sale_price : product.price;\n};\n\nconst calculateTotal = (items: CartItem[]): number => {\n return items.reduce((total, item) => {\n const price = getProductPrice(item.product);\n return total + price * item.quantity;\n }, 0);\n};\n\ninterface CartStore extends CartState {\n addItem: (product: Product) => void;\n removeItem: (id: string | number) => void;\n updateQuantity: (id: string | number, quantity: number) => void;\n clearCart: () => void;\n itemCount: number;\n isDrawerOpen: boolean;\n setDrawerOpen: (open: boolean) => void;\n}\n\nexport const useCartStore = create<CartStore>()(\n persist(\n (set, _get) => ({\n items: [],\n total: 0,\n itemCount: 0,\n isDrawerOpen: false,\n setDrawerOpen: (open: boolean) => set({ isDrawerOpen: open }),\n\n addItem: (product) =>\n set((state) => {\n const existingItem = state.items.find(\n (item) => item.product.id === product.id\n );\n\n if (existingItem) {\n const items = state.items.map((item) =>\n item.product.id === product.id\n ? { ...item, quantity: item.quantity + 1 }\n : item\n );\n return {\n items,\n total: calculateTotal(items),\n itemCount: items.reduce((sum, i) => sum + i.quantity, 0),\n isDrawerOpen: true,\n };\n }\n\n const items = [\n ...state.items,\n { id: product.id, product, quantity: 1 },\n ];\n return {\n items,\n total: calculateTotal(items),\n itemCount: items.reduce((sum, i) => sum + i.quantity, 0),\n isDrawerOpen: true,\n };\n }),\n\n removeItem: (id) =>\n set((state) => {\n const items = state.items.filter((item) => item.id !== id);\n return {\n items,\n total: calculateTotal(items),\n itemCount: items.reduce((sum, i) => sum + i.quantity, 0),\n };\n }),\n\n updateQuantity: (id, quantity) =>\n set((state) => {\n if (quantity <= 0) {\n const items = state.items.filter((item) => item.id !== id);\n return {\n items,\n total: calculateTotal(items),\n itemCount: items.reduce((sum, i) => sum + i.quantity, 0),\n };\n }\n\n const items = state.items.map((item) =>\n item.id === id ? { ...item, quantity } : item\n );\n return {\n items,\n total: calculateTotal(items),\n itemCount: items.reduce((sum, i) => sum + i.quantity, 0),\n };\n }),\n\n clearCart: () => set({ items: [], total: 0, itemCount: 0 }),\n }),\n { name: \"ecommerce_cart\" }\n )\n);\n\n// Backward compatible hook - matches CartContextType with drawer state\nexport const useCart = (): CartContextType & { isDrawerOpen: boolean; setDrawerOpen: (open: boolean) => void } => {\n const store = useCartStore();\n return {\n state: { items: store.items, total: store.total },\n addItem: store.addItem,\n removeItem: store.removeItem,\n updateQuantity: store.updateQuantity,\n clearCart: store.clearCart,\n itemCount: store.itemCount,\n isDrawerOpen: store.isDrawerOpen,\n setDrawerOpen: store.setDrawerOpen,\n };\n};\n"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"path": "ecommerce-core/stores/favorites-store.ts",
|
|
32
32
|
"type": "registry:store",
|
|
33
33
|
"target": "$modules$/ecommerce-core/stores/favorites-store.ts",
|
|
34
|
-
"content": "import { create } from \"zustand\";\
|
|
34
|
+
"content": "import { create } from \"zustand\";\nimport { persist } from \"zustand/middleware\";\nimport type { Product, FavoritesContextType } from \"../types\";\n\ninterface FavoritesStore {\n favorites: Product[];\n favoriteCount: number;\n addToFavorites: (product: Product) => void;\n removeFromFavorites: (productId: string | number) => void;\n isFavorite: (productId: string | number) => boolean;\n clearFavorites: () => void;\n}\n\nexport const useFavoritesStore = create<FavoritesStore>()(\n persist(\n (set, get) => ({\n favorites: [],\n favoriteCount: 0,\n\n addToFavorites: (product) =>\n set((state) => {\n if (state.favorites.some((fav) => fav.id === product.id)) {\n return state;\n }\n const favorites = [...state.favorites, product];\n return { favorites, favoriteCount: favorites.length };\n }),\n\n removeFromFavorites: (productId) =>\n set((state) => {\n const favorites = state.favorites.filter((fav) => fav.id !== productId);\n return { favorites, favoriteCount: favorites.length };\n }),\n\n isFavorite: (productId) => {\n return get().favorites.some((fav) => fav.id === productId);\n },\n\n clearFavorites: () => set({ favorites: [], favoriteCount: 0 }),\n }),\n { name: \"ecommerce_favorites\" }\n )\n);\n\n// Backward compatible hook - matches FavoritesContextType\nexport const useFavorites = (): FavoritesContextType => {\n const store = useFavoritesStore();\n return {\n favorites: store.favorites,\n addToFavorites: store.addToFavorites,\n removeFromFavorites: store.removeFromFavorites,\n isFavorite: store.isFavorite,\n favoriteCount: store.favoriteCount,\n clearFavorites: store.clearFavorites,\n };\n};\n"
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"path": "ecommerce-core/useProducts.ts",
|
|
38
38
|
"type": "registry:hook",
|
|
39
39
|
"target": "$modules$/ecommerce-core/useProducts.ts",
|
|
40
|
-
"content": "import { useMemo } from 'react';\
|
|
40
|
+
"content": "import { useMemo } from 'react';\nimport type { Product, Category, ProductCategory } from './types';\nimport {\n useRepositoryQuery,\n useRawQuery,\n useRawQueryOne,\n parseStringToArray,\n parseJSONString,\n parseSQLiteBoolean,\n parseNumberSafe\n} from '@/modules/db';\n\nconst transformProduct = (row: any): Product => {\n const categoryNames = row.category_names ? row.category_names.split(',') : [];\n const categorySlugs = row.category_slugs ? row.category_slugs.split(',') : [];\n const categoryIds = row.category_ids ? row.category_ids.split(',').map(Number) : [];\n\n const categories: ProductCategory[] = categoryIds.map((id: number, index: number) => ({\n id,\n name: categoryNames[index] || '',\n slug: categorySlugs[index] || '',\n is_primary: index === 0\n }));\n\n const primaryCategory = categories.length > 0 ? categories[0] : null;\n\n return {\n id: parseNumberSafe(row.id),\n name: String(row.name || ''),\n slug: String(row.slug || ''),\n description: row.description || '',\n price: parseNumberSafe(row.price),\n sale_price: row.sale_price ? parseNumberSafe(row.sale_price) : undefined,\n on_sale: parseSQLiteBoolean(row.on_sale),\n images: parseStringToArray(row.images),\n brand: row.brand || '',\n sku: row.sku || '',\n stock: parseNumberSafe(row.stock),\n tags: parseJSONString(row.tags, []) || [],\n rating: parseNumberSafe(row.rating),\n review_count: parseNumberSafe(row.review_count),\n featured: parseSQLiteBoolean(row.featured),\n is_new: parseSQLiteBoolean(row.is_new),\n published: parseSQLiteBoolean(row.published),\n specifications: parseJSONString(row.specifications, {}) || {},\n variants: parseJSONString(row.variants, []) || [],\n created_at: row.created_at || new Date().toISOString(),\n updated_at: row.updated_at || new Date().toISOString(),\n meta_description: row.meta_description || '',\n meta_keywords: row.meta_keywords || '',\n category: primaryCategory?.slug || '',\n category_name: primaryCategory?.name || '',\n categories\n };\n};\n\nconst PRODUCTS_WITH_CATEGORIES_SQL = `\n SELECT p.*,\n GROUP_CONCAT(c.name) as category_names,\n GROUP_CONCAT(c.slug) as category_slugs,\n GROUP_CONCAT(c.id) as category_ids\n FROM products p\n LEFT JOIN product_category_relations pcr ON p.id = pcr.product_id\n LEFT JOIN product_categories c ON pcr.category_id = c.id\n WHERE p.published = 1\n GROUP BY p.id\n`;\n\nexport function useCategories() {\n const { data, isLoading: loading, error } = useRepositoryQuery<Category>('product_categories', {\n orderBy: [{ field: 'name', direction: 'ASC' }]\n });\n\n return {\n categories: data ?? [],\n loading,\n error: error?.message ?? null\n };\n}\n\nexport function useProducts() {\n const sql = `${PRODUCTS_WITH_CATEGORIES_SQL} ORDER BY p.name`;\n\n const { data, isLoading: loading, error } = useRawQuery<any>(\n ['products', 'all'],\n sql\n );\n\n const products = useMemo(() => {\n if (!data) return [];\n return data.map(transformProduct);\n }, [data]);\n\n return { products, loading, error: error?.message ?? null };\n}\n\nexport function useProductBySlug(slug: string) {\n const sql = `\n SELECT p.*,\n GROUP_CONCAT(c.name) as category_names,\n GROUP_CONCAT(c.slug) as category_slugs,\n GROUP_CONCAT(c.id) as category_ids\n FROM products p\n LEFT JOIN product_category_relations pcr ON p.id = pcr.product_id\n LEFT JOIN product_categories c ON pcr.category_id = c.id\n WHERE p.slug = ? AND p.published = 1\n GROUP BY p.id\n `;\n\n const { data, isLoading: loading, error } = useRawQueryOne<any>(\n ['products', 'slug', slug],\n sql,\n [slug],\n { enabled: !!slug }\n );\n\n const product = useMemo(() => {\n if (!data) return null;\n return transformProduct(data);\n }, [data]);\n\n return {\n product,\n loading,\n error: !data && !loading && slug ? 'Product not found' : (error?.message ?? null)\n };\n}\n\nexport function useFeaturedProducts() {\n const sql = `\n SELECT p.*,\n GROUP_CONCAT(c.name) as category_names,\n GROUP_CONCAT(c.slug) as category_slugs,\n GROUP_CONCAT(c.id) as category_ids\n FROM products p\n LEFT JOIN product_category_relations pcr ON p.id = pcr.product_id\n LEFT JOIN product_categories c ON pcr.category_id = c.id\n WHERE p.published = 1 AND p.featured = 1\n GROUP BY p.id\n ORDER BY p.created_at DESC LIMIT 8\n `;\n\n const { data, isLoading: loading, error } = useRawQuery<any>(\n ['products', 'featured'],\n sql\n );\n\n const products = useMemo(() => {\n if (!data) return [];\n return data.map(transformProduct);\n }, [data]);\n\n return { products, loading, error: error?.message ?? null };\n}\n"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"path": "ecommerce-core/useSearch.ts",
|
|
44
44
|
"type": "registry:hook",
|
|
45
45
|
"target": "$modules$/ecommerce-core/useSearch.ts",
|
|
46
|
-
"content": "import { useState, useEffect, useCallback } from 'react';\
|
|
46
|
+
"content": "import { useState, useEffect, useCallback } from 'react';\nimport type { Product } from './types';\nimport { useProducts } from './useProducts';\n\nexport const useSearch = () => {\n const [searchTerm, setSearchTerm] = useState('');\n const [results, setResults] = useState<Product[]>([]);\n const [isSearching, setIsSearching] = useState(false);\n\n // Load all products via useProducts hook\n const { products: allProducts } = useProducts();\n\n // Perform search when searchTerm changes\n useEffect(() => {\n if (!searchTerm.trim()) {\n setResults([]);\n setIsSearching(false);\n return;\n }\n\n setIsSearching(true);\n\n const searchTimeout = setTimeout(() => {\n const filtered = allProducts.filter(product => {\n const term = searchTerm.toLowerCase();\n \n // Search in product name\n if (product.name.toLowerCase().includes(term)) return true;\n \n // Search in description\n if (product.description.toLowerCase().includes(term)) return true;\n \n // Search in category\n if (product.category_name?.toLowerCase().includes(term)) return true;\n \n // Search in brand\n if (product.brand?.toLowerCase().includes(term)) return true;\n \n // Search in tags\n if (product.tags.some(tag => tag.toLowerCase().includes(term))) return true;\n \n return false;\n });\n\n setResults(filtered);\n setIsSearching(false);\n }, 300); // Debounce search\n\n return () => clearTimeout(searchTimeout);\n }, [searchTerm, allProducts]);\n\n const clearSearch = useCallback(() => {\n setSearchTerm('');\n setResults([]);\n setIsSearching(false);\n }, []);\n\n // search function that takes a term and sets the searchTerm\n const search = useCallback((term: string) => {\n setSearchTerm(term);\n }, []);\n\n return {\n searchTerm,\n setSearchTerm,\n results,\n isSearching,\n clearSearch,\n clearResults: clearSearch, // alias for header-ecommerce compatibility\n search, // function to trigger search\n hasResults: results.length > 0\n };\n};\n"
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
"path": "ecommerce-core/format-price.ts",
|
|
50
50
|
"type": "registry:lib",
|
|
51
51
|
"target": "$modules$/ecommerce-core/format-price.ts",
|
|
52
|
-
"content": "export function formatPrice(price: number, currency: string = \"USD\"): string {\
|
|
52
|
+
"content": "export function formatPrice(price: number, currency: string = \"USD\"): string {\n return new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: currency,\n }).format(price);\n}\n"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"path": "ecommerce-core/payment-config.ts",
|
|
56
56
|
"type": "registry:lib",
|
|
57
57
|
"target": "$modules$/ecommerce-core/payment-config.ts",
|
|
58
|
-
"content": "// Payment configuration utility\
|
|
58
|
+
"content": "// Payment configuration utility\n// Parses environment variables and provides payment method configuration\n\nexport type PaymentMethod = \"card\" | \"transfer\" | \"cash\";\nexport type OnlinePaymentProvider = \"stripe\" | \"iyzico\";\n\nexport interface PaymentMethodConfig {\n id: PaymentMethod;\n label: string;\n description: string;\n icon: string; // Icon component name from lucide-react\n requiresOnlineProvider?: boolean;\n}\n\n// Parse comma-separated env variable into array\nconst parseEnvArray = (envVar: string | undefined): string[] => {\n if (!envVar) return [];\n return envVar.split(\",\").map((item) => item.trim()).filter(Boolean);\n};\n\n// Get available payment methods from environment\nexport const getAvailablePaymentMethods = (): PaymentMethod[] => {\n const methods = parseEnvArray(import.meta.env.VITE_AVAILABLE_PAYMENT_METHODS);\n if (methods.length === 0) {\n // Default to all methods if not configured\n return [\"card\", \"transfer\", \"cash\"];\n }\n return methods as PaymentMethod[];\n};\n\n// Get available online payment providers from environment\nexport const getOnlinePaymentProviders = (): OnlinePaymentProvider[] => {\n const providers = parseEnvArray(import.meta.env.VITE_ONLINE_PAYMENT_METHODS);\n if (providers.length === 0) {\n // Default to stripe if not configured\n return [\"stripe\"];\n }\n return providers as OnlinePaymentProvider[];\n};\n\n// Payment method configurations with display information\nexport const PAYMENT_METHOD_CONFIGS: Record<PaymentMethod, PaymentMethodConfig> = {\n card: {\n id: \"card\",\n label: \"Credit/Debit Card\",\n description: \"Pay securely with your credit or debit card\",\n icon: \"CreditCard\",\n requiresOnlineProvider: true,\n },\n transfer: {\n id: \"transfer\",\n label: \"Bank Transfer\",\n description: \"Transfer payment to our bank account\",\n icon: \"Banknote\",\n },\n cash: {\n id: \"cash\",\n label: \"Cash on Delivery\",\n description: \"Pay when your order arrives at your doorstep\",\n icon: \"Truck\",\n },\n};\n\n// Online payment provider configurations\nexport const ONLINE_PROVIDER_CONFIGS: Record<OnlinePaymentProvider, { label: string; description: string }> = {\n stripe: {\n label: \"Stripe\",\n description: \"Secure payment processing by Stripe\",\n },\n iyzico: {\n label: \"iyzico\",\n description: \"Secure payment processing by iyzico\",\n },\n};\n\n// Check if a payment method is available\nexport const isPaymentMethodAvailable = (method: PaymentMethod): boolean => {\n const available = getAvailablePaymentMethods();\n return available.includes(method);\n};\n\n// Check if an online provider is available\nexport const isOnlineProviderAvailable = (provider: OnlinePaymentProvider): boolean => {\n const available = getOnlinePaymentProviders();\n return available.includes(provider);\n};\n\n// Get filtered payment method configs (only available ones)\nexport const getFilteredPaymentMethodConfigs = (): PaymentMethodConfig[] => {\n const availableMethods = getAvailablePaymentMethods();\n return availableMethods\n .map((method) => PAYMENT_METHOD_CONFIGS[method])\n .filter(Boolean);\n};\n"
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
"path": "ecommerce-core/lang/en.json",
|
|
62
62
|
"type": "registry:lang",
|
|
63
63
|
"target": "$modules$/ecommerce-core/lang/en.json",
|
|
64
|
-
"content": "{\
|
|
64
|
+
"content": "{\n \"cart\": \"Cart\",\n \"addToCart\": \"Add to Cart\",\n \"removeFromCart\": \"Remove\",\n \"clearCart\": \"Clear Cart\",\n \"emptyCart\": \"Your cart is empty\",\n \"cartTotal\": \"Total\",\n \"checkout\": \"Checkout\",\n \"quantity\": \"Quantity\",\n \"favorites\": \"Favorites\",\n \"addToFavorites\": \"Add to Favorites\",\n \"removeFromFavorites\": \"Remove from Favorites\",\n \"noFavorites\": \"No favorites yet\",\n \"products\": \"Products\",\n \"search\": \"Search\",\n \"searchPlaceholder\": \"Search products...\",\n \"noResults\": \"No products found\",\n \"outOfStock\": \"Out of Stock\",\n \"inStock\": \"In Stock\",\n \"sale\": \"Sale\",\n \"new\": \"New\",\n \"featured\": \"Featured\"\n}\n"
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
"path": "ecommerce-core/lang/tr.json",
|
|
68
68
|
"type": "registry:lang",
|
|
69
69
|
"target": "$modules$/ecommerce-core/lang/tr.json",
|
|
70
|
-
"content": "{\
|
|
70
|
+
"content": "{\n \"cart\": \"Sepet\",\n \"addToCart\": \"Sepete Ekle\",\n \"removeFromCart\": \"Kaldır\",\n \"clearCart\": \"Sepeti Temizle\",\n \"emptyCart\": \"Sepetiniz boş\",\n \"cartTotal\": \"Toplam\",\n \"checkout\": \"Ödeme\",\n \"quantity\": \"Adet\",\n \"favorites\": \"Favoriler\",\n \"addToFavorites\": \"Favorilere Ekle\",\n \"removeFromFavorites\": \"Favorilerden Kaldır\",\n \"noFavorites\": \"Henüz favori yok\",\n \"products\": \"Ürünler\",\n \"search\": \"Ara\",\n \"searchPlaceholder\": \"Ürün ara...\",\n \"noResults\": \"Ürün bulunamadı\",\n \"outOfStock\": \"Stokta Yok\",\n \"inStock\": \"Stokta\",\n \"sale\": \"İndirim\",\n \"new\": \"Yeni\",\n \"featured\": \"Öne Çıkan\"\n}\n"
|
|
71
71
|
}
|
|
72
72
|
],
|
|
73
73
|
"exports": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"path": "empty-page/index.ts",
|
|
15
15
|
"type": "registry:index",
|
|
16
16
|
"target": "$modules$/empty-page/index.ts",
|
|
17
|
-
"content": "export * from './empty-page';\
|
|
17
|
+
"content": "export * from './empty-page';\nexport { EmptyPage as default } from './empty-page';\n"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"path": "empty-page/empty-page.tsx",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"path": "empty-page/lang/en.json",
|
|
27
27
|
"type": "registry:lang",
|
|
28
28
|
"target": "$modules$/empty-page/lang/en.json",
|
|
29
|
-
"content": "{\
|
|
29
|
+
"content": "{\n \"title\": \"Page Title\",\n \"heading\": \"Page Heading\",\n \"description\": \"This is an empty page template. Replace this content with your own.\"\n}\n"
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"path": "empty-page/lang/tr.json",
|
|
33
33
|
"type": "registry:lang",
|
|
34
34
|
"target": "$modules$/empty-page/lang/tr.json",
|
|
35
|
-
"content": "{\
|
|
35
|
+
"content": "{\n \"title\": \"Sayfa Başlığı\",\n \"heading\": \"Sayfa Başlığı\",\n \"description\": \"Bu boş bir sayfa şablonudur. Bu içeriği kendi içeriğinizle değiştirin.\"\n}\n"
|
|
36
36
|
}
|
|
37
37
|
],
|
|
38
38
|
"exports": {
|