Skip to content

feat(web): issues page answers the pull request page's keyboard - #1421

Merged
donjor merged 1 commit into
hyprwsfrom
t3code/issues-keyboard-parity
Sep 29, 2026
Merged

donjor merged 1 commit into
hyprwsfrom
t3code/issues-keyboard-parity

Conversation

@donjor-agent

@donjor-agent donjor-agent Bot commented Sep 29, 2026

Copy link
Copy Markdown

🤖 claude/anthropic claude-opus-5-5 (high)

What Changed

The issues page answers the same keys as the Pull Requests page.

Key Does
Mod+F Focuses and selects the issue search
↓ in search Steps into the first row
↑ / ↓ on a row Moves between rows; ↑ on the first returns to search
Home / End First or last row
Enter Opens the focused row (unchanged)
Mod+W Closes the open issue (rightPanel.close)
Mod+Shift+C Copies the open issue's link (thread.copyReference)
  • Close and copy read the user's keybindings, like the PR page
  • The thread's issues panel keeps arrow keys only; the thread owns the rest
  • The focus step is a pure helper with its own tests

Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

UI Changes

Row focus Link copied
row focused link copied

Before: the same key sequence; nothing moves, so Enter opens nothing

keyboard-before.mp4

After: search, step down, open, copy, close, back to search

keyboard-after.mp4

Checks

tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

@donjor
donjor force-pushed the t3code/issues-keyboard-parity branch from 79a4018 to 6ef32ca Compare September 29, 2026 20:50
@donjor
donjor force-pushed the t3code/issues-keyboard-parity branch from 6ef32ca to cb94af6 Compare September 29, 2026 22:42
Base automatically changed from t3code/rework-fork-issues-surface to hyprws September 29, 2026 22:53
Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
@donjor
donjor force-pushed the t3code/issues-keyboard-parity branch from cb94af6 to 191eeb0 Compare September 29, 2026 22:54
@donjor
donjor added this pull request to stack #1436 September 29, 2026 22:55
@donjor
donjor merged commit d31f0ba into hyprws Sep 29, 2026
9 checks passed
@donjor
donjor deleted the t3code/issues-keyboard-parity branch September 29, 2026 23:03
donjor added a commit that referenced this pull request Sep 29, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 29, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 29, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 29, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 29, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 30, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 30, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 30, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Sep 30, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 1, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 1, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 1, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 1, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 2, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 2, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 2, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 2, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 8, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 8, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 10, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issue list keeps its rows while a new state or search loads, like the Pull Requests list.

- **Held rows:** the last answer for the same projects stands in
- **Narrowed:** held rows filter to the new state and search terms
- **Search terms:** title, number, repository, author, labels
- **Qualifiers:** `label:bug` and the like stay GitHub's to apply
- **Marked:** rows dim; the group header says what is loading
- **Ghosts:** only when nothing held fits, or a first load
- **No false empty:** a narrowed-to-nothing carry shows ghosts, not "No issues"

The carry is a pure helper with focused tests; `useGitHubIssueList` returns `carried` beside `data`.

## Why

Every new state or search was a new query that started empty, so the whole list blanked to skeletons for a few seconds.
The rows the reader already had were the best answer until GitHub replied.

## UI Changes

| Before | After |
| --- | --- |
| ![switching before](https://github.com/user-attachments/assets/4c28db52-be3c-4c00-b829-c4cc93c3ddc6) | ![switching after](https://github.com/user-attachments/assets/2e3b06ba-a693-4fae-84a7-c213f7ece9be) |
| ![searching before](https://github.com/user-attachments/assets/98fc1e96-a0e7-47c0-9919-644fae7baf60) | ![searching after](https://github.com/user-attachments/assets/0173a4a1-b6f2-462c-b6ae-6191a816f627) |

**Before:** Open to All, then search; the list blanks each time

https://github.com/user-attachments/assets/fec4ef5c-abe5-48c8-bf52-a9092617e503

**After:** same flow; rows stay and narrow in place

https://github.com/user-attachments/assets/8365227c-1205-4008-b32f-9a1b7a54867c

## Checks

```text
tsc --noEmit (apps/web)                    → exit 0
vp test run carry logic + issues page      → exit 0 (10 tests)
vp lint (changed files)                    → exit 0
vp run fork:ci                             → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1421.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 13, 2026
> 🤖 claude/anthropic claude-opus-5-5 (high)

## What Changed

The issues page answers the same keys as the Pull Requests page.

| Key | Does |
| --- | --- |
| **Mod+F** | Focuses and selects the issue search |
| **↓ in search** | Steps into the first row |
| **↑ / ↓ on a row** | Moves between rows; ↑ on the first returns to search |
| **Home / End** | First or last row |
| **Enter** | Opens the focused row (unchanged) |
| **Mod+W** | Closes the open issue (`rightPanel.close`) |
| **Mod+Shift+C** | Copies the open issue's link (`thread.copyReference`) |

- Close and copy read the user's keybindings, like the PR page
- The thread's issues panel keeps arrow keys only; the thread owns the rest
- The focus step is a pure helper with its own tests

## Why

The page has no ChatView, so shared panel shortcuts did nothing there.
A reader could search but never reach a result without the mouse.

## UI Changes

| Row focus | Link copied |
| --- | --- |
| ![row focused](https://github.com/user-attachments/assets/baa34781-637d-44e3-a4a0-1aca36cb9fe2) | ![link copied](https://github.com/user-attachments/assets/2c032775-0cd6-4e90-b00b-221c8bc931ce) |

**Before:** the same key sequence; nothing moves, so Enter opens nothing

https://github.com/user-attachments/assets/f3bfd9a2-ec6e-40ac-9614-f5d5c5b55ed6

**After:** search, step down, open, copy, close, back to search

https://github.com/user-attachments/assets/6e9d7db1-1992-4050-bec7-eb51c86785ff

## Checks

```text
tsc --noEmit (apps/web)                       → exit 0
vp test run keyboard logic + issues page      → exit 0 (9 tests)
vp lint (changed files)                       → exit 0
vp run fork:ci                                → exit 0
```

## Checklist

- [x] This PR is small and focused
- [x] I explained what changed and why
- [x] I included before/after screenshots for any UI changes
- [x] I included a video for animation/interaction changes

Stacked on #1420.

Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: github-issues
Fork-Tier: qol
Fork-Upstreamable: no

<!-- gh-bot:attest {"v":2,"repo":"RSI-Software/t3code-hyprws","ref":"t3code/issues-keyboard-parity@79a4018","agents":[{"role":"host","iface":"claude","provider":"anthropic","model":"claude-opus-5-5","effort":"high","harness":"[email protected]","session":"7bf97c33c682"}],"ts":"2026-09-29T09:22:43Z"} -->
Co-authored-by: donjor <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant