# Lotus

A to-do list built around constant reordering, not fixed buckets.

## The context

Todo lists have always been a design challenge. Everyone building software tries one eventually, and almost nobody stays happy with what they ship.

I wanted to take it from a different angle: no settings screen, no action buttons scattered across a toolbar, no menu bar sitting there whether you need it or not. Just a single composer at the bottom of the screen, enriched with contextual commands, carrying the entire interaction model — everything else surfaces only when you ask for it, through a long press or a typed command.

The trigger was a pitch Charlie Deets posted on LinkedIn: Things 3 treats Today, Tomorrow, and Anytime as fixed buckets, but real task management is constant renegotiation — pulling something into today, pushing it back out, reshuffling mid-afternoon. Every one of those moves in Things means leaving the list, drilling into a picker, coming back.

Deets' pitch pushed me to think outside the box, from a completely different perspective, toward a completely different interaction model. Lotus is what came out of that.

## What it does

- A **composer** at the bottom of the screen — type and send to Anytime, or long-press send to choose Today, Tomorrow, or drill into a custom group
- **Slash commands** that change meaning depending on state: with text typed, `/` is a destination picker; empty, it's the app's command palette (manage groups, theme, clear completed)
- An **`@` shortcut** to jump straight to a group without leaving the keyboard
- Anytime tasks aren't a dumping ground — set a due date and the item routes itself: today's date moves it to Today, tomorrow's to Tomorrow, anything later stays in Anytime. Items already filed in a custom group are left alone regardless of due date
- Completed items stay struck through until midnight, or get swept early with a pull-down gesture
- Full **drag-and-drop reordering**, within and across sections, backed by a fractional-ordering algorithm so reorders never require renumbering the whole list

## _

<!-- layout:fullwidth bg-soft-grey -->

![Lotus demo — composer, slash commands, @ shortcut, due-date routing, drag reorder, and the light/dark switch](/img/projects/lotus/lotus-demo.mp4)

*Composer, slash commands, the `@` shortcut, an Anytime task routed by due date, drag-and-drop reorder, and the switch to dark mode*

## _

<!-- layout:grid -->

![Long-press Add to sheet](/img/projects/lotus/add-to-sheet.png)

![Groups drill-down from the Add to sheet](/img/projects/lotus/groups-drilldown.png)

![Slash command menu, destination picker state](/img/projects/lotus/slash-menu.png)

![Slash command menu, app command state](/img/projects/lotus/slash-menu-empty.png)

## Why it's a playground project

The pitch covered maybe a third of what's in the app now. The rest came from using it daily and noticing what broke: an early swipe-to-complete gesture fought with drag-to-reorder on touch, so it got pulled and replaced with the long-press menu that's still there; a due-date rule that filed everything into Anytime turned out wrong once real dates were involved, so it got corrected to route by whether the date is today, tomorrow, or later; and the composer kept jumping off-screen when the keyboard opened on mobile Safari, fixed twice before it actually held.

None of that shows up in a first working version. It shows up in the 48th PR, still fixing edge cases a daily driver keeps surfacing.

## _

<!-- layout:grid -->

![@ command menu for picking a destination group](/img/projects/lotus/at-menu.png)

![Long-press item menu](/img/projects/lotus/item-menu.png)

![Due date picker sheet](/img/projects/lotus/due-date-sheet.png)

![Theme picker sheet](/img/projects/lotus/theme-sheet.png)

## Dark mode

Light, Dark, or System, picked from the `/theme` command and remembered across sessions.

## _

<!-- layout:grid -->

![Main list in dark mode, with Today, Tomorrow, Anytime, and the Garden group](/img/projects/lotus/main-list-dark.png)

![Long-press Add to sheet in dark mode](/img/projects/lotus/add-to-sheet-dark.png)

![Slash command destination picker in dark mode](/img/projects/lotus/slash-menu-dark.png)

![@ command menu in dark mode](/img/projects/lotus/at-menu-dark.png)

![Long-press item menu in dark mode](/img/projects/lotus/item-menu-dark.png)

## Stack

React 19, TypeScript, Vite, Tailwind CSS v4, Zustand with persisted state, `@dnd-kit` for drag-and-drop, Framer Motion for animation. Data lives in `localStorage` — nothing leaves the device, and the app installs as a PWA rather than shipping through an App Store.
