Compare commits

...

5 Commits

Author SHA1 Message Date
lixu 36f9c95fa7 Merge pull request 'feat(public): 首页改为极简谷歌风格' (#38) from devin/1782372352-home-mobile-center into main
CI / Go (api) (push) Successful in 1m10s
CI / Python (ingestion) (push) Successful in 19s
CI / Migrations (postgres) (push) Successful in 26s
2026-06-25 18:11:18 +08:00
lixu 9ee83e3535 feat(public): 首页改为极简谷歌风格
CI / Go (api) (pull_request) Successful in 54s
CI / Python (ingestion) (pull_request) Successful in 16s
CI / Migrations (postgres) (pull_request) Successful in 27s
2026-06-25 10:08:56 +00:00
lixu 53ade9eeea Merge pull request 'feat(public): 首页搜索居中、移动端自适应,移除下方三卡片' (#37) from devin/1782372352-home-mobile-center into main
CI / Go (api) (push) Successful in 56s
CI / Python (ingestion) (push) Successful in 23s
CI / Migrations (postgres) (push) Successful in 27s
2026-06-25 15:28:54 +08:00
lixu 313bc84cb0 feat(public): 首页搜索居中、移动端自适应,移除下方三卡片
CI / Go (api) (pull_request) Successful in 52s
CI / Python (ingestion) (pull_request) Successful in 25s
CI / Migrations (postgres) (pull_request) Successful in 29s
2026-06-25 07:25:52 +00:00
lixu 8c8df2b8a2 Merge pull request 'fix(admin): 回流接口校验/规范化 GTIN' (#36) from devin/1782352663-backflow-gtin-validate into main
CI / Go (api) (push) Successful in 1m7s
CI / Python (ingestion) (push) Successful in 24s
CI / Migrations (postgres) (push) Successful in 25s
2026-06-25 10:00:29 +08:00
+31 -63
View File
@@ -1,28 +1,8 @@
import { useState } from "react";
import { Search, PlusCircle, Code2, ScanBarcode, ShieldCheck, ArrowRight } from "lucide-react";
import { Search, PlusCircle, ArrowRight } from "lucide-react";
import { api } from "../api";
import type { ProductSummary } from "../types";
const EXAMPLES = ["可乐", "Nutella", "牛奶", "5449000000996"];
const FEATURES = [
{
icon: Search,
title: "客观可查",
desc: "按名称或条码检索商品的成分、营养、规格等官方事实。",
},
{
icon: ShieldCheck,
title: "可溯源",
desc: "每条资料标注数据来源与质量分,公开透明、人人可核。",
},
{
icon: Code2,
title: "开放 API",
desc: "免鉴权只读 REST 接口,开发者可直接接入商品档案。",
},
];
export default function Home({
onOpen,
onContribute,
@@ -57,47 +37,47 @@ export default function Home({
return (
<div className="animate-fade-up">
<section className="relative overflow-hidden rounded-3xl border border-gray-100 bg-gradient-to-b from-white to-brand-50/40 px-6 py-14 text-center shadow-card">
<div
aria-hidden
className="pointer-events-none absolute -top-24 left-1/2 h-72 w-[42rem] -translate-x-1/2 rounded-full bg-brand-200/30 blur-3xl"
/>
<div className="relative">
<span className="inline-flex items-center gap-1.5 rounded-full border border-brand-200 bg-white/70 px-3 py-1 text-xs font-medium text-brand-700">
<ShieldCheck className="w-3.5 h-3.5" /> · ·
</span>
<h1 className="mt-5 text-4xl sm:text-5xl font-extrabold tracking-tight text-gray-900">
<span className="bg-gradient-to-r from-brand-600 to-emerald-500 bg-clip-text text-transparent"></span>
<section
className={`flex flex-col items-center px-4 text-center ${
searched
? "pt-2 pb-6"
: "min-h-[calc(100vh-12rem)] justify-center"
}`}
>
<h1
className={`font-medium tracking-tight text-gray-800 ${
searched ? "text-3xl" : "text-6xl sm:text-7xl"
}`}
>
<span className="text-brand-600"></span>
</h1>
<p className="mx-auto mt-3 max-w-xl text-gray-500">
</p>
<form onSubmit={(e) => run(undefined, e)} className="mx-auto mt-7 flex max-w-2xl gap-2">
<div className="flex flex-1 items-center gap-2 rounded-xl border border-gray-200 bg-white px-3.5 shadow-sm transition focus-within:border-brand-400 focus-within:ring-4 focus-within:ring-brand-500/10">
<form
onSubmit={(e) => run(undefined, e)}
className="mx-auto mt-8 w-full max-w-xl"
>
<div className="flex items-center gap-3 rounded-full border border-gray-200 bg-white px-5 py-3 shadow-sm transition hover:shadow-md focus-within:shadow-md">
<Search className="h-5 w-5 shrink-0 text-gray-400" />
<input
autoFocus
value={q}
onChange={(e) => setQ(e.target.value)}
placeholder="例如:可乐、Nutella、5449000000996"
className="flex-1 bg-transparent py-3.5 outline-none"
placeholder="搜索商品名称或条码"
className="flex-1 bg-transparent outline-none"
/>
</div>
<button type="submit" disabled={loading} className="btn-primary px-7">
{!searched && (
<div className="mt-8">
<button
type="submit"
disabled={loading}
className="rounded-md border border-gray-200 bg-gray-50 px-6 py-2.5 text-sm text-gray-700 transition hover:border-gray-300 hover:shadow-sm"
>
{loading ? "检索中…" : "检索"}
</button>
</div>
)}
</form>
<div className="mt-4 flex flex-wrap items-center justify-center gap-2">
<span className="text-xs text-gray-400"></span>
{EXAMPLES.map((ex) => (
<button key={ex} type="button" className="chip" onClick={() => run(ex)}>
<ScanBarcode className="w-3 h-3" /> {ex}
</button>
))}
</div>
</div>
</section>
{error && (
@@ -106,7 +86,7 @@ export default function Home({
</div>
)}
{searched ? (
{searched && (
<div className="mt-8">
<div className="mb-3 text-sm text-gray-500">
<span className="font-semibold text-gray-700">{total}</span>
@@ -154,18 +134,6 @@ export default function Home({
</ul>
)}
</div>
) : (
<div className="mt-8 grid gap-4 sm:grid-cols-3">
{FEATURES.map(({ icon: Icon, title, desc }) => (
<div key={title} className="card p-5 transition hover:shadow-card-hover">
<span className="grid h-10 w-10 place-items-center rounded-xl bg-brand-50 text-brand-600">
<Icon className="h-5 w-5" />
</span>
<h3 className="mt-3 font-semibold text-gray-800">{title}</h3>
<p className="mt-1 text-sm leading-relaxed text-gray-500">{desc}</p>
</div>
))}
</div>
)}
</div>
);