Compare commits

..
2 Commits
Author SHA1 Message Date
shinalok 46c412f8f3 Merge pull request 'enlarge journal calendar cells and pair day/title on one line' (#1) from journal-calendar-ui-tweaks into main
CI/CD / test (push) Successful in 30s
CI/CD / deploy (push) Successful in 2m15s
Reviewed-on: #1
2026-08-19 17:18:22 +09:00
shinalokandClaude Sonnet 5 8a49757882 enlarge journal calendar cells and pair day/title on one line
CI/CD / test (pull_request) Successful in 51s
CI/CD / deploy (pull_request) Skipped
- calendar-cell-journal: bump min-height 44px -> 76px, scale up date/dot/title font sizes
- journal calendar titles were centered; left-align them
- rework JournalCalendarDay: replace separate category_colors/titles lists
  (mismatched lengths, no way to pair a dot with its title) with a single
  entries list of (color, title) pairs so the dot and its title render on
  the same non-wrapping row per entry

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 17:13:38 +09:00
5 changed files with 68 additions and 18 deletions
+6 -1
View File
@@ -116,10 +116,15 @@ class JournalAttachmentOut(BaseModel):
has_thumbnail: bool has_thumbnail: bool
class JournalCalendarEntry(BaseModel):
color: str # 그 엔트리가 속한 카테고리 색상 (점 표시용)
title: str # 제목(없으면 내용 일부)
class JournalCalendarDay(BaseModel): class JournalCalendarDay(BaseModel):
entry_date: date entry_date: date
total_count: int total_count: int
category_colors: list[str] # 그 날 엔트리가 있는 카테고리들의 색상(점 표시용, 중복 제거) entries: list[JournalCalendarEntry] # 엔트리별 (색상, 제목) 쌍 — 점과 제목이 한 줄에 붙어 나오도록 1:1로 매칭
class JournalDayDetailItem(BaseModel): class JournalDayDetailItem(BaseModel):
+17 -8
View File
@@ -23,6 +23,7 @@ from app.models.journal import (
from app.schemas.journal import ( from app.schemas.journal import (
JournalAttachmentOut, JournalAttachmentOut,
JournalCalendarDay, JournalCalendarDay,
JournalCalendarEntry,
JournalCategoryCreate, JournalCategoryCreate,
JournalDayDetailItem, JournalDayDetailItem,
JournalEntryCreate, JournalEntryCreate,
@@ -363,25 +364,33 @@ def get_monthly_journal_summary(
last_day = date(year, month, days_in_month) last_day = date(year, month, days_in_month)
stmt = ( stmt = (
select(JournalEntry.entry_date, JournalCategory.color) select(JournalEntry.entry_date, JournalCategory.color, JournalEntry.title, JournalEntry.content)
.join(JournalCategory, JournalEntry.category_id == JournalCategory.id) .join(JournalCategory, JournalEntry.category_id == JournalCategory.id)
.where(JournalEntry.user_id == user_id, JournalEntry.entry_date.between(first_day, last_day)) .where(JournalEntry.user_id == user_id, JournalEntry.entry_date.between(first_day, last_day))
.order_by(JournalEntry.entry_date, JournalEntry.created_at)
) )
if category_id is not None: if category_id is not None:
stmt = stmt.where(JournalEntry.category_id == category_id) stmt = stmt.where(JournalEntry.category_id == category_id)
rows = db.execute(stmt).all() rows = db.execute(stmt).all()
counts: dict[date, int] = {} counts: dict[date, int] = {}
colors_by_date: dict[date, list[str]] = {} entries_by_date: dict[date, list[JournalCalendarEntry]] = {}
for entry_date, color in rows: for entry_date, color, title, content in rows:
counts[entry_date] = counts.get(entry_date, 0) + 1 counts[entry_date] = counts.get(entry_date, 0) + 1
colors = colors_by_date.setdefault(entry_date, []) entries = entries_by_date.setdefault(entry_date, [])
color = color or "var(--color-accent)" entries.append(
if color not in colors: JournalCalendarEntry(
colors.append(color) color=color or "var(--color-accent)",
title=title or (content[:12] + ("" if len(content) > 12 else "")),
)
)
return { return {
d: JournalCalendarDay(entry_date=d, total_count=counts[d], category_colors=colors_by_date[d]) d: JournalCalendarDay(
entry_date=d,
total_count=counts[d],
entries=entries_by_date[d],
)
for d in counts for d in counts
} }
+37 -4
View File
@@ -872,15 +872,48 @@ label {
} }
/* 저널링 */ /* 저널링 */
.journal-day-dots { .calendar-cell-journal {
aspect-ratio: auto;
min-height: 76px;
padding: 6px 5px;
overflow: hidden;
}
.calendar-cell-journal .calendar-date {
font-size: 13px;
}
.journal-day-entries {
display: flex; display: flex;
gap: 2px; flex-direction: column;
align-items: flex-start;
width: 100%;
}
.journal-day-entry {
display: flex;
align-items: center;
gap: 4px;
width: 100%;
min-width: 0;
} }
.journal-day-dot { .journal-day-dot {
width: 5px; width: 6px;
height: 5px; height: 6px;
border-radius: 50%; border-radius: 50%;
flex-shrink: 0;
}
.journal-day-title {
min-width: 0;
font-size: 10px;
line-height: 1.3;
color: var(--color-text-muted);
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
.journal-prompt-card, .journal-prompt-card,
+7 -4
View File
@@ -252,16 +252,19 @@
{% for d in week %} {% for d in week %}
{% set day_summary = summary_map.get(d) %} {% set day_summary = summary_map.get(d) %}
<div <div
class="calendar-cell clickable{{ '' if d.month == month else ' muted' }}" class="calendar-cell calendar-cell-journal clickable{{ '' if d.month == month else ' muted' }}"
hx-get="/journal/day/{{ d.isoformat() }}" hx-get="/journal/day/{{ d.isoformat() }}"
hx-target="#day-detail" hx-target="#day-detail"
hx-swap="innerHTML" hx-swap="innerHTML"
> >
<span class="calendar-date">{{ d.day }}</span> <span class="calendar-date">{{ d.day }}</span>
{% if day_summary %} {% if day_summary %}
<span class="journal-day-dots"> <span class="journal-day-entries">
{% for color in day_summary.category_colors %} {% for entry in day_summary.entries %}
<span class="journal-day-dot" style="background: {{ color }};"></span> <span class="journal-day-entry">
<span class="journal-day-dot" style="background: {{ entry.color }};"></span>
<span class="journal-day-title">{{ entry.title }}</span>
</span>
{% endfor %} {% endfor %}
</span> </span>
{% endif %} {% endif %}
+1 -1
View File
@@ -285,7 +285,7 @@ def test_get_monthly_journal_summary_counts_entries_per_day(db_session, test_use
summary = journal_service.get_monthly_journal_summary(db_session, test_user.id, today.year, today.month) summary = journal_service.get_monthly_journal_summary(db_session, test_user.id, today.year, today.month)
assert summary[today].total_count == 2 assert summary[today].total_count == 2
assert summary[today].category_colors == ["#ff0000"] assert [e.color for e in summary[today].entries] == ["#ff0000", "#ff0000"]
def test_get_day_entries_returns_entries_for_that_date(db_session, test_user): def test_get_day_entries_returns_entries_for_that_date(db_session, test_user):