reroute-js 0.46.0 → 1.0.0-alpha.0
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/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/_/store/src/client/theme.css +907 -95
- package/cli/bin.d.ts +1 -1
- package/cli/bin.js +78 -176
- package/cli/bin.js.map +11 -11
- package/cli/index.d.ts +1 -1
- package/cli/index.js +17 -112
- 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 +12 -12
- 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 +21 -21
- 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/cli/src/commands/lib/tailwind.d.ts +0 -20
- package/cli/src/commands/lib/tailwind.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -179,11 +179,9 @@ Reroute is a feature-rich file-based routing framework for building fullstack Re
|
|
|
179
179
|
- ⚡ **React 19 Streaming** - Native `renderToReadableStream` for optimal performance
|
|
180
180
|
|
|
181
181
|
### 🎨 Styling & Theming
|
|
182
|
-
- 🎨 **
|
|
182
|
+
- 🎨 **Native CSS** - Author styles in `src/client/theme.css` with no CSS framework required
|
|
183
183
|
- ⚡ **Live CSS Reload** - Instant style updates in development mode
|
|
184
|
-
-
|
|
185
|
-
- 🚀 **Oxide Engine** - 5x faster builds with the new Tailwind compiler
|
|
186
|
-
- 🔧 **Zero Config** - Works out of the box when `@tailwindcss/cli` is installed
|
|
184
|
+
- 🔧 **Zero Config** - Theme CSS is synced automatically during `reroute gen`
|
|
187
185
|
|
|
188
186
|
### 🎨 Developer Experience
|
|
189
187
|
- 📁 **Project Templates** - Quick start with `basic`, `blog`, or `store` templates
|
package/_/store/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "{{PROJECT_NAME}}",
|
|
3
3
|
"version": "0.0.0",
|
|
4
|
-
"description": "A Reroute store application
|
|
4
|
+
"description": "A Reroute store application",
|
|
5
5
|
"private": true,
|
|
6
6
|
"scripts": {
|
|
7
7
|
"types": "tsc --noEmit",
|
|
@@ -23,8 +23,6 @@
|
|
|
23
23
|
"@types/bun": "latest",
|
|
24
24
|
"@types/react": "^19.2.2",
|
|
25
25
|
"@types/react-dom": "^19.2.2",
|
|
26
|
-
"@tailwindcss/cli": "^4.1.16",
|
|
27
|
-
"tailwindcss": "^4.1.16",
|
|
28
26
|
"typescript": "^5"
|
|
29
27
|
}
|
|
30
28
|
}
|
|
@@ -2,34 +2,22 @@ import { Link } from 'reroute-js/react';
|
|
|
2
2
|
|
|
3
3
|
export default function Header() {
|
|
4
4
|
return (
|
|
5
|
-
<header className='
|
|
5
|
+
<header className='site-header'>
|
|
6
6
|
<div className='container-custom'>
|
|
7
|
-
<div className='
|
|
8
|
-
<Link
|
|
9
|
-
|
|
10
|
-
className='flex items-center gap-2 text-2xl font-bold text-primary-600 hover:text-primary-700 transition-colors'
|
|
11
|
-
>
|
|
12
|
-
<span className='text-3xl'>🛒</span>
|
|
7
|
+
<div className='header-inner'>
|
|
8
|
+
<Link to='/' className='header-logo'>
|
|
9
|
+
<span className='header-logo-icon'>🛒</span>
|
|
13
10
|
<span>Reroute Store</span>
|
|
14
11
|
</Link>
|
|
15
12
|
|
|
16
|
-
<nav className='
|
|
17
|
-
<Link
|
|
18
|
-
to='/'
|
|
19
|
-
className='link-muted font-medium hover:text-primary-600'
|
|
20
|
-
>
|
|
13
|
+
<nav className='header-nav'>
|
|
14
|
+
<Link to='/' className='nav-link'>
|
|
21
15
|
Home
|
|
22
16
|
</Link>
|
|
23
|
-
<Link
|
|
24
|
-
to='/products'
|
|
25
|
-
className='link-muted font-medium hover:text-primary-600'
|
|
26
|
-
>
|
|
17
|
+
<Link to='/products' className='nav-link'>
|
|
27
18
|
Products
|
|
28
19
|
</Link>
|
|
29
|
-
<Link
|
|
30
|
-
to='/categories'
|
|
31
|
-
className='link-muted font-medium hover:text-primary-600'
|
|
32
|
-
>
|
|
20
|
+
<Link to='/categories' className='nav-link'>
|
|
33
21
|
Categories
|
|
34
22
|
</Link>
|
|
35
23
|
</nav>
|
|
@@ -8,12 +8,9 @@ interface ProductCardProps {
|
|
|
8
8
|
|
|
9
9
|
export default function ProductCard({ product }: ProductCardProps) {
|
|
10
10
|
return (
|
|
11
|
-
<div className='card card-hover
|
|
12
|
-
<Link
|
|
13
|
-
|
|
14
|
-
className='block h-full no-underline text-inherit'
|
|
15
|
-
>
|
|
16
|
-
<div className='w-full h-60 bg-gray-50 flex items-center justify-center p-4'>
|
|
11
|
+
<div className='card card-hover product-card'>
|
|
12
|
+
<Link to={`/products/${product.id}`} className='product-card-link'>
|
|
13
|
+
<div className='product-card-image-wrap'>
|
|
17
14
|
<Image
|
|
18
15
|
src={product.image}
|
|
19
16
|
alt={product.title}
|
|
@@ -21,25 +18,21 @@ export default function ProductCard({ product }: ProductCardProps) {
|
|
|
21
18
|
height={180}
|
|
22
19
|
quality={75}
|
|
23
20
|
sizes='(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 180px'
|
|
24
|
-
className='
|
|
21
|
+
className='product-card-image'
|
|
25
22
|
style={{ viewTransitionName: `product-image-${product.id}` }}
|
|
26
23
|
/>
|
|
27
24
|
</div>
|
|
28
25
|
|
|
29
|
-
<div className='
|
|
26
|
+
<div className='product-card-body'>
|
|
30
27
|
<div className='badge-primary'>{product.category}</div>
|
|
31
28
|
|
|
32
|
-
<h3 className='
|
|
33
|
-
{product.title}
|
|
34
|
-
</h3>
|
|
29
|
+
<h3 className='product-card-title'>{product.title}</h3>
|
|
35
30
|
|
|
36
|
-
<div className='
|
|
37
|
-
<span className='
|
|
38
|
-
${product.price.toFixed(2)}
|
|
39
|
-
</span>
|
|
31
|
+
<div className='product-card-footer'>
|
|
32
|
+
<span className='price'>${product.price.toFixed(2)}</span>
|
|
40
33
|
|
|
41
34
|
{product.rating && (
|
|
42
|
-
<div className='
|
|
35
|
+
<div className='product-rating'>
|
|
43
36
|
<span>⭐</span>
|
|
44
37
|
<span>
|
|
45
38
|
{product.rating.rate} ({product.rating.count})
|
|
@@ -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>
|