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(inwidgetChrome) 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
useDefaultEventDuration→CreateEventSheet, 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 ofcalendar.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
NativeSurfacepicks up an optionalsidebarslot. When set, the right column owns its own header / grid via the supplied children; theheaderslot only renders in the plain stack form.NativePaneChrome(widgetChrome.jsx) — drop-in forWidgetCardLayoutscoped to a native two-column surface's right column. The reused widget'sWidgetHeader(grid toolbar / week nav) rides the darker top bar, and the body sits in the inset white card.DataWorkspace,CalendarWorkspace,DialerBodyall gain anativeLayoutflag; theirrenderChromecallback now receives{ header, sidebar, children }so the chrome owns where the sidebar lands. The canvas mounts leavenativeLayoutoff and keep their existing single-column shape.useDefaultEventDuration— pure hook readingprofile.preferences.calendar.default_event_duration_minuteswith aDEFAULT_EVENT_DURATION_MINUTES = 30fallback. Sibling toweek_start_dayunder the same JSONB column; persisted via the existingupdateProfile()merge convention.minutesToTimeValue/timeValueToMinutesinCreateEventSheet.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/formatGhostRangeinCalendarDayColumn.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 the9:30 AM – 10:00 AMlabel.CalendarSettingsPanelroutes every calendars-table CRUD call throughcalUuid = 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
EventDurationOptionsshape 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.
Changelog
What's new in Project88. We ship continuously — this page tracks the user-visible changes that matter.
0.3.0 — Native app surfaces for Dial, Pages, Data, Calendar, Inbox
The five main apps move off the React Flow canvas onto full-bleed native shell surfaces with their own opinionated layouts; Home and user-created boards stay canvas-based and keep every dashboard widget.