Sidebar (lazy tree, keyboard navigation, saved searches), page view with typed properties, tasks, tags, calendar and clip dialogs, settings with shortcut rebinding, canvas, database and board views. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
69 lines
2.8 KiB
Svelte
69 lines
2.8 KiB
Svelte
<script>
|
||
import Icon from './Icon.svelte';
|
||
import { store } from '$lib/state.svelte.js';
|
||
|
||
let closing = $state(false);
|
||
const start = store.currentDay ? new Date(store.currentDay + 'T12:00:00') : new Date();
|
||
let year = $state(start.getFullYear());
|
||
let month = $state(start.getMonth());
|
||
|
||
const iso = (y, m, d) => `${y}-${String(m + 1).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
||
const now = new Date();
|
||
const today = iso(now.getFullYear(), now.getMonth(), now.getDate());
|
||
const mondayFirst = $derived(store.prefs.weekStart !== 'sunday');
|
||
const locale = $derived(store.prefs.locale || undefined);
|
||
|
||
let title = $derived(new Date(year, month, 1).toLocaleDateString(locale, { month: 'long', year: 'numeric' }));
|
||
let heads = $derived(Array.from({ length: 7 }, (_, i) => new Date(2024, 0, (mondayFirst ? 1 : 7) + i).toLocaleDateString(locale, { weekday: 'short' }).slice(0, 2)));
|
||
let cells = $derived.by(() => {
|
||
const first = new Date(year, month, 1);
|
||
const lead = (first.getDay() + (mondayFirst ? 6 : 0)) % 7;
|
||
const count = new Date(year, month + 1, 0).getDate();
|
||
const out = [];
|
||
for (let i = 0; i < lead; i++) out.push(null);
|
||
for (let d = 1; d <= count; d++) out.push(iso(year, month, d));
|
||
return out;
|
||
});
|
||
const have = $derived(store.dailyDays);
|
||
|
||
function go(delta) {
|
||
const d = new Date(year, month + delta, 1);
|
||
year = d.getFullYear();
|
||
month = d.getMonth();
|
||
}
|
||
function pick(day) {
|
||
close();
|
||
setTimeout(() => store.openDaily(new Date(day + 'T12:00:00')), 120);
|
||
}
|
||
function close() {
|
||
closing = true;
|
||
setTimeout(() => { store.calendarOpen = false; closing = false; }, 150);
|
||
}
|
||
</script>
|
||
|
||
<svelte:window onkeydown={(e) => e.key === 'Escape' && close()} />
|
||
|
||
<div class="overlay" class:closing role="presentation" onmousedown={(e) => e.target === e.currentTarget && close()}>
|
||
<div class="panel cal-panel" role="dialog" aria-label="Daily notes calendar">
|
||
<div class="cal-top">
|
||
<button class="btn-icon" aria-label="Previous month" onclick={() => go(-1)}><Icon name="chevLeft" /></button>
|
||
<b>{title}</b>
|
||
<button class="btn-icon" aria-label="Next month" onclick={() => go(1)}><Icon name="chevRight" /></button>
|
||
</div>
|
||
<div class="cal-grid">
|
||
{#each heads as h}<span class="cal-h">{h}</span>{/each}
|
||
{#each cells as day, i (i)}
|
||
{#if day}
|
||
<button class="cal-d" class:today={day === today} class:has={have.has(day)} class:cur={day === store.currentDay} onclick={() => pick(day)} title={have.has(day) ? 'Open this day' : 'Create this day’s note'}>
|
||
{Number(day.slice(8))}
|
||
</button>
|
||
{:else}<span></span>{/if}
|
||
{/each}
|
||
</div>
|
||
<div class="cal-foot">
|
||
<span><i class="cal-dot"></i> has a note</span>
|
||
<button class="btn" onclick={() => pick(today)}>Today</button>
|
||
</div>
|
||
</div>
|
||
</div>
|