Conversation
- Add static website with pages for agents, prompts, instructions, skills, and collections - Implement client-side fuzzy search across all resources - Add file viewer modal with copy-to-clipboard and install-to-editor functionality - Add Tools page for MCP server and future tools - Add Samples page placeholder for copilot-sdk cookbook migration - Add metadata JSON generation script (eng/generate-website-data.mjs) - Add GitHub Actions workflow for automated Pages deployment - Update package.json with website build scripts
- Add multi-select dropdown component for all filter fields - Implement light/dark theme toggle with system preference detection - Add client-side ZIP download for skills using JSZip - Include file lists in skills metadata for download feature - Add title tooltips to multi-select options for long values - Update all pages with consistent theme toggle in header
- Replace all inline scripts with TypeScript modules - Create page-specific modules for agents, prompts, instructions, skills, collections, index - Create core modules: utils.ts, search.ts, modal.ts, choices.ts, jszip.ts, theme.ts - Remove window global exports, use proper ES module imports - Add type interfaces for all data structures - Use data-base-path attribute on body for base URL handling - Bundle Choices.js and JSZip via npm instead of CDN - Astro pages now just have single script import each
The Astro-based website in website-astro/ replaces the old vanilla HTML/JS implementation. The old website/ directory is no longer needed.
- Rename website-astro/ to website/ - Add website/dist/ and website/.astro/ to gitignore - Update generate-website-data.mjs output path
- Remove old website:build-old and website:serve-old scripts - Rename website:build-data to website:data - Update paths from website-astro to website - Simplify website:dev and website:build scripts
The collection YAML files have featured nested under display object, not at the top level. Updated generate-website-data.mjs to check both data.featured and data.display?.featured.
- Add gradient backgrounds and accents using purple/pink/cyan palette - Implement glassmorphism effects on header, cards, and filters - Add gradient text for headings and stats - Improve card hover effects with glow shadows and gradient borders - Update buttons with gradient primary style - Add subtle pattern overlay on hero section - Increase spacing and border radius for modern feel - Update tags with gradient backgrounds - Add left accent border animation on resource items - Improve modal with blur backdrop and rounded corners - Update color palette for both light and dark themes
- Left-align search results content - Add proper icon container with background - Improve spacing and padding - Add highlight styling for search matches - Add empty state styling - Support both .search-result and .search-result-item classes
- Fix VS Code install URL format to match README links - Add separate buttons for VS Code and VS Code Insiders - Support install links for agents, prompts, and instructions - Add VS Code icon SVG to buttons
- Add VS Code and VS Code Insiders install buttons to agent, prompt, and instruction list items - Use smaller button style for list view - Include VS Code icon for visual identification
- Replace separate VS Code/Insiders buttons with single Install dropdown - Primary 'Install' button opens in VS Code, dropdown chevron reveals options - Dropdown shows 'VS Code' and 'VS Code Insiders' choices - Add CSS for split button styling with glassmorphism dropdown - Apply to modal and all list views (agents, prompts, instructions)
- Add Download button to download file as .md file - Add Share button to copy GitHub link to clipboard - Both buttons appear in modal header and list view actions - Use icon-only buttons in list view for cleaner UI
- Add SearchableItem base interface for minimum required fields - Make FuzzySearch class generic with type parameter - Update all page scripts to use typed FuzzySearch instances - Fix type casting in calculateScore method
- Update URL hash when opening/closing modal (#file=path) - Handle browser back/forward navigation - Open modal on page load if hash is present - Share button now copies deep link URL instead of GitHub URL
- Display collection name, description, and tags - Show clickable list of items in the collection - Each item shows icon, filename, usage hint, and type badge - Clicking an item opens that file in the modal - Hide copy/download buttons for collections (they don't apply)
Use official Copilot colors from brand.github.com: - Primary purple: #8534F3 - Purple variants: #C898FD, #B870FF, #43179E, #26115F - Orange accents: #FE4C25, #F08A3A, #C53211 - Updated gradients to use purple-to-orange blend
- Add Copilot_Icon_White.svg and Copilot_Icon_Black.svg - Switch between white/black logos based on theme - Update favicon to use Copilot icon
- Install both root and website dependencies - Run website:data to generate JSON files - Build Astro site in website directory - Deploy from website/dist
- Create website/data/tools.yml with 6 tools: - Awesome Copilot MCP Server - Awesome GitHub Copilot Browser (VS Code extension) - APM - Agent Package Manager (CLI) - Workspace Architect (npm CLI) - Prompt Registry (VS Code extension) - GitHub Node for Visual Studio - Add .schemas/tools.schema.json for YAML validation - Update eng/generate-website-data.mjs to generate tools.json - Add parseYamlFile() to eng/yaml-parser.mjs - Refactor tools.astro to use external TypeScript module - Create website/src/scripts/pages/tools.ts with: - FuzzySearch integration for search - Category filtering - Copy configuration functionality
- Remove separate hero-stats section - Add card-count element to each resource card - Update JS to populate counts from manifest - Add card-with-count CSS for layout with count badge - Reduces vertical space on home page
Add z-index to .hero-search container so dropdown appears above cards
- Add vite.build.sourcemap for production builds - Add vite.css.devSourcemap for CSS in development
The site uses public/styles/global.css via direct link in BaseLayout. The src/styles version was outdated and never imported.
Phase 1 - Screen Reader Critical: - Add aria-label to main navigation - Add accessible names to icon-only buttons (GitHub, theme toggle, close) - Add aria-hidden to decorative SVGs and emoji icons - Add role=dialog, aria-modal, aria-labelledby to modal - Add skip link with visible focus state Phase 2 - Keyboard Navigation: - Implement focus trap in modal (Tab/Shift+Tab cycles) - Return focus to trigger element on modal close - Replace outline:none with visible focus rings - Add keyboard navigation to install dropdown (arrows, escape) - Add aria-expanded to dropdown toggles Phase 3 - Dynamic Content: - Add aria-live=polite to results counts and loading states - Add role=listbox to search results - Add role=list to resource lists - Add role=menu/menuitem to dropdown menus Phase 4 - Forms & Labels: - Add .sr-only utility class for screen reader text - Add visually hidden labels to all search inputs - Add aria-label to filter dropdowns Files modified: - BaseLayout.astro, Modal.astro (ARIA attributes) - modal.ts (focus trap, keyboard navigation) - global.css (sr-only, skip-link, focus styles) - All page files (labels, live regions, roles)
- Change primary buttons from gradient to solid Copilot Purple (#8534F3) - Add position:relative and z-index:10 to .filters-bar to fix Choices.js dropdown appearing behind resource list items
Integrates the cookbook/ folder into the website's Samples page: Data Structure: - Add cookbook/cookbook.yml manifest defining cookbooks and recipes - Add .schemas/cookbook.schema.json for validation - Add COOKBOOK_DIR constant to eng/constants.mjs Build Integration: - Add generateSamplesData() to generate samples.json from cookbook.yml - Include recipe variants with file paths for each language - Add samples count to manifest.json Website UI: - Create samples.ts with FuzzySearch, language/tag filtering - Replace placeholder samples.astro with functional recipe browser - Recipe cards with language indicators and action buttons - Language tabs for switching between implementations - View Recipe/View Example buttons open modal - GitHub link for each recipe Features: - Search recipes by name/description - Filter by programming language (Node.js, Python, .NET, Go) - Filter by tags (multi-select with Choices.js) - 5 recipes across 4 languages = 20 recipe variants
Use the same createChoices/getChoicesValues helpers as other pages for consistent multi-select behavior.
- Add Monaspace Argon NF font for dev icons - Update cookbook.yml with unicode codepoints for language icons: - TypeScript: \uE628 - Python: \uE73C - C#/.NET: \uF81A - Go: \uE626 - Style .lang-tab and .lang-indicator with Nerd Font family
- Remove SearchableRecipe interface that conflicted with SearchableItem - Use proper type casting for search results - Fix FuzzySearch generic type usage
- Add pr-preview.yml workflow using rossjrw/pr-preview-action - Update astro.config.mjs to support dynamic base path via ASTRO_BASE env - Previews deploy to /pr-preview/pr-<number>/ on gh-pages branch - Auto-cleanup when PR is closed
There was a problem hiding this comment.
Pull request overview
This PR adds a comprehensive website for the Awesome GitHub Copilot repository using Astro, featuring browseable pages for agents, prompts, instructions, skills, collections, tools, and samples/cookbook recipes. The website includes search functionality, filtering, modals for file preview, and one-click installation features for VS Code.
Changes:
- Added complete Astro-based website with TypeScript, including pages for all resource types
- Implemented client-side search and filtering with fuzzy matching
- Added data generation pipeline that extracts metadata from repository files
- Created GitHub Actions workflow for automated deployment to GitHub Pages
- Added tools catalog and cookbook manifest for samples/recipes
Reviewed changes
Copilot reviewed 37 out of 42 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| website/astro.config.mjs | Astro configuration for static site generation |
| website/src/scripts/*.ts | TypeScript utilities for search, theme, modal, and UI interactions |
| website/src/scripts/pages/*.ts | Page-specific logic for agents, prompts, skills, etc. |
| website/src/pages/*.astro | Astro page components and layouts |
| website/public/styles/global.css | Comprehensive styling with GitHub Copilot branding |
| eng/generate-website-data.mjs | Data extraction script that builds JSON from repository files |
| eng/yaml-parser.mjs | Added parseYamlFile function for tools.yml parsing |
| website/data/tools.yml | Tools catalog with MCP servers and extensions |
| cookbook/cookbook.yml | Manifest defining cookbooks and recipes structure |
| .github/workflows/deploy-website.yml | Automated deployment workflow for GitHub Pages |
| .schemas/*.json | JSON schemas for tools and cookbook validation |
| } catch { | ||
| btn.innerHTML = '<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.75.75 0 1 1 1.06 1.06L9.06 8l3.22 3.22a.75.75 0 0 1-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 0 1-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06z"/></svg> Failed'; | ||
| setTimeout(() => { btn.disabled = false; btn.innerHTML = originalContent; }, 2000); | ||
| } |
There was a problem hiding this comment.
The downloadSkill function silently catches all errors and only updates the button UI. Users won't know why the download failed (network error, file not found, etc.). Consider using the showToast function to display a more specific error message to help users understand what went wrong.
| - 'prompts/**' | ||
| - 'instructions/**' | ||
| - 'skills/**' | ||
| - 'collections/**' |
There was a problem hiding this comment.
The workflow specifies paths that trigger the build, but the 'cookbook/' path is missing. Changes to cookbook files should also trigger a website rebuild since they're used by the generate-website-data script. Add 'cookbook/' to the paths list.
| - 'collections/**' | |
| - 'collections/**' | |
| - 'cookbook/**' |
| if (tool.links['vscode-insiders']) { | ||
| actions.push(`<a href="${tool.links['vscode-insiders']}" class="btn btn-outline" target="_blank" rel="noopener">VS Code Insiders</a>`); | ||
| } | ||
| if (tool.links['visual-studio']) { | ||
| actions.push(`<a href="${tool.links['visual-studio']}" class="btn btn-outline" target="_blank" rel="noopener">Visual Studio</a>`); | ||
| } |
There was a problem hiding this comment.
The btn-outline class is used on lines 152 and 155, but this class is not defined anywhere in global.css. This will result in unstyled buttons. Either add the .btn-outline CSS class definition or use an existing button class like btn-secondary.
| } | ||
|
|
||
| // Auto-initialize when DOM is ready | ||
| document.addEventListener('DOMContentLoaded', initThemeToggle); |
There was a problem hiding this comment.
The theme initialization is executed on DOMContentLoaded, but the inline script in BaseLayout.astro (lines 22-28) already applies the theme. This could cause a brief flash where the theme is applied, then the event listener is attached. Consider either moving the event listener setup to happen immediately, or ensure this double initialization doesn't cause issues.
| export function setupActionHandlers(): void { | ||
| // Expose functions globally for inline onclick handlers | ||
| (window as Window & { __downloadFile?: (path: string) => void; __shareFile?: (path: string) => void }).__downloadFile = async (path: string) => { | ||
| const success = await downloadFile(path); | ||
| showToast(success ? 'Download started!' : 'Download failed', success ? 'success' : 'error'); | ||
| }; | ||
|
|
||
| (window as Window & { __downloadFile?: (path: string) => void; __shareFile?: (path: string) => void }).__shareFile = async (path: string) => { | ||
| const success = await shareFile(path); | ||
| showToast(success ? 'Link copied!' : 'Failed to copy link', success ? 'success' : 'error'); | ||
| }; | ||
| } |
There was a problem hiding this comment.
The setupActionHandlers function assigns properties to the window object without type safety. Consider defining these as a proper interface extension or using a more type-safe approach for global state management.
| // Return focus to trigger element | ||
| if (triggerElement && typeof triggerElement.focus === 'function') { | ||
| triggerElement.focus(); | ||
| } | ||
|
|
||
| currentFilePath = null; | ||
| currentFileContent = null; | ||
| currentFileType = null; | ||
| triggerElement = null; | ||
| } |
There was a problem hiding this comment.
The modal functions (openFileModal, closeModal) manage focus state using triggerElement, which is good for accessibility. However, there's a potential issue: if the trigger element is removed from the DOM before the modal closes, the focus return will fail silently. Consider checking if the element still exists in the DOM and is visible before attempting to focus it.
| * Get file content (for preview/full content) | ||
| */ | ||
| function getFileContent(filePath) { | ||
| try { | ||
| return fs.readFileSync(filePath, "utf8"); | ||
| } catch (e) { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| /** |
There was a problem hiding this comment.
Unused function getFileContent.
| * Get file content (for preview/full content) | |
| */ | |
| function getFileContent(filePath) { | |
| try { | |
| return fs.readFileSync(filePath, "utf8"); | |
| } catch (e) { | |
| return null; | |
| } | |
| } | |
| /** |
| if (!container) return; | ||
|
|
||
| const toggle = container.querySelector<HTMLButtonElement>('.install-btn-toggle'); | ||
| const menu = container.querySelector('.install-dropdown-menu'); |
There was a problem hiding this comment.
Unused variable menu.
| /** | ||
| * Get the current theme preference | ||
| */ | ||
| function getThemePreference(): 'light' | 'dark' { |
There was a problem hiding this comment.
Unused function getThemePreference.
| const searchInput = document.getElementById('search-input') as HTMLInputElement; | ||
| const categoryFilter = document.getElementById('filter-category') as HTMLSelectElement; | ||
| const clearFiltersBtn = document.getElementById('clear-filters'); | ||
| const countEl = document.getElementById('results-count'); |
There was a problem hiding this comment.
Unused variable countEl.
This reverts commit 26df6a2.
|
@aaronpowell I've opened a new pull request, #638, to work on those changes. Once the pull request is ready, I'll request review from you. |
The previous implementation only escaped single quotes, which could allow
backslashes in file paths to break out of the JavaScript string context.
Now we escape backslashes first (\ -> \\), then single quotes (' -> \'),
preventing potential security issues.
Fixes CodeQL alert #26 for incomplete string escaping.
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
fix(website): escape backslashes in file paths to prevent string context breakout
…github/awesome-copilot into experiment/github-pages-website
- Standardized string quotes to double quotes across multiple files. - Improved formatting and indentation for better readability. - Added a function to format multiline text in tools rendering. - Enhanced dropdown and action button handlers for better event management. - Updated the theme application logic to initialize on page load. - Refactored utility functions for consistency and clarity. - Improved error handling and user feedback in download and share functionalities.
Pull Request Checklist
npm startand verified thatREADME.mdis up to date.Description
Type of Contribution
Additional Notes
By submitting this pull request, I confirm that my contribution abides by the Code of Conduct and will be licensed under the MIT License.