v0.10.21: 产品归档页 C1-C4(原站 /shop/ 模板 1398 + WPC 筛选 + WooCommerce 网格)

- 导入 archive 模板 post 1398(slug=shop-archive),/collection/ 用 ElementorRenderer
  直出 hero/两列外壳,按 widget id 注入 ShopFilters/ShopProducts;新增 server function
  解决客户端导航时 loader 打不开 db 的问题
- C1 hero:面包屑 Home / Shop(BreadcrumbWidget + vars.breadcrumb 上下文)
- C2 筛选:12 组属性(term taxonomy 顺序,scripts/import-attribute-term-order.ts);
  长期列表 5 项 + See more,Battery/Operating/Install 默认折叠;URL query 驱动,
  SoM 筛选实测 22 条;顶部 Filters 标题/已选 chips/Clear all
- C3 网格:WooCommerce 归档 DOM(结果计数、orderby、24 卡 4 列、卡片 1:1 图/标题/
  Read more);默认排序导入 products.meta.menu_order(scripts/import-product-menu-order.ts),
  前三个商品与原站一致(DSOM-040R/110R/130N)
- C4 分页:页码/箭头、当前页样式、page2 25–48 条验证
- 修复 Tailwind .columns-4 与 WooCommerce 网格类冲突;app.css 新增 shop 归档 scoped 样式
- 1436 实测:hero 52.8、shop 节 2906.7、筛选区 2798.7、网格 2523.3、卡 257.7×409、
  分页 y2855,与原站逐项一致(±6px 内);bun test 11 pass;版本 0.10.21
This commit is contained in:
bigcode
2026-11-02 12:32:18 +08:00
parent 5ff5f9d477
commit ddeeca3293
12 changed files with 866 additions and 46 deletions
+16 -2
View File
@@ -114,6 +114,11 @@ export async function getFooterTemplate() {
return getPublishedContent("footer", "template");
}
/** # 函数 产品归档页 Elementor 模板(legacy elementor_library post 1398) */
export async function getShopTemplate() {
return getPublishedContent("shop-archive", "template");
}
/** # 类型 产品筛选状态:每个筛选字段已选值列表 */
export type FilterState = Record<string, string[]>;
@@ -146,7 +151,7 @@ export async function listProducts(opts: {
q?: string;
page?: number;
pageSize?: number;
sort?: "latest" | "title" | "views";
sort?: "default" | "latest" | "title" | "views" | "price" | "price-desc";
}): Promise<ProductListResult> {
const page = Math.max(1, opts.page || 1);
const pageSize = Math.min(48, Math.max(8, opts.pageSize || 24));
@@ -181,7 +186,16 @@ export async function listProducts(opts: {
async function runProductQuery(conds: unknown[], page: number, pageSize: number, sort?: string): Promise<ProductListResult> {
const where = and(...(conds as never[]));
const [{ total }] = await db.select({ total: count() }).from(products).where(where);
const order = sort === "title" ? asc(products.title) : sort === "views" ? desc(products.views) : desc(products.createdAt);
// 排序(对齐原站 /shop/ 的 orderby:默认=WooCommerce menu_order、
// popularity=浏览量、date/最新=发布时间、price/price-desc=价格升降;
// menu_order 由 scripts/import-product-menu-order.ts 写入 products.meta.menu_order)
const order =
sort === "title" ? asc(products.title)
: sort === "views" ? desc(products.views)
: sort === "price" ? asc(products.price)
: sort === "price-desc" ? desc(products.price)
: sort === "latest" ? desc(products.createdAt)
: sql`NULLIF(${products.meta}->>'menu_order', '')::int ASC NULLS LAST, ${products.id} ASC`;
const items = await db
.select({
id: products.id,