Something went wrong. Try again.
a local-first atmospheric chalky task planner
Something went wrong. Try again.
3.2 kB · 102 lines
Svelte
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103<script lang="ts"> import DayColumn from "./DayColumn.svelte"; import { ui } from "../store/ui.svelte"; import { threeDays, dayParts } from "../date";
let days = $derived(threeDays(ui.anchor)); // Reactive today, not a bare `todayKey()` call — see ui.svelte.ts's // `todayKey`/`checkRollover` for why: this needs to move without a refresh. let today = $derived(ui.todayKey);
// Column sizing knobs, matching WeekGrid's. const COL_W = 340; const GAP = 18; // keep in sync with --gap
// Measured width of the grid (incl. its 24px side padding, so ≈ viewport). let gridW = $state(0); // Content width available to the columns (grid width minus the 48px padding). // Phones drop to 14px a side, but nothing under 480px fits two columns either // way, so the fixed 48 never changes the count. let contentW = $derived(Math.max(0, gridW - 48));
function colCount(w: number): number { if (w <= 0) return 1; return Math.max(1, Math.min(days.length, Math.floor((w + GAP) / (COL_W + GAP)))); }
// With only 3 days there's no benefit to WeekGrid's height-aware packing — // an even, chronological split reads fine either way, so just go by width. // Still frozen mid-drag like WeekGrid, so tiles don't hop columns while a // task is being dragged. let cols = $state(1); $effect(() => { if (ui.dragging) return; cols = colCount(contentW); });
// Split the day sequence into `cols` *contiguous* columns (today/tomorrow // together, the day after alone, at 2 columns). let columns = $derived.by(() => { const k = Math.max(1, Math.min(cols, days.length)); const per = Math.ceil(days.length / k); const groups: string[][] = Array.from({ length: k }, () => []); days.forEach((key, i) => groups[Math.min(k - 1, Math.floor(i / per))].push(key)); return groups; });</script>
<div class="grid" bind:clientWidth={gridW}> <div class="cols" class:stacked={columns.length === 1}> {#each columns as col, ci (ci)} <div class="mcol"> {#each col as key (key)} {@const p = dayParts(key)} <div class="cell"> <DayColumn day={key} num={p.num} mon={p.mon} dow={p.dow} today={key === today} /> </div> {/each} </div> {/each} </div></div>
<style> .grid { padding: 6px 24px 0; } /* Phones: 14px + the rows' 2px inset lands on the shared 16px gutter (see Header.svelte's .bar). */ @media (max-width: 480px) { .grid { padding-inline: 14px; } }
.cols { display: flex; align-items: flex-start; gap: var(--gap); } /* Narrowest layout: a single column, all three days stacked — cap the width like DayView so a lone column doesn't stretch full-bleed. */ .cols.stacked { max-width: 640px; margin: 0 auto; } .mcol { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; /* vertical space between day tiles stacked in the same column */ gap: 26px; }
.cell { min-width: 0; display: flex; flex-direction: column; }
.cols :global(.col > .body) { min-height: calc(var(--row-h) * 3); }</style>