고정 페이지 HTML 문서 모드 추가 v1.5.1

This commit is contained in:
2026-05-26 11:03:33 +09:00
parent 0ad2ab3f9d
commit a25306389b
15 changed files with 169 additions and 14 deletions

View File

@@ -0,0 +1,34 @@
import { getMethod, getRequestURL, setResponseHeader } from 'h3'
import { getPageBySlug } from '../repositories/content-repository'
/**
* 공개 페이지가 HTML 문서 모드일 때 Nuxt 렌더링 대신 원문 HTML을 응답한다.
* @param {import('h3').H3Event} event - 요청 이벤트
* @returns {Promise<string | void>} HTML 문서 또는 다음 핸들러 진행
*/
export default defineEventHandler(async (event) => {
const method = getMethod(event)
if (method !== 'GET' && method !== 'HEAD') {
return
}
const pathname = getRequestURL(event).pathname
const match = pathname.match(/^\/pages\/([^/]+)\/?$/)
if (!match) {
return
}
const slug = decodeURIComponent(match[1])
const page = await getPageBySlug(slug)
if (page?.renderMode !== 'html_document') {
return
}
setResponseHeader(event, 'content-type', 'text/html; charset=utf-8')
setResponseHeader(event, 'cache-control', 'no-cache')
return page.content || ''
})

View File

@@ -62,6 +62,7 @@ const mapPageRow = (row) => ({
title: row.title,
slug: row.slug,
content: row.content,
renderMode: row.render_mode || 'markdown',
featuredImage: row.featured_image,
createdAt: row.created_at.toISOString(),
updatedAt: row.updated_at.toISOString()
@@ -538,12 +539,14 @@ export const createAdminPage = async (input) => {
title,
slug,
content,
render_mode,
featured_image
)
VALUES (
${input.title},
${input.slug},
${input.content},
${input.renderMode},
${input.featuredImage}
)
RETURNING *
@@ -571,6 +574,7 @@ export const updateAdminPage = async (id, input) => {
title = ${input.title},
slug = ${input.slug},
content = ${input.content},
render_mode = ${input.renderMode},
featured_image = ${input.featuredImage},
updated_at = now()
WHERE id = ${id}

View File

@@ -4,9 +4,15 @@ import { normalizeMarkdownContent } from '../../lib/markdown-content-normalizer.
export const adminPageInputSchema = z.object({
title: z.string().trim().min(1),
slug: z.string().trim().min(1).regex(/^[a-z0-9가-힣]+(?:-[a-z0-9가-힣]+)*$/),
content: z.preprocess(normalizeMarkdownContent, z.string()).default(''),
renderMode: z.enum(['markdown', 'html_document']).default('markdown'),
content: z.string().default(''),
featuredImage: z.string().trim().nullable().default(null)
})
}).transform((input) => ({
...input,
content: input.renderMode === 'html_document'
? input.content
: normalizeMarkdownContent(input.content)
}))
/**
* 관리자 페이지 입력값 정리

View File

@@ -28,6 +28,7 @@ export const pageSchema = z.object({
title: z.string().min(1),
slug: z.string().min(1),
content: z.string(),
renderMode: z.enum(['markdown', 'html_document']).default('markdown'),
featuredImage: z.string().nullable().default(null),
createdAt: z.string(),
updatedAt: z.string()

View File

@@ -37,6 +37,7 @@ const samplePages = [
title: 'About',
slug: 'about',
content: 'sori.studio 소개 페이지입니다.',
renderMode: 'markdown',
featuredImage: null,
createdAt: now,
updatedAt: now