README.md, docs/{architecture,css-classes,dev-workflow}.md, manifest.json,
package.json, package-lock.json, versions.json, .gitignore, LICENSE, and
tsconfig.json are re-added here with their current content only. Their
prior revision history is gone by design: an audit found 22 of README.md's
24 historical revisions still linked to handoff.md (a gitignored, never-
published file) — a dead reference that only ever disclosed the private
doc's existence, not its content, but was live across nearly the entire
project history until a recent cleanup. Since these are docs/metadata
rather than code, commit-by-commit revision history has no review value
here; only the current, already-audited content is kept. Code history
(everything else) is untouched.
Found by an actual read-through of every 1.1/1.2 file, not keyword search:
- src/utils.ts, src/view/chart.ts, esbuild.config.mjs: comments/code named
a specific timezone (CEST), keyboard layout (Swedish), and locale code
(sv-SE) used only for its date-format side effect — three independent
signals triangulating toward the same nationality. Genericized all three;
esbuild.config.mjs now formats the build timestamp manually instead of
depending on any locale string at all.
- main.ts, src/view/table.ts, src/view/toolbar.ts: "iPhone"/"iCloud"
framed as the author's own device/sync setup — genericized to "mobile"/
"sync".
- main.ts, src/inline-view.ts, src/travel-data.ts, src/travel-view.ts:
dangling "see handoff"/"HANDOFF" references to handoff.md, which is
gitignored and not part of the public repo. Replaced each with a
self-contained inline explanation instead of a pointer nobody can follow.
- docs/architecture.md: "Built for the author's book library and habit
tracking" softened to describe original use case without first-person
ownership framing.
- docs/dev-workflow.md: the project-tree diagram was stale (referenced
test-mobile-dashboards.mjs and xlsx-to-csv-roundtrip.mjs, both long gone)
and garbled (a cut-off local/ bullet with a "hardcoded-path caveat"
aside). Rewritten to match the actual current file list.
Tests: 115 passed, 0 failed. Typecheck clean. Build unaffected.
"Knowledge/..." was the author's actual legacy vault folder, used
throughout resolvePath and migrateFileConfigKey examples/tests and one
dev-workflow doc note. Replaced with a generic "Library/..." placeholder
everywhere it appeared. Tests unaffected (115 passed, 0 failed) since
these were just literal string fixtures, not behavior.
The native views are mobile-friendly, making the 📱 Mobile button a
redundant second rendering path with a Dataview dependency. The csv-add
and csv-refresh blocks its dashboards used stay fully supported for
back-compat; the generator + templates move to the local (gitignored)
tooling for anyone still stamping Dataview dashboards.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
handoff.md and the five live-vault scripts (dashboard regenerator +
simulator, normalizers, xlsx roundtrip verifier) move to a gitignored
local/ folder — they operate on the author's vault by name and are
useless to anyone else. test:all drops the vault-bound mobile suite
(template shape stays covered by the view smoke tests). Docs sanitized
to describe patterns, not the author's folder layout; the migration
script requires OBSIDIAN_VAULT with no default; remaining code comments
genericized.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
No vault-layout defaults baked in; usage: node migrate-xlsx-to-csv.mjs
<folder> <basename...> with OBSIDIAN_VAULT for the vault path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The asset inherited from the travel-tracker visualizer had data-iso="" on
55 of its 177 paths: Australia, Brazil, Argentina, Iceland, Austria, and
50 others rendered but could never be colored confirmed/photo-only.
Regenerated from world-atlas countries-110m (Natural Earth, public
domain) via create-world-map.mjs — 176 countries, every path keyed, same
960×500 viewBox and integer quantization, 108 KB (was 113). Also: new
README screenshots — reworked tasks-board sample data and a travel-map
shot demonstrating the fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The only test dependency (travel_flat.csv) is now an inline template
string; create-sample-data.mjs imported the xlsx package that left with
the SheetJS retirement, so it couldn't even run. The repo ships code,
docs, and README screenshots — users bring their own data.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Data and image files live only at the tip — the history carries code and
docs; there was never anything but these exact synthetic fixtures, but a
data-free history is simpler to trust.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README rewritten for the community store: pitch, install (BRAT + manual
with the world-map.svg caveat), quick start, view-mode and chart feature
tours, all five embed blocks, privacy/network disclosure (local-only
except opt-in AnkiConnect on localhost), development notes. MIT LICENSE
and versions.json added; manifest gains authorUrl and a current
description; settings tab heading finally says DataDeck instead of the
pre-rename XLSX Card View.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merges task rows from a folder scan (task-shaped CSVs only; '/' = whole
vault) and/or an explicit file list into one board rendered by the same
renderTasks as the full view. Each file's columns map onto a canonical
Title/Type/Project/Priority/Due/Status/Notes set via name aliases
(buildAggregate — pure, unit-tested); files without a Project column
contribute their basename as the project. Edits write through to the
row's source file (done toggles, inline cells, the expander), guarded by
the sync-conflict stash, only touching files whose serialized text
actually changed; the board re-syncs off vault modify events. Context
menu gains 'Open source: <file>'. Replaces the old vault-wide DataviewJS
Main Dashboard pattern.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ⚙ Config modal stacked three nested y-scrollers on mobile — the modal
content, the 60vh .csv-modal-form, and the 360px column-config table wrap
— so a swipe grabbed whichever inner region was under the finger instead
of moving the modal. Phones now let both inner regions grow to content
height; the modal is the single vertical scroller and the table keeps its
horizontal swipe. (Also applies to the Add-entry modal, which shares
.csv-modal-form.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
doSave was a debounced whole-file overwrite from in-memory rows with no
check that the file changed underneath: with the same CSV open on Mac and
iPhone (iCloud), the second device's save silently ate the first's edits.
Both hosts now anchor on the last-read/written text; when the disk has
diverged at save time, the disk version is stashed to Archive/<name>
sync-conflict <stamp>.csv with a Notice, and the visible edits win the
write. CardView also gains the vault-modify re-sync the inline block
always had (stale full views + guaranteed conflicts before), skipping
mid-edit states so a pending save reconciles instead. Fixed alongside:
the inline host's external-modify handler never updated its sync anchor,
which would have false-flagged a conflict on every save after an
external change.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The control pills each took Obsidian mobile's full input height on their
own line, pushing the canvas below the fold (~40% of the screen). Phones
now get a two-per-row grid at 32px control height, a full-width formula
input, and a taller (300px) canvas. Smooth toggle shares the active
styling with Best fit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Composites the (transparent) Chart.js canvas onto the theme background
before encoding, names the file '<csv> chart <date HHmm>.png', and writes
it via vault.createBinary. Works in both scatter/line and bar modes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Date-X charts gain two transforms: a Smooth toggle that draws a centered
7-day rolling-average line per series over faint raw dots (dots keep the
tooltips, the mean line carries the legend), and a By day/week/month
select that aggregates each series into calendar buckets (local-Monday
weeks) with a sum/avg/count pick — 'km per week, one line per person' in
two clicks. Mutually exclusive by design: a bucketed series is already
smooth. csv-chart blocks get bucket: and smooth: (true = 7 days, or a
number of days). Size-by hides under bucketing (no per-row point left).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Picking a categorical column as X (view picker or a csv-chart x: line)
flips into bar mode: one bar per value, with a count/sum/avg aggregate
select (persisted as chartAgg; agg: in blocks). Hue makes grouped bars;
comma-separated columns (Genre, Tags) split so a row counts once per
value; empty X buckets as a — bar pinned last. Fit/formula controls hide
in bar mode. Size-by maps a numeric column onto 3–14 px point radii with
a sqrt (area-true) scale — chartSizeCol / size: — with the raw value in
the tooltip. Bar controller registered in the shared lazy loader.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A Color picker in the Chart view (persisted per file as chartHueCol) and a
hue:/color: option in csv-chart blocks split the plot into one series per
distinct value of a categorical column, drawn from Obsidian's extended
color variables (Tableau-ish fallbacks). Best fit becomes per-series —
each dashed line keeps its series color, spans only its own x-extent, and
the footer reads 'A: +0.2/day (R² 0.91) · B: …'. Fit lines are filtered
out of the legend; tooltips gain a [series] prefix. Chart core refactored
from a single point-set to a series array (extractSeries, hueColumns).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Travel: headers were Country/Notes but analyzeTravel reads literal
lowercase keys — the scaffolded file opened in Travel view with every
row silently dropped. Now exactly travel.py's flat-CSV columns,
including city/visa_status/resolved (tourist detection + residency
exemptions read them).
- Tasks: added Type + Project (the columns the view's sections/grouping
are designed around — without Project, grouping fell back to Priority
headings), and Status is no longer typed Checkbox: the Add-form toggle
wrote 1/0 that the view's DONE_WORDS vocabulary didn't recognise.
DONE_WORDS also gains "1" so files from the old template still read.
- Habits: habitColumns pinned (auto-detect needs a row of values, so a
fresh file had zero toggles) and statusColumn explicitly disabled
("Read" is a status alias that polluted Stats/Library).
- New: Create chart file — a Date/Value/Notes measurement log pinned to
the Chart view with Value on Y and the fit line on.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every 'today' default came from toISOString().slice(0,10) — the UTC date,
which is the previous day between local midnight and UTC midnight in any
UTC+ timezone. Concretely: a habit logged at 00:30 CEST prefilled
yesterday's row, tasks flipped to overdue on the wrong midnight, archive
backups got yesterday's filename, and the new chart view's date ticks/
tooltips rendered local-midnight timestamps one day early. New
localISODate() helper in utils.ts used by all four call sites.
Also: a csv-add select whose saved value isn't a known option now shows
that value in the custom slot (the assignment was a dead 'val ? "" : ""'
ternary — the form displayed '—' while data existed, making it easy to
assume nothing was recorded).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Escape passed the live textarea value into closeInlineEditor — committing
the edit it was supposed to cancel — and the display:none that followed
blurred the textarea, firing a second commit. Escape now closes with the
original text, a closed-flag makes close idempotent, and an unchanged note
no longer queues a vault write on every open/close.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
makeEditable committed unconditionally on blur: clicking into a cell and
away again dirtied the file every time, and on date cells the write-back
was the 10-char truncated picker value — touching a date cell that carried
extra data silently clobbered it. Blur now compares against the value the
input was seeded with and skips the save on no-ops; Escape sets a cancelled
flag and blurs, so discard works even where element removal fires blur.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CardView.getDateCol ignored fileCfg.dateColumns entirely — a column typed
as Date in ⚙ Config only drove the dashboard/date sort if it happened to
sit in the first position, while the inline csv-view host already honoured
the config. The full view now checks the explicit pick first (but still
avoids the inline host's name-based fallback: 'Due' is date-named and that
would auto-default every tasks file to Dashboard).
Also gives InlineCardHost.getNotesCol the same '"" = disabled' semantics
the other role getters already have.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two bugs from the Config-modal functions-table redesign:
1. The modal stores "" for '— none —' and promises it disables the
function, and InlineCardHost honours that — but CardView's getters
(status/category/title/notes/image) used truthy checks, so "" fell
through to name detection and the function silently came back in the
full-page view. Getters now mirror the inline host: an explicit ""
means disabled, undefined means auto-detect.
2. The redesign dropped the one-function-per-column invariant the runtime
still assumes: assigning a role to a column now clears any other
explicit role on that same column, as the old per-column picker did.
Rewrote the six FileConfigModal smoke tests that still targeted the old
per-column Function select markup. Suite is green: 103 passed, 0 failed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The section sort pinned the literal bucket "Tasks", but the redesign keyed
buckets by raw type value ("task", "idea", …), so on real files the Tasks
section sorted alphabetically — landing last, after Idea/Note/Reference.
Task-like values (task/todo/action and empty, per TASK_WORDS) now fold into
one pinned Tasks bucket, matching the module's own documented intent; other
type sections render title-cased, A→Z. Updated the two smoke tests that
still asserted the pre-redesign Tasks/Notes/Ideas split.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New Chart view mode (scatter/line of any numeric column pair, X/Y pickers
persisted per file) plus a csv-chart code block for embedding charts — or
pure y=f(x) plots — in notes. Least-squares fit line with equation + R²
(per-day trend phrasing on date X), formula overlay via a new eval-free
expression parser (src/formula.ts). Chart.js lazy loader extracted from the
dashboard into src/chartjs-loader.ts and shared by all three consumers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add datadeck-work symlink to the second vault's plugins folder and
update the deploy script to copy build output to both vaults.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Direct follow-up to the isTruthyVal/normalization discussion: instead
of a column only converging onto strict 1/0 one row at a time as each
happens to get toggled, add a one-shot cleanup button scoped to a
single column (not a whole-file action).
Appears next to the Type select only when that column is Checkbox-
typed. Rewrites every row's raw value in that column to exactly "1"
(isTruthyVal match: yes/true/1, case-insensitive) or "0" (everything
else - 0, "", no, false, or any other leftover text) - the same rule
already used to decide checked/unchecked, just applied to the whole
column at once. Two-click confirm, same pattern as removing a column,
since it's an immediate data rewrite (not deferred to Save) - and a
Notice reports how many rows actually changed.
- CardView.cleanupBooleanColumn() (main.ts) does the actual rewrite +
save + re-render.
- FileConfigModal takes an onCleanupBooleanColumn callback (defaults to
a no-op so older callers/tests are unaffected), wired through
toolbar.ts's openColumns().
Tests: the button only appears for Checkbox-typed columns (not
Categorical/Text/the title column), and the two-click confirm gates
the actual callback correctly.
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
Answers a question about Type=Checkbox semantics by tracing every
read/write path, and fixes the two inconsistencies found along the way.
Semantics (now consistent across all of them):
- Switching a column's Type to Checkbox never touches existing row data,
only fileCfg.habitColumns.
- "Checked" is a narrow truth-list, not a wide falsy-list: only
1/true/yes (case-insensitive) read as on. Everything else - 0, "",
no, false, or any leftover non-conforming text from before the column
was Checkbox-typed - reads as off, with no error. Extracted into a
shared isTruthyVal() in utils.ts (previously duplicated as
CardView.isTruthy and inlined again in the mobile add-form).
- Every write path normalizes to exactly "1" or "0", never blank.
Two real gaps fixed, both found by tracing the write paths:
1. NoteExpanderModal (the row-editor used by Kanban/Library/Tasks/Focus
card clicks) didn't know about Checkbox columns at all - editing an
existing row showed raw text you could type anything into, which
defeats the point of Type being a single source of truth. Added the
same toggle AddEntryModal already has, wired through a new optional
isBooleanCol param.
2. The mobile csv-add form had its own completely independent boolean
auto-detection from existing data, ignoring fileCfg.habitColumns
entirely. A column freshly retyped to Checkbox (before it had any
boolean-shaped data yet) rendered as a toggle in the Dashboard and
desktop Add modal, but stayed a plain text field on mobile. Now
checks the explicit list first, matching getBooleanColumns().
Tests: isTruthyVal's truth-table, and a new note-expander case
confirming a Checkbox column renders as a toggle (not text) and
normalizes a leftover non-0/1 value to "0"/"1" on click.
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
Two follow-ups from the Config redesign discussion:
1. AddEntryModal/NoteExpanderModal previously re-derived the title
column internally by name (Title/Name), ignoring FileConfig.titleColumn.
Both now take an optional titleCol param; main.ts and inline-view.ts
pass their already-resolved titleKey() (which honours the override)
instead of leaving each modal to guess independently. Same fix in the
mobile csv-add form (add-entry-form.ts), which already had fileCfg in
scope. A Title override configured in Config now actually excludes
the right column from every dropdown/select path, not just the ones
that happened to be named Title/Name.
2. getBooleanColumns() used a habitColumns.length > 0 check to decide
whether the explicit list wins over auto-detection - so explicitly
emptying the list (unchecking every Checkbox-typed column in Config,
meaning "no habit columns for this file") silently fell back to
auto-detect instead of actually turning the habit tracker off.
Changed to a plain truthy-array check, matching how categoricalColumns
already worked. This matters for the Habit-Dashboard question:
Type=Checkbox is already the single source of truth for which columns
are habit-trackable (no separate "special field" needed - a column
just has one Type, and Checkbox is what puts it in the grid) - this
fix makes that guarantee hold even at the empty-list edge case.
Tests: two new cases confirming an explicit titleCol override drives the
header/exclusion/delete-label in the expander and the dropdown exclusion
in the add form.
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
Follow-up to the auto-detected-role indicator, from further discussion
of the redesign. Two changes to the data model, one to the layout:
1. Type (Text/Checkbox/Categorical) replaces the independent Habit and
Categorical toggles with one mutually-exclusive select. Nothing
stopped a column from being checked as both before, which never
made sense — a column has one data shape, not two. Still backed by
the same habitColumns/categoricalColumns lists at runtime (no
behavior change to getBooleanColumns/isCategoricalCol), the modal
just now enforces the exclusivity that was implicitly assumed
everywhere else.
Status stays a Function, not a Type — deliberately not generalizing
to a plain 'Checkmark' type. The Tasks-view done-checkmark comes
from word-matching (done/completed/closed/…) against whatever
multi-valued vocabulary a real Status column already uses, not from
the column being strictly 2-valued; most real status columns have
3+ states.
2. Title is now a configurable Function, backed by a new
FileConfig.titleColumn (defaults to auto-detect by name, same as
before). There was previously no way to override which column is
the title at all. titleKey() in main.ts and inline-view.ts now
check the override first.
3. The per-column config renders as an actual <table> (Column | Type |
Function | Card field) instead of stacked vertical cards, scrolling
horizontally on narrow widths rather than wrapping — same pattern
the sticky Table-view header already uses.
Tests: rewrote the FileConfigModal suite for the table structure,
added coverage for Type mutual exclusivity and the new Title function.
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
The per-column Role dropdown only ever showed an explicit fileCfg
override — a column literally named 'Status' (or Category/Notes/Image/
Anki-front by their own name lists) already drives getStatusCol() etc.
at render time by name, but the modal showed '— no special role —' for
it with nothing to indicate that. This was the exact confusion behind
a user question: 'what corresponds to the checkmark in the file?' —
the Status role does, but for a conventionally-named column there was
no visual confirmation it was already active.
- Extracted the Category/Status/Notes column name-alias lists (already
duplicated between main.ts and inline-view.ts) into shared constants
in src/utils.ts, and split ankiFrontCol's fallback chain out into an
exported autoAnkiFrontCol() in src/view/anki.ts. Both were already
pure name/position lookups; this just makes them independently
callable without an explicit override applied.
- FileConfigModal now takes an AutoDetectedRoles snapshot (computed
once in toolbar.ts's openColumns(), the same lists/functions the
views themselves use) and roleOf() shows the resolved role plus an
'auto (by name)' badge whenever nothing is explicitly configured for
that slot — exactly mirroring the fact that explicit overrides always
win outright over name detection at runtime (never blended).
Tests: two new FileConfigModal cases — a name-matched column shows its
role with the auto badge and no saved config, and an explicit override
on a different column suppresses the badge everywhere for that role,
matching what getStatusCol()/etc. actually resolve.
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
Replaces the ⚙ Columns modal's eight separate 'which column(s) for
role X?' sections (Category/Status/Notes/Anki-front dropdowns +
Habit/Card-field/Categorical checkbox grids) with a single vertical
list of per-column rows. Each row gets:
- a Role select (none/Category/Status/Notes/Image/Anki front) —
mutually exclusive, since each of these was already a single-column
slot; picking one for a column automatically clears it from
whichever column held it before, and clears any other role the same
column previously held.
- three independent toggles (Habit/Card field/Categorical) a column
can hold any combination of.
Also folds in an Image-column picker (previously name-detection only,
no UI) and renames the toolbar button/menu entry from 'Columns' to
'Config' since it now covers more than columns.
Role/toggle edits stay in-memory (this.current) until Save, same as
before; only add/remove-column still refetches from disk immediately
since those persist right away. Split refresh() (disk refetch, for
structural changes) from a new renderRows() (local re-render, for
role/toggle changes) so editing roles never discards other unsaved
edits in the draft.
Tests: rewrote the categorical-toggle tests for the new row structure,
added coverage for role exclusivity (cross-column eviction, same-
column reassignment) and confirmed role/toggle edits never call
getFileCfg (no disk refetch).
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
Renamed csv-card-view -> datadeck (id, display name, symlink, docs) to
better reflect the plugin's scope beyond a single card view. Also fixed
kanban cards silently omitting a field's chip when its value was empty,
instead of showing "Field: —" like the table/select-chip views already do.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Learnings from kepano/obsidian-skills applied:
- openOrCreateNotes built frontmatter by hand-quoting values, which produced
invalid YAML for cells containing backslashes (bad escape sequences) or
newlines (multi-line CSV cells), corrupting the whole properties block.
Now builds a property object and serializes with Obsidian's stringifyYaml.
- Sidecar notes gain a `source` property wikilinking back to the CSV file
(skipped when a column is already named "source"), so every note carries
a backlink to its data source.
- New npm scripts (reload / errors / check:live) drive the running Obsidian
via the Obsidian CLI: plugin:reload replaces the manual Cmd+R step and
dev:errors surfaces runtime failures from the terminal.
- dev-workflow.md documents the CLI-driven verify pass (dev:screenshot,
dev:dom, dev:css, dev:mobile, eval).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The picker's capture-phase scroll listener dismissed on any scroll in the
document, including its own list — so scrolling the list, or typing (which
auto-scrolls the keyboard cursor into view), closed it instantly and bounced
focus back to the modal. Now it ignores scrolls that originate inside the
picker itself.
The ⚙ Columns modal also gained inline column add/remove: a chip list with a
confirm-to-delete ✕ per column, and a "+ Add column" input, wired through new
CardView.addColumn/removeColumn methods that update headers, row data, and
any per-file config pointing at a deleted column.
Inline view (src/inline-view.ts): a csv-view code block renders an editable
table/cards/kanban view of a CSV inside any note. InlineCardHost satisfies the
renderers' duck-typed surface so renderTable/renderLibrary/renderKanbanGenre are
reused unchanged; edits write back via vault.modify and re-sync off the modify
event. Block directives: file/mode/height/collapse.
- Cards/Kanban thumbnails: getImageCol() auto-detects Image/Cover/Poster/…
columns; resolveImageSrc() handles vault paths, wikilinks, md-images, URLs.
- Card title + context-menu "Open entry" now open the expander even without a
notes column (NoteExpanderModal hides its notes section when absent), so
notes-less files (e.g. applications trackers) are editable from cards.
- collapse: directive + fileCfg.collapsedGroups: Cards groups collapse by
default and remember manual toggles (full-page too).
- Habit add-form toggles for 0/1 columns; pseudo-categorical columns (few
distinct values) get option dropdowns in the add + edit forms via shared
looksCategorical() helper.
- Kanban: empty group value → "—" column (was dropped in default grouping);
rows with blank/unknown status render ungrouped instead of vanishing while
the column header still counted them.
- Dark-mode table row hover: explicit text-tint overlay (was near-invisible).
- Docs: csv-view syntax in README; architecture + open follow-ups in handoff.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Notes
- openOrCreateNotes now tags spawned notes with the row's project on
tasks/projects files: `tags: [project-<slug>]` via a new tagify() helper,
reviving the old per-project dashboard tag-scan. Gated to hasTaskColumns
files so books/movies notes don't grow project tags.
Anki sync (src/view/anki.ts)
- New 🎴 Anki toolbar button (+ ⋯ menu) pushes rows to Anki via AnkiConnect
(127.0.0.1:8765). One row → one Basic note: configurable front column
(⚙ Columns → "Anki card front", FileConfig.ankiFrontCol), other columns on
the back, HTML-escaped. Deck = file basename, auto-created. allowDuplicate
off → idempotent re-sync. Clear notice when Anki isn't reachable.
Palette commands
- "Create tasks/travel/habit tracker file" scaffold a new CSV with that view's
canonical columns, pin defaultMode, and open it (FILE_TEMPLATES +
createTemplateFile + PromptModal).
Tasks view + Add-entry modal
- Split the Tasks view into three peer sections: Tasks / Notes / Ideas.
- Add-entry modal: Type and Priority render as native <select>s prefilled with
Task/Note/Idea and Low/Medium/High on tasks files; Due gets a date picker
(isDateCol now matches due/deadline). Native selects fix the focus-trap bug
where the body-appended picker bounced focus back to the title, leaving
empty project/type/etc. columns unfillable.
Docs + tests
- README Anki-sync section + setup, updated feature/mode notes; architecture
module map. New coverage: tagify, anki sync (4), 3-section split, date-col
due/deadline. Full suite green (csv 6, logic 115, mobile 21, smoke 62).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First pass at this used appearance:none + vertical padding + line-height,
which made the label taller than the control and clipped it at the top.
Mirror how Obsidian's own dropdowns center: a fixed `height` with zero
top/bottom padding lets the native control flex-center the label
(line-height is irrelevant). Keeps the custom chevron and per-class
horizontal padding.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>