Skip to content

Consolidate listing pages with unified grid cards and modal system#2101

Open
aaronpowell wants to merge 2 commits into
stagedfrom
aaronpowell/extensions-grid-layout
Open

Consolidate listing pages with unified grid cards and modal system#2101
aaronpowell wants to merge 2 commits into
stagedfrom
aaronpowell/extensions-grid-layout

Conversation

@aaronpowell

Copy link
Copy Markdown
Contributor

Description

This PR consolidates the listing pages (Extensions, Agents, Instructions, Skills, Hooks, Workflows, Plugins) from a stacked list layout to a unified card grid design, eliminating significant HTML/CSS/JavaScript duplication across pages.

Why

The website had implemented card-grid layouts independently on each listing page, resulting in:

  • Duplicated card HTML templates in 7 different *-render.ts files
  • Duplicated grid CSS and card styling in global.css with 5 per-page selector groups
  • Duplicated detail popup modals with separate markup on each page
  • Duplicated card-click and modal-wiring logic in each page script
  • Maintenance burden when fixing bugs or adjusting styling (must edit 7+ files)

Approach

1. Shared card rendering primitives

  • Created card-model.ts with a unified SharedCardRenderItem interface used across all pages
  • Created card-render.ts with reusable renderSharedCardHtml() helper to eliminate per-page template duplication
  • Each page adapter now maps its data into this shared contract and calls the unified renderer

2. Unified modal system

  • Merged all detail-popup modals into the existing Modal.astro component
  • Extended modal.ts with openCardDetailsModal() function supporting both file-view and card-details modes
  • Switched from per-page modal markup to a single modal that displays content via configuration
  • Applied dynamic imports for marked and front-matter to avoid Vite "Outdated Optimize Dep" errors

3. Consolidated CSS

  • Introduced .listing-cards-page class to replace 5 duplicated page-specific selector groups
  • Applied this class to all 5 affected pages (instructions, agents, hooks, workflows, plugins)
  • Reduced CSS duplication while preserving consistent styling across pages

4. In-app source viewing

  • Changed Source action buttons from external <a> tags to <button> elements with data-open-file-path handler
  • Added global click listener in modal.ts to open resource files in-app instead of navigating to GitHub
  • Extracted getResourceType(filePath) helper to auto-detect file types from extensions
  • Applied to Instructions, Agents, Skills, Hooks, Workflows, and local Plugins
  • External plugins retain repository link behavior for backward compatibility

5. Restored plugin items visibility

  • Plugin cards now display included items (agents, skills, etc.) in the detail popup
  • Shows items as formatted tags (first 24, then "+N more" if exceeding limit)
  • Provides visibility into what resources are bundled with each plugin

Files changed

Created:

  • website/src/scripts/pages/card-model.ts - Shared card/grid data model interfaces
  • website/src/scripts/pages/card-render.ts - Shared HTML card rendering helpers

Modified:

  • website/src/scripts/modal.ts - Unified modal system with in-app file open handler
  • website/src/styles/global.css - Added .listing-cards-page class, consolidated CSS, fixed keyword tag clipping
  • website/src/pages/{agents,instructions,extensions,skills,hooks,workflows,plugins}.astro - Added shared class, removed per-page modals
  • website/src/scripts/pages/{agents,instructions,skills,hooks,workflows,plugins}.ts - Use unified modal and in-app file handler
  • website/src/scripts/pages/{*}-render.ts - All migrated to shared renderSharedCardHtml()
  • website/src/scripts/pages/extensions-render.ts - Fixed nested button markup (thumbnail button → div)
  • Extension canvas.json files - Minor updates

Testing notes

  • Verified card grids render on all 7 listing pages
  • Verified card clicks open detail modals with proper content
  • Tested image galleries work on extension cards
  • Tested in-app source viewing opens files in modal vs external links
  • Confirmed plugin items display and plugin items count correctly
  • Verified responsive grid layout at different viewport sizes
  • Confirmed keyboard navigation (Escape closes modal) works

Non-obvious decisions

  • In-app source viewing: External plugins still use repository links since we can't easily fetch external repo file contents. Local plugins use in-app modal for consistency.
  • Nested button fix: Extended the thumbnail wrapper from <button> to <div class="resource-thumbnail-btn"> to fix browser DOM rewriting of invalid nested buttons (fixes Coffilot card rendering).
  • Dynamic imports for modal markdown: Direct imports caused Vite "Outdated Optimize Dep" errors; switched to async dynamic imports that load only when entering details mode.

Type of Contribution

  • Update to website listing pages and modal infrastructure
  • Refactoring/consolidation (no new features, pure code organization)

By submitting this pull request, I confirm that my contribution abides by the Code of Conduct and will be licensed under the MIT License.

Copilot AI review requested due to automatic review settings June 23, 2026 04:04
@github-actions github-actions Bot added canvas-extension PR touches canvas extensions new-submission PR adds at least one new contribution website-update PR touches website content or code labels Jun 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the website’s resource listing pages to use a shared card-grid renderer and a unified modal system, aiming to remove duplicated HTML/CSS/JS across Extensions, Agents, Instructions, Skills, Hooks, Workflows, and Plugins.

Changes:

  • Introduces shared card rendering helpers (card-render.ts) and shared card data types (card-model.ts) and migrates per-page *-render.ts templates to use them.
  • Adds a “card details” mode to the existing modal (openCardDetailsModal) and updates listing page scripts to open details modals and in-app source views.
  • Consolidates/extends global styling for card grids and details-mode modal layouts; updates several extension canvas.json metadata entries.
Show a summary per file
File Description
website/src/styles/global.css Adds modal “details-mode” styling and shared listing card grid styles.
website/src/scripts/pages/workflows.ts Switches to card-details modal and native <select multiple> filtering; adds modal actions.
website/src/scripts/pages/workflows-render.ts Migrates workflow card HTML to renderSharedCardHtml() and shared empty-state helper.
website/src/scripts/pages/skills.ts Switches to card-details modal; adds modal actions for install/download/source.
website/src/scripts/pages/skills-render.ts Migrates skill card HTML to renderSharedCardHtml() and shared empty-state helper.
website/src/scripts/pages/plugins.ts Switches to card-details modal; adds included-items tags and install/source/repository actions.
website/src/scripts/pages/plugins-render.ts Migrates plugin card HTML to renderSharedCardHtml() and shared empty-state helper.
website/src/scripts/pages/instructions.ts Switches to card-details modal; replaces Choices-based filtering with native multi-select.
website/src/scripts/pages/instructions-render.ts Migrates instruction card HTML to renderSharedCardHtml() and shared empty-state helper.
website/src/scripts/pages/hooks.ts Switches to card-details modal; replaces Choices-based filtering with native multi-select; adds download action wiring.
website/src/scripts/pages/hooks-render.ts Migrates hook card HTML to renderSharedCardHtml() and shared empty-state helper.
website/src/scripts/pages/extensions.ts Replaces the extensions preview modal with the unified details modal + gallery support.
website/src/scripts/pages/extensions-render.ts Migrates extension cards to renderSharedCardHtml() and adjusts thumbnail wrapper markup.
website/src/scripts/pages/card-render.ts Adds shared empty state HTML + shared “resource card” HTML renderer.
website/src/scripts/pages/card-model.ts Adds shared card/grid TypeScript model types (currently not enforced by renderers).
website/src/scripts/pages/agents.ts Switches to card-details modal and in-app source viewing actions.
website/src/scripts/pages/agents-render.ts Migrates agent card HTML to renderSharedCardHtml() and shared empty-state helper.
website/src/scripts/modal.ts Adds openCardDetailsModal() and a global click handler for data-open-file-path; uses dynamic imports for markdown rendering deps.
website/src/pages/workflows.astro Adds listing-cards-page class and relies on shared modal.
website/src/pages/skills.astro Adds listing-cards-page class and relies on shared modal.
website/src/pages/plugins.astro Adds listing-cards-page class and relies on shared modal.
website/src/pages/instructions.astro Adds listing-cards-page class and relies on shared modal.
website/src/pages/hooks.astro Adds listing-cards-page class and relies on shared modal.
website/src/pages/extensions.astro Removes the custom extensions preview modal and uses the shared modal component.
website/src/pages/agents.astro Keeps agents page container class (but missing listing-cards-page).
extensions/gesture-review/canvas.json Updates description text.
extensions/diagram-viewer/canvas.json Updates description text.
extensions/color-orb/canvas.json Updates description text.
extensions/backlog-swipe-triage/canvas.json Updates description text.
extensions/arcade-canvas/canvas.json Changes extension id (affects anchors/links).
extensions/accessibility-kanban/canvas.json Updates description text.

Copilot's findings

  • Files reviewed: 31/31 changed files
  • Comments generated: 8

Comment thread website/src/pages/agents.astro Outdated
Comment thread website/src/scripts/pages/workflows.ts
Comment thread website/src/scripts/pages/plugins.ts
Comment thread website/src/scripts/pages/instructions.ts
Comment thread website/src/scripts/pages/hooks.ts
Comment thread website/src/scripts/pages/skills.ts
Comment thread website/src/scripts/pages/agents.ts
Comment thread extensions/arcade-canvas/canvas.json Outdated
- Add detail popup modal for extension cards with full metadata and gallery
- Implement image gallery with thumbnail strip and main image selection
- Add modal styling and positioning in global.css
- Connect card click handlers to open modal with extension data

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@aaronpowell aaronpowell force-pushed the aaronpowell/extensions-grid-layout branch from 46f390c to 31def0b Compare June 23, 2026 04:15
@github-actions github-actions Bot removed the canvas-extension PR touches canvas extensions label Jun 23, 2026
- Add missing listing-cards-page class to agents.astro page root
- Pass focusable button element to openCardDetailsModal instead of article
- Fixes focus restoration for keyboard users when closing modal
- Applied fix across all listing pages (agents, instructions, hooks, plugins, skills, workflows)

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 25/25 changed files
  • Comments generated: 5

Comment on lines +153 to +157
gallery?.querySelectorAll<HTMLButtonElement>(".extension-details-thumbnail-btn").forEach((button) => {
const isActive = button.dataset.galleryImageUrl === url;
button.classList.toggle("active", isActive);
button.toggleAttribute("aria-current", isActive);
});
Comment on lines +299 to +309
const thumbnailButton = target.closest(
".resource-thumbnail-btn"
) as HTMLButtonElement | null;
if (thumbnailButton) {
event.preventDefault();
event.stopPropagation();
const extensionId = thumbnailButton.dataset.extensionId;
if (!extensionId) return;
openDetailsModal(extensionId, undefined, thumbnailButton);
return;
}
Comment on lines +318 to +322
const card = target.closest(".resource-item") as HTMLElement | null;
const extensionId = card?.dataset.extensionId;
if (extensionId) {
openDetailsModal(extensionId, undefined, card || undefined);
}
Comment on lines +47 to +52
function getSelectValues(select: HTMLSelectElement | null): string[] {
if (!select) return [];
return Array.from(select.selectedOptions).map((option) => option.value);
}

function setSelectValues(select: HTMLSelectElement | null, values: string[]): void {
Comment on lines +1 to +5
export type CardActionKind = "link" | "install" | "copy" | "download" | "share";
export type CardActionVariant = "primary" | "secondary" | "icon";

export interface CardAction {
id: string;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-submission PR adds at least one new contribution website-update PR touches website content or code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants