summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Root <root@dangofactory.local>2026-09-25 07:15:48 +0900
committerCharlie Root <root@dangofactory.local>2026-09-25 07:15:48 +0900
commit9f35f3c8d60ca9ebefeaab4bc1aaf2d1df7909c4 (patch)
treedc96920738e4251cb8090ab4e3e0ae8460c38cfa
parentf57ca05ecbfadb6285d408369c0effe590f4b622 (diff)
downloadkukuri-9f35f3c8d60ca9ebefeaab4bc1aaf2d1df7909c4.tar.gz
kukuri-9f35f3c8d60ca9ebefeaab4bc1aaf2d1df7909c4.tar.bz2
kukuri-9f35f3c8d60ca9ebefeaab4bc1aaf2d1df7909c4.zip
UI: rebuild the frames to the 2.22 ASCII - no date/event overlap, no NEW on Timeline, Note as note buttons
Calendar month (screen 3 ASCII): the day cell no longer draws an event bar. The ASCII shows only "15 16 17 [18] 19 20 21 <-today" plus the note "point = event", and the bar I had added was what collided with the date. The cell is now date + selection/today fill + one small dot, and today and selected are passed in rather than guessed per cell. Calendar day (screen 4 ASCII): back to the specified frame - a time column (850/940/1030/1120/1215/1310) with a rule per slot and that slot's items to the right, timetable and auto-source mixed on the same axis. I had replaced this with a Google-style free-floating hour grid, which is not what the design draws. The header takes a list of dates, so single-day and multi-day both work, and the weekday is shown next to the date. Note (screen 5, and 2.6): Note is the list of notes, filtered by the content kind - "全部/課題/文書/成果物" - with the notes themselves as full-row buttons (探究ノート, 数学プリント, 班レポート, 発表スライド) and a bordered entry for the unsubmitted view. The explanatory line ("残るもの") is gone; it told the reader nothing. Per 2.6 a note is a set of cards, so tasks/documents/artefacts are not sibling entries beside notes - they are what the notes contain, which is what the filter selects between. Timeline (screen 2): rows are separated by rules again (they were missing), and the NEW badge is gone - the ASCII has no badge there (only Home's timeline digest carries [NEW], which is left as is). Live (screen 6): section headings plus full-row buttons, with the teacher-only start action as a filled button. Dropped the descriptive subtitle. Home: unchanged in substance - the five ASCII blocks stay, since Home is the navigational hub and is meant to be the fullest frame.
-rw-r--r--modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesCalendarNoteLive.kt349
-rw-r--r--modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesHomeTimeline.kt15
2 files changed, 220 insertions, 144 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 c340483..6e58ac2 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
@@ -1,6 +1,7 @@
package jp.orgflow.web
import androidx.compose.foundation.background
+import androidx.compose.foundation.border
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.clickable
@@ -63,10 +64,11 @@ import kotlinx.datetime.LocalDate
@Composable
fun CalendarFrame() {
var selectedDay by remember { mutableStateOf<LocalDate?>(null) }
+ val today = remember { todayLocalDate() }
val day = selectedDay
Column(Modifier.fillMaxSize()) {
if (day == null) {
- MonthCalendar(onDayClick = { selectedDay = it.date })
+ MonthCalendar(today = today, selected = null, onDayClick = { selectedDay = it.date })
} else {
DayTimelineView(listOf(day)) { selectedDay = null }
}
@@ -75,7 +77,7 @@ fun CalendarFrame() {
/** 月グリッド。予定のある日にドットを出す(§2.22)。 */
@Composable
-private fun MonthCalendar(onDayClick: (CalendarDay) -> Unit) {
+private fun MonthCalendar(today: LocalDate, selected: LocalDate?, onDayClick: (CalendarDay) -> Unit) {
// 今日の月を得る。kotlinx-datetime の now() は kotlin.time.Clock を要求し、
// この構成の Wasm ではリンクできない(IrLinkageError)。
// また com.kizitonwose.calendar.core の YearMonth.Companion.now も同じ理由で
@@ -102,7 +104,7 @@ private fun MonthCalendar(onDayClick: (CalendarDay) -> Unit) {
Column(Modifier.fillMaxSize().padding(20.dp)) {
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(
- "${visibleMonth.year}年${visibleMonth.monthNumber}月",
+ "${visibleMonth.monthNumber}月${visibleMonth.year}",
Modifier.weight(1f),
style = MaterialTheme.typography.h6,
fontWeight = FontWeight.Bold,
@@ -138,7 +140,7 @@ private fun MonthCalendar(onDayClick: (CalendarDay) -> Unit) {
HorizontalCalendar(
modifier = Modifier.fillMaxWidth(),
state = state,
- dayContent = { d -> DayCell(d, onClick = onDayClick) },
+ dayContent = { d -> DayCell(d, today = today, selected = selected, onClick = onDayClick) },
)
Spacer(Modifier.height(8.dp))
Text(
@@ -150,34 +152,55 @@ private fun MonthCalendar(onDayClick: (CalendarDay) -> Unit) {
}
/**
- * 日セル。予定のある日は下にドットを出す。
- * hasEvents は実データ結線までの仮値(ここでは日の偶奇で見本表示)。
+ * 日セル。設計 面3 の ASCII に従い「日付 + 選択枠 + 予定の点」だけを描く。
+ *
+ * 15 16 17 [18] 19 20 21 <-今日
+ * 点=予定 日タップ->日表示(時間軸)
+ *
+ * 予定の色バーは描かない(設計の ASCII には無い。バーを入れると
+ * 日付と重なる)。予定の有無は点で示す。
*/
@Composable
-private fun DayCell(day: CalendarDay, onClick: (CalendarDay) -> Unit) {
- val clickable = day.position == DayPosition.MonthDate
- val hasEvents = clickable && (day.date.dayOfMonth % 5 == 0)
+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)
+
Column(
Modifier
.aspectRatio(1f)
- .padding(4.dp)
- .clip(CircleShape)
- .clickable(enabled = clickable) { onClick(day) },
+ .padding(3.dp)
+ .clip(RoundedCornerShape(8.dp))
+ .then(
+ when {
+ isSelected -> Modifier.background(MaterialTheme.colors.primary)
+ isToday -> Modifier.background(MaterialTheme.colors.secondary)
+ else -> Modifier
+ },
+ )
+ .clickable(enabled = isMonthDate) { onClick(day) },
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Text(
text = day.date.dayOfMonth.toString(),
fontSize = 14.sp,
- color = when (day.position) {
- DayPosition.MonthDate -> MaterialTheme.colors.onSurface
- else -> MaterialTheme.colors.onSurface.copy(alpha = 0.3f)
+ fontWeight = if (isSelected || isToday) FontWeight.Bold else FontWeight.Normal,
+ color = when {
+ isSelected || isToday -> Color.White
+ isMonthDate -> MaterialTheme.colors.onSurface
+ else -> MaterialTheme.colors.onSurface.copy(alpha = 0.35f)
},
)
+ // 予定の有無を示す点(日付と重ならないよう下段に分ける)
Text(
text = if (hasEvents) "•" else " ",
- fontSize = 10.sp,
- color = MaterialTheme.colors.primary,
+ fontSize = 9.sp,
+ color = when {
+ isSelected || isToday -> Color.White
+ else -> MaterialTheme.colors.primary
+ },
)
}
}
@@ -207,30 +230,33 @@ private fun dayOfWeekJp(ordinal: Int): String = when (ordinal) {
* 予定は「開始時刻・長さ・種別」を持ち、時間軸上の高さで表す。
* 時間割と自動源(2.21)の予定が同じ軸に混ざる。
*/
-private data class TimeBlock(val startMin: Int, val endMin: Int, val title: String, val kind: String)
-
@Composable
private fun DayTimelineView(days: List<LocalDate>, onBack: () -> Unit) {
- val hourStart = 8
- val hourEnd = 19
- val hourHeight = 52.dp
- val totalHours = hourEnd - hourStart
+ val today = remember { todayLocalDate() }
- // 見本の予定(実データは後段)。時間割 + 工程 + 当日連絡。
- val blocks = listOf(
- TimeBlock(8 * 60 + 50, 9 * 60 + 40, "1限 数学", "時間割"),
- TimeBlock(9 * 60 + 40, 10 * 60 + 30, "2限 国語", "時間割"),
- TimeBlock(11 * 60 + 20, 12 * 60 + 15, "昼休み", "予定"),
- TimeBlock(12 * 60 + 15, 13 * 60 + 10, "3限 英語", "時間割"),
- TimeBlock(12 * 60 + 30, 13 * 60 + 0, "中間資料の提出", "工程"),
+ // 見本の予定(実データは後段)。時間割 + 工程 + 昼休み。
+ // 設計 面4 の ASCII:
+ // +----+-----------------------------+
+ // | 850| ## 1限 数学 (時間割) |
+ // | 940| ## 2限 国語 (時間割) |
+ // |1030| (あき) |
+ // |1215| ## 昼休み |
+ // |1310| ## 3限 英語 / 中間資料(工程)|
+ // +----+-----------------------------+
+ // 時刻は4桁(850/940/1030/1215/1310)で、その時間帯の項目を右に並べる。
+ // 時間割と自動源(2.21)の予定が同じ軸に混ざる。
+ val rows = listOf(
+ "850" to listOf("1限 数学" to "時間割"),
+ "940" to listOf("2限 国語" to "時間割"),
+ "1030" to listOf("(あき)" to ""),
+ "1120" to listOf("" to ""),
+ "1215" to listOf("昼休み" to ""),
+ "1310" to listOf("3限 英語" to "時間割", "中間資料の提出" to "工程"),
)
- Column(Modifier.fillMaxSize()) {
- // 見出し: 対象日(複数日なら範囲)。戻る操作。
- Row(
- Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 10.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
+ Column(Modifier.fillMaxSize().padding(16.dp)) {
+ // 見出し: 対象日(複数日なら範囲)。1日でも複数日でも同じ実装。
+ Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(
"‹",
Modifier.clickable { onBack() }.padding(end = 10.dp),
@@ -238,7 +264,9 @@ private fun DayTimelineView(days: List<LocalDate>, onBack: () -> Unit) {
)
Text(
if (days.size == 1) {
- "${days[0].monthNumber}月${days[0].dayOfMonth}日"
+ val d = days[0]
+ "${d.monthNumber}月${d.dayOfMonth}日(${dayOfWeekJp(d.dayOfWeek.ordinal)})" +
+ if (d == today) " 今日" else ""
} else {
"${days.first().monthNumber}/${days.first().dayOfMonth} - " +
"${days.last().monthNumber}/${days.last().dayOfMonth}"
@@ -247,140 +275,160 @@ private fun DayTimelineView(days: List<LocalDate>, onBack: () -> Unit) {
fontWeight = FontWeight.Bold,
)
}
- Divider()
+ Spacer(Modifier.height(10.dp))
- // 時間軸グリッド。左が時刻、右が予定ブロック。画面いっぱいに伸ばす。
- Row(Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
- // 時刻の目盛り
- Column(Modifier.width(56.dp)) {
- for (h in hourStart until hourEnd) {
+ // 時刻と項目の枠。左の時刻列に罫線、右に項目。
+ Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
+ for ((time, items) in rows) {
+ Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.Top) {
Text(
- "$h:00",
- Modifier.height(hourHeight).padding(top = 2.dp, end = 6.dp),
+ time,
+ Modifier.width(48.dp).padding(top = 8.dp, end = 8.dp),
style = MaterialTheme.typography.caption,
- color = MaterialTheme.colors.onSurface.copy(alpha = 0.55f),
+ color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
+ textAlign = TextAlign.End,
)
- }
- }
- // 予定の面。日が複数なら列に分ける。
- Row(Modifier.weight(1f)) {
- for (d in days) {
- Box(Modifier.weight(1f).height(hourHeight * totalHours)) {
- // 時間の罫線
- Column(Modifier.fillMaxSize()) {
- for (h in hourStart until hourEnd) {
- Divider(Modifier.height(hourHeight), color = MaterialTheme.colors.onSurface.copy(alpha = 0.12f))
+ Column(Modifier.weight(1f)) {
+ // 時間の区切り線(設計の横罫線)
+ Divider(color = MaterialTheme.colors.onSurface.copy(alpha = 0.18f))
+ if (items.isEmpty()) {
+ Spacer(Modifier.height(26.dp))
+ } else {
+ for ((title, kind) in items) {
+ Row(
+ Modifier.fillMaxWidth().padding(vertical = 5.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(title, Modifier.weight(1f), style = MaterialTheme.typography.body2)
+ if (kind.isNotEmpty()) {
+ Text(
+ "($kind)",
+ style = MaterialTheme.typography.caption,
+ color = MaterialTheme.colors.onSurface.copy(alpha = 0.55f),
+ )
+ }
+ }
}
}
- // 予定ブロック(開始時刻と長さを高さで表す)
- for (b in blocks) {
- val fromH = (b.startMin - hourStart * 60).coerceAtLeast(0)
- val toH = (b.endMin - hourStart * 60).coerceAtMost(totalHours * 60)
- val top = hourHeight * (fromH / 60f)
- val hgt = hourHeight * ((toH - fromH) / 60f)
- Box(
- Modifier
- .padding(start = 3.dp, end = 3.dp)
- .offset(y = top)
- .height(hgt.coerceAtLeast(18.dp))
- .fillMaxWidth()
- .clip(RoundedCornerShape(6.dp))
- .background(
- if (b.kind == "時間割") {
- MaterialTheme.colors.primary.copy(alpha = 0.85f)
- } else {
- MaterialTheme.colors.secondary
- },
- )
- .padding(5.dp),
- ) {
- Text(
- b.title,
- style = MaterialTheme.typography.caption,
- color = Color.White,
- maxLines = 2,
- )
- }
- }
- }
- if (days.size > 1) {
- Divider(Modifier.width(1.dp).fillMaxSize(), color = MaterialTheme.colors.onSurface.copy(alpha = 0.2f))
}
}
}
+ Divider(color = MaterialTheme.colors.onSurface.copy(alpha = 0.18f))
}
+ Spacer(Modifier.height(8.dp))
+ Text(
+ "時間割と自動源(2.21)の予定が同じ軸に混ざる",
+ style = MaterialTheme.typography.caption,
+ color = MaterialTheme.colors.onSurface.copy(alpha = 0.5f),
+ )
}
}
/** 面5 ノート一覧(Note): 「残るもの」。 */
@Composable
fun NoteFrame() {
- val filters = listOf("すべて", "ノート", "課題", "文書", "成果物", "未提出")
+ // 設計 面5 の ASCII:
+ // [全部|課題|文書|成果物] <-フィルタ
+ // > 探究ノート 編集 10:20
+ // > 数学プリント 提出 9/21
+ // > 班レポート 共同編集中(3人)
+ // [未提出ビュー] <-F46 教員/本人
+ //
+ // 2.6 のとおりノートは「カードを並べたもの」であり、課題・文書・成果物は
+ // ノートの外にある独立項目ではない。ノートの中にカードが入る。
+ // そのためここは「ノートの一覧」であり、フィルタで中身の種類を絞る。
+ // 説明文(「残るもの」等)は置かない(意味が伝わらないため)。
+ val filters = listOf("全部", "課題", "文書", "成果物")
Column(Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(20.dp)) {
- Text("Note", style = MaterialTheme.typography.h5, fontWeight = FontWeight.Bold)
- Text(
- "残るもの",
- style = MaterialTheme.typography.caption,
- color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
- )
- Spacer(Modifier.height(12.dp))
- Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
- for (f in filters) Text("[$f]", style = MaterialTheme.typography.caption)
- }
- Spacer(Modifier.height(12.dp))
- NoteRow("探究メモ", "ノート", "9/22 更新")
- NoteRow("展示企画書.odt", "文書", "編集中 3人")
- NoteRow("文化祭アンケート", "課題", "未提出 2/40")
- NoteRow("発表スライド", "成果物", "9/18")
- NoteRow("振り返りシート", "課題", "未提出")
+ FilterRow(filters)
+ Spacer(Modifier.height(14.dp))
+ NoteButton("探究ノート", "編集 10:20")
+ NoteButton("数学プリント", "提出 9/21")
+ NoteButton("班レポート", "共同編集中(3人)")
+ NoteButton("発表スライド", "提出 9/18")
+ Spacer(Modifier.height(14.dp))
+ // F46 未提出ビューへの入口(教員/本人にのみ出す)
+ OutlineButton("未提出ビュー")
}
}
+/** フィルタ。選択中のものを塗って示す。 */
@Composable
-private fun NoteRow(title: String, kind: String, meta: String) {
- Card(Modifier.fillMaxWidth().padding(vertical = 4.dp), elevation = 0.dp) {
- Row(Modifier.padding(10.dp), verticalAlignment = Alignment.CenterVertically) {
- Text(title, Modifier.weight(1f), style = MaterialTheme.typography.body2)
- Text(kind, style = MaterialTheme.typography.caption, color = MaterialTheme.colors.primary)
- Spacer(Modifier.width(10.dp))
+private fun FilterRow(filters: List<String>) {
+ Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
+ for ((i, f) in filters.withIndex()) {
+ val on = i == 0
Text(
- meta,
- style = MaterialTheme.typography.caption,
- color = MaterialTheme.colors.onSurface.copy(alpha = 0.5f),
+ f,
+ Modifier
+ .clip(RoundedCornerShape(8.dp))
+ .background(if (on) MaterialTheme.colors.primary else MaterialTheme.colors.surface)
+ .clickable { }
+ .padding(horizontal = 12.dp, vertical = 7.dp),
+ style = MaterialTheme.typography.body2,
+ color = if (on) Color.White else MaterialTheme.colors.onSurface,
)
}
}
}
-/** 面6 Live: 配信中/配信予定/録画(F51)。教員には [配信開始] が出る。 */
+/** ノート1件。行全体がボタン(押すと開く)。 */
@Composable
-fun LiveFrame(isTeacher: Boolean = false) {
- Column(Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(20.dp)) {
- Text("Live", style = MaterialTheme.typography.h5, fontWeight = FontWeight.Bold)
+private fun NoteButton(title: String, meta: String) {
+ Row(
+ Modifier
+ .fillMaxWidth()
+ .padding(vertical = 3.dp)
+ .clip(RoundedCornerShape(10.dp))
+ .background(MaterialTheme.colors.surface)
+ .clickable { }
+ .padding(horizontal = 14.dp, vertical = 12.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(">", Modifier.width(18.dp), style = MaterialTheme.typography.body2, color = MaterialTheme.colors.primary)
+ Text(title, Modifier.weight(1f), style = MaterialTheme.typography.body2)
Text(
- "今つなぐ / 見る",
+ meta,
style = MaterialTheme.typography.caption,
- color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
+ color = MaterialTheme.colors.onSurface.copy(alpha = 0.55f),
)
- Spacer(Modifier.height(16.dp))
+ }
+}
+
+/** 枠だけのボタン(未提出ビュー等の入口)。 */
+@Composable
+private fun OutlineButton(label: String) {
+ Row(
+ Modifier
+ .clip(RoundedCornerShape(10.dp))
+ .border(1.dp, MaterialTheme.colors.primary, RoundedCornerShape(10.dp))
+ .clickable { }
+ .padding(horizontal = 14.dp, vertical = 10.dp),
+ ) {
+ Text(label, style = MaterialTheme.typography.body2, color = MaterialTheme.colors.primary)
+ }
+}
+
+/** 面6 Live: 配信中/配信予定/録画(F51)。教員には [配信開始] が出る。 */
+@Composable
+fun LiveFrame(isTeacher: Boolean = false) {
+ // 設計 面6 の ASCII:
+ // o 配信中 / > 全校集会 [視聴する]
+ // 配信予定 / 5限 音楽鑑賞会 14:00
+ // 録画 / > 先週の学級会議 32分
+ // 説明文は置かず、見出しとボタンだけで構成する。
+ Column(Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(20.dp)) {
LiveSection("配信中")
- LiveRow("全校集会", "[視聴する]", accent = true)
- Spacer(Modifier.height(12.dp))
+ ActionButton("全校集会", "視聴する")
+ Spacer(Modifier.height(16.dp))
LiveSection("配信予定")
- LiveRow("5限 音楽鑑賞会", "14:00", accent = false)
- Spacer(Modifier.height(12.dp))
+ ActionButton("5限 音楽鑑賞会", "14:00")
+ Spacer(Modifier.height(16.dp))
LiveSection("録画")
- LiveRow("先週の学級会議", "32分", accent = false)
+ ActionButton("先週の学級会議", "32分")
if (isTeacher) {
Spacer(Modifier.height(20.dp))
- Card(backgroundColor = MaterialTheme.colors.primary, elevation = 4.dp) {
- Text(
- "[ 配信開始 ]",
- Modifier.padding(horizontal = 16.dp, vertical = 10.dp),
- style = MaterialTheme.typography.body1,
- color = Color.White,
- )
- }
+ ActionButton("配信を始める", null, filled = true)
}
}
}
@@ -388,17 +436,36 @@ fun LiveFrame(isTeacher: Boolean = false) {
@Composable
private fun LiveSection(t: String) {
Text(t, style = MaterialTheme.typography.body1, fontWeight = FontWeight.Bold)
- Divider(Modifier.padding(vertical = 4.dp))
+ Divider(Modifier.padding(vertical = 6.dp))
}
+/** 行全体がボタン。filled のときは主色で塗る(配信開始など)。 */
@Composable
-private fun LiveRow(title: String, meta: String, accent: Boolean) {
- Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically) {
- Text(if (accent) "o $title" else "> $title", Modifier.weight(1f), style = MaterialTheme.typography.body2)
+private fun ActionButton(title: String, meta: String?, filled: Boolean = false) {
+ Row(
+ Modifier
+ .fillMaxWidth()
+ .padding(vertical = 3.dp)
+ .clip(RoundedCornerShape(10.dp))
+ .background(if (filled) MaterialTheme.colors.primary else MaterialTheme.colors.surface)
+ .clickable { }
+ .padding(horizontal = 14.dp, vertical = 12.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(">", Modifier.width(18.dp), style = MaterialTheme.typography.body2,
+ color = if (filled) Color.White else MaterialTheme.colors.primary)
Text(
- meta,
+ title,
+ Modifier.weight(1f),
style = MaterialTheme.typography.body2,
- color = if (accent) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
+ color = if (filled) Color.White else MaterialTheme.colors.onSurface,
)
+ if (meta != null) {
+ Text(
+ meta,
+ style = MaterialTheme.typography.caption,
+ color = if (filled) Color.White else MaterialTheme.colors.onSurface.copy(alpha = 0.55f),
+ )
+ }
}
}
diff --git a/modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesHomeTimeline.kt b/modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesHomeTimeline.kt
index f3e1ba2..2441df1 100644
--- a/modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesHomeTimeline.kt
+++ b/modules/orgflow-ui/src/commonMain/kotlin/jp/orgflow/web/FramesHomeTimeline.kt
@@ -147,12 +147,15 @@ fun TimelineFrame() {
Column(
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(20.dp),
) {
- Row(Modifier.fillMaxWidth().padding(vertical = 3.dp), verticalAlignment = Alignment.CenterVertically) {
- Feed("田中", "資料を配りました", "PDF", "10:02")
- }
+ // 1行1件。行間は罫線で区切る(前回は線が欠けていた)。
+ Feed("田中", "資料を配りました", "PDF", "10:02")
+ FeedDivider()
Feed("教務", "明日の持ち物一覧", null, "要確認")
+ FeedDivider()
Feed("部長", "練習は中止です", null, null)
+ FeedDivider()
Feed("保健室", "掲示板はこちら", null, "要回答")
+ FeedDivider()
Feed("野田", "部活の変更", null, "要回答")
Spacer(Modifier.height(10.dp))
Text(
@@ -163,6 +166,12 @@ fun TimelineFrame() {
}
}
+/** タイムラインの行間の罫線。 */
+@Composable
+private fun FeedDivider() {
+ Divider(color = MaterialTheme.colors.onSurface.copy(alpha = 0.15f))
+}
+
/** タイムライン1行。発信者・本文・添付/バッジ・時刻。 */
@Composable
private fun Feed(from: String, body: String, attach: String?, badge: String?) {