Add silent servo category
This commit is contained in:
@@ -230,7 +230,7 @@ select:focus, input:focus, textarea:focus { border-color: var(--blue); box-shado
|
|||||||
.section-heading > p { max-width: 480px; margin: 0; color: #6e7a8e; line-height: 1.8; font-size: 13px; }
|
.section-heading > p { max-width: 480px; margin: 0; color: #6e7a8e; line-height: 1.8; font-size: 13px; }
|
||||||
.catalog-summary {
|
.catalog-summary {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(7, 1fr);
|
grid-template-columns: repeat(8, 1fr);
|
||||||
gap: 9px;
|
gap: 9px;
|
||||||
margin-bottom: 22px;
|
margin-bottom: 22px;
|
||||||
}
|
}
|
||||||
@@ -451,6 +451,7 @@ footer > span { color: #9aa4b2; font-size: 10px; }
|
|||||||
.hero-copy { max-width: 760px; }
|
.hero-copy { max-width: 760px; }
|
||||||
.selector-shell { width: min(100%, 720px); }
|
.selector-shell { width: min(100%, 720px); }
|
||||||
.how-section { gap: 45px; }
|
.how-section { gap: 45px; }
|
||||||
|
.catalog-summary { grid-template-columns: repeat(4, 1fr); }
|
||||||
.catalog-grid { grid-template-columns: repeat(2, 1fr); }
|
.catalog-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
.catalog-image-button { height: 260px; }
|
.catalog-image-button { height: 260px; }
|
||||||
}
|
}
|
||||||
@@ -475,7 +476,6 @@ footer > span { color: #9aa4b2; font-size: 10px; }
|
|||||||
.capability-strip div:nth-child(2) { border-right: 0; }
|
.capability-strip div:nth-child(2) { border-right: 0; }
|
||||||
.section-heading { align-items: flex-start; flex-direction: column; gap: 18px; }
|
.section-heading { align-items: flex-start; flex-direction: column; gap: 18px; }
|
||||||
.catalog-summary { grid-template-columns: repeat(2, 1fr); }
|
.catalog-summary { grid-template-columns: repeat(2, 1fr); }
|
||||||
.catalog-summary button:last-child { grid-column: 1 / -1; }
|
|
||||||
.catalog-toolbar { top: 64px; }
|
.catalog-toolbar { top: 64px; }
|
||||||
.catalog-grid { grid-template-columns: 1fr; gap: 15px; }
|
.catalog-grid { grid-template-columns: 1fr; gap: 15px; }
|
||||||
.catalog-image-button { height: 280px; }
|
.catalog-image-button { height: 280px; }
|
||||||
|
|||||||
32
app/page.tsx
32
app/page.tsx
@@ -39,6 +39,7 @@ const CATALOG_CATEGORIES = [
|
|||||||
"全金属舵机",
|
"全金属舵机",
|
||||||
"大扭矩舵机",
|
"大扭矩舵机",
|
||||||
"积木舵机",
|
"积木舵机",
|
||||||
|
"静音舵机",
|
||||||
"标准齿轮箱",
|
"标准齿轮箱",
|
||||||
"翻盖电机",
|
"翻盖电机",
|
||||||
];
|
];
|
||||||
@@ -63,6 +64,8 @@ function getFeaturedSpecs(product: CatalogProduct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SERVO_CATEGORIES = ["标准舵机", "异形舵机", "全金属舵机", "大扭矩舵机", "积木舵机"];
|
const SERVO_CATEGORIES = ["标准舵机", "异形舵机", "全金属舵机", "大扭矩舵机", "积木舵机"];
|
||||||
|
const SILENT_SERVO_CATEGORY = "静音舵机";
|
||||||
|
const SELECTOR_CATEGORIES = [...SERVO_CATEGORIES, SILENT_SERVO_CATEGORY];
|
||||||
const TORQUE_MIN = 0.09;
|
const TORQUE_MIN = 0.09;
|
||||||
const TORQUE_MAX = 920;
|
const TORQUE_MAX = 920;
|
||||||
const TORQUE_PRESETS = [0.1, 1, 5, 20, 100, 300, 920];
|
const TORQUE_PRESETS = [0.1, 1, 5, 20, 100, 300, 920];
|
||||||
@@ -80,6 +83,17 @@ function parseNumbers(value = "") {
|
|||||||
return (value.match(/\d+(?:\.\d+)?/g) ?? []).map(Number);
|
return (value.match(/\d+(?:\.\d+)?/g) ?? []).map(Number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSilentServo(product: CatalogProduct) {
|
||||||
|
return SERVO_CATEGORIES.includes(product.category) &&
|
||||||
|
[product.name, ...Object.values(product.specs)].join(" ").includes("静音");
|
||||||
|
}
|
||||||
|
|
||||||
|
const SILENT_SERVO_COUNT = CATALOG_PRODUCTS.filter(isSilentServo).length;
|
||||||
|
|
||||||
|
function getCategoryCount(category: string) {
|
||||||
|
return category === SILENT_SERVO_CATEGORY ? SILENT_SERVO_COUNT : CATALOG_COUNTS[category];
|
||||||
|
}
|
||||||
|
|
||||||
function inferWeight(product: CatalogProduct) {
|
function inferWeight(product: CatalogProduct) {
|
||||||
const listedWeight = parseNumbers(product.specs["重量"])[0];
|
const listedWeight = parseNumbers(product.specs["重量"])[0];
|
||||||
if (Number.isFinite(listedWeight)) return listedWeight;
|
if (Number.isFinite(listedWeight)) return listedWeight;
|
||||||
@@ -152,6 +166,7 @@ const SELECTOR_PRODUCTS = CATALOG_PRODUCTS.filter((product) =>
|
|||||||
voltageMin: voltageValues[0] ?? ratedVoltage,
|
voltageMin: voltageValues[0] ?? ratedVoltage,
|
||||||
voltageMax: voltageValues.at(-1) ?? ratedVoltage,
|
voltageMax: voltageValues.at(-1) ?? ratedVoltage,
|
||||||
weight: inferWeight(product),
|
weight: inferWeight(product),
|
||||||
|
isSilent: isSilentServo(product),
|
||||||
gear: classifyGear(product.specs["齿轮材质"]),
|
gear: classifyGear(product.specs["齿轮材质"]),
|
||||||
angle: product.specs["可操作角度"] ?? product.specs["操作角度范围"] ?? "",
|
angle: product.specs["可操作角度"] ?? product.specs["操作角度范围"] ?? "",
|
||||||
control,
|
control,
|
||||||
@@ -186,8 +201,9 @@ function getMatches(requirements: Requirements) {
|
|||||||
return SELECTOR_PRODUCTS.map((product) => {
|
return SELECTOR_PRODUCTS.map((product) => {
|
||||||
let score = 20;
|
let score = 20;
|
||||||
const reasons: string[] = [];
|
const reasons: string[] = [];
|
||||||
const categoryOk =
|
const categoryOk = requirements.category === "全部舵机" ||
|
||||||
requirements.category === "全部舵机" || requirements.category === product.category;
|
requirements.category === product.category ||
|
||||||
|
(requirements.category === SILENT_SERVO_CATEGORY && product.isSilent);
|
||||||
const torqueOk = product.torque >= requirements.torque;
|
const torqueOk = product.torque >= requirements.torque;
|
||||||
const voltageOk = requirements.voltage === product.ratedVoltage;
|
const voltageOk = requirements.voltage === product.ratedVoltage;
|
||||||
const weightOk =
|
const weightOk =
|
||||||
@@ -275,7 +291,9 @@ export default function Home() {
|
|||||||
const query = catalogQuery.trim().toLowerCase();
|
const query = catalogQuery.trim().toLowerCase();
|
||||||
return CATALOG_PRODUCTS.filter((product) => {
|
return CATALOG_PRODUCTS.filter((product) => {
|
||||||
const matchesCategory =
|
const matchesCategory =
|
||||||
catalogCategory === "全部产品" || product.category === catalogCategory;
|
catalogCategory === "全部产品" ||
|
||||||
|
product.category === catalogCategory ||
|
||||||
|
(catalogCategory === SILENT_SERVO_CATEGORY && isSilentServo(product));
|
||||||
if (!matchesCategory) return false;
|
if (!matchesCategory) return false;
|
||||||
if (!query) return true;
|
if (!query) return true;
|
||||||
const haystack = [
|
const haystack = [
|
||||||
@@ -427,9 +445,9 @@ export default function Home() {
|
|||||||
onChange={(event) => update("category", event.target.value)}
|
onChange={(event) => update("category", event.target.value)}
|
||||||
>
|
>
|
||||||
<option value="全部舵机">全部舵机(243款)</option>
|
<option value="全部舵机">全部舵机(243款)</option>
|
||||||
{SERVO_CATEGORIES.map((category) => (
|
{SELECTOR_CATEGORIES.map((category) => (
|
||||||
<option key={category} value={category}>
|
<option key={category} value={category}>
|
||||||
{category}({CATALOG_COUNTS[category]}款)
|
{category}({getCategoryCount(category)}款)
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
@@ -742,7 +760,7 @@ export default function Home() {
|
|||||||
<p className="eyebrow"><span /> 官方产品目录 · 2026.06</p>
|
<p className="eyebrow"><span /> 官方产品目录 · 2026.06</p>
|
||||||
<h2>完整收录280个产品型号</h2>
|
<h2>完整收录280个产品型号</h2>
|
||||||
</div>
|
</div>
|
||||||
<p>覆盖标准、异形、全金属、大扭矩和积木舵机,以及标准齿轮箱与翻盖电机。参数来自高徳乐官方产品型号表。</p>
|
<p>覆盖标准、异形、静音、全金属、大扭矩和积木舵机,以及标准齿轮箱与翻盖电机。参数来自高徳乐官方产品型号表。</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="catalog-summary" aria-label="产品分类统计">
|
<div className="catalog-summary" aria-label="产品分类统计">
|
||||||
@@ -756,7 +774,7 @@ export default function Home() {
|
|||||||
setCatalogLimit(24);
|
setCatalogLimit(24);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<strong>{CATALOG_COUNTS[category]}</strong>
|
<strong>{getCategoryCount(category)}</strong>
|
||||||
<span>{category}</span>
|
<span>{category}</span>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user