npm

Reference

Calendar

A demo appointments calendar at /calendar with three views: Month, Week, and Day. It has an AM/PM hour grid with a live current-time line, event blocks that span their own duration, Google-style color labels, and a clean add dialog, all built from Dialog, Input, Select, Checkbox and date-fns. No calendar dependency, no hand-rolled table, no custom time picker.

See it live

Open /calendar in the app. Switch views with the segmented control (top-right), click any day (Month) or hour cell (Week/Day) to add, and click an event to remove it.

Views

  • Month is a 6-week grid. Each day shows up to three event chips with a +N more overflow; hover a day for its add (+) button.
  • Week is seven day columns over a scrollable 24-hour grid.
  • Day is a single day column over the same hour grid.

Week and Day render AM/PM hour labels (9 AM) and a red current-time line, and they auto-scroll the current hour into view when opened. Each event is positioned by its start time and sized by its duration. When two events overlap they split into side-by-side columns: a lane-assignment pass groups them into clusters and divides the width evenly.

Event model

Events carry a start and end so Week/Day can position a block by its start and size it by its duration.

event
type Ev = {
  id: number;
  date: string;   // "yyyy-MM-dd"
  start: string;  // "HH:mm"
  end: string;    // "HH:mm"
  title: string;
  color: string;  // color-label key (see below)
  type: "event" | "task" | "appointment";
  guests?: string;
  meet?: boolean;
  location?: string;
  description?: string;
  notify: string; // minutes before, as string
};

Color labels

A Google-style palette: Blueberry, Tomato, Tangerine, Banana, Sage, Peacock, Lavender, Grape, and Graphite. Because these are content colors, they use static Tailwind classes, the same convention as the tab color labels (TAB_COLORS). The color you pick drives the event block, its chip, and a live dot beside the title.

color labels
const EVENT_COLORS = [
  { key: "blueberry", label: "Blueberry", chip: "bg-blue-600 text-white", dot: "bg-blue-600" },
  { key: "tomato",    label: "Tomato",    chip: "bg-red-600 text-white",  dot: "bg-red-600" },
  // …tangerine, banana, sage, peacock, lavender, grape, graphite
];

Add dialog

Simple by default, complete on demand. The essentials stay visible; everything else tucks behind More options.

Always visible

  • Borderless title with a live color accent.
  • Event / Task / Appointment segmented tabs.
  • Date plus start and end time via the app Select (15-minute slots, 9:00 AM labels).
  • A color swatch picker.

Behind “More options”

  • Guests, Google Meet toggle, location, description.
  • A notify Select (At time of event → 1 day before).

No native time picker

Start and end use the styled Select with AM/PM options rather than <input type="time">. It looks the same in every browser, with no native clock panel to fight. If the end isn't after the start, it auto-corrects to start + 1h.

Built from

Dialog, Input, Select, Checkbox, Button, Breadcrumbs, cn, and date-fns. A copy-ready brief for it lives in the requirement templates.