Refine responsive catalog and branding
This commit is contained in:
118
app/page.tsx
118
app/page.tsx
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { FormEvent, useMemo, useState } from "react";
|
||||
import { FormEvent, useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
CATALOG_COUNTS,
|
||||
CATALOG_PRODUCTS as RAW_CATALOG_PRODUCTS,
|
||||
@@ -352,6 +352,7 @@ function Metric({ label, value }: { label: string; value: string }) {
|
||||
|
||||
export default function Home() {
|
||||
const [stage, setStage] = useState(0);
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
const [requirements, setRequirements] = useState(DEFAULT_REQUIREMENTS);
|
||||
const [showSampleForm, setShowSampleForm] = useState(false);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
@@ -360,9 +361,14 @@ export default function Home() {
|
||||
const [catalogCategory, setCatalogCategory] = useState("全部产品");
|
||||
const [catalogScale, setCatalogScale] = useState("all");
|
||||
const [catalogLimit, setCatalogLimit] = useState(24);
|
||||
const [catalogToolbarCompact, setCatalogToolbarCompact] = useState(false);
|
||||
const [catalogToolbarFiltersOpen, setCatalogToolbarFiltersOpen] = useState(false);
|
||||
const [catalogToolbarHidden, setCatalogToolbarHidden] = useState(false);
|
||||
const [precisionGearQuery, setPrecisionGearQuery] = useState("");
|
||||
const [precisionGearCategory, setPrecisionGearCategory] = useState("全部子类");
|
||||
const [precisionGearLimit, setPrecisionGearLimit] = useState(24);
|
||||
const [precisionGearToolbarCompact, setPrecisionGearToolbarCompact] = useState(false);
|
||||
const [precisionGearFiltersOpen, setPrecisionGearFiltersOpen] = useState(false);
|
||||
const [selectedCatalogProduct, setSelectedCatalogProduct] = useState<CatalogProduct | null>(null);
|
||||
const [catalogVisualMode, setCatalogVisualMode] = useState<CatalogVisualMode>("main");
|
||||
|
||||
@@ -419,12 +425,41 @@ export default function Home() {
|
||||
? getCatalogProductDimensionImage(selectedCatalogProduct)
|
||||
: null;
|
||||
|
||||
useEffect(() => {
|
||||
function updateCatalogToolbarState() {
|
||||
const toolbar = document.querySelector(".catalog-toolbar");
|
||||
const shouldCompact = window.innerWidth <= 720 && Boolean(toolbar) && toolbar.getBoundingClientRect().top <= 72 && window.scrollY > 0;
|
||||
setCatalogToolbarCompact((current) => (current === shouldCompact ? current : shouldCompact));
|
||||
if (!shouldCompact) setCatalogToolbarFiltersOpen(false);
|
||||
|
||||
const precisionHeading = document.querySelector(".precision-gear-catalog-heading");
|
||||
const shouldHideCatalogToolbar = window.innerWidth <= 720 && Boolean(precisionHeading) && precisionHeading.getBoundingClientRect().top <= 72;
|
||||
setCatalogToolbarHidden((current) => (current === shouldHideCatalogToolbar ? current : shouldHideCatalogToolbar));
|
||||
|
||||
const precisionToolbar = document.querySelector(".precision-gear-controls");
|
||||
const shouldCompactPrecision = window.innerWidth <= 720 && Boolean(precisionToolbar) && precisionToolbar.getBoundingClientRect().top <= 72 && window.scrollY > 0;
|
||||
setPrecisionGearToolbarCompact((current) => (current === shouldCompactPrecision ? current : shouldCompactPrecision));
|
||||
if (!shouldCompactPrecision) setPrecisionGearFiltersOpen(false);
|
||||
}
|
||||
|
||||
updateCatalogToolbarState();
|
||||
window.addEventListener("scroll", updateCatalogToolbarState, { passive: true });
|
||||
document.addEventListener("scroll", updateCatalogToolbarState, { passive: true, capture: true });
|
||||
window.addEventListener("resize", updateCatalogToolbarState);
|
||||
return () => {
|
||||
window.removeEventListener("scroll", updateCatalogToolbarState);
|
||||
document.removeEventListener("scroll", updateCatalogToolbarState, true);
|
||||
window.removeEventListener("resize", updateCatalogToolbarState);
|
||||
};
|
||||
}, []);
|
||||
|
||||
function openCatalogProduct(product: CatalogProduct) {
|
||||
setSelectedCatalogProduct(product);
|
||||
setCatalogVisualMode("main");
|
||||
}
|
||||
|
||||
function startSelection() {
|
||||
setMobileMenuOpen(false);
|
||||
setStage(1);
|
||||
requestAnimationFrame(() => {
|
||||
document.getElementById("selector")?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
@@ -454,22 +489,33 @@ export default function Home() {
|
||||
return (
|
||||
<main>
|
||||
<header className="site-header">
|
||||
<a className="brand" href="#top" aria-label="高徳乐 AI选型首页">
|
||||
<span className="brand-mark">G</span>
|
||||
<span>
|
||||
<a className="brand" href="#top" aria-label="高德乐 AI选型首页">
|
||||
<span className="brand-wordmark">
|
||||
<strong>GAUDELOT</strong>
|
||||
<small>高徳乐 · 精密传动</small>
|
||||
<small>高德乐</small>
|
||||
</span>
|
||||
</a>
|
||||
<nav aria-label="主导航">
|
||||
<a href="#selector">AI选型</a>
|
||||
<a href="#products">完整目录</a>
|
||||
<a href="#precision-gears">精密齿轮</a>
|
||||
<a href="#how">服务流程</a>
|
||||
<nav id="mobile-primary-nav" className={mobileMenuOpen ? "is-open" : ""} aria-label="主导航">
|
||||
<a href="#selector" onClick={() => setMobileMenuOpen(false)}>AI选型</a>
|
||||
<a href="#products" onClick={() => setMobileMenuOpen(false)}>完整目录</a>
|
||||
<a href="#precision-gears" onClick={() => setMobileMenuOpen(false)}>精密齿轮</a>
|
||||
<a href="#how" onClick={() => setMobileMenuOpen(false)}>服务流程</a>
|
||||
</nav>
|
||||
<button className="header-cta" type="button" onClick={startSelection}>
|
||||
开始选型 <span>→</span>
|
||||
</button>
|
||||
<div className="header-actions">
|
||||
<button className="header-cta" type="button" onClick={startSelection}>
|
||||
开始选型 <span>→</span>
|
||||
</button>
|
||||
<button
|
||||
className="mobile-menu-toggle"
|
||||
type="button"
|
||||
aria-expanded={mobileMenuOpen}
|
||||
aria-controls="mobile-primary-nav"
|
||||
onClick={() => setMobileMenuOpen((open) => !open)}
|
||||
>
|
||||
<span aria-hidden="true">{mobileMenuOpen ? "×" : "☰"}</span>
|
||||
<small>{mobileMenuOpen ? "关闭" : "菜单"}</small>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section className="hero" id="top">
|
||||
@@ -962,6 +1008,7 @@ export default function Home() {
|
||||
<p>官方目录按八个主分类收录{CATALOG_PRODUCTS.length}款产品;静音舵机作为特色子集筛选,不重复计入产品总数。</p>
|
||||
</div>
|
||||
|
||||
<div className="catalog-directory">
|
||||
<div className="catalog-summary" aria-label="产品分类统计">
|
||||
{PRIMARY_CATALOG_CATEGORIES.map((category) => (
|
||||
<button
|
||||
@@ -980,7 +1027,7 @@ export default function Home() {
|
||||
</div>
|
||||
<p className="catalog-category-note">分类已按官方目录表头及业务规则复核 · 八个主分类合计{CATALOG_PRODUCTS.length}款 · 舵盘配件6款 · 静音舵机11款为标准舵机特色子集</p>
|
||||
|
||||
<div className="catalog-toolbar">
|
||||
<div className={`catalog-toolbar ${catalogToolbarCompact ? "is-compact" : ""} ${catalogToolbarFiltersOpen ? "filters-open" : ""} ${catalogToolbarHidden ? "is-hidden" : ""}`}>
|
||||
<label className="catalog-search">
|
||||
<span>⌕</span>
|
||||
<input
|
||||
@@ -996,6 +1043,14 @@ export default function Home() {
|
||||
<button type="button" onClick={() => setCatalogQuery("")} aria-label="清空搜索">×</button>
|
||||
)}
|
||||
</label>
|
||||
<button
|
||||
className="catalog-mobile-filter-toggle"
|
||||
type="button"
|
||||
aria-expanded={catalogToolbarFiltersOpen}
|
||||
onClick={() => setCatalogToolbarFiltersOpen((open) => !open)}
|
||||
>
|
||||
{catalogToolbarFiltersOpen ? "收起" : "筛选"}
|
||||
</button>
|
||||
<div className="category-pills" aria-label="产品类别筛选">
|
||||
{CATALOG_FILTER_CATEGORIES.map((category) => (
|
||||
<button
|
||||
@@ -1056,7 +1111,6 @@ export default function Home() {
|
||||
<span className="catalog-placeholder">GAUDELOT</span>
|
||||
)}
|
||||
<small>{product.category}</small>
|
||||
<span className="catalog-zoom-hint">点击查看大图</span>
|
||||
</button>
|
||||
<div className="catalog-card-body">
|
||||
<p>{product.code}</p>
|
||||
@@ -1090,25 +1144,10 @@ export default function Home() {
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<aside className="precision-gear-panel" id="precision-gears" aria-labelledby="precision-gears-title">
|
||||
<div className="precision-gear-copy">
|
||||
<p className="eyebrow"><span /> 精密齿轮</p>
|
||||
<h3 id="precision-gears-title">精密齿轮配件</h3>
|
||||
<p>独立目录收录 511 款产品,覆盖 11 个子类,为微型传动、机构配套与定制开发提供齿轮件支持。</p>
|
||||
</div>
|
||||
<div className="precision-gear-overview">
|
||||
<div className="precision-gear-stat"><strong>511</strong><span>款产品</span></div>
|
||||
<div className="precision-gear-stat"><strong>11</strong><span>个子类</span></div>
|
||||
<div className="precision-gear-subcats" aria-label="精密齿轮配件子类">
|
||||
{PRECISION_GEAR_SUBCATEGORIES.map(([name, count]) => (
|
||||
<span key={name}>{name} <b>{count}</b></span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div className="precision-gear-catalog" aria-label="精密齿轮配件产品卡片">
|
||||
<p className="eyebrow precision-gear-section-label"><span /> 精密齿轮</p>
|
||||
<div className="precision-gear-catalog" id="precision-gears" aria-label="精密齿轮配件产品卡片">
|
||||
<div className="precision-gear-catalog-heading">
|
||||
<div>
|
||||
<p className="step-kicker">产品卡片目录</p>
|
||||
@@ -1116,7 +1155,7 @@ export default function Home() {
|
||||
</div>
|
||||
<p>小型卡片展示型号、子类和关键规格,点击图片可查看产品大图与完整参数。</p>
|
||||
</div>
|
||||
<div className="precision-gear-controls">
|
||||
<div className={`precision-gear-controls ${precisionGearToolbarCompact ? "is-compact" : ""} ${precisionGearFiltersOpen ? "filters-open" : ""}`}>
|
||||
<input
|
||||
value={precisionGearQuery}
|
||||
onChange={(event) => {
|
||||
@@ -1126,6 +1165,14 @@ export default function Home() {
|
||||
placeholder="搜索齿轮名称、编码、材质或规格"
|
||||
aria-label="搜索精密齿轮配件"
|
||||
/>
|
||||
<button
|
||||
className="precision-gear-mobile-filter-toggle"
|
||||
type="button"
|
||||
aria-expanded={precisionGearFiltersOpen}
|
||||
onClick={() => setPrecisionGearFiltersOpen((open) => !open)}
|
||||
>
|
||||
{precisionGearFiltersOpen ? "收起" : "筛选"}
|
||||
</button>
|
||||
<div className="precision-gear-pills" aria-label="精密齿轮子类筛选">
|
||||
<button
|
||||
type="button"
|
||||
@@ -1302,8 +1349,7 @@ export default function Home() {
|
||||
|
||||
<footer>
|
||||
<div className="brand footer-brand">
|
||||
<span className="brand-mark">G</span>
|
||||
<span><strong>GAUDELOT</strong><small>高徳乐 · 精密传动</small></span>
|
||||
<span className="brand-wordmark"><strong>GAUDELOT</strong><small>高德乐</small></span>
|
||||
</div>
|
||||
<p>AI选型结果仅供初步筛选,最终型号、价格、交期与适配结果以工程师和正式文件确认为准。</p>
|
||||
<span>内部原型 · V1</span>
|
||||
|
||||
Reference in New Issue
Block a user