New /diy hub: curated resources for making your own gear, with cross-links into the rest of the app. - src/lib/diyGuides.ts: seed data — categories (Boards, Ramps & wooden obstacles, Concrete & DIY spots, Repairs & tuning, Tools & plans), resource cards (Open Source Skateboards / SK8CAD / Instructables / YouTube), and an actions block (find a Builder, find a DIY crew, map a DIY spot, sell builds, find a coach). - src/pages/DiyPage.tsx renders it (category chips + card grid + actions); external links go through sanitizeUrl and credit the source. - Route /diy (lazyWithRetry) + a nav-catalog entry (id diy) so it appears in the desktop "More" menu and the mobile burger; also linked from the site footer and the map links strip. Smoke test walks /diy.
210 lines
6.5 KiB
TypeScript
210 lines
6.5 KiB
TypeScript
/**
|
||
* Curated DIY resources — how to make your own boards, ramps and concrete spots.
|
||
*
|
||
* This is a **seed** list (vetted links + in-app actions), not user content, so
|
||
* it needs no moderation. Titles/blurbs are i18n keys (`diyUi.*`). To extend,
|
||
* just add entries here.
|
||
*
|
||
* ⚠️ Link out, never rehost: credit the source. External URLs are rendered
|
||
* through `sanitizeUrl` on the page.
|
||
*/
|
||
|
||
export type DiyCategoryId = 'boards' | 'ramps' | 'concrete' | 'repairs' | 'tools';
|
||
|
||
export interface DiyCategory {
|
||
id: DiyCategoryId;
|
||
titleKey: string;
|
||
emoji: string;
|
||
}
|
||
|
||
/** A resource card — either an external guide (`url`) or an in-app action (`to`). */
|
||
export interface DiyCard {
|
||
id: string;
|
||
/** Omit for the cross-link actions block. */
|
||
category?: DiyCategoryId;
|
||
titleKey: string;
|
||
blurbKey: string;
|
||
emoji: string;
|
||
/** Shown as a credit for external links. */
|
||
source?: string;
|
||
url?: string;
|
||
to?: string;
|
||
}
|
||
|
||
export const DIY_CATEGORIES: DiyCategory[] = [
|
||
{ id: 'boards', titleKey: 'diyUi.categories.boards', emoji: '🛹' },
|
||
{ id: 'ramps', titleKey: 'diyUi.categories.ramps', emoji: '🪚' },
|
||
{ id: 'concrete', titleKey: 'diyUi.categories.concrete', emoji: '🧱' },
|
||
{ id: 'repairs', titleKey: 'diyUi.categories.repairs', emoji: '🔧' },
|
||
{ id: 'tools', titleKey: 'diyUi.categories.tools', emoji: '📐' },
|
||
];
|
||
|
||
export const DIY_CARDS: DiyCard[] = [
|
||
// ── Boards ────────────────────────────────────────────────────────────────
|
||
{
|
||
id: 'oss-build',
|
||
category: 'boards',
|
||
emoji: '🛹',
|
||
titleKey: 'diyUi.cards.ossBuild.title',
|
||
blurbKey: 'diyUi.cards.ossBuild.blurb',
|
||
source: 'Open Source Skateboards',
|
||
url: 'https://opensourceskateboards.com',
|
||
},
|
||
{
|
||
id: 'sk8cad',
|
||
category: 'boards',
|
||
emoji: '🧊',
|
||
titleKey: 'diyUi.cards.sk8cad.title',
|
||
blurbKey: 'diyUi.cards.sk8cad.blurb',
|
||
source: 'Open Source Skateboards',
|
||
url: 'https://sk8cad.com',
|
||
},
|
||
{
|
||
id: 'deck-cost',
|
||
category: 'boards',
|
||
emoji: '💰',
|
||
titleKey: 'diyUi.cards.deckCost.title',
|
||
blurbKey: 'diyUi.cards.deckCost.blurb',
|
||
source: 'Open Source Skateboards',
|
||
url: 'https://opensourceskateboards.com',
|
||
},
|
||
|
||
// ── Ramps & wooden obstacles ─────────────────────────────────────────────
|
||
{
|
||
id: 'ledge-box',
|
||
category: 'ramps',
|
||
emoji: '📦',
|
||
titleKey: 'diyUi.cards.ledgeBox.title',
|
||
blurbKey: 'diyUi.cards.ledgeBox.blurb',
|
||
source: 'Instructables',
|
||
url: 'https://www.instructables.com/howto/skate+ledge/',
|
||
},
|
||
{
|
||
id: 'quarterpipe',
|
||
category: 'ramps',
|
||
emoji: '🌊',
|
||
titleKey: 'diyUi.cards.quarterpipe.title',
|
||
blurbKey: 'diyUi.cards.quarterpipe.blurb',
|
||
source: 'Instructables',
|
||
url: 'https://www.instructables.com/howto/skate+ramp/',
|
||
},
|
||
{
|
||
id: 'flatbar',
|
||
category: 'ramps',
|
||
emoji: '➖',
|
||
titleKey: 'diyUi.cards.flatbar.title',
|
||
blurbKey: 'diyUi.cards.flatbar.blurb',
|
||
source: 'YouTube',
|
||
url: 'https://www.youtube.com/results?search_query=how+to+build+a+skate+flatbar',
|
||
},
|
||
|
||
// ── Concrete & DIY spots ─────────────────────────────────────────────────
|
||
{
|
||
id: 'concrete-basics',
|
||
category: 'concrete',
|
||
emoji: '🧱',
|
||
titleKey: 'diyUi.cards.concreteBasics.title',
|
||
blurbKey: 'diyUi.cards.concreteBasics.blurb',
|
||
source: 'Instructables',
|
||
url: 'https://www.instructables.com/howto/concrete+skatepark/',
|
||
},
|
||
{
|
||
id: 'coping',
|
||
category: 'concrete',
|
||
emoji: '🛞',
|
||
titleKey: 'diyUi.cards.coping.title',
|
||
blurbKey: 'diyUi.cards.coping.blurb',
|
||
source: 'YouTube',
|
||
url: 'https://www.youtube.com/results?search_query=diy+skatepark+coping',
|
||
},
|
||
{
|
||
id: 'map-spot',
|
||
category: 'concrete',
|
||
emoji: '📍',
|
||
titleKey: 'diyUi.cards.mapSpot.title',
|
||
blurbKey: 'diyUi.cards.mapSpot.blurb',
|
||
to: '/create-spot',
|
||
},
|
||
|
||
// ── Repairs & tuning ─────────────────────────────────────────────────────
|
||
{
|
||
id: 'regrip',
|
||
category: 'repairs',
|
||
emoji: '🩹',
|
||
titleKey: 'diyUi.cards.regrip.title',
|
||
blurbKey: 'diyUi.cards.regrip.blurb',
|
||
source: 'YouTube',
|
||
url: 'https://www.youtube.com/results?search_query=how+to+regrip+a+skateboard',
|
||
},
|
||
{
|
||
id: 'tune',
|
||
category: 'repairs',
|
||
emoji: '🔩',
|
||
titleKey: 'diyUi.cards.tune.title',
|
||
blurbKey: 'diyUi.cards.tune.blurb',
|
||
source: 'YouTube',
|
||
url: 'https://www.youtube.com/results?search_query=clean+skateboard+bearings+bushings',
|
||
},
|
||
|
||
// ── Tools & plans ────────────────────────────────────────────────────────
|
||
{
|
||
id: 'print-molds',
|
||
category: 'tools',
|
||
emoji: '🖨️',
|
||
titleKey: 'diyUi.cards.printMolds.title',
|
||
blurbKey: 'diyUi.cards.printMolds.blurb',
|
||
source: 'Printables',
|
||
url: 'https://www.printables.com/search/models?q=skateboard+mold',
|
||
},
|
||
{
|
||
id: 'sk8cad-tools',
|
||
category: 'tools',
|
||
emoji: '📐',
|
||
titleKey: 'diyUi.cards.sk8cadTools.title',
|
||
blurbKey: 'diyUi.cards.sk8cadTools.blurb',
|
||
source: 'Open Source Skateboards',
|
||
url: 'https://sk8cad.com',
|
||
},
|
||
];
|
||
|
||
/**
|
||
* Cross-links into the rest of the app — the point of the section: turn a guide
|
||
* into a person, a place, or a sale.
|
||
*/
|
||
export const DIY_ACTIONS: DiyCard[] = [
|
||
{
|
||
id: 'find-builder',
|
||
emoji: '🧱',
|
||
titleKey: 'diyUi.actions.findBuilder.title',
|
||
blurbKey: 'diyUi.actions.findBuilder.blurb',
|
||
to: '/lab?craft=building',
|
||
},
|
||
{
|
||
id: 'find-crew',
|
||
emoji: '👥',
|
||
titleKey: 'diyUi.actions.findCrew.title',
|
||
blurbKey: 'diyUi.actions.findCrew.blurb',
|
||
to: '/crews',
|
||
},
|
||
{
|
||
id: 'map-spot-action',
|
||
emoji: '📍',
|
||
titleKey: 'diyUi.actions.mapSpot.title',
|
||
blurbKey: 'diyUi.actions.mapSpot.blurb',
|
||
to: '/create-spot',
|
||
},
|
||
{
|
||
id: 'sell-builds',
|
||
emoji: '🛒',
|
||
titleKey: 'diyUi.actions.sellBuilds.title',
|
||
blurbKey: 'diyUi.actions.sellBuilds.blurb',
|
||
to: '/create-listing',
|
||
},
|
||
{
|
||
id: 'find-coach',
|
||
emoji: '🎓',
|
||
titleKey: 'diyUi.actions.findCoach.title',
|
||
blurbKey: 'diyUi.actions.findCoach.blurb',
|
||
to: '/lab?craft=coaching',
|
||
},
|
||
];
|