Improve catalog detail modal with size images
This commit is contained in:
@@ -24,6 +24,34 @@ const SOURCE_MAIN_IMAGES = {
|
||||
"313": "/catalog-products/source-main/313-main.png",
|
||||
} as const;
|
||||
|
||||
const SOURCE_SIZE_IMAGES = {
|
||||
"1004": "/catalog-products/size-reference/1004-size.png",
|
||||
"258": "/catalog-products/size-reference/258-size.jpg",
|
||||
"259": "/catalog-products/size-reference/259-size.jpg",
|
||||
"266": "/catalog-products/size-reference/266-size.jpg",
|
||||
"267": "/catalog-products/size-reference/267-size.jpg",
|
||||
"268": "/catalog-products/size-reference/268-size.jpg",
|
||||
"270": "/catalog-products/size-reference/270-size.jpg",
|
||||
"271": "/catalog-products/size-reference/271-size.jpg",
|
||||
"272": "/catalog-products/size-reference/272-size.jpg",
|
||||
"273": "/catalog-products/size-reference/273-size.jpg",
|
||||
"274": "/catalog-products/size-reference/274-size.jpg",
|
||||
"275": "/catalog-products/size-reference/275-size.jpg",
|
||||
"276": "/catalog-products/size-reference/276-size.jpg",
|
||||
"308": "/catalog-products/size-reference/308-size.png",
|
||||
"309": "/catalog-products/size-reference/309-size.png",
|
||||
"310": "/catalog-products/size-reference/310-size.png",
|
||||
"311": "/catalog-products/size-reference/311-size.png",
|
||||
"313": "/catalog-products/size-reference/313-size.png",
|
||||
"563": "/catalog-products/size-reference/563-size.png",
|
||||
"565": "/catalog-products/size-reference/565-size.png",
|
||||
"566": "/catalog-products/size-reference/566-size.png",
|
||||
"567": "/catalog-products/size-reference/567-size.png",
|
||||
"568": "/catalog-products/size-reference/568-size.png",
|
||||
"572": "/catalog-products/size-reference/572-size.png",
|
||||
} as const;
|
||||
|
||||
type ProductImageSet = Record<string, string>;
|
||||
type SourceImageKey = keyof typeof SOURCE_MAIN_IMAGES;
|
||||
|
||||
function hasWeight(name: string, grams: string) {
|
||||
@@ -37,57 +65,73 @@ function getGearSeries(name: string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function getSmallServoImage(name: string): string | null {
|
||||
if (hasWeight(name, "1\\.7")) return SOURCE_MAIN_IMAGES["1004"];
|
||||
function getSmallServoImage(name: string, images: ProductImageSet): string | null {
|
||||
if (hasWeight(name, "1\\.7")) return images["1004"];
|
||||
|
||||
const gearSeries = getGearSeries(name);
|
||||
if (hasWeight(name, "2") && gearSeries === "plastic") return SOURCE_MAIN_IMAGES["272"];
|
||||
if (hasWeight(name, "3\\.7") && gearSeries === "plastic") return SOURCE_MAIN_IMAGES["271"];
|
||||
if (hasWeight(name, "2") && gearSeries === "plastic") return images["272"];
|
||||
if (hasWeight(name, "3\\.7") && gearSeries === "plastic") return images["271"];
|
||||
|
||||
if (hasWeight(name, "9")) {
|
||||
if (gearSeries === "metal") return SOURCE_MAIN_IMAGES["266"];
|
||||
if (gearSeries === "semi") return SOURCE_MAIN_IMAGES["259"];
|
||||
if (gearSeries === "plastic") return SOURCE_MAIN_IMAGES["258"];
|
||||
if (gearSeries === "metal") return images["266"];
|
||||
if (gearSeries === "semi") return images["259"];
|
||||
if (gearSeries === "plastic") return images["258"];
|
||||
}
|
||||
|
||||
if (hasWeight(name, "17")) {
|
||||
if (gearSeries === "metal") return SOURCE_MAIN_IMAGES["274"];
|
||||
if (gearSeries === "plastic") return SOURCE_MAIN_IMAGES["273"];
|
||||
if (gearSeries === "metal") return images["274"];
|
||||
if (gearSeries === "plastic") return images["273"];
|
||||
}
|
||||
|
||||
if (hasWeight(name, "25")) {
|
||||
if (gearSeries === "metal") return SOURCE_MAIN_IMAGES["276"];
|
||||
if (gearSeries === "plastic") return SOURCE_MAIN_IMAGES["275"];
|
||||
if (gearSeries === "metal") return images["276"];
|
||||
if (gearSeries === "plastic") return images["275"];
|
||||
}
|
||||
|
||||
if (hasWeight(name, "37")) {
|
||||
if (gearSeries === "metal") return SOURCE_MAIN_IMAGES["270"];
|
||||
if (gearSeries === "semi") return SOURCE_MAIN_IMAGES["268"];
|
||||
if (gearSeries === "plastic") return SOURCE_MAIN_IMAGES["267"];
|
||||
if (gearSeries === "metal") return images["270"];
|
||||
if (gearSeries === "semi") return images["268"];
|
||||
if (gearSeries === "plastic") return images["267"];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getBrickServoImage(name: string): string | null {
|
||||
if (name.includes("3x3x3")) return SOURCE_MAIN_IMAGES["311"];
|
||||
if (name.includes("3x3x7")) return SOURCE_MAIN_IMAGES["310"];
|
||||
if (name.includes("3x7x5")) return SOURCE_MAIN_IMAGES["309"];
|
||||
if (name.includes("6x6x5")) return SOURCE_MAIN_IMAGES["308"];
|
||||
if (name.includes("11x5x4")) return SOURCE_MAIN_IMAGES["313"];
|
||||
function getBrickServoImage(name: string, images: ProductImageSet): string | null {
|
||||
if (name.includes("3x3x3")) return images["311"];
|
||||
if (name.includes("3x3x7")) return images["310"];
|
||||
if (name.includes("3x7x5")) return images["309"];
|
||||
if (name.includes("6x6x5")) return images["308"];
|
||||
if (name.includes("11x5x4")) return images["313"];
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getCatalogProductImage(product: CatalogProduct) {
|
||||
if (product.category === "积木舵机") {
|
||||
return getBrickServoImage(product.name) ?? product.image;
|
||||
return getBrickServoImage(product.name, SOURCE_MAIN_IMAGES) ?? product.image;
|
||||
}
|
||||
|
||||
if (product.category === "标准舵机" || product.category === "异形舵机") {
|
||||
return getSmallServoImage(product.name) ?? product.image;
|
||||
return getSmallServoImage(product.name, SOURCE_MAIN_IMAGES) ?? product.image;
|
||||
}
|
||||
|
||||
return product.image;
|
||||
}
|
||||
|
||||
export function getCatalogProductDimensionImage(product: CatalogProduct) {
|
||||
if (product.category === "舵盘配件") {
|
||||
return SOURCE_SIZE_IMAGES[product.id.replace("shop-", "")] ?? null;
|
||||
}
|
||||
|
||||
if (product.category === "积木舵机") {
|
||||
return getBrickServoImage(product.name, SOURCE_SIZE_IMAGES);
|
||||
}
|
||||
|
||||
if (product.category === "标准舵机" || product.category === "异形舵机") {
|
||||
return getSmallServoImage(product.name, SOURCE_SIZE_IMAGES);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export const CATALOG_SOURCE_IMAGE_KEYS: SourceImageKey[] = Object.keys(SOURCE_MAIN_IMAGES) as SourceImageKey[];
|
||||
|
||||
@@ -458,12 +458,23 @@ select:focus, input:focus, textarea:focus { border-color: var(--blue); box-shado
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
}
|
||||
.catalog-modal-product { display: grid; grid-template-columns: 360px 1fr; align-items: center; gap: 34px; }
|
||||
.catalog-modal-image { min-height: 240px; display: flex; align-items: center; justify-content: center; border-radius: 13px; overflow: hidden; background: #f2f5fa; }
|
||||
.catalog-modal-image img { display: block; max-width: 100%; max-height: min(55vh, 460px); width: auto; height: auto; object-fit: contain; mix-blend-mode: multiply; }
|
||||
.catalog-modal-product { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(245px, .75fr); align-items: stretch; gap: 25px; }
|
||||
.catalog-modal-visuals { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
||||
.catalog-modal-visual-card { min-width: 0; display: grid; grid-template-rows: auto minmax(0, 1fr); gap: 7px; }
|
||||
.catalog-modal-visual-label { color: #687791; font-size: 10px; font-weight: 800; letter-spacing: .04em; }
|
||||
.catalog-modal-image, .catalog-modal-size-image { min-height: 250px; display: flex; align-items: center; justify-content: center; border: 1px solid #e1e7f0; border-radius: 13px; overflow: hidden; background: #f5f7fb; }
|
||||
.catalog-modal-image img, .catalog-modal-size-image img { display: block; max-width: 100%; max-height: min(43vh, 390px); width: auto; height: auto; object-fit: contain; mix-blend-mode: multiply; }
|
||||
.catalog-modal-size-image { background: #fbfcfe; }
|
||||
.catalog-modal-size-empty { display: grid; gap: 8px; padding: 18px; text-align: center; }
|
||||
.catalog-modal-size-empty strong { color: #6b7890; font-size: 14px; line-height: 1.5; }
|
||||
.catalog-modal-size-empty small { color: #9aa5b5; font-size: 9px; line-height: 1.5; }
|
||||
.catalog-modal-product-info { display: flex; flex-direction: column; justify-content: center; min-width: 0; padding: 10px 3px; }
|
||||
.catalog-modal-product h2 { margin: 4px 0 10px; font-size: 27px; line-height: 1.3; letter-spacing: -.025em; }
|
||||
.catalog-modal-product code { color: #5d6b81; font-size: 11px; }
|
||||
.catalog-source-note { color: #96a0af; font-size: 9px; }
|
||||
.catalog-modal-highlight { display: grid; gap: 5px; margin-top: 26px; padding: 13px 14px; border: 1px solid #dbe5f5; border-radius: 11px; background: #f5f8fd; }
|
||||
.catalog-modal-highlight span { color: #8a96a9; font-size: 9px; }
|
||||
.catalog-modal-highlight strong { color: var(--ink); font-size: 12px; line-height: 1.55; }
|
||||
.catalog-spec-table { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin-top: 25px; overflow: hidden; border: 1px solid #e0e5ed; border-radius: 11px; background: #e0e5ed; }
|
||||
.catalog-spec-table div { min-height: 48px; padding: 10px 12px; display: grid; align-content: center; gap: 4px; background: white; }
|
||||
.catalog-spec-table span { color: #8b96a7; font-size: 9px; }
|
||||
|
||||
54
app/page.tsx
54
app/page.tsx
@@ -7,7 +7,7 @@ import {
|
||||
type CatalogProduct,
|
||||
} from "./catalog-data";
|
||||
import { STEERING_WHEEL_ACCESSORIES } from "./catalog-accessories";
|
||||
import { getCatalogProductImage } from "./catalog-image-map";
|
||||
import { getCatalogProductDimensionImage, getCatalogProductImage } from "./catalog-image-map";
|
||||
|
||||
const CATALOG_PRODUCTS = [...RAW_CATALOG_PRODUCTS, ...STEERING_WHEEL_ACCESSORIES].map((product) => ({
|
||||
...product,
|
||||
@@ -89,6 +89,16 @@ function getFeaturedSpecs(product: CatalogProduct) {
|
||||
.map((label) => [label, product.specs[label]] as const);
|
||||
}
|
||||
|
||||
function getProductDimensionSummary(product: CatalogProduct) {
|
||||
const directSize = product.specs["产品尺寸"] ?? product.specs["外形尺寸"];
|
||||
if (directSize) return directSize;
|
||||
|
||||
const dimensions = ["长(mm)", "宽(mm)", "高(mm)"]
|
||||
.map((label) => product.specs[label])
|
||||
.filter(Boolean);
|
||||
return dimensions.length > 0 ? dimensions.join(" × ") : "尺寸图待补充";
|
||||
}
|
||||
|
||||
const SERVO_CATEGORIES = ["标准舵机", "异形舵机", "全金属舵机", "大扭矩舵机", "积木舵机"];
|
||||
const SILENT_SERVO_CATEGORY = "静音舵机";
|
||||
const CUSTOM_SERVO_CATEGORY = "非标准舵机定制";
|
||||
@@ -387,6 +397,12 @@ export default function Home() {
|
||||
requirements.annualVolume === "50000件以上" ||
|
||||
Number(requirements.firstOrderQuantity) >= 1000 ||
|
||||
requirements.application === "工业设备";
|
||||
const selectedCatalogDimensionImage = selectedCatalogProduct
|
||||
? getCatalogProductDimensionImage(selectedCatalogProduct)
|
||||
: null;
|
||||
const selectedCatalogDimensionSummary = selectedCatalogProduct
|
||||
? getProductDimensionSummary(selectedCatalogProduct)
|
||||
: "";
|
||||
|
||||
function startSelection() {
|
||||
setStage(1);
|
||||
@@ -1088,20 +1104,42 @@ export default function Home() {
|
||||
aria-label="关闭产品详情"
|
||||
>×</button>
|
||||
<div className="catalog-modal-product">
|
||||
<div className="catalog-modal-image">
|
||||
{selectedCatalogProduct.image ? (
|
||||
<img src={selectedCatalogProduct.image} alt={selectedCatalogProduct.name} />
|
||||
) : (
|
||||
<span className="catalog-placeholder">GAUDELOT</span>
|
||||
)}
|
||||
<div className="catalog-modal-visuals">
|
||||
<div className="catalog-modal-visual-card">
|
||||
<span className="catalog-modal-visual-label">产品主图</span>
|
||||
<div className="catalog-modal-image">
|
||||
{selectedCatalogProduct.image ? (
|
||||
<img src={selectedCatalogProduct.image} alt={selectedCatalogProduct.name} />
|
||||
) : (
|
||||
<span className="catalog-placeholder">GAUDELOT</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="catalog-modal-visual-card">
|
||||
<span className="catalog-modal-visual-label">产品尺寸</span>
|
||||
<div className="catalog-modal-size-image">
|
||||
{selectedCatalogDimensionImage ? (
|
||||
<img src={selectedCatalogDimensionImage} alt={`${selectedCatalogProduct.name} 产品尺寸`} />
|
||||
) : (
|
||||
<div className="catalog-modal-size-empty">
|
||||
<strong>{selectedCatalogDimensionSummary}</strong>
|
||||
<small>当前目录未提供对应尺寸图</small>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="catalog-modal-product-info">
|
||||
<p className="step-kicker">{selectedCatalogProduct.category}</p>
|
||||
<h2 id="catalog-modal-title">{selectedCatalogProduct.name}</h2>
|
||||
<code>{selectedCatalogProduct.code}</code>
|
||||
<p className="catalog-source-note">
|
||||
{selectedCatalogProduct.page > 0 ? `官方产品目录第 ${selectedCatalogProduct.page} 页` : "商城产品资料 · 舵盘配件"}
|
||||
</p>
|
||||
<div className="catalog-modal-highlight">
|
||||
<span>产品尺寸</span>
|
||||
<strong>{selectedCatalogDimensionSummary}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="catalog-spec-table">
|
||||
|
||||
Reference in New Issue
Block a user