Commit graph

78 commits

Author SHA1 Message Date
SVM0N
4faff4588e docs/config: restore current docs and package metadata, history stripped
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.
2026-07-16 14:03:23 +00:00
SVM0N
6351d84e16 chore(privacy): remove identity/locale signals and dangling private-doc refs
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.
2026-07-16 12:56:45 +00:00
SVM0N
0893a4a52c chore(privacy): genericize the last real vault folder name in docs/tests
"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.
2026-07-16 12:35:12 +00:00
SVM0N
07b311341d feat!: retire the DataviewJS mobile-dashboard generator
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>
2026-07-13 03:41:55 +00:00
SVM0N
2e45c2ce4c chore: rebuild bundle post-rewrite
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 17:25:10 +00:00
SVM0N
73050282f8 chore(privacy): personal tooling goes local — vault layout leaves the public repo
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>
2026-07-12 17:24:08 +00:00
SVM0N
9ef5e37134 chore: parameterized xlsx→csv migration script — folder and file names are CLI args
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>
2026-07-12 17:10:41 +00:00
SVM0N
86ab777392 fix(travel): regenerate world-map.svg — 55 countries were permanently uncolorable
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>
2026-07-12 11:33:09 +00:00
SVM0N
554d5508f4 test: neutral fixture wording so privacy audits stay zero-hit
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 08:32:45 +00:00
SVM0N
bbf27162be chore: drop sample data files and the legacy generator — tests inline their fixtures
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>
2026-07-12 08:20:51 +00:00
SVM0N
7be2c99a6a chore: add synthetic sample data and README screenshots
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>
2026-07-12 08:17:26 +00:00
SVM0N
97669c14ff chore(release): publish prep — store-quality README, MIT LICENSE, versions.json, v1.6.0
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>
2026-07-12 06:40:58 +00:00
SVM0N
0b6da69a20 feat(tasks): csv-tasks block — cross-file tasks board (phase 2)
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>
2026-07-12 02:31:33 +00:00
SVM0N
4f20484ff7 style(config): one scroll surface in the modal on phones
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>
2026-07-12 02:27:14 +00:00
SVM0N
c59af99008 feat(sync): no more silent clobbering — conflict stash + live re-sync in the full view
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>
2026-07-12 02:26:05 +00:00
SVM0N
95f0a24f80 style(chart): compact mobile controls — two per row, short inputs, chart gets the space
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>
2026-07-12 02:13:30 +00:00
SVM0N
bead820e0e feat(chart): ⬇ PNG export — save the rendered chart as an image next to the CSV
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>
2026-07-12 02:12:38 +00:00
SVM0N
c2e3201a5a feat(chart): 7-day rolling-mean smoothing + week/month date bucketing
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>
2026-07-12 02:11:41 +00:00
SVM0N
fb03f4e674 chore: add Chart Test.csv generator (deployed to a personal vault root)
Deterministic 96-row running log — date/person/weekday/distance/pace/
effort — with per-person trends, built to exercise every Chart-view
feature: time-series hue + per-series fits, size-by, bar aggregates.
Run: node create-chart-test-data.mjs "<vault>/Chart Test.csv"

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 01:42:50 +00:00
SVM0N
22e434f0e0 feat(chart): bar/aggregate mode for categorical X + size-by point radius
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>
2026-07-12 01:41:23 +00:00
SVM0N
396acec6be feat(chart): ggplot-style hue — Color-by splits into per-category series
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>
2026-07-12 01:31:55 +00:00
SVM0N
7846130637 fix(templates): scaffolds now match what the views actually read; add Create chart file
- 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>
2026-07-12 01:26:53 +00:00
SVM0N
39a89c6be0 docs(handoff): record the chart-view arc and bug-hunt session
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 15:48:52 +00:00
SVM0N
8fdae93cbb fix(dates): today is the local date everywhere, not the UTC date
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>
2026-07-11 15:46:37 +00:00
SVM0N
1c9f836584 fix(kanban): Escape discards the inline note edit; close only saves real changes
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>
2026-07-11 15:43:52 +00:00
SVM0N
0dab369bfb fix(table): inline cell edits only save on real changes; no-op clicks can't truncate dates
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>
2026-07-11 15:42:54 +00:00
SVM0N
a40891ac6c fix(config): full view honours the explicit Date-column pick; inline notes '— none —' respected
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>
2026-07-11 15:41:40 +00:00
SVM0N
826565befe fix(config): '— none —' disables a function everywhere; functions exclusive per column again
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>
2026-07-11 15:39:57 +00:00
SVM0N
3346bda3f6 fix(tasks): pin the Tasks section first again after per-type section redesign
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>
2026-07-11 15:36:43 +00:00
SVM0N
6cb2deccb2 feat(chart): Chart view + csv-chart block with best-fit and formula overlay
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>
2026-07-11 15:32:30 +00:00
SVM0N
b12da235ea Deploy plugin to two personal Obsidian vaults
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>
2026-07-09 03:40:38 +00:00
SVM0N
51e00499dc Optimize tasks table column widths for mobile viewing 2026-07-07 11:20:28 +00:00
SVM0N
79c4875162 Fix AddEntryModal constructor and enhance Tasks file template 2026-07-07 10:42:09 +00:00
Cursor Agent
c4189c58e1 feat(config): per-column "Clean up" action for Checkbox columns
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>
2026-07-06 09:45:49 +00:00
Cursor Agent
08a7b4c08f feat(checkbox): make Type=Checkbox behave consistently everywhere it's edited
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>
2026-07-06 09:34:09 +00:00
Cursor Agent
74788daa4e fix(modals): thread the resolved title column into Add/Edit forms; fix habitColumns empty-list fallback
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>
2026-07-06 09:16:22 +00:00
Cursor Agent
8a4de617f6 feat(config): unify Habit+Categorical into a Type column, add Title as a Function, render as a real table
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>
2026-07-06 09:06:47 +00:00
Cursor Agent
e260a4ed00 feat(config): surface auto-detected roles in the ⚙ Config modal
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>
2026-07-06 08:47:14 +00:00
Cursor Agent
53ca235bc2 feat(config): redesign file settings into a per-column role table
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>
2026-07-06 08:19:57 +00:00
Cursor Agent
7937c8beb6 fix(kanban): give blank-status rows a labeled "—" group instead of bare margin
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
2026-07-06 07:42:17 +00:00
Cursor Agent
9a7ead1696 feat(entries): add a highlight option for entry titles
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
2026-07-06 07:35:55 +00:00
Cursor Agent
d8cdad2c60 feat(settings): explicit categorical-column selector in the Columns panel
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
2026-07-06 07:29:34 +00:00
Cursor Agent
0aa57b978c fix(add-entry): exclude title/index column from categorical dropdown detection
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
2026-07-06 07:19:14 +00:00
Cursor Agent
9d604d5b73 fix(tasks): stop empty sheets from turning every column into a toggle; add done checkmark to Notes/Ideas
Co-authored-by: SVM0N <SVM0N@users.noreply.github.com>
2026-07-06 07:14:35 +00:00
SVM0N
992d57cdc9 rename plugin to DataDeck; fix(kanban): show empty-field chips as em dash
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>
2026-07-03 13:41:37 +00:00
Claude
c94d9e0a66 fix(notes): serialize sidecar frontmatter with stringifyYaml; docs: Obsidian CLI dev loop
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>
2026-07-03 00:54:54 +00:00
SVM0N
8d7afe4d9a fix(picker): stop internal scroll from self-dismissing dropdown; feat: add/remove CSV columns from Columns modal
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.
2026-07-01 10:19:36 +00:00
SVM0N
8518dd7a2f feat: inline csv-view block, image columns, kanban grouping fixes
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>
2026-06-28 17:53:11 +00:00
SVM0N
5011fe2433 feat: project-tag notes, Anki sync, file-template commands, Tasks refinements
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>
2026-06-15 16:47:28 +00:00
SVM0N
08db8e791b fix(css): center select labels via fixed height, not vertical padding
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>
2026-06-14 14:33:19 +00:00