diff --git a/package.json b/package.json index 4a8602ea3..2e6d1ba4e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dusuniot-rebuild", - "version": "0.10.31", + "version": "0.10.32", "private": true, "type": "module", "scripts": { diff --git a/src/components/elementor/Renderer.tsx b/src/components/elementor/Renderer.tsx index 464827b5a..9ef00061d 100644 --- a/src/components/elementor/Renderer.tsx +++ b/src/components/elementor/Renderer.tsx @@ -145,7 +145,8 @@ function paddingCss(v: unknown): string | undefined { if (typeof v === "object") { const o = v as Record; const unit = s(o.unit) || "px"; - const t = o.top, r = o.right, b = o.bottom, l = o.left; + // Elementor 语义:空串 = 未设置(继承默认值),显式 "0" 才是 0(产品 hero 按钮 text_padding 全空 → 12px 24px 默认) + const t = o.top === "" ? null : o.top, r = o.right === "" ? null : o.right, b = o.bottom === "" ? null : o.bottom, l = o.left === "" ? null : o.left; if (t == null && r == null && b == null && l == null) return undefined; const px = (x: unknown) => `${x ?? 0}${unit}`; return collapseBoxValues(`${px(t)} ${px(r)} ${px(b)} ${px(l)}`); @@ -818,6 +819,11 @@ function WidgetNodeInner({ el }: { el: ElElement }) { return ; case "woocommerce-products": return ; + /* 原站这两类 widget 在 hero 渲染为空(询价型商品无价格/购物车,取证 dsgw-210-a-1 + * 叶子扫描仅 7 个 widget);渲染非空会把 hero 撑高(Add to Cart 占位 +42px) */ + case "woocommerce-product-price": + case "wc-add-to-cart": + return null; case "video": return ; case "counter": @@ -2148,7 +2154,16 @@ function WooProductMeta() { function WooProductShortDescription() { const woo = useContext(WooContext); if (!woo?.shortDescription) return null; - return
; + return
; +} + +/** # 函数 WP wpautop 简化版:把首个块级标签(ul/ol/table/hN/p)之前的裸文本包进

+ * dump 的 short_description 与 WP 库存一致(裸文本 + \r\n

    ),原站经 the_content 输出时 + * 首段被包成

    (取证 dsgw-210-a-1:P h=96 + mb 14.4);不包则匿名文本行盒与 ul 缝距不齐 + */ +function wpautopLite(html: string): string { + const m = /^([^<]+)(<[\s\S]*)$/.exec(html.trim()); + return m ? `

    ${m[1].trim()}

    ${m[2]}` : html; } /** # 组件 Woo 产品数据标签页(woocommerce-product-data-tabs) @@ -2211,18 +2226,23 @@ function WooProductsWidget() { /** # 常量 Woo 产品组件样式(取证 2026-11-03 dsgw-210-a-1 @1440) */ const WOO_CSS = ` .woo-gallery { margin: 0 0 32px; } +/* 取证(dsgw-210-a-1,2026-11-03):主图框 .flex-viewport border 1px #C7CBDA(484 宽)、缩略图 img 115×115 同色边框 */ +.woo-gallery .woo-gallery-image { border: 1px solid #C7CBDA; } .woo-gallery .woo-gallery-image img { display: block; width: 100%; height: auto; } .woo-gallery .woo-thumbs { list-style: none; display: flex; flex-wrap: wrap; margin: 6px -4px 0; padding: 0; } .woo-gallery .woo-thumbs li { width: 25%; padding: 4px; box-sizing: border-box; list-style: none; } -.woo-gallery .woo-thumbs img { display: block; width: 100%; height: auto; border-radius: 3px; cursor: pointer; opacity: 0.85; } +.woo-gallery .woo-thumbs img { display: block; width: 100%; height: auto; border: 1px solid #C7CBDA; cursor: pointer; } .woo-title { margin: 0; font-size: 24px; font-weight: 600; line-height: 24px; color: #333; } -.woo-meta { display: flex; flex-wrap: wrap; margin: 16px -10px 0; font-size: 16px; line-height: 24px; color: #333; } +.woo-meta { display: flex; flex-wrap: wrap; margin: 0 -10px; font-size: 16px; line-height: 24px; color: #333; } .woo-meta .woo-meta-item { padding: 0 10px; } .woo-meta .woo-meta-label { font-weight: 700; } -.woo-meta .woo-meta-value a { color: #333; text-decoration: none; } -.woo-meta .woo-meta-value a:hover { color: #ED6C00; } -.woo-short-desc { margin-top: 20px; font-size: 16px; line-height: 32px; color: #333; } -.woo-short-desc p { margin: 0 0 10px; } +.woo-meta .woo-meta-value a { color: #ED6C00; text-decoration: none; } +.woo-meta .woo-meta-value a:hover { color: #FFA11B; } +/* 取证(dsgw-210-a-1,2026-11-03):正文 p/匿名文本行高 24(P h=96/4 行)、列表项 32(UL 224/7 项)、p 底距 14.4 */ +.woo-short-desc { margin-top: 0; font-size: 16px; line-height: 24px; color: #333; } +.woo-short-desc li { line-height: 32px; } +.woo-short-desc p { margin: 0 0 14.4px; } +.woo-short-desc ul { margin: 0; } .woo-tabs-list { list-style: none; display: none; margin: 0; padding: 0; } .woo-tabs-list li { display: inline-block; } .woo-tabs-list li a { display: inline-block; padding: 12.8px 19.2px; font-size: 16px; font-weight: 700; line-height: 16px; color: #515151; } diff --git a/src/server/data.ts b/src/server/data.ts index e3dcd3482..c0b597e2b 100644 --- a/src/server/data.ts +++ b/src/server/data.ts @@ -287,6 +287,7 @@ export async function getProductDetail(slug: string) { description: products.description, price: products.price, regularPrice: products.regularPrice, + gallery: products.gallery, stockStatus: products.stockStatus, stock: products.stock, specUrl: products.specUrl, @@ -302,8 +303,10 @@ export async function getProductDetail(slug: string) { .leftJoin(media, eq(media.id, products.featuredMediaId)) .where(and(eq(products.slug, slug), eq(products.status, "published"))); if (!row) return null; - const galleryUrls = row.meta && Array.isArray((row.meta as any).gallery) - ? await db.select({ url: media.url, alt: media.altText }).from(media).where(inArray(media.id, (row.meta as any).gallery)) + // 图廊 ID 存 products.gallery 列(JSON 数组,如 [3785,3784];meta.gallery 不存在) + const galleryIds: unknown = (row as unknown as { gallery?: unknown }).gallery; + const galleryUrls = Array.isArray(galleryIds) && galleryIds.length + ? await db.select({ url: media.url, alt: media.altText }).from(media).where(inArray(media.id, galleryIds as number[])) : []; const attributes = await db .select({ attr: productAttributes.name, attrSlug: productAttributes.slug, value: productAttributeValues.value, valueSlug: productAttributeValues.slug }) diff --git a/src/styles/app.css b/src/styles/app.css index a70cea91c..3641a6569 100644 --- a/src/styles/app.css +++ b/src/styles/app.css @@ -83,6 +83,8 @@ } .fa-chevron-up::before { content: "\f077"; } .fa-comment-dots::before { content: "\f4ad"; } +/* 产品 hero「Specification」按钮右图标(模板 2741 b267c2a selected_icon far fa-file-alt) */ +.fa-file-alt::before { content: "\f15c"; } .fa-check-circle::before { content: "\f058"; } /* 联系页地址列(icon-list 38bf7c7/cbf19d1 等):信封与地图钉(FA Solid 码位) */ .fa-envelope::before { content: "\f0e0"; }