Commit Graph
36 Commits
Author SHA1 Message Date
thandClaude Opus 4.7 48b5907f4c v2.0.2 — English tag aliases, English-only website, undo-body flaky fix
- tags: accept #birthday and #appointment as English synonyms for
  #geburtstag and #termin. Normalised to the German canonical form at
  extractTags() write-time so every downstream check (parseTags /
  calendar logic / board filters) keeps working without per-call-site
  aliasing. Editor body-regex extended so the "new appointment"
  heuristic and auto-sync trigger on either variant.
- website: replace #termin/#geburtstag with #appointment/#birthday in
  tag chips, calendar feature list, and calendar legend.
- tests: fix flaky "Undo: Editor Save → Ctrl+Z reverts body change"
  that raced doSave(). The test polled the server for the patched body
  and fired Ctrl+Z as soon as it landed, but the undo shortcut is
  guarded by !guards.isOpen('modal'), and closeModal() only runs after
  the post-patch _reloadAll — on fast servers the key was swallowed.
  Poll now also waits for the modal `.open` class to drop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 10:04:08 +02:00
thandClaude Opus 4.6 c2485b1307 fix(editor): appointment bucket-skip detects {id:null} shells too
The calendar day-popup invokes openModal with `{id: null, title, body}`
rather than a bare `null`, so `!card` was false and the #termin-body
exemption never fired — new appointments still inherited the active
bucket. Key the "is new" check on `card?.id` instead so both entry
shapes are treated the same.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:10:17 +02:00
thandClaude Opus 4.6 0e3088db9a editor: new appointments never inherit the active bucket
The modal's default-bucket logic dropped new cards into the current
real bucket when opened from one. Calendar-created appointments
(body pre-seeded with #termin / #geburtstag) would then land in e.g.
"work" instead of living bucket-less as calendar entries should.
Detect the pre-filled tag on open and force inpBucket empty for
those; regular new cards still inherit the active bucket.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:04:39 +02:00
thandClaude Opus 4.6 ca47052768 collab attachments, multi-day events, calendar improvements
- Collab buckets sync attachments alongside cards (images/PDFs/audio).
  New /api/collab-attachments endpoint on relay, encrypted at rest,
  bucket-scoped for members.
- CalDAV multi-day events via **Bis:** body field. Calendar renders
  event on every day in range with day counter (1/6, 2/6, ...).
- Calendar preserves month across close/reopen (only jumps to today
  on first open).
- Calendar title: centered nav group with [MM-DD] Mon Y [KW-KW] —
  dimmed brackets, fixed width so nothing wiggles.
- Editor: scratchpad uses custom confirm, autobackup-draft dialog
  replaced with custom styled dialog.
- Scanlines theme feature removed (performance issue).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 18:22:02 +02:00
thandClaude Opus 4.6 3cca14a3c6 fixes: collab move, caldav abort, draft recovery, autobackup, test stabilization
- Collab: moving a shared card to a local bucket no longer deletes it
  (clear relay_uid before tombstone echo returns)
- CalDAV: abort sync on remote fetch failure instead of treating all
  local cards as remotely-deleted
- Editor: autobackup drafts to localStorage with restore prompt on
  re-open (skipped during tests)
- Cards POST: persist scratchpad and due_date (was dropped on create)
- Disable spellcheck/autocorrect on editor inputs
- Test runner: purge leftover __prefix__ cards/buckets + editor drafts
  before every run (cleans up from failed previous runs)
- Stabilize mark-done, group-delete, undo-body tests with poll loops

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:01:07 +02:00
thandClaude Opus 4.6 7e2b130434 fixes: scratchpad, zen ESC, chat time, tooltip safety, collab sync race
- Scratchpad: card-scoped private notes in editor (toggle vs preview),
  smaller font, cleared via button, stored in cards.scratchpad
- Zen mode: ESC exits zen before closing detail, Z toggles zen
- Chat: always show absolute time (hh:mm, yesterday, or date+time)
- Backspace/Delete also deletes focused card (not just selected)
- Selected + focused cards use brand accent (not accent2)
- Tooltip: guard against non-element targets
- Collab sync: skip poll while editor is open, 2s push debounce
- Rrule test: only check geburtstag tag, not title format

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 00:45:31 +02:00
thandClaude Opus 4.6 b9bd294c90 fix: image resize preview, todo checkbox alignment, modal overflow clip
- Image resize respects width attr in preview (no more snap-back)
- Single-task checkbox aligned with flex center instead of translateY hack
- Modal/detail containers clip card-bar at rounded corners
- Right-click on image no longer triggers resize (left-button only)
- Split dist.sh and bump.sh into separate scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 12:17:24 +02:00
thandClaude Opus 4.6 f465306c1d global tooltip system, migrate all title attrs to data-tip/data-help
New tooltip.js module with styled tooltips (data-tip) and multi-line
inline help (data-help). Migrates all ~70 native title attributes
across index.php, JS modules, and all plugins. Adds inline help on
9 strategic UI elements (split, superview, zen, extract, assets, etc).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:55:17 +02:00
thandClaude Opus 4.6 04b52ecc19 gitea: default repo setting; editor: asset picker with thumbnail grid
Gitea plugin: default_repo field per account (stored in DB, pre-fills
create issue form but stays editable). Editor toolbar: asset picker
flyout with 4-column thumbnail grid and live search filter. Clicking
a tile inserts the matching markdown.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 19:26:04 +02:00
thandClaude Opus 4.6 bbfe968ff1 fix: suppress shortcuts when typing in input fields
Shortcut dispatcher now skips non-modifier keys when focus is in an
editable field. Editor find bar ESC stops propagation to close bar
before modal.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 12:57:05 +02:00
thandClaude Opus 4.6 d1b26e625a search: integrate find/replace into search overlay, add toolbar buttons
Moves board-wide find/replace from standalone overlay into the search
panel as a toggleable replace row. Adds editor toolbar find/replace
button. Ctrl+Shift+H now opens search in replace mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 12:53:11 +02:00
thandClaude Opus 4.6 3078906548 find/replace: editor (Ctrl+H/F) + board-wide (Ctrl+Shift+H)
Editor find/replace (public/js/modules/editor.js, public/index.php):
* New #editor-find-bar inside #editor-pane (above the textarea, pushes
  it down via flex-col). Two rows: find input + match count + prev/next
  + close, and replace input + replace-one + replace-all.
* Ctrl+H opens find+replace, Ctrl+F opens find-only (replace row
  hidden). Same shortcut toggles off if already open in the same mode.
* runFind(): case-insensitive indexOf scan, all match positions stored.
  jumpTo() sets textarea.setSelectionRange for the Nth match.
  findNext/findPrev cycle with wrap-around.
* replaceOne(): body.setRangeText at the current match position, re-scan.
  replaceAll(): regex-based global replace on body.value.
* Enter in find input = next (Shift+Enter = prev). Enter in replace
  input = replace one. Escape closes the bar + refocuses textarea.
* closeModal() calls closeFindBar() to clean up on editor close.

Board-wide find/replace (public/js/app.js):
* Ctrl+Shift+H opens a centered overlay that fetches all cards with
  full bodies (api('api/cards'), bypasses lazy-load).
* Live search: typing in the find input scans all card bodies case-
  insensitive. Matches shown as a scrollable list with color dot,
  card title, occurrence count, and a context snippet with <mark>
  highlight around the first match.
* Status line: "12 occurrences in 5 cards" or "no matches".
* Replace All button (danger-styled, disabled until both inputs have
  text and matches exist). Click opens a showDialog confirmation:
  "Replace 12 occurrences of 'foo' with 'bar' across 5 cards?"
  On confirm: regex replace per card body → PATCH → _reloadAll.
* Escape / click-outside / Close button dismiss the overlay.

Shortcuts registered in the central registry for the help screen:
* ⌃ H (editor), ⌃ F (editor), ⌃ ⇧ H (global board-wide).

Tests (public/plugins/tests/board-find-replace.test.js):
* Ctrl+Shift+H opens the overlay (polls for #board-find-replace).
* Typing in find shows matching cards (creates 3 cards, 2 match,
  asserts status count + list contains matching titles + excludes
  non-matching title).
* Replace all updates card bodies after confirmation (creates 2
  cards with "hello", replaces with "goodbye", confirms dialog,
  verifies via API that bodies are "goodbye world goodbye" and
  "goodbye there").
* Replace all button disabled without replace text.

detail.test.js: "closes on ESC" stabilized — guard that detail is
actually open before dispatching Escape, poll (20×50ms) instead of
fixed sleep(150) for the .open class to be removed.

chore: bump version to 0.9.21

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 12:23:18 +02:00
thandClaude Opus 4.6 bf81d046e6 PDF upload, gallery → assets with type tabs, orphan detection fix
PDF upload support:
* index.php: application/pdf added to $mimeMap + $extMap in the
  /api/upload handler. PDFs are stored in uploads/ like images/audio.
* editor.js uploadFile(): detects PDF via MIME or .pdf extension.
  Inserts a markdown link [📄 filename](uploads/...) instead of an
  image embed. Paste + drop handlers updated to accept PDFs.
* index.php: new toolbar button #md-upload-pdf with ph-file-pdf icon
  next to the extract button. Triggers a hidden file input
  (accept=".pdf"). Wired in editor.js.

Gallery → Assets rename:
* index.php footer button: "Images" → "Assets", icon ph-folder-open.
* index.php gallery overlay header: "images" → "assets", icon
  ph-folder-open, upload input accept extended to include .pdf.
* Empty state text: "no images" → "no assets".

File-type tabs in the assets overlay:
* index.php: new #gallery-tabs div with 4 buttons (All / Images /
  Audio / PDF), each with data-filter attribute.
* gallery.js: fileType(url) helper returns 'image'|'audio'|'pdf'|
  'other'. Tab clicks toggle .active class and filter gallery-items
  by data-url + fileType. activeFilter persists across re-opens.
* CSS: .gallery-tab styling with hover + .active accent fill.

PDF rendering in the assets grid:
* gallery.js mediaTile(): PDFs render as ph-file-pdf icon + filename
  instead of a thumbnail. Orphaned PDFs show the same icon tile.
* Click on an orphaned PDF opens it in a new tab (window.open).
* "New card" from an orphaned PDF inserts a markdown link (not
  image embed).

Orphan detection fix (gallery.js):
* Root cause: loadCards() in app.js uses two-phase lazy loading —
  first /api/cards/meta (body=null on all cards), then batches of 25
  with full bodies. Opening the gallery before the last batch
  completes meant most cards had body=null, getReferencedUrls()
  found no URLs, and every file appeared orphaned.
* Fix: openGallery() now fetches its own card list with full bodies
  via api('api/cards') in parallel with api('api/uploads'), stored in
  a module-local galleryCards array. Both getReferencedUrls() and
  findCardForUrl() read from galleryCards instead of state.cards.
* Bonus: added a fallback regex uploads/[hex]{32}.[ext] that catches
  references in any format the specific patterns might miss (HTML
  attributes, custom blocks, inline text).

chore: bump version to 0.9.18

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:39:50 +02:00
thandClaude Opus 4.6 ce6ca73ea0 pulse: 1× local vs 3× remote, local cards don't trigger all-tab dot
Locally-created cards (editor, quick capture, duplicate) now get a
single subtle pulse instead of the triple-pulse reserved for relay-
synced cards. Local cards also never trigger the unread dot on the
fixed "all" bucket tab — the user just created them, there's nothing
"unseen" about their own work.

state.js: new state.recentlyCreatedIds Set. Populated by editor.js
doSave (POST), app.js quick capture (POST), and context-menu.js
duplicate (both date-rename and copy paths).

board.js renderBoard diff: new card ids are checked against
recentlyCreatedIds at diff time. Local ids go into a renderBoard-
local newLocalIds set (never into state.unseenCardIds). Remote ids
go into unseenCardIds as before.

board.js drain block (end of renderBoard): two-phase drain.
Phase 1: newLocalIds → pulseCards(local, 'card-pulse-local') with
900ms timeout, works in any bucket. Consumed recentlyCreatedIds
entries are deleted.
Phase 2: remaining unseenCardIds (remote only) → pulseCards(remote,
'card-pulse-new') with 2400ms timeout, only on activeBucket=all.

decorateAllUnreadDot() reads only state.unseenCardIds which now
contains exclusively remote ids → no dot from local card creation.

style.css: new .card-pulse-local class — same @keyframes but
animation-iteration-count:1. Anim-fast/slow overrides added.

chore: bump version to 0.9.16

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:15:53 +02:00
thandClaude Opus 4.6 88108ecc1b focus: restore body focus on overlay close, test shield, ESC closes results
Focus restoration:
* editor.js closeModal(): blur activeElement after the close so board
  shortcuts (arrows, bare keys) work immediately without clicking.
* detail.js closeDetail(): same blur, skipped when openedFromSearch
  (search input should keep focus in that case).
* search.js closeSearch(): blur after removing .open.
* calendar.js closeCalendar(): blur after closeDayPopup.
All four check activeElement !== body before blurring to avoid no-ops.

Test shield (loader.js):
* ensureProgressBar() now also creates #test-shield — a transparent
  fixed overlay (z-index one below the progress bar) covering the
  viewport below the bar. Blocks all real mouse interaction while
  tests run; synthetic events from the test suite still work because
  they bypass pointer-events. cursor:not-allowed as visual feedback.
  Removed by hideProgress() alongside the progress bar.

ESC closes test results (runner.js):
* The existing keydown listener now also handles Escape when the
  test-panel is visible. stopPropagation prevents the app's Escape
  chain from firing a second close underneath.

Tests (board.test.js):
* New describe "Board: Focus restoration after overlay close":
  - closing the editor returns focus to body
  - closing the detail view returns focus to body
  - closing search returns focus to body
  - arrow keys work after editor round-trip (enter → enter → escape)
    — the exact flow the user reported as broken. Dispatches
    ArrowDown → Enter (detail) → Enter (editor) → Escape (close) →
    asserts body focus → ArrowDown → asserts .card-focused exists.
* Fixed .not.toBe() → (x !== y).toBe(true) since the custom runner
  doesn't have a .not chain.

chore: bump version to 0.9.14

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:02:27 +02:00
thandClaude Opus 4.6 26ffa0e71f plugin(collab-buckets): collaborative buckets via relay
End-to-end shared buckets between relay tenants. Bucket metadata + members
sync through new relay routes (collab-buckets, collab-cards, collab-locks);
card content rides the existing inter-tenant encryption hop. Edit locks,
ownership transfer, LWW conflict stashing, undo for local-bucket destructive
actions, "Make collaborative…" upgrade path, and a resilient outbox for
relay-down create attempts. See plugins/collab-buckets/README.md and
TODO.md for the full picture.

Core hooks added so the plugin can integrate without monkey-patching:
- buckets.js context menu: collab-aware rename/color/delete + Members &
  owner / Make collaborative entries
- editor.js dispatches hyprcrd:editor-open / hyprcrd:editor-close for the
  per-card edit-lock heartbeat
- app.js exposes window.state for the plugin's MutationObserver
- index.php POST/PATCH/DELETE on /api/buckets refuse to mutate collab
  buckets directly (must go through the relay)
- Database.php adds buckets.collab_uid column + unique partial index
- import handler now restores color and collab_uid (was silently dropping
  color, which caused the test runner's auto-restore to wipe custom
  bucket colors)
- relay bootstrap creates collab_buckets, collab_bucket_members,
  collab_cards, collab_card_locks tables and prunes tombstones / expired
  locks on every request

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:49:53 +02:00
th 22f73ab3b9 fixes + theme 2026-04-11 13:01:27 +02:00
th 262b853c5b slideshow 2026-04-11 01:22:52 +02:00
th 3f4ba3c0f4 plugin infrastruktur 2026-04-10 07:58:07 +02:00
th dd2a995f6c canvas feature 2026-04-10 06:35:30 +02:00
th 0d494bf507 UI-tests und fixes aus tests 2026-04-09 23:21:37 +02:00
th 968d980be1 UI-tests und fixes aus tests 2026-04-09 22:18:45 +02:00
th 73da8fb849 cleanup and refactor 2026-04-09 19:39:56 +02:00
th e6243701a3 haufen sachen 2026-04-08 22:46:48 +02:00
th 416ca9e854 kalender und fixes 2026-04-08 17:24:55 +02:00
th 940d9bbde4 todo fixes 2026-04-08 15:55:43 +02:00
th e0fca064ae calender stuff 2026-04-08 14:04:23 +02:00
th 8e78468743 calendar 2026-04-08 07:47:00 +02:00
th 836826dba5 hilfe eingebaut 2026-04-07 23:57:30 +02:00
thandClaude Opus 4.6 9018f09351 fix reorder in virtual buckets, split view tags, editor/preview cleanup
- Fix card drag reorder in favorites/journal/current (filter logic
  now mirrors renderBoard)
- Split view shows tag-matched cards as own group alongside related
- Remove extract/tree-view buttons from detail preview (edit-only)
- Context menu tag input: Enter assigns tag directly
- Tag autocomplete closes on ESC/click-outside globally
- Close modal cleans up both autocomplete popups

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 22:42:08 +02:00
th 6855381d5c tags2 2026-04-07 22:02:17 +02:00
th 719f9d51ff tags 2026-04-07 21:58:45 +02:00
th a9603aa0e8 bak 2026-04-07 17:47:09 +02:00
th 03f57cbaee bak 2026-04-07 08:20:48 +02:00
th 9c71e65041 bak 2026-04-06 21:39:37 +02:00
th 0d4d369870 bak 2026-04-06 20:27:19 +02:00