Changelog

0.3.1 — Full-height sidebars for Data/Calendar/Dial, default appointment length, snap-to-create

The Data, Calendar, and Dial native surfaces share one layout — a full-height left sidebar with the app's toolbar on the darker top bar over the right column. Calendar gains a default appointment length setting and a click-to-create ghost preview that snaps to 15-min and centers on the pointer.

What's new

  • One layout across the native surfaces. Data, Calendar, and Dial now mount the same shape on their native shell surfaces — a full-height left sidebar with the app's header / toolbar riding the darker top bar over the right column. A new shared NativePaneChrome (in widgetChrome) backs the right column arrangement.
    • Data — the table-list rail runs full-height; the "Data" + New table header lives at the top of the rail; the grid's toolbar rides the darker top bar.
    • Calendar — the mini-month + My Calendars sidebar runs full-height (the redundant "Calendar" title row is gone); the week header rides the darker top bar and gains a New event button.
    • Dial — while actively dialing, the contact card lifts out of the columns row into a full-height sidebar; the dialer header moves to the right column. Empty / closed / error states fall back to the plain full-width header. Contact-card resize is now clamped against the right container.
  • Default appointment length. New user setting under Settings → Calendar → Defaults → Default appointment length with six fixed presets — 15 / 30 / 45 / 60 / 90 / 120 minutes. Defaults to 30 min. Every event-creation entry point reads it via useDefaultEventDurationCreateEventSheet, so picking a start time auto-fills the end (until you set one explicitly).
  • Click-to-create ghost preview. Hovering an empty slot on the day / week grid paints a dashed primary-tinted block at the snapped start position — exactly the appointment a click will make. The block is sized to the default length, snapped to 15-min increments, centered on the pointer (so it straddles the cursor instead of hanging below it), labelled with the start–end range (e.g. 9:30 AM – 10:00 AM), and hides while hovering an existing event so a stale preview never sits behind a real block. Clicks commit at the snapped minute.
  • Google calendar Remove fix + control gating. The calendars-table CRUD (hide, org_wide, share add / remove, visibility tier) now keys on the row's uuid (calendarUuid) instead of calendar.id — the latter is the external Google id (an email) for Google calendars, so the previous keying silently no-op'd against the uuid-typed column. Project88 sharing controls (Public to org, visibility tier picker, per-user shares editor) are now hidden for Google calendars since sharing is managed in Google; the sheet shows a short note plus Remove from my calendar list only.

Under the hood

  • NativeSurface picks up an optional sidebar slot. When set, the right column owns its own header / grid via the supplied children; the header slot only renders in the plain stack form.
  • NativePaneChrome (widgetChrome.jsx) — drop-in for WidgetCardLayout scoped to a native two-column surface's right column. The reused widget's WidgetHeader (grid toolbar / week nav) rides the darker top bar, and the body sits in the inset white card.
  • DataWorkspace, CalendarWorkspace, DialerBody all gain a nativeLayout flag; their renderChrome callback now receives { header, sidebar, children } so the chrome owns where the sidebar lands. The canvas mounts leave nativeLayout off and keep their existing single-column shape.
  • useDefaultEventDuration — pure hook reading profile.preferences.calendar.default_event_duration_minutes with a DEFAULT_EVENT_DURATION_MINUTES = 30 fallback. Sibling to week_start_day under the same JSONB column; persisted via the existing updateProfile() merge convention.
  • minutesToTimeValue / timeValueToMinutes in CreateEventSheet.jsx — minute-of-day ↔ "HH:MM" helpers, clamped to 23:59 so long defaults can't roll the end past midnight while the date stays fixed.
  • ghostStartMinute / formatGhostRange in CalendarDayColumn.jsx — pure helpers (exported for tests) that map a row-relative cursor Y to a snapped start minute (cursor-centered, clamped to the visible hour range) and render the 9:30 AM – 10:00 AM label.
  • CalendarSettingsPanel routes every calendars-table CRUD call through calUuid = calendar.calendarUuid || calendar.id.

What's next

  • Lift the same shared-sidebar pattern to the remaining native apps (Inbox, Pages) where it makes sense.
  • An EventDurationOptions shape that lets future per-calendar defaults override the user-level value without changing the resolver call sites.

See Calendar → Layout, Calendar → Default appointment length, Calendar → Click-to-create ghost preview, Data → Layout, and Dial overview.

On this page