Skip to content

release: support clickable links - #32

Draft
dwilding wants to merge 24 commits into
mainfrom
support-links
Draft

dwilding wants to merge 24 commits into
mainfrom
support-links

Conversation

@dwilding

Copy link
Copy Markdown
Owner

This is experimental work. I'm not sure whether I actually want to merge it.

dwilding and others added 9 commits October 22, 2026 13:12
Render a transparent overlay behind the task editor that mirrors the
textarea's metrics. Any http(s) URL in Today or Inbox is underlined
with a subtle themed color. Hold Cmd (macOS) or Ctrl (Windows/Linux)
and click a link to open it in a new tab.

Zero dependencies: plain DOM APIs only.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Set the textarea cursor to pointer when Cmd (macOS) or Ctrl
(Windows/Linux) is held and the pointer is over a link. Track the
pointer position so pressing or releasing the modifier key updates
the cursor without mouse movement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract modifierHeld() to replace three copies of the platform
modifier check. Merge the keydown and keyup listeners into one
loop. Comment the non-obvious mechanics: the width sync, the
scroll copy, the pointer-events toggle, and the overlay technique.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The tests embed app/index.html in an iframe and drive the real app:
rendering, re-render triggers, scroll sync, hit-testing, and the hand
cursor. Serve the repository root and open tests/test_links.html in
a browser to run them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The final pass over link handling found one gap: the url regex was
case-sensitive, so a pasted HTTPS://... url never became a link. Match
schemes in any case, and cover the gap in the tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Serve the repository and run the test page in the runner's
preinstalled headless Chrome. The virtual time budget lets the
async test sequence settle before Chrome dumps the DOM, and the
step greps the dumped title for the passing result. On failure
it prints the test output block so the run log shows which
checks failed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the headless test run into a just recipe so CI and local
runs share one entry point. Pin the actions to commit SHAs,
drop the workflow's permissions to nothing, and rename the
file to .yaml.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The uvx indirection existed only to install just on the
runner. Run the headless tests directly in the workflow
instead, and keep the app-test recipe for local use.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The app tests stay out of the commit hooks: just app-test opens a
browser and waits for Ctrl+C, so it can't gate commits. Run it on
demand, and let the CI workflow gate pushes and pull requests.

The first run of the fixers appended missing final newlines and
trimmed one trailing space, so the sha1 references are updated too.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dwilding dwilding added the server Affects server installations label Oct 22, 2026
The overlay no longer sets z-index: 1. It still paints above the
static textareas, and the action menus now paint above it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
dwilding and others added 14 commits October 22, 2026 23:17
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CI runs on ubuntu, so platformApple was always false and the Cmd
branches never executed. The test page now accepts ?platform=mac:
it loads the app in a srcdoc iframe with navigator.platform
spoofed as MacIntel, injected before main.js captures the platform.
CI runs the suite in both modes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The overlay syncs to scrollTop, which stays clamped while the editor
rubber-bands, so the underlines would drift during the bounce. The
tests assert the computed overscroll-behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The final review found two gaps in the link overlay:

Scrolling moves the content under a stationary pointer without any
mousemove, so the hand cursor and the tooltip went stale. Track the
last pointer position and modifier state, re-evaluate the cursor in
the scroll listener, and clear the state when the window loses focus,
since the modifier can be released while the window is unfocused
without a keyup reaching the page.

Nothing guarded font-metric parity between the textarea and the
overlay, so a future font change on one but not the other would drift
the underlines while every existing check still passed. Add a
computed-style tripwire to the test suite.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The overlay rendered from the editor's value and scroll position before
three mutators finished writing them: inboxSnoozeSelected rendered before
its scroll-measurement dance, selectUnsnoozed rendered before focus()
could scroll to the caret, and the body Ctrl+Enter handler rendered
before it reset the scroll to the top of the gap. In each case the
underlines could stay stale until the next render.

Move each storeThenSave call after the final value and scrollTop
assignment so the overlay always renders from the final state. The
scroll-measurement dance in inboxSnoozeSelected is unchanged.

The mutators test section drives every code path that changes the
editor's text or scroll position and verifies the overlay against the
editor afterwards. Each check starts from the seeded state, so a
failure cannot leak its setup into the checks that follow. Mutation
testing confirms each fix is caught by its check.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Completed tasks render URLs as native anchors in the normal view.
The editing views keep plain text, so the whole task stays one
coherent move-back control. simple.css appends the URL after
external links; suppress that echo on task links, which already
show the URL as their text.

Anchors open in a new tab with noopener noreferrer. Trailing
punctuation is trimmed from the href but kept in the surrounding
text. Task text is rendered with DOM APIs, not innerHTML, so
markup in a task stays inert.

The tests drive the real page in an iframe: rendering, escaping,
the editing views, the import flow, the storage event, and the
todo.txt round trip.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The bounce fix lives on the bare textarea selector in style.css,
which every editor page loads, so it already applies everywhere.
The tests only asserted the Today editor. Load each other editor
page in the iframe and assert the computed overscroll-behavior on
every textarea it renders: icon-normal, icon-notify, week, send,
demo, and demo-week.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

server Affects server installations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant