Align catalog with Bambu Lab product line, add conditional filters and admin sidebar
All checks were successful
Deploy / deploy (push) Successful in 2m24s
All checks were successful
Deploy / deploy (push) Successful in 2m24s
- Add master catalog (bambuLabCatalog.ts) as single source of truth for materials, finishes, colors, and refill/spool availability - Fix incorrect finish-per-material mappings (remove PLA: 85A/90A/95A HF/FR/GF/HF, add ASA: Basic/CF/Aero, fix PETG/PC) - Implement cascading filters on public site: material restricts finish, finish restricts color - Add AdminSidebar component across all admin pages - Redirect /upadaj to /dashboard when already authenticated - Update color hex mappings and tests to match official Bambu Lab names
This commit is contained in:
407
src/data/bambuLabCatalog.ts
Normal file
407
src/data/bambuLabCatalog.ts
Normal file
@@ -0,0 +1,407 @@
|
||||
// Master Bambu Lab product catalog — single source of truth
|
||||
// Material → Finish → Color[] with refill/spool availability
|
||||
|
||||
export interface CatalogColorEntry {
|
||||
name: string;
|
||||
refill: boolean;
|
||||
spool: boolean;
|
||||
}
|
||||
|
||||
export interface CatalogFinish {
|
||||
colors: CatalogColorEntry[];
|
||||
}
|
||||
|
||||
export type BambuLabCatalog = Record<string, Record<string, CatalogFinish>>;
|
||||
|
||||
export const BAMBU_LAB_CATALOG: BambuLabCatalog = {
|
||||
PLA: {
|
||||
Basic: {
|
||||
colors: [
|
||||
{ name: 'Jade White', refill: true, spool: true },
|
||||
{ name: 'Black', refill: true, spool: true },
|
||||
{ name: 'Red', refill: true, spool: true },
|
||||
{ name: 'Bambu Green', refill: true, spool: true },
|
||||
{ name: 'Blue', refill: true, spool: true },
|
||||
{ name: 'Scarlet Red', refill: true, spool: true },
|
||||
{ name: 'Lemon Yellow', refill: true, spool: true },
|
||||
{ name: 'Cyan', refill: true, spool: true },
|
||||
{ name: 'Sakura Pink', refill: true, spool: true },
|
||||
{ name: 'Cobalt Blue', refill: true, spool: true },
|
||||
{ name: 'Mistletoe Green', refill: true, spool: true },
|
||||
{ name: 'Dark Red', refill: true, spool: true },
|
||||
{ name: 'Hot Pink', refill: true, spool: true },
|
||||
{ name: 'Lavender', refill: true, spool: true },
|
||||
{ name: 'Light Blue', refill: true, spool: true },
|
||||
{ name: 'Sky Blue', refill: true, spool: true },
|
||||
{ name: 'Sunflower Yellow', refill: true, spool: true },
|
||||
{ name: 'Pumpkin Orange', refill: true, spool: true },
|
||||
{ name: 'Lime', refill: true, spool: true },
|
||||
{ name: 'Blue Grey', refill: true, spool: false },
|
||||
{ name: 'Beige', refill: true, spool: false },
|
||||
{ name: 'Light Gray', refill: true, spool: false },
|
||||
{ name: 'Yellow', refill: true, spool: false },
|
||||
{ name: 'Orange', refill: true, spool: false },
|
||||
{ name: 'Gold', refill: true, spool: false },
|
||||
{ name: 'Bright Green', refill: true, spool: false },
|
||||
{ name: 'Pink', refill: true, spool: false },
|
||||
{ name: 'Magenta', refill: true, spool: false },
|
||||
{ name: 'Maroon Red', refill: true, spool: false },
|
||||
{ name: 'Purple', refill: true, spool: false },
|
||||
{ name: 'Turquoise', refill: true, spool: false },
|
||||
{ name: 'Brown', refill: true, spool: false },
|
||||
{ name: 'Bronze', refill: true, spool: false },
|
||||
{ name: 'Silver', refill: true, spool: false },
|
||||
{ name: 'Dark Gray', refill: true, spool: false },
|
||||
],
|
||||
},
|
||||
'Basic Gradient': {
|
||||
colors: [
|
||||
{ name: 'Neon City', refill: false, spool: true },
|
||||
{ name: 'Midnight Blaze', refill: false, spool: true },
|
||||
{ name: 'South Beach', refill: false, spool: true },
|
||||
{ name: 'Arctic Whisper', refill: false, spool: true },
|
||||
{ name: 'Cotton Candy Cloud', refill: false, spool: true },
|
||||
{ name: 'Ocean to Meadow', refill: false, spool: true },
|
||||
{ name: 'Solar Breeze', refill: false, spool: true },
|
||||
{ name: 'Velvet Eclipse', refill: false, spool: true },
|
||||
{ name: 'Dawn Radiance', refill: false, spool: true },
|
||||
{ name: 'Dusk Glare', refill: false, spool: true },
|
||||
{ name: 'Blueberry Bubblegum', refill: false, spool: true },
|
||||
{ name: 'Blue Hawaii', refill: false, spool: true },
|
||||
{ name: 'Gilded Rose', refill: false, spool: true },
|
||||
{ name: 'Pink Citrus', refill: false, spool: true },
|
||||
{ name: 'Mint Lime', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
Matte: {
|
||||
colors: [
|
||||
{ name: 'Matte Ivory White', refill: true, spool: false },
|
||||
{ name: 'Matte Charcoal', refill: true, spool: false },
|
||||
{ name: 'Matte Scarlet Red', refill: true, spool: false },
|
||||
{ name: 'Matte Marine Blue', refill: true, spool: false },
|
||||
{ name: 'Matte Mandarin Orange', refill: true, spool: false },
|
||||
{ name: 'Matte Ash Gray', refill: true, spool: false },
|
||||
{ name: 'Matte Desert Tan', refill: true, spool: false },
|
||||
{ name: 'Matte Nardo Gray', refill: true, spool: false },
|
||||
{ name: 'Matte Apple Green', refill: true, spool: false },
|
||||
{ name: 'Matte Bone White', refill: true, spool: false },
|
||||
{ name: 'Matte Caramel', refill: true, spool: false },
|
||||
{ name: 'Matte Dark Blue', refill: true, spool: false },
|
||||
{ name: 'Matte Dark Brown', refill: true, spool: false },
|
||||
{ name: 'Matte Dark Chocolate', refill: true, spool: false },
|
||||
{ name: 'Matte Dark Green', refill: true, spool: false },
|
||||
{ name: 'Matte Dark Red', refill: true, spool: false },
|
||||
{ name: 'Matte Grass Green', refill: true, spool: false },
|
||||
{ name: 'Matte Ice Blue', refill: true, spool: false },
|
||||
{ name: 'Matte Lemon Yellow', refill: true, spool: false },
|
||||
{ name: 'Matte Lilac Purple', refill: true, spool: false },
|
||||
{ name: 'Matte Plum', refill: true, spool: false },
|
||||
{ name: 'Matte Sakura Pink', refill: true, spool: false },
|
||||
{ name: 'Matte Sky Blue', refill: true, spool: false },
|
||||
{ name: 'Matte Latte Brown', refill: true, spool: false },
|
||||
{ name: 'Matte Terracotta', refill: true, spool: false },
|
||||
],
|
||||
},
|
||||
'Silk+': {
|
||||
colors: [
|
||||
{ name: 'Candy Green', refill: false, spool: true },
|
||||
{ name: 'Candy Red', refill: false, spool: true },
|
||||
{ name: 'Mint', refill: false, spool: true },
|
||||
{ name: 'Titan Gray', refill: false, spool: true },
|
||||
{ name: 'Rose Gold', refill: false, spool: true },
|
||||
{ name: 'Champagne', refill: false, spool: true },
|
||||
{ name: 'Baby Blue', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
'Silk Multi-Color': {
|
||||
colors: [
|
||||
{ name: 'Silk Aurora Purple', refill: false, spool: true },
|
||||
{ name: 'Silk Phantom Blue', refill: false, spool: true },
|
||||
{ name: 'Silk Mystic Magenta', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
Metal: {
|
||||
colors: [
|
||||
{ name: 'Iron Gray Metallic', refill: false, spool: true },
|
||||
{ name: 'Iridium Gold Metallic', refill: false, spool: true },
|
||||
{ name: 'Cobalt Blue Metallic', refill: false, spool: true },
|
||||
{ name: 'Copper Brown Metallic', refill: false, spool: true },
|
||||
{ name: 'Oxide Green Metallic', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
Sparkle: {
|
||||
colors: [
|
||||
{ name: 'Onyx Black Sparkle', refill: false, spool: true },
|
||||
{ name: 'Classic Gold Sparkle', refill: false, spool: true },
|
||||
{ name: 'Crimson Red Sparkle', refill: false, spool: true },
|
||||
{ name: 'Royal Purple Sparkle', refill: false, spool: true },
|
||||
{ name: 'Slate Gray Sparkle', refill: false, spool: true },
|
||||
{ name: 'Alpine Green Sparkle', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
Galaxy: {
|
||||
colors: [
|
||||
{ name: 'Nebulae', refill: true, spool: true },
|
||||
],
|
||||
},
|
||||
Marble: {
|
||||
colors: [
|
||||
{ name: 'White Marble', refill: false, spool: true },
|
||||
{ name: 'Red Granite', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
Glow: {
|
||||
colors: [
|
||||
{ name: 'Glow Blue', refill: false, spool: true },
|
||||
{ name: 'Glow Green', refill: false, spool: true },
|
||||
{ name: 'Glow Orange', refill: false, spool: true },
|
||||
{ name: 'Glow Pink', refill: false, spool: true },
|
||||
{ name: 'Glow Yellow', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
Wood: {
|
||||
colors: [
|
||||
{ name: 'Ochre Yellow', refill: false, spool: true },
|
||||
{ name: 'White Oak', refill: false, spool: true },
|
||||
{ name: 'Clay Brown', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
'Tough+': {
|
||||
colors: [
|
||||
{ name: 'Black', refill: true, spool: true },
|
||||
],
|
||||
},
|
||||
CF: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
{ name: 'Burgundy Red', refill: false, spool: true },
|
||||
{ name: 'Jeans Blue', refill: false, spool: true },
|
||||
{ name: 'Lava Gray', refill: false, spool: true },
|
||||
{ name: 'Matcha Green', refill: false, spool: true },
|
||||
{ name: 'Royal Blue', refill: false, spool: true },
|
||||
{ name: 'Iris Purple', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
PETG: {
|
||||
HF: {
|
||||
colors: [
|
||||
{ name: 'Jade White', refill: true, spool: true },
|
||||
{ name: 'Black', refill: true, spool: true },
|
||||
{ name: 'Red', refill: true, spool: true },
|
||||
{ name: 'Green', refill: true, spool: true },
|
||||
{ name: 'Blue', refill: true, spool: true },
|
||||
{ name: 'Gray', refill: true, spool: true },
|
||||
{ name: 'Orange', refill: true, spool: true },
|
||||
{ name: 'Cream', refill: true, spool: true },
|
||||
{ name: 'Forest Green', refill: true, spool: true },
|
||||
{ name: 'Lake Blue', refill: true, spool: true },
|
||||
{ name: 'Lime Green', refill: true, spool: true },
|
||||
{ name: 'Peanut Brown', refill: true, spool: true },
|
||||
],
|
||||
},
|
||||
Translucent: {
|
||||
colors: [
|
||||
{ name: 'Clear', refill: false, spool: true },
|
||||
{ name: 'Translucent Gray', refill: false, spool: true },
|
||||
{ name: 'Translucent Brown', refill: false, spool: true },
|
||||
{ name: 'Translucent Purple', refill: false, spool: true },
|
||||
{ name: 'Translucent Orange', refill: false, spool: true },
|
||||
{ name: 'Translucent Olive', refill: false, spool: true },
|
||||
{ name: 'Translucent Pink', refill: false, spool: true },
|
||||
{ name: 'Translucent Light Blue', refill: false, spool: true },
|
||||
{ name: 'Translucent Tea', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
CF: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
{ name: 'Brick Red', refill: false, spool: true },
|
||||
{ name: 'Indigo Blue', refill: false, spool: true },
|
||||
{ name: 'Malachite Green', refill: false, spool: true },
|
||||
{ name: 'Titan Gray', refill: false, spool: true },
|
||||
{ name: 'Violet Purple', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
ABS: {
|
||||
Basic: {
|
||||
colors: [
|
||||
{ name: 'ABS Azure', refill: true, spool: true },
|
||||
{ name: 'ABS Black', refill: true, spool: true },
|
||||
{ name: 'ABS Blue', refill: true, spool: true },
|
||||
{ name: 'ABS Olive', refill: true, spool: true },
|
||||
{ name: 'ABS Tangerine Yellow', refill: true, spool: true },
|
||||
{ name: 'ABS Navy Blue', refill: true, spool: true },
|
||||
{ name: 'ABS Orange', refill: true, spool: true },
|
||||
{ name: 'ABS Bambu Green', refill: true, spool: true },
|
||||
{ name: 'ABS Red', refill: true, spool: true },
|
||||
{ name: 'ABS White', refill: true, spool: true },
|
||||
{ name: 'ABS Silver', refill: true, spool: true },
|
||||
],
|
||||
},
|
||||
GF: {
|
||||
colors: [
|
||||
{ name: 'ABS GF Yellow', refill: true, spool: false },
|
||||
{ name: 'ABS GF Orange', refill: true, spool: false },
|
||||
],
|
||||
},
|
||||
},
|
||||
TPU: {
|
||||
'85A': {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
{ name: 'White', refill: false, spool: true },
|
||||
{ name: 'Flesh', refill: false, spool: true },
|
||||
{ name: 'Light Cyan', refill: false, spool: true },
|
||||
{ name: 'Neon Orange', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
'90A': {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
{ name: 'White', refill: false, spool: true },
|
||||
{ name: 'Red', refill: false, spool: true },
|
||||
{ name: 'Blaze', refill: false, spool: true },
|
||||
{ name: 'Frozen', refill: false, spool: true },
|
||||
{ name: 'Grape Jelly', refill: false, spool: true },
|
||||
{ name: 'Crystal Blue', refill: false, spool: true },
|
||||
{ name: 'Quicksilver', refill: false, spool: true },
|
||||
{ name: 'Cocoa Brown', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
'95A HF': {
|
||||
colors: [
|
||||
{ name: 'Black', refill: true, spool: false },
|
||||
{ name: 'White', refill: true, spool: false },
|
||||
{ name: 'TPU 95A HF Yellow', refill: true, spool: false },
|
||||
],
|
||||
},
|
||||
},
|
||||
ASA: {
|
||||
Basic: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: true, spool: true },
|
||||
{ name: 'Blue', refill: true, spool: true },
|
||||
{ name: 'Gray', refill: true, spool: true },
|
||||
{ name: 'Green', refill: true, spool: true },
|
||||
{ name: 'Red', refill: true, spool: true },
|
||||
{ name: 'White', refill: true, spool: true },
|
||||
],
|
||||
},
|
||||
CF: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
Aero: {
|
||||
colors: [
|
||||
{ name: 'White', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
PA6: {
|
||||
GF: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
PAHT: {
|
||||
CF: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
PC: {
|
||||
Basic: {
|
||||
colors: [
|
||||
{ name: 'Clear Black', refill: false, spool: true },
|
||||
{ name: 'Transparent', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
FR: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
PET: {
|
||||
CF: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
PPA: {
|
||||
CF: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
PPS: {
|
||||
CF: {
|
||||
colors: [
|
||||
{ name: 'Black', refill: false, spool: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
|
||||
export function getMaterialOptions(): string[] {
|
||||
return Object.keys(BAMBU_LAB_CATALOG).sort();
|
||||
}
|
||||
|
||||
export function getFinishesForMaterial(material: string): string[] {
|
||||
const materialData = BAMBU_LAB_CATALOG[material];
|
||||
if (!materialData) return [];
|
||||
return Object.keys(materialData).sort();
|
||||
}
|
||||
|
||||
export function getAllFinishes(): string[] {
|
||||
const finishes = new Set<string>();
|
||||
for (const material of Object.values(BAMBU_LAB_CATALOG)) {
|
||||
for (const finish of Object.keys(material)) {
|
||||
finishes.add(finish);
|
||||
}
|
||||
}
|
||||
return [...finishes].sort();
|
||||
}
|
||||
|
||||
export function getColorsForMaterialFinish(material: string, finish: string): CatalogColorEntry[] {
|
||||
return BAMBU_LAB_CATALOG[material]?.[finish]?.colors ?? [];
|
||||
}
|
||||
|
||||
export function getColorsForMaterial(material: string): CatalogColorEntry[] {
|
||||
const materialData = BAMBU_LAB_CATALOG[material];
|
||||
if (!materialData) return [];
|
||||
const seen = new Set<string>();
|
||||
const result: CatalogColorEntry[] = [];
|
||||
for (const finish of Object.values(materialData)) {
|
||||
for (const color of finish.colors) {
|
||||
if (!seen.has(color.name)) {
|
||||
seen.add(color.name);
|
||||
result.push(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
|
||||
export function catalogIsSpoolOnly(material: string, finish: string, color: string): boolean {
|
||||
const entry = BAMBU_LAB_CATALOG[material]?.[finish]?.colors.find(c => c.name === color);
|
||||
return entry ? (entry.spool && !entry.refill) : false;
|
||||
}
|
||||
|
||||
export function catalogIsRefillOnly(material: string, finish: string, color: string): boolean {
|
||||
const entry = BAMBU_LAB_CATALOG[material]?.[finish]?.colors.find(c => c.name === color);
|
||||
return entry ? (entry.refill && !entry.spool) : false;
|
||||
}
|
||||
|
||||
export function getFinishOptionsForType(type: string): string[] {
|
||||
return getFinishesForMaterial(type);
|
||||
}
|
||||
Reference in New Issue
Block a user