@promakeai/cli 0.0.6 → 0.1.1
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 +31 -31
- package/dist/registry/about-page.json +4 -2
- package/dist/registry/about-section.json +2 -2
- package/dist/registry/announcement-bar.json +43 -0
- package/dist/registry/auth-core.json +43 -0
- package/dist/registry/auth.json +1 -1
- package/dist/registry/blog-list-page.json +3 -2
- package/dist/registry/blog-section.json +1 -1
- package/dist/registry/cart-page.json +3 -3
- package/dist/registry/case-study-page.json +48 -0
- package/dist/registry/checkout-page.json +6 -5
- package/dist/registry/coming-soon-page-minimal.json +45 -0
- package/dist/registry/coming-soon-page.json +47 -0
- package/dist/registry/contact-info-grid.json +1 -1
- package/dist/registry/contact-page-centered.json +2 -2
- package/dist/registry/contact-page-map-overlay.json +4 -3
- package/dist/registry/contact-page-map-split.json +4 -3
- package/dist/registry/contact-page-split.json +3 -3
- package/dist/registry/contact-page.json +5 -3
- package/dist/registry/cookie-consent.json +43 -0
- package/dist/registry/cookies-page.json +3 -1
- package/dist/registry/cta-section.json +1 -1
- package/dist/registry/db.json +1 -1
- package/dist/registry/docs/about-page.md +5 -0
- package/dist/registry/docs/announcement-bar.md +38 -0
- package/dist/registry/docs/auth-core.md +64 -0
- package/dist/registry/docs/blog-list-page.md +1 -0
- package/dist/registry/docs/case-study-page.md +39 -0
- package/dist/registry/docs/checkout-page.md +2 -1
- package/dist/registry/docs/coming-soon-page-minimal.md +32 -0
- package/dist/registry/docs/coming-soon-page.md +37 -0
- package/dist/registry/docs/contact-page-map-overlay.md +2 -2
- package/dist/registry/docs/contact-page-map-split.md +2 -2
- package/dist/registry/docs/contact-page.md +5 -0
- package/dist/registry/docs/cookie-consent.md +37 -0
- package/dist/registry/docs/cookies-page.md +5 -0
- package/dist/registry/docs/ecommerce-core.md +4 -3
- package/dist/registry/docs/forgot-password-page-split.md +45 -0
- package/dist/registry/docs/forgot-password-page.md +14 -5
- package/dist/registry/docs/header-ecommerce.md +1 -0
- package/dist/registry/docs/hero-carousel.md +37 -0
- package/dist/registry/docs/landing-page-app.md +43 -0
- package/dist/registry/docs/landing-page-saas.md +41 -0
- package/dist/registry/docs/login-page-split.md +13 -4
- package/dist/registry/docs/login-page.md +17 -4
- package/dist/registry/docs/logo-cloud.md +33 -0
- package/dist/registry/docs/masonry-grid.md +37 -0
- package/dist/registry/docs/my-orders-page.md +44 -0
- package/dist/registry/docs/order-confirmation-page.md +41 -0
- package/dist/registry/docs/portfolio-page.md +38 -0
- package/dist/registry/docs/pricing-page.md +38 -0
- package/dist/registry/docs/privacy-page.md +5 -0
- package/dist/registry/docs/product-quick-view.md +37 -0
- package/dist/registry/docs/reading-progress.md +31 -0
- package/dist/registry/docs/register-page-split.md +45 -0
- package/dist/registry/docs/register-page.md +14 -7
- package/dist/registry/docs/reset-password-page-split.md +45 -0
- package/dist/registry/docs/reset-password-page.md +36 -0
- package/dist/registry/docs/share-buttons.md +37 -0
- package/dist/registry/docs/team-page.md +38 -0
- package/dist/registry/docs/terms-page.md +5 -0
- package/dist/registry/docs/timeline-section.md +37 -0
- package/dist/registry/docs/video-hero.md +41 -0
- package/dist/registry/ecommerce-core.json +17 -1
- package/dist/registry/empty-page.json +1 -1
- package/dist/registry/faq-categorized.json +1 -1
- package/dist/registry/faq-simple.json +1 -1
- package/dist/registry/favorites-ecommerce-block.json +1 -1
- package/dist/registry/feature-section.json +2 -2
- package/dist/registry/footer.json +1 -1
- package/dist/registry/forgot-password-page-split.json +50 -0
- package/dist/registry/forgot-password-page.json +9 -7
- package/dist/registry/header-ecommerce.json +3 -2
- package/dist/registry/header-mega.json +1 -1
- package/dist/registry/hero-carousel.json +45 -0
- package/dist/registry/hero-cta.json +2 -2
- package/dist/registry/hero-gradient.json +1 -1
- package/dist/registry/hero.json +1 -1
- package/dist/registry/index.json +22 -2
- package/dist/registry/landing-page-app.json +47 -0
- package/dist/registry/landing-page-saas.json +47 -0
- package/dist/registry/login-page-split.json +11 -7
- package/dist/registry/login-page.json +4 -4
- package/dist/registry/logo-cloud.json +41 -0
- package/dist/registry/masonry-grid.json +43 -0
- package/dist/registry/my-orders-page.json +52 -0
- package/dist/registry/order-confirmation-page.json +49 -0
- package/dist/registry/portfolio-page.json +45 -0
- package/dist/registry/pricing-page.json +47 -0
- package/dist/registry/pricing-section.json +1 -1
- package/dist/registry/privacy-page.json +3 -1
- package/dist/registry/product-detail-block.json +1 -1
- package/dist/registry/product-quick-view.json +46 -0
- package/dist/registry/products-page.json +3 -3
- package/dist/registry/reading-progress.json +43 -0
- package/dist/registry/register-page-split.json +50 -0
- package/dist/registry/register-page.json +9 -7
- package/dist/registry/reset-password-page-split.json +50 -0
- package/dist/registry/reset-password-page.json +39 -0
- package/dist/registry/share-buttons.json +46 -0
- package/dist/registry/team-page.json +47 -0
- package/dist/registry/terms-page.json +3 -1
- package/dist/registry/testimonials-carousel.json +1 -1
- package/dist/registry/testimonials-grid.json +1 -1
- package/dist/registry/timeline-section.json +43 -0
- package/dist/registry/video-hero.json +42 -0
- package/package.json +1 -1
- package/template/index.html +5 -5
- package/template/src/App.tsx +4 -0
- package/template/src/components/GoogleAnalytics.tsx +34 -0
- package/template/src/components/Layout.tsx +1 -1
- package/template/src/components/ScriptInjector.tsx +62 -0
- package/template/src/constants/constants.json +8 -2
- package/template/src/pages/Index.tsx +5 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "team-page",
|
|
3
|
+
"type": "registry:page",
|
|
4
|
+
"title": "Team Page",
|
|
5
|
+
"description": "Team members page with responsive grid layout, member cards with photo, name, role, bio, and social links. Includes staggered animations, hover effects, and a join team CTA section.",
|
|
6
|
+
"registryDependencies": [
|
|
7
|
+
"animations"
|
|
8
|
+
],
|
|
9
|
+
"route": {
|
|
10
|
+
"path": "/team",
|
|
11
|
+
"componentName": "TeamPage"
|
|
12
|
+
},
|
|
13
|
+
"usage": "import { TeamPage } from '@/modules/team-page';\n\n<Route path=\"/team\" element={<TeamPage />} />\n\n• 6 team member cards with social links\n• StaggerContainer grid animation\n• Join team CTA section\n• Customizable via lang files",
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
16
|
+
"path": "team-page/index.ts",
|
|
17
|
+
"type": "registry:index",
|
|
18
|
+
"target": "$modules$/team-page/index.ts",
|
|
19
|
+
"content": "export * from \"./team-page\";\r\nexport { default } from \"./team-page\";\r\n"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"path": "team-page/team-page.tsx",
|
|
23
|
+
"type": "registry:page",
|
|
24
|
+
"target": "$modules$/team-page/team-page.tsx",
|
|
25
|
+
"content": "import { useTranslation } from \"react-i18next\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { Layout } from \"@/components/Layout\";\r\nimport { Card, CardContent } from \"@/components/ui/card\";\r\nimport { Twitter, Linkedin, Github, Mail } from \"lucide-react\";\r\nimport { FadeIn, StaggerContainer, StaggerItem } from \"@/modules/animations\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\ninterface TeamMember {\r\n id: string;\r\n name: string;\r\n role: string;\r\n bio: string;\r\n image: string;\r\n social?: {\r\n twitter?: string;\r\n linkedin?: string;\r\n github?: string;\r\n email?: string;\r\n };\r\n}\r\n\r\ninterface TeamPageProps {\r\n className?: string;\r\n}\r\n\r\nexport function TeamPage({ className }: TeamPageProps) {\r\n const { t } = useTranslation(\"team-page\");\r\n usePageTitle({ title: t(\"title\") });\r\n\r\n const teamMembers: TeamMember[] = [\r\n {\r\n id: \"1\",\r\n name: t(\"member1Name\"),\r\n role: t(\"member1Role\"),\r\n bio: t(\"member1Bio\"),\r\n image: \"/images/placeholder.png\",\r\n social: { twitter: \"#\", linkedin: \"#\", email: \"sarah@example.com\" },\r\n },\r\n {\r\n id: \"2\",\r\n name: t(\"member2Name\"),\r\n role: t(\"member2Role\"),\r\n bio: t(\"member2Bio\"),\r\n image: \"/images/placeholder.png\",\r\n social: { github: \"#\", linkedin: \"#\", email: \"michael@example.com\" },\r\n },\r\n {\r\n id: \"3\",\r\n name: t(\"member3Name\"),\r\n role: t(\"member3Role\"),\r\n bio: t(\"member3Bio\"),\r\n image: \"/images/placeholder.png\",\r\n social: { twitter: \"#\", linkedin: \"#\" },\r\n },\r\n {\r\n id: \"4\",\r\n name: t(\"member4Name\"),\r\n role: t(\"member4Role\"),\r\n bio: t(\"member4Bio\"),\r\n image: \"/images/placeholder.png\",\r\n social: { github: \"#\", twitter: \"#\" },\r\n },\r\n {\r\n id: \"5\",\r\n name: t(\"member5Name\"),\r\n role: t(\"member5Role\"),\r\n bio: t(\"member5Bio\"),\r\n image: \"/images/placeholder.png\",\r\n social: { linkedin: \"#\", email: \"lisa@example.com\" },\r\n },\r\n {\r\n id: \"6\",\r\n name: t(\"member6Name\"),\r\n role: t(\"member6Role\"),\r\n bio: t(\"member6Bio\"),\r\n image: \"/images/placeholder.png\",\r\n social: { twitter: \"#\", linkedin: \"#\" },\r\n },\r\n ];\r\n\r\n const socialIcons = {\r\n twitter: Twitter,\r\n linkedin: Linkedin,\r\n github: Github,\r\n email: Mail,\r\n };\r\n\r\n return (\r\n <Layout>\r\n <div className={cn(\"min-h-screen bg-muted/30 py-12 md:py-16\", className)}>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\r\n {/* Header */}\r\n <FadeIn className=\"text-center mb-16\">\r\n <p className=\"text-sm font-medium text-primary mb-2 uppercase tracking-wide\">\r\n {t(\"label\")}\r\n </p>\r\n <h1 className=\"text-4xl md:text-5xl font-bold text-foreground mb-4\">\r\n {t(\"heading\")}\r\n </h1>\r\n <p className=\"text-lg text-muted-foreground max-w-2xl mx-auto\">\r\n {t(\"description\")}\r\n </p>\r\n </FadeIn>\r\n\r\n {/* Team Grid */}\r\n <StaggerContainer className=\"grid sm:grid-cols-2 lg:grid-cols-3 gap-6\">\r\n {teamMembers.map((member) => (\r\n <StaggerItem key={member.id}>\r\n <div className=\"group bg-card border border-border rounded-xl overflow-hidden h-full hover:shadow-xl transition-shadow duration-300\">\r\n {/* Image */}\r\n <div className=\"aspect-[4/3] overflow-hidden bg-muted\">\r\n <img\r\n src={member.image}\r\n alt={member.name}\r\n className=\"w-full h-full object-cover object-top group-hover:scale-105 transition-transform duration-500\"\r\n onError={(e) => {\r\n e.currentTarget.src = \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='300' viewBox='0 0 400 300'%3E%3Crect fill='%23f3f4f6' width='400' height='300'/%3E%3Ccircle cx='200' cy='120' r='50' fill='%23d1d5db'/%3E%3Cellipse cx='200' cy='260' rx='80' ry='60' fill='%23d1d5db'/%3E%3C/svg%3E\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div className=\"p-5\">\r\n <h3 className=\"text-xl font-semibold text-foreground mb-1\">\r\n {member.name}\r\n </h3>\r\n <p className=\"text-primary font-medium text-sm mb-3\">\r\n {member.role}\r\n </p>\r\n <p className=\"text-muted-foreground text-sm mb-4\">\r\n {member.bio}\r\n </p>\r\n\r\n {/* Social Links */}\r\n {member.social && (\r\n <div className=\"flex gap-2\">\r\n {Object.entries(member.social).map(([platform, url]) => {\r\n const Icon = socialIcons[platform as keyof typeof socialIcons];\r\n if (!Icon || !url) return null;\r\n return (\r\n <a\r\n key={platform}\r\n href={platform === \"email\" ? `mailto:${url}` : url}\r\n className=\"w-8 h-8 rounded-full bg-muted hover:bg-primary/10 flex items-center justify-center transition-colors\"\r\n aria-label={platform}\r\n >\r\n <Icon className=\"h-4 w-4 text-muted-foreground hover:text-primary transition-colors\" />\r\n </a>\r\n );\r\n })}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </StaggerItem>\r\n ))}\r\n </StaggerContainer>\r\n\r\n {/* CTA Section */}\r\n <FadeIn delay={0.3} className=\"text-center mt-16\">\r\n <Card className=\"bg-primary/5 border-primary/20\">\r\n <CardContent className=\"p-8 md:p-12\">\r\n <h2 className=\"text-2xl md:text-3xl font-bold text-foreground mb-4\">\r\n {t(\"ctaTitle\")}\r\n </h2>\r\n <p className=\"text-muted-foreground mb-6 max-w-xl mx-auto\">\r\n {t(\"ctaDescription\")}\r\n </p>\r\n <a\r\n href=\"/careers\"\r\n className=\"inline-flex items-center justify-center px-6 py-3 bg-primary text-primary-foreground font-medium rounded-lg hover:bg-primary/90 transition-colors\"\r\n >\r\n {t(\"ctaButton\")}\r\n </a>\r\n </CardContent>\r\n </Card>\r\n </FadeIn>\r\n </div>\r\n </div>\r\n </Layout>\r\n );\r\n}\r\n\r\nexport default TeamPage;\r\n"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"path": "team-page/lang/en.json",
|
|
29
|
+
"type": "registry:lang",
|
|
30
|
+
"target": "$modules$/team-page/lang/en.json",
|
|
31
|
+
"content": "{\r\n \"title\": \"Our Team\",\r\n \"label\": \"Our Team\",\r\n \"heading\": \"Meet the People Behind the Magic\",\r\n \"description\": \"Ask Promake to customize this team description based on your company culture and values.\",\r\n \"member1Name\": \"Team Member\",\r\n \"member1Role\": \"CEO & Founder\",\r\n \"member1Bio\": \"Ask Promake to add real team member bios here.\",\r\n \"member2Name\": \"Team Member\",\r\n \"member2Role\": \"CTO\",\r\n \"member2Bio\": \"Ask Promake to add real team member bios here.\",\r\n \"member3Name\": \"Team Member\",\r\n \"member3Role\": \"Head of Design\",\r\n \"member3Bio\": \"Ask Promake to add real team member bios here.\",\r\n \"member4Name\": \"Team Member\",\r\n \"member4Role\": \"Lead Developer\",\r\n \"member4Bio\": \"Ask Promake to add real team member bios here.\",\r\n \"member5Name\": \"Team Member\",\r\n \"member5Role\": \"Product Manager\",\r\n \"member5Bio\": \"Ask Promake to add real team member bios here.\",\r\n \"member6Name\": \"Team Member\",\r\n \"member6Role\": \"Marketing Director\",\r\n \"member6Bio\": \"Ask Promake to add real team member bios here.\",\r\n \"ctaTitle\": \"Want to Join Our Team?\",\r\n \"ctaDescription\": \"Ask Promake to customize this CTA description based on your hiring needs.\",\r\n \"ctaButton\": \"View Open Positions\"\r\n}\r\n"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"path": "team-page/lang/tr.json",
|
|
35
|
+
"type": "registry:lang",
|
|
36
|
+
"target": "$modules$/team-page/lang/tr.json",
|
|
37
|
+
"content": "{\r\n \"title\": \"Ekibimiz\",\r\n \"label\": \"Ekibimiz\",\r\n \"heading\": \"Sihrin Arkasındaki İnsanlarla Tanışın\",\r\n \"description\": \"Olağanüstü sonuçlar sunmaya ve sınırları zorlamaya adanmış tutkulu bir uzman ekibi.\",\r\n \"member1Name\": \"Ayşe Yılmaz\",\r\n \"member1Role\": \"CEO & Kurucu\",\r\n \"member1Bio\": \"Teknoloji inovasyonunda 15+ yıllık deneyime sahip vizyoner lider.\",\r\n \"member2Name\": \"Mehmet Kaya\",\r\n \"member2Role\": \"CTO\",\r\n \"member2Bio\": \"Ölçeklenebilir çözümler konusunda tutkulu full-stack mimar.\",\r\n \"member3Name\": \"Zeynep Demir\",\r\n \"member3Role\": \"Tasarım Direktörü\",\r\n \"member3Bio\": \"Güzel kullanıcı deneyimleri yaratan ödüllü tasarımcı.\",\r\n \"member4Name\": \"Ali Öztürk\",\r\n \"member4Role\": \"Baş Geliştirici\",\r\n \"member4Bio\": \"Açık kaynak katkıcısı ve temiz kod savunucusu.\",\r\n \"member5Name\": \"Elif Şahin\",\r\n \"member5Role\": \"Ürün Müdürü\",\r\n \"member5Bio\": \"Fikirleri başarılı ürünlere dönüştüren stratejik düşünür.\",\r\n \"member6Name\": \"Can Arslan\",\r\n \"member6Role\": \"Pazarlama Direktörü\",\r\n \"member6Bio\": \"Veri odaklı yaklaşıma sahip büyüme uzmanı.\",\r\n \"ctaTitle\": \"Ekibimize Katılmak İster misiniz?\",\r\n \"ctaDescription\": \"İnovasyon tutkumuzu paylaşan yetenekli bireyleri her zaman arıyoruz.\",\r\n \"ctaButton\": \"Açık Pozisyonları Görüntüle\"\r\n}\r\n"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"exports": {
|
|
41
|
+
"types": [],
|
|
42
|
+
"variables": [
|
|
43
|
+
"TeamPage",
|
|
44
|
+
"default"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
"type": "registry:page",
|
|
4
4
|
"title": "Terms of Service Page",
|
|
5
5
|
"description": "Terms of service/use page with numbered sections covering account terms, acceptable use, intellectual property, disclaimers, limitation of liability, and termination. Includes table of contents, collapsible sections, and professional legal formatting. Last updated date and acceptance notice included.",
|
|
6
|
-
"registryDependencies": [
|
|
6
|
+
"registryDependencies": [
|
|
7
|
+
"animations"
|
|
8
|
+
],
|
|
7
9
|
"usage": "import { TermsPage } from '@/modules/terms-page';\n\n<Route path=\"/terms\" element={<TermsPage />} />\n\n• Legal terms structure with numbered sections\n• Sections: account, use, IP, liability, termination\n• Edit content in lang/en.json",
|
|
8
10
|
"route": {
|
|
9
11
|
"path": "/terms",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"path": "testimonials-carousel/lang/en.json",
|
|
27
27
|
"type": "registry:lang",
|
|
28
28
|
"target": "$modules$/testimonials-carousel/lang/en.json",
|
|
29
|
-
"content": "{\r\n \"title\": \"What Our Customers Say\",\r\n \"subtitle\": \"
|
|
29
|
+
"content": "{\r\n \"title\": \"What Our Customers Say\",\r\n \"subtitle\": \"Ask Promake to customize this subtitle based on your testimonials section purpose.\",\r\n \"testimonial1Name\": \"Customer Name\",\r\n \"testimonial1Role\": \"Ask Promake to replace this with appropriate job title\",\r\n \"testimonial1Review\": \"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ask Promake to replace this testimonial with relevant customer feedback based on your site.\",\r\n \"testimonial2Name\": \"Client Name\",\r\n \"testimonial2Role\": \"This role will be customized by Promake\",\r\n \"testimonial2Review\": \"This is placeholder testimonial text. Ask Promake to generate appropriate customer reviews based on your service or product offerings.\",\r\n \"testimonial3Name\": \"Testimonial Name\",\r\n \"testimonial3Role\": \"Replace with customer role\",\r\n \"testimonial3Review\": \"Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ask Promake to customize this review to match your project context.\",\r\n \"testimonial4Name\": \"Reviewer Name\",\r\n \"testimonial4Role\": \"Ask Promake to customize this role\",\r\n \"testimonial4Review\": \"Placeholder customer testimonial. Ask Promake to replace this with contextually appropriate feedback based on your industry and services.\"\r\n}\r\n"
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"path": "testimonials-carousel/lang/tr.json",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"path": "testimonials-grid/lang/en.json",
|
|
26
26
|
"type": "registry:lang",
|
|
27
27
|
"target": "$modules$/testimonials-grid/lang/en.json",
|
|
28
|
-
"content": "{\r\n \"title\": \"What People Say\",\r\n \"subtitle\": \"
|
|
28
|
+
"content": "{\r\n \"title\": \"What People Say\",\r\n \"subtitle\": \"Ask Promake to customize this subtitle to match your testimonials section.\",\r\n \"testimonial1Name\": \"Industry Leader Name\",\r\n \"testimonial1Role\": \"Ask Promake to replace with appropriate executive title\",\r\n \"testimonial1Review\": \"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ask Promake to generate appropriate testimonial based on your site and audience.\",\r\n \"testimonial2Name\": \"Customer Name\",\r\n \"testimonial2Role\": \"This role will be customized by Promake\",\r\n \"testimonial2Review\": \"Placeholder testimonial text. Ask Promake to replace this with relevant feedback based on your content or services.\",\r\n \"testimonial3Name\": \"Expert Name\",\r\n \"testimonial3Role\": \"Replace with expert role\",\r\n \"testimonial3Review\": \"Sed do eiusmod tempor incididunt ut labore. Ask Promake to customize this review to provide contextually appropriate testimonial content.\"\r\n}\r\n"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"path": "testimonials-grid/lang/tr.json",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "timeline-section",
|
|
3
|
+
"type": "registry:component",
|
|
4
|
+
"title": "Timeline Section",
|
|
5
|
+
"description": "Vertical timeline with alternating left/right items. Perfect for company history, roadmaps, or process steps.",
|
|
6
|
+
"dependencies": [],
|
|
7
|
+
"registryDependencies": [
|
|
8
|
+
"animations"
|
|
9
|
+
],
|
|
10
|
+
"usage": "import { TimelineSection } from '@/modules/timeline-section';\n\n<TimelineSection />\n\n• Installed at: src/modules/timeline-section/\n• Customize content: lang/en/timeline-section.json\n• Props: items[], title, subtitle",
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "timeline-section/timeline-section.tsx",
|
|
14
|
+
"type": "registry:component",
|
|
15
|
+
"target": "$modules$/timeline-section/timeline-section.tsx",
|
|
16
|
+
"content": "\"use client\";\r\n\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { FadeIn } from \"@/modules/animations\";\r\n\r\ninterface TimelineItem {\r\n year: string;\r\n title: string;\r\n description: string;\r\n icon?: React.ReactNode;\r\n}\r\n\r\ninterface TimelineSectionProps {\r\n items?: TimelineItem[];\r\n title?: string;\r\n subtitle?: string;\r\n className?: string;\r\n}\r\n\r\nconst defaultIcon = (\r\n <svg\r\n className=\"w-5 h-5\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <polyline points=\"12 6 12 12 16 14\" />\r\n </svg>\r\n);\r\n\r\nexport function TimelineSection({\r\n items,\r\n title,\r\n subtitle,\r\n className,\r\n}: TimelineSectionProps) {\r\n const { t } = useTranslation(\"timeline-section\");\r\n\r\n const displayTitle = title ?? t(\"title\");\r\n const displaySubtitle = subtitle ?? t(\"subtitle\");\r\n\r\n const defaultItems: TimelineItem[] = [\r\n {\r\n year: t(\"items.0.year\"),\r\n title: t(\"items.0.title\"),\r\n description: t(\"items.0.description\"),\r\n },\r\n {\r\n year: t(\"items.1.year\"),\r\n title: t(\"items.1.title\"),\r\n description: t(\"items.1.description\"),\r\n },\r\n {\r\n year: t(\"items.2.year\"),\r\n title: t(\"items.2.title\"),\r\n description: t(\"items.2.description\"),\r\n },\r\n {\r\n year: t(\"items.3.year\"),\r\n title: t(\"items.3.title\"),\r\n description: t(\"items.3.description\"),\r\n },\r\n ];\r\n\r\n const displayItems = items ?? defaultItems;\r\n\r\n return (\r\n <section className={cn(\"py-16 md:py-24\", className)}>\r\n <div className=\"container max-w-[var(--container-max-width)] mx-auto px-4\">\r\n {/* Header */}\r\n <FadeIn className=\"text-center mb-12 md:mb-16\">\r\n <h2 className=\"text-3xl md:text-4xl font-bold mb-4\">{displayTitle}</h2>\r\n <p className=\"text-lg text-muted-foreground max-w-2xl mx-auto\">\r\n {displaySubtitle}\r\n </p>\r\n </FadeIn>\r\n\r\n {/* Timeline */}\r\n <div className=\"relative\">\r\n {/* Center line */}\r\n <div className=\"absolute left-4 md:left-1/2 top-0 bottom-0 w-0.5 bg-border md:-translate-x-1/2\" />\r\n\r\n <div className=\"space-y-8 md:space-y-12\">\r\n {displayItems.map((item, index) => (\r\n <FadeIn\r\n key={index}\r\n delay={index * 0.1}\r\n className={cn(\r\n \"relative pl-12 md:pl-0\",\r\n \"md:grid md:grid-cols-2 md:gap-8\",\r\n index % 2 === 0 ? \"md:text-right\" : \"\"\r\n )}\r\n >\r\n {/* Year badge - Mobile */}\r\n <div className=\"absolute left-0 top-0 md:hidden\">\r\n <div className=\"w-8 h-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-xs font-bold\">\r\n {item.icon || defaultIcon}\r\n </div>\r\n </div>\r\n\r\n {/* Content - Left side on desktop (for even items) */}\r\n <div\r\n className={cn(\r\n \"md:pr-8\",\r\n index % 2 === 0 ? \"md:block\" : \"md:hidden\"\r\n )}\r\n >\r\n <div className=\"bg-card border border-border rounded-xl p-6 shadow-sm\">\r\n <span className=\"inline-block text-sm font-semibold text-primary mb-2\">\r\n {item.year}\r\n </span>\r\n <h3 className=\"text-xl font-bold mb-2\">{item.title}</h3>\r\n <p className=\"text-muted-foreground\">{item.description}</p>\r\n </div>\r\n </div>\r\n\r\n {/* Center icon - Desktop only */}\r\n <div className=\"hidden md:block absolute left-1/2 top-6 -translate-x-1/2 z-10\">\r\n <div className=\"w-10 h-10 rounded-full bg-primary text-primary-foreground flex items-center justify-center shadow-lg\">\r\n {item.icon || defaultIcon}\r\n </div>\r\n </div>\r\n\r\n {/* Content - Right side on desktop (for odd items) */}\r\n <div\r\n className={cn(\r\n \"md:pl-8 md:text-left\",\r\n index % 2 === 0 ? \"md:hidden\" : \"md:block\"\r\n )}\r\n >\r\n <div className=\"bg-card border border-border rounded-xl p-6 shadow-sm md:hidden block\">\r\n <span className=\"inline-block text-sm font-semibold text-primary mb-2\">\r\n {item.year}\r\n </span>\r\n <h3 className=\"text-xl font-bold mb-2\">{item.title}</h3>\r\n <p className=\"text-muted-foreground\">{item.description}</p>\r\n </div>\r\n </div>\r\n\r\n {/* Empty space for grid alignment */}\r\n <div\r\n className={cn(\r\n \"hidden md:block\",\r\n index % 2 === 0 ? \"md:pl-8\" : \"md:pr-8\"\r\n )}\r\n >\r\n {index % 2 !== 0 && (\r\n <div className=\"bg-card border border-border rounded-xl p-6 shadow-sm\">\r\n <span className=\"inline-block text-sm font-semibold text-primary mb-2\">\r\n {item.year}\r\n </span>\r\n <h3 className=\"text-xl font-bold mb-2\">{item.title}</h3>\r\n <p className=\"text-muted-foreground\">{item.description}</p>\r\n </div>\r\n )}\r\n </div>\r\n </FadeIn>\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n );\r\n}\r\n"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "timeline-section/index.ts",
|
|
20
|
+
"type": "registry:index",
|
|
21
|
+
"target": "$modules$/timeline-section/index.ts",
|
|
22
|
+
"content": "export * from \"./timeline-section\";\r\n"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"path": "timeline-section/lang/en.json",
|
|
26
|
+
"type": "registry:lang",
|
|
27
|
+
"target": "$modules$/timeline-section/lang/en.json",
|
|
28
|
+
"content": "{\r\n \"title\": \"Our Journey\",\r\n \"subtitle\": \"Ask Promake to customize these milestones based on your company history.\",\r\n \"items\": [\r\n {\r\n \"year\": \"2020\",\r\n \"title\": \"Company Founded\",\r\n \"description\": \"Started with a vision to revolutionize the industry.\"\r\n },\r\n {\r\n \"year\": \"2021\",\r\n \"title\": \"First Major Milestone\",\r\n \"description\": \"Reached 10,000 customers and expanded the team.\"\r\n },\r\n {\r\n \"year\": \"2022\",\r\n \"title\": \"Global Expansion\",\r\n \"description\": \"Opened offices in 5 new countries across 3 continents.\"\r\n },\r\n {\r\n \"year\": \"2023\",\r\n \"title\": \"Industry Recognition\",\r\n \"description\": \"Won multiple awards for innovation and customer satisfaction.\"\r\n }\r\n ]\r\n}\r\n"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"path": "timeline-section/lang/tr.json",
|
|
32
|
+
"type": "registry:lang",
|
|
33
|
+
"target": "$modules$/timeline-section/lang/tr.json",
|
|
34
|
+
"content": "{\r\n \"title\": \"Yolculuğumuz\",\r\n \"subtitle\": \"Bu kilometre taşlarını şirket geçmişinize göre özelleştirmek için Promake'e sorun.\",\r\n \"items\": [\r\n {\r\n \"year\": \"2020\",\r\n \"title\": \"Şirket Kuruldu\",\r\n \"description\": \"Sektörü dönüştürme vizyonuyla yola çıktık.\"\r\n },\r\n {\r\n \"year\": \"2021\",\r\n \"title\": \"İlk Büyük Başarı\",\r\n \"description\": \"10.000 müşteriye ulaştık ve ekibimizi genişlettik.\"\r\n },\r\n {\r\n \"year\": \"2022\",\r\n \"title\": \"Global Genişleme\",\r\n \"description\": \"3 kıtada 5 yeni ülkede ofis açtık.\"\r\n },\r\n {\r\n \"year\": \"2023\",\r\n \"title\": \"Sektör Takdiri\",\r\n \"description\": \"İnovasyon ve müşteri memnuniyeti alanında birçok ödül kazandık.\"\r\n }\r\n ]\r\n}\r\n"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"exports": {
|
|
38
|
+
"types": [],
|
|
39
|
+
"variables": [
|
|
40
|
+
"TimelineSection"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "video-hero",
|
|
3
|
+
"type": "registry:block",
|
|
4
|
+
"title": "Video Hero Section",
|
|
5
|
+
"description": "Full-width hero section with autoplaying video background, gradient overlay, headline, description, CTA buttons, and animated stats. Includes scroll indicator and FadeIn animations.",
|
|
6
|
+
"registryDependencies": [
|
|
7
|
+
"animations"
|
|
8
|
+
],
|
|
9
|
+
"usage": "import { VideoHero } from '@/modules/video-hero';\n\n<VideoHero\n videoSrc=\"/videos/hero.mp4\"\n posterSrc=\"/images/hero-poster.jpg\"\n/>\n\n• Muted autoplay video\n• Fallback poster image\n• Responsive overlay text\n• Scroll indicator",
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "video-hero/index.ts",
|
|
13
|
+
"type": "registry:index",
|
|
14
|
+
"target": "$modules$/video-hero/index.ts",
|
|
15
|
+
"content": "export { VideoHero } from \"./video-hero\";\r\n"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"path": "video-hero/video-hero.tsx",
|
|
19
|
+
"type": "registry:block",
|
|
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"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": "video-hero/lang/en.json",
|
|
25
|
+
"type": "registry:lang",
|
|
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\": \"Ask Promake to customize this description based on your brand. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\",\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"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"path": "video-hero/lang/tr.json",
|
|
31
|
+
"type": "registry:lang",
|
|
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\": \"Son teknoloji çözümlerimizin endüstrileri nasıl dönüştürdüğünü ve dünya genelinde işletmeler için yeni olanaklar yarattığını keşfedin.\",\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"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"exports": {
|
|
37
|
+
"types": [],
|
|
38
|
+
"variables": [
|
|
39
|
+
"VideoHero"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
package/package.json
CHANGED
package/template/index.html
CHANGED
|
@@ -248,18 +248,18 @@
|
|
|
248
248
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
249
249
|
|
|
250
250
|
<!-- SEO -->
|
|
251
|
-
<title>
|
|
251
|
+
<title>Site Name - Modern Website Template</title>
|
|
252
252
|
<meta
|
|
253
253
|
name="description"
|
|
254
|
-
content="
|
|
254
|
+
content="A flexible website template for businesses, blogs, ecommerce stores, or portfolios."
|
|
255
255
|
/>
|
|
256
|
-
<meta name="author" content="
|
|
256
|
+
<meta name="author" content="Site Name" />
|
|
257
257
|
|
|
258
258
|
<!-- Open Graph -->
|
|
259
|
-
<meta property="og:title" content="
|
|
259
|
+
<meta property="og:title" content="Site Name" />
|
|
260
260
|
<meta
|
|
261
261
|
property="og:description"
|
|
262
|
-
content="
|
|
262
|
+
content="A flexible website template for businesses, blogs, ecommerce stores, or portfolios."
|
|
263
263
|
/>
|
|
264
264
|
<meta property="og:type" content="website" />
|
|
265
265
|
<meta property="og:image" content="" />
|
package/template/src/App.tsx
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
2
|
+
import { GoogleAnalytics } from "@/components/GoogleAnalytics";
|
|
3
|
+
import { ScriptInjector } from "@/components/ScriptInjector";
|
|
2
4
|
import { Router } from "./router";
|
|
3
5
|
|
|
4
6
|
const App = () => {
|
|
5
7
|
return (
|
|
6
8
|
<TooltipProvider>
|
|
9
|
+
<GoogleAnalytics />
|
|
10
|
+
<ScriptInjector />
|
|
7
11
|
<Router />
|
|
8
12
|
</TooltipProvider>
|
|
9
13
|
);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import constants from "@/constants/constants.json";
|
|
3
|
+
|
|
4
|
+
export function GoogleAnalytics() {
|
|
5
|
+
const injected = useRef(false);
|
|
6
|
+
const gaId = constants.scripts.gaId;
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!gaId || injected.current) return;
|
|
10
|
+
if (document.querySelector(`[data-injected="gtag"]`)) return;
|
|
11
|
+
|
|
12
|
+
injected.current = true;
|
|
13
|
+
|
|
14
|
+
// Inject gtag.js script
|
|
15
|
+
const script = document.createElement("script");
|
|
16
|
+
script.async = true;
|
|
17
|
+
script.src = `https://www.googletagmanager.com/gtag/js?id=${gaId}`;
|
|
18
|
+
script.setAttribute("data-injected", "gtag");
|
|
19
|
+
document.head.appendChild(script);
|
|
20
|
+
|
|
21
|
+
// Inject inline config script
|
|
22
|
+
const inlineScript = document.createElement("script");
|
|
23
|
+
inlineScript.setAttribute("data-injected", "gtag-config");
|
|
24
|
+
inlineScript.innerHTML = `
|
|
25
|
+
window.dataLayer = window.dataLayer || [];
|
|
26
|
+
function gtag(){dataLayer.push(arguments);}
|
|
27
|
+
gtag('js', new Date());
|
|
28
|
+
gtag('config', '${gaId}');
|
|
29
|
+
`;
|
|
30
|
+
document.head.appendChild(inlineScript);
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import constants from "@/constants/constants.json";
|
|
3
|
+
|
|
4
|
+
function injectScript(html: string, target: "head" | "body", position: "start" | "end", marker: string) {
|
|
5
|
+
if (!html) return;
|
|
6
|
+
|
|
7
|
+
// Check if already injected
|
|
8
|
+
if (document.querySelector(`[data-injected="${marker}"]`)) return;
|
|
9
|
+
|
|
10
|
+
const container = document.createElement("div");
|
|
11
|
+
container.innerHTML = html;
|
|
12
|
+
|
|
13
|
+
const targetElement = target === "head" ? document.head : document.body;
|
|
14
|
+
|
|
15
|
+
// Create wrapper with marker
|
|
16
|
+
const wrapper = document.createDocumentFragment();
|
|
17
|
+
|
|
18
|
+
Array.from(container.childNodes).forEach((node) => {
|
|
19
|
+
if (node.nodeName === "SCRIPT") {
|
|
20
|
+
// Recreate script for execution
|
|
21
|
+
const script = node as HTMLScriptElement;
|
|
22
|
+
const newScript = document.createElement("script");
|
|
23
|
+
newScript.setAttribute("data-injected", marker);
|
|
24
|
+
Array.from(script.attributes).forEach((attr) => {
|
|
25
|
+
newScript.setAttribute(attr.name, attr.value);
|
|
26
|
+
});
|
|
27
|
+
if (script.innerHTML) {
|
|
28
|
+
newScript.innerHTML = script.innerHTML;
|
|
29
|
+
}
|
|
30
|
+
wrapper.appendChild(newScript);
|
|
31
|
+
} else {
|
|
32
|
+
const clone = node.cloneNode(true) as HTMLElement;
|
|
33
|
+
if (clone.setAttribute) {
|
|
34
|
+
clone.setAttribute("data-injected", marker);
|
|
35
|
+
}
|
|
36
|
+
wrapper.appendChild(clone);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (position === "start") {
|
|
41
|
+
targetElement.insertBefore(wrapper, targetElement.firstChild);
|
|
42
|
+
} else {
|
|
43
|
+
targetElement.appendChild(wrapper);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function ScriptInjector() {
|
|
48
|
+
const injected = useRef(false);
|
|
49
|
+
const { headStart, headEnd, bodyStart, bodyEnd } = constants.scripts;
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (injected.current) return;
|
|
53
|
+
injected.current = true;
|
|
54
|
+
|
|
55
|
+
injectScript(headStart, "head", "start", "head-start");
|
|
56
|
+
injectScript(headEnd, "head", "end", "head-end");
|
|
57
|
+
injectScript(bodyStart, "body", "start", "body-start");
|
|
58
|
+
injectScript(bodyEnd, "body", "end", "body-end");
|
|
59
|
+
}, []);
|
|
60
|
+
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
@@ -34,8 +34,14 @@
|
|
|
34
34
|
"ogImage": "",
|
|
35
35
|
"twitterSite": "",
|
|
36
36
|
"twitterImage": "",
|
|
37
|
-
"googleVerification": ""
|
|
38
|
-
|
|
37
|
+
"googleVerification": ""
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"gaId": "234324",
|
|
41
|
+
"headStart": "",
|
|
42
|
+
"headEnd": "",
|
|
43
|
+
"bodyStart": "",
|
|
44
|
+
"bodyEnd": ""
|
|
39
45
|
},
|
|
40
46
|
"email": "hello@example.com",
|
|
41
47
|
"supportEmail": "support@example.com",
|