Skip to content

Add section shortcut links - #205

Open
HamptonMakes wants to merge 7 commits into
mainfrom
hampton/section-shortcut-links
Open

Add section shortcut links#205
HamptonMakes wants to merge 7 commits into
mainfrom
hampton/section-shortcut-links

Conversation

@HamptonMakes

@HamptonMakes HamptonMakes commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Why

Plan sections need durable, shareable URLs without making readers hunt through the browser address bar.

What

  • Reveal a borderless link icon when a reader hovers or focuses a section heading
  • Copy the full section URL with immediate success or failure feedback
  • Preserve stable heading text for the outline, comments, and changed-section tracking

Risk Assessment

Low risk. This is isolated client-side presentation and clipboard behavior on rendered plan headings, with browser coverage for visibility and copying.

References

Hover Copied
Borderless section link on hover Copied feedback

Generated with Amp

@HamptonMakes
HamptonMakes marked this pull request as ready for review August 28, 2026 21:04

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 661be379a0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

permalink.setAttribute("aria-label", `Copy link to ${headingText}`)
permalink.title = "Copy link to this section"
permalink.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>'
permalink.addEventListener("click", event => this.copySectionLink(event))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use a Stimulus action for the permalink click

This direct listener is not a last-resort case: the newly created link is inside the connected controller and can use a data-action binding to invoke copySectionLink. Keeping the listener here violates the repository's explicit requirement to prefer standard Stimulus bindings whenever Stimulus can bind the element.

AGENTS.md reference: AGENTS.md:L90-L90

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated by Amp 🤖 — the generated permalink now uses a Stimulus data-action instead of a direct listener.

Comment on lines +69 to +70
const permalink = document.createElement("a")
permalink.className = "section-permalink"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Rebuild section links after live content swaps

When an open plan receives a live revision, live_update_controller.js replaces the children of #plan-content-body, but this ancestor controller remains connected and buildToc() is not called again. The replacement headings therefore never pass through this permalink creation block, so every section shortcut disappears until a full reload; listen for the in-place content replacement and rebuild the heading state rather than relying solely on connect().

AGENTS.md reference: AGENTS.md:L76-L80

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated by Amp 🤖 — live body replacements now dispatch a bubbling content-updated event; the content-nav action rebuilds headings, shortcut links, the outline, and scroll tracking. The checkbox live-update system spec verifies the rebuilt link.

const link = event.currentTarget

try {
await navigator.clipboard.writeText(link.href)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove thread parameters from copied section URLs

When the plan was opened from a notification using ?thread=<id>, the fragment-only href resolves against that full URL, so copying link.href retains the thread parameter. Opening the resulting section link causes text_selection_controller to auto-open and scroll to that comment thread, overriding the section destination; construct the copied URL from the canonical plan URL or remove transient query parameters before writing it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated by Amp 🤖 — shortcut hrefs now start from the canonical plan URL and strip query parameters before adding the section fragment. Coverage opens through a transient thread query and verifies it is absent from the shortcut.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up by Amp 🤖 — this now derives from the current page URL (so historical versions retain their own path), strips its query, and adds only the section fragment.

@HamptonMakes

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-28T21:49:36.764390Z 5ac10e9 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@HamptonMakes

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: fb2e9ecdeb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@HamptonMakes

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0196a12233

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1649 to +1650
display: flex;
align-items: center;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the title-slide accent above the heading

For presentation plans with a title slide, buildToc() adds this class to the slide's heading, so display: flex turns the h1::before accent bar defined in deck.css into a horizontal flex item beside the title instead of the block above it. This visibly breaks the title-slide composition—and can reflow it when Stimulus connects—in both the embedded deck and presentation mode; scope the row layout away from deck title headings or explicitly preserve their vertical accent layout.

AGENTS.md reference: AGENTS.md:L87-L89

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated by Amp 🤖 — title-slide headings now use a two-column grid with the accent spanning the full first row, preserving the accent above the title while centering the shortcut beside it. Added browser coverage for both the accent placement and title/link centerlines.

@HamptonMakes

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 50ee32c9b2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +81 to +84
const sectionUrl = new URL(pageUrl)
sectionUrl.hash = id
permalink.className = "section-permalink"
permalink.href = sectionUrl.href

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prevent section shortcuts from reusing existing IDs

When another element outside the H1–H3 outline already owns this generated ID, the shortcut copies a fragment that resolves to that earlier element rather than this heading. For example, the Markdown renderer assigns section-1 to a numbered H4 (markdown_helper.rb:119-125), but a later H2 titled “Section 1” also receives section-1 because usedIds only tracks the selected H1–H3 headings; its copied shortcut therefore opens the H4. Reserve all existing document IDs before choosing the shortcut target ID.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated by Amp 🤖 — generated Commonmarker self-anchors are replaced by the shortcut, and every remaining document ID is reserved before heading IDs are assigned. Browser coverage injects an existing fragment and verifies the heading receives a unique suffixed target.

Comment on lines +1693 to +1696
.section-permalink[data-copy-state]::after {
content: attr(data-copy-message);
position: absolute;
left: calc(100% + var(--space-xs));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep copy feedback inside the viewport

On a narrow viewport with a long heading, the flex layout places the shortcut at the card's right edge, and this absolute pseudo-element always opens to its right. The “Copied!”/failure bubble consequently extends beyond the viewport and creates horizontal overflow or partially hidden feedback; position it inward at phone widths or otherwise clamp it to the viewport.

AGENTS.md reference: AGENTS.md:L87-L89

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated by Amp 🤖 — at phone widths the feedback bubble is right-aligned to the shortcut so it opens inward. Browser coverage clicks it at 390px and verifies both the right edge and absence of horizontal overflow.

@HamptonMakes

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbf6a30a98

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +58 to +59
this._headings.forEach(heading => {
heading.querySelectorAll("a.anchor[id]").forEach(anchor => anchor.remove())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve generated heading fragments when replacing anchors

When a plan has repeated unnumbered headings, Commonmarker assigns fragments such as intro and intro-1, but removing those anchors and regenerating IDs with this controller's -2 suffix convention leaves the second heading as intro-2. Existing bookmarks and authored links to #intro-1 then have no target; preserve the generated anchor ID when promoting the fragment target to the heading, or retain an equivalent alias.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated by Amp 🤖 — generated duplicate fragments are now promoted verbatim from each empty self-anchor (for example intro and intro-1) instead of regenerated. A browser spec locks those exact IDs.

// shortcut replaces it; keeping both would leave two elements claiming
// the same fragment once the heading itself receives that id.
this._headings.forEach(heading => {
heading.querySelectorAll("a.anchor[id]").forEach(anchor => anchor.remove())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict removal to generated empty self-anchors

For a heading containing allowed raw HTML such as <a class="anchor" id="details" href="/details">Details</a>, this selector also removes the author-supplied link and its visible text. The Markdown sanitizer permits a, class, id, and href, so distinguish Commonmarker's empty self-link from authored descendants before deleting it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated by Amp 🤖 — promotion is now restricted to empty anchors whose href is their own fragment. Visible and non-self authored links remain intact, with browser coverage for an authored class=anchor link.

@HamptonMakes

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 5ac10e992a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant