v0.10.25: /solution/ 归档+落地页复刻(archive 组件/分页/摘录24词)、Header 全断点对齐、page_css 导入管线、reviews/populated 宽度/_css_classes/tabs HTML/图片变体修复

This commit is contained in:
bigcode
2026-11-03 03:59:04 +08:00
parent 7559977ae1
commit 9a51994860
17 changed files with 681 additions and 146 deletions
+26 -11
View File
@@ -373,9 +373,9 @@ function firstUploadedImage(meta: unknown): string | null {
/** # 类型 博客列表项(列表卡片 + 文章页侧栏/相关文章复用) */
export type PostListItem = Awaited<ReturnType<typeof listPosts>>["items"][number];
/** # 成员变量 /solution/ 索引页展示的方案落地页 slug(与原站 SOLUTION 索引卡片一一对应) **/
/** # 成员变量 /solution/ 归档展示的方案落地页 slug(原站 category-solution 全部 14 篇) **/
export const SOLUTION_SLUGS = [
"smart-apartment-solution",
"smart-apartment-gateway",
"smart-apartment-gateway-oem",
"oil-gas-management-solution",
"energy-storage-ems-solution",
@@ -384,32 +384,47 @@ export const SOLUTION_SLUGS = [
"smart-building-solution",
"smart-retail-solution",
"smart-home-solution",
"smart-apartment-solution",
"smart-elderly-care-solution",
"ble-positioning-solution",
"ble-mesh-lighting-control-solution",
"home-assistant-grow-lighting-solution",
] as const;
/** # 函数 方案落地页列表(/solution/ 索引卡片:标题 + 摘要 + 图)
* 返回值 按 SOLUTION_SLUGS 顺序的已发布 elementor 方案页(缺省跳过)
/** # 函数 方案归档列表(/solution/ 索引卡片:标题 + 摘要 + 图)
* 与原站 Elementor archive-posts 一致:按发布时间倒序、每页 12 篇(第 1 页 12 篇 + 分页)。
* 参数 page 页码(1 起);pageSize 每页条数(默认 12)
* 返回值 { items, total, page, pageSize }
*/
export async function listSolutionLandings() {
export async function listSolutionLandings(page = 1, pageSize = 12) {
const conds = [eq(contents.type, "post"), eq(contents.status, "published"), inArray(contents.slug, [...SOLUTION_SLUGS])];
const [{ n: total }] = await db
.select({ n: count() })
.from(contents)
.where(and(...conds));
const rows = await db
.select({
id: contents.id,
slug: contents.slug,
title: contents.title,
excerpt: contents.excerpt,
publishedAt: contents.publishedAt,
imageUrl: media.url,
imageAlt: media.altText,
hasElementor: sql<boolean>`(meta -> 'elementor') is not null`,
})
.from(contents)
.leftJoin(media, eq(media.id, contents.featuredMediaId))
.where(and(eq(contents.type, "post"), eq(contents.status, "published"), inArray(contents.slug, [...SOLUTION_SLUGS])));
const bySlug = new Map(rows.map((r) => [r.slug, r]));
return [...SOLUTION_SLUGS]
.map((s) => bySlug.get(s))
.filter((r) => !!r)
.map((r) => ({ ...r, title: decodeHtmlEntities(r.title) }));
.where(and(...conds))
.orderBy(desc(contents.publishedAt))
.limit(pageSize)
.offset((page - 1) * pageSize);
return {
items: rows.map((r) => ({ ...r, title: decodeHtmlEntities(r.title), excerpt: r.excerpt ?? "" })),
total,
page,
pageSize,
};
}
export async function listPosts(page = 1, pageSize = 12, categorySlug?: string) {