mirror of
https://github.com/github/awesome-copilot.git
synced 2026-07-17 11:23:27 +00:00
chore: publish from main
This commit is contained in:
@@ -1,242 +0,0 @@
|
|||||||
---
|
|
||||||
// Modal component for viewing file contents
|
|
||||||
---
|
|
||||||
|
|
||||||
<div
|
|
||||||
id="file-modal"
|
|
||||||
class="modal hidden"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
aria-labelledby="modal-title"
|
|
||||||
>
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<div class="modal-header-top">
|
|
||||||
<h3 id="modal-title">File</h3>
|
|
||||||
<div class="modal-actions">
|
|
||||||
<div id="modal-file-switcher" class="modal-file-switcher hidden">
|
|
||||||
<span class="modal-file-switcher-label">File</span>
|
|
||||||
<div id="modal-file-dropdown" class="modal-file-dropdown">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
id="modal-file-button"
|
|
||||||
class="btn btn-secondary modal-file-button"
|
|
||||||
aria-label="Select file to preview"
|
|
||||||
aria-haspopup="menu"
|
|
||||||
aria-expanded="false"
|
|
||||||
>
|
|
||||||
<span id="modal-file-button-label">SKILL.md</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
id="modal-file-toggle"
|
|
||||||
class="btn btn-secondary modal-file-toggle"
|
|
||||||
aria-label="Open file menu"
|
|
||||||
aria-haspopup="menu"
|
|
||||||
aria-expanded="false"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="12"
|
|
||||||
height="12"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M4.427 7.427l3.396 3.396a.25.25 0 00.354 0l3.396-3.396A.25.25 0 0011.396 7H4.604a.25.25 0 00-.177.427z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<div id="modal-file-menu" class="modal-file-menu" role="menu"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
id="install-command-btn"
|
|
||||||
class="btn btn-secondary hidden"
|
|
||||||
aria-label="Copy install command"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<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>
|
|
||||||
<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"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
<span aria-hidden="true">Copy Install</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
id="raw-btn"
|
|
||||||
class="btn btn-secondary hidden"
|
|
||||||
aria-label="View raw file"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M2.3 3.2a.75.75 0 0 1 1.06 0L8 7.94l4.64-4.72a.75.75 0 1 1 1.06 1.06L9.06 8l4.64 4.72a.75.75 0 1 1-1.06 1.06L8 8.06l-4.64 4.72a.75.75 0 1 1-1.06-1.06L6.94 8 2.3 3.28a.75.75 0 0 1 0-1.06z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
<span aria-hidden="true">Raw</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
id="render-btn"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
aria-label="Render file"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M2 2h12v1H2V2zm0 3h12v1H2V5zm0 3h12v1H2V8zm0 3h12v1H2v-1z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
<span aria-hidden="true">Render</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
id="copy-btn"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
aria-label="Copy to clipboard"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<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>
|
|
||||||
<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"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
<span aria-hidden="true">Copy</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
id="download-btn"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
aria-label="Download file"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M7.47 10.78a.75.75 0 0 0 1.06 0l3.75-3.75a.75.75 0 0 0-1.06-1.06L8.75 8.44V1.75a.75.75 0 0 0-1.5 0v6.69L4.78 5.97a.75.75 0 0 0-1.06 1.06l3.75 3.75ZM3.75 13a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
<span aria-hidden="true">Download</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
id="share-btn"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
aria-label="Copy link to clipboard"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M7.775 3.275a.75.75 0 0 0 1.06 1.06l1.25-1.25a2 2 0 1 1 2.83 2.83l-2.5 2.5a2 2 0 0 1-2.83 0 .75.75 0 0 0-1.06 1.06 3.5 3.5 0 0 0 4.95 0l2.5-2.5a3.5 3.5 0 0 0-4.95-4.95l-1.25 1.25zm-.025 5.45a.75.75 0 0 0-1.06-1.06l-1.25 1.25a2 2 0 1 1-2.83-2.83l2.5-2.5a2 2 0 0 1 2.83 0 .75.75 0 0 0 1.06-1.06 3.5 3.5 0 0 0-4.95 0l-2.5 2.5a3.5 3.5 0 0 0 4.95 4.95l1.25-1.25z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
<span aria-hidden="true">Share</span>
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
id="install-dropdown"
|
|
||||||
class="install-dropdown"
|
|
||||||
style="display: none;"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
id="install-btn-main"
|
|
||||||
class="btn btn-primary install-btn-main"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>
|
|
||||||
Install
|
|
||||||
</a>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary install-btn-toggle"
|
|
||||||
aria-label="Install options"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-haspopup="true"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="12"
|
|
||||||
height="12"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M4.427 7.427l3.396 3.396a.25.25 0 00.354 0l3.396-3.396A.25.25 0 0011.396 7H4.604a.25.25 0 00-.177.427z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<div class="install-dropdown-menu" role="menu">
|
|
||||||
<a
|
|
||||||
id="install-vscode"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
role="menuitem"
|
|
||||||
>
|
|
||||||
VS Code
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
id="install-insiders"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
role="menuitem"
|
|
||||||
>
|
|
||||||
VS Code Insiders
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
id="close-modal"
|
|
||||||
class="btn btn-icon"
|
|
||||||
aria-label="Close dialog"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<pre id="modal-content"><code /></pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -42,9 +42,7 @@ const TYPE_PAGES: Record<string, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Resource types that have a dedicated detail page at /<type>/<id>/. Search
|
// Resource types that have a dedicated detail page at /<type>/<id>/. Search
|
||||||
// results for these should deep-link to the canonical detail page rather than
|
// results for these should deep-link to the canonical detail page.
|
||||||
// the listing page with an inert #file= hash (listing pages no longer open a
|
|
||||||
// modal from that hash).
|
|
||||||
const DETAIL_ROUTE_TYPES = new Set([
|
const DETAIL_ROUTE_TYPES = new Set([
|
||||||
"agent",
|
"agent",
|
||||||
"instruction",
|
"instruction",
|
||||||
@@ -118,9 +116,7 @@ export default function pagefindResources(): AstroIntegration {
|
|||||||
|
|
||||||
const url = hasDetailPage
|
const url = hasDetailPage
|
||||||
? `${base}${record.type}/${encodeURIComponent(record.id)}/`
|
? `${base}${record.type}/${encodeURIComponent(record.id)}/`
|
||||||
: `${base}${typePage.slice(1)}#file=${encodeURIComponent(
|
: `${base}${typePage.slice(1)}`;
|
||||||
record.path
|
|
||||||
)}`;
|
|
||||||
const typeLabel = TYPE_LABELS[record.type] || record.type;
|
const typeLabel = TYPE_LABELS[record.type] || record.type;
|
||||||
|
|
||||||
const addResult = await index.addCustomRecord({
|
const addResult = await index.addCustomRecord({
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
|
import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
|
||||||
import Modal from "../components/Modal.astro";
|
|
||||||
import Icon from "../components/Icon.astro";
|
import Icon from "../components/Icon.astro";
|
||||||
import BackToTop from "../components/BackToTop.astro";
|
import BackToTop from "../components/BackToTop.astro";
|
||||||
|
|
||||||
@@ -177,8 +176,6 @@ const base = import.meta.env.BASE_URL;
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Modal />
|
|
||||||
|
|
||||||
<!-- Back to Top Button -->
|
<!-- Back to Top Button -->
|
||||||
<BackToTop />
|
<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 StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
|
||||||
import samplesData from '../../../../public/data/samples.json';
|
import samplesData from '../../../../public/data/samples.json';
|
||||||
import Modal from '../../../components/Modal.astro';
|
|
||||||
import EmbeddedPageData from '../../../components/EmbeddedPageData.astro';
|
import EmbeddedPageData from '../../../components/EmbeddedPageData.astro';
|
||||||
import {
|
import {
|
||||||
getRecipeResultsCountText,
|
getRecipeResultsCountText,
|
||||||
@@ -56,7 +55,6 @@ const languageOptions = Array.from(
|
|||||||
<div id="samples-list" set:html={renderCookbookSectionsHtml(initialRecipeMatches)}></div>
|
<div id="samples-list" set:html={renderCookbookSectionsHtml(initialRecipeMatches)}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Modal />
|
|
||||||
<EmbeddedPageData filename="samples.json" data={samplesData} />
|
<EmbeddedPageData filename="samples.json" data={samplesData} />
|
||||||
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,19 @@ export interface CookbookRecipeMatch {
|
|||||||
highlightedName?: string;
|
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(
|
export function getRecipeResultsCountText(
|
||||||
filteredCount: number,
|
filteredCount: number,
|
||||||
totalCount: number
|
totalCount: number
|
||||||
@@ -211,27 +224,32 @@ function renderRecipeCard(
|
|||||||
${
|
${
|
||||||
variant
|
variant
|
||||||
? `
|
? `
|
||||||
<button class="btn btn-secondary btn-small view-recipe-btn" data-doc="${escapeHtml(
|
<a class="btn btn-secondary btn-small" href="${buildCookbookRecipeUrl(
|
||||||
variant.doc
|
cookbook.id,
|
||||||
|
displayLanguage,
|
||||||
|
recipe.id
|
||||||
)}">
|
)}">
|
||||||
<svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor" aria-hidden="true">
|
<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>
|
</svg>
|
||||||
View Recipe
|
View Recipe
|
||||||
</button>
|
</a>
|
||||||
${
|
${
|
||||||
variant.example
|
variant.example
|
||||||
? `
|
? `
|
||||||
<button class="btn btn-secondary btn-small view-example-btn" data-example="${escapeHtml(
|
<a class="btn btn-secondary btn-small" href="${buildCookbookRecipeUrl(
|
||||||
variant.example
|
cookbook.id,
|
||||||
|
displayLanguage,
|
||||||
|
recipe.id,
|
||||||
|
variant.example
|
||||||
)}">
|
)}">
|
||||||
<svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor" aria-hidden="true">
|
<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"/>
|
<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>
|
</svg>
|
||||||
View Example
|
View Example
|
||||||
</button>
|
</a>
|
||||||
`
|
`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
<a href="https://github.com/github/awesome-copilot/blob/main/${escapeHtml(
|
<a href="https://github.com/github/awesome-copilot/blob/main/${escapeHtml(
|
||||||
variant.doc
|
variant.doc
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
import { FuzzySearch, type SearchableItem } from "../search";
|
import { FuzzySearch, type SearchableItem } from "../search";
|
||||||
import { fetchData, debounce } from "../utils";
|
import { fetchData, debounce } from "../utils";
|
||||||
import { createChoices, getChoicesValues, type Choices } from "../choices";
|
import { createChoices, getChoicesValues, type Choices } from "../choices";
|
||||||
import { setupModal } from "../modal";
|
|
||||||
import {
|
import {
|
||||||
getRecipeResultsCountText,
|
getRecipeResultsCountText,
|
||||||
renderCookbookSectionsHtml,
|
renderCookbookSectionsHtml,
|
||||||
@@ -62,10 +61,10 @@ export async function initSamplesPage(): Promise<void> {
|
|||||||
search = new FuzzySearch(allRecipes);
|
search = new FuzzySearch(allRecipes);
|
||||||
|
|
||||||
// Setup UI
|
// Setup UI
|
||||||
setupModal();
|
handleLegacyCookbookHashLink();
|
||||||
setupFilters();
|
setupFilters();
|
||||||
setupSearch();
|
setupSearch();
|
||||||
setupRecipeListeners();
|
setupInteractionListeners();
|
||||||
updateResultsCount();
|
updateResultsCount();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to initialize samples page:", error);
|
console.error("Failed to initialize samples page:", error);
|
||||||
@@ -259,38 +258,16 @@ function renderCookbooks(): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Setup event listeners
|
// Setup event listeners
|
||||||
setupRecipeListeners();
|
setupInteractionListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup event listeners for recipe interactions
|
* Setup event listeners for cookbook interactions
|
||||||
*/
|
*/
|
||||||
function setupRecipeListeners(): void {
|
function setupInteractionListeners(): 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");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Language tab clicks
|
// Language tab clicks
|
||||||
document.querySelectorAll(".lang-tab").forEach((tab) => {
|
document.querySelectorAll(".lang-tab").forEach((tab) => {
|
||||||
tab.addEventListener("click", (e) => {
|
tab.addEventListener("click", () => {
|
||||||
const langId = (tab as HTMLElement).dataset.lang;
|
const langId = (tab as HTMLElement).dataset.lang;
|
||||||
if (langId) {
|
if (langId) {
|
||||||
selectedLanguage = 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(
|
function handleLegacyCookbookHashLink(): void {
|
||||||
filePath: string,
|
const hashMatch = window.location.hash.match(/^#file=(.+)$/);
|
||||||
type: "recipe" | "example"
|
if (!hashMatch) return;
|
||||||
): Promise<void> {
|
|
||||||
// Use existing modal infrastructure
|
let filePath: string;
|
||||||
const { openFileModal } = await import("../modal");
|
try {
|
||||||
await openFileModal(filePath, type);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -945,436 +945,10 @@ body:has(#main-content) {
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modal */
|
.hidden {
|
||||||
.modal {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1000001;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
background-color: rgba(0, 0, 0, 0.6);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal.hidden, .hidden {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background: var(--color-bg-secondary);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--border-radius-lg);
|
|
||||||
width: 100%;
|
|
||||||
max-width: 800px;
|
|
||||||
max-height: 85vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
box-shadow: var(--shadow-lg);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 14px;
|
|
||||||
padding: 16px 20px;
|
|
||||||
border-bottom: 1px solid var(--color-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header-top {
|
|
||||||
gap: 16px;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header-top h3 {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-emphasis);
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
min-width: 0;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-switcher {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-switcher.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-switcher label {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.04em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-switcher-label {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.04em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-dropdown {
|
|
||||||
position: relative;
|
|
||||||
display: inline-flex;
|
|
||||||
min-width: min(320px, 100%);
|
|
||||||
max-width: min(420px, 100%);
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-button {
|
|
||||||
justify-content: flex-start;
|
|
||||||
min-width: 0;
|
|
||||||
flex: 1;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
border-right: 1px solid var(--color-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-button span {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-toggle {
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
padding: 10px;
|
|
||||||
min-width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-toggle svg {
|
|
||||||
transition: transform var(--transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-dropdown.open .modal-file-toggle svg {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-menu {
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
margin-top: 4px;
|
|
||||||
background: var(--color-bg-secondary);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
box-shadow: var(--shadow-md);
|
|
||||||
z-index: 1000;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transform: translateY(-8px);
|
|
||||||
transition: all var(--transition);
|
|
||||||
max-height: 280px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-dropdown.open .modal-file-menu {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-menu-item {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
padding: 10px 14px;
|
|
||||||
text-align: left;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
color: var(--color-text);
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background var(--transition);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-menu-item:hover,
|
|
||||||
.modal-file-menu-item:focus-visible {
|
|
||||||
background: var(--color-bg-tertiary);
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-menu-item.active {
|
|
||||||
background: color-mix(in srgb, var(--color-accent) 14%, transparent);
|
|
||||||
color: var(--color-text-emphasis);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-menu-item:first-child {
|
|
||||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-file-menu-item:last-child {
|
|
||||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-actions {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-actions button, .modal-actions div {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
flex: 1;
|
|
||||||
overflow: auto;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body pre {
|
|
||||||
margin: 0;
|
|
||||||
padding: 24px;
|
|
||||||
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 1.6;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-wrap: break-word;
|
|
||||||
background: var(--color-bg);
|
|
||||||
color: var(--color-text);
|
|
||||||
min-height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal.details-mode .modal-content {
|
|
||||||
max-width: 980px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal.details-mode #modal-file-switcher,
|
|
||||||
.modal.details-mode #install-command-btn,
|
|
||||||
.modal.details-mode #copy-btn,
|
|
||||||
.modal.details-mode #download-btn,
|
|
||||||
.modal.details-mode #share-btn,
|
|
||||||
.modal.details-mode #render-btn,
|
|
||||||
.modal.details-mode #raw-btn,
|
|
||||||
.modal.details-mode #install-dropdown {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal.details-mode .modal-card-details {
|
|
||||||
padding: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal.details-mode .modal-card-details .resource-details-body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-rendered-content {
|
|
||||||
padding: 24px;
|
|
||||||
min-height: 200px;
|
|
||||||
background: var(--color-bg);
|
|
||||||
color: var(--color-text);
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-rendered-content > :first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-rendered-content > :last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-code-content .shiki {
|
|
||||||
margin: 0 !important;
|
|
||||||
padding: 24px;
|
|
||||||
min-height: 200px;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Collection Modal View */
|
|
||||||
.collection-view {
|
|
||||||
padding: 20px 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-description {
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--color-text);
|
|
||||||
margin-bottom: 16px;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-tags {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 6px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-items-header {
|
|
||||||
padding: 10px 0;
|
|
||||||
border-bottom: 1px solid var(--color-border);
|
|
||||||
margin-bottom: 8px;
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-items-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 10px 12px;
|
|
||||||
background: var(--color-bg);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all var(--transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-item:hover {
|
|
||||||
background: var(--color-bg-tertiary);
|
|
||||||
border-color: var(--color-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-item-icon {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-item-icon svg {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-item-info {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-item-name {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text);
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-item-usage {
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
margin-top: 2px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-item-type {
|
|
||||||
font-size: 11px;
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
background: var(--color-bg-tertiary);
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 4px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-loading,
|
|
||||||
.collection-error {
|
|
||||||
padding: 40px;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.collection-error {
|
|
||||||
color: var(--color-error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* External plugin badge */
|
|
||||||
.resource-tag-external {
|
|
||||||
background: var(--color-accent);
|
|
||||||
color: var(--color-bg);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* External plugin modal metadata */
|
|
||||||
.external-plugin-metadata {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
padding: 12px 16px;
|
|
||||||
background: var(--color-bg-tertiary);
|
|
||||||
border-radius: var(--border-radius);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.external-plugin-meta-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
gap: 12px;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.external-plugin-meta-label {
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
font-weight: 500;
|
|
||||||
min-width: 80px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.external-plugin-meta-value {
|
|
||||||
color: var(--color-text);
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.external-plugin-meta-value a {
|
|
||||||
color: var(--color-accent);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.external-plugin-meta-value a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.external-plugin-cta {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.external-plugin-repo-btn {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.external-plugin-note {
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
font-style: italic;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Page Layouts */
|
/* Page Layouts */
|
||||||
.page-header {
|
.page-header {
|
||||||
padding: 40px 0 28px;
|
padding: 40px 0 28px;
|
||||||
@@ -3496,34 +3070,6 @@ header .theme-toggle-container {
|
|||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================
|
|
||||||
MODAL ENTRANCE/EXIT ANIMATION
|
|
||||||
============================================ */
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal.visible {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
transform: scale(0.95) translateY(10px);
|
|
||||||
opacity: 0;
|
|
||||||
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal.visible .modal-content {
|
|
||||||
transform: scale(1) translateY(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
PAGE HEADER ENHANCEMENT
|
PAGE HEADER ENHANCEMENT
|
||||||
============================================ */
|
============================================ */
|
||||||
|
|||||||
Reference in New Issue
Block a user