feat(website): add samples/cookbook page with recipe browser

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
This commit is contained in:
Aaron Powell
2026-02-02 15:11:12 +11:00
parent 23f08bbb63
commit b8d93a0344
14 changed files with 1699 additions and 67 deletions

View File

@@ -1,95 +1,246 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import Modal from '../components/Modal.astro';
const base = import.meta.env.BASE_URL;
---
<BaseLayout title="Samples" description="Code samples and examples for building with GitHub Copilot" activeNav="samples">
<BaseLayout title="Samples" description="Code samples, recipes, and examples for building with GitHub Copilot" activeNav="samples">
<main id="main-content">
<div class="page-header">
<div class="container">
<h1>📚 Samples</h1>
<p>Code samples and examples for building with GitHub Copilot</p>
<h1>📚 Samples & Recipes</h1>
<p>Code samples, recipes, and examples for building with GitHub Copilot tools</p>
</div>
</div>
<div class="page-content">
<div class="container">
<div class="coming-soon">
<div class="coming-soon-icon" aria-hidden="true">🚧</div>
<h2>Coming Soon</h2>
<p>We're migrating code samples from the <a href="https://github.com/github/copilot-sdk/tree/main/cookbook" target="_blank" rel="noopener">Copilot SDK Cookbook</a> to this repository.</p>
<p>Check back soon for examples including:</p>
<ul class="sample-list">
<li>Building custom agents</li>
<li>Integrating with MCP servers</li>
<li>Creating prompt templates</li>
<li>Working with Copilot APIs</li>
</ul>
<div class="coming-soon-actions">
<a href="https://github.com/github/copilot-sdk/tree/main/cookbook" class="btn btn-primary" target="_blank" rel="noopener">
View Current Cookbook
</a>
<a href="https://github.com/github/awesome-copilot" class="btn btn-secondary" target="_blank" rel="noopener">
Watch Repository
</a>
<div class="search-bar">
<label for="search-input" class="sr-only">Search recipes</label>
<input type="text" id="search-input" placeholder="Search recipes..." autocomplete="off">
</div>
<div class="filters-bar" id="filters-bar">
<div class="filter-group">
<label for="filter-language">Language:</label>
<select id="filter-language" aria-label="Filter by language">
<option value="">All Languages</option>
</select>
</div>
<div class="filter-group">
<label for="filter-tag">Tags:</label>
<select id="filter-tag" multiple aria-label="Filter by tags"></select>
</div>
<button id="clear-filters" class="btn btn-secondary btn-small">Clear Filters</button>
</div>
<div class="results-count" id="results-count" aria-live="polite"></div>
<div id="samples-list" role="list">
<div class="loading" aria-live="polite">Loading samples...</div>
</div>
</div>
</div>
</main>
<style>
.coming-soon {
text-align: center;
padding: 64px 32px;
background-color: var(--color-bg-secondary);
border: 1px dashed var(--color-border);
border-radius: var(--border-radius-lg);
<Modal />
<style is:global>
/* Cookbook Section */
.cookbook-section {
margin-bottom: 48px;
}
.coming-soon-icon {
font-size: 64px;
.cookbook-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 24px;
margin-bottom: 24px;
}
.coming-soon h2 {
color: var(--color-text-emphasis);
margin-bottom: 16px;
font-size: 28px;
}
.coming-soon p {
color: var(--color-text-muted);
max-width: 500px;
margin: 0 auto 16px;
}
.sample-list {
list-style: none;
padding: 0;
margin: 24px auto;
max-width: 300px;
text-align: left;
}
.sample-list li {
padding: 8px 0;
color: var(--color-text);
padding-bottom: 16px;
border-bottom: 1px solid var(--color-border);
}
.sample-list li::before {
content: '→ ';
color: var(--color-link);
.cookbook-info h2 {
margin: 0 0 8px 0;
font-size: 24px;
color: var(--color-text-emphasis);
}
.coming-soon-actions {
margin-top: 32px;
.cookbook-info p {
margin: 0;
color: var(--color-text-muted);
}
.cookbook-languages {
display: flex;
gap: 8px;
flex-shrink: 0;
}
.lang-tab {
padding: 8px 12px;
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
background: var(--color-bg-secondary);
color: var(--color-text);
cursor: pointer;
font-size: 16px;
transition: all var(--transition);
}
.lang-tab:hover {
border-color: var(--color-link);
background: var(--color-bg-tertiary);
}
.lang-tab.active {
border-color: var(--color-link);
background: var(--color-link);
color: white;
}
/* Recipe Grid */
.recipes-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 20px;
}
/* Recipe Card */
.recipe-card {
background: var(--color-card-bg);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-lg);
padding: 24px;
transition: all var(--transition);
}
.recipe-card:hover {
border-color: var(--color-link);
box-shadow: var(--shadow);
}
.recipe-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 12px;
justify-content: center;
margin-bottom: 12px;
}
.recipe-header h3 {
margin: 0;
font-size: 18px;
color: var(--color-text-emphasis);
}
.recipe-langs {
display: flex;
gap: 4px;
flex-shrink: 0;
}
.lang-indicator {
font-size: 14px;
opacity: 0.7;
}
.recipe-description {
color: var(--color-text-muted);
font-size: 14px;
margin: 0 0 16px 0;
line-height: 1.5;
}
.recipe-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 16px;
}
.recipe-tag {
background: var(--color-bg-secondary);
color: var(--color-text-muted);
padding: 4px 10px;
border-radius: 12px;
font-size: 12px;
border: 1px solid var(--color-border);
}
.recipe-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
padding-top: 16px;
border-top: 1px solid var(--color-border);
}
.recipe-actions .btn {
font-size: 13px;
}
.recipe-actions .btn svg {
flex-shrink: 0;
}
.no-variant {
color: var(--color-text-muted);
font-size: 13px;
font-style: italic;
}
/* Empty state */
.empty-state {
text-align: center;
padding: 64px 24px;
background: var(--color-bg-secondary);
border-radius: var(--border-radius-lg);
border: 1px dashed var(--color-border);
}
.empty-state h3 {
margin: 0 0 8px 0;
color: var(--color-text-muted);
}
.empty-state p {
margin: 0;
color: var(--color-text-muted);
}
/* Search highlight */
.search-highlight {
background-color: var(--color-warning);
color: var(--color-text-emphasis);
padding: 0 2px;
border-radius: 2px;
}
/* Responsive */
@media (max-width: 768px) {
.cookbook-header {
flex-direction: column;
}
.recipes-grid {
grid-template-columns: 1fr;
}
.recipe-actions {
flex-direction: column;
}
.recipe-actions .btn {
width: 100%;
justify-content: center;
}
}
</style>
<script>
import '../scripts/pages/samples';
</script>
</BaseLayout>