Compare commits

...

2 Commits

7 changed files with 54 additions and 23 deletions

View File

@@ -4,7 +4,7 @@
- 프로젝트명: 10 Minute Planner 웹 UI
- 기술 스택: Vue 3 + Vite + TailwindCSS + JavaScript
- 현재 기준 버전: `v0.1.36` 준비 중
- 현재 기준 버전: `v0.1.37` 준비 중
- Git 원격 저장소: `https://git.sori.studio/zenn/planner.sori.studio.git`
## 기준 디자인
@@ -188,6 +188,9 @@
- 달력 날짜 버튼은 셀 안쪽에 고정 크기 원형 버튼으로 다시 배치해서 모바일에서 서로 겹쳐 보이는 현상을 줄였다.
- 좌측 상단 소개 영역은 개발 설명 문장을 빼고, 서비스 소개용 짧은 카피와 배지 스타일로 다시 구성했다.
- 달력 날짜 버튼은 의도상 원형이며, 현재는 `size` 고정 기준으로 다시 맞춰서 타원처럼 보이는 인상을 줄이는 방향으로 정리했다.
- 플래너 본문, 2페이지 펼침, 인쇄 전용 `PlannerPage` 모두 `총 시간` 값은 `00시간 00분` 한글 포맷으로 통일했다.
- 모바일 대응 이후 인쇄에서 `TIME TABLE`이 사라지던 문제를 막기 위해, print 시에는 `PlannerPage` 내부 레이아웃을 다시 가로 배치로 고정하고 타임테이블 오버플로를 해제하도록 보정했다.
- `TODO.md`는 중복 체크 항목을 정리했고, 인증 확장을 위해 `이메일 인증 / 비밀번호 재설정 / rate limit / 메일 인프라` 작업을 별도 항목으로 추가했다.
- 비로그인 랜딩 카드는 상단 고정이 아니라 화면 중앙에 오도록 정렬을 수정했다.
- 현재 환경에서는 Docker 데몬이 꺼져 있어서 `docker compose build` 실검증은 하지 못했고, 데몬 시작 후 다시 확인이 필요하다.
- 이미지 저장 기능은 추후 `print-only` 또는 별도 export 전용 레이아웃을 기준으로 구현하면 화면/인쇄/공유 결과를 맞추기 쉽다.

View File

@@ -46,7 +46,7 @@
- [x] 목표별로 D-DAY 표시 시작일과 종료일을 설정할 수 있게 한다.
- [x] 목표 표시 기간이 서로 겹치면 저장되지 않도록 막는다.
- [ ] 목표 완료 처리와 보관 상태를 구분한다.
- [ ] 목표 편집/삭제 UI를 추가한다.
- [x] 목표 편집/삭제 UI를 추가한다.
- [ ] 목표 목록 정렬 규칙과 검색 UX를 다듬는다.
## 4단계: 데이터 구조와 저장
@@ -56,9 +56,7 @@
- [x] 로컬 저장 또는 외부 저장 방식 중 우선 구현 방식을 정한다.
- [x] 입력 상태가 새로고침 후에도 유지되도록 만든다.
- [x] DB 전환 시점을 잡을 수 있도록 저장 레이어를 분리한다.
- [ ] 회원 가입 및 로그인 구조를 고려한 사용자별 데이터 모델을 설계한다.
- [x] 회원 가입 및 로그인 구조를 고려한 사용자별 데이터 모델을 설계한다.
- [ ] 사용자별 문서 저장/조회 흐름을 정리한다.
- [x] 사용자별 문서 저장/조회 흐름을 정리한다.
- [ ] 출력용 문서 포맷과 프린트 흐름을 고려한 데이터 구조를 정리한다.
@@ -77,7 +75,6 @@
## 6단계: 계정 및 서비스 확장
- [ ] 회원 가입 / 로그인 방식 후보를 정리한다.
- [x] 회원 가입 / 로그인 방식 후보를 정리한다.
- [x] 사용자 설정 화면에서 닉네임 / 이메일 / 비밀번호 수정 흐름을 분리한다.
- [x] 상단 헤더를 왼쪽 사이드 내비게이션 구조로 재배치한다.
@@ -92,6 +89,10 @@
- [x] UGREEN NAS 기준 `docker-compose.yml` 초안을 작성한다.
- [x] 백엔드 기본 스캐폴딩을 추가한다.
- [x] PostgreSQL 전환 초안을 적용한다.
- [ ] 이메일 인증 플로우를 설계하고 구현한다.
- [ ] 비밀번호 찾기 / 재설정 토큰 흐름을 추가한다.
- [ ] 로그인 및 인증 관련 rate limit / 잠금 정책을 추가한다.
- [ ] 메일 발송 인프라와 발신 도메인 정책을 확정한다.
## 메모

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "ten-minute-planner",
"version": "0.1.36",
"version": "0.1.37",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ten-minute-planner",
"version": "0.1.36",
"version": "0.1.37",
"dependencies": {
"vue": "^3.5.13"
},

View File

@@ -1,7 +1,7 @@
{
"name": "ten-minute-planner",
"private": true,
"version": "0.1.36",
"version": "0.1.37",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1850,7 +1850,7 @@ onBeforeUnmount(() => {
:dday="plannerDday"
:show-dday="showPlannerDday"
:comment="planner.comment"
:total-time="formatTotalTime(planner)"
:total-time="formatTotalTimeKorean(planner)"
:tasks="planner.tasks"
:memo="planner.memo"
:hours="hours"
@@ -2203,7 +2203,7 @@ onBeforeUnmount(() => {
:dday="plannerDday"
:show-dday="showPlannerDday"
:comment="planner.comment"
:total-time="formatTotalTime(planner)"
:total-time="formatTotalTimeKorean(planner)"
:tasks="planner.tasks"
:memo="planner.memo"
:hours="hours"
@@ -2226,7 +2226,7 @@ onBeforeUnmount(() => {
:dday="''"
:show-dday="false"
:comment="secondaryPlanner.comment"
:total-time="formatTotalTime(secondaryPlanner)"
:total-time="formatTotalTimeKorean(secondaryPlanner)"
:tasks="secondaryPlanner.tasks"
:memo="secondaryPlanner.memo"
:hours="hours"
@@ -2302,7 +2302,7 @@ onBeforeUnmount(() => {
:dday="plannerDday"
:show-dday="showPlannerDday"
:comment="planner.comment"
:total-time="formatTotalTime(planner)"
:total-time="formatTotalTimeKorean(planner)"
:tasks="planner.tasks"
:memo="planner.memo"
:hours="hours"
@@ -2327,7 +2327,7 @@ onBeforeUnmount(() => {
:dday="plannerDday"
:show-dday="showPlannerDday"
:comment="planner.comment"
:total-time="formatTotalTime(planner)"
:total-time="formatTotalTimeKorean(planner)"
:tasks="planner.tasks"
:memo="planner.memo"
:hours="hours"
@@ -2349,7 +2349,7 @@ onBeforeUnmount(() => {
:dday="''"
:show-dday="false"
:comment="secondaryPlanner.comment"
:total-time="formatTotalTime(secondaryPlanner)"
:total-time="formatTotalTimeKorean(secondaryPlanner)"
:tasks="secondaryPlanner.tasks"
:memo="secondaryPlanner.memo"
:hours="hours"

View File

@@ -121,8 +121,8 @@ onBeforeUnmount(() => {
<article
class="planner-sheet flex w-full max-w-[762px] flex-col gap-3 bg-paper px-4 py-4 text-[10px] font-bold tracking-[0.16em] text-ink shadow-paper sm:px-8 sm:py-8 lg:px-12 lg:py-12"
>
<div class="flex flex-col gap-4 py-3 sm:py-[18px]">
<div class="flex flex-col gap-3 sm:gap-4" :class="props.showDday ? 'sm:flex-row' : ''">
<div class="planner-sheet__meta flex flex-col gap-4 py-3 sm:py-[18px]">
<div class="planner-sheet__meta-top flex flex-col gap-3 sm:gap-4" :class="props.showDday ? 'sm:flex-row' : ''">
<div class="relative min-h-[82px] border-t border-ink px-[10px] pt-[10px]" :class="props.showDday ? 'w-full sm:w-[394px] sm:flex-1' : 'w-full flex-1'">
<span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">YEAR / MONTH / DAY</span>
<p class="pt-5 text-[11px] tracking-[0.2em] text-ink sm:pt-6 sm:text-sm">
@@ -135,7 +135,7 @@ onBeforeUnmount(() => {
<p class="pt-5 text-[11px] tracking-[0.2em] text-ink sm:pt-6 sm:text-sm">{{ dday }}</p>
</div>
</div>
<div class="flex flex-col gap-3 border-b border-ink pb-3 sm:gap-4 sm:pb-[18px] lg:flex-row">
<div class="planner-sheet__meta-bottom flex flex-col gap-3 border-b border-ink pb-3 sm:gap-4 sm:pb-[18px] lg:flex-row">
<div class="relative min-h-[82px] w-full flex-1 border-t border-ink px-[10px] pt-[10px] lg:w-[394px]">
<span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">COMMENT</span>
<textarea
@@ -147,14 +147,14 @@ onBeforeUnmount(() => {
/>
</div>
<div class="relative min-h-[82px] w-full border-t border-ink px-[10px] pt-[10px] lg:w-[210px]">
<span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted"> 시간</span>
<span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">FOCUSED TIME</span>
<p class="pt-5 text-[11px] tracking-[0.2em] text-ink sm:pt-6 sm:text-sm">{{ totalTime }}</p>
</div>
</div>
</div>
<div class="flex flex-col gap-5 py-[10px] lg:flex-row lg:gap-4">
<div class="flex w-full flex-1 flex-col gap-7 sm:gap-9 lg:w-[394px]">
<div class="planner-sheet__body flex flex-col gap-5 py-[10px] lg:flex-row lg:gap-4">
<div class="planner-sheet__lists flex w-full flex-1 flex-col gap-7 sm:gap-9 lg:w-[394px]">
<section class="relative">
<div class="absolute -top-[9px] left-0 bg-paper px-[2px] text-muted">TASKS</div>
<div class="border-t border-ink">
@@ -225,10 +225,10 @@ onBeforeUnmount(() => {
</section>
</div>
<section class="relative w-full shrink-0 lg:w-[210px]">
<section class="planner-sheet__timetable relative w-full shrink-0 lg:w-[210px]">
<div class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">TIME TABLE</div>
<div class="overflow-x-auto pb-1">
<div class="min-w-[210px] border-t border-ink">
<div class="planner-sheet__timetable-scroll overflow-x-auto pb-1">
<div class="planner-sheet__timetable-grid min-w-[210px] border-t border-ink">
<div
v-for="(hour, index) in hours"
:key="`${hour}-${index}`"

View File

@@ -143,6 +143,33 @@
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
.planner-sheet__meta-top,
.planner-sheet__meta-bottom,
.planner-sheet__body {
display: flex !important;
flex-direction: row !important;
gap: 16px !important;
}
.planner-sheet__lists {
width: 394px !important;
flex: 1 1 auto !important;
}
.planner-sheet__timetable {
width: 210px !important;
flex-shrink: 0 !important;
}
.planner-sheet__timetable-scroll {
overflow: visible !important;
padding-bottom: 0 !important;
}
.planner-sheet__timetable-grid {
min-width: 210px !important;
}
}
@media screen {