v0.1.39 - 달력 원형과 D-DAY 표시 상태 보정

This commit is contained in:
2026-04-22 18:13:50 +09:00
parent 3c3b0d20dd
commit b18af56c3c
6 changed files with 27 additions and 11 deletions

View File

@@ -4,7 +4,7 @@
- 프로젝트명: 10 Minute Planner 웹 UI - 프로젝트명: 10 Minute Planner 웹 UI
- 기술 스택: Vue 3 + Vite + TailwindCSS + JavaScript - 기술 스택: Vue 3 + Vite + TailwindCSS + JavaScript
- 현재 기준 버전: `v0.1.38` 준비 중 - 현재 기준 버전: `v0.1.39` 준비 중
- Git 원격 저장소: `https://git.sori.studio/zenn/planner.sori.studio.git` - Git 원격 저장소: `https://git.sori.studio/zenn/planner.sori.studio.git`
## 기준 디자인 ## 기준 디자인
@@ -196,6 +196,9 @@
- `TODO.md`는 중복 체크 항목을 정리했고, 인증 확장을 위해 `이메일 인증 / 비밀번호 재설정 / rate limit / 메일 인프라` 작업을 별도 항목으로 추가했다. - `TODO.md`는 중복 체크 항목을 정리했고, 인증 확장을 위해 `이메일 인증 / 비밀번호 재설정 / rate limit / 메일 인프라` 작업을 별도 항목으로 추가했다.
- Resend 무료 플랜은 도메인 1개 제약이 있어 현재 프로젝트 인증 메일에는 바로 쓰기 어렵다. 다음 단계에서는 AWS SES 또는 범용 SMTP 공급자 기준으로 메일 발송 추상화를 붙이는 쪽이 적합하다. - Resend 무료 플랜은 도메인 1개 제약이 있어 현재 프로젝트 인증 메일에는 바로 쓰기 어렵다. 다음 단계에서는 AWS SES 또는 범용 SMTP 공급자 기준으로 메일 발송 추상화를 붙이는 쪽이 적합하다.
- 현재 인증 메일/재설정 메일은 실제 발송 대신 개발용 `previewUrl`을 응답으로 돌려주는 단계다. 프론트 UI 연결과 실제 메일러 연결은 다음 단계에서 마무리하면 된다. - 현재 인증 메일/재설정 메일은 실제 발송 대신 개발용 `previewUrl`을 응답으로 돌려주는 단계다. 프론트 UI 연결과 실제 메일러 연결은 다음 단계에서 마무리하면 된다.
- 미니 달력 날짜 버튼은 원형 비율이 흔들리지 않도록 고정 `width/height` 기준으로 다시 맞췄다.
- 플래너 본문 D-DAY 텍스트는 3줄까지만 보이고, 넘치면 말줄임 처리되도록 정리했다.
- 목표가 없는 빈 날짜에서는 `D-DAY 사용` 토글이 저장 상태와 무관하게 `OFF + 비활성`처럼 보이도록 보정했다.
- 비로그인 랜딩 카드는 상단 고정이 아니라 화면 중앙에 오도록 정렬을 수정했다. - 비로그인 랜딩 카드는 상단 고정이 아니라 화면 중앙에 오도록 정렬을 수정했다.
- 현재 환경에서는 Docker 데몬이 꺼져 있어서 `docker compose build` 실검증은 하지 못했고, 데몬 시작 후 다시 확인이 필요하다. - 현재 환경에서는 Docker 데몬이 꺼져 있어서 `docker compose build` 실검증은 하지 못했고, 데몬 시작 후 다시 확인이 필요하다.
- 이미지 저장 기능은 추후 `print-only` 또는 별도 export 전용 레이아웃을 기준으로 구현하면 화면/인쇄/공유 결과를 맞추기 쉽다. - 이미지 저장 기능은 추후 `print-only` 또는 별도 export 전용 레이아웃을 기준으로 구현하면 화면/인쇄/공유 결과를 맞추기 쉽다.

4
package-lock.json generated
View File

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

View File

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

View File

@@ -212,7 +212,7 @@ function startOfDay(date) {
function buildFallbackRecord(date) { function buildFallbackRecord(date) {
return { return {
comment: '', comment: '',
goalEnabled: true, goalEnabled: false,
selectedGoalId: null, selectedGoalId: null,
tasks: Array.from({ length: 15 }, (_, index) => ({ tasks: Array.from({ length: 15 }, (_, index) => ({
label: '', label: '',
@@ -363,6 +363,7 @@ const activePlannerGoals = computed(() =>
}), }),
) )
const plannerGoal = computed(() => activePlannerGoals.value[0] ?? null) const plannerGoal = computed(() => activePlannerGoals.value[0] ?? null)
const plannerGoalToggleOn = computed(() => Boolean(plannerGoal.value) && planner.value.goalEnabled)
const plannerDday = computed(() => { const plannerDday = computed(() => {
if (!planner.value.goalEnabled || !plannerGoal.value) { if (!planner.value.goalEnabled || !plannerGoal.value) {
return '' return ''
@@ -1930,13 +1931,13 @@ onBeforeUnmount(() => {
<button <button
type="button" type="button"
class="relative h-8 w-16 shrink-0 rounded-full transition-colors duration-300 ease-out disabled:cursor-not-allowed disabled:opacity-50" class="relative h-8 w-16 shrink-0 rounded-full transition-colors duration-300 ease-out disabled:cursor-not-allowed disabled:opacity-50"
:class="planner.goalEnabled ? 'bg-stone-900' : 'bg-stone-300'" :class="plannerGoalToggleOn ? 'bg-stone-900' : 'bg-stone-300'"
:disabled="!hasActiveGoalForSelectedDate" :disabled="!hasActiveGoalForSelectedDate"
@click="updateGoalEnabled(planner, !planner.goalEnabled)" @click="updateGoalEnabled(planner, !planner.goalEnabled)"
> >
<span <span
class="absolute left-1 top-1 h-6 w-6 transform-gpu rounded-full bg-white shadow-sm transition-transform duration-300 ease-out will-change-transform" class="absolute left-1 top-1 h-6 w-6 transform-gpu rounded-full bg-white shadow-sm transition-transform duration-300 ease-out will-change-transform"
:class="planner.goalEnabled ? 'translate-x-8' : 'translate-x-0'" :class="plannerGoalToggleOn ? 'translate-x-8' : 'translate-x-0'"
/> />
</button> </button>
</div> </div>
@@ -2091,13 +2092,13 @@ onBeforeUnmount(() => {
<button <button
type="button" type="button"
class="relative h-8 w-16 shrink-0 rounded-full transition-colors duration-300 ease-out disabled:cursor-not-allowed disabled:opacity-50" class="relative h-8 w-16 shrink-0 rounded-full transition-colors duration-300 ease-out disabled:cursor-not-allowed disabled:opacity-50"
:class="planner.goalEnabled ? 'bg-stone-900' : 'bg-stone-300'" :class="plannerGoalToggleOn ? 'bg-stone-900' : 'bg-stone-300'"
:disabled="!hasActiveGoalForSelectedDate" :disabled="!hasActiveGoalForSelectedDate"
@click="updateGoalEnabled(planner, !planner.goalEnabled)" @click="updateGoalEnabled(planner, !planner.goalEnabled)"
> >
<span <span
class="absolute left-1 top-1 h-6 w-6 transform-gpu rounded-full bg-white shadow-sm transition-transform duration-300 ease-out will-change-transform" class="absolute left-1 top-1 h-6 w-6 transform-gpu rounded-full bg-white shadow-sm transition-transform duration-300 ease-out will-change-transform"
:class="planner.goalEnabled ? 'translate-x-8' : 'translate-x-0'" :class="plannerGoalToggleOn ? 'translate-x-8' : 'translate-x-0'"
/> />
</button> </button>
</div> </div>

View File

@@ -132,7 +132,7 @@ function selectYear(year) {
> >
<button <button
type="button" type="button"
class="relative flex size-8 items-center justify-center rounded-full border text-[10px] font-semibold transition sm:size-10 sm:text-[11px]" class="relative flex h-10 w-10 shrink-0 items-center justify-center rounded-full border text-[10px] font-semibold transition sm:h-[44px] sm:w-[44px] sm:text-[11px]"
:class="[ :class="[
day.key === selectedKey day.key === selectedKey
? 'border-ink bg-ink text-white' ? 'border-ink bg-ink text-white'

View File

@@ -132,7 +132,19 @@ onBeforeUnmount(() => {
</div> </div>
<div v-if="props.showDday" class="relative min-h-[82px] w-full border-t border-ink px-[10px] pt-[10px] sm:w-[210px]"> <div v-if="props.showDday" class="relative min-h-[82px] w-full border-t border-ink px-[10px] pt-[10px] sm:w-[210px]">
<span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">D-DAY</span> <span class="absolute -top-2 left-0 bg-paper px-[2px] text-muted">D-DAY</span>
<p class="pt-5 text-[11px] tracking-[0.2em] text-ink sm:pt-6 sm:text-sm">{{ dday }}</p> <p
class="pt-5 text-[11px] tracking-[0.14em] text-ink sm:pt-6 sm:text-sm"
style="
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-word;
"
>
{{ dday }}
</p>
</div> </div>
</div> </div>
<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="planner-sheet__meta-bottom flex flex-col gap-3 border-b border-ink pb-3 sm:gap-4 sm:pb-[18px] lg:flex-row">