reroute-js 0.46.0 → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -4
- package/_/store/package.json +1 -3
- package/_/store/src/client/components/Header.tsx +8 -20
- package/_/store/src/client/components/ProductCard.tsx +9 -16
- package/_/store/src/client/index.css +1118 -0
- package/_/store/src/client/routes/[404].tsx +20 -31
- package/_/store/src/client/routes/categories/[category].tsx +23 -28
- package/_/store/src/client/routes/categories/index.tsx +19 -27
- package/_/store/src/client/routes/index.tsx +27 -37
- package/_/store/src/client/routes/products/[id].tsx +35 -48
- package/_/store/src/client/routes/products/index.tsx +20 -50
- package/cli/bin.d.ts +1 -1
- package/cli/bin.js +87 -185
- package/cli/bin.js.map +11 -11
- package/cli/index.d.ts +1 -1
- package/cli/index.js +19 -114
- package/cli/index.js.map +5 -5
- package/cli/src/cli.d.ts +1 -1
- package/cli/src/commands/analyze.d.ts +1 -1
- package/cli/src/commands/build.d.ts +1 -1
- package/cli/src/commands/dev.d.ts +1 -1
- package/cli/src/commands/gen.d.ts +1 -1
- package/cli/src/commands/gen.d.ts.map +1 -1
- package/cli/src/commands/index.d.ts +1 -1
- package/cli/src/commands/init.d.ts +1 -1
- package/cli/src/commands/lib/assets.d.ts +1 -1
- package/cli/src/commands/lib/bundler.d.ts +1 -1
- package/cli/src/commands/lib/command.d.ts +1 -1
- package/cli/src/commands/lib/env.d.ts +1 -1
- package/cli/src/commands/lib/index.d.ts +2 -2
- package/cli/src/commands/lib/index.d.ts.map +1 -1
- package/cli/src/commands/lib/log.d.ts +1 -1
- package/cli/src/commands/lib/markdown/availability.d.ts +1 -1
- package/cli/src/commands/lib/markdown/index.d.ts +1 -1
- package/cli/src/commands/lib/markdown/processor.d.ts +1 -1
- package/cli/src/commands/lib/production.d.ts +1 -1
- package/cli/src/commands/lib/server.d.ts +1 -1
- package/cli/src/commands/lib/streaming/analyzer.d.ts +1 -1
- package/cli/src/commands/lib/streaming/suspense.d.ts +1 -1
- package/cli/src/commands/lib/terminal-ui.d.ts +1 -1
- package/cli/src/commands/lib/theme.d.ts +20 -0
- package/cli/src/commands/lib/theme.d.ts.map +1 -0
- package/cli/src/commands/lib/version.d.ts +1 -1
- package/cli/src/commands/og.d.ts +1 -1
- package/cli/src/commands/start.d.ts +1 -1
- package/cli/src/index.d.ts +1 -1
- package/core/index.d.ts +1 -1
- package/core/index.js +16 -16
- package/core/index.js.map +6 -6
- package/core/src/bundler/hash.d.ts +1 -1
- package/core/src/bundler/index.d.ts +1 -1
- package/core/src/config.d.ts +1 -1
- package/core/src/content/discovery.d.ts +1 -1
- package/core/src/content/index.d.ts +1 -1
- package/core/src/content/metadata.d.ts +1 -1
- package/core/src/i18n/catalog.d.ts +1 -1
- package/core/src/i18n/discover.d.ts +1 -1
- package/core/src/i18n/index.d.ts +1 -1
- package/core/src/i18n/messages.d.ts +1 -1
- package/core/src/i18n/negotiate.d.ts +1 -1
- package/core/src/i18n/pathname.d.ts +1 -1
- package/core/src/i18n/resolve.d.ts +1 -1
- package/core/src/i18n/types.d.ts +1 -1
- package/core/src/index.d.ts +1 -1
- package/core/src/llms/extractor.d.ts +1 -1
- package/core/src/llms/formatter.d.ts +1 -1
- package/core/src/llms/full-generator.d.ts +1 -1
- package/core/src/llms/index-generator.d.ts +1 -1
- package/core/src/llms/index.d.ts +1 -1
- package/core/src/og/discovery.d.ts +1 -1
- package/core/src/og/index.d.ts +1 -1
- package/core/src/og/meta.d.ts +1 -1
- package/core/src/og/render.d.ts +1 -1
- package/core/src/og/types.d.ts +1 -1
- package/core/src/robots/discovery.d.ts +1 -1
- package/core/src/robots/generator.d.ts +1 -1
- package/core/src/robots/index.d.ts +1 -1
- package/core/src/robots/policies.d.ts +1 -1
- package/core/src/rss/discovery.d.ts +1 -1
- package/core/src/rss/generator.d.ts +1 -1
- package/core/src/rss/index.d.ts +1 -1
- package/core/src/sitemap/discovery.d.ts +1 -1
- package/core/src/sitemap/generator.d.ts +1 -1
- package/core/src/sitemap/index.d.ts +1 -1
- package/core/src/ssr/index.d.ts +1 -1
- package/core/src/ssr/lib/cache.d.ts +1 -1
- package/core/src/ssr/lib/cleanup.d.ts +1 -1
- package/core/src/ssr/lib/collections.d.ts +1 -1
- package/core/src/ssr/lib/compression.d.ts +1 -1
- package/core/src/ssr/lib/compute/content.d.ts +1 -1
- package/core/src/ssr/lib/compute/index.d.ts +1 -1
- package/core/src/ssr/lib/compute/layouts.d.ts +1 -1
- package/core/src/ssr/lib/compute/routes.d.ts +1 -1
- package/core/src/ssr/lib/content-path.d.ts +1 -1
- package/core/src/ssr/lib/data.d.ts +1 -1
- package/core/src/ssr/lib/html.d.ts +1 -1
- package/core/src/ssr/lib/imports.d.ts +1 -1
- package/core/src/ssr/lib/index.d.ts +1 -1
- package/core/src/ssr/lib/layouts.d.ts +1 -1
- package/core/src/ssr/lib/metadata.d.ts +1 -1
- package/core/src/ssr/lib/mime.d.ts +1 -1
- package/core/src/ssr/lib/modules.d.ts +1 -1
- package/core/src/ssr/lib/path.d.ts +1 -1
- package/core/src/ssr/lib/preload.d.ts +1 -1
- package/core/src/ssr/lib/route-match.d.ts +1 -1
- package/core/src/ssr/lib/scripts/collections.d.ts +1 -1
- package/core/src/ssr/lib/scripts/data.d.ts +1 -1
- package/core/src/ssr/lib/scripts/escape.d.ts +1 -1
- package/core/src/ssr/lib/scripts/feeds.d.ts +1 -1
- package/core/src/ssr/lib/scripts/index.d.ts +1 -1
- package/core/src/ssr/lib/seed.d.ts +1 -1
- package/core/src/ssr/lib/serialize.d.ts +1 -1
- package/core/src/ssr/lib/setup.d.ts +2 -2
- package/core/src/ssr/lib/setup.d.ts.map +1 -1
- package/core/src/ssr/lib/styles.d.ts +3 -3
- package/core/src/ssr/lib/styles.d.ts.map +1 -1
- package/core/src/ssr/lib/template.d.ts +1 -1
- package/core/src/ssr/lib/types.d.ts +1 -1
- package/core/src/ssr/render.d.ts +2 -2
- package/core/src/ssr/render.d.ts.map +1 -1
- package/core/src/ssr/stream.d.ts +2 -2
- package/core/src/ssr/stream.d.ts.map +1 -1
- package/elysia/index.d.ts +1 -1
- package/elysia/index.js +27 -27
- package/elysia/index.js.map +9 -9
- package/elysia/src/index.d.ts +1 -1
- package/elysia/src/libs/assets.d.ts +1 -1
- package/elysia/src/libs/cache.d.ts +1 -1
- package/elysia/src/libs/caching.d.ts +1 -1
- package/elysia/src/libs/http.d.ts +1 -1
- package/elysia/src/libs/i18n.d.ts +1 -1
- package/elysia/src/libs/image.d.ts +1 -1
- package/elysia/src/libs/index.d.ts +1 -1
- package/elysia/src/libs/llms.d.ts +1 -1
- package/elysia/src/libs/response.d.ts +1 -1
- package/elysia/src/libs/serving.d.ts +1 -1
- package/elysia/src/plugin.d.ts +1 -1
- package/elysia/src/routes/artifacts.d.ts +1 -1
- package/elysia/src/routes/content.d.ts +1 -1
- package/elysia/src/routes/image.d.ts +1 -1
- package/elysia/src/routes/index.d.ts +1 -1
- package/elysia/src/routes/internal.d.ts +1 -1
- package/elysia/src/routes/llms.d.ts +1 -1
- package/elysia/src/routes/og.d.ts +1 -1
- package/elysia/src/routes/redirects.d.ts +1 -1
- package/elysia/src/routes/robots.d.ts +1 -1
- package/elysia/src/routes/rss.d.ts +1 -1
- package/elysia/src/routes/search.d.ts +1 -1
- package/elysia/src/routes/sitemap.d.ts +1 -1
- package/elysia/src/routes/ssr.d.ts +2 -2
- package/elysia/src/routes/ssr.d.ts.map +1 -1
- package/elysia/src/routes/static.d.ts +1 -1
- package/elysia/src/types.d.ts +1 -1
- package/package.json +2 -5
- package/react/index.d.ts +1 -1
- package/react/index.js +2 -2
- package/react/index.js.map +1 -1
- package/react/src/components/ClientOnly.d.ts +1 -1
- package/react/src/components/ContentRoute.d.ts +1 -1
- package/react/src/components/Image.d.ts +1 -1
- package/react/src/components/LazyRoute.d.ts +1 -1
- package/react/src/components/Link.d.ts +1 -1
- package/react/src/components/Markdown.d.ts +1 -1
- package/react/src/components/Outlet.d.ts +1 -1
- package/react/src/components/index.d.ts +1 -1
- package/react/src/hooks/index.d.ts +1 -1
- package/react/src/hooks/useContent.d.ts +1 -1
- package/react/src/hooks/useData.d.ts +1 -1
- package/react/src/hooks/useFeed.d.ts +1 -1
- package/react/src/hooks/useLayoutData.d.ts +1 -1
- package/react/src/hooks/useLlms.d.ts +1 -1
- package/react/src/hooks/useNavigate.d.ts +1 -1
- package/react/src/hooks/useParams.d.ts +1 -1
- package/react/src/hooks/useRouter.d.ts +1 -1
- package/react/src/hooks/useSearch.d.ts +1 -1
- package/react/src/hooks/useSearchParams.d.ts +1 -1
- package/react/src/hooks/useToc.d.ts +1 -1
- package/react/src/i18n/LocaleProvider.d.ts +1 -1
- package/react/src/i18n/helpers.d.ts +1 -1
- package/react/src/i18n/index.d.ts +1 -1
- package/react/src/index.d.ts +1 -1
- package/react/src/lib/collection.d.ts +1 -1
- package/react/src/lib/content.d.ts +1 -1
- package/react/src/lib/head.d.ts +1 -1
- package/react/src/lib/index.d.ts +1 -1
- package/react/src/lib/lazy-route.d.ts +1 -1
- package/react/src/lib/route-loader.d.ts +1 -1
- package/react/src/providers/ContentProvider.d.ts +1 -1
- package/react/src/providers/RerouteProvider.d.ts +1 -1
- package/react/src/providers/RouterProvider.d.ts +1 -1
- package/react/src/providers/index.d.ts +1 -1
- package/react/src/types/any.d.ts +1 -1
- package/react/src/types/index.d.ts +1 -1
- package/react/src/types/router.d.ts +1 -1
- package/telemetry/react.d.ts +1 -1
- package/telemetry/react.js +2 -2
- package/telemetry/react.js.map +1 -1
- package/telemetry/server.d.ts +1 -1
- package/telemetry/server.js +2 -2
- package/telemetry/server.js.map +4 -4
- package/telemetry/src/react/api.d.ts +1 -1
- package/telemetry/src/react/context.d.ts +1 -1
- package/telemetry/src/react/index.d.ts +1 -1
- package/telemetry/src/react/telemetry.d.ts +1 -1
- package/telemetry/src/server/context.d.ts +1 -1
- package/telemetry/src/server/headers/extractor.d.ts +1 -1
- package/telemetry/src/server/headers/index.d.ts +1 -1
- package/telemetry/src/server/headers/presets.d.ts +1 -1
- package/telemetry/src/server/index.d.ts +1 -1
- package/telemetry/src/server/instrumentation.d.ts +1 -1
- package/telemetry/src/server/plugin.d.ts +1 -1
- package/telemetry/src/server/sourcemap.d.ts +1 -1
- package/_/store/src/client/theme.css +0 -306
- package/cli/src/commands/lib/tailwind.d.ts +0 -20
- package/cli/src/commands/lib/tailwind.d.ts.map +0 -1
|
@@ -6,20 +6,18 @@ export default function NotFoundPage() {
|
|
|
6
6
|
<>
|
|
7
7
|
<Header />
|
|
8
8
|
|
|
9
|
-
<main className='
|
|
10
|
-
<div className='
|
|
11
|
-
<div className='
|
|
12
|
-
<div className='
|
|
13
|
-
<h1 className='
|
|
14
|
-
|
|
15
|
-
</h1>
|
|
16
|
-
<p className='text-xl text-gray-600 mb-8'>
|
|
9
|
+
<main className='page-main page-main-lg'>
|
|
10
|
+
<div className='not-found-content'>
|
|
11
|
+
<div className='animate-slide-up'>
|
|
12
|
+
<div className='not-found-code'>404</div>
|
|
13
|
+
<h1 className='not-found-title'>Page Not Found</h1>
|
|
14
|
+
<p className='not-found-lead'>
|
|
17
15
|
Oops! The page you're looking for doesn't exist. It might have
|
|
18
16
|
been moved or deleted.
|
|
19
17
|
</p>
|
|
20
18
|
</div>
|
|
21
19
|
|
|
22
|
-
<div className='
|
|
20
|
+
<div className='not-found-actions animate-in'>
|
|
23
21
|
<Link to='/' className='btn-primary btn-lg'>
|
|
24
22
|
🏠 Go Home
|
|
25
23
|
</Link>
|
|
@@ -28,32 +26,23 @@ export default function NotFoundPage() {
|
|
|
28
26
|
</Link>
|
|
29
27
|
</div>
|
|
30
28
|
|
|
31
|
-
<div className='
|
|
32
|
-
<Link
|
|
33
|
-
|
|
34
|
-
className='
|
|
35
|
-
|
|
36
|
-
<div className='text-4xl mb-3'>🏷️</div>
|
|
37
|
-
<h3 className='font-semibold mb-2'>Categories</h3>
|
|
38
|
-
<p className='text-sm text-gray-600'>Browse by category</p>
|
|
29
|
+
<div className='not-found-links animate-scale'>
|
|
30
|
+
<Link to='/categories' className='card card-hover card-padded'>
|
|
31
|
+
<div className='not-found-card-icon'>🏷️</div>
|
|
32
|
+
<h3 className='not-found-card-title'>Categories</h3>
|
|
33
|
+
<p className='not-found-card-desc'>Browse by category</p>
|
|
39
34
|
</Link>
|
|
40
35
|
|
|
41
|
-
<Link
|
|
42
|
-
|
|
43
|
-
className='
|
|
44
|
-
|
|
45
|
-
<div className='text-4xl mb-3'>📦</div>
|
|
46
|
-
<h3 className='font-semibold mb-2'>All Products</h3>
|
|
47
|
-
<p className='text-sm text-gray-600'>View our catalog</p>
|
|
36
|
+
<Link to='/products' className='card card-hover card-padded'>
|
|
37
|
+
<div className='not-found-card-icon'>📦</div>
|
|
38
|
+
<h3 className='not-found-card-title'>All Products</h3>
|
|
39
|
+
<p className='not-found-card-desc'>View our catalog</p>
|
|
48
40
|
</Link>
|
|
49
41
|
|
|
50
|
-
<Link
|
|
51
|
-
|
|
52
|
-
className='
|
|
53
|
-
|
|
54
|
-
<div className='text-4xl mb-3'>⚡</div>
|
|
55
|
-
<h3 className='font-semibold mb-2'>Featured</h3>
|
|
56
|
-
<p className='text-sm text-gray-600'>See what's popular</p>
|
|
42
|
+
<Link to='/' className='card card-hover card-padded'>
|
|
43
|
+
<div className='not-found-card-icon'>⚡</div>
|
|
44
|
+
<h3 className='not-found-card-title'>Featured</h3>
|
|
45
|
+
<p className='not-found-card-desc'>See what's popular</p>
|
|
57
46
|
</Link>
|
|
58
47
|
</div>
|
|
59
48
|
</div>
|
|
@@ -57,7 +57,6 @@ function CategoryPage() {
|
|
|
57
57
|
const [loading, setLoading] = useState(!routeData);
|
|
58
58
|
const [error, setError] = useState<string | null>(routeData?.error || null);
|
|
59
59
|
|
|
60
|
-
// Load products on mount if not from SSR
|
|
61
60
|
useEffect(() => {
|
|
62
61
|
if (products.length > 0) {
|
|
63
62
|
setLoading(false);
|
|
@@ -86,11 +85,9 @@ function CategoryPage() {
|
|
|
86
85
|
});
|
|
87
86
|
}, [category, products.length]);
|
|
88
87
|
|
|
89
|
-
// Filter and sort products
|
|
90
88
|
useEffect(() => {
|
|
91
89
|
let result = [...products];
|
|
92
90
|
|
|
93
|
-
// Apply search filter
|
|
94
91
|
if (searchQuery.trim()) {
|
|
95
92
|
const query = searchQuery.toLowerCase();
|
|
96
93
|
result = result.filter(
|
|
@@ -100,7 +97,6 @@ function CategoryPage() {
|
|
|
100
97
|
);
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
// Apply sorting
|
|
104
100
|
switch (sortBy) {
|
|
105
101
|
case 'price-asc':
|
|
106
102
|
result.sort((a, b) => a.price - b.price);
|
|
@@ -112,7 +108,6 @@ function CategoryPage() {
|
|
|
112
108
|
result.sort((a, b) => a.title.localeCompare(b.title));
|
|
113
109
|
break;
|
|
114
110
|
default:
|
|
115
|
-
// Keep default order
|
|
116
111
|
break;
|
|
117
112
|
}
|
|
118
113
|
|
|
@@ -126,9 +121,8 @@ function CategoryPage() {
|
|
|
126
121
|
<>
|
|
127
122
|
<Header />
|
|
128
123
|
|
|
129
|
-
<main className='
|
|
130
|
-
|
|
131
|
-
<nav className='flex items-center gap-2 text-sm text-gray-600 mb-8'>
|
|
124
|
+
<main className='page-main'>
|
|
125
|
+
<nav className='breadcrumb'>
|
|
132
126
|
<Link to='/' className='link'>
|
|
133
127
|
Home
|
|
134
128
|
</Link>
|
|
@@ -137,32 +131,32 @@ function CategoryPage() {
|
|
|
137
131
|
Categories
|
|
138
132
|
</Link>
|
|
139
133
|
<span>/</span>
|
|
140
|
-
<span className='
|
|
134
|
+
<span className='breadcrumb-current'>{categoryLabel}</span>
|
|
141
135
|
</nav>
|
|
142
136
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
<
|
|
147
|
-
|
|
137
|
+
<div className='page-intro'>
|
|
138
|
+
<div className='category-header'>
|
|
139
|
+
<span className='category-header-icon'>{icon}</span>
|
|
140
|
+
<h1 className='section-heading section-heading-flush'>
|
|
141
|
+
{categoryLabel}
|
|
142
|
+
</h1>
|
|
148
143
|
</div>
|
|
149
144
|
<p className='section-subheading'>
|
|
150
145
|
{products.length} products in this category
|
|
151
146
|
</p>
|
|
152
147
|
</div>
|
|
153
148
|
|
|
154
|
-
|
|
155
|
-
<div className='flex flex-wrap items-center gap-4 mb-8 p-6 bg-white rounded-xl shadow-card'>
|
|
149
|
+
<div className='filter-bar'>
|
|
156
150
|
<input
|
|
157
151
|
type='search'
|
|
158
152
|
placeholder='Search in this category...'
|
|
159
|
-
className='input
|
|
153
|
+
className='input input-grow'
|
|
160
154
|
value={searchQuery}
|
|
161
155
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
162
156
|
/>
|
|
163
157
|
|
|
164
158
|
<select
|
|
165
|
-
className='select min
|
|
159
|
+
className='select select-min'
|
|
166
160
|
value={sortBy}
|
|
167
161
|
onChange={(e) => setSortBy(e.target.value as SortOption)}
|
|
168
162
|
>
|
|
@@ -173,30 +167,31 @@ function CategoryPage() {
|
|
|
173
167
|
</select>
|
|
174
168
|
|
|
175
169
|
{!loading && (
|
|
176
|
-
<div className='
|
|
170
|
+
<div className='filter-count'>
|
|
177
171
|
Showing {filteredProducts.length} of {products.length} products
|
|
178
172
|
</div>
|
|
179
173
|
)}
|
|
180
174
|
</div>
|
|
181
175
|
|
|
182
|
-
{/* Products Grid */}
|
|
183
176
|
{loading ? (
|
|
184
|
-
<div className='
|
|
185
|
-
<div className='
|
|
177
|
+
<div className='state-loading'>
|
|
178
|
+
<div className='state-loading-pulse'>Loading products...</div>
|
|
186
179
|
</div>
|
|
187
180
|
) : error ? (
|
|
188
|
-
<div className='
|
|
181
|
+
<div className='state-error'>
|
|
189
182
|
{error}
|
|
190
|
-
<div className='
|
|
191
|
-
<Link to='/categories' className='link
|
|
183
|
+
<div className='state-error-action'>
|
|
184
|
+
<Link to='/categories' className='link link-semibold'>
|
|
192
185
|
← Back to Categories
|
|
193
186
|
</Link>
|
|
194
187
|
</div>
|
|
195
188
|
</div>
|
|
196
189
|
) : filteredProducts.length === 0 ? (
|
|
197
|
-
<div className='
|
|
198
|
-
<div className='
|
|
199
|
-
<div className='
|
|
190
|
+
<div className='state-empty'>
|
|
191
|
+
<div className='state-empty-icon'>🔍</div>
|
|
192
|
+
<div className='state-empty-action'>
|
|
193
|
+
No products found matching your criteria
|
|
194
|
+
</div>
|
|
200
195
|
{searchQuery && (
|
|
201
196
|
<button
|
|
202
197
|
type='button'
|
|
@@ -79,10 +79,10 @@ function CategoriesIndexPage() {
|
|
|
79
79
|
return (
|
|
80
80
|
<>
|
|
81
81
|
<Header />
|
|
82
|
-
<main className='
|
|
82
|
+
<main className='page-main'>
|
|
83
83
|
<h1 className='section-heading'>Shop by Category</h1>
|
|
84
|
-
<div className='
|
|
85
|
-
<div className='
|
|
84
|
+
<div className='state-loading'>
|
|
85
|
+
<div className='state-loading-pulse'>Loading categories...</div>
|
|
86
86
|
</div>
|
|
87
87
|
</main>
|
|
88
88
|
</>
|
|
@@ -93,10 +93,8 @@ function CategoriesIndexPage() {
|
|
|
93
93
|
return (
|
|
94
94
|
<>
|
|
95
95
|
<Header />
|
|
96
|
-
<main className='
|
|
97
|
-
<div className='
|
|
98
|
-
{error}
|
|
99
|
-
</div>
|
|
96
|
+
<main className='page-main'>
|
|
97
|
+
<div className='state-error'>{error}</div>
|
|
100
98
|
</main>
|
|
101
99
|
</>
|
|
102
100
|
);
|
|
@@ -106,8 +104,8 @@ function CategoriesIndexPage() {
|
|
|
106
104
|
<>
|
|
107
105
|
<Header />
|
|
108
106
|
|
|
109
|
-
<main className='
|
|
110
|
-
<div className='
|
|
107
|
+
<main className='page-main'>
|
|
108
|
+
<div className='page-intro-lg'>
|
|
111
109
|
<h1 className='section-heading'>Shop by Category</h1>
|
|
112
110
|
<p className='section-subheading'>
|
|
113
111
|
Browse curated collections and jump straight into your favorite
|
|
@@ -115,7 +113,7 @@ function CategoriesIndexPage() {
|
|
|
115
113
|
</p>
|
|
116
114
|
</div>
|
|
117
115
|
|
|
118
|
-
<div className='
|
|
116
|
+
<div className='category-grid'>
|
|
119
117
|
{categories.map((category) => {
|
|
120
118
|
const label = formatCategoryLabel(category);
|
|
121
119
|
const description =
|
|
@@ -127,14 +125,12 @@ function CategoriesIndexPage() {
|
|
|
127
125
|
<Link
|
|
128
126
|
key={category}
|
|
129
127
|
to={to}
|
|
130
|
-
className='card card-hover
|
|
128
|
+
className='card card-hover category-card'
|
|
131
129
|
>
|
|
132
|
-
<div className='
|
|
133
|
-
<h2 className='
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<p className='text-gray-600 text-sm mb-4'>{description}</p>
|
|
137
|
-
<span className='inline-flex items-center gap-2 btn-primary btn-sm'>
|
|
130
|
+
<div className='category-card-icon'>{icon}</div>
|
|
131
|
+
<h2 className='category-card-title'>{label}</h2>
|
|
132
|
+
<p className='category-card-desc'>{description}</p>
|
|
133
|
+
<span className='category-card-cta btn-primary btn-sm'>
|
|
138
134
|
View Products <span aria-hidden='true'>→</span>
|
|
139
135
|
</span>
|
|
140
136
|
</Link>
|
|
@@ -142,11 +138,9 @@ function CategoriesIndexPage() {
|
|
|
142
138
|
})}
|
|
143
139
|
</div>
|
|
144
140
|
|
|
145
|
-
<div className='
|
|
146
|
-
<h3 className='
|
|
147
|
-
|
|
148
|
-
</h3>
|
|
149
|
-
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8'>
|
|
141
|
+
<div className='why-shop'>
|
|
142
|
+
<h3 className='why-shop-title'>Why Shop With Us?</h3>
|
|
143
|
+
<div className='why-shop-grid'>
|
|
150
144
|
{[
|
|
151
145
|
{
|
|
152
146
|
icon: '🚚',
|
|
@@ -170,11 +164,9 @@ function CategoriesIndexPage() {
|
|
|
170
164
|
},
|
|
171
165
|
].map((item) => (
|
|
172
166
|
<div key={item.title}>
|
|
173
|
-
<div className='
|
|
174
|
-
<div className='
|
|
175
|
-
|
|
176
|
-
</div>
|
|
177
|
-
<div className='text-sm text-gray-600'>{item.desc}</div>
|
|
167
|
+
<div className='why-shop-item-icon'>{item.icon}</div>
|
|
168
|
+
<div className='why-shop-item-title'>{item.title}</div>
|
|
169
|
+
<div className='why-shop-item-desc'>{item.desc}</div>
|
|
178
170
|
</div>
|
|
179
171
|
))}
|
|
180
172
|
</div>
|
|
@@ -30,16 +30,16 @@ function HomePage() {
|
|
|
30
30
|
<>
|
|
31
31
|
<Header />
|
|
32
32
|
|
|
33
|
-
<main className='
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<h1 className='text-5xl md:text-6xl font-bold text-gray-900 mb-4 leading-tight'>
|
|
33
|
+
<main className='page-main'>
|
|
34
|
+
<section className='hero animate-slide-up'>
|
|
35
|
+
<h1 className='hero-title'>
|
|
37
36
|
Welcome to {import.meta.env.REROUTE_SITE_NAME || 'Reroute Store'}
|
|
38
37
|
</h1>
|
|
39
|
-
<p className='
|
|
40
|
-
{import.meta.env.REROUTE_SITE_DESCRIPTION ||
|
|
38
|
+
<p className='hero-lead'>
|
|
39
|
+
{import.meta.env.REROUTE_SITE_DESCRIPTION ||
|
|
40
|
+
'A modern e-commerce demo built with Reroute, showcasing file-based routing, SSR, and seamless API integration with FakeStoreAPI'}
|
|
41
41
|
</p>
|
|
42
|
-
<div className='
|
|
42
|
+
<div className='hero-actions'>
|
|
43
43
|
<Link to='/products' className='btn-primary btn-lg'>
|
|
44
44
|
Shop Now
|
|
45
45
|
</Link>
|
|
@@ -49,19 +49,18 @@ function HomePage() {
|
|
|
49
49
|
</div>
|
|
50
50
|
</section>
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
<section className='section-block'>
|
|
53
|
+
<div className='section-header'>
|
|
54
|
+
<h2 className='section-heading section-heading-flush'>
|
|
55
|
+
Featured Products
|
|
56
|
+
</h2>
|
|
57
|
+
<Link to='/products' className='link link-semibold link-lg'>
|
|
57
58
|
View All →
|
|
58
59
|
</Link>
|
|
59
60
|
</div>
|
|
60
61
|
|
|
61
62
|
{error ? (
|
|
62
|
-
<div className='
|
|
63
|
-
{error}
|
|
64
|
-
</div>
|
|
63
|
+
<div className='state-error'>{error}</div>
|
|
65
64
|
) : (
|
|
66
65
|
<div className='product-grid'>
|
|
67
66
|
{featuredProducts.map((product) => (
|
|
@@ -71,46 +70,37 @@ function HomePage() {
|
|
|
71
70
|
)}
|
|
72
71
|
</section>
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
<section className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mt-12 pt-8'>
|
|
73
|
+
<section className='features-grid'>
|
|
76
74
|
<div className='feature-card'>
|
|
77
|
-
<div className='
|
|
78
|
-
<h3 className='
|
|
79
|
-
|
|
80
|
-
</h3>
|
|
81
|
-
<p className='text-gray-600 leading-relaxed'>
|
|
75
|
+
<div className='feature-icon'>⚡</div>
|
|
76
|
+
<h3 className='feature-title'>Lightning Fast</h3>
|
|
77
|
+
<p className='feature-text'>
|
|
82
78
|
Built on Bun for blazing fast performance, server-side rendering
|
|
83
79
|
and image caching
|
|
84
80
|
</p>
|
|
85
81
|
</div>
|
|
86
82
|
|
|
87
83
|
<div className='feature-card'>
|
|
88
|
-
<div className='
|
|
89
|
-
<h3 className='
|
|
90
|
-
|
|
91
|
-
</h3>
|
|
92
|
-
<p className='text-gray-600 leading-relaxed'>
|
|
84
|
+
<div className='feature-icon'>🎯</div>
|
|
85
|
+
<h3 className='feature-title'>File-Based Routing</h3>
|
|
86
|
+
<p className='feature-text'>
|
|
93
87
|
Automatic route generation from your file structure with zero
|
|
94
88
|
configuration
|
|
95
89
|
</p>
|
|
96
90
|
</div>
|
|
97
91
|
|
|
98
92
|
<div className='feature-card'>
|
|
99
|
-
<div className='
|
|
100
|
-
<h3 className='
|
|
101
|
-
|
|
102
|
-
</h3>
|
|
103
|
-
<p className='text-gray-600 leading-relaxed'>
|
|
93
|
+
<div className='feature-icon'>🔄</div>
|
|
94
|
+
<h3 className='feature-title'>SSR Support</h3>
|
|
95
|
+
<p className='feature-text'>
|
|
104
96
|
SEO-friendly with automatic hydration
|
|
105
97
|
</p>
|
|
106
98
|
</div>
|
|
107
99
|
|
|
108
100
|
<div className='feature-card'>
|
|
109
|
-
<div className='
|
|
110
|
-
<h3 className='
|
|
111
|
-
|
|
112
|
-
</h3>
|
|
113
|
-
<p className='text-gray-600 leading-relaxed'>
|
|
101
|
+
<div className='feature-icon'>📦</div>
|
|
102
|
+
<h3 className='feature-title'>API Integration</h3>
|
|
103
|
+
<p className='feature-text'>
|
|
114
104
|
Seamless integration with external APIs using serializable
|
|
115
105
|
responses
|
|
116
106
|
</p>
|
|
@@ -4,7 +4,6 @@ import Header from '../../components/Header';
|
|
|
4
4
|
import ProductCard from '../../components/ProductCard';
|
|
5
5
|
import { getProduct, getProductsByCategory, type Product } from '../../lib/api';
|
|
6
6
|
|
|
7
|
-
// Enable SSR data fetching for this route
|
|
8
7
|
const ssr = {
|
|
9
8
|
async data({ params }: { params: { id?: string } }) {
|
|
10
9
|
try {
|
|
@@ -45,7 +44,6 @@ function ProductDetailPage() {
|
|
|
45
44
|
const params = useParams<{ id: string }>();
|
|
46
45
|
const productId = params.id ? Number.parseInt(params.id, 10) : null;
|
|
47
46
|
|
|
48
|
-
// Read SSR-seeded or prefetched data for this route
|
|
49
47
|
const routeData = useData<{
|
|
50
48
|
product: Product | null;
|
|
51
49
|
relatedProducts: Product[];
|
|
@@ -58,7 +56,6 @@ function ProductDetailPage() {
|
|
|
58
56
|
const relatedProducts = data?.relatedProducts ?? [];
|
|
59
57
|
const error = data?.error ?? (productId ? null : 'Invalid product ID');
|
|
60
58
|
|
|
61
|
-
// Fallback on client nav if hover prefetch didn't run
|
|
62
59
|
useEffect(() => {
|
|
63
60
|
if (typeof window === 'undefined') return;
|
|
64
61
|
if (routeData !== undefined) return;
|
|
@@ -80,7 +77,6 @@ function ProductDetailPage() {
|
|
|
80
77
|
|
|
81
78
|
const handleAddToCart = () => {
|
|
82
79
|
setAddingToCart(true);
|
|
83
|
-
// Simulate adding to cart
|
|
84
80
|
setTimeout(() => {
|
|
85
81
|
setAddingToCart(false);
|
|
86
82
|
alert(`Added ${product?.title} to cart!`);
|
|
@@ -95,10 +91,12 @@ function ProductDetailPage() {
|
|
|
95
91
|
return (
|
|
96
92
|
<>
|
|
97
93
|
<Header />
|
|
98
|
-
<main className='
|
|
99
|
-
<h1 className='
|
|
100
|
-
<div className='
|
|
101
|
-
<div className='
|
|
94
|
+
<main className='page-main'>
|
|
95
|
+
<h1 className='page-title'>Loading...</h1>
|
|
96
|
+
<div className='state-loading'>
|
|
97
|
+
<div className='state-loading-pulse'>
|
|
98
|
+
Loading product details...
|
|
99
|
+
</div>
|
|
102
100
|
</div>
|
|
103
101
|
</main>
|
|
104
102
|
</>
|
|
@@ -109,11 +107,11 @@ function ProductDetailPage() {
|
|
|
109
107
|
return (
|
|
110
108
|
<>
|
|
111
109
|
<Header />
|
|
112
|
-
<main className='
|
|
113
|
-
<div className='
|
|
110
|
+
<main className='page-main'>
|
|
111
|
+
<div className='state-error'>
|
|
114
112
|
{error || 'Product not found'}
|
|
115
|
-
<div className='
|
|
116
|
-
<Link to='/products' className='link
|
|
113
|
+
<div className='state-error-action'>
|
|
114
|
+
<Link to='/products' className='link link-semibold'>
|
|
117
115
|
← Back to Products
|
|
118
116
|
</Link>
|
|
119
117
|
</div>
|
|
@@ -127,9 +125,8 @@ function ProductDetailPage() {
|
|
|
127
125
|
<>
|
|
128
126
|
<Header />
|
|
129
127
|
|
|
130
|
-
<main className='
|
|
131
|
-
|
|
132
|
-
<nav className='flex items-center gap-2 text-sm text-gray-600 mb-8'>
|
|
128
|
+
<main className='page-main'>
|
|
129
|
+
<nav className='breadcrumb'>
|
|
133
130
|
<Link to='/' className='link'>
|
|
134
131
|
Home
|
|
135
132
|
</Link>
|
|
@@ -142,13 +139,11 @@ function ProductDetailPage() {
|
|
|
142
139
|
{product.category}
|
|
143
140
|
</Link>
|
|
144
141
|
<span>/</span>
|
|
145
|
-
<span className='
|
|
142
|
+
<span className='breadcrumb-current'>{product.title}</span>
|
|
146
143
|
</nav>
|
|
147
144
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
{/* Product Image */}
|
|
151
|
-
<div className='card flex items-center justify-center p-8 min-h-[500px]'>
|
|
145
|
+
<div className='product-detail-grid'>
|
|
146
|
+
<div className='card product-detail-image'>
|
|
152
147
|
<Image
|
|
153
148
|
src={product.image}
|
|
154
149
|
alt={product.title}
|
|
@@ -157,43 +152,36 @@ function ProductDetailPage() {
|
|
|
157
152
|
quality={85}
|
|
158
153
|
sizes='(max-width: 1024px) 90vw, 350px'
|
|
159
154
|
priority
|
|
160
|
-
className='
|
|
155
|
+
className='product-detail-image-img'
|
|
161
156
|
style={{ viewTransitionName: `product-image-${product.id}` }}
|
|
162
157
|
/>
|
|
163
158
|
</div>
|
|
164
159
|
|
|
165
|
-
|
|
166
|
-
<div className='flex flex-col gap-6'>
|
|
160
|
+
<div className='product-detail-info'>
|
|
167
161
|
<div className='badge-primary'>{product.category}</div>
|
|
168
162
|
|
|
169
|
-
<h1 className='
|
|
170
|
-
{product.title}
|
|
171
|
-
</h1>
|
|
163
|
+
<h1 className='product-detail-title'>{product.title}</h1>
|
|
172
164
|
|
|
173
165
|
{product.rating && (
|
|
174
|
-
<div className='
|
|
175
|
-
<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
<span>({product.rating.count} reviews)</span>
|
|
181
|
-
</div>
|
|
166
|
+
<div className='product-rating-lg'>
|
|
167
|
+
<span className='product-rating-star'>⭐</span>
|
|
168
|
+
<span className='product-rating-value'>
|
|
169
|
+
{product.rating.rate}
|
|
170
|
+
</span>
|
|
171
|
+
<span>({product.rating.count} reviews)</span>
|
|
182
172
|
</div>
|
|
183
173
|
)}
|
|
184
174
|
|
|
185
|
-
<div className='
|
|
186
|
-
${product.price.toFixed(2)}
|
|
187
|
-
</div>
|
|
175
|
+
<div className='price-lg'>${product.price.toFixed(2)}</div>
|
|
188
176
|
|
|
189
|
-
<p className='
|
|
177
|
+
<p className='product-detail-description'>
|
|
190
178
|
{product.description}
|
|
191
179
|
</p>
|
|
192
180
|
|
|
193
|
-
<div className='
|
|
181
|
+
<div className='product-actions'>
|
|
194
182
|
<button
|
|
195
183
|
type='button'
|
|
196
|
-
className='btn-primary
|
|
184
|
+
className='btn-primary btn-grow'
|
|
197
185
|
onClick={handleAddToCart}
|
|
198
186
|
disabled={addingToCart}
|
|
199
187
|
>
|
|
@@ -209,24 +197,23 @@ function ProductDetailPage() {
|
|
|
209
197
|
</button>
|
|
210
198
|
</div>
|
|
211
199
|
|
|
212
|
-
<div className='
|
|
213
|
-
<div className='
|
|
214
|
-
<span className='
|
|
200
|
+
<div className='product-perks'>
|
|
201
|
+
<div className='product-perk'>
|
|
202
|
+
<span className='product-perk-check'>✓</span>
|
|
215
203
|
<span>Free shipping on orders over $50</span>
|
|
216
204
|
</div>
|
|
217
|
-
<div className='
|
|
218
|
-
<span className='
|
|
205
|
+
<div className='product-perk'>
|
|
206
|
+
<span className='product-perk-check'>✓</span>
|
|
219
207
|
<span>30-day return policy</span>
|
|
220
208
|
</div>
|
|
221
|
-
<div className='
|
|
222
|
-
<span className='
|
|
209
|
+
<div className='product-perk'>
|
|
210
|
+
<span className='product-perk-check'>✓</span>
|
|
223
211
|
<span>Secure checkout</span>
|
|
224
212
|
</div>
|
|
225
213
|
</div>
|
|
226
214
|
</div>
|
|
227
215
|
</div>
|
|
228
216
|
|
|
229
|
-
{/* Related Products */}
|
|
230
217
|
{relatedProducts.length > 0 && (
|
|
231
218
|
<section className='animate-in'>
|
|
232
219
|
<h2 className='section-heading'>Related Products</h2>
|