feat(web): complete MVP0 public layout, banner, and SEO baseline
This commit is contained in:
@@ -12,6 +12,20 @@ async function main() {
|
||||
status: "published",
|
||||
},
|
||||
})
|
||||
|
||||
await db.systemSetting.upsert({
|
||||
where: { key: "public.header_banner" },
|
||||
update: {},
|
||||
create: {
|
||||
key: "public.header_banner",
|
||||
value: JSON.stringify({
|
||||
enabled: true,
|
||||
message: "New portfolio release is live.",
|
||||
ctaLabel: "Open latest posts",
|
||||
ctaHref: "/",
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
@@ -7,4 +7,9 @@ export {
|
||||
registerPostCrudAuditHook,
|
||||
updatePost,
|
||||
} from "./posts"
|
||||
export { isAdminSelfRegistrationEnabled, setAdminSelfRegistrationEnabled } from "./settings"
|
||||
export type { PublicHeaderBanner } from "./settings"
|
||||
export {
|
||||
getPublicHeaderBanner,
|
||||
isAdminSelfRegistrationEnabled,
|
||||
setAdminSelfRegistrationEnabled,
|
||||
} from "./settings"
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
import { db } from "./client"
|
||||
|
||||
const ADMIN_SELF_REGISTRATION_KEY = "admin.self_registration_enabled"
|
||||
const PUBLIC_HEADER_BANNER_KEY = "public.header_banner"
|
||||
|
||||
type PublicHeaderBannerRecord = {
|
||||
enabled: boolean
|
||||
message: string
|
||||
ctaLabel?: string
|
||||
ctaHref?: string
|
||||
}
|
||||
|
||||
export type PublicHeaderBanner = {
|
||||
message: string
|
||||
ctaLabel?: string
|
||||
ctaHref?: string
|
||||
}
|
||||
|
||||
function resolveEnvFallback(): boolean {
|
||||
return process.env.CMS_ADMIN_SELF_REGISTRATION_ENABLED === "true"
|
||||
@@ -18,6 +32,25 @@ function parseStoredBoolean(value: string): boolean | null {
|
||||
return null
|
||||
}
|
||||
|
||||
function parsePublicHeaderBanner(value: string): PublicHeaderBannerRecord | null {
|
||||
try {
|
||||
const parsed = JSON.parse(value) as Record<string, unknown>
|
||||
|
||||
if (typeof parsed.enabled !== "boolean" || typeof parsed.message !== "string") {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
enabled: parsed.enabled,
|
||||
message: parsed.message,
|
||||
ctaLabel: typeof parsed.ctaLabel === "string" ? parsed.ctaLabel : undefined,
|
||||
ctaHref: typeof parsed.ctaHref === "string" ? parsed.ctaHref : undefined,
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function isAdminSelfRegistrationEnabled(): Promise<boolean> {
|
||||
try {
|
||||
const setting = await db.systemSetting.findUnique({
|
||||
@@ -54,3 +87,30 @@ export async function setAdminSelfRegistrationEnabled(enabled: boolean): Promise
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function getPublicHeaderBanner(): Promise<PublicHeaderBanner | null> {
|
||||
try {
|
||||
const setting = await db.systemSetting.findUnique({
|
||||
where: { key: PUBLIC_HEADER_BANNER_KEY },
|
||||
select: { value: true },
|
||||
})
|
||||
|
||||
if (!setting) {
|
||||
return null
|
||||
}
|
||||
|
||||
const parsed = parsePublicHeaderBanner(setting.value)
|
||||
|
||||
if (!parsed || !parsed.enabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
message: parsed.message,
|
||||
ctaLabel: parsed.ctaLabel,
|
||||
ctaHref: parsed.ctaHref,
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user