first commit

This commit is contained in:
2026-09-11 15:49:41 +08:00
commit 5b69bc818a
98 changed files with 30551 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
import { and, asc, desc, eq } from "drizzle-orm";
import type { DrizzleD1Database } from "drizzle-orm/d1";
import {
cases,
contentItems,
posts,
siteSettings,
type CaseStudy,
type ContentItem,
type ContentKind,
type Post,
} from "../db/schema";
import * as schema from "../db/schema";
export type Db = DrizzleD1Database<typeof schema>;
export type Settings = Record<string, string>;
export type HomeData = {
settings: Settings;
services: ContentItem[];
features: ContentItem[];
steps: ContentItem[];
faqs: ContentItem[];
cases: CaseStudy[];
};
export async function getSettings(db: Db): Promise<Settings> {
const rows = await db.select().from(siteSettings);
return Object.fromEntries(rows.map((r) => [r.key, r.value]));
}
export async function getItems(db: Db, kind: ContentKind): Promise<ContentItem[]> {
return db
.select()
.from(contentItems)
.where(and(eq(contentItems.kind, kind), eq(contentItems.status, "published")))
.orderBy(asc(contentItems.sortOrder));
}
export async function getCases(db: Db): Promise<CaseStudy[]> {
return db
.select()
.from(cases)
.where(eq(cases.status, "published"))
.orderBy(asc(cases.sortOrder));
}
export async function getPublishedPosts(db: Db): Promise<Post[]> {
return db
.select()
.from(posts)
.where(eq(posts.status, "published"))
.orderBy(desc(posts.publishedAt));
}
export async function getPostBySlug(db: Db, slug: string): Promise<Post | null> {
const [post] = await db
.select()
.from(posts)
.where(and(eq(posts.slug, slug), eq(posts.status, "published")))
.limit(1);
return post ?? null;
}
export async function getHomeData(db: Db): Promise<HomeData> {
const [settings, services, features, steps, faqs, caseList] = await Promise.all([
getSettings(db),
getItems(db, "service"),
getItems(db, "feature"),
getItems(db, "step"),
getItems(db, "faq"),
getCases(db),
]);
return { settings, services, features, steps, faqs, cases: caseList };
}
export function digits(input: string | undefined): string {
return (input ?? "").replace(/\D/g, "");
}
export function whatsappHref(
settings: Settings,
text = "你好,我想查詢村屋太陽能安裝,想預約免費評估。",
): string {
return `https://api.whatsapp.com/send?phone=${digits(settings.whatsapp)}&text=${encodeURIComponent(text)}`;
}
export function telHref(settings: Settings): string {
const phone = (settings.phone ?? "").replace(/[^\d+]/g, "");
return `tel:${phone}`;
}
export function mailHref(settings: Settings): string {
return `mailto:${settings.email ?? ""}?subject=${encodeURIComponent("查詢村屋太陽能安裝")}`;
}
export function formatDate(d: Date | null | undefined): string {
if (!d) return "";
return new Date(d).toLocaleDateString("zh-Hant-HK", {
year: "numeric",
month: "long",
day: "numeric",
});
}