Add pinned notes: paper notes with a pushpin, composed in a Note Pad widget - #361
Merged
Conversation
…widget Notes are a plugin-owned wpd_note CPT (non-public, custom REST controller at /desktop-mode/v1/notes). Write a note in the Note Pad widget, drag the sheet out of the pad, and drop it on the wallpaper, where it pins itself with an animated pushpin. The pin is the only drag handle; dragging a note to the recycle bin soft-trashes it with an Undo toast. Highlights: - Visibility maps to post status: private (default) or publish (public, read-only on every other desktop user's wallpaper, with an author chip and a steel-tinted pin). Only the owner can mutate a note, admins included; gate new-note creation via desktop_mode_notes_user_can_create. - Position, color, z-order, and a creation-time jitter seed (hashed from the initial text, never rewritten on edits) persist in postmeta, so the owner's placement and each note's subtle paper tilt are canonical. - Optimistic concurrency (updatedAtMs token, 409 with the server copy) plus Heartbeat delta sync for live cross-user updates, with a full re-hydration fallback when a delta overflows the server cap. - Motion set in src/notes/motion.ts: pin insertion thunk, pull-out with a paper imprint, pendulum swing while carried, snap-back with overshoot, and crumple-into-bin, all gated behind prefers-reduced-motion. - Drop routing goes through two new seams consulted by the existing targets (canvas-payloads.ts and recycle-bin-payloads.ts), since the drop-target registry allows one target per element. File drops landing on top of a note still reach the wallpaper canvas target. - Six pastel papers with dark-scheme variants as CSS custom properties; the palette is filterable via desktop_mode_notes_colors and filter-added slugs render unclamped. - Tests: 24 PHPUnit tests (CPT flags, ownership, conflicts, heartbeat visibility) and 31 Vitest tests (layer, drag payloads, drop routing, widget). Docs updated: hooks-reference, javascript-reference, api-index, architecture.
… visibility and custom item display
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new “pinned notes” feature to Desktop Mode: users compose notes in a Note Pad widget, pin them to the wallpaper (pushpin is the drag handle), sync across users (public notes) via REST + Heartbeat deltas, and support soft-trash with Undo via the Recycle Bin.
Changes:
- Introduces a new
wpd_noteCPT with a dedicated REST controller (/desktop-mode/v1/notes) and Heartbeat delta sync for cross-user updates. - Adds the client notes layer (rendering, drag/drop seams, motion/physics, trash flow) and a separate Note Pad widget bundle + styles.
- Extends drop routing seams for the wallpaper canvas and recycle bin to support handler-owned payloads (notes) without claiming new drop targets.
Reviewed changes
Copilot reviewed 44 out of 46 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
vite.config.js |
Adds the widget-notes Vite build target for the Note Pad widget bundle. |
package.json |
Adds build:widget-notes and includes it in the main build chain. |
src/types.ts |
Extends DesktopConfig with optional notesUrl to gate client boot. |
src/desktop.ts |
Boots the pinned-notes feature in the main shell bundle. |
src/notes/index.ts |
Composes notes boot: installs REST deps, mounts layer, drop handlers, and cross-bundle creation event listener. |
src/notes/types.ts |
Defines note wire shape, drag payload shapes, Heartbeat payloads, and the cross-bundle CustomEvent name. |
src/notes/rest.ts |
Adds a tracked-fetch REST client with nonce handling and a typed 409 conflict error. |
src/notes/heartbeat.ts |
Wires notes into the Heartbeat contribute/subscribe bus. |
src/notes/colors.ts |
Adds built-in color cycle helpers and non-clamping slug sanitization for DOM rendering. |
src/notes/pin.ts |
Centralizes pushpin sizing/anchor constants and <img> construction. |
src/notes/motion.ts |
Implements pinned-note animation sequences and deterministic jitter. |
src/notes/trash.ts |
Implements soft-trash + Undo flow using notes REST endpoints and toasts. |
src/notes/drop-handlers.ts |
Registers note handlers into canvas/bin seams (create/reposition/trash) with ghost-offset coordinate math. |
src/notes/layer.ts |
Implements the notes wall layer and per-note controller behavior (editability, drag, z-order, heartbeat updates). |
src/plugins/notes-widget/index.ts |
Implements the Note Pad widget composer UI, drag tear-off payload, and keyboard pin path (POST + CustomEvent). |
src/plugins/notes-widget/styles.css |
Adds Note Pad widget chrome styles (consumes shared note tokens). |
src/desktop-files/canvas-payloads.ts |
Adds a payload-handler seam consulted by the existing wallpaper canvas drop target. |
src/desktop-files/recycle-bin-payloads.ts |
Adds a payload-handler seam consulted by the existing recycle bin drop targets. |
src/desktop-files/layer.ts |
Routes non-file payloads through the canvas payload seam; avoids grid preview for handler-owned payloads. |
src/desktop-files/recycle-bin-targets.ts |
Routes unknown payloads through the recycle-bin payload seam (notes trash path). |
includes/notes/bootstrap.php |
Bootstraps the server-side pinned-notes feature modules. |
includes/notes/cpt.php |
Registers wpd_note CPT, meta, sanitizers, palette filter, and untrash status restoration. |
includes/notes/rest.php |
Adds REST routes for list/create/update/delete/restore with owner-only mutation and optimistic concurrency. |
includes/notes/heartbeat.php |
Adds server Heartbeat delta computation and visibility rules matching the REST list. |
includes/notes/recycle-bin.php |
Opts notes into recycle bin capture and enforces owner-only bin visibility/restore/purge + badge count correction. |
includes/widgets/widget-notes.php |
Registers/enqueues the widget’s assets and registers the Note Pad widget definition. |
includes/assets.php |
Registers desktop-mode-notes stylesheet for pinned-notes layer visuals. |
includes/render/assets.php |
Enqueues notes stylesheet and exposes notesUrl in desktopModeConfig. |
includes/recycle-bin/capture.php |
Expands default captured post types to include non-builtin show_ui CPTs and dedupes the list. |
includes/recycle-bin/store.php |
Improves recycle-bin row shaping for CPTs (menu dashicon + excerpt/content subtitle). |
docs/javascript-reference.md |
Documents pinned-note drag payload types, the creation CustomEvent, and notesUrl config. |
docs/hooks-reference.md |
Documents new notes filters and updated recycle-bin capture behavior. |
docs/architecture.md |
Documents pinned notes feature architecture and the drop-routing seams. |
docs/api-index.md |
Adds the pinned-notes creation CustomEvent to the API index. |
desktop-mode.php |
Wires the new notes bootstrap and widget registration into plugin load. |
tests/vitest/notes-rest.test.ts |
Adds REST client tests (URLs, payload mapping, typed 409 conflict handling). |
tests/vitest/notes-layer.test.ts |
Adds layer tests (render modes, jitter stability, heartbeat deltas, trash/undo). |
tests/vitest/notes-drop-handlers.test.ts |
Adds seam routing tests for canvas/bin drop paths and coordinate math. |
tests/vitest/notes-widget.test.ts |
Adds widget composer tests (drag gating, payload shape, keyboard pin path event handoff). |
tests/phpunit/tests/notesCpt.php |
Adds CPT + sanitizer + untrash status tests. |
tests/phpunit/tests/notesRest.php |
Adds REST route tests (ownership, visibility, concurrency, trash/restore, heartbeat). |
tests/phpunit/tests/notesRecycleBin.php |
Adds recycle-bin integration tests for notes ownership and CPT bin behavior. |
assets/css/notes.css |
Adds pinned-notes shared tokens and the pinned note / ghost visuals, including reduced-motion handling. |
assets/images/pushpin.svg |
Adds the pushpin asset with documented anchor geometry. |
assets/js/widget-notes.css |
Adds built widget CSS output for the Note Pad widget. |
assets/js/widget-notes.min.css |
Adds minified built widget CSS output. |
Files not reviewed (1)
- assets/js/widget-notes.min.css: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…titles, and ensure owner attribution for unstamped trashed notes
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Notes.mov
A new, self-contained notes feature for the desktop. You write a note in the Note Pad widget, drag the sheet out of the pad, and drop it on the wallpaper, where it pins itself with an animated pushpin. The pin is the only drag handle. Dragging a note to the recycle bin soft-trashes it with an Undo toast. Marking a note public shows it, read-only and with author attribution, on every other desktop user's wallpaper.
This is separate from the Guidelines-backed sticky notes layer, which is untouched.
Data model (PHP)
wpd_noteCPT: non-public, excluded from search, absent from core REST (includes/notes/cpt.php).private(default) orpublish(public). Only the owner can edit, move, recolor, or delete a note, and administrators do not bypass ownership. New-note creation is gated by thedesktop_mode_notes_user_can_createfilter._wpd_note_x/_wpd_note_y, normalized 0..1), paper color (_wpd_note_color, whitelist filterable viadesktop_mode_notes_colors), z-order (_wpd_note_z), and a creation-time jitter seed (_wpd_note_seed, hashed from the initial text and never rewritten, so edits do not re-tilt the paper)./desktop-mode/v1/notes(includes/notes/rest.php) with optimistic concurrency: a staleupdatedAtMstoken returns 409 with the server copy attached.includes/notes/heartbeat.php) streams cross-user changes; the client falls back to a full re-hydration when a delta overflows the server cap.Client (TS)
src/plugins/notes-widget/, its own bundle): a pad of pastel paper. The top sheet is the draft; two peek sheets underneath advertise the next colors in the cycle; a folded corner cycles the color; six paper-dot swatches pick directly; a Public checkbox and a keyboard "Pin to desktop" path (Ctrl+Enter) round it out. Empty drafts refuse to lift with a small shake.src/notes/, main bundle): renders the wall. Deterministic per-note jitter (paper tilt, pin offset and twist) from the creation seed. Owner chrome (color dot showing the next color, globe/lock visibility toggle) is hover-revealed; other users' notes render a steel pin that is scenery, not a handle.src/notes/motion.ts): pin insertion thunk (fall, strike squash, spring settle, ripple), pull-out with a paper imprint left behind, pendulum swing while carried (driven by drag velocity), snap-back with overshoot on cancel, crumple-into-bin on trash. All gated behindprefers-reduced-motion.note-draft,note) route through two small seams consulted by the existing targets:src/desktop-files/canvas-payloads.tsandsrc/desktop-files/recycle-bin-payloads.ts. File drops landing on top of a pinned note still fall through to the wallpaper canvas target.Review
A high-effort multi-agent review ran over the diff before this PR; the ten confirmed findings were all fixed in place, including: live nonce reads so long sessions survive the nonce_life rollover, newest-first list capping, truncated-delta re-hydration, flushing edits typed while the create POST was in flight, drag-listener leaks on click-only pin gestures, pinned notes no longer blocking wallpaper file drops, filter-added colors rendering unclamped, a creation capability filter, remote z-order changes applying on heartbeat, and visible failure feedback on the keyboard pin path.
Testing
npm run build,npm run lint,npm run typecheck,npm run test:js(1897 passing),npm run test:php(1113 passing) all green.Docs
docs/hooks-reference.md(both new filters),docs/javascript-reference.md(payload contracts,notesUrlconfig,desktop-mode-note-createdevent),docs/api-index.md,docs/architecture.md.