diff options
| author | charlie <root@dangofactory.local> | 2026-09-25 20:35:53 +0900 |
|---|---|---|
| committer | charlie <root@dangofactory.local> | 2026-09-25 20:35:53 +0900 |
| commit | 1069fc2c0d3d56289e028bc8e7f9e0857c01c253 (patch) | |
| tree | 8be75dd3305a5fe3cd320b87b6cac4aeea484da8 /modules | |
| parent | 9f35f3c8d60ca9ebefeaab4bc1aaf2d1df7909c4 (diff) | |
| download | kukuri-1069fc2c0d3d56289e028bc8e7f9e0857c01c253.tar.gz kukuri-1069fc2c0d3d56289e028bc8e7f9e0857c01c253.tar.bz2 kukuri-1069fc2c0d3d56289e028bc8e7f9e0857c01c253.zip | |
UI calendar: match the reference image (colour bars, English header, Close pill)
The month grid now follows the Calendar Library reference screenshot that was
given as the target for this screen.
What changes, day cell:
- Events are drawn as short coloured bars along the bottom edge of the cell
(about 55% of the cell width, 3dp tall). Stacked from the top when a day
has more than one event, so a date and its bars never overlap.
- Previously a day with events showed a single bullet "•" in the theme
accent, and the old code comment argued against bars because they would
collide with the date number. Putting them on their own line inside the
cell removes that collision.
- Colours come from the new EventKind enum, mapped onto the pie's four
quadrants (section 2.5.1): year=teal, activity=blue, personal=red,
committee=brown, school=gray. The reference image's five colours are used
as-is rather than inventing a palette.
What changes, month chrome:
- Header is centred and reads "September 2026" (English month name + year)
with chevrons on both sides, replacing the left-aligned Japanese
"9月2026".
- Weekday row uses uppercase three-letter names (MON TUE WED THU FRI SAT
SUN) instead of single Japanese characters.
- A thin dark divider separates the weekday row from the grid, matching the
reference's grid lines.
- The caption "予定ドットのある日をタップ" is replaced by a centred pill
"Close" button, per the reference. In the month view there is nothing to
close, so it currently resets the visible month; the intended behaviour
still needs a decision.
- Cell corner radius 8dp -> 4dp to match the reference's squarer cells.
Colours follow the reference image exactly (sampled values): teal #008080,
blue #0000FF, red #FF0000, brown #A52A2A, gray #808080. Whether these specific
hues should be the app's event colours, or should derive from the theme, is not
settled by the reference alone and remains open.
Sample event data (3/12/17/22) is still hard-coded in eventsOf(); wiring it to
real sources is separate work. Compiles for wasm, jvm and android.
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesCalendarNoteLive.kt | 154 |
1 files changed, 117 insertions, 37 deletions
diff --git a/modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesCalendarNoteLive.kt b/modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesCalendarNoteLive.kt index 6e58ac2..da0d233 100644 --- a/modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesCalendarNoteLive.kt +++ b/modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesCalendarNoteLive.kt @@ -60,6 +60,15 @@ import kotlinx.datetime.LocalDate * 月グリッドは kizitonwose/Calendar (MIT, com.kizitonwose.calendar:compose-multiplatform) * を使う。月の移動・日セルの造形は自作せず、このライブラリの state に任せる * (ライブラリはロジックを提供し、見た目はこちらが決める、という設計の分担)。 + * + * 2026-09-25 指示: 月グリッドの見た目を参照画像(Calendar Library)に合わせる。 + * - 月見出しは中央寄せ "September 2026"(英語月名 + 年)、左右にシェブロン + * - 曜日行は大文字3字 "SUN MON TUE WED THU FRI SAT" + * - 日セルは下辺に予定の色バー(セル幅の約55%)。複数予定は縦積み + * - 格子は細い暗灰色の罫線 + * - 前月/翌月の日付は dim + * - 下部中央にピル型 "Close" ボタン + * 予定の色は種別(§2.5.1 のパイ4象限 = 一年/活動/個人/委員会)に対応させる。 */ @Composable fun CalendarFrame() { @@ -75,7 +84,49 @@ fun CalendarFrame() { } } -/** 月グリッド。予定のある日にドットを出す(§2.22)。 */ +/** + * 予定の種別。§2.5.1 のパイ4象限に対応する。 + * 参照画像の 5 色(teal/blue/red/brown/gray)をそのまま種別に割り当てる。 + */ +private enum class EventKind(val color: Color) { + Year(Color(0xFF008080)), // 一年(teal) + Activity(Color(0xFF0000FF)), // 活動(blue) + Personal(Color(0xFFFF0000)), // 個人(red) + Committee(Color(0xFFA52A2A)), // 委員会(brown) + School(Color(0xFF808080)), // 学校行事/その他(gray) +} + +/** 種別名(凡例・日タイムラインで使う)。 */ +private fun EventKind.label(): String = when (this) { + EventKind.Year -> "一年" + EventKind.Activity -> "活動" + EventKind.Personal -> "個人" + EventKind.Committee -> "委員会" + EventKind.School -> "学校行事" +} + +/** その日の予定。いまは見本(実データは後段)。 */ +private fun eventsOf(date: LocalDate): List<EventKind> = when (date.dayOfMonth) { + 3, 12 -> listOf(EventKind.Year) + 17 -> listOf(EventKind.Activity, EventKind.Personal) + 22 -> listOf(EventKind.Committee, EventKind.School) + else -> emptyList() +} + +/** 英語の月名。参照画像の見出し表記に合わせる。 */ +private fun monthNameEn(m: Int): String = when (m) { + 1 -> "January"; 2 -> "February"; 3 -> "March"; 4 -> "April" + 5 -> "May"; 6 -> "June"; 7 -> "July"; 8 -> "August" + 9 -> "September"; 10 -> "October"; 11 -> "November"; else -> "December" +} + +/** 曜日見出し(大文字3字)。ordinal は MONDAY=0。 */ +private fun dayOfWeekEn(ordinal: Int): String = when (ordinal) { + 0 -> "MON"; 1 -> "TUE"; 2 -> "WED"; 3 -> "THU" + 4 -> "FRI"; 5 -> "SAT"; else -> "SUN" +} + +/** 月グリッド。予定のある日に色バーを出す(参照画像)。 */ @Composable private fun MonthCalendar(today: LocalDate, selected: LocalDate?, onDayClick: (CalendarDay) -> Unit) { // 今日の月を得る。kotlinx-datetime の now() は kotlin.time.Clock を要求し、 @@ -102,76 +153,101 @@ private fun MonthCalendar(today: LocalDate, selected: LocalDate?, onDayClick: (C val visibleMonth = state.firstVisibleMonth.yearMonth Column(Modifier.fillMaxSize().padding(20.dp)) { + // 見出し: 中央寄せ "September 2026"、左右にシェブロン(参照画像) Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Text( - "${visibleMonth.monthNumber}月${visibleMonth.year}", - Modifier.weight(1f), - style = MaterialTheme.typography.h6, - fontWeight = FontWeight.Bold, - ) - Text( "‹", Modifier.padding(8.dp).clickable { scope.launch { state.animateScrollToMonth(state.firstVisibleMonth.yearMonth.minusMonths(1)) } }, + fontSize = 20.sp, + ) + Text( + "${monthNameEn(visibleMonth.monthNumber)} ${visibleMonth.year}", + Modifier.weight(1f), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.h6, + fontWeight = FontWeight.Normal, ) Text( "›", Modifier.padding(8.dp).clickable { scope.launch { state.animateScrollToMonth(state.firstVisibleMonth.yearMonth.plusMonths(1)) } }, + fontSize = 20.sp, ) } - Row(Modifier.fillMaxWidth()) { + // 曜日行: 大文字3字、細い罫線で下を区切る(参照画像) + Row(Modifier.fillMaxWidth().padding(top = 10.dp)) { for (d in daysOfWeek) { Text( modifier = Modifier.weight(1f), textAlign = TextAlign.Center, - fontSize = 12.sp, + fontSize = 11.sp, // d の型はターゲットで変わる (Android は java.time.DayOfWeek、 // 他は kotlinx.datetime.DayOfWeek)。ordinal は両方で使えるので、 - // 曜日名は ordinal から引く。 - text = dayOfWeekJp(d.ordinal), + // 曜日名は ordinal から引く。daysOfWeek() の並びは設定した + // firstDayOfWeek に従うため、ordinal で英語名を引く。 + text = dayOfWeekEn(d.ordinal), fontWeight = FontWeight.Medium, + color = MaterialTheme.colors.onSurface.copy(alpha = 0.85f), ) } } - Divider(Modifier.padding(vertical = 6.dp)) + // 罫線(参照画像の格子線に合わせた細い暗灰色) + Divider( + Modifier.padding(vertical = 6.dp), + color = MaterialTheme.colors.onSurface.copy(alpha = 0.20f), + ) HorizontalCalendar( modifier = Modifier.fillMaxWidth(), state = state, dayContent = { d -> DayCell(d, today = today, selected = selected, onClick = onDayClick) }, ) - Spacer(Modifier.height(8.dp)) - Text( - "予定ドットのある日をタップ", - style = MaterialTheme.typography.caption, - color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f), - ) + Spacer(Modifier.height(10.dp)) + // 下部中央のピル型 Close(参照画像)。日を選んでいない月表示では + // 閉じる対象が無いので、月の先頭へ戻す動作に割り当てる。 + Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { + Text( + "Close", + Modifier + .clip(RoundedCornerShape(50)) + .background(MaterialTheme.colors.secondary) + .clickable { + scope.launch { state.animateScrollToMonth(state.firstVisibleMonth.yearMonth) } + } + .padding(horizontal = 40.dp, vertical = 10.dp), + fontSize = 14.sp, + color = Color.White, + ) + } } } /** - * 日セル。設計 面3 の ASCII に従い「日付 + 選択枠 + 予定の点」だけを描く。 + * 日セル。参照画像(Calendar Library)に合わせる。 * - * 15 16 17 [18] 19 20 21 <-今日 - * 点=予定 日タップ->日表示(時間軸) + * +----------+ + * | 17 | <- 日付(上段) + * | ▬▬▬▬ | <- 予定の色バー(下辺、セル幅の約55%) + * | ▬▬▬▬ | 複数予定は縦積み(上から順) + * +----------+ * - * 予定の色バーは描かない(設計の ASCII には無い。バーを入れると - * 日付と重なる)。予定の有無は点で示す。 + * バーはセル内で日付の下の行に置くため、日付と重ならない。 + * 選択/今日はセルの地色で示し、予定バーはその上に描く。 */ @Composable private fun DayCell(day: CalendarDay, today: LocalDate, selected: LocalDate?, onClick: (CalendarDay) -> Unit) { val isMonthDate = day.position == DayPosition.MonthDate val isSelected = selected == day.date val isToday = day.date == today - val hasEvents = isMonthDate && (day.date.dayOfMonth % 5 == 0) + val events = if (isMonthDate) eventsOf(day.date) else emptyList() Column( Modifier .aspectRatio(1f) - .padding(3.dp) - .clip(RoundedCornerShape(8.dp)) + .padding(2.dp) + .clip(RoundedCornerShape(4.dp)) .then( when { isSelected -> Modifier.background(MaterialTheme.colors.primary) @@ -179,10 +255,11 @@ private fun DayCell(day: CalendarDay, today: LocalDate, selected: LocalDate?, on else -> Modifier }, ) - .clickable(enabled = isMonthDate) { onClick(day) }, + .clickable(enabled = isMonthDate) { onClick(day) } + .padding(top = 6.dp, bottom = 6.dp), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, ) { + // 上段: 日付 Text( text = day.date.dayOfMonth.toString(), fontSize = 14.sp, @@ -193,15 +270,18 @@ private fun DayCell(day: CalendarDay, today: LocalDate, selected: LocalDate?, on else -> MaterialTheme.colors.onSurface.copy(alpha = 0.35f) }, ) - // 予定の有無を示す点(日付と重ならないよう下段に分ける) - Text( - text = if (hasEvents) "•" else " ", - fontSize = 9.sp, - color = when { - isSelected || isToday -> Color.White - else -> MaterialTheme.colors.primary - }, - ) + Spacer(Modifier.weight(1f)) + // 下段: 予定の色バー。セル幅の約55%を中央に置く。 + for (e in events) { + Box( + Modifier + .padding(top = 2.dp) + .fillMaxWidth(0.55f) + .height(3.dp) + .clip(RoundedCornerShape(2.dp)) + .background(e.color), + ) + } } } |
