reroute-js 0.45.12-beta.1 → 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.
Files changed (254) hide show
  1. package/README.md +102 -6
  2. package/_/blog/src/client/routes/blog/[layout].tsx +45 -13
  3. package/_/blog/src/client/routes/blog/content/pt-BR/1-hello-world.tsx +27 -0
  4. package/_/blog/src/client/routes/index.tsx +4 -4
  5. package/_/search/src/client/routes/docs/content/content-collections.md +18 -0
  6. package/_/store/package.json +1 -3
  7. package/_/store/src/client/components/Header.tsx +8 -20
  8. package/_/store/src/client/components/ProductCard.tsx +9 -16
  9. package/_/store/src/client/routes/[404].tsx +20 -31
  10. package/_/store/src/client/routes/categories/[category].tsx +23 -28
  11. package/_/store/src/client/routes/categories/index.tsx +19 -27
  12. package/_/store/src/client/routes/index.tsx +27 -37
  13. package/_/store/src/client/routes/products/[id].tsx +35 -48
  14. package/_/store/src/client/routes/products/index.tsx +20 -50
  15. package/_/store/src/client/theme.css +907 -95
  16. package/cli/bin.d.ts +2 -2
  17. package/cli/bin.js +1035 -490
  18. package/cli/bin.js.map +33 -25
  19. package/cli/index.d.ts +2 -2
  20. package/cli/index.js +18 -113
  21. package/cli/index.js.map +5 -5
  22. package/cli/src/cli.d.ts +2 -2
  23. package/cli/src/commands/analyze.d.ts +2 -2
  24. package/cli/src/commands/build.d.ts +2 -2
  25. package/cli/src/commands/dev.d.ts +2 -2
  26. package/cli/src/commands/gen.d.ts +2 -2
  27. package/cli/src/commands/gen.d.ts.map +1 -1
  28. package/cli/src/commands/index.d.ts +2 -2
  29. package/cli/src/commands/init.d.ts +2 -2
  30. package/cli/src/commands/lib/assets.d.ts +2 -2
  31. package/cli/src/commands/lib/bundler.d.ts +2 -2
  32. package/cli/src/commands/lib/command.d.ts +2 -2
  33. package/cli/src/commands/lib/env.d.ts +2 -2
  34. package/cli/src/commands/lib/index.d.ts +3 -3
  35. package/cli/src/commands/lib/index.d.ts.map +1 -1
  36. package/cli/src/commands/lib/log.d.ts +2 -2
  37. package/cli/src/commands/lib/markdown/availability.d.ts +2 -2
  38. package/cli/src/commands/lib/markdown/index.d.ts +2 -2
  39. package/cli/src/commands/lib/markdown/processor.d.ts +2 -2
  40. package/cli/src/commands/lib/production.d.ts +2 -2
  41. package/cli/src/commands/lib/server.d.ts +2 -2
  42. package/cli/src/commands/lib/streaming/analyzer.d.ts +2 -2
  43. package/cli/src/commands/lib/streaming/suspense.d.ts +2 -2
  44. package/cli/src/commands/lib/terminal-ui.d.ts +2 -2
  45. package/cli/src/commands/lib/theme.d.ts +20 -0
  46. package/cli/src/commands/lib/theme.d.ts.map +1 -0
  47. package/cli/src/commands/lib/version.d.ts +2 -2
  48. package/cli/src/commands/og.d.ts +2 -2
  49. package/cli/src/commands/start.d.ts +2 -2
  50. package/cli/src/index.d.ts +2 -2
  51. package/core/index.d.ts +2 -2
  52. package/core/index.js +677 -127
  53. package/core/index.js.map +29 -21
  54. package/core/src/bundler/hash.d.ts +2 -2
  55. package/core/src/bundler/index.d.ts +2 -2
  56. package/core/src/config.d.ts +6 -3
  57. package/core/src/config.d.ts.map +1 -1
  58. package/core/src/content/discovery.d.ts +2 -2
  59. package/core/src/content/index.d.ts +2 -2
  60. package/core/src/content/metadata.d.ts +2 -2
  61. package/core/src/i18n/catalog.d.ts +17 -0
  62. package/core/src/i18n/catalog.d.ts.map +1 -0
  63. package/core/src/i18n/discover.d.ts +19 -0
  64. package/core/src/i18n/discover.d.ts.map +1 -0
  65. package/core/src/i18n/index.d.ts +17 -0
  66. package/core/src/i18n/index.d.ts.map +1 -0
  67. package/core/src/i18n/messages.d.ts +18 -0
  68. package/core/src/i18n/messages.d.ts.map +1 -0
  69. package/core/src/i18n/negotiate.d.ts +18 -0
  70. package/core/src/i18n/negotiate.d.ts.map +1 -0
  71. package/core/src/i18n/pathname.d.ts +34 -0
  72. package/core/src/i18n/pathname.d.ts.map +1 -0
  73. package/core/src/i18n/resolve.d.ts +22 -0
  74. package/core/src/i18n/resolve.d.ts.map +1 -0
  75. package/core/src/i18n/types.d.ts +68 -0
  76. package/core/src/i18n/types.d.ts.map +1 -0
  77. package/core/src/index.d.ts +3 -2
  78. package/core/src/index.d.ts.map +1 -1
  79. package/core/src/llms/extractor.d.ts +2 -2
  80. package/core/src/llms/formatter.d.ts +2 -2
  81. package/core/src/llms/full-generator.d.ts +2 -2
  82. package/core/src/llms/index-generator.d.ts +2 -2
  83. package/core/src/llms/index.d.ts +2 -2
  84. package/core/src/og/discovery.d.ts +2 -2
  85. package/core/src/og/index.d.ts +2 -2
  86. package/core/src/og/meta.d.ts +2 -2
  87. package/core/src/og/render.d.ts +2 -2
  88. package/core/src/og/types.d.ts +2 -2
  89. package/core/src/robots/discovery.d.ts +2 -2
  90. package/core/src/robots/generator.d.ts +2 -2
  91. package/core/src/robots/index.d.ts +2 -2
  92. package/core/src/robots/policies.d.ts +2 -2
  93. package/core/src/rss/discovery.d.ts +4 -2
  94. package/core/src/rss/discovery.d.ts.map +1 -1
  95. package/core/src/rss/generator.d.ts +2 -2
  96. package/core/src/rss/index.d.ts +2 -2
  97. package/core/src/sitemap/discovery.d.ts +7 -2
  98. package/core/src/sitemap/discovery.d.ts.map +1 -1
  99. package/core/src/sitemap/generator.d.ts +2 -2
  100. package/core/src/sitemap/generator.d.ts.map +1 -1
  101. package/core/src/sitemap/index.d.ts +2 -2
  102. package/core/src/ssr/index.d.ts +2 -2
  103. package/core/src/ssr/lib/cache.d.ts +2 -2
  104. package/core/src/ssr/lib/cleanup.d.ts +2 -2
  105. package/core/src/ssr/lib/collections.d.ts +2 -2
  106. package/core/src/ssr/lib/compression.d.ts +2 -2
  107. package/core/src/ssr/lib/compute/content.d.ts +2 -9
  108. package/core/src/ssr/lib/compute/content.d.ts.map +1 -1
  109. package/core/src/ssr/lib/compute/index.d.ts +2 -2
  110. package/core/src/ssr/lib/compute/layouts.d.ts +2 -2
  111. package/core/src/ssr/lib/compute/routes.d.ts +2 -2
  112. package/core/src/ssr/lib/compute/routes.d.ts.map +1 -1
  113. package/core/src/ssr/lib/content-path.d.ts +22 -0
  114. package/core/src/ssr/lib/content-path.d.ts.map +1 -0
  115. package/core/src/ssr/lib/data.d.ts +2 -2
  116. package/core/src/ssr/lib/data.d.ts.map +1 -1
  117. package/core/src/ssr/lib/html.d.ts +2 -2
  118. package/core/src/ssr/lib/imports.d.ts +2 -2
  119. package/core/src/ssr/lib/index.d.ts +2 -2
  120. package/core/src/ssr/lib/layouts.d.ts +2 -2
  121. package/core/src/ssr/lib/metadata.d.ts +2 -2
  122. package/core/src/ssr/lib/metadata.d.ts.map +1 -1
  123. package/core/src/ssr/lib/mime.d.ts +2 -2
  124. package/core/src/ssr/lib/modules.d.ts +4 -4
  125. package/core/src/ssr/lib/modules.d.ts.map +1 -1
  126. package/core/src/ssr/lib/path.d.ts +2 -2
  127. package/core/src/ssr/lib/preload.d.ts +2 -2
  128. package/core/src/ssr/lib/preload.d.ts.map +1 -1
  129. package/core/src/ssr/lib/route-match.d.ts +2 -2
  130. package/core/src/ssr/lib/scripts/collections.d.ts +2 -2
  131. package/core/src/ssr/lib/scripts/data.d.ts +3 -3
  132. package/core/src/ssr/lib/scripts/data.d.ts.map +1 -1
  133. package/core/src/ssr/lib/scripts/escape.d.ts +2 -2
  134. package/core/src/ssr/lib/scripts/feeds.d.ts +2 -2
  135. package/core/src/ssr/lib/scripts/index.d.ts +2 -2
  136. package/core/src/ssr/lib/seed.d.ts +2 -2
  137. package/core/src/ssr/lib/seed.d.ts.map +1 -1
  138. package/core/src/ssr/lib/serialize.d.ts +2 -2
  139. package/core/src/ssr/lib/setup.d.ts +4 -4
  140. package/core/src/ssr/lib/setup.d.ts.map +1 -1
  141. package/core/src/ssr/lib/styles.d.ts +4 -4
  142. package/core/src/ssr/lib/styles.d.ts.map +1 -1
  143. package/core/src/ssr/lib/template.d.ts +2 -2
  144. package/core/src/ssr/lib/types.d.ts +2 -2
  145. package/core/src/ssr/render.d.ts +5 -3
  146. package/core/src/ssr/render.d.ts.map +1 -1
  147. package/core/src/ssr/stream.d.ts +5 -3
  148. package/core/src/ssr/stream.d.ts.map +1 -1
  149. package/elysia/index.d.ts +2 -2
  150. package/elysia/index.js +891 -196
  151. package/elysia/index.js.map +35 -26
  152. package/elysia/src/index.d.ts +2 -2
  153. package/elysia/src/libs/assets.d.ts +2 -2
  154. package/elysia/src/libs/cache.d.ts +2 -2
  155. package/elysia/src/libs/caching.d.ts +2 -2
  156. package/elysia/src/libs/http.d.ts +2 -2
  157. package/elysia/src/libs/i18n.d.ts +26 -0
  158. package/elysia/src/libs/i18n.d.ts.map +1 -0
  159. package/elysia/src/libs/image.d.ts +2 -2
  160. package/elysia/src/libs/index.d.ts +2 -2
  161. package/elysia/src/libs/llms.d.ts +2 -2
  162. package/elysia/src/libs/response.d.ts +2 -2
  163. package/elysia/src/libs/serving.d.ts +2 -2
  164. package/elysia/src/plugin.d.ts +2 -2
  165. package/elysia/src/routes/artifacts.d.ts +2 -2
  166. package/elysia/src/routes/content.d.ts +2 -2
  167. package/elysia/src/routes/image.d.ts +2 -2
  168. package/elysia/src/routes/index.d.ts +2 -2
  169. package/elysia/src/routes/internal.d.ts +2 -2
  170. package/elysia/src/routes/llms.d.ts +2 -2
  171. package/elysia/src/routes/og.d.ts +2 -2
  172. package/elysia/src/routes/redirects.d.ts +2 -2
  173. package/elysia/src/routes/robots.d.ts +2 -2
  174. package/elysia/src/routes/rss.d.ts +2 -2
  175. package/elysia/src/routes/rss.d.ts.map +1 -1
  176. package/elysia/src/routes/search.d.ts +2 -2
  177. package/elysia/src/routes/search.d.ts.map +1 -1
  178. package/elysia/src/routes/sitemap.d.ts +2 -2
  179. package/elysia/src/routes/ssr.d.ts +3 -3
  180. package/elysia/src/routes/ssr.d.ts.map +1 -1
  181. package/elysia/src/routes/static.d.ts +2 -2
  182. package/elysia/src/types.d.ts +2 -2
  183. package/package.json +8 -10
  184. package/react/index.d.ts +2 -2
  185. package/react/index.js +560 -170
  186. package/react/index.js.map +12 -10
  187. package/react/src/components/ClientOnly.d.ts +2 -2
  188. package/react/src/components/ContentRoute.d.ts +3 -3
  189. package/react/src/components/ContentRoute.d.ts.map +1 -1
  190. package/react/src/components/Image.d.ts +2 -2
  191. package/react/src/components/LazyRoute.d.ts +2 -2
  192. package/react/src/components/Link.d.ts +2 -2
  193. package/react/src/components/Link.d.ts.map +1 -1
  194. package/react/src/components/Markdown.d.ts +2 -2
  195. package/react/src/components/Outlet.d.ts +2 -2
  196. package/react/src/components/index.d.ts +2 -2
  197. package/react/src/hooks/index.d.ts +2 -2
  198. package/react/src/hooks/useContent.d.ts +2 -2
  199. package/react/src/hooks/useContent.d.ts.map +1 -1
  200. package/react/src/hooks/useData.d.ts +2 -2
  201. package/react/src/hooks/useFeed.d.ts +2 -2
  202. package/react/src/hooks/useLayoutData.d.ts +2 -2
  203. package/react/src/hooks/useLlms.d.ts +2 -2
  204. package/react/src/hooks/useNavigate.d.ts +2 -2
  205. package/react/src/hooks/useParams.d.ts +2 -2
  206. package/react/src/hooks/useRouter.d.ts +2 -2
  207. package/react/src/hooks/useSearch.d.ts +2 -2
  208. package/react/src/hooks/useSearch.d.ts.map +1 -1
  209. package/react/src/hooks/useSearchParams.d.ts +2 -2
  210. package/react/src/hooks/useToc.d.ts +2 -2
  211. package/react/src/i18n/LocaleProvider.d.ts +49 -0
  212. package/react/src/i18n/LocaleProvider.d.ts.map +1 -0
  213. package/react/src/i18n/helpers.d.ts +24 -0
  214. package/react/src/i18n/helpers.d.ts.map +1 -0
  215. package/react/src/i18n/index.d.ts +13 -0
  216. package/react/src/i18n/index.d.ts.map +1 -0
  217. package/react/src/index.d.ts +3 -2
  218. package/react/src/index.d.ts.map +1 -1
  219. package/react/src/lib/collection.d.ts +2 -2
  220. package/react/src/lib/content.d.ts +4 -3
  221. package/react/src/lib/content.d.ts.map +1 -1
  222. package/react/src/lib/head.d.ts +2 -2
  223. package/react/src/lib/index.d.ts +2 -2
  224. package/react/src/lib/lazy-route.d.ts +2 -2
  225. package/react/src/lib/route-loader.d.ts +2 -2
  226. package/react/src/providers/ContentProvider.d.ts +3 -3
  227. package/react/src/providers/ContentProvider.d.ts.map +1 -1
  228. package/react/src/providers/RerouteProvider.d.ts +8 -6
  229. package/react/src/providers/RerouteProvider.d.ts.map +1 -1
  230. package/react/src/providers/RouterProvider.d.ts +2 -2
  231. package/react/src/providers/index.d.ts +2 -2
  232. package/react/src/types/any.d.ts +2 -2
  233. package/react/src/types/index.d.ts +2 -2
  234. package/react/src/types/router.d.ts +2 -2
  235. package/telemetry/react.d.ts +2 -2
  236. package/telemetry/react.js +3 -3
  237. package/telemetry/react.js.map +1 -1
  238. package/telemetry/server.d.ts +2 -2
  239. package/telemetry/server.js +56 -4
  240. package/telemetry/server.js.map +20 -15
  241. package/telemetry/src/react/api.d.ts +2 -2
  242. package/telemetry/src/react/context.d.ts +2 -2
  243. package/telemetry/src/react/index.d.ts +2 -2
  244. package/telemetry/src/react/telemetry.d.ts +2 -2
  245. package/telemetry/src/server/context.d.ts +2 -2
  246. package/telemetry/src/server/headers/extractor.d.ts +2 -2
  247. package/telemetry/src/server/headers/index.d.ts +2 -2
  248. package/telemetry/src/server/headers/presets.d.ts +2 -2
  249. package/telemetry/src/server/index.d.ts +2 -2
  250. package/telemetry/src/server/instrumentation.d.ts +2 -2
  251. package/telemetry/src/server/plugin.d.ts +2 -2
  252. package/telemetry/src/server/sourcemap.d.ts +2 -2
  253. package/cli/src/commands/lib/tailwind.d.ts +0 -20
  254. package/cli/src/commands/lib/tailwind.d.ts.map +0 -1
@@ -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='container-custom py-8'>
130
- {/* Breadcrumbs */}
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='text-gray-900'>{categoryLabel}</span>
134
+ <span className='breadcrumb-current'>{categoryLabel}</span>
141
135
  </nav>
142
136
 
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>
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
- {/* Controls */}
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 flex-1 min-w-[250px]'
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-w-[200px]'
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='ml-auto text-sm text-gray-600'>
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='text-center py-16 text-gray-600 text-lg'>
185
- <div className='animate-pulse'>Loading products...</div>
177
+ <div className='state-loading'>
178
+ <div className='state-loading-pulse'>Loading products...</div>
186
179
  </div>
187
180
  ) : error ? (
188
- <div className='text-center py-16 bg-red-50 text-red-600 text-lg rounded-xl'>
181
+ <div className='state-error'>
189
182
  {error}
190
- <div className='mt-4'>
191
- <Link to='/categories' className='link font-semibold'>
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='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>
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='container-custom py-8'>
82
+ <main className='page-main'>
83
83
  <h1 className='section-heading'>Shop by Category</h1>
84
- <div className='text-center py-16 text-gray-600 text-lg'>
85
- <div className='animate-pulse'>Loading categories...</div>
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='container-custom py-8'>
97
- <div className='text-center py-16 bg-red-50 text-red-600 text-lg rounded-xl'>
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='container-custom py-8'>
110
- <div className='mb-12'>
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='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 mb-12'>
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 group p-8 no-underline text-gray-900 block'
128
+ className='card card-hover category-card'
131
129
  >
132
- <div className='text-5xl mb-4'>{icon}</div>
133
- <h2 className='text-2xl font-bold mb-2 capitalize group-hover:text-primary-600 transition-colors'>
134
- {label}
135
- </h2>
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='mt-16 p-8 bg-gray-50 rounded-xl text-center'>
146
- <h3 className='text-2xl font-bold mb-6 text-gray-900'>
147
- Why Shop With Us?
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='text-4xl mb-2'>{item.icon}</div>
174
- <div className='font-semibold text-gray-700 mb-1'>
175
- {item.title}
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='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'>
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='text-xl text-gray-600 mb-8 max-w-2xl mx-auto'>
40
- {import.meta.env.REROUTE_SITE_DESCRIPTION || 'A modern e-commerce demo built with Reroute, showcasing file-based routing, SSR, and seamless API integration with FakeStoreAPI'}
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='flex gap-4 justify-center flex-wrap'>
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
- {/* Featured Products */}
53
- <section className='mb-16'>
54
- <div className='flex justify-between items-center mb-6'>
55
- <h2 className='section-heading mb-0'>Featured Products</h2>
56
- <Link to='/products' className='link font-semibold text-lg'>
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='text-center py-12 bg-red-50 text-red-600 text-lg rounded-xl'>
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
- {/* Features */}
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='text-5xl mb-4'>⚡</div>
78
- <h3 className='text-xl font-semibold mb-2 text-gray-900'>
79
- Lightning Fast
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='text-5xl mb-4'>🎯</div>
89
- <h3 className='text-xl font-semibold mb-2 text-gray-900'>
90
- File-Based Routing
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='text-5xl mb-4'>🔄</div>
100
- <h3 className='text-xl font-semibold mb-2 text-gray-900'>
101
- SSR Support
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='text-5xl mb-4'>📦</div>
110
- <h3 className='text-xl font-semibold mb-2 text-gray-900'>
111
- API Integration
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='container-custom py-8'>
99
- <h1 className='text-4xl font-bold text-gray-900 mb-8'>Loading...</h1>
100
- <div className='text-center py-16 text-gray-600 text-lg'>
101
- <div className='animate-pulse'>Loading product details...</div>
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='container-custom py-8'>
113
- <div className='text-center py-16 bg-red-50 text-red-600 text-lg rounded-xl'>
110
+ <main className='page-main'>
111
+ <div className='state-error'>
114
112
  {error || 'Product not found'}
115
- <div className='mt-4'>
116
- <Link to='/products' className='link font-semibold'>
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='container-custom py-8'>
131
- {/* Breadcrumbs */}
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='text-gray-900'>{product.title}</span>
142
+ <span className='breadcrumb-current'>{product.title}</span>
146
143
  </nav>
147
144
 
148
- {/* Product Details */}
149
- <div className='grid grid-cols-1 lg:grid-cols-2 gap-12 mb-16'>
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='max-w-full max-h-[500px] object-contain relative z-10'
155
+ className='product-detail-image-img'
161
156
  style={{ viewTransitionName: `product-image-${product.id}` }}
162
157
  />
163
158
  </div>
164
159
 
165
- {/* Product Info */}
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='text-4xl font-bold text-gray-900 leading-tight'>
170
- {product.title}
171
- </h1>
163
+ <h1 className='product-detail-title'>{product.title}</h1>
172
164
 
173
165
  {product.rating && (
174
- <div className='flex items-center gap-4'>
175
- <div className='flex items-center gap-2 text-base text-gray-600'>
176
- <span className='text-2xl'>⭐</span>
177
- <span className='font-semibold text-xl'>
178
- {product.rating.rate}
179
- </span>
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='text-4xl font-bold text-primary-600'>
186
- ${product.price.toFixed(2)}
187
- </div>
175
+ <div className='price-lg'>${product.price.toFixed(2)}</div>
188
176
 
189
- <p className='text-lg text-gray-700 leading-relaxed'>
177
+ <p className='product-detail-description'>
190
178
  {product.description}
191
179
  </p>
192
180
 
193
- <div className='flex gap-4 mt-4'>
181
+ <div className='product-actions'>
194
182
  <button
195
183
  type='button'
196
- className='btn-primary flex-1 disabled:opacity-50'
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='p-4 bg-gray-50 rounded-xl text-sm text-gray-600 space-y-2'>
213
- <div className='flex items-center gap-2'>
214
- <span className='text-green-600 font-bold'>✓</span>
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='flex items-center gap-2'>
218
- <span className='text-green-600 font-bold'>✓</span>
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='flex items-center gap-2'>
222
- <span className='text-green-600 font-bold'>✓</span>
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>