Merge branch 'main' into all-contributors/add-thesurenk

This commit is contained in:
Ayan Gupta
2026-07-20 13:56:28 -07:00
committed by GitHub
156 changed files with 15003 additions and 4304 deletions
-1
View File
@@ -504,7 +504,6 @@ import PageHeader from '../components/PageHeader.astro';
<td align="center" size="13px" colspan="7">
<img src="https://raw.githubusercontent.com/all-contributors/all-contributors-cli/1b8533af435da9854653492b1327a23a4dbd0a10/assets/logo-small.svg">
<a href="https://all-contributors.js.org/docs/en/bot/usage">Add your contributions</a>
</img>
</td>
</tr>
</tfoot>
+11 -21
View File
@@ -46,6 +46,7 @@ interface ExtensionEntry extends HeaderItem {
installUrl?: string | null;
installCommand?: string | null;
sourceUrl?: string | null;
externalSource?: string | null;
external?: boolean;
author?: ExtensionAuthor | null;
keywords?: string[];
@@ -117,6 +118,7 @@ const installUrl = safeUrl(
: "")
);
const sourceUrl = safeUrl(item.sourceUrl);
const externalSource = (item.externalSource || "").trim();
const installCommand =
item.installCommand ||
(item.pluginName
@@ -124,16 +126,13 @@ const installCommand =
: "");
const githubUrl = isExternal
? sourceUrl || installUrl || GITHUB_TREE
? sourceUrl || GITHUB_TREE
: item.path
? `${GITHUB_TREE}/${item.path}`
: installUrl || GITHUB_TREE;
// Sidebar "Source" shows item.path; external extensions have no repo path.
const sidebarItem =
isExternal && (sourceUrl || installUrl)
? { ...item, path: sourceUrl || installUrl }
: item;
const sidebarItem = isExternal && sourceUrl ? { ...item, path: sourceUrl } : item;
const shortHash = (value: string) =>
/^[0-9a-f]{40}$/i.test(value) ? value.slice(0, 7) : value;
@@ -262,22 +261,13 @@ if (!isExternal && item.ref) {
>
{
isExternal ? (
<div class="skill-install" slot="install">
<p class="skill-install-label">Install this extension</p>
<p class="skill-install-note">
This extension is maintained in an external repository.
</p>
{installUrl && (
<button
type="button"
class="btn btn-secondary skill-install-url-btn"
data-action="copy-install-url"
data-install-url={installUrl}
>
Copy install URL
</button>
)}
</div>
<PluginInstall
slot="install"
isExternal={true}
externalSource={externalSource || null}
label="Install this extension"
note="This extension is maintained in an external repository."
/>
) : (
<PluginInstall
slot="install"
-159
View File
@@ -1,159 +0,0 @@
---
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
import BackToTop from "../../components/BackToTop.astro";
import hooksData from "../../../public/data/hooks.json";
import RawMarkdown from "../../components/pages/RawMarkdown.astro";
import type { HeaderItem } from "../../components/pages/Header.astro";
import DetailHeader from "../../components/pages/Header.astro";
import Breadcrumb from "../../components/pages/Breadcrumb.astro";
import Sidebar from "../../components/pages/Sidebar.astro";
import FileBrowser from "../../components/pages/FileBrowser.astro";
import { readResourceMarkdown, formatLastUpdated } from "../../lib/detail-page";
const GITHUB_BASE = "https://github.com/github/awesome-copilot/blob/main";
const GITHUB_TREE_BASE = "https://github.com/github/awesome-copilot/tree/main";
interface HookFile {
name: string;
path: string;
size?: number;
}
interface HookItem extends HeaderItem {
id: string;
title: string;
description?: string;
path: string;
readmeFile: string;
readmeFileName?: string;
files: HookFile[];
hooks: string[];
tags: string[];
assets: string[];
lastUpdated?: string | null;
}
export function getStaticPaths() {
return (hooksData.items as HookItem[]).map((item) => ({
params: { id: item.id },
props: { item },
}));
}
const { item } = Astro.props as { item: HookItem };
const { markdownHtml, frontmatterText, rawMarkdown } = readResourceMarkdown(
item.readmeFile
);
const lastUpdated = formatLastUpdated(item.lastUpdated);
const githubUrl = `${GITHUB_TREE_BASE}/${item.path}`;
const readmeFileName = item.readmeFileName ?? "README.md";
const fileCount = item.files.length;
const chips: {
title: string;
items: string[];
filterBase?: string;
filterParam?: string;
}[] = [];
if (item.hooks.length > 0) {
chips.push({ title: "Hook events", items: item.hooks });
}
chips.push({
title: "Files",
items: [`${fileCount} file${fileCount === 1 ? "" : "s"}`],
});
if (item.tags.length > 0) {
chips.push({
title: "Tags",
items: item.tags,
filterBase: "/hooks/",
filterParam: "tag",
});
}
---
<StarlightPage
frontmatter={{
title: item.title,
description: item.description,
template: "splash",
prev: false,
next: false,
editUrl: false,
}}
>
<div
id="main-content"
class="resource-detail-page hook-detail-page"
data-file-browser-page
data-bundle-id={item.id}
data-path={item.readmeFile}
>
<RawMarkdown markdown={rawMarkdown} />
<div class="container">
<Breadcrumb
paths={[
{ name: "Home", href: "/" },
{ name: "Hooks", href: "/hooks/" },
]}
title={item.title}
/>
<DetailHeader item={item} />
<div class="detail-layout">
<div class="detail-main">
<FileBrowser
files={item.files}
primaryPath={item.readmeFile}
primaryName={readmeFileName}
primaryHtml={markdownHtml}
githubBase={GITHUB_BASE}
/>
</div>
<Sidebar
item={item}
lastUpdated={lastUpdated ?? undefined}
frontmatterText={frontmatterText || undefined}
githubUrl={githubUrl}
chips={chips}
>
<div class="skill-install" slot="install">
<p class="skill-install-label">Install this hook</p>
<p class="skill-install-note">
Hooks are multi-file bundles with no CLI installer. Download the
ZIP and copy the files into your project's hooks directory.
</p>
<button
type="button"
class="btn btn-primary skill-download-btn"
data-action="download-zip"
>
<svg
viewBox="0 0 16 16"
width="16"
height="16"
fill="currentColor"
aria-hidden="true"
><path
d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"
></path><path
d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"
></path></svg
>
Download ZIP
</button>
</div>
</Sidebar>
</div>
</div>
</div>
<BackToTop />
<script>
import "../../scripts/pages/file-browser";
</script>
</StarlightPage>
-56
View File
@@ -1,56 +0,0 @@
---
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
import ContributeCTA from '../components/ContributeCTA.astro';
import PageHeader from '../components/PageHeader.astro';
import EmbeddedPageData from '../components/EmbeddedPageData.astro';
import BackToTop from '../components/BackToTop.astro';
import hooksData from '../../public/data/hooks.json';
import { renderHooksHtml, sortHooks } from '../scripts/pages/hooks-render';
const initialItems = sortHooks(hooksData.items, 'title');
---
<StarlightPage frontmatter={{ title: 'Hooks', description: 'Automated workflows triggered by Copilot coding agent events', template: 'splash', prev: false, next: false, editUrl: false }}>
<div id="main-content" class="hooks-page listing-cards-page">
<PageHeader title="Hooks" description="Automated workflows triggered by Copilot coding agent events" icon="hook" />
<div class="page-content">
<div class="container">
<div class="listing-toolbar">
<div class="listing-toolbar-row">
<div class="results-count" id="results-count" aria-live="polite">{initialItems.length} hooks</div>
<details class="listing-controls">
<summary class="listing-controls-trigger btn btn-secondary btn-small">Sort &amp; Filter</summary>
<div class="listing-controls-panel">
<div class="filters-bar" id="filters-bar">
<div class="filter-group">
<label for="filter-tag">Tag:</label>
<select id="filter-tag" multiple aria-label="Filter by tag"></select>
</div>
<div class="filter-group">
<label for="sort-select">Sort:</label>
<select id="sort-select" aria-label="Sort by">
<option value="title">Name (A-Z)</option>
<option value="lastUpdated">Recently Updated</option>
</select>
</div>
<button id="clear-filters" class="btn btn-secondary btn-small">Clear Filters</button>
</div>
</div>
</details>
</div>
</div>
<div class="resource-list" id="resource-list" role="list" set:html={renderHooksHtml(initialItems)}></div>
<ContributeCTA resourceType="hooks" />
</div>
</div>
</div>
<BackToTop />
<EmbeddedPageData filename="hooks.json" data={hooksData} />
<script>
import '../scripts/listing-flyouts';
import '../scripts/pages/hooks';
</script>
</StarlightPage>
-58
View File
@@ -1,6 +1,5 @@
---
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
import Modal from "../components/Modal.astro";
import Icon from "../components/Icon.astro";
import BackToTop from "../components/BackToTop.astro";
@@ -116,44 +115,6 @@ const base = import.meta.env.BASE_URL;
-
</div>
</a>
<a
href={`${base}hooks/`}
class="card card-with-count card-category-automation"
id="card-hooks"
style="--animation-delay: 150ms;"
>
<div class="card-icon" aria-hidden="true">
<Icon name="hook" size={40} />
</div>
<div class="card-content">
<h3>Hooks</h3>
<p>Automated workflows triggered by agent events</p>
</div>
<div class="card-count" data-count="hooks" aria-label="Hook count">
-
</div>
</a>
<a
href={`${base}workflows/`}
class="card card-with-count card-category-automation"
id="card-workflows"
style="--animation-delay: 200ms;"
>
<div class="card-icon" aria-hidden="true">
<Icon name="workflow" size={40} />
</div>
<div class="card-content">
<h3>Workflows</h3>
<p>AI-powered automations for GitHub Actions</p>
</div>
<div
class="card-count"
data-count="workflows"
aria-label="Workflow count"
>
-
</div>
</a>
<a
href={`${base}plugins/`}
class="card card-with-count card-category-extension"
@@ -196,23 +157,6 @@ const base = import.meta.env.BASE_URL;
-
</div>
</a>
<a
href={`${base}tools/`}
class="card card-with-count card-category-dev"
id="card-tools"
style="--animation-delay: 350ms;"
>
<div class="card-icon" aria-hidden="true">
<Icon name="wrench" size={40} />
</div>
<div class="card-content">
<h3>Tools</h3>
<p>MCP servers and developer tools</p>
</div>
<div class="card-count" data-count="tools" aria-label="Tool count">
-
</div>
</a>
<a
href={`${base}learning-hub/`}
class="card card-with-count card-category-learn"
@@ -232,8 +176,6 @@ const base = import.meta.env.BASE_URL;
</section>
</div>
<Modal />
<!-- Back to Top Button -->
<BackToTop />
@@ -0,0 +1,229 @@
---
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
import BackToTop from "../../../../../components/BackToTop.astro";
import Breadcrumb from "../../../../../components/pages/Breadcrumb.astro";
import FileBrowser from "../../../../../components/pages/FileBrowser.astro";
import { readResourceMarkdown } from "../../../../../lib/detail-page";
import samplesData from "../../../../../../public/data/samples.json";
interface RecipeVariant {
doc: string;
example: string | null;
}
interface Recipe {
id: string;
name: string;
description: string;
tags: string[];
languages: string[];
variants: Record<string, RecipeVariant>;
external?: boolean;
url?: string | null;
author?: { name: string; url?: string } | null;
}
interface Language {
id: string;
name: string;
icon: string;
extension: string;
}
interface Cookbook {
id: string;
name: string;
description: string;
path: string;
featured: boolean;
languages: Language[];
recipes: Recipe[];
}
interface SamplesData {
cookbooks: Cookbook[];
}
const GITHUB_BASE = "https://github.com/github/awesome-copilot/blob/main";
function buildCookbookUrl(
cookbookId: string,
languageId: string,
recipeId: string,
filePath?: string | null
): string {
const basePath = `/learning-hub/cookbook/${encodeURIComponent(
cookbookId
)}/${encodeURIComponent(languageId)}/${encodeURIComponent(recipeId)}/`;
if (!filePath) return basePath;
return `${basePath}#file=${encodeURIComponent(filePath)}`;
}
export function getStaticPaths() {
const entries = (samplesData as SamplesData).cookbooks.flatMap((cookbook) =>
cookbook.recipes.flatMap((recipe) =>
Object.keys(recipe.variants ?? {}).map((languageId) => ({
params: {
cookbook: cookbook.id,
language: languageId,
recipe: recipe.id,
},
}))
)
);
return entries;
}
const { cookbook, language, recipe } = Astro.params as {
cookbook: string;
language: string;
recipe: string;
};
const cookbookEntry = (samplesData as SamplesData).cookbooks.find(
(item) => item.id === cookbook
);
const recipeEntry = cookbookEntry?.recipes.find((item) => item.id === recipe);
const languageEntry = cookbookEntry?.languages.find((item) => item.id === language);
const variant = recipeEntry?.variants?.[language];
if (!cookbookEntry || !recipeEntry || !languageEntry || !variant || recipeEntry.external) {
return Astro.redirect("/learning-hub/cookbook/");
}
const { markdownHtml } = readResourceMarkdown(variant.doc);
const files = [{ name: variant.doc.split("/").pop() ?? variant.doc, path: variant.doc }];
if (variant.example) {
files.push({
name: variant.example.split("/").pop() ?? variant.example,
path: variant.example,
});
}
const recipeUrl = buildCookbookUrl(cookbook, language, recipe);
const exampleUrl = variant.example
? buildCookbookUrl(cookbook, language, recipe, variant.example)
: null;
---
<StarlightPage
frontmatter={{
title: `${recipeEntry.name} (${languageEntry.name})`,
description: recipeEntry.description,
template: "splash",
prev: false,
next: false,
editUrl: false,
}}
>
<div
id="main-content"
class="resource-detail-page cookbook-detail-page"
data-file-browser-page
data-bundle-id={`${cookbookEntry.id}-${recipeEntry.id}-${languageEntry.id}`}
data-path={variant.doc}
>
<div class="container">
<Breadcrumb
paths={[
{ name: "Home", href: "/" },
{ name: "Learning Hub", href: "/learning-hub/" },
{ name: "Cookbook", href: "/learning-hub/cookbook/" },
{ name: cookbookEntry.name, href: "/learning-hub/cookbook/" },
]}
title={recipeEntry.name}
/>
<header class="cookbook-detail-header">
<h1>{recipeEntry.name}</h1>
<p>{recipeEntry.description}</p>
<div class="cookbook-detail-meta">
<span class="cookbook-detail-language">{languageEntry.icon} {languageEntry.name}</span>
<div class="cookbook-detail-tags">
{recipeEntry.tags.map((tag) => (
<span class="recipe-tag">{tag}</span>
))}
</div>
</div>
<div class="cookbook-detail-actions">
<a class="btn btn-secondary btn-small" href={recipeUrl}>
View Recipe
</a>
{exampleUrl && (
<a class="btn btn-secondary btn-small" href={exampleUrl}>
View Example
</a>
)}
<a
class="btn btn-secondary btn-small"
href={`https://github.com/github/awesome-copilot/blob/main/${variant.doc}`}
target="_blank"
rel="noopener"
>
GitHub
</a>
</div>
</header>
<FileBrowser
files={files}
primaryPath={variant.doc}
primaryName={variant.doc.split("/").pop() ?? variant.doc}
primaryHtml={markdownHtml}
githubBase={GITHUB_BASE}
/>
</div>
</div>
<BackToTop />
<script>
import "../../../../../scripts/pages/file-browser";
</script>
<style is:global>
.cookbook-detail-header {
margin-bottom: 24px;
display: flex;
flex-direction: column;
gap: 12px;
}
.cookbook-detail-header h1 {
margin: 0;
color: var(--color-text-emphasis);
}
.cookbook-detail-header p {
margin: 0;
color: var(--color-text-muted);
}
.cookbook-detail-meta {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
}
.cookbook-detail-language {
display: inline-flex;
align-items: center;
gap: 6px;
font-family: "Monaspace Argon NF", monospace;
}
.cookbook-detail-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.cookbook-detail-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
</style>
</StarlightPage>
@@ -1,7 +1,6 @@
---
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
import samplesData from '../../../../public/data/samples.json';
import Modal from '../../../components/Modal.astro';
import EmbeddedPageData from '../../../components/EmbeddedPageData.astro';
import {
getRecipeResultsCountText,
@@ -56,7 +55,6 @@ const languageOptions = Array.from(
<div id="samples-list" set:html={renderCookbookSectionsHtml(initialRecipeMatches)}></div>
</div>
<Modal />
<EmbeddedPageData filename="samples.json" data={samplesData} />
<style is:global>
-277
View File
@@ -1,277 +0,0 @@
---
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
import toolsData from '../../public/data/tools.json';
import Modal from '../components/Modal.astro';
import ContributeCTA from "../components/ContributeCTA.astro";
import EmbeddedPageData from "../components/EmbeddedPageData.astro";
import PageHeader from "../components/PageHeader.astro";
import BackToTop from '../components/BackToTop.astro';
import { renderToolsHtml, sortTools } from "../scripts/pages/tools-render";
const initialItems = sortTools(
toolsData.items.map((item) => ({
...item,
title: item.name,
})),
"title"
);
---
<StarlightPage frontmatter={{ title: 'Tools', description: 'MCP servers and developer tools for GitHub Copilot', template: 'splash', prev: false, next: false, editUrl: false }}>
<div id="main-content">
<PageHeader title="Tools" description="MCP servers and developer tools for GitHub Copilot" icon="wrench" />
<div class="page-content">
<div class="container">
<div class="listing-toolbar">
<div class="listing-toolbar-row">
<div id="results-count" class="results-count" aria-live="polite">{initialItems.length} tools</div>
<details class="listing-controls">
<summary class="listing-controls-trigger btn btn-secondary btn-small">Sort &amp; Filter</summary>
<div class="listing-controls-panel">
<div class="filters-bar" id="filters-bar">
<div class="filter-group">
<label for="filter-category">Category:</label>
<select id="filter-category" class="filter-select" aria-label="Filter by category">
<option value="">All Categories</option>
{toolsData.filters.categories.map((category) => (
<option value={category}>{category}</option>
))}
</select>
</div>
<div class="filter-group">
<label for="sort-select">Sort:</label>
<select id="sort-select" class="filter-select" aria-label="Sort tools">
<option value="featured">Featured First</option>
<option value="title">Title</option>
</select>
</div>
<button id="clear-filters" class="btn btn-secondary btn-small">Clear</button>
</div>
</div>
</details>
</div>
</div>
<div id="tools-list" set:html={renderToolsHtml(initialItems)}></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>
</div>
<ContributeCTA resourceType="tools" />
</div>
</div>
</div>
<Modal />
<BackToTop />
<EmbeddedPageData filename="tools.json" data={toolsData} />
<style is:global>
.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: 24px;
}
.tool-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.tool-header h2 {
margin: 0;
font-size: 24px;
color: var(--color-text-emphasis);
}
.tool-badges {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.tool-badge {
padding: 4px 12px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.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-section ul {
margin: 0;
padding-left: 24px;
color: var(--color-text-muted);
}
.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 {
text-align: center;
padding: 48px;
background-color: var(--color-bg-secondary);
border: 1px dashed var(--color-border);
border-radius: var(--border-radius-lg);
}
.coming-soon h2 {
color: var(--color-text-muted);
margin-bottom: 8px;
}
.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 '../scripts/listing-flyouts';
import '../scripts/pages/tools';
</script>
</StarlightPage>
-131
View File
@@ -1,131 +0,0 @@
---
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
import BackToTop from "../../components/BackToTop.astro";
import workflowsData from "../../../public/data/workflows.json";
import RawMarkdown from "../../components/pages/RawMarkdown.astro";
import type { HeaderItem } from "../../components/pages/Header.astro";
import DetailHeader from "../../components/pages/Header.astro";
import Breadcrumb from "../../components/pages/Breadcrumb.astro";
import Main from "../../components/pages/Main.astro";
import Sidebar from "../../components/pages/Sidebar.astro";
import { readResourceMarkdown, formatLastUpdated } from "../../lib/detail-page";
const GITHUB_BASE = "https://github.com/github/awesome-copilot/blob/main";
const workflowGuideHref = "/learning-hub/agentic-workflows/";
interface WorkflowItem extends HeaderItem {
id: string;
title: string;
description?: string;
path: string;
triggers: string[];
lastUpdated?: string | null;
}
export function getStaticPaths() {
return (workflowsData.items as WorkflowItem[]).map((item) => ({
params: { id: item.id },
props: { item },
}));
}
const { item } = Astro.props as { item: WorkflowItem };
const { markdownHtml, frontmatterText, rawMarkdown } = readResourceMarkdown(
item.path
);
const lastUpdated = formatLastUpdated(item.lastUpdated);
const githubUrl = `${GITHUB_BASE}/${item.path}`;
const chips: { title: string; items: string[] }[] = [];
if (item.triggers.length > 0) {
chips.push({ title: "Triggers", items: item.triggers });
}
---
<StarlightPage
frontmatter={{
title: item.title,
description: item.description,
template: "splash",
prev: false,
next: false,
editUrl: false,
}}
>
<div
id="main-content"
class="resource-detail-page"
data-resource-detail
data-path={item.path}
>
<RawMarkdown markdown={rawMarkdown} />
<div class="container">
<Breadcrumb
paths={[
{ name: "Home", href: "/" },
{ name: "Agentic Workflows", href: "/workflows/" },
]}
title={item.title}
/>
<DetailHeader item={item} />
<div class="detail-layout">
<Main markdownHtml={markdownHtml} githubUrl={githubUrl} />
<Sidebar
item={item}
lastUpdated={lastUpdated ?? undefined}
frontmatterText={frontmatterText || undefined}
githubUrl={githubUrl}
chips={chips}
>
<div class="skill-install" slot="install">
<p class="skill-install-label">Install this workflow</p>
<p class="skill-install-note">
Install the <code>gh aw</code> CLI{" "}
(<code>gh extension install github/gh-aw</code>), then copy this
file into <code>.github/workflows/</code> and run{" "}
<code>gh aw compile</code> to generate the lock file. See the{" "}
<a href={workflowGuideHref}>Agentic Workflows guide</a>{" "}
for full setup steps.
</p>
<button
type="button"
class="btn btn-primary skill-download-btn"
data-action="download"
>
<svg
viewBox="0 0 16 16"
width="16"
height="16"
fill="currentColor"
aria-hidden="true"
><path
d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"
></path><path
d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"
></path></svg
>
Download workflow
</button>
<button
type="button"
class="btn btn-secondary skill-download-btn"
data-action="copy-markdown"
>
Copy markdown
</button>
</div>
</Sidebar>
</div>
</div>
</div>
<BackToTop />
<script>
import "../../scripts/pages/resource-detail";
</script>
</StarlightPage>
-56
View File
@@ -1,56 +0,0 @@
---
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
import workflowsData from '../../public/data/workflows.json';
import ContributeCTA from '../components/ContributeCTA.astro';
import EmbeddedPageData from '../components/EmbeddedPageData.astro';
import PageHeader from '../components/PageHeader.astro';
import BackToTop from '../components/BackToTop.astro';
import { renderWorkflowsHtml, sortWorkflows } from '../scripts/pages/workflows-render';
const initialItems = sortWorkflows(workflowsData.items, 'title');
---
<StarlightPage frontmatter={{ title: 'Agentic Workflows', description: 'AI-powered repository automations that run coding agents in GitHub Actions', template: 'splash', prev: false, next: false, editUrl: false }}>
<div id="main-content" class="workflows-page listing-cards-page">
<PageHeader title="Agentic Workflows" description="AI-powered repository automations that run coding agents in GitHub Actions" icon="workflow" />
<div class="page-content">
<div class="container">
<div class="listing-toolbar">
<div class="listing-toolbar-row">
<div class="results-count" id="results-count" aria-live="polite">{initialItems.length} workflows</div>
<details class="listing-controls">
<summary class="listing-controls-trigger btn btn-secondary btn-small">Sort &amp; Filter</summary>
<div class="listing-controls-panel">
<div class="filters-bar" id="filters-bar">
<div class="filter-group">
<label for="filter-trigger">Trigger:</label>
<select id="filter-trigger" multiple aria-label="Filter by trigger"></select>
</div>
<div class="filter-group">
<label for="sort-select">Sort:</label>
<select id="sort-select" aria-label="Sort by">
<option value="title">Name (A-Z)</option>
<option value="lastUpdated">Recently Updated</option>
</select>
</div>
<button id="clear-filters" class="btn btn-secondary btn-small">Clear Filters</button>
</div>
</div>
</details>
</div>
</div>
<div class="resource-list" id="resource-list" role="list" set:html={renderWorkflowsHtml(initialItems)}></div>
<ContributeCTA resourceType="workflows" />
</div>
</div>
</div>
<BackToTop />
<EmbeddedPageData filename="workflows.json" data={workflowsData} />
<script>
import '../scripts/listing-flyouts';
import '../scripts/pages/workflows';
</script>
</StarlightPage>