@promakeai/cli 0.3.2 → 0.3.4
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 +415 -209
- 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/auth.json +70 -0
- 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/docs/reset-password-page.md +36 -0
- 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/reset-password-page.json +39 -0
- 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
|
@@ -13,19 +13,19 @@
|
|
|
13
13
|
"path": "blog-core/index.ts",
|
|
14
14
|
"type": "registry:index",
|
|
15
15
|
"target": "$modules$/blog-core/index.ts",
|
|
16
|
-
"content": "// Types\nexport * from './types';\n\n// Store (Zustand)\nexport { useBlogStore, useBlog } from './stores/blog-store';\n\n// Hooks\nexport {\n usePosts,\n usePostBySlug,\n useFeaturedPosts,\n useRecentPosts,\n usePopularPosts,\n usePostsByCategory,\n usePostsByTag,\n usePostSearch,\n useBlogCategories,\n usePostStats\n} from './usePosts';\n"
|
|
16
|
+
"content": "// Types\r\nexport * from './types';\r\n\r\n// Store (Zustand)\r\nexport { useBlogStore, useBlog } from './stores/blog-store';\r\n\r\n// Hooks\r\nexport {\r\n usePosts,\r\n usePostBySlug,\r\n useFeaturedPosts,\r\n useRecentPosts,\r\n usePopularPosts,\r\n usePostsByCategory,\r\n usePostsByTag,\r\n usePostSearch,\r\n useBlogCategories,\r\n usePostStats\r\n} from './usePosts';\r\n"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "blog-core/types.ts",
|
|
20
20
|
"type": "registry:type",
|
|
21
21
|
"target": "$modules$/blog-core/types.ts",
|
|
22
|
-
"content": "export interface PostCategory {\n id: number;\n name: string;\n slug: string;\n is_primary: boolean;\n}\n\nexport interface Post {\n id: number;\n title: string;\n slug: string;\n content: string;\n excerpt: string;\n featured_image: string;\n images: string[];\n category: string; // Primary category slug (backward compatibility)\n category_name?: string; // Primary category name (backward compatibility)\n categories: PostCategory[]; // Multi-category support\n author: string;\n author_avatar: string;\n published_at: string;\n updated_at: string;\n tags: string[];\n read_time: number;\n view_count: number;\n featured: boolean;\n published: boolean;\n meta_description: string;\n meta_keywords: string;\n}\n\nexport interface Author {\n id: number;\n name: string;\n slug: string;\n bio?: string;\n avatar?: string;\n social?: {\n twitter?: string;\n linkedin?: string;\n github?: string;\n website?: string;\n };\n}\n\nexport interface Comment {\n id: number;\n post_id: number;\n author_name: string;\n author_email: string;\n content: string;\n created_at: string;\n approved: boolean;\n}\n\nexport interface BlogCategory {\n id: number;\n name: string;\n slug: string;\n description?: string;\n image?: string;\n}\n\nexport interface BlogContextType {\n favorites: Post[];\n addToFavorites: (post: Post) => void;\n removeFromFavorites: (postId: string) => void;\n isFavorite: (postId: string) => boolean;\n clearFavorites: () => void;\n}\n\nexport interface BlogSettings {\n site: {\n name: string;\n description: string;\n url: string;\n logo?: string;\n };\n author: {\n name: string;\n bio?: string;\n avatar?: string;\n };\n social: {\n twitter?: string;\n linkedin?: string;\n github?: string;\n facebook?: string;\n };\n comments: {\n enabled: boolean;\n moderation: boolean;\n };\n newsletter: {\n enabled: boolean;\n provider?: string;\n };\n}\n"
|
|
22
|
+
"content": "export interface PostCategory {\r\n id: number;\r\n name: string;\r\n slug: string;\r\n is_primary: boolean;\r\n}\r\n\r\nexport interface Post {\r\n id: number;\r\n title: string;\r\n slug: string;\r\n content: string;\r\n excerpt: string;\r\n featured_image: string;\r\n images: string[];\r\n category: string; // Primary category slug (backward compatibility)\r\n category_name?: string; // Primary category name (backward compatibility)\r\n categories: PostCategory[]; // Multi-category support\r\n author: string;\r\n author_avatar: string;\r\n published_at: string;\r\n updated_at: string;\r\n tags: string[];\r\n read_time: number;\r\n view_count: number;\r\n featured: boolean;\r\n published: boolean;\r\n meta_description: string;\r\n meta_keywords: string;\r\n}\r\n\r\nexport interface Author {\r\n id: number;\r\n name: string;\r\n slug: string;\r\n bio?: string;\r\n avatar?: string;\r\n social?: {\r\n twitter?: string;\r\n linkedin?: string;\r\n github?: string;\r\n website?: string;\r\n };\r\n}\r\n\r\nexport interface Comment {\r\n id: number;\r\n post_id: number;\r\n author_name: string;\r\n author_email: string;\r\n content: string;\r\n created_at: string;\r\n approved: boolean;\r\n}\r\n\r\nexport interface BlogCategory {\r\n id: number;\r\n name: string;\r\n slug: string;\r\n description?: string;\r\n image?: string;\r\n}\r\n\r\nexport interface BlogContextType {\r\n favorites: Post[];\r\n addToFavorites: (post: Post) => void;\r\n removeFromFavorites: (postId: string) => void;\r\n isFavorite: (postId: string) => boolean;\r\n clearFavorites: () => void;\r\n}\r\n\r\nexport interface BlogSettings {\r\n site: {\r\n name: string;\r\n description: string;\r\n url: string;\r\n logo?: string;\r\n };\r\n author: {\r\n name: string;\r\n bio?: string;\r\n avatar?: string;\r\n };\r\n social: {\r\n twitter?: string;\r\n linkedin?: string;\r\n github?: string;\r\n facebook?: string;\r\n };\r\n comments: {\r\n enabled: boolean;\r\n moderation: boolean;\r\n };\r\n newsletter: {\r\n enabled: boolean;\r\n provider?: string;\r\n };\r\n}\r\n"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"path": "blog-core/stores/blog-store.ts",
|
|
26
26
|
"type": "registry:store",
|
|
27
27
|
"target": "$modules$/blog-core/stores/blog-store.ts",
|
|
28
|
-
"content": "import { create } from \"zustand\";\nimport { persist } from \"zustand/middleware\";\nimport type { Post, BlogContextType } from \"../types\";\n\ninterface BlogStore {\n favorites: Post[];\n addToFavorites: (post: Post) => void;\n removeFromFavorites: (postId: string) => void;\n isFavorite: (postId: string) => boolean;\n clearFavorites: () => void;\n}\n\nexport const useBlogStore = create<BlogStore>()(\n persist(\n (set, get) => ({\n favorites: [],\n\n addToFavorites: (post) =>\n set((state) => {\n if (state.favorites.some((p) => p.id === post.id)) {\n return state;\n }\n return { favorites: [...state.favorites, post] };\n }),\n\n removeFromFavorites: (postId) =>\n set((state) => ({\n favorites: state.favorites.filter((p) => String(p.id) !== postId),\n })),\n\n isFavorite: (postId) => {\n return get().favorites.some((p) => String(p.id) === postId);\n },\n\n clearFavorites: () => set({ favorites: [] }),\n }),\n { name: \"blog_favorites\" }\n )\n);\n\n// Backward compatible hook - matches BlogContextType\nexport const useBlog = (): BlogContextType => {\n const store = useBlogStore();\n return {\n favorites: store.favorites,\n addToFavorites: store.addToFavorites,\n removeFromFavorites: store.removeFromFavorites,\n isFavorite: store.isFavorite,\n clearFavorites: store.clearFavorites,\n };\n};\n"
|
|
28
|
+
"content": "import { create } from \"zustand\";\r\nimport { persist } from \"zustand/middleware\";\r\nimport type { Post, BlogContextType } from \"../types\";\r\n\r\ninterface BlogStore {\r\n favorites: Post[];\r\n addToFavorites: (post: Post) => void;\r\n removeFromFavorites: (postId: string) => void;\r\n isFavorite: (postId: string) => boolean;\r\n clearFavorites: () => void;\r\n}\r\n\r\nexport const useBlogStore = create<BlogStore>()(\r\n persist(\r\n (set, get) => ({\r\n favorites: [],\r\n\r\n addToFavorites: (post) =>\r\n set((state) => {\r\n if (state.favorites.some((p) => p.id === post.id)) {\r\n return state;\r\n }\r\n return { favorites: [...state.favorites, post] };\r\n }),\r\n\r\n removeFromFavorites: (postId) =>\r\n set((state) => ({\r\n favorites: state.favorites.filter((p) => String(p.id) !== postId),\r\n })),\r\n\r\n isFavorite: (postId) => {\r\n return get().favorites.some((p) => String(p.id) === postId);\r\n },\r\n\r\n clearFavorites: () => set({ favorites: [] }),\r\n }),\r\n { name: \"blog_favorites\" }\r\n )\r\n);\r\n\r\n// Backward compatible hook - matches BlogContextType\r\nexport const useBlog = (): BlogContextType => {\r\n const store = useBlogStore();\r\n return {\r\n favorites: store.favorites,\r\n addToFavorites: store.addToFavorites,\r\n removeFromFavorites: store.removeFromFavorites,\r\n isFavorite: store.isFavorite,\r\n clearFavorites: store.clearFavorites,\r\n };\r\n};\r\n"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"path": "blog-core/usePosts.ts",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"path": "blog-core/lang/en.json",
|
|
38
38
|
"type": "registry:lang",
|
|
39
39
|
"target": "$modules$/blog-core/lang/en.json",
|
|
40
|
-
"content": "{\n \"favorites\": \"Favorites\",\n \"addedToFavorites\": \"Added to favorites\",\n \"removedFromFavorites\": \"Removed from favorites\",\n \"noFavorites\": \"No favorites yet\",\n \"clearFavorites\": \"Clear all favorites\",\n \"posts\": \"Posts\",\n \"categories\": \"Categories\",\n \"tags\": \"Tags\",\n \"readMore\": \"Read more\",\n \"minRead\": \"min read\",\n \"views\": \"views\",\n \"loadingPosts\": \"Loading posts...\",\n \"noPosts\": \"No posts found\",\n \"errorLoadingPosts\": \"Error loading posts\"\n}\n"
|
|
40
|
+
"content": "{\r\n \"favorites\": \"Favorites\",\r\n \"addedToFavorites\": \"Added to favorites\",\r\n \"removedFromFavorites\": \"Removed from favorites\",\r\n \"noFavorites\": \"No favorites yet\",\r\n \"clearFavorites\": \"Clear all favorites\",\r\n \"posts\": \"Posts\",\r\n \"categories\": \"Categories\",\r\n \"tags\": \"Tags\",\r\n \"readMore\": \"Read more\",\r\n \"minRead\": \"min read\",\r\n \"views\": \"views\",\r\n \"loadingPosts\": \"Loading posts...\",\r\n \"noPosts\": \"No posts found\",\r\n \"errorLoadingPosts\": \"Error loading posts\"\r\n}\r\n"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"path": "blog-core/lang/tr.json",
|
|
44
44
|
"type": "registry:lang",
|
|
45
45
|
"target": "$modules$/blog-core/lang/tr.json",
|
|
46
|
-
"content": "{\n \"favorites\": \"Favoriler\",\n \"addedToFavorites\": \"Favorilere eklendi\",\n \"removedFromFavorites\": \"Favorilerden kaldırıldı\",\n \"noFavorites\": \"Henüz favori yok\",\n \"clearFavorites\": \"Tüm favorileri temizle\",\n \"posts\": \"Yazılar\",\n \"categories\": \"Kategoriler\",\n \"tags\": \"Etiketler\",\n \"readMore\": \"Devamını oku\",\n \"minRead\": \"dk okuma\",\n \"views\": \"görüntüleme\",\n \"loadingPosts\": \"Yazılar yükleniyor...\",\n \"noPosts\": \"Yazı bulunamadı\",\n \"errorLoadingPosts\": \"Yazılar yüklenirken hata oluştu\"\n}\n"
|
|
46
|
+
"content": "{\r\n \"favorites\": \"Favoriler\",\r\n \"addedToFavorites\": \"Favorilere eklendi\",\r\n \"removedFromFavorites\": \"Favorilerden kaldırıldı\",\r\n \"noFavorites\": \"Henüz favori yok\",\r\n \"clearFavorites\": \"Tüm favorileri temizle\",\r\n \"posts\": \"Yazılar\",\r\n \"categories\": \"Kategoriler\",\r\n \"tags\": \"Etiketler\",\r\n \"readMore\": \"Devamını oku\",\r\n \"minRead\": \"dk okuma\",\r\n \"views\": \"görüntüleme\",\r\n \"loadingPosts\": \"Yazılar yükleniyor...\",\r\n \"noPosts\": \"Yazı bulunamadı\",\r\n \"errorLoadingPosts\": \"Yazılar yüklenirken hata oluştu\"\r\n}\r\n"
|
|
47
47
|
}
|
|
48
48
|
],
|
|
49
49
|
"exports": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"path": "blog-list-page/index.ts",
|
|
19
19
|
"type": "registry:index",
|
|
20
20
|
"target": "$modules$/blog-list-page/index.ts",
|
|
21
|
-
"content": "export * from './blog-list-page';\nexport { BlogListPage as default } from './blog-list-page';\n"
|
|
21
|
+
"content": "export * from './blog-list-page';\r\nexport { BlogListPage as default } from './blog-list-page';\r\n"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"path": "blog-list-page/blog-list-page.tsx",
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
"path": "blog-list-page/lang/en.json",
|
|
31
31
|
"type": "registry:lang",
|
|
32
32
|
"target": "$modules$/blog-list-page/lang/en.json",
|
|
33
|
-
"content": "{\n \"title\": \"Blog\",\n \"subtitle\": \"Discover our latest articles and insights\",\n \"allPosts\": \"All Posts\",\n \"featuredPosts\": \"Featured Posts\",\n \"recentPosts\": \"Recent Posts\",\n \"popularPosts\": \"Popular Posts\",\n \"categories\": \"Categories\",\n \"tags\": \"Tags\",\n \"filters\": \"Filters\",\n \"search\": \"Search\",\n \"searchPlaceholder\": \"Search posts...\",\n \"sortBy\": \"Sort By\",\n \"sortNewest\": \"Newest First\",\n \"sortOldest\": \"Oldest First\",\n \"sortPopular\": \"Most Popular\",\n \"sortReadingTime\": \"Reading Time\",\n \"showing\": \"Showing\",\n \"of\": \"of\",\n \"posts\": \"posts\",\n \"for\": \"for\",\n \"noPostsFound\": \"No posts found matching your criteria.\",\n \"clearFilters\": \"Clear Filters\",\n \"filterDescription\": \"Filter posts by category, tags, and more\",\n \"readMore\": \"Read More\",\n \"minRead\": \"min\",\n \"views\": \"views\",\n \"error\": \"Failed to load posts\"\n}\n"
|
|
33
|
+
"content": "{\r\n \"title\": \"Blog\",\r\n \"subtitle\": \"Discover our latest articles and insights\",\r\n \"allPosts\": \"All Posts\",\r\n \"featuredPosts\": \"Featured Posts\",\r\n \"recentPosts\": \"Recent Posts\",\r\n \"popularPosts\": \"Popular Posts\",\r\n \"categories\": \"Categories\",\r\n \"tags\": \"Tags\",\r\n \"filters\": \"Filters\",\r\n \"search\": \"Search\",\r\n \"searchPlaceholder\": \"Search posts...\",\r\n \"sortBy\": \"Sort By\",\r\n \"sortNewest\": \"Newest First\",\r\n \"sortOldest\": \"Oldest First\",\r\n \"sortPopular\": \"Most Popular\",\r\n \"sortReadingTime\": \"Reading Time\",\r\n \"showing\": \"Showing\",\r\n \"of\": \"of\",\r\n \"posts\": \"posts\",\r\n \"for\": \"for\",\r\n \"noPostsFound\": \"No posts found matching your criteria.\",\r\n \"clearFilters\": \"Clear Filters\",\r\n \"filterDescription\": \"Filter posts by category, tags, and more\",\r\n \"readMore\": \"Read More\",\r\n \"minRead\": \"min\",\r\n \"views\": \"views\",\r\n \"error\": \"Failed to load posts\"\r\n}\r\n"
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
"path": "blog-list-page/lang/tr.json",
|
|
37
37
|
"type": "registry:lang",
|
|
38
38
|
"target": "$modules$/blog-list-page/lang/tr.json",
|
|
39
|
-
"content": "{\n \"title\": \"Blog\",\n \"subtitle\": \"En son makalelerimizi ve görüşlerimizi keşfedin\",\n \"allPosts\": \"Tüm Yazılar\",\n \"featuredPosts\": \"Öne Çıkan Yazılar\",\n \"recentPosts\": \"Son Yazılar\",\n \"popularPosts\": \"Popüler Yazılar\",\n \"categories\": \"Kategoriler\",\n \"tags\": \"Etiketler\",\n \"filters\": \"Filtreler\",\n \"search\": \"Arama\",\n \"searchPlaceholder\": \"Yazı ara...\",\n \"sortBy\": \"Sırala\",\n \"sortNewest\": \"En Yeni\",\n \"sortOldest\": \"En Eski\",\n \"sortPopular\": \"En Popüler\",\n \"sortReadingTime\": \"Okuma Süresi\",\n \"showing\": \"Gösterilen\",\n \"of\": \"/\",\n \"posts\": \"yazı\",\n \"for\": \"için\",\n \"noPostsFound\": \"Kriterlere uygun yazı bulunamadı.\",\n \"clearFilters\": \"Filtreleri Temizle\",\n \"filterDescription\": \"Yazıları kategori, etiket ve daha fazlasına göre filtreleyin\",\n \"readMore\": \"Devamını Oku\",\n \"minRead\": \"dk\",\n \"views\": \"görüntülenme\",\n \"error\": \"Yazılar yüklenemedi\"\n}\n"
|
|
39
|
+
"content": "{\r\n \"title\": \"Blog\",\r\n \"subtitle\": \"En son makalelerimizi ve görüşlerimizi keşfedin\",\r\n \"allPosts\": \"Tüm Yazılar\",\r\n \"featuredPosts\": \"Öne Çıkan Yazılar\",\r\n \"recentPosts\": \"Son Yazılar\",\r\n \"popularPosts\": \"Popüler Yazılar\",\r\n \"categories\": \"Kategoriler\",\r\n \"tags\": \"Etiketler\",\r\n \"filters\": \"Filtreler\",\r\n \"search\": \"Arama\",\r\n \"searchPlaceholder\": \"Yazı ara...\",\r\n \"sortBy\": \"Sırala\",\r\n \"sortNewest\": \"En Yeni\",\r\n \"sortOldest\": \"En Eski\",\r\n \"sortPopular\": \"En Popüler\",\r\n \"sortReadingTime\": \"Okuma Süresi\",\r\n \"showing\": \"Gösterilen\",\r\n \"of\": \"/\",\r\n \"posts\": \"yazı\",\r\n \"for\": \"için\",\r\n \"noPostsFound\": \"Kriterlere uygun yazı bulunamadı.\",\r\n \"clearFilters\": \"Filtreleri Temizle\",\r\n \"filterDescription\": \"Yazıları kategori, etiket ve daha fazlasına göre filtreleyin\",\r\n \"readMore\": \"Devamını Oku\",\r\n \"minRead\": \"dk\",\r\n \"views\": \"görüntülenme\",\r\n \"error\": \"Yazılar yüklenemedi\"\r\n}\r\n"
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
42
|
"exports": {
|
|
@@ -15,25 +15,25 @@
|
|
|
15
15
|
"path": "blog-section/index.ts",
|
|
16
16
|
"type": "registry:index",
|
|
17
17
|
"target": "$modules$/blog-section/index.ts",
|
|
18
|
-
"content": "export * from './blog-section';\n"
|
|
18
|
+
"content": "export * from './blog-section';\r\n"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"path": "blog-section/blog-section.tsx",
|
|
22
22
|
"type": "registry:component",
|
|
23
23
|
"target": "$modules$/blog-section/blog-section.tsx",
|
|
24
|
-
"content": "import { Link } from \"react-router\";\nimport { ArrowRight } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport { cn } from \"@/lib/utils\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Card,\n CardContent,\n CardFooter,\n CardHeader,\n} from \"@/components/ui/card\";\nimport { useRecentPosts } from \"@/modules/blog-core\";\nimport type { Post } from \"@/modules/blog-core/types\";\n\ninterface BlogSectionProps {\n posts?: Post[];\n loading?: boolean;\n className?: string;\n}\n\nexport function BlogSection({\n posts: propPosts,\n loading: propLoading,\n className,\n}: BlogSectionProps) {\n const { t } = useTranslation(\"blog-section\");\n const { posts: hookPosts, loading: hookLoading } = useRecentPosts(3);\n\n const posts = propPosts ?? hookPosts;\n const loading = propLoading ?? hookLoading;\n\n return (\n <section className={cn(\"py-16 md:py-24\", className)}>\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\n {/* Header */}\n <div className=\"text-center mb-12\">\n <Badge variant=\"secondary\" className=\"mb-4\">\n {t(\"tagline\", \"Latest Updates\")}\n </Badge>\n <h2 className=\"text-3xl font-bold md:text-4xl lg:text-5xl mb-4\">\n {t(\"title\", \"From Our Blog\")}\n </h2>\n <p className=\"text-muted-foreground max-w-2xl mx-auto mb-6\">\n {t(\n \"subtitle\",\n \"Discover the latest trends, tips, and insights from our team of experts.\"\n )}\n </p>\n <Button variant=\"link\" asChild>\n <Link to=\"/blog\">\n {t(\"viewAll\", \"View all articles\")}\n <ArrowRight className=\"ml-2 h-4 w-4\" />\n </Link>\n </Button>\n </div>\n\n {/* Posts Grid */}\n <div className=\"grid md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-6xl mx-auto\">\n {loading ? (\n [...Array(3)].map((_, i) => (\n <Card key={i} className=\"overflow-hidden p-0 animate-pulse\">\n <div className=\"aspect-video bg-muted\"></div>\n <CardHeader className=\"pt-6 pb-2\">\n <div className=\"flex items-center gap-2 mb-2\">\n <div className=\"h-5 w-16 bg-muted rounded\"></div>\n <div className=\"h-4 w-20 bg-muted rounded\"></div>\n </div>\n <div className=\"h-6 w-3/4 bg-muted rounded\"></div>\n </CardHeader>\n <CardContent className=\"py-0\">\n <div className=\"h-4 w-full bg-muted rounded mb-2\"></div>\n <div className=\"h-4 w-2/3 bg-muted rounded\"></div>\n </CardContent>\n <CardFooter className=\"pb-2\">\n <div className=\"h-4 w-24 bg-muted rounded\"></div>\n </CardFooter>\n </Card>\n ))\n ) : (\n posts.map((post) => (\n <Card key={post.id} className=\"overflow-hidden group p-0\">\n <div className=\"aspect-video overflow-hidden\">\n <Link to={`/blog/${post.slug}`}>\n <img\n src={post.featured_image || \"/images/placeholder.png\"}\n alt={post.title}\n className=\"w-full h-full object-cover transition-transform duration-300 group-hover:scale-105\"\n onError={(e) => {\n e.currentTarget.style.display = \"none\";\n }}\n />\n </Link>\n </div>\n <CardHeader className=\"pt-6 pb-2\">\n <div className=\"flex items-center gap-2 mb-2\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {post.category_name || post.category}\n </Badge>\n <span className=\"text-xs text-muted-foreground\">\n {new Date(post.published_at).toLocaleDateString()}\n </span>\n </div>\n <Link to={`/blog/${post.slug}`}>\n <h3 className=\"text-lg font-semibold hover:text-primary transition-colors line-clamp-2\">\n {post.title}\n </h3>\n </Link>\n </CardHeader>\n <CardContent className=\"py-0\">\n <p className=\"text-sm text-muted-foreground line-clamp-2\">\n {post.excerpt}\n </p>\n </CardContent>\n <CardFooter className=\"pb-2\">\n <Link\n to={`/blog/${post.slug}`}\n className=\"text-sm font-medium text-primary hover:underline inline-flex items-center whitespace-nowrap\"\n >\n {t(\"readMore\", \"Read more\")}\n <ArrowRight className=\"ml-1 h-3 w-3 shrink-0\" />\n </Link>\n </CardFooter>\n </Card>\n ))\n )}\n </div>\n </div>\n </section>\n );\n}\n"
|
|
24
|
+
"content": "import { Link } from \"react-router\";\r\nimport { ArrowRight } from \"lucide-react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Badge } from \"@/components/ui/badge\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport {\r\n Card,\r\n CardContent,\r\n CardFooter,\r\n CardHeader,\r\n} from \"@/components/ui/card\";\r\nimport { useRecentPosts } from \"@/modules/blog-core\";\r\nimport type { Post } from \"@/modules/blog-core/types\";\r\n\r\ninterface BlogSectionProps {\r\n posts?: Post[];\r\n loading?: boolean;\r\n className?: string;\r\n}\r\n\r\nexport function BlogSection({\r\n posts: propPosts,\r\n loading: propLoading,\r\n className,\r\n}: BlogSectionProps) {\r\n const { t } = useTranslation(\"blog-section\");\r\n const { posts: hookPosts, loading: hookLoading } = useRecentPosts(3);\r\n\r\n const posts = propPosts ?? hookPosts;\r\n const loading = propLoading ?? hookLoading;\r\n\r\n return (\r\n <section className={cn(\"py-16 md:py-24\", className)}>\r\n <div className=\"w-full max-w-[var(--container-max-width)] mx-auto px-4\">\r\n {/* Header */}\r\n <div className=\"text-center mb-12\">\r\n <Badge variant=\"secondary\" className=\"mb-4\">\r\n {t(\"tagline\", \"Latest Updates\")}\r\n </Badge>\r\n <h2 className=\"text-3xl font-bold md:text-4xl lg:text-5xl mb-4\">\r\n {t(\"title\", \"From Our Blog\")}\r\n </h2>\r\n <p className=\"text-muted-foreground max-w-2xl mx-auto mb-6\">\r\n {t(\r\n \"subtitle\",\r\n \"Discover the latest trends, tips, and insights from our team of experts.\"\r\n )}\r\n </p>\r\n <Button variant=\"link\" asChild>\r\n <Link to=\"/blog\">\r\n {t(\"viewAll\", \"View all articles\")}\r\n <ArrowRight className=\"ml-2 h-4 w-4\" />\r\n </Link>\r\n </Button>\r\n </div>\r\n\r\n {/* Posts Grid */}\r\n <div className=\"grid md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-6xl mx-auto\">\r\n {loading ? (\r\n [...Array(3)].map((_, i) => (\r\n <Card key={i} className=\"overflow-hidden p-0 animate-pulse\">\r\n <div className=\"aspect-video bg-muted\"></div>\r\n <CardHeader className=\"pt-6 pb-2\">\r\n <div className=\"flex items-center gap-2 mb-2\">\r\n <div className=\"h-5 w-16 bg-muted rounded\"></div>\r\n <div className=\"h-4 w-20 bg-muted rounded\"></div>\r\n </div>\r\n <div className=\"h-6 w-3/4 bg-muted rounded\"></div>\r\n </CardHeader>\r\n <CardContent className=\"py-0\">\r\n <div className=\"h-4 w-full bg-muted rounded mb-2\"></div>\r\n <div className=\"h-4 w-2/3 bg-muted rounded\"></div>\r\n </CardContent>\r\n <CardFooter className=\"pb-2\">\r\n <div className=\"h-4 w-24 bg-muted rounded\"></div>\r\n </CardFooter>\r\n </Card>\r\n ))\r\n ) : (\r\n posts.map((post) => (\r\n <Card key={post.id} className=\"overflow-hidden group p-0\">\r\n <div className=\"aspect-video overflow-hidden\">\r\n <Link to={`/blog/${post.slug}`}>\r\n <img\r\n src={post.featured_image || \"/images/placeholder.png\"}\r\n alt={post.title}\r\n className=\"w-full h-full object-cover transition-transform duration-300 group-hover:scale-105\"\r\n onError={(e) => {\r\n e.currentTarget.style.display = \"none\";\r\n }}\r\n />\r\n </Link>\r\n </div>\r\n <CardHeader className=\"pt-6 pb-2\">\r\n <div className=\"flex items-center gap-2 mb-2\">\r\n <Badge variant=\"outline\" className=\"text-xs\">\r\n {post.category_name || post.category}\r\n </Badge>\r\n <span className=\"text-xs text-muted-foreground\">\r\n {new Date(post.published_at).toLocaleDateString()}\r\n </span>\r\n </div>\r\n <Link to={`/blog/${post.slug}`}>\r\n <h3 className=\"text-lg font-semibold hover:text-primary transition-colors line-clamp-2\">\r\n {post.title}\r\n </h3>\r\n </Link>\r\n </CardHeader>\r\n <CardContent className=\"py-0\">\r\n <p className=\"text-sm text-muted-foreground line-clamp-2\">\r\n {post.excerpt}\r\n </p>\r\n </CardContent>\r\n <CardFooter className=\"pb-2\">\r\n <Link\r\n to={`/blog/${post.slug}`}\r\n className=\"text-sm font-medium text-primary hover:underline inline-flex items-center whitespace-nowrap\"\r\n >\r\n {t(\"readMore\", \"Read more\")}\r\n <ArrowRight className=\"ml-1 h-3 w-3 shrink-0\" />\r\n </Link>\r\n </CardFooter>\r\n </Card>\r\n ))\r\n )}\r\n </div>\r\n </div>\r\n </section>\r\n );\r\n}\r\n"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"path": "blog-section/lang/en.json",
|
|
28
28
|
"type": "registry:lang",
|
|
29
29
|
"target": "$modules$/blog-section/lang/en.json",
|
|
30
|
-
"content": "{\n \"tagline\": \"Latest Updates\",\n \"title\": \"From Our Blog\",\n \"subtitle\": \"Insights, tutorials, and stories to help you succeed.\",\n \"viewAll\": \"View all articles\",\n \"readMore\": \"Read more\",\n \"post1Title\": \"Getting Started: A Complete Guide\",\n \"post1Summary\": \"Learn the essential steps to launch your project successfully and avoid common pitfalls.\",\n \"post1Category\": \"Tutorial\",\n \"post1Author\": \"Sarah Chen\",\n \"post1Date\": \"Jan 15, 2024\",\n \"post2Title\": \"10 Best Practices You Need to Know\",\n \"post2Summary\": \"Discover proven strategies that will help you work smarter and achieve better results.\",\n \"post2Category\": \"Best Practices\",\n \"post2Author\": \"Michael Park\",\n \"post2Date\": \"Jan 10, 2024\",\n \"post3Title\": \"Design Trends That Matter in 2024\",\n \"post3Summary\": \"Stay ahead of the curve with these emerging design trends shaping the industry.\",\n \"post3Category\": \"Design\",\n \"post3Author\": \"Emily Davis\",\n \"post3Date\": \"Jan 5, 2024\"\n}"
|
|
30
|
+
"content": "{\r\n \"tagline\": \"Latest Updates\",\r\n \"title\": \"From Our Blog\",\r\n \"subtitle\": \"Insights, tutorials, and stories to help you succeed.\",\r\n \"viewAll\": \"View all articles\",\r\n \"readMore\": \"Read more\",\r\n \"post1Title\": \"Getting Started: A Complete Guide\",\r\n \"post1Summary\": \"Learn the essential steps to launch your project successfully and avoid common pitfalls.\",\r\n \"post1Category\": \"Tutorial\",\r\n \"post1Author\": \"Sarah Chen\",\r\n \"post1Date\": \"Jan 15, 2024\",\r\n \"post2Title\": \"10 Best Practices You Need to Know\",\r\n \"post2Summary\": \"Discover proven strategies that will help you work smarter and achieve better results.\",\r\n \"post2Category\": \"Best Practices\",\r\n \"post2Author\": \"Michael Park\",\r\n \"post2Date\": \"Jan 10, 2024\",\r\n \"post3Title\": \"Design Trends That Matter in 2024\",\r\n \"post3Summary\": \"Stay ahead of the curve with these emerging design trends shaping the industry.\",\r\n \"post3Category\": \"Design\",\r\n \"post3Author\": \"Emily Davis\",\r\n \"post3Date\": \"Jan 5, 2024\"\r\n}"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"path": "blog-section/lang/tr.json",
|
|
34
34
|
"type": "registry:lang",
|
|
35
35
|
"target": "$modules$/blog-section/lang/tr.json",
|
|
36
|
-
"content": "{\n \"tagline\": \"Son Güncellemeler\",\n \"title\": \"Blogumuzdan\",\n \"subtitle\": \"Ekibimizden içgörüler, ipuçları ve hikayeleri keşfedin.\",\n \"viewAll\": \"Tüm makaleleri görüntüle\",\n \"readMore\": \"Devamını oku\",\n \"post1Title\": \"Başlangıç Rehberi\",\n \"post1Summary\": \"Kapsamlı rehberimizle hızlı bir şekilde başlamak için temel adımları öğrenin.\",\n \"post1Category\": \"Eğitim\",\n \"post1Author\": \"Sarah Chen\",\n \"post1Date\": \"15 Ocak 2024\",\n \"post2Title\": \"Başarı İçin En İyi Uygulamalar\",\n \"post2Summary\": \"Daha iyi sonuçlar elde etmenize yardımcı olan kanıtlanmış stratejileri keşfedin.\",\n \"post2Category\": \"En İyi Uygulamalar\",\n \"post2Author\": \"Michael Park\",\n \"post2Date\": \"10 Ocak 2024\",\n \"post3Title\": \"2024 Tasarım Trendleri\",\n \"post3Summary\": \"En son tasarım trendlerini ve projelerinizde nasıl uygulayacağınızı keşfedin.\",\n \"post3Category\": \"Tasarım\",\n \"post3Author\": \"Emily Davis\",\n \"post3Date\": \"5 Ocak 2024\"\n}"
|
|
36
|
+
"content": "{\r\n \"tagline\": \"Son Güncellemeler\",\r\n \"title\": \"Blogumuzdan\",\r\n \"subtitle\": \"Ekibimizden içgörüler, ipuçları ve hikayeleri keşfedin.\",\r\n \"viewAll\": \"Tüm makaleleri görüntüle\",\r\n \"readMore\": \"Devamını oku\",\r\n \"post1Title\": \"Başlangıç Rehberi\",\r\n \"post1Summary\": \"Kapsamlı rehberimizle hızlı bir şekilde başlamak için temel adımları öğrenin.\",\r\n \"post1Category\": \"Eğitim\",\r\n \"post1Author\": \"Sarah Chen\",\r\n \"post1Date\": \"15 Ocak 2024\",\r\n \"post2Title\": \"Başarı İçin En İyi Uygulamalar\",\r\n \"post2Summary\": \"Daha iyi sonuçlar elde etmenize yardımcı olan kanıtlanmış stratejileri keşfedin.\",\r\n \"post2Category\": \"En İyi Uygulamalar\",\r\n \"post2Author\": \"Michael Park\",\r\n \"post2Date\": \"10 Ocak 2024\",\r\n \"post3Title\": \"2024 Tasarım Trendleri\",\r\n \"post3Summary\": \"En son tasarım trendlerini ve projelerinizde nasıl uygulayacağınızı keşfedin.\",\r\n \"post3Category\": \"Tasarım\",\r\n \"post3Author\": \"Emily Davis\",\r\n \"post3Date\": \"5 Ocak 2024\"\r\n}"
|
|
37
37
|
}
|
|
38
38
|
],
|
|
39
39
|
"exports": {
|
|
@@ -14,25 +14,25 @@
|
|
|
14
14
|
"path": "cards-carousel-section/index.ts",
|
|
15
15
|
"type": "registry:index",
|
|
16
16
|
"target": "$modules$/cards-carousel-section/index.ts",
|
|
17
|
-
"content": "export * from './cards-carousel-section';\n"
|
|
17
|
+
"content": "export * from './cards-carousel-section';\r\n"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"path": "cards-carousel-section/cards-carousel-section.tsx",
|
|
21
21
|
"type": "registry:component",
|
|
22
22
|
"target": "$modules$/cards-carousel-section/cards-carousel-section.tsx",
|
|
23
|
-
"content": "import { useEffect, useRef, useState, createContext, useContext } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { X, ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\n// Context for outside click detection\nconst CarouselContext = createContext<{\n onCardClose: (index: number) => void;\n currentIndex: number;\n}>({\n onCardClose: () => {},\n currentIndex: 0,\n});\n\n// Card interface\ninterface CardData {\n category: string;\n title: string;\n src: string;\n content: ReactNode;\n}\n\n// Card Component\nexport function Card({\n card,\n index,\n layout = false,\n}: {\n card: CardData;\n index: number;\n layout?: boolean;\n}) {\n const [open, setOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const { onCardClose } = useContext(CarouselContext);\n\n const handleOpen = () => setOpen(true);\n const handleClose = () => {\n setOpen(false);\n onCardClose(index);\n };\n\n useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if (event.key === \"Escape\") {\n handleClose();\n }\n }\n\n if (open) {\n document.body.style.overflow = \"hidden\";\n window.addEventListener(\"keydown\", onKeyDown);\n } else {\n document.body.style.overflow = \"auto\";\n }\n\n return () => {\n window.removeEventListener(\"keydown\", onKeyDown);\n document.body.style.overflow = \"auto\";\n };\n }, [open, handleClose]);\n\n return (\n <>\n <AnimatePresence>\n {open && (\n <div className=\"fixed inset-0 h-screen z-50 overflow-auto\">\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n className=\"bg-black/80 backdrop-blur-lg h-full w-full fixed inset-0\"\n onClick={handleClose}\n />\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n ref={containerRef}\n layoutId={layout ? `card-${card.title}` : undefined}\n className=\"max-w-5xl mx-auto bg-white dark:bg-neutral-900 h-fit z-[60] my-10 p-4 md:p-10 rounded-3xl relative\"\n >\n <button\n className=\"sticky top-4 h-8 w-8 right-0 ml-auto bg-black dark:bg-white rounded-full flex items-center justify-center\"\n onClick={handleClose}\n >\n <X className=\"h-6 w-6 text-neutral-100 dark:text-neutral-900\" />\n </button>\n <motion.p\n layoutId={layout ? `category-${card.title}` : undefined}\n className=\"text-base font-medium text-black dark:text-white\"\n >\n {card.category}\n </motion.p>\n <motion.p\n layoutId={layout ? `title-${card.title}` : undefined}\n className=\"text-2xl md:text-5xl font-semibold text-neutral-700 mt-4 dark:text-white\"\n >\n {card.title}\n </motion.p>\n <div className=\"py-10\">{card.content}</div>\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n <motion.button\n layoutId={layout ? `card-${card.title}` : undefined}\n onClick={handleOpen}\n className=\"rounded-3xl bg-gray-100 dark:bg-neutral-900 h-80 w-56 md:h-[40rem] md:w-96 overflow-hidden flex flex-col items-start justify-start relative z-10\"\n >\n <div className=\"absolute h-full top-0 inset-x-0 bg-gradient-to-b from-black/50 via-transparent to-transparent z-30 pointer-events-none\" />\n <div className=\"relative z-40 p-8\">\n <motion.p\n layoutId={layout ? `category-${card.title}` : undefined}\n className=\"text-white text-sm md:text-base font-medium text-left\"\n >\n {card.category}\n </motion.p>\n <motion.p\n layoutId={layout ? `title-${card.title}` : undefined}\n className=\"text-white text-xl md:text-3xl font-semibold max-w-xs text-left mt-2\"\n >\n {card.title}\n </motion.p>\n </div>\n <img\n src={card.src}\n alt={card.title}\n className=\"object-cover absolute z-10 inset-0 w-full h-full\"\n />\n </motion.button>\n </>\n );\n}\n\n// Carousel Component\nexport function Carousel({ items }: { items: ReactNode[] }) {\n const carouselRef = useRef<HTMLDivElement>(null);\n const [canScrollLeft, setCanScrollLeft] = useState(false);\n const [canScrollRight, setCanScrollRight] = useState(true);\n const [currentIndex, setCurrentIndex] = useState(0);\n\n const checkScrollability = () => {\n if (carouselRef.current) {\n const { scrollLeft, scrollWidth, clientWidth } = carouselRef.current;\n setCanScrollLeft(scrollLeft > 0);\n setCanScrollRight(scrollLeft < scrollWidth - clientWidth);\n }\n };\n\n useEffect(() => {\n checkScrollability();\n }, []);\n\n const scrollLeft = () => {\n if (carouselRef.current) {\n carouselRef.current.scrollBy({ left: -300, behavior: \"smooth\" });\n }\n };\n\n const scrollRight = () => {\n if (carouselRef.current) {\n carouselRef.current.scrollBy({ left: 300, behavior: \"smooth\" });\n }\n };\n\n const handleCardClose = (index: number) => {\n if (carouselRef.current) {\n const cardWidth = isMobile() ? 230 : 384;\n const gap = isMobile() ? 4 : 8;\n const scrollPosition = (cardWidth + gap) * (index + 1);\n carouselRef.current.scrollTo({\n left: scrollPosition,\n behavior: \"smooth\",\n });\n setCurrentIndex(index);\n }\n };\n\n const isMobile = () => {\n return window && window.innerWidth < 768;\n };\n\n return (\n <CarouselContext.Provider value={{ onCardClose: handleCardClose, currentIndex }}>\n <div className=\"relative w-full\">\n <div\n className=\"flex w-full overflow-x-scroll overscroll-x-auto py-10 md:py-20 scroll-smooth [scrollbar-width:none]\"\n ref={carouselRef}\n onScroll={checkScrollability}\n >\n <div className=\"absolute right-0 z-[1000] h-auto w-[5%] overflow-hidden bg-gradient-to-l from-background to-transparent pointer-events-none\" />\n <div className=\"flex flex-row justify-start gap-4 pl-4 max-w-7xl mx-auto\">\n {items.map((item, index) => (\n <motion.div\n initial={{ opacity: 0, y: 20 }}\n animate={{\n opacity: 1,\n y: 0,\n transition: {\n duration: 0.5,\n delay: 0.2 * index,\n ease: \"easeOut\",\n },\n }}\n key={\"card\" + index}\n className=\"last:pr-[5%] md:last:pr-[33%] rounded-3xl\"\n >\n {item}\n </motion.div>\n ))}\n </div>\n </div>\n <div className=\"flex justify-end gap-2 mr-10\">\n <button\n className=\"relative z-40 h-10 w-10 rounded-full bg-gray-100 flex items-center justify-center disabled:opacity-50\"\n onClick={scrollLeft}\n disabled={!canScrollLeft}\n >\n <ChevronLeft className=\"h-6 w-6 text-gray-500\" />\n </button>\n <button\n className=\"relative z-40 h-10 w-10 rounded-full bg-gray-100 flex items-center justify-center disabled:opacity-50\"\n onClick={scrollRight}\n disabled={!canScrollRight}\n >\n <ChevronRight className=\"h-6 w-6 text-gray-500\" />\n </button>\n </div>\n </div>\n </CarouselContext.Provider>\n );\n}\n\n// Section Component\ninterface CardsCarouselSectionProps {\n title?: string;\n items: CardData[];\n className?: string;\n}\n\nexport function CardsCarouselSection({\n title,\n items,\n className,\n}: CardsCarouselSectionProps) {\n const cards = items.map((card, index) => (\n <Card key={card.src} card={card} index={index} />\n ));\n\n return (\n <section className={cn(\"w-full py-16 md:py-20\", className)}>\n {title && (\n <h2 className=\"max-w-7xl pl-4 mx-auto text-xl md:text-5xl font-bold text-neutral-800 dark:text-neutral-200\">\n {title}\n </h2>\n )}\n <Carousel items={cards} />\n </section>\n );\n}\n"
|
|
23
|
+
"content": "import { useEffect, useRef, useState, createContext, useContext } from \"react\";\r\nimport type { ReactNode } from \"react\";\r\nimport { motion, AnimatePresence } from \"framer-motion\";\r\nimport { X, ChevronLeft, ChevronRight } from \"lucide-react\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\n// Context for outside click detection\r\nconst CarouselContext = createContext<{\r\n onCardClose: (index: number) => void;\r\n currentIndex: number;\r\n}>({\r\n onCardClose: () => {},\r\n currentIndex: 0,\r\n});\r\n\r\n// Card interface\r\ninterface CardData {\r\n category: string;\r\n title: string;\r\n src: string;\r\n content: ReactNode;\r\n}\r\n\r\n// Card Component\r\nexport function Card({\r\n card,\r\n index,\r\n layout = false,\r\n}: {\r\n card: CardData;\r\n index: number;\r\n layout?: boolean;\r\n}) {\r\n const [open, setOpen] = useState(false);\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const { onCardClose } = useContext(CarouselContext);\r\n\r\n const handleOpen = () => setOpen(true);\r\n const handleClose = () => {\r\n setOpen(false);\r\n onCardClose(index);\r\n };\r\n\r\n useEffect(() => {\r\n function onKeyDown(event: KeyboardEvent) {\r\n if (event.key === \"Escape\") {\r\n handleClose();\r\n }\r\n }\r\n\r\n if (open) {\r\n document.body.style.overflow = \"hidden\";\r\n window.addEventListener(\"keydown\", onKeyDown);\r\n } else {\r\n document.body.style.overflow = \"auto\";\r\n }\r\n\r\n return () => {\r\n window.removeEventListener(\"keydown\", onKeyDown);\r\n document.body.style.overflow = \"auto\";\r\n };\r\n }, [open, handleClose]);\r\n\r\n return (\r\n <>\r\n <AnimatePresence>\r\n {open && (\r\n <div className=\"fixed inset-0 h-screen z-50 overflow-auto\">\r\n <motion.div\r\n initial={{ opacity: 0 }}\r\n animate={{ opacity: 1 }}\r\n exit={{ opacity: 0 }}\r\n className=\"bg-black/80 backdrop-blur-lg h-full w-full fixed inset-0\"\r\n onClick={handleClose}\r\n />\r\n <motion.div\r\n initial={{ opacity: 0 }}\r\n animate={{ opacity: 1 }}\r\n exit={{ opacity: 0 }}\r\n ref={containerRef}\r\n layoutId={layout ? `card-${card.title}` : undefined}\r\n className=\"max-w-5xl mx-auto bg-white dark:bg-neutral-900 h-fit z-[60] my-10 p-4 md:p-10 rounded-3xl relative\"\r\n >\r\n <button\r\n className=\"sticky top-4 h-8 w-8 right-0 ml-auto bg-black dark:bg-white rounded-full flex items-center justify-center\"\r\n onClick={handleClose}\r\n >\r\n <X className=\"h-6 w-6 text-neutral-100 dark:text-neutral-900\" />\r\n </button>\r\n <motion.p\r\n layoutId={layout ? `category-${card.title}` : undefined}\r\n className=\"text-base font-medium text-black dark:text-white\"\r\n >\r\n {card.category}\r\n </motion.p>\r\n <motion.p\r\n layoutId={layout ? `title-${card.title}` : undefined}\r\n className=\"text-2xl md:text-5xl font-semibold text-neutral-700 mt-4 dark:text-white\"\r\n >\r\n {card.title}\r\n </motion.p>\r\n <div className=\"py-10\">{card.content}</div>\r\n </motion.div>\r\n </div>\r\n )}\r\n </AnimatePresence>\r\n <motion.button\r\n layoutId={layout ? `card-${card.title}` : undefined}\r\n onClick={handleOpen}\r\n className=\"rounded-3xl bg-gray-100 dark:bg-neutral-900 h-80 w-56 md:h-[40rem] md:w-96 overflow-hidden flex flex-col items-start justify-start relative z-10\"\r\n >\r\n <div className=\"absolute h-full top-0 inset-x-0 bg-gradient-to-b from-black/50 via-transparent to-transparent z-30 pointer-events-none\" />\r\n <div className=\"relative z-40 p-8\">\r\n <motion.p\r\n layoutId={layout ? `category-${card.title}` : undefined}\r\n className=\"text-white text-sm md:text-base font-medium text-left\"\r\n >\r\n {card.category}\r\n </motion.p>\r\n <motion.p\r\n layoutId={layout ? `title-${card.title}` : undefined}\r\n className=\"text-white text-xl md:text-3xl font-semibold max-w-xs text-left mt-2\"\r\n >\r\n {card.title}\r\n </motion.p>\r\n </div>\r\n <img\r\n src={card.src}\r\n alt={card.title}\r\n className=\"object-cover absolute z-10 inset-0 w-full h-full\"\r\n />\r\n </motion.button>\r\n </>\r\n );\r\n}\r\n\r\n// Carousel Component\r\nexport function Carousel({ items }: { items: ReactNode[] }) {\r\n const carouselRef = useRef<HTMLDivElement>(null);\r\n const [canScrollLeft, setCanScrollLeft] = useState(false);\r\n const [canScrollRight, setCanScrollRight] = useState(true);\r\n const [currentIndex, setCurrentIndex] = useState(0);\r\n\r\n const checkScrollability = () => {\r\n if (carouselRef.current) {\r\n const { scrollLeft, scrollWidth, clientWidth } = carouselRef.current;\r\n setCanScrollLeft(scrollLeft > 0);\r\n setCanScrollRight(scrollLeft < scrollWidth - clientWidth);\r\n }\r\n };\r\n\r\n useEffect(() => {\r\n checkScrollability();\r\n }, []);\r\n\r\n const scrollLeft = () => {\r\n if (carouselRef.current) {\r\n carouselRef.current.scrollBy({ left: -300, behavior: \"smooth\" });\r\n }\r\n };\r\n\r\n const scrollRight = () => {\r\n if (carouselRef.current) {\r\n carouselRef.current.scrollBy({ left: 300, behavior: \"smooth\" });\r\n }\r\n };\r\n\r\n const handleCardClose = (index: number) => {\r\n if (carouselRef.current) {\r\n const cardWidth = isMobile() ? 230 : 384;\r\n const gap = isMobile() ? 4 : 8;\r\n const scrollPosition = (cardWidth + gap) * (index + 1);\r\n carouselRef.current.scrollTo({\r\n left: scrollPosition,\r\n behavior: \"smooth\",\r\n });\r\n setCurrentIndex(index);\r\n }\r\n };\r\n\r\n const isMobile = () => {\r\n return window && window.innerWidth < 768;\r\n };\r\n\r\n return (\r\n <CarouselContext.Provider value={{ onCardClose: handleCardClose, currentIndex }}>\r\n <div className=\"relative w-full\">\r\n <div\r\n className=\"flex w-full overflow-x-scroll overscroll-x-auto py-10 md:py-20 scroll-smooth [scrollbar-width:none]\"\r\n ref={carouselRef}\r\n onScroll={checkScrollability}\r\n >\r\n <div className=\"absolute right-0 z-[1000] h-auto w-[5%] overflow-hidden bg-gradient-to-l from-background to-transparent pointer-events-none\" />\r\n <div className=\"flex flex-row justify-start gap-4 pl-4 max-w-7xl mx-auto\">\r\n {items.map((item, index) => (\r\n <motion.div\r\n initial={{ opacity: 0, y: 20 }}\r\n animate={{\r\n opacity: 1,\r\n y: 0,\r\n transition: {\r\n duration: 0.5,\r\n delay: 0.2 * index,\r\n ease: \"easeOut\",\r\n },\r\n }}\r\n key={\"card\" + index}\r\n className=\"last:pr-[5%] md:last:pr-[33%] rounded-3xl\"\r\n >\r\n {item}\r\n </motion.div>\r\n ))}\r\n </div>\r\n </div>\r\n <div className=\"flex justify-end gap-2 mr-10\">\r\n <button\r\n className=\"relative z-40 h-10 w-10 rounded-full bg-gray-100 flex items-center justify-center disabled:opacity-50\"\r\n onClick={scrollLeft}\r\n disabled={!canScrollLeft}\r\n >\r\n <ChevronLeft className=\"h-6 w-6 text-gray-500\" />\r\n </button>\r\n <button\r\n className=\"relative z-40 h-10 w-10 rounded-full bg-gray-100 flex items-center justify-center disabled:opacity-50\"\r\n onClick={scrollRight}\r\n disabled={!canScrollRight}\r\n >\r\n <ChevronRight className=\"h-6 w-6 text-gray-500\" />\r\n </button>\r\n </div>\r\n </div>\r\n </CarouselContext.Provider>\r\n );\r\n}\r\n\r\n// Section Component\r\ninterface CardsCarouselSectionProps {\r\n title?: string;\r\n items: CardData[];\r\n className?: string;\r\n}\r\n\r\nexport function CardsCarouselSection({\r\n title,\r\n items,\r\n className,\r\n}: CardsCarouselSectionProps) {\r\n const cards = items.map((card, index) => (\r\n <Card key={card.src} card={card} index={index} />\r\n ));\r\n\r\n return (\r\n <section className={cn(\"w-full py-16 md:py-20\", className)}>\r\n {title && (\r\n <h2 className=\"max-w-7xl pl-4 mx-auto text-xl md:text-5xl font-bold text-neutral-800 dark:text-neutral-200\">\r\n {title}\r\n </h2>\r\n )}\r\n <Carousel items={cards} />\r\n </section>\r\n );\r\n}\r\n"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"path": "cards-carousel-section/lang/en.json",
|
|
27
27
|
"type": "registry:lang",
|
|
28
28
|
"target": "$modules$/cards-carousel-section/lang/en.json",
|
|
29
|
-
"content": "{\n \"title\": \"Explore\"\n}\n"
|
|
29
|
+
"content": "{\r\n \"title\": \"Explore\"\r\n}\r\n"
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"path": "cards-carousel-section/lang/tr.json",
|
|
33
33
|
"type": "registry:lang",
|
|
34
34
|
"target": "$modules$/cards-carousel-section/lang/tr.json",
|
|
35
|
-
"content": "{\n \"title\": \"Keşfet\"\n}\n"
|
|
35
|
+
"content": "{\r\n \"title\": \"Keşfet\"\r\n}\r\n"
|
|
36
36
|
}
|
|
37
37
|
],
|
|
38
38
|
"exports": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"path": "cart-drawer/index.ts",
|
|
15
15
|
"type": "registry:index",
|
|
16
16
|
"target": "$modules$/cart-drawer/index.ts",
|
|
17
|
-
"content": "export * from './cart-drawer';\n"
|
|
17
|
+
"content": "export * from './cart-drawer';\r\n"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"path": "cart-drawer/cart-drawer.tsx",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"path": "cart-drawer/lang/en.json",
|
|
27
27
|
"type": "registry:lang",
|
|
28
28
|
"target": "$modules$/cart-drawer/lang/en.json",
|
|
29
|
-
"content": "{\n \"title\": \"Shopping cart\",\n \"empty\": \"Your cart is empty\",\n \"qty\": \"Qty\",\n \"remove\": \"Remove\",\n \"subtotal\": \"Subtotal\",\n \"shippingNote\": \"Shipping and taxes calculated at checkout.\",\n \"checkout\": \"Checkout\",\n \"or\": \"or\",\n \"continueShopping\": \"Continue Shopping\"\n}\n"
|
|
29
|
+
"content": "{\r\n \"title\": \"Shopping cart\",\r\n \"empty\": \"Your cart is empty\",\r\n \"qty\": \"Qty\",\r\n \"remove\": \"Remove\",\r\n \"subtotal\": \"Subtotal\",\r\n \"shippingNote\": \"Shipping and taxes calculated at checkout.\",\r\n \"checkout\": \"Checkout\",\r\n \"or\": \"or\",\r\n \"continueShopping\": \"Continue Shopping\"\r\n}\r\n"
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"path": "cart-drawer/lang/tr.json",
|
|
33
33
|
"type": "registry:lang",
|
|
34
34
|
"target": "$modules$/cart-drawer/lang/tr.json",
|
|
35
|
-
"content": "{\n \"title\": \"Sepet\",\n \"empty\": \"Sepetiniz boş\",\n \"qty\": \"Adet\",\n \"remove\": \"Kaldır\",\n \"subtotal\": \"Ara Toplam\",\n \"shippingNote\": \"Kargo ve vergiler ödeme sırasında hesaplanır.\",\n \"checkout\": \"Ödemeye Geç\",\n \"or\": \"veya\",\n \"continueShopping\": \"Alışverişe Devam Et\"\n}\n"
|
|
35
|
+
"content": "{\r\n \"title\": \"Sepet\",\r\n \"empty\": \"Sepetiniz boş\",\r\n \"qty\": \"Adet\",\r\n \"remove\": \"Kaldır\",\r\n \"subtotal\": \"Ara Toplam\",\r\n \"shippingNote\": \"Kargo ve vergiler ödeme sırasında hesaplanır.\",\r\n \"checkout\": \"Ödemeye Geç\",\r\n \"or\": \"veya\",\r\n \"continueShopping\": \"Alışverişe Devam Et\"\r\n}\r\n"
|
|
36
36
|
}
|
|
37
37
|
],
|
|
38
38
|
"exports": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"path": "cart-page/index.ts",
|
|
18
18
|
"type": "registry:index",
|
|
19
19
|
"target": "$modules$/cart-page/index.ts",
|
|
20
|
-
"content": "export * from './cart-page';\nexport { CartPage as default } from './cart-page';\n"
|
|
20
|
+
"content": "export * from './cart-page';\r\nexport { CartPage as default } from './cart-page';\r\n"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"path": "cart-page/cart-page.tsx",
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
"path": "cart-page/lang/en.json",
|
|
30
30
|
"type": "registry:lang",
|
|
31
31
|
"target": "$modules$/cart-page/lang/en.json",
|
|
32
|
-
"content": "{\n \"pageTitle\": \"Shopping Cart\",\n \"title\": \"Shopping Cart\",\n \"empty\": \"Your Cart is Empty\",\n \"emptyDescription\": \"Looks like you haven't added any items to your cart yet.\",\n \"addToCart\": \"Add to Cart\",\n \"removeItem\": \"Remove Item\",\n \"quantity\": \"Quantity\",\n \"subtotal\": \"Subtotal\",\n \"shipping\": \"Shipping\",\n \"tax\": \"Tax\",\n \"total\": \"Total\",\n \"proceedToCheckout\": \"Proceed to Checkout\",\n \"secureCheckout\": \"Secure Checkout\",\n \"orderSummary\": \"Order Summary\",\n \"itemsInCart\": \"items in your cart\",\n \"items\": \"items\",\n \"variant\": \"Variant\",\n \"each\": \"each\",\n \"freeShippingMessage\": \"Add {{amount}} more for free shipping!\",\n \"continueShopping\": \"Continue Shopping\",\n \"secureCheckoutDescription\": \"Your payment information is encrypted and secure\",\n \"free\": \"Free\"\n}\n"
|
|
32
|
+
"content": "{\r\n \"pageTitle\": \"Shopping Cart\",\r\n \"title\": \"Shopping Cart\",\r\n \"empty\": \"Your Cart is Empty\",\r\n \"emptyDescription\": \"Looks like you haven't added any items to your cart yet.\",\r\n \"addToCart\": \"Add to Cart\",\r\n \"removeItem\": \"Remove Item\",\r\n \"quantity\": \"Quantity\",\r\n \"subtotal\": \"Subtotal\",\r\n \"shipping\": \"Shipping\",\r\n \"tax\": \"Tax\",\r\n \"total\": \"Total\",\r\n \"proceedToCheckout\": \"Proceed to Checkout\",\r\n \"secureCheckout\": \"Secure Checkout\",\r\n \"orderSummary\": \"Order Summary\",\r\n \"itemsInCart\": \"items in your cart\",\r\n \"items\": \"items\",\r\n \"variant\": \"Variant\",\r\n \"each\": \"each\",\r\n \"freeShippingMessage\": \"Add {{amount}} more for free shipping!\",\r\n \"continueShopping\": \"Continue Shopping\",\r\n \"secureCheckoutDescription\": \"Your payment information is encrypted and secure\",\r\n \"free\": \"Free\"\r\n}\r\n"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"path": "cart-page/lang/tr.json",
|
|
36
36
|
"type": "registry:lang",
|
|
37
37
|
"target": "$modules$/cart-page/lang/tr.json",
|
|
38
|
-
"content": "{\n \"pageTitle\": \"Alışveriş Sepeti\",\n \"title\": \"Alışveriş Sepeti\",\n \"empty\": \"Sepetiniz Boş\",\n \"emptyDescription\": \"Henüz sepetinize hiç ürün eklememişsiniz.\",\n \"addToCart\": \"Sepete Ekle\",\n \"removeItem\": \"Ürünü Kaldır\",\n \"quantity\": \"Adet\",\n \"subtotal\": \"Ara Toplam\",\n \"shipping\": \"Kargo\",\n \"tax\": \"Vergi\",\n \"total\": \"Toplam\",\n \"proceedToCheckout\": \"Ödemeye Geç\",\n \"secureCheckout\": \"Güvenli Ödeme\",\n \"orderSummary\": \"Sipariş Özeti\",\n \"itemsInCart\": \"sepetinizdeki ürün\",\n \"items\": \"ürün\",\n \"variant\": \"Varyant\",\n \"each\": \"adet\",\n \"freeShippingMessage\": \"Ücretsiz kargo için {{amount}} daha ekleyin!\",\n \"continueShopping\": \"Alışverişe Devam Et\",\n \"secureCheckoutDescription\": \"Ödeme bilgileriniz şifreli ve güvenlidir\",\n \"free\": \"Ücretsiz\"\n}\n"
|
|
38
|
+
"content": "{\r\n \"pageTitle\": \"Alışveriş Sepeti\",\r\n \"title\": \"Alışveriş Sepeti\",\r\n \"empty\": \"Sepetiniz Boş\",\r\n \"emptyDescription\": \"Henüz sepetinize hiç ürün eklememişsiniz.\",\r\n \"addToCart\": \"Sepete Ekle\",\r\n \"removeItem\": \"Ürünü Kaldır\",\r\n \"quantity\": \"Adet\",\r\n \"subtotal\": \"Ara Toplam\",\r\n \"shipping\": \"Kargo\",\r\n \"tax\": \"Vergi\",\r\n \"total\": \"Toplam\",\r\n \"proceedToCheckout\": \"Ödemeye Geç\",\r\n \"secureCheckout\": \"Güvenli Ödeme\",\r\n \"orderSummary\": \"Sipariş Özeti\",\r\n \"itemsInCart\": \"sepetinizdeki ürün\",\r\n \"items\": \"ürün\",\r\n \"variant\": \"Varyant\",\r\n \"each\": \"adet\",\r\n \"freeShippingMessage\": \"Ücretsiz kargo için {{amount}} daha ekleyin!\",\r\n \"continueShopping\": \"Alışverişe Devam Et\",\r\n \"secureCheckoutDescription\": \"Ödeme bilgileriniz şifreli ve güvenlidir\",\r\n \"free\": \"Ücretsiz\"\r\n}\r\n"
|
|
39
39
|
}
|
|
40
40
|
],
|
|
41
41
|
"exports": {
|
|
@@ -23,19 +23,19 @@
|
|
|
23
23
|
"path": "case-study-page/index.ts",
|
|
24
24
|
"type": "registry:index",
|
|
25
25
|
"target": "$modules$/case-study-page/index.ts",
|
|
26
|
-
"content": "export * from \"./case-study-page\";\nexport { CaseStudyPage as default } from \"./case-study-page\";\n"
|
|
26
|
+
"content": "export * from \"./case-study-page\";\r\nexport { CaseStudyPage as default } from \"./case-study-page\";\r\n"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"path": "case-study-page/lang/en.json",
|
|
30
30
|
"type": "registry:lang",
|
|
31
31
|
"target": "$modules$/case-study-page/lang/en.json",
|
|
32
|
-
"content": "{\n \"pageTitle\": \"Case Study\",\n \"title\": \"E-commerce Platform Redesign\",\n \"subtitle\": \"Let Promake tailor this case study to your actual project.\",\n \"sections\": {\n \"challenge\": {\n \"title\": \"The Challenge\",\n \"content\": \"The client needed a complete overhaul of their e-commerce platform to improve user experience, increase conversion rates, and modernize their brand presence. The existing platform was outdated, had poor mobile support, and suffered from slow load times that were affecting sales.\"\n },\n \"solution\": {\n \"title\": \"Our Solution\",\n \"content\": \"We designed and developed a modern, responsive e-commerce platform with a focus on performance and user experience. Key improvements included a streamlined checkout process, advanced product filtering, personalized recommendations, and a complete visual redesign that aligned with the client's evolved brand identity.\"\n },\n \"results\": {\n \"title\": \"The Results\",\n \"content\": \"After launch, the client saw a 45% increase in conversion rates, 60% improvement in page load times, and a 35% increase in mobile sales. Customer satisfaction scores improved by 28%, and the average order value increased by 22%.\"\n }\n },\n \"gallery\": \"Project Gallery\",\n \"projectDetails\": \"Project Details\",\n \"labels\": {\n \"client\": \"Client\",\n \"date\": \"Date\",\n \"category\": \"Category\",\n \"services\": \"Services\"\n },\n \"details\": {\n \"client\": \"Acme Corporation\",\n \"date\": \"January 2024\",\n \"category\": \"Web Design\",\n \"services\": [\"UX Design\", \"UI Design\", \"Development\"]\n },\n \"visitWebsite\": \"Visit Website\",\n \"share\": \"Share This Project\",\n \"navigation\": {\n \"prev\": \"Previous Project\",\n \"next\": \"Next Project\"\n },\n \"prev\": \"Prev\",\n \"next\": \"Next\",\n \"allProjects\": \"All Projects\"\n}\n"
|
|
32
|
+
"content": "{\r\n \"pageTitle\": \"Case Study\",\r\n \"title\": \"E-commerce Platform Redesign\",\r\n \"subtitle\": \"Let Promake tailor this case study to your actual project.\",\r\n \"sections\": {\r\n \"challenge\": {\r\n \"title\": \"The Challenge\",\r\n \"content\": \"The client needed a complete overhaul of their e-commerce platform to improve user experience, increase conversion rates, and modernize their brand presence. The existing platform was outdated, had poor mobile support, and suffered from slow load times that were affecting sales.\"\r\n },\r\n \"solution\": {\r\n \"title\": \"Our Solution\",\r\n \"content\": \"We designed and developed a modern, responsive e-commerce platform with a focus on performance and user experience. Key improvements included a streamlined checkout process, advanced product filtering, personalized recommendations, and a complete visual redesign that aligned with the client's evolved brand identity.\"\r\n },\r\n \"results\": {\r\n \"title\": \"The Results\",\r\n \"content\": \"After launch, the client saw a 45% increase in conversion rates, 60% improvement in page load times, and a 35% increase in mobile sales. Customer satisfaction scores improved by 28%, and the average order value increased by 22%.\"\r\n }\r\n },\r\n \"gallery\": \"Project Gallery\",\r\n \"projectDetails\": \"Project Details\",\r\n \"labels\": {\r\n \"client\": \"Client\",\r\n \"date\": \"Date\",\r\n \"category\": \"Category\",\r\n \"services\": \"Services\"\r\n },\r\n \"details\": {\r\n \"client\": \"Acme Corporation\",\r\n \"date\": \"January 2024\",\r\n \"category\": \"Web Design\",\r\n \"services\": [\"UX Design\", \"UI Design\", \"Development\"]\r\n },\r\n \"visitWebsite\": \"Visit Website\",\r\n \"share\": \"Share This Project\",\r\n \"navigation\": {\r\n \"prev\": \"Previous Project\",\r\n \"next\": \"Next Project\"\r\n },\r\n \"prev\": \"Prev\",\r\n \"next\": \"Next\",\r\n \"allProjects\": \"All Projects\"\r\n}\r\n"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"path": "case-study-page/lang/tr.json",
|
|
36
36
|
"type": "registry:lang",
|
|
37
37
|
"target": "$modules$/case-study-page/lang/tr.json",
|
|
38
|
-
"content": "{\n \"pageTitle\": \"Vaka Çalışması\",\n \"title\": \"E-ticaret Platformu Yenileme\",\n \"subtitle\": \"Promake ile bu vaka çalışmasını gerçek projenize göre uyarlayın.\",\n \"sections\": {\n \"challenge\": {\n \"title\": \"Zorluk\",\n \"content\": \"Müşteri, kullanıcı deneyimini iyileştirmek, dönüşüm oranlarını artırmak ve marka varlığını modernize etmek için e-ticaret platformunun tamamen yenilenmesini istedi. Mevcut platform eskimişti, mobil desteği zayıftı ve satışları etkileyen yavaş yükleme süreleri yaşıyordu.\"\n },\n \"solution\": {\n \"title\": \"Çözümümüz\",\n \"content\": \"Performans ve kullanıcı deneyimine odaklanan modern, duyarlı bir e-ticaret platformu tasarladık ve geliştirdik. Temel iyileştirmeler arasında basitleştirilmiş ödeme süreci, gelişmiş ürün filtreleme, kişiselleştirilmiş öneriler ve müşterinin gelişen marka kimliğiyle uyumlu tam bir görsel yenileme yer aldı.\"\n },\n \"results\": {\n \"title\": \"Sonuçlar\",\n \"content\": \"Lansmandan sonra müşteri, dönüşüm oranlarında %45 artış, sayfa yükleme sürelerinde %60 iyileşme ve mobil satışlarda %35 artış gördü. Müşteri memnuniyeti puanları %28 iyileşti ve ortalama sipariş değeri %22 arttı.\"\n }\n },\n \"gallery\": \"Proje Galerisi\",\n \"projectDetails\": \"Proje Detayları\",\n \"labels\": {\n \"client\": \"Müşteri\",\n \"date\": \"Tarih\",\n \"category\": \"Kategori\",\n \"services\": \"Hizmetler\"\n },\n \"details\": {\n \"client\": \"Acme Corporation\",\n \"date\": \"Ocak 2024\",\n \"category\": \"Web Tasarımı\",\n \"services\": [\"UX Tasarımı\", \"UI Tasarımı\", \"Geliştirme\"]\n },\n \"visitWebsite\": \"Web Sitesini Ziyaret Et\",\n \"share\": \"Bu Projeyi Paylaş\",\n \"navigation\": {\n \"prev\": \"Önceki Proje\",\n \"next\": \"Sonraki Proje\"\n },\n \"prev\": \"Önceki\",\n \"next\": \"Sonraki\",\n \"allProjects\": \"Tüm Projeler\"\n}\n"
|
|
38
|
+
"content": "{\r\n \"pageTitle\": \"Vaka Çalışması\",\r\n \"title\": \"E-ticaret Platformu Yenileme\",\r\n \"subtitle\": \"Promake ile bu vaka çalışmasını gerçek projenize göre uyarlayın.\",\r\n \"sections\": {\r\n \"challenge\": {\r\n \"title\": \"Zorluk\",\r\n \"content\": \"Müşteri, kullanıcı deneyimini iyileştirmek, dönüşüm oranlarını artırmak ve marka varlığını modernize etmek için e-ticaret platformunun tamamen yenilenmesini istedi. Mevcut platform eskimişti, mobil desteği zayıftı ve satışları etkileyen yavaş yükleme süreleri yaşıyordu.\"\r\n },\r\n \"solution\": {\r\n \"title\": \"Çözümümüz\",\r\n \"content\": \"Performans ve kullanıcı deneyimine odaklanan modern, duyarlı bir e-ticaret platformu tasarladık ve geliştirdik. Temel iyileştirmeler arasında basitleştirilmiş ödeme süreci, gelişmiş ürün filtreleme, kişiselleştirilmiş öneriler ve müşterinin gelişen marka kimliğiyle uyumlu tam bir görsel yenileme yer aldı.\"\r\n },\r\n \"results\": {\r\n \"title\": \"Sonuçlar\",\r\n \"content\": \"Lansmandan sonra müşteri, dönüşüm oranlarında %45 artış, sayfa yükleme sürelerinde %60 iyileşme ve mobil satışlarda %35 artış gördü. Müşteri memnuniyeti puanları %28 iyileşti ve ortalama sipariş değeri %22 arttı.\"\r\n }\r\n },\r\n \"gallery\": \"Proje Galerisi\",\r\n \"projectDetails\": \"Proje Detayları\",\r\n \"labels\": {\r\n \"client\": \"Müşteri\",\r\n \"date\": \"Tarih\",\r\n \"category\": \"Kategori\",\r\n \"services\": \"Hizmetler\"\r\n },\r\n \"details\": {\r\n \"client\": \"Acme Corporation\",\r\n \"date\": \"Ocak 2024\",\r\n \"category\": \"Web Tasarımı\",\r\n \"services\": [\"UX Tasarımı\", \"UI Tasarımı\", \"Geliştirme\"]\r\n },\r\n \"visitWebsite\": \"Web Sitesini Ziyaret Et\",\r\n \"share\": \"Bu Projeyi Paylaş\",\r\n \"navigation\": {\r\n \"prev\": \"Önceki Proje\",\r\n \"next\": \"Sonraki Proje\"\r\n },\r\n \"prev\": \"Önceki\",\r\n \"next\": \"Sonraki\",\r\n \"allProjects\": \"Tüm Projeler\"\r\n}\r\n"
|
|
39
39
|
}
|
|
40
40
|
],
|
|
41
41
|
"exports": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"path": "category-section/index.ts",
|
|
11
11
|
"type": "registry:index",
|
|
12
12
|
"target": "$modules$/category-section/index.ts",
|
|
13
|
-
"content": "export * from './category-section';\n"
|
|
13
|
+
"content": "export * from './category-section';\r\n"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"path": "category-section/category-section.tsx",
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"path": "category-section/lang/en.json",
|
|
23
23
|
"type": "registry:lang",
|
|
24
24
|
"target": "$modules$/category-section/lang/en.json",
|
|
25
|
-
"content": "{\n \"title\": \"Shop by Category\",\n \"subtitle\": \"Discover our carefully curated collections\",\n \"explore\": \"Explore\"\n}\n"
|
|
25
|
+
"content": "{\r\n \"title\": \"Shop by Category\",\r\n \"subtitle\": \"Discover our carefully curated collections\",\r\n \"explore\": \"Explore\"\r\n}\r\n"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"path": "category-section/lang/tr.json",
|
|
29
29
|
"type": "registry:lang",
|
|
30
30
|
"target": "$modules$/category-section/lang/tr.json",
|
|
31
|
-
"content": "{\n \"title\": \"Kategorilere Göz Atın\",\n \"subtitle\": \"Özenle seçilmiş koleksiyonlarımızı keşfedin\",\n \"explore\": \"Keşfet\"\n}\n"
|
|
31
|
+
"content": "{\r\n \"title\": \"Kategorilere Göz Atın\",\r\n \"subtitle\": \"Özenle seçilmiş koleksiyonlarımızı keşfedin\",\r\n \"explore\": \"Keşfet\"\r\n}\r\n"
|
|
32
32
|
}
|
|
33
33
|
],
|
|
34
34
|
"exports": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"path": "checkout-page/index.ts",
|
|
19
19
|
"type": "registry:index",
|
|
20
20
|
"target": "$modules$/checkout-page/index.ts",
|
|
21
|
-
"content": "export * from './checkout-page';\nexport { CheckoutPage as default } from './checkout-page';\n"
|
|
21
|
+
"content": "export * from './checkout-page';\r\nexport { CheckoutPage as default } from './checkout-page';\r\n"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"path": "checkout-page/checkout-page.tsx",
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
"path": "checkout-page/lang/en.json",
|
|
31
31
|
"type": "registry:lang",
|
|
32
32
|
"target": "$modules$/checkout-page/lang/en.json",
|
|
33
|
-
"content": "{\n \"pageTitle\": \"Checkout\",\n \"title\": \"Checkout\",\n \"completeOrder\": \"Complete your order\",\n \"contactInformation\": \"Contact Information\",\n \"shippingAddress\": \"Shipping Address\",\n \"paymentMethod\": \"Payment Method\",\n \"orderSummary\": \"Order Summary\",\n \"placeOrder\": \"Place Order\",\n \"processing\": \"Processing...\",\n \"firstName\": \"First Name\",\n \"lastName\": \"Last Name\",\n \"email\": \"Email Address\",\n \"phone\": \"Phone Number\",\n \"address\": \"Address\",\n \"city\": \"City\",\n \"postalCode\": \"Postal Code\",\n \"country\": \"Country\",\n \"selectCountry\": \"Select a country\",\n \"qty\": \"Qty\",\n \"subtotal\": \"Subtotal\",\n \"shipping\": \"Shipping\",\n \"free\": \"Free\",\n \"tax\": \"Tax\",\n \"total\": \"Total\",\n \"and\": \"and\",\n \"termsOfService\": \"Terms of Service\",\n \"privacyPolicy\": \"Privacy Policy\",\n \"addressPlaceholder\": \"Street address, apartment, suite, etc.\",\n \"orderNotesOptional\": \"Order Notes (Optional)\",\n \"orderNotesPlaceholder\": \"Special instructions for your order...\",\n \"agreeToTermsTextBefore\": \"I agree to the\",\n \"agreeToTermsError\": \"Please agree to the terms and conditions\",\n \"card\": \"Credit/Debit Card\",\n \"transfer\": \"Bank Transfer\",\n \"cash\": \"Cash on Delivery\",\n \"cardDescription\": \"Pay securely with your credit or debit card\",\n \"transferDescription\": \"Transfer payment to our bank account\",\n \"cashDescription\": \"Pay when your order arrives at your doorstep\",\n \"proceedToPayment\": \"Proceed to Payment\",\n \"cartEmpty\": \"Your cart is empty\",\n \"cartEmptyDescription\": \"Please add items to your cart before proceeding to checkout.\",\n \"continueShopping\": \"Continue Shopping\"\n}\n"
|
|
33
|
+
"content": "{\r\n \"pageTitle\": \"Checkout\",\r\n \"title\": \"Checkout\",\r\n \"completeOrder\": \"Complete your order\",\r\n \"contactInformation\": \"Contact Information\",\r\n \"shippingAddress\": \"Shipping Address\",\r\n \"paymentMethod\": \"Payment Method\",\r\n \"orderSummary\": \"Order Summary\",\r\n \"placeOrder\": \"Place Order\",\r\n \"processing\": \"Processing...\",\r\n \"firstName\": \"First Name\",\r\n \"lastName\": \"Last Name\",\r\n \"email\": \"Email Address\",\r\n \"phone\": \"Phone Number\",\r\n \"address\": \"Address\",\r\n \"city\": \"City\",\r\n \"postalCode\": \"Postal Code\",\r\n \"country\": \"Country\",\r\n \"selectCountry\": \"Select a country\",\r\n \"qty\": \"Qty\",\r\n \"subtotal\": \"Subtotal\",\r\n \"shipping\": \"Shipping\",\r\n \"free\": \"Free\",\r\n \"tax\": \"Tax\",\r\n \"total\": \"Total\",\r\n \"and\": \"and\",\r\n \"termsOfService\": \"Terms of Service\",\r\n \"privacyPolicy\": \"Privacy Policy\",\r\n \"addressPlaceholder\": \"Street address, apartment, suite, etc.\",\r\n \"orderNotesOptional\": \"Order Notes (Optional)\",\r\n \"orderNotesPlaceholder\": \"Special instructions for your order...\",\r\n \"agreeToTermsTextBefore\": \"I agree to the\",\r\n \"agreeToTermsError\": \"Please agree to the terms and conditions\",\r\n \"card\": \"Credit/Debit Card\",\r\n \"transfer\": \"Bank Transfer\",\r\n \"cash\": \"Cash on Delivery\",\r\n \"cardDescription\": \"Pay securely with your credit or debit card\",\r\n \"transferDescription\": \"Transfer payment to our bank account\",\r\n \"cashDescription\": \"Pay when your order arrives at your doorstep\",\r\n \"proceedToPayment\": \"Proceed to Payment\",\r\n \"cartEmpty\": \"Your cart is empty\",\r\n \"cartEmptyDescription\": \"Please add items to your cart before proceeding to checkout.\",\r\n \"continueShopping\": \"Continue Shopping\"\r\n}\r\n"
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
"path": "checkout-page/lang/tr.json",
|
|
37
37
|
"type": "registry:lang",
|
|
38
38
|
"target": "$modules$/checkout-page/lang/tr.json",
|
|
39
|
-
"content": "{\n \"pageTitle\": \"Ödeme\",\n \"title\": \"Ödeme\",\n \"completeOrder\": \"Siparişinizi tamamlayın\",\n \"contactInformation\": \"İletişim Bilgileri\",\n \"shippingAddress\": \"Teslimat Adresi\",\n \"paymentMethod\": \"Ödeme Yöntemi\",\n \"orderSummary\": \"Sipariş Özeti\",\n \"placeOrder\": \"Siparişi Tamamla\",\n \"processing\": \"İşleniyor...\",\n \"firstName\": \"Ad\",\n \"lastName\": \"Soyad\",\n \"email\": \"E-posta Adresi\",\n \"phone\": \"Telefon Numarası\",\n \"address\": \"Adres\",\n \"city\": \"Şehir\",\n \"postalCode\": \"Posta Kodu\",\n \"country\": \"Ülke\",\n \"selectCountry\": \"Ülke seçin\",\n \"qty\": \"Adet\",\n \"subtotal\": \"Ara Toplam\",\n \"shipping\": \"Kargo\",\n \"free\": \"Ücretsiz\",\n \"tax\": \"Vergi\",\n \"total\": \"Toplam\",\n \"and\": \"ve\",\n \"termsOfService\": \"Hizmet Koşulları\",\n \"privacyPolicy\": \"Gizlilik Politikası\",\n \"addressPlaceholder\": \"Sokak adresi, daire, suit, vb.\",\n \"orderNotesOptional\": \"Sipariş Notları (Opsiyonel)\",\n \"orderNotesPlaceholder\": \"Siparişiniz için özel talimatlar...\",\n \"agreeToTermsTextBefore\": \"Kabul ediyorum:\",\n \"agreeToTermsError\": \"Lütfen hizmet koşullarını kabul edin\",\n \"card\": \"Kredi/Banka Kartı\",\n \"transfer\": \"Banka Havalesi\",\n \"cash\": \"Kapıda Ödeme\",\n \"cardDescription\": \"Kredi veya banka kartınızla güvenli ödeme\",\n \"transferDescription\": \"Banka hesabımıza ödeme transferi\",\n \"cashDescription\": \"Siparişiniz kapınıza geldiğinde ödeme\",\n \"proceedToPayment\": \"Ödemeye Geç\",\n \"cartEmpty\": \"Sepetiniz boş\",\n \"cartEmptyDescription\": \"Ödemeye geçmeden önce lütfen sepetinize ürün ekleyin.\",\n \"continueShopping\": \"Alışverişe Devam Et\"\n}\n"
|
|
39
|
+
"content": "{\r\n \"pageTitle\": \"Ödeme\",\r\n \"title\": \"Ödeme\",\r\n \"completeOrder\": \"Siparişinizi tamamlayın\",\r\n \"contactInformation\": \"İletişim Bilgileri\",\r\n \"shippingAddress\": \"Teslimat Adresi\",\r\n \"paymentMethod\": \"Ödeme Yöntemi\",\r\n \"orderSummary\": \"Sipariş Özeti\",\r\n \"placeOrder\": \"Siparişi Tamamla\",\r\n \"processing\": \"İşleniyor...\",\r\n \"firstName\": \"Ad\",\r\n \"lastName\": \"Soyad\",\r\n \"email\": \"E-posta Adresi\",\r\n \"phone\": \"Telefon Numarası\",\r\n \"address\": \"Adres\",\r\n \"city\": \"Şehir\",\r\n \"postalCode\": \"Posta Kodu\",\r\n \"country\": \"Ülke\",\r\n \"selectCountry\": \"Ülke seçin\",\r\n \"qty\": \"Adet\",\r\n \"subtotal\": \"Ara Toplam\",\r\n \"shipping\": \"Kargo\",\r\n \"free\": \"Ücretsiz\",\r\n \"tax\": \"Vergi\",\r\n \"total\": \"Toplam\",\r\n \"and\": \"ve\",\r\n \"termsOfService\": \"Hizmet Koşulları\",\r\n \"privacyPolicy\": \"Gizlilik Politikası\",\r\n \"addressPlaceholder\": \"Sokak adresi, daire, suit, vb.\",\r\n \"orderNotesOptional\": \"Sipariş Notları (Opsiyonel)\",\r\n \"orderNotesPlaceholder\": \"Siparişiniz için özel talimatlar...\",\r\n \"agreeToTermsTextBefore\": \"Kabul ediyorum:\",\r\n \"agreeToTermsError\": \"Lütfen hizmet koşullarını kabul edin\",\r\n \"card\": \"Kredi/Banka Kartı\",\r\n \"transfer\": \"Banka Havalesi\",\r\n \"cash\": \"Kapıda Ödeme\",\r\n \"cardDescription\": \"Kredi veya banka kartınızla güvenli ödeme\",\r\n \"transferDescription\": \"Banka hesabımıza ödeme transferi\",\r\n \"cashDescription\": \"Siparişiniz kapınıza geldiğinde ödeme\",\r\n \"proceedToPayment\": \"Ödemeye Geç\",\r\n \"cartEmpty\": \"Sepetiniz boş\",\r\n \"cartEmptyDescription\": \"Ödemeye geçmeden önce lütfen sepetinize ürün ekleyin.\",\r\n \"continueShopping\": \"Alışverişe Devam Et\"\r\n}\r\n"
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
42
|
"exports": {
|
|
@@ -14,25 +14,25 @@
|
|
|
14
14
|
"path": "coming-soon-page-minimal/index.ts",
|
|
15
15
|
"type": "registry:index",
|
|
16
16
|
"target": "$modules$/coming-soon-page-minimal/index.ts",
|
|
17
|
-
"content": "export * from \"./coming-soon-page-minimal\";\nexport { default } from \"./coming-soon-page-minimal\";\n"
|
|
17
|
+
"content": "export * from \"./coming-soon-page-minimal\";\r\nexport { default } from \"./coming-soon-page-minimal\";\r\n"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"path": "coming-soon-page-minimal/coming-soon-page-minimal.tsx",
|
|
21
21
|
"type": "registry:page",
|
|
22
22
|
"target": "$modules$/coming-soon-page-minimal/coming-soon-page-minimal.tsx",
|
|
23
|
-
"content": "import { useState, useEffect, useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { ArrowRight } from \"lucide-react\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { cn } from \"@/lib/utils\";\n\ninterface ComingSoonPageMinimalProps {\n launchDate?: Date;\n className?: string;\n}\n\n// Default launch date: 30 days from initial load\nconst DEFAULT_LAUNCH_DATE = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\n\nexport function ComingSoonPageMinimal({\n launchDate: launchDateProp,\n className\n}: ComingSoonPageMinimalProps) {\n const { t } = useTranslation(\"coming-soon-page-minimal\");\n usePageTitle({ title: t(\"title\", \"Coming Soon\") });\n\n const launchDate = useMemo(() => launchDateProp ?? DEFAULT_LAUNCH_DATE, [launchDateProp]);\n\n const [email, setEmail] = useState(\"\");\n const [isSubmitted, setIsSubmitted] = useState(false);\n const [days, setDays] = useState(0);\n\n useEffect(() => {\n const calculateDays = () => {\n const difference = launchDate.getTime() - new Date().getTime();\n if (difference > 0) {\n setDays(Math.floor(difference / (1000 * 60 * 60 * 24)));\n }\n };\n calculateDays();\n const timer = setInterval(calculateDays, 60000);\n return () => clearInterval(timer);\n }, [launchDate]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitted(true);\n setEmail(\"\");\n };\n\n return (\n <div className={cn(\n \"min-h-screen flex flex-col items-center justify-center bg-background px-4\",\n className\n )}>\n <div className=\"max-w-3xl mx-auto text-center\">\n {/* Large countdown number */}\n <div className=\"mb-8\">\n <span className=\"text-[12rem] md:text-[16rem] lg:text-[20rem] font-bold leading-none text-primary/10\">\n {days}\n </span>\n </div>\n\n {/* Heading overlaid */}\n <div className=\"-mt-32 md:-mt-48 lg:-mt-64 relative z-10 mb-12\">\n <p className=\"text-sm uppercase tracking-[0.3em] text-muted-foreground mb-4\">\n {t(\"daysLeft\", \"days until launch\")}\n </p>\n <h1 className=\"text-4xl md:text-6xl lg:text-7xl font-bold text-foreground mb-6\">\n {t(\"heading\", \"Coming Soon\")}\n </h1>\n <p className=\"text-lg text-muted-foreground max-w-lg mx-auto\">\n {t(\"description\", \"We're crafting something beautiful. Leave your email to get notified.\")}\n </p>\n </div>\n\n {/* Email signup */}\n <div className=\"max-w-sm mx-auto\">\n {!isSubmitted ? (\n <form onSubmit={handleSubmit} className=\"relative\">\n <Input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={t(\"emailPlaceholder\", \"your@email.com\")}\n required\n className=\"h-14 pr-14 text-base\"\n />\n <Button\n type=\"submit\"\n size=\"icon\"\n className=\"absolute right-2 top-1/2 -translate-y-1/2 h-10 w-10 rounded-full\"\n >\n <ArrowRight className=\"h-5 w-5\" />\n </Button>\n </form>\n ) : (\n <p className=\"text-primary font-medium py-4\">\n {t(\"success\", \"We'll be in touch!\")}\n </p>\n )}\n </div>\n </div>\n\n {/* Bottom decoration line */}\n <div className=\"absolute bottom-0 left-0 right-0 h-1 bg-gradient-to-r from-transparent via-primary/50 to-transparent\" />\n </div>\n );\n}\n\nexport default ComingSoonPageMinimal;\n"
|
|
23
|
+
"content": "import { useState, useEffect, useMemo } from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { ArrowRight } from \"lucide-react\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\ninterface ComingSoonPageMinimalProps {\r\n launchDate?: Date;\r\n className?: string;\r\n}\r\n\r\n// Default launch date: 30 days from initial load\r\nconst DEFAULT_LAUNCH_DATE = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\r\n\r\nexport function ComingSoonPageMinimal({\r\n launchDate: launchDateProp,\r\n className\r\n}: ComingSoonPageMinimalProps) {\r\n const { t } = useTranslation(\"coming-soon-page-minimal\");\r\n usePageTitle({ title: t(\"title\", \"Coming Soon\") });\r\n\r\n const launchDate = useMemo(() => launchDateProp ?? DEFAULT_LAUNCH_DATE, [launchDateProp]);\r\n\r\n const [email, setEmail] = useState(\"\");\r\n const [isSubmitted, setIsSubmitted] = useState(false);\r\n const [days, setDays] = useState(0);\r\n\r\n useEffect(() => {\r\n const calculateDays = () => {\r\n const difference = launchDate.getTime() - new Date().getTime();\r\n if (difference > 0) {\r\n setDays(Math.floor(difference / (1000 * 60 * 60 * 24)));\r\n }\r\n };\r\n calculateDays();\r\n const timer = setInterval(calculateDays, 60000);\r\n return () => clearInterval(timer);\r\n }, [launchDate]);\r\n\r\n const handleSubmit = (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setIsSubmitted(true);\r\n setEmail(\"\");\r\n };\r\n\r\n return (\r\n <div className={cn(\r\n \"min-h-screen flex flex-col items-center justify-center bg-background px-4\",\r\n className\r\n )}>\r\n <div className=\"max-w-3xl mx-auto text-center\">\r\n {/* Large countdown number */}\r\n <div className=\"mb-8\">\r\n <span className=\"text-[12rem] md:text-[16rem] lg:text-[20rem] font-bold leading-none text-primary/10\">\r\n {days}\r\n </span>\r\n </div>\r\n\r\n {/* Heading overlaid */}\r\n <div className=\"-mt-32 md:-mt-48 lg:-mt-64 relative z-10 mb-12\">\r\n <p className=\"text-sm uppercase tracking-[0.3em] text-muted-foreground mb-4\">\r\n {t(\"daysLeft\", \"days until launch\")}\r\n </p>\r\n <h1 className=\"text-4xl md:text-6xl lg:text-7xl font-bold text-foreground mb-6\">\r\n {t(\"heading\", \"Coming Soon\")}\r\n </h1>\r\n <p className=\"text-lg text-muted-foreground max-w-lg mx-auto\">\r\n {t(\"description\", \"We're crafting something beautiful. Leave your email to get notified.\")}\r\n </p>\r\n </div>\r\n\r\n {/* Email signup */}\r\n <div className=\"max-w-sm mx-auto\">\r\n {!isSubmitted ? (\r\n <form onSubmit={handleSubmit} className=\"relative\">\r\n <Input\r\n type=\"email\"\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n placeholder={t(\"emailPlaceholder\", \"your@email.com\")}\r\n required\r\n className=\"h-14 pr-14 text-base\"\r\n />\r\n <Button\r\n type=\"submit\"\r\n size=\"icon\"\r\n className=\"absolute right-2 top-1/2 -translate-y-1/2 h-10 w-10 rounded-full\"\r\n >\r\n <ArrowRight className=\"h-5 w-5\" />\r\n </Button>\r\n </form>\r\n ) : (\r\n <p className=\"text-primary font-medium py-4\">\r\n {t(\"success\", \"We'll be in touch!\")}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Bottom decoration line */}\r\n <div className=\"absolute bottom-0 left-0 right-0 h-1 bg-gradient-to-r from-transparent via-primary/50 to-transparent\" />\r\n </div>\r\n );\r\n}\r\n\r\nexport default ComingSoonPageMinimal;\r\n"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"path": "coming-soon-page-minimal/lang/en.json",
|
|
27
27
|
"type": "registry:lang",
|
|
28
28
|
"target": "$modules$/coming-soon-page-minimal/lang/en.json",
|
|
29
|
-
"content": "{\n \"title\": \"Coming Soon\",\n \"daysLeft\": \"days until launch\",\n \"heading\": \"Coming Soon\",\n \"description\": \"We're crafting something beautiful. Stay tuned!\",\n \"emailPlaceholder\": \"your@email.com\",\n \"success\": \"We'll be in touch!\"\n}"
|
|
29
|
+
"content": "{\r\n \"title\": \"Coming Soon\",\r\n \"daysLeft\": \"days until launch\",\r\n \"heading\": \"Coming Soon\",\r\n \"description\": \"We're crafting something beautiful. Stay tuned!\",\r\n \"emailPlaceholder\": \"your@email.com\",\r\n \"success\": \"We'll be in touch!\"\r\n}"
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"path": "coming-soon-page-minimal/lang/tr.json",
|
|
33
33
|
"type": "registry:lang",
|
|
34
34
|
"target": "$modules$/coming-soon-page-minimal/lang/tr.json",
|
|
35
|
-
"content": "{\n \"title\": \"Yakında\",\n \"daysLeft\": \"gün kaldı\",\n \"heading\": \"Yakında\",\n \"description\": \"Güzel bir şey hazırlıyoruz. Haberdar olmak için e-postanızı bırakın.\",\n \"emailPlaceholder\": \"ornek@email.com\",\n \"success\": \"Sizinle iletişime geçeceğiz!\"\n}\n"
|
|
35
|
+
"content": "{\r\n \"title\": \"Yakında\",\r\n \"daysLeft\": \"gün kaldı\",\r\n \"heading\": \"Yakında\",\r\n \"description\": \"Güzel bir şey hazırlıyoruz. Haberdar olmak için e-postanızı bırakın.\",\r\n \"emailPlaceholder\": \"ornek@email.com\",\r\n \"success\": \"Sizinle iletişime geçeceğiz!\"\r\n}\r\n"
|
|
36
36
|
}
|
|
37
37
|
],
|
|
38
38
|
"exports": {
|
|
@@ -16,25 +16,25 @@
|
|
|
16
16
|
"path": "coming-soon-page/index.ts",
|
|
17
17
|
"type": "registry:index",
|
|
18
18
|
"target": "$modules$/coming-soon-page/index.ts",
|
|
19
|
-
"content": "export * from \"./coming-soon-page\";\nexport { default } from \"./coming-soon-page\";\n"
|
|
19
|
+
"content": "export * from \"./coming-soon-page\";\r\nexport { default } from \"./coming-soon-page\";\r\n"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"path": "coming-soon-page/coming-soon-page.tsx",
|
|
23
23
|
"type": "registry:page",
|
|
24
24
|
"target": "$modules$/coming-soon-page/coming-soon-page.tsx",
|
|
25
|
-
"content": "import { useState, useEffect, useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { usePageTitle } from \"@/hooks/use-page-title\";\nimport { Mail, Twitter, Instagram, Github, Linkedin } from \"lucide-react\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { cn } from \"@/lib/utils\";\nimport { FadeIn, ScaleUp } from \"@/modules/animations\";\n\ninterface ComingSoonPageProps {\n launchDate?: Date;\n className?: string;\n}\n\ninterface TimeLeft {\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n}\n\n// Default launch date: 30 days from initial load\nconst DEFAULT_LAUNCH_DATE = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\n\nexport function ComingSoonPage({\n launchDate: launchDateProp,\n className\n}: ComingSoonPageProps) {\n const { t } = useTranslation(\"coming-soon-page\");\n usePageTitle({ title: t(\"title\", \"Coming Soon\") });\n\n const launchDate = useMemo(() => launchDateProp ?? DEFAULT_LAUNCH_DATE, [launchDateProp]);\n\n const [email, setEmail] = useState(\"\");\n const [isSubmitted, setIsSubmitted] = useState(false);\n const [timeLeft, setTimeLeft] = useState<TimeLeft>({ days: 0, hours: 0, minutes: 0, seconds: 0 });\n\n useEffect(() => {\n const calculateTimeLeft = () => {\n const difference = launchDate.getTime() - new Date().getTime();\n\n if (difference > 0) {\n setTimeLeft({\n days: Math.floor(difference / (1000 * 60 * 60 * 24)),\n hours: Math.floor((difference / (1000 * 60 * 60)) % 24),\n minutes: Math.floor((difference / 1000 / 60) % 60),\n seconds: Math.floor((difference / 1000) % 60),\n });\n }\n };\n\n calculateTimeLeft();\n const timer = setInterval(calculateTimeLeft, 1000);\n return () => clearInterval(timer);\n }, [launchDate]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n // Handle email submission\n setIsSubmitted(true);\n setEmail(\"\");\n };\n\n const socialLinks = [\n { icon: Twitter, href: \"#\", label: \"Twitter\" },\n { icon: Instagram, href: \"#\", label: \"Instagram\" },\n { icon: Github, href: \"#\", label: \"GitHub\" },\n { icon: Linkedin, href: \"#\", label: \"LinkedIn\" },\n ];\n\n const timeUnits = [\n { value: timeLeft.days, label: t(\"days\", \"Days\") },\n { value: timeLeft.hours, label: t(\"hours\", \"Hours\") },\n { value: timeLeft.minutes, label: t(\"minutes\", \"Minutes\") },\n { value: timeLeft.seconds, label: t(\"seconds\", \"Seconds\") },\n ];\n\n return (\n <div className={cn(\n \"min-h-screen flex flex-col items-center justify-center relative overflow-hidden\",\n \"bg-gradient-to-br from-background via-muted/50 to-background\",\n className\n )}>\n {/* Background decoration */}\n <div className=\"absolute inset-0 overflow-hidden pointer-events-none\">\n <div className=\"absolute -top-1/2 -left-1/2 w-full h-full bg-primary/5 rounded-full blur-3xl\" />\n <div className=\"absolute -bottom-1/2 -right-1/2 w-full h-full bg-primary/10 rounded-full blur-3xl\" />\n </div>\n\n <div className=\"relative z-10 w-full max-w-[var(--container-max-width)] mx-auto px-4 py-12 text-center\">\n {/* Heading */}\n <FadeIn className=\"mb-6\">\n <h1 className=\"text-4xl md:text-5xl lg:text-6xl font-bold text-foreground mb-4\">\n {t(\"heading\", \"Something Amazing is Coming\")}\n </h1>\n <p className=\"text-lg md:text-xl text-muted-foreground max-w-2xl mx-auto\">\n {t(\"description\", \"We're working hard to bring you something special. Stay tuned and be the first to know when we launch.\")}\n </p>\n </FadeIn>\n\n {/* Countdown */}\n <ScaleUp delay={0.1} className=\"mb-12\">\n <div className=\"flex justify-center gap-4 md:gap-8\">\n {timeUnits.map((unit, index) => (\n <div key={index} className=\"flex flex-col items-center\">\n <div className=\"w-16 h-16 md:w-24 md:h-24 bg-card border border-border rounded-2xl flex items-center justify-center shadow-lg\">\n <span className=\"text-2xl md:text-4xl font-bold text-foreground\">\n {String(unit.value).padStart(2, \"0\")}\n </span>\n </div>\n <span className=\"mt-2 text-xs md:text-sm text-muted-foreground uppercase tracking-wide\">\n {unit.label}\n </span>\n </div>\n ))}\n </div>\n </ScaleUp>\n\n {/* Email signup */}\n <FadeIn delay={0.2} className=\"mb-12\">\n {!isSubmitted ? (\n <form onSubmit={handleSubmit} className=\"flex flex-col sm:flex-row gap-3 max-w-md mx-auto\">\n <div className=\"relative flex-1\">\n <Mail className=\"absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-muted-foreground\" />\n <Input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={t(\"emailPlaceholder\", \"Enter your email\")}\n required\n className=\"pl-10 h-12\"\n />\n </div>\n <Button type=\"submit\" size=\"lg\" className=\"h-12\">\n {t(\"notify\", \"Notify Me\")}\n </Button>\n </form>\n ) : (\n <div className=\"bg-primary/10 border border-primary/20 rounded-lg p-4 max-w-md mx-auto\">\n <p className=\"text-primary font-medium\">\n {t(\"success\", \"Thank you! We'll notify you when we launch.\")}\n </p>\n </div>\n )}\n </FadeIn>\n\n {/* Social links */}\n <FadeIn delay={0.3}>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t(\"followUs\", \"Follow us for updates\")}\n </p>\n <div className=\"flex justify-center gap-4\">\n {socialLinks.map((social, index) => (\n <a\n key={index}\n href={social.href}\n aria-label={social.label}\n className=\"w-10 h-10 rounded-full bg-muted hover:bg-primary/10 flex items-center justify-center transition-colors\"\n >\n <social.icon className=\"h-5 w-5 text-muted-foreground hover:text-primary transition-colors\" />\n </a>\n ))}\n </div>\n </FadeIn>\n </div>\n </div>\n );\n}\n\nexport default ComingSoonPage;\n"
|
|
25
|
+
"content": "import { useState, useEffect, useMemo } from \"react\";\r\nimport { useTranslation } from \"react-i18next\";\r\nimport { usePageTitle } from \"@/hooks/use-page-title\";\r\nimport { Mail, Twitter, Instagram, Github, Linkedin } from \"lucide-react\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { FadeIn, ScaleUp } from \"@/modules/animations\";\r\n\r\ninterface ComingSoonPageProps {\r\n launchDate?: Date;\r\n className?: string;\r\n}\r\n\r\ninterface TimeLeft {\r\n days: number;\r\n hours: number;\r\n minutes: number;\r\n seconds: number;\r\n}\r\n\r\n// Default launch date: 30 days from initial load\r\nconst DEFAULT_LAUNCH_DATE = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\r\n\r\nexport function ComingSoonPage({\r\n launchDate: launchDateProp,\r\n className\r\n}: ComingSoonPageProps) {\r\n const { t } = useTranslation(\"coming-soon-page\");\r\n usePageTitle({ title: t(\"title\", \"Coming Soon\") });\r\n\r\n const launchDate = useMemo(() => launchDateProp ?? DEFAULT_LAUNCH_DATE, [launchDateProp]);\r\n\r\n const [email, setEmail] = useState(\"\");\r\n const [isSubmitted, setIsSubmitted] = useState(false);\r\n const [timeLeft, setTimeLeft] = useState<TimeLeft>({ days: 0, hours: 0, minutes: 0, seconds: 0 });\r\n\r\n useEffect(() => {\r\n const calculateTimeLeft = () => {\r\n const difference = launchDate.getTime() - new Date().getTime();\r\n\r\n if (difference > 0) {\r\n setTimeLeft({\r\n days: Math.floor(difference / (1000 * 60 * 60 * 24)),\r\n hours: Math.floor((difference / (1000 * 60 * 60)) % 24),\r\n minutes: Math.floor((difference / 1000 / 60) % 60),\r\n seconds: Math.floor((difference / 1000) % 60),\r\n });\r\n }\r\n };\r\n\r\n calculateTimeLeft();\r\n const timer = setInterval(calculateTimeLeft, 1000);\r\n return () => clearInterval(timer);\r\n }, [launchDate]);\r\n\r\n const handleSubmit = (e: React.FormEvent) => {\r\n e.preventDefault();\r\n // Handle email submission\r\n setIsSubmitted(true);\r\n setEmail(\"\");\r\n };\r\n\r\n const socialLinks = [\r\n { icon: Twitter, href: \"#\", label: \"Twitter\" },\r\n { icon: Instagram, href: \"#\", label: \"Instagram\" },\r\n { icon: Github, href: \"#\", label: \"GitHub\" },\r\n { icon: Linkedin, href: \"#\", label: \"LinkedIn\" },\r\n ];\r\n\r\n const timeUnits = [\r\n { value: timeLeft.days, label: t(\"days\", \"Days\") },\r\n { value: timeLeft.hours, label: t(\"hours\", \"Hours\") },\r\n { value: timeLeft.minutes, label: t(\"minutes\", \"Minutes\") },\r\n { value: timeLeft.seconds, label: t(\"seconds\", \"Seconds\") },\r\n ];\r\n\r\n return (\r\n <div className={cn(\r\n \"min-h-screen flex flex-col items-center justify-center relative overflow-hidden\",\r\n \"bg-gradient-to-br from-background via-muted/50 to-background\",\r\n className\r\n )}>\r\n {/* Background decoration */}\r\n <div className=\"absolute inset-0 overflow-hidden pointer-events-none\">\r\n <div className=\"absolute -top-1/2 -left-1/2 w-full h-full bg-primary/5 rounded-full blur-3xl\" />\r\n <div className=\"absolute -bottom-1/2 -right-1/2 w-full h-full bg-primary/10 rounded-full blur-3xl\" />\r\n </div>\r\n\r\n <div className=\"relative z-10 w-full max-w-[var(--container-max-width)] mx-auto px-4 py-12 text-center\">\r\n {/* Heading */}\r\n <FadeIn className=\"mb-6\">\r\n <h1 className=\"text-4xl md:text-5xl lg:text-6xl font-bold text-foreground mb-4\">\r\n {t(\"heading\", \"Something Amazing is Coming\")}\r\n </h1>\r\n <p className=\"text-lg md:text-xl text-muted-foreground max-w-2xl mx-auto\">\r\n {t(\"description\", \"We're working hard to bring you something special. Stay tuned and be the first to know when we launch.\")}\r\n </p>\r\n </FadeIn>\r\n\r\n {/* Countdown */}\r\n <ScaleUp delay={0.1} className=\"mb-12\">\r\n <div className=\"flex justify-center gap-4 md:gap-8\">\r\n {timeUnits.map((unit, index) => (\r\n <div key={index} className=\"flex flex-col items-center\">\r\n <div className=\"w-16 h-16 md:w-24 md:h-24 bg-card border border-border rounded-2xl flex items-center justify-center shadow-lg\">\r\n <span className=\"text-2xl md:text-4xl font-bold text-foreground\">\r\n {String(unit.value).padStart(2, \"0\")}\r\n </span>\r\n </div>\r\n <span className=\"mt-2 text-xs md:text-sm text-muted-foreground uppercase tracking-wide\">\r\n {unit.label}\r\n </span>\r\n </div>\r\n ))}\r\n </div>\r\n </ScaleUp>\r\n\r\n {/* Email signup */}\r\n <FadeIn delay={0.2} className=\"mb-12\">\r\n {!isSubmitted ? (\r\n <form onSubmit={handleSubmit} className=\"flex flex-col sm:flex-row gap-3 max-w-md mx-auto\">\r\n <div className=\"relative flex-1\">\r\n <Mail className=\"absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-muted-foreground\" />\r\n <Input\r\n type=\"email\"\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n placeholder={t(\"emailPlaceholder\", \"Enter your email\")}\r\n required\r\n className=\"pl-10 h-12\"\r\n />\r\n </div>\r\n <Button type=\"submit\" size=\"lg\" className=\"h-12\">\r\n {t(\"notify\", \"Notify Me\")}\r\n </Button>\r\n </form>\r\n ) : (\r\n <div className=\"bg-primary/10 border border-primary/20 rounded-lg p-4 max-w-md mx-auto\">\r\n <p className=\"text-primary font-medium\">\r\n {t(\"success\", \"Thank you! We'll notify you when we launch.\")}\r\n </p>\r\n </div>\r\n )}\r\n </FadeIn>\r\n\r\n {/* Social links */}\r\n <FadeIn delay={0.3}>\r\n <p className=\"text-sm text-muted-foreground mb-4\">\r\n {t(\"followUs\", \"Follow us for updates\")}\r\n </p>\r\n <div className=\"flex justify-center gap-4\">\r\n {socialLinks.map((social, index) => (\r\n <a\r\n key={index}\r\n href={social.href}\r\n aria-label={social.label}\r\n className=\"w-10 h-10 rounded-full bg-muted hover:bg-primary/10 flex items-center justify-center transition-colors\"\r\n >\r\n <social.icon className=\"h-5 w-5 text-muted-foreground hover:text-primary transition-colors\" />\r\n </a>\r\n ))}\r\n </div>\r\n </FadeIn>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport default ComingSoonPage;\r\n"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"path": "coming-soon-page/lang/en.json",
|
|
29
29
|
"type": "registry:lang",
|
|
30
30
|
"target": "$modules$/coming-soon-page/lang/en.json",
|
|
31
|
-
"content": "{\n \"title\": \"Coming Soon\",\n \"heading\": \"Something Amazing is Coming\",\n \"description\": \"Build anticipation for your launch. Explain what's coming and why it's exciting.\",\n \"days\": \"Days\",\n \"hours\": \"Hours\",\n \"minutes\": \"Minutes\",\n \"seconds\": \"Seconds\",\n \"emailPlaceholder\": \"Enter your email\",\n \"notify\": \"Notify Me\",\n \"success\": \"Thank you! We'll notify you when we launch.\",\n \"followUs\": \"Follow us for updates\"\n}"
|
|
31
|
+
"content": "{\r\n \"title\": \"Coming Soon\",\r\n \"heading\": \"Something Amazing is Coming\",\r\n \"description\": \"Build anticipation for your launch. Explain what's coming and why it's exciting.\",\r\n \"days\": \"Days\",\r\n \"hours\": \"Hours\",\r\n \"minutes\": \"Minutes\",\r\n \"seconds\": \"Seconds\",\r\n \"emailPlaceholder\": \"Enter your email\",\r\n \"notify\": \"Notify Me\",\r\n \"success\": \"Thank you! We'll notify you when we launch.\",\r\n \"followUs\": \"Follow us for updates\"\r\n}"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"path": "coming-soon-page/lang/tr.json",
|
|
35
35
|
"type": "registry:lang",
|
|
36
36
|
"target": "$modules$/coming-soon-page/lang/tr.json",
|
|
37
|
-
"content": "{\n \"title\": \"Yakında\",\n \"heading\": \"Harika Bir Şey Geliyor\",\n \"description\": \"Lansmanınız için heyecan yaratın. Nelerin geleceğini ve neden heyecan verici olduğunu anlatın.\",\n \"days\": \"Gün\",\n \"hours\": \"Saat\",\n \"minutes\": \"Dakika\",\n \"seconds\": \"Saniye\",\n \"emailPlaceholder\": \"E-posta adresiniz\",\n \"notify\": \"Beni Bilgilendir\",\n \"success\": \"Teşekkürler! Lansman yapıldığında sizi bilgilendireceğiz.\",\n \"followUs\": \"Güncellemeler için bizi takip edin\"\n}"
|
|
37
|
+
"content": "{\r\n \"title\": \"Yakında\",\r\n \"heading\": \"Harika Bir Şey Geliyor\",\r\n \"description\": \"Lansmanınız için heyecan yaratın. Nelerin geleceğini ve neden heyecan verici olduğunu anlatın.\",\r\n \"days\": \"Gün\",\r\n \"hours\": \"Saat\",\r\n \"minutes\": \"Dakika\",\r\n \"seconds\": \"Saniye\",\r\n \"emailPlaceholder\": \"E-posta adresiniz\",\r\n \"notify\": \"Beni Bilgilendir\",\r\n \"success\": \"Teşekkürler! Lansman yapıldığında sizi bilgilendireceğiz.\",\r\n \"followUs\": \"Güncellemeler için bizi takip edin\"\r\n}"
|
|
38
38
|
}
|
|
39
39
|
],
|
|
40
40
|
"exports": {
|