reroute-js 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/package.json +8 -6
  4. package/packages/cli/README.md +264 -0
  5. package/{cli/bin.d.ts → packages/cli/bin.ts} +1 -1
  6. package/packages/core/README.md +90 -0
  7. package/packages/elysia/README.md +250 -0
  8. package/packages/react/README.md +3 -0
  9. package/_/README.md +0 -59
  10. package/_/basic/package.json +0 -23
  11. package/_/basic/src/client/App.tsx +0 -10
  12. package/_/basic/src/client/components/Counter.tsx +0 -15
  13. package/_/basic/src/client/index.html +0 -12
  14. package/_/basic/src/client/index.tsx +0 -5
  15. package/_/basic/src/client/routes/[404].tsx +0 -18
  16. package/_/basic/src/client/routes/about.tsx +0 -25
  17. package/_/basic/src/client/routes/index.tsx +0 -57
  18. package/_/basic/src/index.ts +0 -20
  19. package/_/basic/tsconfig.json +0 -26
  20. package/_/blog/package.json +0 -23
  21. package/_/blog/src/client/App.tsx +0 -10
  22. package/_/blog/src/client/components/Counter.tsx +0 -14
  23. package/_/blog/src/client/components/RecentPosts.tsx +0 -90
  24. package/_/blog/src/client/index.html +0 -13
  25. package/_/blog/src/client/index.tsx +0 -5
  26. package/_/blog/src/client/routes/[404].tsx +0 -21
  27. package/_/blog/src/client/routes/about.tsx +0 -31
  28. package/_/blog/src/client/routes/blog/[404].tsx +0 -21
  29. package/_/blog/src/client/routes/blog/[layout].tsx +0 -84
  30. package/_/blog/src/client/routes/blog/[slug].tsx +0 -11
  31. package/_/blog/src/client/routes/blog/content/1-hello-world.tsx +0 -27
  32. package/_/blog/src/client/routes/blog/content/2-what-is-reroute.tsx +0 -31
  33. package/_/blog/src/client/routes/blog/index.tsx +0 -70
  34. package/_/blog/src/client/routes/index.tsx +0 -63
  35. package/_/blog/src/index.ts +0 -20
  36. package/_/blog/tsconfig.json +0 -26
  37. package/_/store/package.json +0 -25
  38. package/_/store/src/client/App.tsx +0 -17
  39. package/_/store/src/client/components/Header.tsx +0 -40
  40. package/_/store/src/client/components/ProductCard.tsx +0 -51
  41. package/_/store/src/client/index.html +0 -17
  42. package/_/store/src/client/index.tsx +0 -7
  43. package/_/store/src/client/lib/api.ts +0 -153
  44. package/_/store/src/client/routes/[404].tsx +0 -63
  45. package/_/store/src/client/routes/categories/[category].tsx +0 -223
  46. package/_/store/src/client/routes/categories/index.tsx +0 -187
  47. package/_/store/src/client/routes/index.tsx +0 -126
  48. package/_/store/src/client/routes/products/[id].tsx +0 -233
  49. package/_/store/src/client/routes/products/index.tsx +0 -261
  50. package/_/store/src/client/theme.css +0 -306
  51. package/_/store/src/index.ts +0 -19
  52. package/_/store/tsconfig.json +0 -26
  53. package/cli/bin.d.ts.map +0 -1
  54. package/cli/bin.js +0 -878
  55. package/cli/bin.js.map +0 -15
  56. package/cli/index.d.ts +0 -2
  57. package/cli/index.d.ts.map +0 -1
  58. package/cli/index.js +0 -147
  59. package/cli/index.js.map +0 -10
  60. package/cli/src/cli.d.ts +0 -8
  61. package/cli/src/cli.d.ts.map +0 -1
  62. package/cli/src/commands/build.d.ts +0 -8
  63. package/cli/src/commands/build.d.ts.map +0 -1
  64. package/cli/src/commands/dev.d.ts +0 -8
  65. package/cli/src/commands/dev.d.ts.map +0 -1
  66. package/cli/src/commands/gen.d.ts +0 -3
  67. package/cli/src/commands/gen.d.ts.map +0 -1
  68. package/cli/src/commands/init.d.ts +0 -8
  69. package/cli/src/commands/init.d.ts.map +0 -1
  70. package/cli/src/libs/index.d.ts +0 -2
  71. package/cli/src/libs/index.d.ts.map +0 -1
  72. package/cli/src/libs/tailwind.d.ts +0 -45
  73. package/cli/src/libs/tailwind.d.ts.map +0 -1
  74. package/core/index.d.ts +0 -2
  75. package/core/index.d.ts.map +0 -1
  76. package/core/index.js +0 -1117
  77. package/core/index.js.map +0 -25
  78. package/core/src/bundler/hash.d.ts +0 -2
  79. package/core/src/bundler/hash.d.ts.map +0 -1
  80. package/core/src/bundler/index.d.ts +0 -3
  81. package/core/src/bundler/index.d.ts.map +0 -1
  82. package/core/src/bundler/transpile.d.ts +0 -4
  83. package/core/src/bundler/transpile.d.ts.map +0 -1
  84. package/core/src/content/discovery.d.ts +0 -5
  85. package/core/src/content/discovery.d.ts.map +0 -1
  86. package/core/src/content/index.d.ts +0 -4
  87. package/core/src/content/index.d.ts.map +0 -1
  88. package/core/src/content/metadata.d.ts +0 -9
  89. package/core/src/content/metadata.d.ts.map +0 -1
  90. package/core/src/content/registry.d.ts +0 -2
  91. package/core/src/content/registry.d.ts.map +0 -1
  92. package/core/src/index.d.ts +0 -7
  93. package/core/src/index.d.ts.map +0 -1
  94. package/core/src/ssr/data.d.ts +0 -9
  95. package/core/src/ssr/data.d.ts.map +0 -1
  96. package/core/src/ssr/index.d.ts +0 -4
  97. package/core/src/ssr/index.d.ts.map +0 -1
  98. package/core/src/ssr/modules.d.ts +0 -8
  99. package/core/src/ssr/modules.d.ts.map +0 -1
  100. package/core/src/ssr/render.d.ts +0 -20
  101. package/core/src/ssr/render.d.ts.map +0 -1
  102. package/core/src/ssr/seed.d.ts +0 -2
  103. package/core/src/ssr/seed.d.ts.map +0 -1
  104. package/core/src/template/html.d.ts +0 -4
  105. package/core/src/template/html.d.ts.map +0 -1
  106. package/core/src/template/index.d.ts +0 -2
  107. package/core/src/template/index.d.ts.map +0 -1
  108. package/core/src/types.d.ts +0 -50
  109. package/core/src/types.d.ts.map +0 -1
  110. package/core/src/utils/cache.d.ts +0 -12
  111. package/core/src/utils/cache.d.ts.map +0 -1
  112. package/core/src/utils/compression.d.ts +0 -5
  113. package/core/src/utils/compression.d.ts.map +0 -1
  114. package/core/src/utils/index.d.ts +0 -5
  115. package/core/src/utils/index.d.ts.map +0 -1
  116. package/core/src/utils/mime.d.ts +0 -3
  117. package/core/src/utils/mime.d.ts.map +0 -1
  118. package/core/src/utils/path.d.ts +0 -6
  119. package/core/src/utils/path.d.ts.map +0 -1
  120. package/elysia/index.d.ts +0 -2
  121. package/elysia/index.d.ts.map +0 -1
  122. package/elysia/index.js +0 -1762
  123. package/elysia/index.js.map +0 -32
  124. package/elysia/src/index.d.ts +0 -3
  125. package/elysia/src/index.d.ts.map +0 -1
  126. package/elysia/src/plugin.d.ts +0 -32
  127. package/elysia/src/plugin.d.ts.map +0 -1
  128. package/elysia/src/routes/artifacts.d.ts +0 -3
  129. package/elysia/src/routes/artifacts.d.ts.map +0 -1
  130. package/elysia/src/routes/content.d.ts +0 -3
  131. package/elysia/src/routes/content.d.ts.map +0 -1
  132. package/elysia/src/routes/dev.d.ts +0 -7
  133. package/elysia/src/routes/dev.d.ts.map +0 -1
  134. package/elysia/src/routes/ssr.d.ts +0 -19
  135. package/elysia/src/routes/ssr.d.ts.map +0 -1
  136. package/elysia/src/routes/static.d.ts +0 -19
  137. package/elysia/src/routes/static.d.ts.map +0 -1
  138. package/elysia/src/types.d.ts +0 -31
  139. package/elysia/src/types.d.ts.map +0 -1
  140. package/elysia/src/utils/http.d.ts +0 -5
  141. package/elysia/src/utils/http.d.ts.map +0 -1
  142. package/react/index.d.ts +0 -2
  143. package/react/index.d.ts.map +0 -1
  144. package/react/index.js +0 -1152
  145. package/react/index.js.map +0 -23
  146. package/react/src/components/ContentRoute.d.ts +0 -13
  147. package/react/src/components/ContentRoute.d.ts.map +0 -1
  148. package/react/src/components/Link.d.ts +0 -8
  149. package/react/src/components/Link.d.ts.map +0 -1
  150. package/react/src/components/Outlet.d.ts +0 -7
  151. package/react/src/components/Outlet.d.ts.map +0 -1
  152. package/react/src/components/index.d.ts +0 -4
  153. package/react/src/components/index.d.ts.map +0 -1
  154. package/react/src/hooks/index.d.ts +0 -7
  155. package/react/src/hooks/index.d.ts.map +0 -1
  156. package/react/src/hooks/useContent.d.ts +0 -26
  157. package/react/src/hooks/useContent.d.ts.map +0 -1
  158. package/react/src/hooks/useData.d.ts +0 -10
  159. package/react/src/hooks/useData.d.ts.map +0 -1
  160. package/react/src/hooks/useNavigate.d.ts +0 -6
  161. package/react/src/hooks/useNavigate.d.ts.map +0 -1
  162. package/react/src/hooks/useParams.d.ts +0 -6
  163. package/react/src/hooks/useParams.d.ts.map +0 -1
  164. package/react/src/hooks/useRouter.d.ts +0 -7
  165. package/react/src/hooks/useRouter.d.ts.map +0 -1
  166. package/react/src/hooks/useSearchParams.d.ts +0 -6
  167. package/react/src/hooks/useSearchParams.d.ts.map +0 -1
  168. package/react/src/index.d.ts +0 -6
  169. package/react/src/index.d.ts.map +0 -1
  170. package/react/src/providers/ContentProvider.d.ts +0 -35
  171. package/react/src/providers/ContentProvider.d.ts.map +0 -1
  172. package/react/src/providers/RerouteProvider.d.ts +0 -25
  173. package/react/src/providers/RerouteProvider.d.ts.map +0 -1
  174. package/react/src/providers/RouterProvider.d.ts +0 -23
  175. package/react/src/providers/RouterProvider.d.ts.map +0 -1
  176. package/react/src/providers/index.d.ts +0 -4
  177. package/react/src/providers/index.d.ts.map +0 -1
  178. package/react/src/types/any.d.ts +0 -3
  179. package/react/src/types/any.d.ts.map +0 -1
  180. package/react/src/types/index.d.ts +0 -3
  181. package/react/src/types/index.d.ts.map +0 -1
  182. package/react/src/types/router.d.ts +0 -32
  183. package/react/src/types/router.d.ts.map +0 -1
  184. package/react/src/utils/content.d.ts +0 -8
  185. package/react/src/utils/content.d.ts.map +0 -1
  186. package/react/src/utils/head.d.ts +0 -6
  187. package/react/src/utils/head.d.ts.map +0 -1
  188. package/react/src/utils/index.d.ts +0 -3
  189. package/react/src/utils/index.d.ts.map +0 -1
@@ -1,223 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { Link, useData, useParams } from 'reroute-js/react';
3
- import Header from '../../components/Header';
4
- import ProductCard from '../../components/ProductCard';
5
- import { getProductsByCategory, type Product } from '../../lib/api';
6
-
7
- const categoryIcons: Record<string, string> = {
8
- electronics: '💻',
9
- jewelery: '💎',
10
- "men's clothing": '👔',
11
- "women's clothing": '👗',
12
- };
13
-
14
- const formatCategoryLabel = (category: string) =>
15
- category
16
- .split(' ')
17
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
18
- .join(' ');
19
-
20
- type SortOption = 'default' | 'price-asc' | 'price-desc' | 'name-asc';
21
-
22
- const ssr = {
23
- async data({ params }: { params: { category?: string } }) {
24
- try {
25
- const cat = params?.category;
26
- if (!cat) {
27
- return {
28
- products: [],
29
- error: 'No category specified',
30
- };
31
- }
32
- const products = await getProductsByCategory(cat);
33
- return { products } as { products: Product[] };
34
- } catch (e) {
35
- console.error('ssr.data error for category:', e);
36
- return {
37
- products: [],
38
- error: 'Failed to load products for this category.',
39
- };
40
- }
41
- },
42
- };
43
-
44
- function CategoryPage() {
45
- const params = useParams<{ category: string }>();
46
- const category = params.category || '';
47
-
48
- const routeData = useData<{ products: Product[]; error?: string }>();
49
- const [products, setProducts] = useState<Product[]>(
50
- routeData?.products || [],
51
- );
52
- const [filteredProducts, setFilteredProducts] = useState<Product[]>(
53
- routeData?.products || [],
54
- );
55
- const [searchQuery, setSearchQuery] = useState<string>('');
56
- const [sortBy, setSortBy] = useState<SortOption>('default');
57
- const [loading, setLoading] = useState(!routeData);
58
- const [error, setError] = useState<string | null>(routeData?.error || null);
59
-
60
- // Load products on mount if not from SSR
61
- useEffect(() => {
62
- if (products.length > 0) {
63
- setLoading(false);
64
- return;
65
- }
66
- if (!category) {
67
- setError('No category specified');
68
- setLoading(false);
69
- return;
70
- }
71
-
72
- setLoading(true);
73
- setError(null);
74
-
75
- getProductsByCategory(category)
76
- .then((data) => {
77
- setProducts(data);
78
- setFilteredProducts(data);
79
- })
80
- .catch((err) => {
81
- console.error('Failed to load products:', err);
82
- setError('Failed to load products. Please try again later.');
83
- })
84
- .finally(() => {
85
- setLoading(false);
86
- });
87
- }, [category, products.length]);
88
-
89
- // Filter and sort products
90
- useEffect(() => {
91
- let result = [...products];
92
-
93
- // Apply search filter
94
- if (searchQuery.trim()) {
95
- const query = searchQuery.toLowerCase();
96
- result = result.filter(
97
- (product) =>
98
- product.title.toLowerCase().includes(query) ||
99
- product.description.toLowerCase().includes(query),
100
- );
101
- }
102
-
103
- // Apply sorting
104
- switch (sortBy) {
105
- case 'price-asc':
106
- result.sort((a, b) => a.price - b.price);
107
- break;
108
- case 'price-desc':
109
- result.sort((a, b) => b.price - a.price);
110
- break;
111
- case 'name-asc':
112
- result.sort((a, b) => a.title.localeCompare(b.title));
113
- break;
114
- default:
115
- // Keep default order
116
- break;
117
- }
118
-
119
- setFilteredProducts(result);
120
- }, [products, searchQuery, sortBy]);
121
-
122
- const categoryLabel = formatCategoryLabel(category);
123
- const icon = categoryIcons[category] || '🏷️';
124
-
125
- return (
126
- <>
127
- <Header />
128
-
129
- <main className='container-custom py-8'>
130
- {/* Breadcrumbs */}
131
- <nav className='flex items-center gap-2 text-sm text-gray-600 mb-8'>
132
- <Link to='/' className='link'>
133
- Home
134
- </Link>
135
- <span>/</span>
136
- <Link to='/categories' className='link'>
137
- Categories
138
- </Link>
139
- <span>/</span>
140
- <span className='text-gray-900'>{categoryLabel}</span>
141
- </nav>
142
-
143
- {/* Header */}
144
- <div className='mb-8'>
145
- <div className='flex items-center gap-3 mb-2'>
146
- <span className='text-5xl'>{icon}</span>
147
- <h1 className='section-heading mb-0'>{categoryLabel}</h1>
148
- </div>
149
- <p className='section-subheading'>
150
- {products.length} products in this category
151
- </p>
152
- </div>
153
-
154
- {/* Controls */}
155
- <div className='flex flex-wrap items-center gap-4 mb-8 p-6 bg-white rounded-xl shadow-card'>
156
- <input
157
- type='search'
158
- placeholder='Search in this category...'
159
- className='input flex-1 min-w-[250px]'
160
- value={searchQuery}
161
- onChange={(e) => setSearchQuery(e.target.value)}
162
- />
163
-
164
- <select
165
- className='select min-w-[200px]'
166
- value={sortBy}
167
- onChange={(e) => setSortBy(e.target.value as SortOption)}
168
- >
169
- <option value='default'>Sort: Default</option>
170
- <option value='price-asc'>Price: Low to High</option>
171
- <option value='price-desc'>Price: High to Low</option>
172
- <option value='name-asc'>Name: A-Z</option>
173
- </select>
174
-
175
- {!loading && (
176
- <div className='ml-auto text-sm text-gray-600'>
177
- Showing {filteredProducts.length} of {products.length} products
178
- </div>
179
- )}
180
- </div>
181
-
182
- {/* Products Grid */}
183
- {loading ? (
184
- <div className='text-center py-16 text-gray-600 text-lg'>
185
- <div className='animate-pulse'>Loading products...</div>
186
- </div>
187
- ) : error ? (
188
- <div className='text-center py-16 bg-red-50 text-red-600 text-lg rounded-xl'>
189
- {error}
190
- <div className='mt-4'>
191
- <Link to='/categories' className='link font-semibold'>
192
- ← Back to Categories
193
- </Link>
194
- </div>
195
- </div>
196
- ) : filteredProducts.length === 0 ? (
197
- <div className='text-center py-16 text-gray-600 text-lg'>
198
- <div className='text-6xl mb-4'>🔍</div>
199
- <div className='mb-4'>No products found matching your criteria</div>
200
- {searchQuery && (
201
- <button
202
- type='button'
203
- className='btn-primary btn-sm'
204
- onClick={() => setSearchQuery('')}
205
- >
206
- Clear Search
207
- </button>
208
- )}
209
- </div>
210
- ) : (
211
- <div className='product-grid animate-in'>
212
- {filteredProducts.map((product) => (
213
- <ProductCard key={product.id} product={product} />
214
- ))}
215
- </div>
216
- )}
217
- </main>
218
- </>
219
- );
220
- }
221
-
222
- export default CategoryPage;
223
- export { ssr };
@@ -1,187 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { Link, useData } from 'reroute-js/react';
3
- import Header from '../../components/Header';
4
- import { getCategories } from '../../lib/api';
5
-
6
- const categoryIcons: Record<string, string> = {
7
- electronics: '💻',
8
- jewelery: '💎',
9
- "men's clothing": '👔',
10
- "women's clothing": '👗',
11
- };
12
-
13
- const categoryDescriptions: Record<string, string> = {
14
- electronics: 'Explore the latest in technology and gadgets',
15
- jewelery: 'Discover beautiful jewelry and accessories',
16
- "men's clothing": 'Shop stylish clothing for men',
17
- "women's clothing": 'Find fashionable apparel for women',
18
- };
19
-
20
- const formatCategoryLabel = (category: string) =>
21
- category
22
- .split(' ')
23
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
24
- .join(' ');
25
-
26
- const ssr = {
27
- async data() {
28
- try {
29
- const categories = await getCategories();
30
- return { categories } as { categories: string[] };
31
- } catch (e) {
32
- console.error('ssr.data error for categories:', e);
33
- return { categories: [], error: 'Failed to load categories.' };
34
- }
35
- },
36
- };
37
-
38
- function CategoriesIndexPage() {
39
- const routeData = useData<{ categories: string[]; error?: string }>();
40
- const [categories, setCategories] = useState(routeData?.categories ?? []);
41
- const [loading, setLoading] = useState(!routeData);
42
- const [error, setError] = useState<string | null>(routeData?.error ?? null);
43
-
44
- useEffect(() => {
45
- if (routeData?.categories?.length) {
46
- setCategories(routeData.categories);
47
- setLoading(false);
48
- return;
49
- }
50
-
51
- let cancelled = false;
52
- setLoading(true);
53
- setError(null);
54
-
55
- getCategories()
56
- .then((data) => {
57
- if (!cancelled) {
58
- setCategories(data);
59
- }
60
- })
61
- .catch((err) => {
62
- console.error('Failed to load categories:', err);
63
- if (!cancelled) {
64
- setError('Failed to load categories. Please try again later.');
65
- }
66
- })
67
- .finally(() => {
68
- if (!cancelled) {
69
- setLoading(false);
70
- }
71
- });
72
-
73
- return () => {
74
- cancelled = true;
75
- };
76
- }, [routeData]);
77
-
78
- if (loading) {
79
- return (
80
- <>
81
- <Header />
82
- <main className='container-custom py-8'>
83
- <div className='text-center py-16 text-gray-600 text-lg'>
84
- <div className='animate-pulse'>Loading categories...</div>
85
- </div>
86
- </main>
87
- </>
88
- );
89
- }
90
-
91
- if (error) {
92
- return (
93
- <>
94
- <Header />
95
- <main className='container-custom py-8'>
96
- <div className='text-center py-16 bg-red-50 text-red-600 text-lg rounded-xl'>
97
- {error}
98
- </div>
99
- </main>
100
- </>
101
- );
102
- }
103
-
104
- return (
105
- <>
106
- <Header />
107
-
108
- <main className='container-custom py-8'>
109
- <div className='mb-12'>
110
- <h1 className='section-heading'>Shop by Category</h1>
111
- <p className='section-subheading'>
112
- Browse curated collections and jump straight into your favorite
113
- category.
114
- </p>
115
- </div>
116
-
117
- <div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 mb-12'>
118
- {categories.map((category) => {
119
- const label = formatCategoryLabel(category);
120
- const description =
121
- categoryDescriptions[category] || `Explore our ${label} picks`;
122
- const icon = categoryIcons[category] || '🏷️';
123
- const to = `/categories/${encodeURIComponent(category)}`;
124
-
125
- return (
126
- <Link
127
- key={category}
128
- to={to}
129
- className='card card-hover group p-8 no-underline text-gray-900 block'
130
- >
131
- <div className='text-5xl mb-4'>{icon}</div>
132
- <h2 className='text-2xl font-bold mb-2 capitalize group-hover:text-primary-600 transition-colors'>
133
- {label}
134
- </h2>
135
- <p className='text-gray-600 text-sm mb-4'>{description}</p>
136
- <span className='inline-flex items-center gap-2 btn-primary btn-sm'>
137
- View Products <span aria-hidden='true'>→</span>
138
- </span>
139
- </Link>
140
- );
141
- })}
142
- </div>
143
-
144
- <div className='mt-16 p-8 bg-gray-50 rounded-xl text-center'>
145
- <h3 className='text-2xl font-bold mb-6 text-gray-900'>
146
- Why Shop With Us?
147
- </h3>
148
- <div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8'>
149
- {[
150
- {
151
- icon: '🚚',
152
- title: 'Fast Shipping',
153
- desc: 'Free delivery on orders over $50',
154
- },
155
- {
156
- icon: '🔒',
157
- title: 'Secure Payment',
158
- desc: 'Your data is always protected',
159
- },
160
- {
161
- icon: '↩️',
162
- title: 'Easy Returns',
163
- desc: '30-day return policy',
164
- },
165
- {
166
- icon: '⭐',
167
- title: 'Quality Products',
168
- desc: 'Verified and rated by customers',
169
- },
170
- ].map((item) => (
171
- <div key={item.title}>
172
- <div className='text-4xl mb-2'>{item.icon}</div>
173
- <div className='font-semibold text-gray-700 mb-1'>
174
- {item.title}
175
- </div>
176
- <div className='text-sm text-gray-600'>{item.desc}</div>
177
- </div>
178
- ))}
179
- </div>
180
- </div>
181
- </main>
182
- </>
183
- );
184
- }
185
-
186
- export default CategoriesIndexPage;
187
- export { ssr };
@@ -1,126 +0,0 @@
1
- import { Link, useData } from 'reroute-js/react';
2
- import Header from '../components/Header';
3
- import ProductCard from '../components/ProductCard';
4
- import { getAllProducts, type Product } from '../lib/api';
5
-
6
- const ssr = {
7
- async data() {
8
- try {
9
- const products = await getAllProducts();
10
- const shuffled = [...products].sort(() => Math.random() - 0.5);
11
- return { featuredProducts: shuffled.slice(0, 4) } as {
12
- featuredProducts: Product[];
13
- };
14
- } catch (e) {
15
- console.error('ssr.data error for home:', e);
16
- return {
17
- featuredProducts: [],
18
- error: 'Failed to load featured products.',
19
- };
20
- }
21
- },
22
- };
23
-
24
- function HomePage() {
25
- const data = useData<{ featuredProducts: Product[]; error?: string }>();
26
- const featuredProducts = data?.featuredProducts || [];
27
- const error = data?.error || null;
28
-
29
- return (
30
- <>
31
- <Header />
32
-
33
- <main className='container-custom py-8'>
34
- {/* Hero Section */}
35
- <section className='text-center py-12 mb-12 animate-slide-up'>
36
- <h1 className='text-5xl md:text-6xl font-bold text-gray-900 mb-4 leading-tight'>
37
- Welcome to Reroute Store
38
- </h1>
39
- <p className='text-xl text-gray-600 mb-8 max-w-2xl mx-auto'>
40
- A modern e-commerce demo built with Reroute, showcasing file-based
41
- routing, SSR, and seamless API integration with FakeStoreAPI
42
- </p>
43
- <div className='flex gap-4 justify-center flex-wrap'>
44
- <Link to='/products' className='btn-primary btn-lg'>
45
- Shop Now
46
- </Link>
47
- <Link to='/categories' className='btn-secondary btn-lg'>
48
- Browse Categories
49
- </Link>
50
- </div>
51
- </section>
52
-
53
- {/* Featured Products */}
54
- <section className='mb-16'>
55
- <div className='flex justify-between items-center mb-6'>
56
- <h2 className='section-heading mb-0'>Featured Products</h2>
57
- <Link to='/products' className='link font-semibold text-lg'>
58
- View All →
59
- </Link>
60
- </div>
61
-
62
- {error ? (
63
- <div className='text-center py-12 bg-red-50 text-red-600 text-lg rounded-xl'>
64
- {error}
65
- </div>
66
- ) : (
67
- <div className='product-grid'>
68
- {featuredProducts.map((product) => (
69
- <ProductCard key={product.id} product={product} />
70
- ))}
71
- </div>
72
- )}
73
- </section>
74
-
75
- {/* Features */}
76
- <section className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mt-12 pt-8'>
77
- <div className='feature-card'>
78
- <div className='text-5xl mb-4'>⚡</div>
79
- <h3 className='text-xl font-semibold mb-2 text-gray-900'>
80
- Lightning Fast
81
- </h3>
82
- <p className='text-gray-600 leading-relaxed'>
83
- Built on Bun for blazing fast performance and server-side
84
- rendering
85
- </p>
86
- </div>
87
-
88
- <div className='feature-card'>
89
- <div className='text-5xl mb-4'>🎯</div>
90
- <h3 className='text-xl font-semibold mb-2 text-gray-900'>
91
- File-Based Routing
92
- </h3>
93
- <p className='text-gray-600 leading-relaxed'>
94
- Automatic route generation from your file structure with zero
95
- configuration
96
- </p>
97
- </div>
98
-
99
- <div className='feature-card'>
100
- <div className='text-5xl mb-4'>🔄</div>
101
- <h3 className='text-xl font-semibold mb-2 text-gray-900'>
102
- SSR Support
103
- </h3>
104
- <p className='text-gray-600 leading-relaxed'>
105
- SEO-friendly server-side rendering with automatic hydration
106
- </p>
107
- </div>
108
-
109
- <div className='feature-card'>
110
- <div className='text-5xl mb-4'>📦</div>
111
- <h3 className='text-xl font-semibold mb-2 text-gray-900'>
112
- API Integration
113
- </h3>
114
- <p className='text-gray-600 leading-relaxed'>
115
- Seamless integration with external APIs using serializable
116
- responses
117
- </p>
118
- </div>
119
- </section>
120
- </main>
121
- </>
122
- );
123
- }
124
-
125
- export default HomePage;
126
- export { ssr };