This commit is contained in:
2026-04-21 12:30:44 +09:00
commit 56b64d176b
15 changed files with 3292 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
node_modules/
dist/
.DS_Store
*.log

37
AGENTS.md Normal file
View File

@@ -0,0 +1,37 @@
# Codex Working Rules
This file defines repo-specific rules that CODEX AI and future helpers should follow.
## Product Rules
- Preserve the planner identity as a `10-minute planner diary`.
- Keep the default primary experience as `1 page + right-side information panel`.
- Keep `2 page spread` mode available unless the user explicitly removes it.
- Prefer calm paper-like layouts over generic dashboard styling.
## Technical Rules
- Use Vue for implementation.
- Use TailwindCSS for styling.
- Prefer reusable Vue components over large monolithic templates.
- Keep mock data easy to replace with real data sources later.
- Preserve responsive behavior for desktop and mobile.
## Workflow Rules
- Use local Git versioning continuously during development.
- Record meaningful product or technical notes in `HANDOFF.md`.
- Do not remove user-authored notes from `HANDOFF.md` unless they are outdated and replaced.
- When a major change is made, update both code and handoff context together.
## Commit Rules
- Use semantic version style commits starting from `v0.0.1` when the user asks for versioned checkpoints.
- Prefer small, understandable checkpoints over large ambiguous commits.
## Design Implementation Rules
- Use the provided Figma files as the visual source of truth.
- Match the overall proportions, line rhythm, and typography feel of the diary layout.
- Add new UI around the planner only when it clearly supports navigation, planning, or review.

46
HANDOFF.md Normal file
View File

@@ -0,0 +1,46 @@
# Handoff Notes
## Project Summary
- Project: 10 Minute Planner web UI
- Stack: Vue 3 + Vite + TailwindCSS + TypeScript
- Current version baseline: `v0.0.1`
## Source Design
- Figma spread view: `https://www.figma.com/design/ZgIAmg2YlVWpABD7JVLPzY/Untitled?node-id=1-36&m=dev`
- Figma focus view with side info: `https://www.figma.com/design/ZgIAmg2YlVWpABD7JVLPzY/Untitled?node-id=1-2472&m=dev`
## Current Product Direction
- Default UX direction is `1 page + extra information panel`.
- `2 page spread` view is still implemented as an alternate mode for comparison.
- The UI should feel like a paper diary, but interactions should still feel like an app.
## Current Implementation
- Main shell: `src/App.vue`
- Planner paper layout: `src/components/PlannerPage.vue`
- Right-side calendar: `src/components/MiniCalendar.vue`
- Tailwind setup is in place and should remain the styling system for this project.
## Decisions Made
- Vue was chosen over static HTML because the planner needs stateful interactions:
date switching, mode toggling, sidebar summaries, and future data persistence.
- TailwindCSS is the required styling approach even when using Vue.
- The current data is mock data for layout and interaction verification.
## Next Recommended Steps
- Connect planner data to persistent storage or local state management.
- Make task checkbox state editable.
- Add timetable interaction for selecting or painting focused time blocks.
- Decide whether the right panel should prioritize calendar, stats, or next-day planning on mobile.
- Add print/export styling if the diary-like output needs physical printing.
## Update Rule
- When an important decision, constraint, bug, or workflow change happens, append it here.
- Keep this file concise and practical so the next helper can continue without re-discovery.

12
index.html Normal file
View File

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>10분 플래너</title>
</head>
<body class="bg-stone-100">
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

2586
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

23
package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "ten-minute-planner",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.5.13"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.2",
"vite": "^6.0.5",
"vue-tsc": "^2.2.0"
}
}

6
postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

337
src/App.vue Normal file
View File

@@ -0,0 +1,337 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import MiniCalendar from './components/MiniCalendar.vue'
import PlannerPage from './components/PlannerPage.vue'
type PlannerTask = {
id: string
title: string
checked?: boolean
}
type PlannerRecord = {
dday: string
comment: string
totalTime: string
tasks: PlannerTask[]
memo: string[]
prevSummary: string[]
nextFocus: string[]
}
type ViewMode = 'focus' | 'spread'
const viewMode = ref<ViewMode>('focus')
const selectedDate = ref(new Date(2026, 3, 21))
const hours = [
'6', '7', '8', '9', '10', '11', '12',
'1', '2', '3', '4', '5',
'6', '7', '8', '9', '10', '11', '12',
'1', '2', '3', '4', '5',
]
const plannerSeed: Record<string, PlannerRecord> = {
'2026-04-21': {
dday: 'D-12 LAUNCH',
comment: '집중 작업 3개만 남기고, 10분 단위로 흐름을 끊지 않기.',
totalTime: '09H 40M',
tasks: [
{ id: '01', title: '홈 화면 정보 구조 정리', checked: true },
{ id: '02', title: '플래너 페이지 헤더 상태 연결', checked: true },
{ id: '03', title: '타임테이블 액티브 블록 설계' },
{ id: '04', title: '우측 캘린더 빠른 이동 구현' },
{ id: '05', title: '전날 요약 영역 문구 다듬기' },
{ id: '06', title: '다음날 할 일 자동 제안 시나리오' },
{ id: '07', title: '통계 카드 레이아웃 정리' },
{ id: '08', title: '모바일 스택 레이아웃 점검' },
{ id: '09', title: '체크박스 인터랙션 연결' },
{ id: '10', title: '페이지 넘김 애니메이션 방향 검토' },
{ id: '11', title: 'Tailwind 토큰 정리' },
{ id: '12', title: 'Vue 컴포넌트 분리 기준 정하기' },
{ id: '13', title: '빈 상태 문구 작성' },
{ id: '14', title: '주간 리듬 회고 메모 추가' },
{ id: '15', title: '디자인 QA 체크리스트 정리' },
],
memo: [
'오른쪽 패널은 정보 확인과 이동이 한 번에 되도록 유지.',
'2페이지 보기는 비교용으로 남기고 기본값은 집중 보기로 사용.',
'작업 흐름이 끊기지 않도록 클릭 포인트를 줄이기.',
],
prevSummary: [
'어제 완료한 핵심 3개 보기',
'이전 체크 누적률 78%',
'막힌 작업 메모 바로 이어보기',
],
nextFocus: [
'내일 첫 집중 블록 예약',
'다음날 핵심 3개 자동 복사',
'미완료 작업만 재정렬',
],
},
'2026-04-22': {
dday: 'D-11 LAUNCH',
comment: '초반 90분은 구현, 후반은 문장과 사용성 정리에 사용.',
totalTime: '08H 20M',
tasks: [
{ id: '01', title: '통계 섹션 수치 실제 계산 연결', checked: true },
{ id: '02', title: '날짜 선택 시 상태 동기화' },
{ id: '03', title: '다음날 할 일 템플릿 개선' },
{ id: '04', title: '2페이지 보기 비교 카피 작성' },
{ id: '05', title: '주간 흐름 카드 추가' },
{ id: '06', title: '메모 영역 편집 UX 개선' },
{ id: '07', title: '프린트 스타일 초안 점검' },
{ id: '08', title: '색 대비 보정' },
{ id: '09', title: '우측 패널 축약 버전 검토' },
{ id: '10', title: '마감용 체크리스트 분리' },
{ id: '11', title: '키보드 탐색 흐름 다듬기' },
{ id: '12', title: '데이터 구조 문서화' },
{ id: '13', title: '테스트 날짜 더미 세트 늘리기' },
{ id: '14', title: '브랜드 푸터 위치 확정' },
{ id: '15', title: '빈 상태 일러스트 여부 결정' },
],
memo: [
'한 화면에 모든 정보를 모으되 시선 이동은 짧게.',
'캘린더는 검색보다 빠른 이동 장치로 동작해야 함.',
'실행 화면은 다이어리 같고, 인터랙션은 앱처럼.',
],
prevSummary: [
'이전날 메모 3줄 이어보기',
'전날 타임블록 밀도 확인',
'완료율 기준 다음 일정 추천',
],
nextFocus: [
'다음날 오전 블록 추천',
'오늘 미완료 작업 넘기기',
'이번 주 누적 시간 요약',
],
},
}
const dateFormatter = new Intl.DateTimeFormat('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
weekday: 'short',
})
function toKey(date: Date) {
const year = date.getFullYear()
const month = `${date.getMonth() + 1}`.padStart(2, '0')
const day = `${date.getDate()}`.padStart(2, '0')
return `${year}-${month}-${day}`
}
function buildFallbackRecord(date: Date): PlannerRecord {
return {
dday: 'D-00 FOCUS',
comment: `${date.getMonth() + 1}${date.getDate()}일 플래너를 위한 빈 페이지입니다.`,
totalTime: '00H 00M',
tasks: Array.from({ length: 15 }, (_, index) => ({
id: `${index + 1}`.padStart(2, '0'),
title: index < 3 ? '새 작업을 추가해 주세요.' : '',
})),
memo: ['메모를 남겨 두세요.', '중요한 문장을 짧게 적어 보세요.', '내일로 넘길 내용을 적어 두세요.'],
prevSummary: ['이전 기록 없음', '새로운 흐름 시작', ''],
nextFocus: ['다음 집중 블록 준비', '내일의 핵심 3개 정하기', ''],
}
}
const planner = computed(() => plannerSeed[toKey(selectedDate.value)] ?? buildFallbackRecord(selectedDate.value))
const secondaryDate = computed(() => {
const next = new Date(selectedDate.value)
next.setDate(next.getDate() + 1)
return next
})
const secondaryPlanner = computed(() => plannerSeed[toKey(secondaryDate.value)] ?? buildFallbackRecord(secondaryDate.value))
const monthLabel = computed(() =>
`${selectedDate.value.getFullYear()}.${`${selectedDate.value.getMonth() + 1}`.padStart(2, '0')}`,
)
const calendarDays = computed(() => {
const base = selectedDate.value
const first = new Date(base.getFullYear(), base.getMonth(), 1)
const start = new Date(first)
start.setDate(first.getDate() - first.getDay())
return Array.from({ length: 35 }, (_, index) => {
const date = new Date(start)
date.setDate(start.getDate() + index)
return {
key: toKey(date),
label: date.getDate(),
date,
isCurrentMonth: date.getMonth() === base.getMonth(),
}
})
})
const completedTasks = computed(() => planner.value.tasks.filter((task) => task.checked).length)
const completionRate = computed(() => Math.round((completedTasks.value / planner.value.tasks.length) * 100))
function shiftDate(amount: number) {
const next = new Date(selectedDate.value)
next.setDate(next.getDate() + amount)
selectedDate.value = next
}
</script>
<template>
<main class="min-h-screen px-4 py-6 text-ink sm:px-6 lg:px-10">
<div class="mx-auto flex max-w-[1680px] flex-col gap-6">
<header class="flex flex-col gap-4 rounded-[28px] border border-white/60 bg-white/70 p-5 backdrop-blur sm:p-6">
<div class="flex flex-col gap-3 lg:flex-row lg:items-end lg:justify-between">
<div class="space-y-2">
<p class="text-[11px] font-bold uppercase tracking-[0.28em] text-stone-500">10 Minute Planner</p>
<h1 class="text-2xl font-semibold tracking-[-0.04em] text-stone-900 sm:text-4xl">
다이어리처럼 보이되, 앱답게 빠르게 이동하는 플래너
</h1>
<p class="max-w-3xl text-sm font-medium leading-6 text-stone-600">
기본 모드는 Figma의 1페이지 + 보조 정보 패널 구성을 따르고, 비교용으로 2페이지 펼침 보기도 함께 제공합니다.
</p>
</div>
<div class="flex flex-wrap items-center gap-3">
<div class="inline-flex rounded-full border border-stone-200 bg-stone-100 p-1">
<button
type="button"
class="rounded-full px-4 py-2 text-xs font-bold tracking-[0.14em] transition"
:class="viewMode === 'focus' ? 'bg-white text-ink shadow-sm' : 'text-stone-500'"
@click="viewMode = 'focus'"
>
1 PAGE + INFO
</button>
<button
type="button"
class="rounded-full px-4 py-2 text-xs font-bold tracking-[0.14em] transition"
:class="viewMode === 'spread' ? 'bg-white text-ink shadow-sm' : 'text-stone-500'"
@click="viewMode = 'spread'"
>
2 PAGE SPREAD
</button>
</div>
<div class="inline-flex items-center gap-2 rounded-full border border-stone-200 bg-white px-2 py-2">
<button
type="button"
class="rounded-full border border-stone-200 px-3 py-2 text-xs font-bold tracking-[0.14em] text-stone-600 transition hover:border-stone-400 hover:text-ink"
@click="shiftDate(-1)"
>
PREV DAY
</button>
<button
type="button"
class="rounded-full border border-stone-200 px-3 py-2 text-xs font-bold tracking-[0.14em] text-stone-600 transition hover:border-stone-400 hover:text-ink"
@click="shiftDate(1)"
>
NEXT DAY
</button>
</div>
</div>
</div>
</header>
<section
v-if="viewMode === 'focus'"
class="grid gap-6 xl:grid-cols-[minmax(0,1fr)_320px]"
>
<PlannerPage
:date-label="dateFormatter.format(selectedDate)"
:dday="planner.dday"
:comment="planner.comment"
:total-time="planner.totalTime"
:tasks="planner.tasks"
:memo="planner.memo"
:hours="hours"
/>
<aside class="flex flex-col gap-4">
<section class="border border-stone-200 bg-white/80 p-5">
<p class="mb-4 text-[11px] font-bold tracking-[0.22em] text-ink">PREV SNAPSHOT</p>
<div class="space-y-3">
<p
v-for="item in planner.prevSummary"
:key="item"
class="border-b border-stone-200 pb-3 text-[11px] font-semibold tracking-[0.08em] text-stone-700 last:border-b-0 last:pb-0"
>
{{ item || ' ' }}
</p>
</div>
</section>
<section class="border border-stone-200 bg-white/80 p-5">
<p class="mb-4 text-[11px] font-bold tracking-[0.22em] text-ink">READ NEXT</p>
<div class="space-y-3">
<p
v-for="item in planner.nextFocus"
:key="item"
class="border-b border-stone-200 pb-3 text-[11px] font-semibold tracking-[0.08em] text-stone-700 last:border-b-0 last:pb-0"
>
{{ item || ' ' }}
</p>
</div>
</section>
<MiniCalendar
:month-label="monthLabel"
:days="calendarDays"
:selected-key="toKey(selectedDate)"
@select="selectedDate = $event"
/>
<section class="grid grid-cols-2 gap-4">
<article class="border border-stone-200 bg-white/80 p-5">
<p class="text-[11px] font-bold tracking-[0.22em] text-ink">STATS</p>
<div class="mt-5 space-y-4">
<div>
<p class="text-[28px] font-semibold tracking-[-0.05em] text-stone-900">{{ completionRate }}%</p>
<p class="text-[11px] font-semibold tracking-[0.08em] text-stone-500">TASK COMPLETION</p>
</div>
<div>
<p class="text-[22px] font-semibold tracking-[-0.04em] text-stone-900">{{ planner.totalTime }}</p>
<p class="text-[11px] font-semibold tracking-[0.08em] text-stone-500">FOCUSED TIME</p>
</div>
</div>
</article>
<article class="border border-stone-200 bg-white/80 p-5">
<p class="text-[11px] font-bold tracking-[0.22em] text-ink">NEXT DAY</p>
<div class="mt-5 space-y-3">
<p class="text-lg font-semibold tracking-[-0.04em] text-stone-900">
{{ dateFormatter.format(secondaryDate) }}
</p>
<p class="text-[11px] font-semibold tracking-[0.08em] text-stone-600">
내일의 작업은 "{{ secondaryPlanner.tasks[0]?.title || '새 작업 추가' }}" 시작합니다.
</p>
</div>
</article>
</section>
</aside>
</section>
<section v-else class="overflow-x-auto rounded-[32px] border border-white/60 bg-white/40 p-4 sm:p-6">
<div class="flex min-w-[1260px] gap-6">
<PlannerPage
:date-label="dateFormatter.format(selectedDate)"
:dday="planner.dday"
:comment="planner.comment"
:total-time="planner.totalTime"
:tasks="planner.tasks"
:memo="planner.memo"
:hours="hours"
/>
<PlannerPage
:date-label="dateFormatter.format(secondaryDate)"
:dday="secondaryPlanner.dday"
:comment="secondaryPlanner.comment"
:total-time="secondaryPlanner.totalTime"
:tasks="secondaryPlanner.tasks"
:memo="secondaryPlanner.memo"
:hours="hours"
/>
</div>
</section>
</div>
</main>
</template>

View File

@@ -0,0 +1,47 @@
<script setup lang="ts">
type DayCell = {
key: string
label: number
date: Date
isCurrentMonth: boolean
}
defineProps<{
monthLabel: string
days: DayCell[]
selectedKey: string
}>()
const emit = defineEmits<{
select: [date: Date]
}>()
</script>
<template>
<section class="border border-stone-200 bg-white/80 p-5">
<div class="mb-4 flex items-center justify-between">
<h2 class="text-[11px] font-bold tracking-[0.22em] text-ink">CALENDAR</h2>
<span class="text-[11px] font-semibold tracking-[0.16em] text-stone-500">{{ monthLabel }}</span>
</div>
<div class="mb-3 grid grid-cols-7 gap-2 text-center text-[10px] font-bold tracking-[0.12em] text-stone-400">
<span v-for="weekday in ['S', 'M', 'T', 'W', 'T', 'F', 'S']" :key="weekday">{{ weekday }}</span>
</div>
<div class="grid grid-cols-7 gap-2">
<button
v-for="day in days"
:key="day.key"
type="button"
class="aspect-square rounded-full border text-[11px] font-semibold transition"
:class="[
day.key === selectedKey
? 'border-ink bg-ink text-white'
: 'border-stone-200 bg-stone-50 text-stone-700 hover:border-stone-400 hover:bg-white',
day.isCurrentMonth ? '' : 'opacity-35',
]"
@click="emit('select', day.date)"
>
{{ day.label }}
</button>
</div>
</section>
</template>

View File

@@ -0,0 +1,124 @@
<script setup lang="ts">
type PlannerTask = {
id: string
title: string
checked?: boolean
}
type PlannerProps = {
dateLabel: string
dday: string
comment: string
totalTime: string
tasks: PlannerTask[]
memo: string[]
hours: string[]
brand?: string
}
defineProps<PlannerProps>()
</script>
<template>
<article
class="flex w-full max-w-[762px] flex-col gap-3 bg-paper px-6 py-6 text-[10px] font-bold tracking-[0.16em] text-ink shadow-paper sm:px-12 sm:py-12"
>
<div class="flex flex-col gap-4 py-[18px]">
<div class="flex gap-4">
<div class="relative h-[90px] w-[394px] flex-1 border-t border-ink px-[10px] pt-[10px]">
<span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">YEAR / MONTH / DAY</span>
<p class="pt-6 text-xs tracking-[0.24em] text-ink sm:text-sm">{{ dateLabel }}</p>
</div>
<div class="relative h-[90px] w-[210px] border-t border-ink px-[10px] pt-[10px]">
<span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">D-DAY</span>
<p class="pt-6 text-xs tracking-[0.24em] text-ink sm:text-sm">{{ dday }}</p>
</div>
</div>
<div class="flex gap-4 border-b border-ink pb-[18px]">
<div class="relative h-[90px] w-[394px] flex-1 border-t border-ink px-[10px] pt-[10px]">
<span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">COMMENT</span>
<p class="pt-6 text-[11px] font-semibold normal-case tracking-[0.08em] text-stone-700 sm:text-xs">
{{ comment }}
</p>
</div>
<div class="relative h-[90px] w-[210px] border-t border-ink px-[10px] pt-[10px]">
<span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">TOTAL TIME</span>
<p class="pt-6 text-xs tracking-[0.24em] text-ink sm:text-sm">{{ totalTime }}</p>
</div>
</div>
</div>
<div class="flex gap-4 py-[10px]">
<div class="flex w-[394px] flex-1 flex-col gap-9">
<section class="relative">
<div class="absolute -top-[9px] left-0 bg-paper px-[2px] text-muted">TASKS</div>
<div class="border-t border-ink">
<div
v-for="(task, index) in tasks"
:key="task.id"
class="flex h-[38px] items-center border-b"
:class="index % 5 === 4 || index === tasks.length - 1 ? 'border-ink' : 'border-line'"
>
<div class="h-full w-[62px] border-r border-dashed border-ink px-2 py-2 text-[9px] text-stone-500">
{{ task.id }}
</div>
<div class="flex min-w-0 flex-1 items-center px-3">
<span class="truncate text-[11px] font-semibold normal-case tracking-[0.06em] text-stone-800">
{{ task.title }}
</span>
</div>
<div class="flex h-full w-[42px] items-center justify-center p-[10px]">
<span
class="block h-full w-full border border-dashed"
:class="task.checked ? 'border-ink bg-stone-100' : 'border-ink/60'"
/>
</div>
</div>
</div>
</section>
<section class="relative">
<div class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">MEMO</div>
<div class="border-t border-ink">
<div
v-for="(memoItem, index) in memo"
:key="`${memoItem}-${index}`"
class="flex h-[38px] items-center border-b"
:class="index === memo.length - 1 ? 'border-ink' : 'border-line'"
>
<div class="h-full w-[62px] border-r border-dashed border-ink" />
<div class="flex-1 px-3 text-[11px] font-semibold normal-case tracking-[0.06em] text-stone-700">
{{ memoItem }}
</div>
</div>
</div>
</section>
</div>
<section class="relative w-[210px] shrink-0">
<div class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">TIME TABLE</div>
<div class="border-t border-ink">
<div
v-for="(hour, index) in hours"
:key="`${hour}-${index}`"
class="flex h-[30px] border-b"
:class="index === hours.length - 1 ? 'border-ink' : 'border-line'"
>
<div class="flex h-full w-[30px] items-center justify-center border-r border-ink text-[9px] text-ink">
{{ hour }}
</div>
<div
v-for="quarter in 6"
:key="quarter"
class="h-full w-[30px] border-r border-dashed border-line last:border-r-0"
/>
</div>
</div>
</section>
</div>
<div class="flex justify-end">
<p class="text-[10px] tracking-[0.18em] text-ink">{{ brand ?? 'SORI.STUDIO' }}</p>
</div>
</article>
</template>

5
src/main.ts Normal file
View File

@@ -0,0 +1,5 @@
import { createApp } from 'vue'
import App from './App.vue'
import './style.css'
createApp(App).mount('#app')

22
src/style.css Normal file
View File

@@ -0,0 +1,22 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
html {
font-family: "Inter", "Pretendard", ui-sans-serif, system-ui, sans-serif;
color: #111111;
background: #f3f0ea;
}
body {
min-height: 100vh;
background:
radial-gradient(circle at top, rgba(255, 255, 255, 0.9), transparent 32%),
linear-gradient(180deg, #f6f2ea 0%, #efe8de 100%);
}
button {
@apply outline-none;
}
}

18
tailwind.config.js Normal file
View File

@@ -0,0 +1,18 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./index.html', './src/**/*.{vue,ts}'],
theme: {
extend: {
colors: {
ink: '#111111',
line: '#c9c9c9',
muted: '#b4b1c1',
paper: '#fffdf9',
},
boxShadow: {
paper: '0 24px 64px rgba(17, 17, 17, 0.08)',
},
},
},
plugins: [],
}

18
tsconfig.json Normal file
View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"noEmit": true,
"types": ["vite/client"]
},
"include": ["src/**/*.ts", "src/**/*.vue"]
}

6
vite.config.ts Normal file
View File

@@ -0,0 +1,6 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
})