mirror of
https://github.com/github/awesome-copilot.git
synced 2026-07-22 05:14:15 +00:00
Remove website modal and use cookbook detail routes (#2312)
- replace cookbook recipe/example modal views with dedicated detail pages - add legacy #file cookbook hash redirects to canonical routes - remove modal component/runtime and associated CSS and stale page references Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: ca1a64ec-678f-45ac-ba68-33a37717398a
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,19 @@ export interface CookbookRecipeMatch {
|
||||
highlightedName?: string;
|
||||
}
|
||||
|
||||
function buildCookbookRecipeUrl(
|
||||
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 getRecipeResultsCountText(
|
||||
filteredCount: number,
|
||||
totalCount: number
|
||||
@@ -211,27 +224,32 @@ function renderRecipeCard(
|
||||
${
|
||||
variant
|
||||
? `
|
||||
<button class="btn btn-secondary btn-small view-recipe-btn" data-doc="${escapeHtml(
|
||||
variant.doc
|
||||
<a class="btn btn-secondary btn-small" href="${buildCookbookRecipeUrl(
|
||||
cookbook.id,
|
||||
displayLanguage,
|
||||
recipe.id
|
||||
)}">
|
||||
<svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor" aria-hidden="true">
|
||||
<path d="M1 2.75A.75.75 0 0 1 1.75 2h12.5a.75.75 0 0 1 0 1.5H1.75A.75.75 0 0 1 1 2.75zm0 5A.75.75 0 0 1 1.75 7h12.5a.75.75 0 0 1 0 1.5H1.75A.75.75 0 0 1 1 7.75zM1.75 12h12.5a.75.75 0 0 1 0 1.5H1.75a.75.75 0 0 1 0-1.5z"/>
|
||||
<path d="M1 2.75A.75.75 0 0 1 1.75 2h12.5a.75.75 0 0 1 0 1.5H1.75A.75.75 0 0 1 1 2.75zm0 5A.75.75 0 0 1 1.75 7h12.5a.75.75 0 0 1 0 1.5H1.75A.75.75 0 0 1 1 7.75zM1.75 12h12.5a.75.75 0 0 1 0 1.5H1.75a.75.75 0 0 1 0-1.5z"/>
|
||||
</svg>
|
||||
View Recipe
|
||||
</button>
|
||||
</a>
|
||||
${
|
||||
variant.example
|
||||
? `
|
||||
<button class="btn btn-secondary btn-small view-example-btn" data-example="${escapeHtml(
|
||||
variant.example
|
||||
? `
|
||||
<a class="btn btn-secondary btn-small" href="${buildCookbookRecipeUrl(
|
||||
cookbook.id,
|
||||
displayLanguage,
|
||||
recipe.id,
|
||||
variant.example
|
||||
)}">
|
||||
<svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor" aria-hidden="true">
|
||||
<path d="M4.72 3.22a.75.75 0 0 1 1.06 0l3.5 3.5a.75.75 0 0 1 0 1.06l-3.5 3.5a.75.75 0 0 1-1.06-1.06L7.69 7.5 4.72 4.28a.75.75 0 0 1 0-1.06zm6.25 1.06L10.22 5l.75.75-2.25 2.25 2.25 2.25-.75.75-.75-.72L11.97 7.5z"/>
|
||||
</svg>
|
||||
View Example
|
||||
</button>
|
||||
<svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor" aria-hidden="true">
|
||||
<path d="M4.72 3.22a.75.75 0 0 1 1.06 0l3.5 3.5a.75.75 0 0 1 0 1.06l-3.5 3.5a.75.75 0 0 1-1.06-1.06L7.69 7.5 4.72 4.28a.75.75 0 0 1 0-1.06zm6.25 1.06L10.22 5l.75.75-2.25 2.25 2.25 2.25-.75.75-.75-.72L11.97 7.5z"/>
|
||||
</svg>
|
||||
View Example
|
||||
</a>
|
||||
`
|
||||
: ""
|
||||
: ""
|
||||
}
|
||||
<a href="https://github.com/github/awesome-copilot/blob/main/${escapeHtml(
|
||||
variant.doc
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
import { FuzzySearch, type SearchableItem } from "../search";
|
||||
import { fetchData, debounce } from "../utils";
|
||||
import { createChoices, getChoicesValues, type Choices } from "../choices";
|
||||
import { setupModal } from "../modal";
|
||||
import {
|
||||
getRecipeResultsCountText,
|
||||
renderCookbookSectionsHtml,
|
||||
@@ -62,10 +61,10 @@ export async function initSamplesPage(): Promise<void> {
|
||||
search = new FuzzySearch(allRecipes);
|
||||
|
||||
// Setup UI
|
||||
setupModal();
|
||||
handleLegacyCookbookHashLink();
|
||||
setupFilters();
|
||||
setupSearch();
|
||||
setupRecipeListeners();
|
||||
setupInteractionListeners();
|
||||
updateResultsCount();
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize samples page:", error);
|
||||
@@ -259,38 +258,16 @@ function renderCookbooks(): void {
|
||||
});
|
||||
|
||||
// Setup event listeners
|
||||
setupRecipeListeners();
|
||||
setupInteractionListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup event listeners for recipe interactions
|
||||
* Setup event listeners for cookbook interactions
|
||||
*/
|
||||
function setupRecipeListeners(): void {
|
||||
// View recipe buttons
|
||||
document.querySelectorAll(".view-recipe-btn").forEach((btn) => {
|
||||
btn.addEventListener("click", async (e) => {
|
||||
e.stopPropagation();
|
||||
const docPath = (btn as HTMLElement).dataset.doc;
|
||||
if (docPath) {
|
||||
await showRecipeContent(docPath, "recipe");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// View example buttons
|
||||
document.querySelectorAll(".view-example-btn").forEach((btn) => {
|
||||
btn.addEventListener("click", async (e) => {
|
||||
e.stopPropagation();
|
||||
const examplePath = (btn as HTMLElement).dataset.example;
|
||||
if (examplePath) {
|
||||
await showRecipeContent(examplePath, "example");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function setupInteractionListeners(): void {
|
||||
// Language tab clicks
|
||||
document.querySelectorAll(".lang-tab").forEach((tab) => {
|
||||
tab.addEventListener("click", (e) => {
|
||||
tab.addEventListener("click", () => {
|
||||
const langId = (tab as HTMLElement).dataset.lang;
|
||||
if (langId) {
|
||||
selectedLanguage = langId;
|
||||
@@ -307,15 +284,60 @@ function setupRecipeListeners(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Show recipe/example content in modal
|
||||
* Redirect legacy cookbook #file=<path> links to canonical cookbook routes.
|
||||
*/
|
||||
async function showRecipeContent(
|
||||
filePath: string,
|
||||
type: "recipe" | "example"
|
||||
): Promise<void> {
|
||||
// Use existing modal infrastructure
|
||||
const { openFileModal } = await import("../modal");
|
||||
await openFileModal(filePath, type);
|
||||
function handleLegacyCookbookHashLink(): void {
|
||||
const hashMatch = window.location.hash.match(/^#file=(.+)$/);
|
||||
if (!hashMatch) return;
|
||||
|
||||
let filePath: string;
|
||||
try {
|
||||
filePath = decodeURIComponent(hashMatch[1]);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
const parsed = parseCookbookPath(filePath);
|
||||
if (!parsed) return;
|
||||
|
||||
const nextUrl = `/learning-hub/cookbook/${encodeURIComponent(
|
||||
parsed.cookbook
|
||||
)}/${encodeURIComponent(parsed.language)}/${encodeURIComponent(
|
||||
parsed.recipe
|
||||
)}/${parsed.example ? `#file=${encodeURIComponent(filePath)}` : ""}`;
|
||||
|
||||
window.location.replace(nextUrl);
|
||||
}
|
||||
|
||||
function parseCookbookPath(filePath: string): {
|
||||
cookbook: string;
|
||||
language: string;
|
||||
recipe: string;
|
||||
example: boolean;
|
||||
} | null {
|
||||
const docMatch = filePath.match(/^cookbook\/([^/]+)\/([^/]+)\/([^/]+)\.md$/);
|
||||
if (docMatch) {
|
||||
return {
|
||||
cookbook: docMatch[1],
|
||||
language: docMatch[2],
|
||||
recipe: docMatch[3],
|
||||
example: false,
|
||||
};
|
||||
}
|
||||
|
||||
const exampleMatch = filePath.match(
|
||||
/^cookbook\/([^/]+)\/([^/]+)\/recipe\/([^/.]+)\.[^/.]+$/
|
||||
);
|
||||
if (exampleMatch) {
|
||||
return {
|
||||
cookbook: exampleMatch[1],
|
||||
language: exampleMatch[2],
|
||||
recipe: exampleMatch[3],
|
||||
example: true,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user