Add data-driven public pages (home, news, profile)
Real App Router pages reading the converted Prisma models: - home: latest 4 articles (websiteArticles) + hotel_name from settings - /news + /news/[slug]: article index and detail - /u/[username]: profile (avatar via imager helper, motto, rank, credits, online) - shared SiteNav (reads session via auth() + hotel_name), globals.css - src/lib/format.ts: avatarImageUrl + excerpt helpers (unit-tested) Verified: tsc exit 0, vitest 43/43, next build exit 0 (7 routes). Pages render against a live DB (deferred until DATABASE_URL is provided). i18n to be layered on next.
This commit is contained in:
1 parent
8fca407f0f
commit
6e34d485d4
9 files changed
+327
-7
No files matched your search
@@ -0,0 +1,21 @@
|
||||
/** Build a Habbo avatar-imager URL for a figure string. */
|
||||
export function avatarImageUrl(
|
||||
base: string,
|
||||
look: string,
|
||||
opts: { size?: "s" | "m" | "l"; headOnly?: boolean; direction?: number } = {},
|
||||
): string {
|
||||
const params = new URLSearchParams({ figure: look });
|
||||
if (opts.size) params.set("size", opts.size);
|
||||
if (opts.headOnly) params.set("headonly", "1");
|
||||
if (opts.direction !== undefined) params.set("direction", String(opts.direction));
|
||||
const sep = base.includes("?") ? "&" : "?";
|
||||
return `${base}${sep}${params.toString()}`;
|
||||
}
|
||||
|
||||
/** Trim text to `max` chars on a word boundary, adding an ellipsis. */
|
||||
export function excerpt(text: string, max = 160): string {
|
||||
if (text.length <= max) return text;
|
||||
const cut = text.slice(0, max);
|
||||
const lastSpace = cut.lastIndexOf(" ");
|
||||
return `${(lastSpace > 0 ? cut.slice(0, lastSpace) : cut).trimEnd()}…`;
|
||||
}
|
||||
Reference in new issue
Block a user