This commit is contained in:
Suphonchai Phoonsawat 2026-08-18 12:52:40 +07:00
commit 41573b3c4f
54 changed files with 32839 additions and 0 deletions

23
web/app/app.vue Normal file
View file

@ -0,0 +1,23 @@
<script setup lang="ts">
const { initTheme, toggle, isDark } = useTheme()
onMounted(() => initTheme())
</script>
<template>
<div class="min-h-screen bg-slate-50 text-slate-900 dark:bg-slate-900 dark:text-slate-100">
<header class="flex items-center justify-between border-b border-slate-200 px-6 py-4 dark:border-slate-700">
<NuxtLink to="/" class="text-lg font-semibold">Word Versioning</NuxtLink>
<button
type="button"
class="rounded-md border border-slate-300 px-3 py-1.5 text-sm hover:bg-slate-100 dark:border-slate-600 dark:hover:bg-slate-800"
@click="toggle"
>
{{ isDark ? '☀️ Light' : '🌙 Dark' }}
</button>
</header>
<main class="mx-auto max-w-3xl p-6">
<NuxtPage />
</main>
</div>
</template>

View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View file

@ -0,0 +1,36 @@
export type Theme = 'light' | 'dark'
// ต้องตรงกับ inline script กัน FOUC ใน nuxt.config.ts
const STORAGE_KEY = 'theme-preference'
export function useTheme() {
const theme = useState<Theme>('theme', () => 'light')
const isDark = computed(() => theme.value === 'dark')
function apply(next: Theme) {
theme.value = next
if (import.meta.client) {
document.documentElement.classList.toggle('dark', next === 'dark')
// ข้อยกเว้นเดียวที่ localStorage อนุญาต: theme preference ไม่ใช่ credential (กติกา #4)
localStorage.setItem(STORAGE_KEY, next)
}
}
/** Sync state กับที่ inline script ตั้งไว้ตอนโหลดหน้า (client เท่านั้น) */
function initTheme() {
if (!import.meta.client) return
const stored = localStorage.getItem(STORAGE_KEY)
if (stored === 'light' || stored === 'dark') {
theme.value = stored
} else {
theme.value = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
document.documentElement.classList.toggle('dark', theme.value === 'dark')
}
function toggle() {
apply(theme.value === 'dark' ? 'light' : 'dark')
}
return { theme, isDark, initTheme, toggle }
}

15
web/app/pages/index.vue Normal file
View file

@ -0,0 +1,15 @@
<template>
<section class="space-y-4">
<h1 class="text-2xl font-bold">สร้างเอกสารจาก template</h1>
<p class="text-slate-600 dark:text-slate-300">
เลือก template กรอกค่า fields แล้วดาวน์โหลด .docx ที่เป็น version 1 พร้อม metadata
ไปเปิดต่อใน Word พร้อม add-in
</p>
<!-- Phase 6: รายการ template ที่ active + ลิงก์เข้าหน้า documents/create/[templateId] -->
<div
class="rounded-lg border border-dashed border-slate-300 p-8 text-center text-sm text-slate-500 dark:border-slate-600 dark:text-slate-400"
>
รายการ template จะแสดงที่นี่ (Phase 6)
</div>
</section>
</template>