b307919bf7
Replace the single JSX file with a Next.js project, shared catalog and recommendation modules, backend API routes, file-backed persistence, Ollama recommendation endpoint, and picture-layer bike composition. Add initial aligned component assets for existing BSU layers plus RockShox and Maxxis products.
54 lines
13 KiB
TypeScript
54 lines
13 KiB
TypeScript
import type { FrameProduct, ForkProduct, ShockProduct, TireProduct } from "./types";
|
|
|
|
const manufacturer = (title: string, url = "") => ({ title, url, kind: "manufacturer" as const });
|
|
const community = (title: string, url = "") => ({ title, url, kind: "community" as const });
|
|
const placeholder = { title: "Needs verified setup research before production use", url: "", kind: "placeholder" as const };
|
|
|
|
export const frames: FrameProduct[] = [
|
|
{ id: "transition-sentinel", category: "frame", brand: "Transition", model: "Sentinel", travel: 140, headAngle: 64, geometry: "enduro", bestFor: ["enduro", "trail"], description: "Aggressive trail and light enduro frame.", sources: [manufacturer("Transition Sentinel geometry"), placeholder] },
|
|
{ id: "transition-scout", category: "frame", brand: "Transition", model: "Scout", travel: 130, headAngle: 65.5, geometry: "trail", bestFor: ["trail", "xc"], description: "Playful short-travel trail frame.", imagePath: "/images/frame/transition/scout.png", sources: [manufacturer("Transition Scout geometry"), community("Existing BSU image asset")] },
|
|
{ id: "norco-sight-vlt", category: "frame", brand: "Norco", model: "Sight VLT", travel: 140, headAngle: 64, geometry: "enduro", bestFor: ["enduro", "trail"], description: "Full-power e-MTB enduro platform.", sources: [manufacturer("Norco Sight VLT geometry"), placeholder] },
|
|
{ id: "canyon-spectral", category: "frame", brand: "Canyon", model: "Spectral", travel: 140, headAngle: 64.5, geometry: "trail", bestFor: ["trail", "enduro"], description: "Balanced all-mountain platform.", sources: [manufacturer("Canyon Spectral geometry"), placeholder] },
|
|
{ id: "last-coal", category: "frame", brand: "Last", model: "Coal", travel: 150, headAngle: 63.5, geometry: "enduro", bestFor: ["enduro"], description: "Long, slack enduro frame.", sources: [manufacturer("LAST Coal geometry"), placeholder] },
|
|
{ id: "evil-the-calling", category: "frame", brand: "Evil", model: "The Calling", travel: 140, headAngle: 65, geometry: "trail", bestFor: ["trail", "enduro"], description: "Responsive technical trail frame.", sources: [manufacturer("Evil The Calling geometry"), placeholder] },
|
|
];
|
|
|
|
export const forks: ForkProduct[] = [
|
|
{ id: "manitou-mezzer", category: "fork", brand: "Manitou", model: "Mezzer", travels: [140, 150, 160], damper: "MC2 / IRT", psi: { lt: [60, 72], md: [70, 84], hv: [82, 100] }, sag: { xc: 20, trail: 25, enduro: 27 }, rebound: { lt: 14, md: 11, hv: 9 }, lsc: { lt: 5, md: 7, hv: 9 }, hsc: { lt: 3, md: 4, hv: 5 }, tokens: { lt: 0, md: 1, hv: 2 }, notes: "Very tunable, supple air spring with strong mid-stroke support.", imagePath: "/images/fork/manitou/mezzer.png", sources: [manufacturer("Manitou Mezzer setup guide"), community("Pinkbike and MTBR Mezzer setup discussions")] },
|
|
{ id: "fox-38", category: "fork", brand: "Fox", model: "38 Factory", travels: [160, 170, 180], damper: "GRIP2", psi: { lt: [65, 78], md: [76, 92], hv: [88, 110] }, sag: { xc: 20, trail: 25, enduro: 28 }, rebound: { lt: 13, md: 11, hv: 8 }, lsc: { lt: 6, md: 8, hv: 10 }, hsc: { lt: 3, md: 4, hv: 5 }, tokens: { lt: 0, md: 1, hv: 2 }, notes: "Stiff enduro chassis for hard charging.", sources: [manufacturer("Fox 38 tuning guide"), placeholder] },
|
|
{ id: "fox-36", category: "fork", brand: "Fox", model: "36 Factory", travels: [140, 150, 160], damper: "GRIP2", psi: { lt: [60, 74], md: [70, 86], hv: [82, 102] }, sag: { xc: 20, trail: 25, enduro: 27 }, rebound: { lt: 13, md: 11, hv: 9 }, lsc: { lt: 5, md: 7, hv: 9 }, hsc: { lt: 2, md: 3, hv: 4 }, tokens: { lt: 0, md: 1, hv: 2 }, notes: "All-mountain default with good stiffness-to-weight balance.", sources: [manufacturer("Fox 36 tuning guide"), placeholder] },
|
|
{ id: "fox-34", category: "fork", brand: "Fox", model: "34 Factory", travels: [120, 130, 140], damper: "GRIP2", psi: { lt: [55, 68], md: [64, 80], hv: [76, 94] }, sag: { xc: 20, trail: 22, enduro: 25 }, rebound: { lt: 12, md: 10, hv: 8 }, lsc: { lt: 4, md: 6, hv: 8 }, hsc: { lt: 2, md: 3, hv: 4 }, tokens: { lt: 0, md: 0, hv: 1 }, notes: "Light trail and downcountry option.", sources: [manufacturer("Fox 34 tuning guide"), placeholder] },
|
|
{ id: "rockshox-zeb", category: "fork", brand: "RockShox", model: "ZEB Ultimate", travels: [150, 160, 170, 180], damper: "Charger 3 / DebonAir+", psi: { lt: [62, 76], md: [72, 88], hv: [84, 106] }, sag: { xc: 20, trail: 25, enduro: 28 }, rebound: { lt: 14, md: 12, hv: 10 }, lsc: { lt: 5, md: 7, hv: 9 }, hsc: { lt: 3, md: 4, hv: 5 }, tokens: { lt: 0, md: 1, hv: 2 }, notes: "Plush big-bike fork for enduro terrain.", imagePath: "/images/fork/rockshox/zeb.png", sources: [manufacturer("RockShox ZEB product page", "https://www.sram.com/en/rockshox/models/fs-zeb-ult-b1"), placeholder] },
|
|
{ id: "rockshox-lyrik", category: "fork", brand: "RockShox", model: "Lyrik Ultimate", travels: [140, 150, 160], damper: "Charger 3 / DebonAir+", psi: { lt: [58, 72], md: [68, 83], hv: [80, 100] }, sag: { xc: 20, trail: 25, enduro: 28 }, rebound: { lt: 14, md: 12, hv: 10 }, lsc: { lt: 4, md: 6, hv: 8 }, hsc: { lt: 2, md: 3, hv: 4 }, tokens: { lt: 0, md: 1, hv: 2 }, notes: "Strong trail/enduro all-rounder.", imagePath: "/images/fork/rockshox/lyrik.png", sources: [manufacturer("RockShox Lyrik product page", "https://www.sram.com/en/rockshox/models/fs-lyrk-ult-e1"), placeholder] },
|
|
{ id: "rockshox-pike", category: "fork", brand: "RockShox", model: "Pike Ultimate", travels: [120, 130, 140], damper: "Charger 3 / DebonAir+", psi: { lt: [55, 68], md: [64, 78], hv: [76, 93] }, sag: { xc: 20, trail: 22, enduro: 25 }, rebound: { lt: 13, md: 11, hv: 9 }, lsc: { lt: 3, md: 5, hv: 7 }, hsc: { lt: 2, md: 3, hv: 3 }, tokens: { lt: 0, md: 0, hv: 1 }, notes: "Light and precise trail fork.", imagePath: "/images/fork/rockshox/pike.png", sources: [manufacturer("RockShox Pike product page", "https://www.sram.com/en/rockshox/models/fs-pike-ult-c2"), placeholder] },
|
|
];
|
|
|
|
export const shocks: ShockProduct[] = [
|
|
{ id: "fox-x2", category: "shock", brand: "Fox", model: "X2 Factory", type: "air", psi: { lt: [140, 158], md: [158, 185], hv: [185, 212] }, sag: { xc: 25, trail: 28, enduro: 31 }, rebound: { lt: 12, md: 10, hv: 8 }, lsc: { lt: 5, md: 7, hv: 9 }, hsc: { lt: 3, md: 4, hv: 5 }, tokens: { lt: 0, md: 1, hv: 2 }, notes: "Highly adjustable air shock for technical speed.", sources: [manufacturer("Fox X2 tuning guide"), placeholder] },
|
|
{ id: "fox-float-x", category: "shock", brand: "Fox", model: "Float X Factory", type: "air", psi: { lt: [132, 152], md: [152, 178], hv: [178, 205] }, sag: { xc: 25, trail: 28, enduro: 30 }, rebound: { lt: 11, md: 9, hv: 7 }, lsc: { lt: 5, md: 7, hv: 9 }, tokens: { lt: 0, md: 1, hv: 2 }, notes: "Simpler trail/enduro air shock.", sources: [manufacturer("Fox Float X tuning guide"), placeholder] },
|
|
{ id: "rockshox-vivid-air-ultimate", category: "shock", brand: "RockShox", model: "Vivid Air Ultimate", type: "air", psi: { lt: [128, 150], md: [150, 178], hv: [178, 208] }, sag: { xc: 25, trail: 28, enduro: 32 }, rebound: { lt: 13, md: 11, hv: 9 }, lsc: { lt: 4, md: 6, hv: 8 }, hsc: { lt: 3, md: 4, hv: 5 }, tokens: { lt: 0, md: 1, hv: 2 }, notes: "Supple high-volume air shock.", imagePath: "/images/shock/rockshox/vivid_air_ultimate.png", sources: [manufacturer("RockShox Vivid setup guide"), community("Existing BSU image asset")] },
|
|
{ id: "rockshox-super-deluxe-ultimate", category: "shock", brand: "RockShox", model: "Super Deluxe Ultimate", type: "air", psi: { lt: [135, 158], md: [158, 184], hv: [184, 212] }, sag: { xc: 25, trail: 28, enduro: 31 }, rebound: { lt: 12, md: 10, hv: 8 }, lsc: { lt: 3, md: 5, hv: 7 }, hsc: { lt: 3, md: 4, hv: 5 }, tokens: { lt: 0, md: 1, hv: 2 }, notes: "Reliable trail/enduro OEM workhorse.", imagePath: "/images/shock/rockshox/super_deluxe_ultimate.png", sources: [manufacturer("RockShox Super Deluxe product page", "https://www.sram.com/en/rockshox/models/rs-sdlx-ult-d1"), placeholder] },
|
|
{ id: "rockshox-super-deluxe-coil-ultimate", category: "shock", brand: "RockShox", model: "Super Deluxe Coil Ultimate", type: "coil", sag: { xc: 30, trail: 33, enduro: 36 }, rebound: { lt: 12, md: 10, hv: 8 }, lsc: { lt: 4, md: 6, hv: 8 }, hsc: { lt: 3, md: 4, hv: 5 }, spring: { lt: "350-400 lb/in", md: "400-500 lb/in", hv: "500-600 lb/in" }, notes: "Coil feel and heat consistency for descending-focused builds.", imagePath: "/images/shock/rockshox/super_deluxe_coil_ultimate.png", sources: [manufacturer("RockShox Super Deluxe Coil product page", "https://www.sram.com/en/rockshox/models/rs-sdlc-ult-b1"), placeholder] },
|
|
];
|
|
|
|
const tireSources = [manufacturer("Brand tire pressure guidance"), community("Common community starting pressures")];
|
|
const maxxisSources = [manufacturer("Maxxis product images", "https://www.maxxis.com/catalog/tire/"), manufacturer("Brand tire pressure guidance"), community("Common community starting pressures")];
|
|
export const tires: TireProduct[] = [
|
|
{ id: "maxxis-assegai-front", category: "tire", position: "front", brand: "Maxxis", model: "Assegai", width: 2.5, grip: 10, rolling: 3, bestFor: ["enduro", "wet"], psi: { lt: [17, 22], md: [21, 26], hv: [25, 30] }, notes: "Maximum front grip.", imagePath: "/images/tire/front/maxxis/assegai.png", sources: maxxisSources },
|
|
{ id: "maxxis-dissector-front", category: "tire", position: "front", brand: "Maxxis", model: "Dissector", width: 2.4, grip: 7, rolling: 7, bestFor: ["trail", "xc", "dry"], psi: { lt: [20, 24], md: [23, 28], hv: [27, 32] }, notes: "Fast dry front option.", imagePath: "/images/tire/front/maxxis/dissector.png", sources: maxxisSources },
|
|
{ id: "maxxis-minion-front", category: "tire", position: "front", brand: "Maxxis", model: "Minion DHF", width: 2.5, grip: 9, rolling: 5, bestFor: ["enduro", "trail"], psi: { lt: [18, 23], md: [22, 27], hv: [25, 30] }, notes: "Predictable benchmark front.", imagePath: "/images/tire/front/maxxis/minion.png", sources: maxxisSources },
|
|
{ id: "schwalbe-magic-mary-front", category: "tire", position: "front", brand: "Schwalbe", model: "Magic Mary", width: 2.4, grip: 10, rolling: 3, bestFor: ["enduro", "wet"], psi: { lt: [16, 21], md: [20, 25], hv: [24, 29] }, notes: "Wet and soft-condition front.", sources: tireSources },
|
|
{ id: "schwalbe-albert-radial-front", category: "tire", position: "front", brand: "Schwalbe", model: "Albert Radial", width: 2.35, grip: 8, rolling: 6, bestFor: ["trail", "enduro"], psi: { lt: [19, 24], md: [22, 27], hv: [26, 30] }, notes: "Supple radial casing.", imagePath: "/images/tire/front/schwalbe/albert.png", sources: tireSources },
|
|
{ id: "specialized-eliminator-front", category: "tire", position: "front", brand: "Specialized", model: "Eliminator", width: 2.3, grip: 7, rolling: 7, bestFor: ["trail", "xc"], psi: { lt: [21, 26], md: [24, 29], hv: [28, 33] }, notes: "Efficient front option.", sources: tireSources },
|
|
{ id: "specialized-butcher-front", category: "tire", position: "front", brand: "Specialized", model: "Butcher", width: 2.3, grip: 8, rolling: 6, bestFor: ["enduro", "trail"], psi: { lt: [20, 25], md: [23, 28], hv: [26, 31] }, notes: "Aggressive daily front.", sources: tireSources },
|
|
{ id: "maxxis-assegai-rear", category: "tire", position: "rear", brand: "Maxxis", model: "Assegai", width: 2.5, grip: 9, rolling: 4, bestFor: ["enduro"], psi: { lt: [22, 27], md: [25, 30], hv: [29, 34] }, notes: "Very grippy but slow rear.", imagePath: "/images/tire/rear/maxxis/assegai.png", sources: maxxisSources },
|
|
{ id: "maxxis-dissector-rear", category: "tire", position: "rear", brand: "Maxxis", model: "Dissector", width: 2.4, grip: 7, rolling: 8, bestFor: ["trail", "xc", "dry"], psi: { lt: [22, 27], md: [26, 31], hv: [30, 35] }, notes: "Fast rolling rear.", imagePath: "/images/tire/rear/maxxis/dissector.png", sources: maxxisSources },
|
|
{ id: "maxxis-minion-rear", category: "tire", position: "rear", brand: "Maxxis", model: "Minion DHR II", width: 2.4, grip: 8, rolling: 6, bestFor: ["enduro", "trail"], psi: { lt: [21, 26], md: [24, 29], hv: [28, 33] }, notes: "Balanced rear traction.", imagePath: "/images/tire/rear/maxxis/minion.png", sources: maxxisSources },
|
|
{ id: "schwalbe-magic-mary-rear", category: "tire", position: "rear", brand: "Schwalbe", model: "Magic Mary", width: 2.4, grip: 9, rolling: 3, bestFor: ["enduro", "wet"], psi: { lt: [20, 25], md: [23, 28], hv: [27, 32] }, notes: "Wet rear traction.", sources: tireSources },
|
|
{ id: "schwalbe-albert-radial-rear", category: "tire", position: "rear", brand: "Schwalbe", model: "Albert Radial", width: 2.35, grip: 7, rolling: 7, bestFor: ["trail", "enduro"], psi: { lt: [21, 26], md: [24, 29], hv: [27, 32] }, notes: "Forgiving all-conditions rear.", imagePath: "/images/tire/rear/schwalbe/albert.png", sources: tireSources },
|
|
{ id: "specialized-eliminator-rear", category: "tire", position: "rear", brand: "Specialized", model: "Eliminator", width: 2.3, grip: 7, rolling: 8, bestFor: ["trail", "xc"], psi: { lt: [23, 28], md: [26, 31], hv: [30, 35] }, notes: "Fast trail rear.", sources: tireSources },
|
|
{ id: "specialized-butcher-rear", category: "tire", position: "rear", brand: "Specialized", model: "Butcher", width: 2.3, grip: 8, rolling: 7, bestFor: ["enduro", "trail"], psi: { lt: [21, 26], md: [24, 29], hv: [27, 33] }, notes: "Balanced rear option.", sources: tireSources },
|
|
];
|
|
|
|
export const catalog = { frames, forks, shocks, tires };
|