v0.0.1
This commit is contained in:
337
src/App.vue
Normal file
337
src/App.vue
Normal 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>
|
||||
47
src/components/MiniCalendar.vue
Normal file
47
src/components/MiniCalendar.vue
Normal 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>
|
||||
124
src/components/PlannerPage.vue
Normal file
124
src/components/PlannerPage.vue
Normal 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
5
src/main.ts
Normal 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
22
src/style.css
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user