Skip to content

Migrated Tags list page to new ListPage + PageHeader pattern#27896

Merged
peterzimon merged 6 commits into
mainfrom
DES-1382/shade-tagslist-layout-migration
May 18, 2026
Merged

Migrated Tags list page to new ListPage + PageHeader pattern#27896
peterzimon merged 6 commits into
mainfrom
DES-1382/shade-tagslist-layout-migration

Conversation

@peterzimon
Copy link
Copy Markdown
Contributor

@peterzimon peterzimon commented May 14, 2026

ref https://linear.app/ghost/issue/DES-1382/tags-list-page-header-migration

  • Replaced the Tags page's deprecated Header primitive and thin wrapper components (TagsLayout, TagsHeader, TagsContent) with the new ListPage template + PageHeader pattern from Shade
  • Public/Internal tab toggle moved into PageHeader.Actions alongside the "New tag" button
  • Sets the pattern for future list-page migrations (Comments, Members, Automations)
  • Proper mobile view was implemented for the tags list screen

ref https://linear.app/tryghost/issue/DES-1382/

- Replaced deprecated Header primitive and wrapper components
  (TagsLayout, TagsHeader, TagsContent) with ListPage + PageHeader
- Public/internal tab toggle moved into PageHeader.Actions
- Updated ListPage: uses Stack primitives internally, grows to fill
  its flex parent, removes Pagination slot, exports ViewBar/FilterBar
  from the patterns barrel
- Empty/loading/error states vertically centred in ListPage.Body

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 07979ed7-b309-4552-9cda-8134915d684d

📥 Commits

Reviewing files that changed from the base of the PR and between 3550e16 and f1d786f.

📒 Files selected for processing (2)
  • apps/posts/src/views/Tags/tags.tsx
  • apps/shade/src/components/page-templates/list-page.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/shade/src/components/page-templates/list-page.tsx
  • apps/posts/src/views/Tags/tags.tsx

Walkthrough

This PR removes three tags-specific components (TagsContent, TagsHeader, TagsLayout) and refactors the Tags page to use MainLayout + ListPage. The Tags page now derives its filter from useSearchParams, renders a PageHeader with a ToggleGroup and mobile menu, and moves loading/error/empty/list states into ListPage.Body. ListPage was refactored to use the shared Stack primitive, accept passthrough div props, and the Pagination slot was removed. patterns.ts now re-exports view-bar and filter-bar.

Possibly related PRs

  • TryGhost/Ghost#27860: Related to tags refactor and changes to PageHeader composition, including view-bar/filter-bar pattern usage.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: migrating the Tags list page to use new ListPage and PageHeader patterns, replacing deprecated components.
Description check ✅ Passed The description is directly related to the changeset, detailing the component replacements, pattern migrations, and implementation details of the tags page refactoring.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch DES-1382/shade-tagslist-layout-migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/posts/src/views/Tags/tags.tsx (1)

12-26: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate the type query param before using it in the API filter.

type currently accepts any query value and is passed straight into visibility. Unsupported values can produce inconsistent toggle selection and unexpected API filtering.

Suggested fix
-    const qs = new URLSearchParams(search);
-    const type = qs.get('type') ?? 'public';
+    const qs = new URLSearchParams(search);
+    const rawType = qs.get('type');
+    const type = rawType === 'internal' ? 'internal' : 'public';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/posts/src/views/Tags/tags.tsx` around lines 12 - 26, Validate the raw
query param before passing it to the API: read the raw type via
useLocation()/URLSearchParams, check it against an allowed set (e.g.
['public','private'] or the enum your API expects), and if it’s not a supported
value fall back to the default ('public'); then pass this validated value into
useBrowseTags filter.visibility so toggle selection and API filtering remain
consistent (refer to the variables type, useLocation, URLSearchParams, and the
useBrowseTags call with filter.visibility).
🧹 Nitpick comments (2)
apps/shade/src/patterns.ts (1)

3-4: ⚡ Quick win

Use @/ alias for new Shade internal re-exports.

Please switch these new re-exports to the @/ alias to match the Shade internal import/export rule.

Proposed change
-export * from './components/patterns/view-bar';
-export * from './components/patterns/filter-bar';
+export * from '@/components/patterns/view-bar';
+export * from '@/components/patterns/filter-bar';

As per coding guidelines, "Use the @/ alias for cross-file imports within Shade itself".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/shade/src/patterns.ts` around lines 3 - 4, Update the re-exports in
patterns.ts to use the Shade internal alias instead of relative paths: replace
export * from './components/patterns/view-bar' and export * from
'./components/patterns/filter-bar' with the equivalent exports using the '@/...'
alias (e.g., export * from '@/components/patterns/view-bar' and export * from
'@/components/patterns/filter-bar') so imports follow the internal cross-file
import/export rule.
apps/shade/src/components/page-templates/list-page.stories.tsx (1)

137-165: ⚡ Quick win

Add a one-line Storybook description for the updated EmptyState story.

This story was modified but still doesn’t include parameters.docs.description.story.

Suggested fix
 export const EmptyState: Story = {
     name: 'Empty state',
+    parameters: {
+        docs: {
+            description: {
+                story: 'Use when the list has no items and you want a centered empty-state CTA.'
+            }
+        }
+    },
     render: () => (

As per coding guidelines: apps/shade/src/components/**/*.stories.tsx — “Add per-story parameters.docs.description.story as one-liner explaining when to use that variant”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/shade/src/components/page-templates/list-page.stories.tsx` around lines
137 - 165, Add a one-line Storybook description to the EmptyState story by
attaching parameters.docs.description.story to the EmptyState export; locate the
EmptyState constant (export const EmptyState: Story) and set
EmptyState.parameters = { docs: { description: { story: 'One-line explanation of
when to use the Empty state variant' } } } (use an appropriate one-liner
describing when to use this empty-members variant).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/posts/src/views/Tags/tags.tsx`:
- Around line 12-26: Validate the raw query param before passing it to the API:
read the raw type via useLocation()/URLSearchParams, check it against an allowed
set (e.g. ['public','private'] or the enum your API expects), and if it’s not a
supported value fall back to the default ('public'); then pass this validated
value into useBrowseTags filter.visibility so toggle selection and API filtering
remain consistent (refer to the variables type, useLocation, URLSearchParams,
and the useBrowseTags call with filter.visibility).

---

Nitpick comments:
In `@apps/shade/src/components/page-templates/list-page.stories.tsx`:
- Around line 137-165: Add a one-line Storybook description to the EmptyState
story by attaching parameters.docs.description.story to the EmptyState export;
locate the EmptyState constant (export const EmptyState: Story) and set
EmptyState.parameters = { docs: { description: { story: 'One-line explanation of
when to use the Empty state variant' } } } (use an appropriate one-liner
describing when to use this empty-members variant).

In `@apps/shade/src/patterns.ts`:
- Around line 3-4: Update the re-exports in patterns.ts to use the Shade
internal alias instead of relative paths: replace export * from
'./components/patterns/view-bar' and export * from
'./components/patterns/filter-bar' with the equivalent exports using the '@/...'
alias (e.g., export * from '@/components/patterns/view-bar' and export * from
'@/components/patterns/filter-bar') so imports follow the internal cross-file
import/export rule.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e89bef58-4095-45da-9e9e-3df353ede4e5

📥 Commits

Reviewing files that changed from the base of the PR and between e55b30b and e19941a.

📒 Files selected for processing (7)
  • apps/posts/src/views/Tags/components/tags-content.tsx
  • apps/posts/src/views/Tags/components/tags-header.tsx
  • apps/posts/src/views/Tags/components/tags-layout.tsx
  • apps/posts/src/views/Tags/tags.tsx
  • apps/shade/src/components/page-templates/list-page.stories.tsx
  • apps/shade/src/components/page-templates/list-page.tsx
  • apps/shade/src/patterns.ts
💤 Files with no reviewable changes (3)
  • apps/posts/src/views/Tags/components/tags-layout.tsx
  • apps/posts/src/views/Tags/components/tags-content.tsx
  • apps/posts/src/views/Tags/components/tags-header.tsx

ref https://linear.app/tryghost/issue/DES-1382/

- On mobile, the Public/Internal toggle collapses into a ··· dropdown
  with DropdownMenuCheckboxItem entries for each tab
- On mobile, the New tag button shows a + icon only (text hidden below sm)
- Switched from useLocation + URLSearchParams to useSearchParams for
  cleaner search param updates from the dropdown handlers

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@peterzimon peterzimon changed the title 🎨 Migrated Tags list page to new ListPage + PageHeader pattern Migrated Tags list page to new ListPage + PageHeader pattern May 14, 2026
@weylandswart weylandswart self-requested a review May 14, 2026 18:33
Copy link
Copy Markdown
Contributor

@weylandswart weylandswart left a comment

Choose a reason for hiding this comment

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

👍 Very nice!

Comment thread apps/posts/src/views/Tags/tags.tsx Outdated
@peterzimon peterzimon merged commit 811533b into main May 18, 2026
41 checks passed
@peterzimon peterzimon deleted the DES-1382/shade-tagslist-layout-migration branch May 18, 2026 08:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants