diff --git a/docs/contracts/_ui.json b/docs/contracts/_ui.json
index 00f6f704a..2ae346d84 100644
--- a/docs/contracts/_ui.json
+++ b/docs/contracts/_ui.json
@@ -1,5 +1,5 @@
{
- "Layout Principles": "* Put reading-first content in the left/main column: introductions, descriptions, markdown, homework content, and comments.\n* Put structured facts in the right/side column: identifiers, metadata, dates, counts, actions, mini calendars, and quick links.\n* On mobile, stack in that order.\n* Reuse existing grids, cards, borders, muted text, and buttons.\n* Popups with discussion use details on the left and discussion on the right on desktop; stack on mobile.",
+ "Layout Principles": "* Put reading-first content in the left/main column: introductions, descriptions, markdown, homework content, and comments.\n* Put structured facts in the right/side column: identifiers, metadata, dates, counts, actions, mini calendars, and quick links.\n* On mobile, stack in that order.\n* Reuse existing grids, cards, borders, muted text, and buttons.\n* Popups are one scrollable column at a comfortable reading width, not a two-column page. Keep the title in a sticky header. Lead with one primary fact (due datetime) and one secondary line (relative urgency), then list remaining overlay facts in a table, then reading, then discussion. Do not add a status side column, chip row, or nested collapsible inside the overlay. Side rails belong on pages, not in overlays.",
"List Table": "* Used for discovery lists such as courses, sections, and teachers.\n* Primary names follow the active locale; an available alternate localized name is secondary text.\n* Structured fields support comparison.\n* Rows link to detail pages.\n* Across viewport widths, one prominent search remains directly available, advanced filters open in an accessible sheet, and active filters remain removable above results.\n* Compact layouts use cards that avoid page-level horizontal scrolling; wide desktop layouts keep every comparison-table column inside the results container without horizontal scrolling.\n* Pagination uses URL-driven Previous, page, and Next links while preserving filters.",
"Data Table Cells": "* Desktop data-table rows keep a consistent compact height; optional secondary lines reserve space when absent.\n* Overflowing text is truncated, with its full value available from a tooltip on pointer hover and keyboard focus.\n* Course and section codes use plain monospace text, never badge styling.\n* Header labels and cell content share the same column edge; textual and categorical values align left, while numeric measures and counts align right.\n* Blank placeholders are hidden from assistive technology and do not replace meaningful labels such as unknown or TBD.\n* Numeric, status, control, and action cells do not receive truncation tooltips when their content fits.",
"Detail Hero": "* Used at the top of course, section, and teacher detail pages.\n* Contains breadcrumb, h1, and an optional subtitle.\n* h1 uses the primary display name of the current object, not an internal ID.\n* At mobile widths, stable public identifiers and concise metadata precede a responsive title so long localized names do not crowd out context or actions.",
diff --git a/docs/contracts/homework.json b/docs/contracts/homework.json
index 7b228a104..33d76db18 100644
--- a/docs/contracts/homework.json
+++ b/docs/contracts/homework.json
@@ -80,7 +80,7 @@
"filter: incomplete/completed/all",
"mobile compact toolbar with direct completion filters and overflow display-mode control",
"cards/list view mode persisted in browser storage",
- "detail popup order: description, due summary, vertical metadata excluding platform createdAt, action controls, discussion; desktop places discussion to the right of the details",
+ "detail popup is one scrollable column: due datetime, relative urgency, remaining facts in a table excluding platform createdAt, then description, then full-width discussion; completion stays in the footer; do not use a two-column overlay",
"create form exposes the collapsible advisory homework title and description style guide"
]
}
@@ -247,7 +247,7 @@
"user completion status",
"edit action",
"cards/list view mode persisted in browser storage",
- "detail popup order: description, due summary, vertical metadata excluding platform createdAt, edit/completion controls, inline discussion; desktop places discussion to the right of the details",
+ "detail popup is one scrollable column: due datetime is primary, relative urgency is secondary, remaining facts (status, tags, publication, submission opens) are a table that does not repeat due date or platform createdAt, then description, then full-width discussion; edit/completion stay in the footer; do not use a two-column overlay",
"section cards use a responsive multi-column layout",
"create and edit forms expose the same collapsible advisory homework title and description style guide"
]
diff --git a/docs/contracts/todo.json b/docs/contracts/todo.json
index 649792b91..8a05d87ca 100644
--- a/docs/contracts/todo.json
+++ b/docs/contracts/todo.json
@@ -136,6 +136,7 @@
"todo.content (description)",
"todo.priority",
"todo.dueAt",
+ "detail popup stacks title, then due datetime, relative urgency, a table of remaining facts (priority, completion), then content; completion/edit/delete stay in the footer",
"completed status action button",
"filter: incomplete/completed/all",
"mobile compact toolbar with direct completion filters and overflow display-mode control"
diff --git a/messages/en-us.json b/messages/en-us.json
index 81e3bda64..2b174ad31 100644
--- a/messages/en-us.json
+++ b/messages/en-us.json
@@ -2263,6 +2263,7 @@
"contentPlaceholder": "Supports Markdown formatting",
"contentEmpty": "No description added.",
"priorityLabel": "Priority",
+ "statusLabel": "Status",
"dueAtLabel": "Due date",
"dueAtPlaceholder": "Optional date and time",
"dueLabel": "Due",
diff --git a/messages/zh-cn.json b/messages/zh-cn.json
index 61ed99b61..6b0d33397 100644
--- a/messages/zh-cn.json
+++ b/messages/zh-cn.json
@@ -2229,6 +2229,7 @@
"contentPlaceholder": "支持 Markdown 格式",
"contentEmpty": "暂无内容",
"priorityLabel": "优先级",
+ "statusLabel": "状态",
"dueAtLabel": "截止时间",
"dueAtPlaceholder": "选择截止时间(可选)",
"dueLabel": "截止",
diff --git a/src/features/dashboard/components/TodoDetailDialog.svelte b/src/features/dashboard/components/TodoDetailDialog.svelte
index 34f2388ea..369a17195 100644
--- a/src/features/dashboard/components/TodoDetailDialog.svelte
+++ b/src/features/dashboard/components/TodoDetailDialog.svelte
@@ -8,18 +8,22 @@ import type {
} from "@/features/dashboard/lib/dashboard-controller-helpers";
import MarkdownPreview from "$lib/components/MarkdownPreview.svelte";
import * as AlertDialog from "$lib/components/ui/alert-dialog/index.js";
-import { Badge } from "$lib/components/ui/badge/index.js";
import { Button, buttonVariants } from "$lib/components/ui/button/index.js";
import * as Dialog from "$lib/components/ui/dialog/index.js";
import { ScrollArea } from "$lib/components/ui/scroll-area/index.js";
import { Separator } from "$lib/components/ui/separator/index.js";
import { Spinner } from "$lib/components/ui/spinner/index.js";
+import * as Table from "$lib/components/ui/table/index.js";
import { cn } from "$lib/utils.js";
export let deleteTodo: (todo: DashboardTodoItem) => void | Promise;
export let fmtDate: (value: string | Date | null | undefined) => string;
+export let isDueOverdue: (value: string | Date | null | undefined) => boolean;
export let onClose: () => void;
export let openTodoEditor: (todo: DashboardTodoItem) => void;
+export let relativeDueLabel: (
+ value: string | Date | null | undefined,
+) => string;
export let todo: DashboardTodoItem | null;
export let todoActionLabel: (todo: DashboardTodoItem) => string;
export let todoSavingById: Record;
@@ -62,22 +66,63 @@ async function confirmDelete(event: MouseEvent) {
-
+ {todo.title}
-
+
{todosCopy.priority[todo.priority]} · {fmtDate(todo.dueAt)}