mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-20 02:15:12 +00:00
Add tools catalog with YAML schema and website page
- 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
This commit is contained in:
151
.schemas/tools.schema.json
Normal file
151
.schemas/tools.schema.json
Normal file
@@ -0,0 +1,151 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Tools Catalog",
|
||||
"description": "Schema for the awesome-copilot tools catalog (website/data/tools.yml)",
|
||||
"type": "object",
|
||||
"required": ["tools"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"tools": {
|
||||
"type": "array",
|
||||
"description": "List of tools in the catalog",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["id", "name", "description", "category"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique identifier for the tool",
|
||||
"pattern": "^[a-z0-9-]+$",
|
||||
"minLength": 1,
|
||||
"maxLength": 50
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Display name for the tool",
|
||||
"minLength": 1,
|
||||
"maxLength": 100
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Description of what this tool does",
|
||||
"minLength": 1,
|
||||
"maxLength": 1000
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"description": "Category for grouping tools",
|
||||
"minLength": 1,
|
||||
"maxLength": 50,
|
||||
"examples": ["MCP Servers", "VS Code Extensions", "CLI Tools", "Visual Studio Extensions"]
|
||||
},
|
||||
"featured": {
|
||||
"type": "boolean",
|
||||
"description": "Whether this tool is featured (shown first)",
|
||||
"default": false
|
||||
},
|
||||
"requirements": {
|
||||
"type": "array",
|
||||
"description": "List of requirements to use this tool",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 200
|
||||
},
|
||||
"maxItems": 10
|
||||
},
|
||||
"features": {
|
||||
"type": "array",
|
||||
"description": "List of key features",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 200
|
||||
},
|
||||
"maxItems": 20
|
||||
},
|
||||
"links": {
|
||||
"type": "object",
|
||||
"description": "Links related to this tool",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"blog": {
|
||||
"type": "string",
|
||||
"description": "Link to a blog post about the tool",
|
||||
"format": "uri"
|
||||
},
|
||||
"documentation": {
|
||||
"type": "string",
|
||||
"description": "Link to documentation",
|
||||
"format": "uri"
|
||||
},
|
||||
"github": {
|
||||
"type": "string",
|
||||
"description": "Link to GitHub repository",
|
||||
"format": "uri"
|
||||
},
|
||||
"marketplace": {
|
||||
"type": "string",
|
||||
"description": "Link to VS Code or Visual Studio Marketplace",
|
||||
"format": "uri"
|
||||
},
|
||||
"npm": {
|
||||
"type": "string",
|
||||
"description": "Link to npm package",
|
||||
"format": "uri"
|
||||
},
|
||||
"pypi": {
|
||||
"type": "string",
|
||||
"description": "Link to PyPI package",
|
||||
"format": "uri"
|
||||
},
|
||||
"vscode": {
|
||||
"type": "string",
|
||||
"description": "VS Code install link (vscode: URI or aka.ms link)"
|
||||
},
|
||||
"vscode-insiders": {
|
||||
"type": "string",
|
||||
"description": "VS Code Insiders install link"
|
||||
},
|
||||
"visual-studio": {
|
||||
"type": "string",
|
||||
"description": "Visual Studio install link"
|
||||
}
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"description": "Configuration snippet for the tool",
|
||||
"required": ["type", "content"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of configuration (for syntax highlighting)",
|
||||
"enum": ["json", "yaml", "bash", "toml", "ini"]
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "The configuration content"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"description": "Tags for filtering and discovery",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9-]+$",
|
||||
"minLength": 1,
|
||||
"maxLength": 30
|
||||
},
|
||||
"uniqueItems": true,
|
||||
"maxItems": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,12 +22,14 @@ import {
|
||||
parseFrontmatter,
|
||||
parseCollectionYaml,
|
||||
parseSkillMetadata,
|
||||
parseYamlFile,
|
||||
} from "./yaml-parser.mjs";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const WEBSITE_DATA_DIR = path.join(ROOT_FOLDER, "website", "public", "data");
|
||||
const WEBSITE_SOURCE_DATA_DIR = path.join(ROOT_FOLDER, "website", "data");
|
||||
|
||||
/**
|
||||
* Ensure the output directory exists
|
||||
@@ -435,6 +437,63 @@ function generateCollectionsData() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate tools metadata from website/data/tools.yml
|
||||
*/
|
||||
function generateToolsData() {
|
||||
const toolsFile = path.join(WEBSITE_SOURCE_DATA_DIR, "tools.yml");
|
||||
|
||||
if (!fs.existsSync(toolsFile)) {
|
||||
console.warn("No tools.yml file found at", toolsFile);
|
||||
return { items: [], filters: { categories: [], tags: [] } };
|
||||
}
|
||||
|
||||
const data = parseYamlFile(toolsFile);
|
||||
|
||||
if (!data || !data.tools) {
|
||||
return { items: [], filters: { categories: [], tags: [] } };
|
||||
}
|
||||
|
||||
const allCategories = new Set();
|
||||
const allTags = new Set();
|
||||
|
||||
const tools = data.tools.map((tool) => {
|
||||
const category = tool.category || "Other";
|
||||
allCategories.add(category);
|
||||
|
||||
const tags = tool.tags || [];
|
||||
tags.forEach((t) => allTags.add(t));
|
||||
|
||||
return {
|
||||
id: tool.id,
|
||||
name: tool.name,
|
||||
description: tool.description || "",
|
||||
category: category,
|
||||
featured: tool.featured || false,
|
||||
requirements: tool.requirements || [],
|
||||
features: tool.features || [],
|
||||
links: tool.links || {},
|
||||
configuration: tool.configuration || null,
|
||||
tags: tags,
|
||||
};
|
||||
});
|
||||
|
||||
// Sort with featured first, then alphabetically
|
||||
const sortedTools = tools.sort((a, b) => {
|
||||
if (a.featured && !b.featured) return -1;
|
||||
if (!a.featured && b.featured) return 1;
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
return {
|
||||
items: sortedTools,
|
||||
filters: {
|
||||
categories: Array.from(allCategories).sort(),
|
||||
tags: Array.from(allTags).sort(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a combined index for search
|
||||
*/
|
||||
@@ -529,6 +588,10 @@ async function main() {
|
||||
const collections = collectionsData.items;
|
||||
console.log(`✓ Generated ${collections.length} collections (${collectionsData.filters.tags.length} tags)`);
|
||||
|
||||
const toolsData = generateToolsData();
|
||||
const tools = toolsData.items;
|
||||
console.log(`✓ Generated ${tools.length} tools (${toolsData.filters.categories.length} categories)`);
|
||||
|
||||
const searchIndex = generateSearchIndex(agents, prompts, instructions, skills, collections);
|
||||
console.log(`✓ Generated search index with ${searchIndex.length} items`);
|
||||
|
||||
@@ -558,6 +621,11 @@ async function main() {
|
||||
JSON.stringify(collectionsData, null, 2)
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(WEBSITE_DATA_DIR, "tools.json"),
|
||||
JSON.stringify(toolsData, null, 2)
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(WEBSITE_DATA_DIR, "search-index.json"),
|
||||
JSON.stringify(searchIndex, null, 2)
|
||||
@@ -572,6 +640,7 @@ async function main() {
|
||||
instructions: instructions.length,
|
||||
skills: skills.length,
|
||||
collections: collections.length,
|
||||
tools: tools.length,
|
||||
total: searchIndex.length,
|
||||
},
|
||||
};
|
||||
@@ -581,7 +650,7 @@ async function main() {
|
||||
JSON.stringify(manifest, null, 2)
|
||||
);
|
||||
|
||||
console.log(`\n✓ All data written to website/data/`);
|
||||
console.log(`\n✓ All data written to website/public/data/`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
|
||||
@@ -195,6 +195,22 @@ function parseSkillMetadata(skillPath) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a generic YAML file (used for tools.yml and other config files)
|
||||
* @param {string} filePath - Path to the YAML file
|
||||
* @returns {object|null} Parsed YAML object or null on error
|
||||
*/
|
||||
function parseYamlFile(filePath) {
|
||||
return safeFileOperation(
|
||||
() => {
|
||||
const content = fs.readFileSync(filePath, "utf8");
|
||||
return yaml.load(content, { schema: yaml.JSON_SCHEMA });
|
||||
},
|
||||
filePath,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
parseCollectionYaml,
|
||||
parseFrontmatter,
|
||||
@@ -202,5 +218,6 @@ export {
|
||||
extractMcpServers,
|
||||
extractMcpServerConfigs,
|
||||
parseSkillMetadata,
|
||||
parseYamlFile,
|
||||
safeFileOperation,
|
||||
};
|
||||
|
||||
205
website/data/tools.yml
Normal file
205
website/data/tools.yml
Normal file
@@ -0,0 +1,205 @@
|
||||
# yaml-language-server: $schema=../../.schemas/tools.schema.json
|
||||
# Tools data for the Awesome GitHub Copilot website
|
||||
# Each tool entry provides information for the tools page
|
||||
|
||||
tools:
|
||||
- id: mcp-server
|
||||
name: Awesome Copilot MCP Server
|
||||
description: >-
|
||||
A Model Context Protocol (MCP) Server that provides prompts for searching and installing
|
||||
prompts, instructions, agents, and skills directly from this repository. Makes it easy
|
||||
to discover and add customizations to your editor.
|
||||
category: MCP Servers
|
||||
featured: true
|
||||
requirements:
|
||||
- Docker installed and running
|
||||
links:
|
||||
blog: https://developer.microsoft.com/blog/announcing-awesome-copilot-mcp-server
|
||||
vscode: https://aka.ms/awesome-copilot/mcp/vscode
|
||||
vscode-insiders: https://aka.ms/awesome-copilot/mcp/vscode-insiders
|
||||
visual-studio: https://aka.ms/awesome-copilot/mcp/vs
|
||||
configuration:
|
||||
type: json
|
||||
content: |
|
||||
{
|
||||
"servers": {
|
||||
"awesome-copilot": {
|
||||
"type": "stdio",
|
||||
"command": "docker",
|
||||
"args": [
|
||||
"run",
|
||||
"-i",
|
||||
"--rm",
|
||||
"ghcr.io/microsoft/mcp-dotnet-samples/awesome-copilot:latest"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
tags:
|
||||
- mcp
|
||||
- docker
|
||||
- search
|
||||
- install
|
||||
|
||||
- id: vscode-extension
|
||||
name: Awesome GitHub Copilot Browser
|
||||
description: >-
|
||||
A VS Code extension that allows you to browse, preview, and download GitHub Copilot
|
||||
customizations from the awesome-copilot repository. Features a tree view for exploring
|
||||
agents, prompts, instructions, and skills with smart caching for better performance.
|
||||
category: VS Code Extensions
|
||||
featured: true
|
||||
requirements:
|
||||
- VS Code version 1.103.0 or higher
|
||||
- Internet connection to fetch repository data
|
||||
- A workspace folder open in VS Code (for downloads)
|
||||
links:
|
||||
github: https://github.com/timheuer/vscode-awesome-copilot
|
||||
vscode: vscode:extension/TimHeuer.awesome-copilot
|
||||
vscode-insiders: vscode-insiders:extension/TimHeuer.awesome-copilot
|
||||
marketplace: https://marketplace.visualstudio.com/items?itemName=TimHeuer.awesome-copilot
|
||||
features:
|
||||
- "🔍 Browse: Explore chat modes, instructions, prompts, agents, and skills in a tree view"
|
||||
- "📖 Preview: View file content before downloading"
|
||||
- "⬇️ Download: Save files to appropriate .github/ folders in your workspace"
|
||||
- "🔃 Refresh: Update repository data with manual refresh"
|
||||
- "💾 Caching: Smart caching for better performance"
|
||||
tags:
|
||||
- vscode
|
||||
- extension
|
||||
- browse
|
||||
- preview
|
||||
- download
|
||||
|
||||
- id: workspace-architect
|
||||
name: Workspace Architect
|
||||
description: >-
|
||||
A comprehensive library of specialized AI personas and chat modes for GitHub Copilot.
|
||||
Includes architectural planning, tech stack guidance, and advanced cognitive reasoning
|
||||
models. Install via npm and use the CLI to download personas and prompts.
|
||||
category: CLI Tools
|
||||
featured: false
|
||||
requirements:
|
||||
- Node.js 20 or higher
|
||||
- npm
|
||||
links:
|
||||
github: https://github.com/archubbuck/workspace-architect
|
||||
npm: https://www.npmjs.com/package/workspace-architect
|
||||
features:
|
||||
- "📦 CLI tool: List and download personas, prompts, and chat modes"
|
||||
- "🎭 Rich persona library: Architecture, React, Azure, and more"
|
||||
- "🧠 Cognitive modes: Advanced reasoning and planning personas"
|
||||
- "⚡ Easy install: npm install -g workspace-architect"
|
||||
configuration:
|
||||
type: bash
|
||||
content: |
|
||||
# Install globally
|
||||
npm install -g workspace-architect
|
||||
|
||||
# List available items
|
||||
workspace-architect list
|
||||
|
||||
# Download a specific item
|
||||
workspace-architect download instructions:basic-setup
|
||||
tags:
|
||||
- cli
|
||||
- npm
|
||||
- personas
|
||||
- chat-modes
|
||||
- prompts
|
||||
|
||||
- id: apm
|
||||
name: APM - Agent Package Manager
|
||||
description: >-
|
||||
npm for AI coding agents. The package manager for AGENTS.md, Agent Skills, and MCP servers.
|
||||
One package installs to every AI agent (Copilot, Cursor, Claude, Codex, Gemini) in their
|
||||
native format.
|
||||
category: CLI Tools
|
||||
featured: true
|
||||
requirements:
|
||||
- Python 3.8 or higher (for pip install)
|
||||
- Or use the shell installer
|
||||
links:
|
||||
github: https://github.com/danielmeppiel/apm
|
||||
pypi: https://pypi.org/project/apm-cli/
|
||||
features:
|
||||
- "📦 Universal packages: One install works for Copilot, Cursor, Claude, and more"
|
||||
- "🔧 Skills & Instructions: Install guardrails and capabilities"
|
||||
- "🔌 MCP Server management: Configure and manage MCP servers"
|
||||
- "🏗️ Create packages: Share your standards and workflows"
|
||||
- "🌐 Multi-source: GitHub, GitHub Enterprise, Azure DevOps"
|
||||
configuration:
|
||||
type: bash
|
||||
content: |
|
||||
# Install via shell script
|
||||
curl -sSL https://raw.githubusercontent.com/danielmeppiel/apm/main/install.sh | sh
|
||||
|
||||
# Or install via pip
|
||||
pip install apm-cli
|
||||
|
||||
# Install a skill
|
||||
apm install danielmeppiel/form-builder
|
||||
|
||||
# Compile for your AI tools
|
||||
apm compile
|
||||
tags:
|
||||
- cli
|
||||
- python
|
||||
- package-manager
|
||||
- skills
|
||||
- agents
|
||||
- mcp
|
||||
|
||||
- id: prompt-registry
|
||||
name: Prompt Registry
|
||||
description: >-
|
||||
A visual marketplace for discovering, installing, and managing GitHub Copilot prompt
|
||||
libraries from multiple sources. Browse bundles in a tile-based interface with search,
|
||||
filters, and one-click install. Supports GitHub, local directories, and APM repositories.
|
||||
category: VS Code Extensions
|
||||
featured: false
|
||||
requirements:
|
||||
- VS Code
|
||||
links:
|
||||
github: https://github.com/AmadeusITGroup/prompt-registry
|
||||
vscode: vscode:extension/AmadeusITGroup.prompt-registry
|
||||
vscode-insiders: vscode-insiders:extension/AmadeusITGroup.prompt-registry
|
||||
marketplace: https://marketplace.visualstudio.com/items?itemName=AmadeusITGroup.prompt-registry
|
||||
features:
|
||||
- "🎨 Visual Marketplace: Browse bundles with search, filters, and one-click install"
|
||||
- "🔌 Multi-Source: Connect to GitHub, local directories, APM, or Awesome Copilot"
|
||||
- "📦 Version Management: Track versions and enable automatic updates"
|
||||
- "👥 Profiles & Hubs: Organize bundles by project/team"
|
||||
- "🌍 Cross-Platform: Works on macOS, Linux, and Windows"
|
||||
tags:
|
||||
- vscode
|
||||
- extension
|
||||
- marketplace
|
||||
- prompts
|
||||
- bundles
|
||||
|
||||
- id: github-node-vs
|
||||
name: GitHub Node for Visual Studio
|
||||
description: >-
|
||||
Adds GitHub and MCP Servers nodes to Solution Explorer in Visual Studio. Quickly access
|
||||
and manage GitHub-specific files like workflows, Copilot instructions, and agents, plus
|
||||
MCP server configurations - all without leaving Visual Studio.
|
||||
category: Visual Studio Extensions
|
||||
featured: false
|
||||
requirements:
|
||||
- Visual Studio 2022 or higher
|
||||
links:
|
||||
github: https://github.com/madskristensen/GitHubNode
|
||||
marketplace: https://marketplace.visualstudio.com/items?itemName=MadsKristensen.GitHubNode
|
||||
features:
|
||||
- "📁 GitHub Node: Easy access to .github folder contents in Solution Explorer"
|
||||
- "➕ Quick Create: Add Copilot instructions, agents, prompts, skills, and workflows"
|
||||
- "🔌 MCP Servers Node: Centralized access to MCP configurations"
|
||||
- "🔄 Git Status Icons: See file status directly in the tree view"
|
||||
- "🌐 Open on GitHub: Quick link to view files on GitHub.com"
|
||||
tags:
|
||||
- visual-studio
|
||||
- extension
|
||||
- solution-explorer
|
||||
- github
|
||||
- mcp
|
||||
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"generated": "2026-01-28T23:49:25.944Z",
|
||||
"generated": "2026-01-29T02:32:57.492Z",
|
||||
"counts": {
|
||||
"agents": 140,
|
||||
"prompts": 134,
|
||||
"instructions": 163,
|
||||
"skills": 28,
|
||||
"collections": 39,
|
||||
"tools": 6,
|
||||
"total": 504
|
||||
}
|
||||
}
|
||||
223
website/public/data/tools.json
Normal file
223
website/public/data/tools.json
Normal file
@@ -0,0 +1,223 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "apm",
|
||||
"name": "APM - Agent Package Manager",
|
||||
"description": "npm for AI coding agents. The package manager for AGENTS.md, Agent Skills, and MCP servers. One package installs to every AI agent (Copilot, Cursor, Claude, Codex, Gemini) in their native format.",
|
||||
"category": "CLI Tools",
|
||||
"featured": true,
|
||||
"requirements": [
|
||||
"Python 3.8 or higher (for pip install)",
|
||||
"Or use the shell installer"
|
||||
],
|
||||
"features": [
|
||||
"📦 Universal packages: One install works for Copilot, Cursor, Claude, and more",
|
||||
"🔧 Skills & Instructions: Install guardrails and capabilities",
|
||||
"🔌 MCP Server management: Configure and manage MCP servers",
|
||||
"🏗️ Create packages: Share your standards and workflows",
|
||||
"🌐 Multi-source: GitHub, GitHub Enterprise, Azure DevOps"
|
||||
],
|
||||
"links": {
|
||||
"github": "https://github.com/danielmeppiel/apm",
|
||||
"pypi": "https://pypi.org/project/apm-cli/"
|
||||
},
|
||||
"configuration": {
|
||||
"type": "bash",
|
||||
"content": "# Install via shell script\ncurl -sSL https://raw.githubusercontent.com/danielmeppiel/apm/main/install.sh | sh\n\n# Or install via pip\npip install apm-cli\n\n# Install a skill\napm install danielmeppiel/form-builder\n\n# Compile for your AI tools\napm compile\n"
|
||||
},
|
||||
"tags": [
|
||||
"cli",
|
||||
"python",
|
||||
"package-manager",
|
||||
"skills",
|
||||
"agents",
|
||||
"mcp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "mcp-server",
|
||||
"name": "Awesome Copilot MCP Server",
|
||||
"description": "A Model Context Protocol (MCP) Server that provides prompts for searching and installing prompts, instructions, agents, and skills directly from this repository. Makes it easy to discover and add customizations to your editor.",
|
||||
"category": "MCP Servers",
|
||||
"featured": true,
|
||||
"requirements": [
|
||||
"Docker installed and running"
|
||||
],
|
||||
"features": [],
|
||||
"links": {
|
||||
"blog": "https://developer.microsoft.com/blog/announcing-awesome-copilot-mcp-server",
|
||||
"vscode": "https://aka.ms/awesome-copilot/mcp/vscode",
|
||||
"vscode-insiders": "https://aka.ms/awesome-copilot/mcp/vscode-insiders",
|
||||
"visual-studio": "https://aka.ms/awesome-copilot/mcp/vs"
|
||||
},
|
||||
"configuration": {
|
||||
"type": "json",
|
||||
"content": "{\n \"servers\": {\n \"awesome-copilot\": {\n \"type\": \"stdio\",\n \"command\": \"docker\",\n \"args\": [\n \"run\",\n \"-i\",\n \"--rm\",\n \"ghcr.io/microsoft/mcp-dotnet-samples/awesome-copilot:latest\"\n ]\n }\n }\n}\n"
|
||||
},
|
||||
"tags": [
|
||||
"mcp",
|
||||
"docker",
|
||||
"search",
|
||||
"install"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "vscode-extension",
|
||||
"name": "Awesome GitHub Copilot Browser",
|
||||
"description": "A VS Code extension that allows you to browse, preview, and download GitHub Copilot customizations from the awesome-copilot repository. Features a tree view for exploring agents, prompts, instructions, and skills with smart caching for better performance.",
|
||||
"category": "VS Code Extensions",
|
||||
"featured": true,
|
||||
"requirements": [
|
||||
"VS Code version 1.103.0 or higher",
|
||||
"Internet connection to fetch repository data",
|
||||
"A workspace folder open in VS Code (for downloads)"
|
||||
],
|
||||
"features": [
|
||||
"🔍 Browse: Explore chat modes, instructions, prompts, agents, and skills in a tree view",
|
||||
"📖 Preview: View file content before downloading",
|
||||
"⬇️ Download: Save files to appropriate .github/ folders in your workspace",
|
||||
"🔃 Refresh: Update repository data with manual refresh",
|
||||
"💾 Caching: Smart caching for better performance"
|
||||
],
|
||||
"links": {
|
||||
"github": "https://github.com/timheuer/vscode-awesome-copilot",
|
||||
"vscode": "vscode:extension/TimHeuer.awesome-copilot",
|
||||
"vscode-insiders": "vscode-insiders:extension/TimHeuer.awesome-copilot",
|
||||
"marketplace": "https://marketplace.visualstudio.com/items?itemName=TimHeuer.awesome-copilot"
|
||||
},
|
||||
"configuration": null,
|
||||
"tags": [
|
||||
"vscode",
|
||||
"extension",
|
||||
"browse",
|
||||
"preview",
|
||||
"download"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "github-node-vs",
|
||||
"name": "GitHub Node for Visual Studio",
|
||||
"description": "Adds GitHub and MCP Servers nodes to Solution Explorer in Visual Studio. Quickly access and manage GitHub-specific files like workflows, Copilot instructions, and agents, plus MCP server configurations - all without leaving Visual Studio.",
|
||||
"category": "Visual Studio Extensions",
|
||||
"featured": false,
|
||||
"requirements": [
|
||||
"Visual Studio 2022 or higher"
|
||||
],
|
||||
"features": [
|
||||
"📁 GitHub Node: Easy access to .github folder contents in Solution Explorer",
|
||||
"➕ Quick Create: Add Copilot instructions, agents, prompts, skills, and workflows",
|
||||
"🔌 MCP Servers Node: Centralized access to MCP configurations",
|
||||
"🔄 Git Status Icons: See file status directly in the tree view",
|
||||
"🌐 Open on GitHub: Quick link to view files on GitHub.com"
|
||||
],
|
||||
"links": {
|
||||
"github": "https://github.com/madskristensen/GitHubNode",
|
||||
"marketplace": "https://marketplace.visualstudio.com/items?itemName=MadsKristensen.GitHubNode"
|
||||
},
|
||||
"configuration": null,
|
||||
"tags": [
|
||||
"visual-studio",
|
||||
"extension",
|
||||
"solution-explorer",
|
||||
"github",
|
||||
"mcp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "prompt-registry",
|
||||
"name": "Prompt Registry",
|
||||
"description": "A visual marketplace for discovering, installing, and managing GitHub Copilot prompt libraries from multiple sources. Browse bundles in a tile-based interface with search, filters, and one-click install. Supports GitHub, local directories, and APM repositories.",
|
||||
"category": "VS Code Extensions",
|
||||
"featured": false,
|
||||
"requirements": [
|
||||
"VS Code"
|
||||
],
|
||||
"features": [
|
||||
"🎨 Visual Marketplace: Browse bundles with search, filters, and one-click install",
|
||||
"🔌 Multi-Source: Connect to GitHub, local directories, APM, or Awesome Copilot",
|
||||
"📦 Version Management: Track versions and enable automatic updates",
|
||||
"👥 Profiles & Hubs: Organize bundles by project/team",
|
||||
"🌍 Cross-Platform: Works on macOS, Linux, and Windows"
|
||||
],
|
||||
"links": {
|
||||
"github": "https://github.com/AmadeusITGroup/prompt-registry",
|
||||
"vscode": "vscode:extension/AmadeusITGroup.prompt-registry",
|
||||
"vscode-insiders": "vscode-insiders:extension/AmadeusITGroup.prompt-registry",
|
||||
"marketplace": "https://marketplace.visualstudio.com/items?itemName=AmadeusITGroup.prompt-registry"
|
||||
},
|
||||
"configuration": null,
|
||||
"tags": [
|
||||
"vscode",
|
||||
"extension",
|
||||
"marketplace",
|
||||
"prompts",
|
||||
"bundles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "workspace-architect",
|
||||
"name": "Workspace Architect",
|
||||
"description": "A comprehensive library of specialized AI personas and chat modes for GitHub Copilot. Includes architectural planning, tech stack guidance, and advanced cognitive reasoning models. Install via npm and use the CLI to download personas and prompts.",
|
||||
"category": "CLI Tools",
|
||||
"featured": false,
|
||||
"requirements": [
|
||||
"Node.js 20 or higher",
|
||||
"npm"
|
||||
],
|
||||
"features": [
|
||||
"📦 CLI tool: List and download personas, prompts, and chat modes",
|
||||
"🎭 Rich persona library: Architecture, React, Azure, and more",
|
||||
"🧠 Cognitive modes: Advanced reasoning and planning personas",
|
||||
"⚡ Easy install: npm install -g workspace-architect"
|
||||
],
|
||||
"links": {
|
||||
"github": "https://github.com/archubbuck/workspace-architect",
|
||||
"npm": "https://www.npmjs.com/package/workspace-architect"
|
||||
},
|
||||
"configuration": {
|
||||
"type": "bash",
|
||||
"content": "# Install globally\nnpm install -g workspace-architect\n\n# List available items\nworkspace-architect list\n\n# Download a specific item\nworkspace-architect download instructions:basic-setup\n"
|
||||
},
|
||||
"tags": [
|
||||
"cli",
|
||||
"npm",
|
||||
"personas",
|
||||
"chat-modes",
|
||||
"prompts"
|
||||
]
|
||||
}
|
||||
],
|
||||
"filters": {
|
||||
"categories": [
|
||||
"CLI Tools",
|
||||
"MCP Servers",
|
||||
"VS Code Extensions",
|
||||
"Visual Studio Extensions"
|
||||
],
|
||||
"tags": [
|
||||
"agents",
|
||||
"browse",
|
||||
"bundles",
|
||||
"chat-modes",
|
||||
"cli",
|
||||
"docker",
|
||||
"download",
|
||||
"extension",
|
||||
"github",
|
||||
"install",
|
||||
"marketplace",
|
||||
"mcp",
|
||||
"npm",
|
||||
"package-manager",
|
||||
"personas",
|
||||
"preview",
|
||||
"prompts",
|
||||
"python",
|
||||
"search",
|
||||
"skills",
|
||||
"solution-explorer",
|
||||
"visual-studio",
|
||||
"vscode"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
|
||||
const base = import.meta.env.BASE_URL;
|
||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||
---
|
||||
|
||||
<BaseLayout title="Tools" description="MCP servers and developer tools for GitHub Copilot" activeNav="tools">
|
||||
<BaseLayout
|
||||
title="Tools"
|
||||
description="MCP servers and developer tools for GitHub Copilot"
|
||||
activeNav="tools"
|
||||
>
|
||||
<main>
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
@@ -15,50 +17,115 @@ const base = import.meta.env.BASE_URL;
|
||||
|
||||
<div class="page-content">
|
||||
<div class="container">
|
||||
<div class="tool-card">
|
||||
<div class="tool-header">
|
||||
<h2>🖥️ Awesome Copilot MCP Server</h2>
|
||||
<span class="badge">Official</span>
|
||||
<div class="search-section">
|
||||
<div class="search-bar">
|
||||
<input
|
||||
type="text"
|
||||
id="search-input"
|
||||
placeholder="Search tools..."
|
||||
class="search-input"
|
||||
/>
|
||||
</div>
|
||||
<p>A Model Context Protocol (MCP) server that provides prompts for searching and installing resources directly from this repository.</p>
|
||||
|
||||
<h3>Features</h3>
|
||||
<ul>
|
||||
<li>Search across all agents, prompts, instructions, skills, and collections</li>
|
||||
<li>Install resources directly to your project</li>
|
||||
<li>Browse featured and curated collections</li>
|
||||
</ul>
|
||||
|
||||
<h3>Requirements</h3>
|
||||
<ul>
|
||||
<li>Docker (required to run the server)</li>
|
||||
</ul>
|
||||
|
||||
<h3>Installation</h3>
|
||||
<p>See the <a href="https://github.com/github/awesome-copilot#mcp-server" target="_blank" rel="noopener">README</a> for installation instructions.</p>
|
||||
|
||||
<div class="tool-actions">
|
||||
<a href="https://github.com/github/awesome-copilot#mcp-server" class="btn btn-primary" target="_blank" rel="noopener">
|
||||
View Documentation
|
||||
</a>
|
||||
<div class="filters">
|
||||
<select id="filter-category" class="filter-select">
|
||||
<option value="">All Categories</option>
|
||||
</select>
|
||||
<button id="clear-filters" class="btn btn-secondary btn-small"
|
||||
>Clear</button
|
||||
>
|
||||
</div>
|
||||
<div id="results-count" class="results-count"></div>
|
||||
</div>
|
||||
|
||||
<div id="tools-list"></div>
|
||||
|
||||
<div class="coming-soon">
|
||||
<h2>More Tools Coming Soon</h2>
|
||||
<p>We're working on additional tools to enhance your GitHub Copilot experience. Check back soon!</p>
|
||||
<p>
|
||||
We're working on additional tools to enhance your GitHub Copilot
|
||||
experience. Check back soon!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
<style is:global>
|
||||
.search-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--color-card-bg);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 3px rgba(133, 52, 243, 0.1);
|
||||
}
|
||||
|
||||
.filters {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.filter-select {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--color-card-bg);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 14px;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.results-count {
|
||||
margin-top: 12px;
|
||||
font-size: 14px;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 48px;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 48px;
|
||||
background-color: var(--color-bg-secondary);
|
||||
border-radius: var(--border-radius-lg);
|
||||
}
|
||||
|
||||
.empty-state h3 {
|
||||
color: var(--color-text-muted);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.tool-card {
|
||||
background-color: var(--color-card-bg);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius-lg);
|
||||
padding: 32px;
|
||||
margin-bottom: 32px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.tool-header {
|
||||
@@ -66,6 +133,7 @@ const base = import.meta.env.BASE_URL;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tool-header h2 {
|
||||
@@ -74,34 +142,111 @@ const base = import.meta.env.BASE_URL;
|
||||
color: var(--color-text-emphasis);
|
||||
}
|
||||
|
||||
.badge {
|
||||
background-color: var(--color-accent);
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
.tool-badges {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tool-badge {
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tool-card h3 {
|
||||
.tool-badge.featured {
|
||||
background-color: var(--color-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tool-badge.category {
|
||||
background-color: var(--color-purple-light);
|
||||
color: var(--color-purple-dark);
|
||||
}
|
||||
|
||||
.tool-description {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.tool-section {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.tool-section h3 {
|
||||
margin-bottom: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-emphasis);
|
||||
}
|
||||
|
||||
.tool-card ul {
|
||||
.tool-section ul {
|
||||
margin: 0;
|
||||
padding-left: 24px;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.tool-card li {
|
||||
.tool-section li {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.tool-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.tool-tag {
|
||||
background-color: var(--color-bg-secondary);
|
||||
color: var(--color-text-muted);
|
||||
padding: 4px 12px;
|
||||
border-radius: 16px;
|
||||
font-size: 12px;
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.tool-config {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.tool-config h3 {
|
||||
margin-bottom: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-emphasis);
|
||||
}
|
||||
|
||||
.tool-config-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tool-config pre {
|
||||
background-color: var(--color-bg-secondary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 16px;
|
||||
overflow-x: auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tool-config code {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 13px;
|
||||
color: var(--color-text-primary);
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.tool-actions {
|
||||
margin-top: 24px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid var(--color-border);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.coming-soon {
|
||||
@@ -120,5 +265,45 @@ const base = import.meta.env.BASE_URL;
|
||||
.coming-soon p {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.copy-config-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px 14px;
|
||||
font-size: 13px;
|
||||
background-color: var(--color-bg-primary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--border-radius);
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
margin-top: 12px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.copy-config-btn:hover {
|
||||
background-color: var(--color-bg-secondary);
|
||||
color: var(--color-text-primary);
|
||||
border-color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.copy-config-btn.copied {
|
||||
background-color: var(--color-success);
|
||||
color: white;
|
||||
border-color: var(--color-success);
|
||||
}
|
||||
|
||||
/* Search highlight */
|
||||
.search-highlight {
|
||||
background-color: var(--color-warning);
|
||||
color: var(--color-text-emphasis);
|
||||
padding: 0 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { initToolsPage } from "../scripts/pages/tools";
|
||||
initToolsPage();
|
||||
</script>
|
||||
</BaseLayout>
|
||||
|
||||
264
website/src/scripts/pages/tools.ts
Normal file
264
website/src/scripts/pages/tools.ts
Normal file
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* Tools page functionality
|
||||
*/
|
||||
import { FuzzySearch, type SearchableItem } from '../search';
|
||||
import { fetchData, debounce, escapeHtml } from '../utils';
|
||||
|
||||
export interface Tool extends SearchableItem {
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
category: string;
|
||||
featured: boolean;
|
||||
requirements: string[];
|
||||
features: string[];
|
||||
links: {
|
||||
blog?: string;
|
||||
vscode?: string;
|
||||
'vscode-insiders'?: string;
|
||||
'visual-studio'?: string;
|
||||
github?: string;
|
||||
documentation?: string;
|
||||
marketplace?: string;
|
||||
npm?: string;
|
||||
pypi?: string;
|
||||
};
|
||||
configuration?: {
|
||||
type: string;
|
||||
content: string;
|
||||
};
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
interface ToolsData {
|
||||
items: Tool[];
|
||||
filters: {
|
||||
categories: string[];
|
||||
tags: string[];
|
||||
};
|
||||
}
|
||||
|
||||
let allItems: Tool[] = [];
|
||||
let search: FuzzySearch<Tool>;
|
||||
let currentFilters = {
|
||||
categories: [] as string[],
|
||||
query: '',
|
||||
};
|
||||
|
||||
function applyFiltersAndRender(): void {
|
||||
const searchInput = document.getElementById('search-input') as HTMLInputElement;
|
||||
const countEl = document.getElementById('results-count');
|
||||
const query = searchInput?.value || '';
|
||||
currentFilters.query = query;
|
||||
|
||||
let results = query ? search.search(query) : [...allItems];
|
||||
|
||||
if (currentFilters.categories.length > 0) {
|
||||
results = results.filter(item =>
|
||||
currentFilters.categories.includes(item.category)
|
||||
);
|
||||
}
|
||||
|
||||
renderTools(results, query);
|
||||
|
||||
let countText = `${results.length} of ${allItems.length} tools`;
|
||||
if (currentFilters.categories.length > 0) {
|
||||
countText += ` (filtered by ${currentFilters.categories.length} categories)`;
|
||||
}
|
||||
if (countEl) countEl.textContent = countText;
|
||||
}
|
||||
|
||||
function renderTools(tools: Tool[], query = ''): void {
|
||||
const container = document.getElementById('tools-list');
|
||||
if (!container) return;
|
||||
|
||||
if (tools.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<h3>No tools found</h3>
|
||||
<p>Try a different search term or adjust filters</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = tools.map(tool => {
|
||||
const badges: string[] = [];
|
||||
if (tool.featured) {
|
||||
badges.push('<span class="tool-badge featured">Featured</span>');
|
||||
}
|
||||
badges.push(`<span class="tool-badge category">${escapeHtml(tool.category)}</span>`);
|
||||
|
||||
const features = tool.features && tool.features.length > 0
|
||||
? `<div class="tool-section">
|
||||
<h3>Features</h3>
|
||||
<ul>${tool.features.map(f => `<li>${escapeHtml(f)}</li>`).join('')}</ul>
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
const requirements = tool.requirements && tool.requirements.length > 0
|
||||
? `<div class="tool-section">
|
||||
<h3>Requirements</h3>
|
||||
<ul>${tool.requirements.map(r => `<li>${escapeHtml(r)}</li>`).join('')}</ul>
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
const tags = tool.tags && tool.tags.length > 0
|
||||
? `<div class="tool-tags">
|
||||
${tool.tags.map(t => `<span class="tool-tag">${escapeHtml(t)}</span>`).join('')}
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
const config = tool.configuration
|
||||
? `<div class="tool-config">
|
||||
<h3>Configuration</h3>
|
||||
<div class="tool-config-wrapper">
|
||||
<pre><code>${escapeHtml(tool.configuration.content)}</code></pre>
|
||||
</div>
|
||||
<button class="copy-config-btn" data-config="${encodeURIComponent(tool.configuration.content)}">
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/>
|
||||
<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"/>
|
||||
</svg>
|
||||
Copy Configuration
|
||||
</button>
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
const actions: string[] = [];
|
||||
if (tool.links.blog) {
|
||||
actions.push(`<a href="${tool.links.blog}" class="btn btn-secondary" target="_blank" rel="noopener">📖 Blog</a>`);
|
||||
}
|
||||
if (tool.links.marketplace) {
|
||||
actions.push(`<a href="${tool.links.marketplace}" class="btn btn-secondary" target="_blank" rel="noopener">🏪 Marketplace</a>`);
|
||||
}
|
||||
if (tool.links.npm) {
|
||||
actions.push(`<a href="${tool.links.npm}" class="btn btn-secondary" target="_blank" rel="noopener">📦 npm</a>`);
|
||||
}
|
||||
if (tool.links.pypi) {
|
||||
actions.push(`<a href="${tool.links.pypi}" class="btn btn-secondary" target="_blank" rel="noopener">🐍 PyPI</a>`);
|
||||
}
|
||||
if (tool.links.documentation) {
|
||||
actions.push(`<a href="${tool.links.documentation}" class="btn btn-secondary" target="_blank" rel="noopener">📚 Docs</a>`);
|
||||
}
|
||||
if (tool.links.github) {
|
||||
actions.push(`<a href="${tool.links.github}" class="btn btn-secondary" target="_blank" rel="noopener">GitHub</a>`);
|
||||
}
|
||||
if (tool.links.vscode) {
|
||||
actions.push(`<a href="${tool.links.vscode}" class="btn btn-primary" target="_blank" rel="noopener">Install in VS Code</a>`);
|
||||
}
|
||||
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>`);
|
||||
}
|
||||
|
||||
const actionsHtml = actions.length > 0
|
||||
? `<div class="tool-actions">${actions.join('')}</div>`
|
||||
: '';
|
||||
|
||||
const titleHtml = query ? search.highlight(tool.name, query) : escapeHtml(tool.name);
|
||||
|
||||
return `
|
||||
<div class="tool-card">
|
||||
<div class="tool-header">
|
||||
<h2>${titleHtml}</h2>
|
||||
<div class="tool-badges">
|
||||
${badges.join('')}
|
||||
</div>
|
||||
</div>
|
||||
<p class="tool-description">${escapeHtml(tool.description)}</p>
|
||||
${features}
|
||||
${requirements}
|
||||
${config}
|
||||
${tags}
|
||||
${actionsHtml}
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
setupCopyConfigHandlers();
|
||||
}
|
||||
|
||||
function setupCopyConfigHandlers(): void {
|
||||
document.querySelectorAll('.copy-config-btn').forEach(btn => {
|
||||
btn.addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
const button = e.currentTarget as HTMLButtonElement;
|
||||
const config = decodeURIComponent(button.dataset.config || '');
|
||||
try {
|
||||
await navigator.clipboard.writeText(config);
|
||||
button.classList.add('copied');
|
||||
const originalHtml = button.innerHTML;
|
||||
button.innerHTML = `
|
||||
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/>
|
||||
</svg>
|
||||
Copied!
|
||||
`;
|
||||
setTimeout(() => {
|
||||
button.classList.remove('copied');
|
||||
button.innerHTML = originalHtml;
|
||||
}, 2000);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy:', err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function initToolsPage(): Promise<void> {
|
||||
const container = document.getElementById('tools-list');
|
||||
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');
|
||||
|
||||
if (container) {
|
||||
container.innerHTML = '<div class="loading">Loading tools...</div>';
|
||||
}
|
||||
|
||||
const data = await fetchData<ToolsData>('tools.json');
|
||||
if (!data || !data.items) {
|
||||
if (container) container.innerHTML = '<div class="empty-state"><h3>Failed to load tools</h3></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Map items to include title for FuzzySearch
|
||||
allItems = data.items.map(item => ({
|
||||
...item,
|
||||
title: item.name, // FuzzySearch uses title
|
||||
}));
|
||||
|
||||
search = new FuzzySearch<Tool>();
|
||||
search.setItems(allItems);
|
||||
|
||||
// Populate category filter
|
||||
if (categoryFilter && data.filters.categories) {
|
||||
categoryFilter.innerHTML = '<option value="">All Categories</option>' +
|
||||
data.filters.categories.map(c => `<option value="${escapeHtml(c)}">${escapeHtml(c)}</option>`).join('');
|
||||
|
||||
categoryFilter.addEventListener('change', () => {
|
||||
currentFilters.categories = categoryFilter.value ? [categoryFilter.value] : [];
|
||||
applyFiltersAndRender();
|
||||
});
|
||||
}
|
||||
|
||||
// Search input handler
|
||||
searchInput?.addEventListener('input', debounce(() => applyFiltersAndRender(), 200));
|
||||
|
||||
// Clear filters
|
||||
clearFiltersBtn?.addEventListener('click', () => {
|
||||
currentFilters = { categories: [], query: '' };
|
||||
if (categoryFilter) categoryFilter.value = '';
|
||||
if (searchInput) searchInput.value = '';
|
||||
applyFiltersAndRender();
|
||||
});
|
||||
|
||||
applyFiltersAndRender();
|
||||
}
|
||||
|
||||
// Auto-initialize when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', initToolsPage);
|
||||
Reference in New Issue
Block a user