Add g and kg catalog filters
This commit is contained in:
@@ -313,6 +313,12 @@ select:focus, input:focus, textarea:focus { border-color: var(--blue); box-shado
|
||||
}
|
||||
.category-pills button.active { border-color: var(--blue); color: white; background: var(--blue); }
|
||||
.category-pills button.feature-filter:not(.active) { border-color: #f1bf92; color: #a75a19; background: #fff9f3; }
|
||||
.catalog-scale-filter { display: grid; grid-template-columns: minmax(240px, 330px) 1fr; align-items: end; gap: 14px; margin-top: 13px; padding-top: 13px; border-top: 1px solid #e7ebf1; }
|
||||
.catalog-scale-filter label { display: grid; gap: 6px; }
|
||||
.catalog-scale-filter label > span { color: #68758a; font-size: 10px; font-weight: 700; }
|
||||
.catalog-scale-filter select { width: 100%; height: 42px; padding: 0 12px; }
|
||||
.catalog-scale-filter p { margin: 0 0 4px; color: #8792a3; font-size: 9px; line-height: 1.55; }
|
||||
.catalog-scale-filter p strong { color: #657187; }
|
||||
.catalog-result-count { margin: 11px 2px 0; color: #8792a3; font-size: 10px; }
|
||||
.catalog-result-count strong { color: var(--blue); font-size: 12px; }
|
||||
.catalog-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
|
||||
@@ -496,6 +502,7 @@ footer > span { color: #9aa4b2; font-size: 10px; }
|
||||
.catalog-summary { grid-template-columns: repeat(2, 1fr); }
|
||||
.catalog-summary button:last-child { grid-column: 1 / -1; }
|
||||
.catalog-toolbar { top: 64px; }
|
||||
.catalog-scale-filter { grid-template-columns: 1fr; align-items: stretch; }
|
||||
.catalog-grid { grid-template-columns: 1fr; gap: 15px; }
|
||||
.catalog-image-button { height: 280px; }
|
||||
.catalog-card-body { padding: 15px; }
|
||||
|
||||
73
app/page.tsx
73
app/page.tsx
@@ -94,6 +94,46 @@ function getCategoryCount(category: string) {
|
||||
return category === SILENT_SERVO_CATEGORY ? SILENT_SERVO_COUNT : CATALOG_COUNTS[category];
|
||||
}
|
||||
|
||||
type ProductScale = {
|
||||
key: string;
|
||||
label: string;
|
||||
unit: "g" | "kg";
|
||||
value: number;
|
||||
};
|
||||
|
||||
function getProductScale(product: CatalogProduct): ProductScale | null {
|
||||
const kilogramMatch = product.name.match(/(\d+(?:\.\d+)?)\s*(?:kg|千克)/i);
|
||||
if (kilogramMatch) {
|
||||
const value = Number(kilogramMatch[1]);
|
||||
return { key: `kg:${value}`, label: `${value}kg`, unit: "kg", value };
|
||||
}
|
||||
|
||||
const gramMatch = product.name.match(/(\d+(?:\.\d+)?)\s*(?:g|克)/i);
|
||||
if (gramMatch) {
|
||||
const value = Number(gramMatch[1]);
|
||||
return { key: `g:${value}`, label: `${value}g`, unit: "g", value };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const PRODUCT_SCALE_OPTIONS = [...CATALOG_PRODUCTS.reduce((options, product) => {
|
||||
const scale = getProductScale(product);
|
||||
if (!scale) return options;
|
||||
const current = options.get(scale.key);
|
||||
options.set(scale.key, { ...scale, count: (current?.count ?? 0) + 1 });
|
||||
return options;
|
||||
}, new Map<string, ProductScale & { count: number }>()).values()].sort(
|
||||
(a, b) => (a.unit === b.unit ? a.value - b.value : a.unit === "g" ? -1 : 1),
|
||||
);
|
||||
|
||||
const GRAM_SCALE_OPTIONS = PRODUCT_SCALE_OPTIONS.filter((option) => option.unit === "g");
|
||||
const KILOGRAM_SCALE_OPTIONS = PRODUCT_SCALE_OPTIONS.filter((option) => option.unit === "kg");
|
||||
const UNMARKED_SCALE_COUNT = CATALOG_PRODUCTS.length - PRODUCT_SCALE_OPTIONS.reduce(
|
||||
(total, option) => total + option.count,
|
||||
0,
|
||||
);
|
||||
|
||||
function inferWeight(product: CatalogProduct) {
|
||||
const listedWeight = parseNumbers(product.specs["重量"])[0];
|
||||
if (Number.isFinite(listedWeight)) return listedWeight;
|
||||
@@ -280,6 +320,7 @@ export default function Home() {
|
||||
const [leadId, setLeadId] = useState("");
|
||||
const [catalogQuery, setCatalogQuery] = useState("");
|
||||
const [catalogCategory, setCatalogCategory] = useState("全部产品");
|
||||
const [catalogScale, setCatalogScale] = useState("all");
|
||||
const [catalogLimit, setCatalogLimit] = useState(24);
|
||||
const [selectedCatalogProduct, setSelectedCatalogProduct] = useState<CatalogProduct | null>(null);
|
||||
|
||||
@@ -290,6 +331,8 @@ export default function Home() {
|
||||
const filteredCatalog = useMemo(() => {
|
||||
const query = catalogQuery.trim().toLowerCase();
|
||||
return CATALOG_PRODUCTS.filter((product) => {
|
||||
const productScale = getProductScale(product)?.key ?? "unmarked";
|
||||
if (catalogScale !== "all" && productScale !== catalogScale) return false;
|
||||
const matchesCategory =
|
||||
catalogCategory === "全部产品" ||
|
||||
product.category === catalogCategory ||
|
||||
@@ -307,7 +350,7 @@ export default function Home() {
|
||||
.toLowerCase();
|
||||
return haystack.includes(query);
|
||||
});
|
||||
}, [catalogCategory, catalogQuery]);
|
||||
}, [catalogCategory, catalogQuery, catalogScale]);
|
||||
const visibleCatalog = filteredCatalog.slice(0, catalogLimit);
|
||||
const needsEngineer =
|
||||
!top?.coreCompatible ||
|
||||
@@ -894,6 +937,32 @@ export default function Home() {
|
||||
>{category === SILENT_SERVO_CATEGORY ? `${category} · ${SILENT_SERVO_COUNT}` : category}</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="catalog-scale-filter">
|
||||
<label>
|
||||
<span>按 g / kg 型号规格筛选</span>
|
||||
<select
|
||||
value={catalogScale}
|
||||
onChange={(event) => {
|
||||
setCatalogScale(event.target.value);
|
||||
setCatalogLimit(24);
|
||||
}}
|
||||
>
|
||||
<option value="all">全部 g / kg 规格</option>
|
||||
<optgroup label="克重系列(g / 克)">
|
||||
{GRAM_SCALE_OPTIONS.map((option) => (
|
||||
<option key={option.key} value={option.key}>{option.label}({option.count}款)</option>
|
||||
))}
|
||||
</optgroup>
|
||||
<optgroup label="千克扭矩等级(kg / 千克)">
|
||||
{KILOGRAM_SCALE_OPTIONS.map((option) => (
|
||||
<option key={option.key} value={option.key}>{option.label}({option.count}款)</option>
|
||||
))}
|
||||
</optgroup>
|
||||
<option value="unmarked">其他未标注 g/kg({UNMARKED_SCALE_COUNT}款)</option>
|
||||
</select>
|
||||
</label>
|
||||
<p><strong>说明:</strong>g/克表示产品克重系列;kg/Kg通常表示舵机扭矩等级,并非产品自身重量。</p>
|
||||
</div>
|
||||
<p className="catalog-result-count">
|
||||
找到 <strong>{filteredCatalog.length}</strong> 个型号
|
||||
</p>
|
||||
@@ -936,7 +1005,7 @@ export default function Home() {
|
||||
<div className="catalog-empty">
|
||||
<strong>没有找到匹配型号</strong>
|
||||
<p>可以尝试减少关键词,或切换到“全部产品”。</p>
|
||||
<button type="button" onClick={() => { setCatalogQuery(""); setCatalogCategory("全部产品"); }}>
|
||||
<button type="button" onClick={() => { setCatalogQuery(""); setCatalogCategory("全部产品"); setCatalogScale("all"); }}>
|
||||
清除筛选
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user