diff --git a/README.md b/README.md index 9c83fbf..1b946fc 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ Moving an existing shadcn (Radix) app over: see [MIGRATING.md](MIGRATING.md) for | `focus` | `registry:block` | The one loud thing on a page, under its header: a label, a title with a highlight and a row of facts | | `avatar-stack` | `registry:block` | Several people in the space of one; the avatars spread apart when pointed at | | `countdown` | `registry:block` | Time left until a moment, to the minute, with rolling digits | -| `week-calendar` | `registry:block` | One week as a time grid like the week view of Calendar: hours down the side (08:00 to 20:00, stretching to fit), timed events as blocks from start to end side by side where they overlap, all-day events as pills above, today circled; one row per day below `md` | +| `week-calendar` | `registry:block` | One week as a time grid like the week view of Calendar: hours down the side (08:00 to 20:00, stretching to fit), timed events as blocks from start to end (a later overlapping one stacks on top, indented, as in Calendar), the full title and time in a tooltip, all-day events as pills above, today circled; one row per day below `md` | | `claude-code` | `registry:block` | Claude Code's screen in a `terminal` for demos and install guides: welcome, prompts, MCP calls, permission questions, the `/plugins` menus (marketplaces, the plugin list with its search box, plugin details) and `/mcp`; content through props; colors are `claude-*` tokens from Claude Code's dark theme | | `typing` | `registry:lib` | Timed keystrokes for typing animations: a steady pace (100ms a key, about 120 WPM) with jitter; Chinese typed as zhuyin that turns into the character on its tone key; `InputBox` shows the zhuyin with `composing` | | `expand-row` | `registry:block` | A list row that opens in place to show its details | diff --git a/app/_docs/demos/week-calendar.tsx b/app/_docs/demos/week-calendar.tsx index f863093..23a32d6 100644 --- a/app/_docs/demos/week-calendar.tsx +++ b/app/_docs/demos/week-calendar.tsx @@ -3,8 +3,13 @@ import { WeekCalendar } from "@/registry/winlab/blocks/week-calendar/week-calend const at = (day: string, time: string) => `2026-11-${day}T${time}:00+08:00` const events = [ - { title: "Lab Meeting", start: at("02", "15:30"), end: at("02", "17:30") }, + { title: "Lab Meeting", start: at("02", "15:30"), end: at("02", "18:30") }, { title: "實驗討論", start: at("02", "16:00"), end: at("02", "17:00") }, + { + title: "[nycu-robotics]-確認工作事項", + start: at("02", "17:30"), + end: at("02", "18:30"), + }, { title: "專題討論", start: at("02", "19:30"), end: at("02", "20:30") }, { title: "6G 雙週會議", start: at("03", "10:00"), end: at("03", "11:00") }, { diff --git a/registry.json b/registry.json index 77da67f..3f79360 100644 --- a/registry.json +++ b/registry.json @@ -1302,7 +1302,8 @@ "cn" ], "registryDependencies": [ - "https://ui.winlab.tw/r/utils.json" + "https://ui.winlab.tw/r/utils.json", + "https://ui.winlab.tw/r/tooltip.json" ], "files": [ { diff --git a/registry/winlab/blocks/week-calendar/week-calendar.tsx b/registry/winlab/blocks/week-calendar/week-calendar.tsx index aed3751..f3872cf 100644 --- a/registry/winlab/blocks/week-calendar/week-calendar.tsx +++ b/registry/winlab/blocks/week-calendar/week-calendar.tsx @@ -1,6 +1,11 @@ import * as React from "react" import { cn } from "@/registry/winlab/lib/utils" +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/registry/winlab/ui/tooltip" export type WeekEvent = { /** Unique within the week; defaults to start, end and title. */ @@ -36,12 +41,13 @@ type Block = { event: Placed from: number to: number - lane: number - lanes: number + /** How many earlier events it sits on; each one indents it 1rem. */ + depth: number } -// The timed events of one day, cut to the day, side by side where they -// overlap: each cluster of overlapping events shares the column in lanes. +// The timed events of one day, cut to the day. Where events overlap, the +// later one sits on top of the earlier, indented by one step, the way +// Calendar stacks them, so each keeps most of the column's width. function blocks(day: string, events: Placed[]): Block[] { const items = events .filter((e) => !e.allDay && e.first <= day && e.last >= day) @@ -49,34 +55,21 @@ function blocks(day: string, events: Placed[]): Block[] { event, from: event.first === day ? event.startMinute : 0, to: event.last === day ? event.endMinute : FULL, - lane: 0, - lanes: 1, + depth: 0, })) .sort((a, b) => a.from - b.from || b.to - a.to) - let cluster: typeof items = [] - let clusterEnd = -1 - const close = () => { - const lanes = Math.max(...cluster.map((item) => item.lane)) + 1 - for (const item of cluster) item.lanes = lanes - } - for (const item of items) { - if (item.from >= clusterEnd && cluster.length) { - close() - cluster = [] - } - const taken = new Set( - cluster.filter((other) => other.to > item.from).map((o) => o.lane) - ) - while (taken.has(item.lane)) item.lane++ - cluster.push(item) - clusterEnd = Math.max(clusterEnd, item.to) - } - if (cluster.length) close() + items.forEach((item, index) => { + const under = items.slice(0, index).filter((other) => other.to > item.from) + item.depth = under.length + ? Math.max(...under.map((other) => other.depth)) + 1 + : 0 + }) return items } // One week the way the week view of Calendar draws it: days in columns, -// hours down the side, each timed event a block from its start to its end, +// hours down the side, each timed event a block from its start to its end +// (overlaps stack, indented), the whole title and time in its tip, // all-day events as pills above the hours. The hours run 08:00 to 20:00 and // stretch to fit any event outside them. Today's date sits in a primary // circle. Below md the columns fold into one row per day, listing events. @@ -154,7 +147,7 @@ function WeekCalendar({ .flatMap(({ timed }, d) => timed.map( (b, i) => - `[data-week-scope=${scope}] [data-block="${d}-${i}"] { --top: ${percent(b.from - startHour * 60)}; --height: ${percent(b.to - b.from)}; --left: ${((b.lane / b.lanes) * 100).toFixed(3)}%; --width: ${(100 / b.lanes).toFixed(3)}%; }` + `[data-week-scope=${scope}] [data-block="${d}-${i}"] { --top: ${percent(b.from - startHour * 60)}; --height: ${percent(b.to - b.from)}; --left: ${b.depth}rem; --width: calc(100% - ${b.depth}rem); }` ) ) .join("\n") @@ -177,15 +170,23 @@ function WeekCalendar({ ) const pill = (event: Placed) => ( -