chore: publish from staged

This commit is contained in:
github-actions[bot]
2026-06-16 23:19:13 +00:00
parent 213aafebf9
commit c937468bfc
25 changed files with 5482 additions and 26 deletions
+11
View File
@@ -36,6 +36,17 @@ const initialItems = sortExtensions(extensionsData.items, 'title');
</div>
</div>
<div class="resource-list" id="resource-list" role="list" set:html={renderExtensionsHtml(initialItems)}></div>
<div id="extension-preview-modal" class="extension-preview-modal hidden" aria-hidden="true">
<div class="extension-preview-dialog" role="dialog" aria-modal="true" aria-labelledby="extension-preview-title">
<div class="extension-preview-header">
<h3 id="extension-preview-title" class="extension-preview-title">Extension preview</h3>
<button id="extension-preview-close" class="btn btn-secondary extension-preview-close" type="button" aria-label="Close preview">Close</button>
</div>
<div class="extension-preview-body">
<img id="extension-preview-image" class="extension-preview-image" src="" alt="" />
</div>
</div>
</div>
<ContributeCTA resourceType="extensions" />
</div>
</div>
+5
View File
@@ -40,6 +40,11 @@ const base = import.meta.env.BASE_URL;
Community-contributed agents, instructions, and skills to enhance your
GitHub Copilot experience
</p>
<p>
<a href="https://github.com/github/awesome-copilot/" target="_blank" rel="noopener noreferrer">
View the Awesome Copilot repository on GitHub
</a>
</p>
</div>
</section>
+54 -23
View File
@@ -3,9 +3,15 @@ import { escapeHtml, getGitHubUrl, getLastUpdatedHtml } from "../utils";
export interface RenderableExtension {
id: string;
name: string;
path: string;
ref: string;
path?: string | null;
ref?: string | null;
description?: string;
lastUpdated?: string | null;
imageUrl?: string | null;
assetPath?: string | null;
installUrl?: string | null;
sourceUrl?: string | null;
external?: boolean;
}
export type ExtensionSortOption = "title" | "lastUpdated";
@@ -36,37 +42,62 @@ export function renderExtensionsHtml(items: RenderableExtension[]): string {
}
return items
.map(
(item) => `
.map((item) => {
const installUrl =
item.installUrl ||
(item.path && item.ref
? `https://github.com/github/awesome-copilot/tree/${item.ref}/${item.path.replace(
/\\/g,
"/"
)}`
: "");
const sourceUrl =
item.sourceUrl || (item.path ? getGitHubUrl(item.path) : "");
return `
<article class="resource-item" role="listitem">
<div class="resource-preview">
<div class="resource-info">
<div class="resource-title">${escapeHtml(item.name)}</div>
<div class="resource-description">Canvas extension</div>
<div class="resource-meta">
${getLastUpdatedHtml(item.lastUpdated)}
</div>
</div>
</div>
${
item.imageUrl
? `<button type="button" class="resource-thumbnail-btn" data-preview-url="${escapeHtml(item.imageUrl)}" data-preview-alt="${escapeHtml(item.name)} preview" aria-label="Open ${escapeHtml(item.name)} preview">
<img class="resource-thumbnail" src="${escapeHtml(item.imageUrl)}" alt="${escapeHtml(item.name)} preview" loading="lazy" />
</button>`
: `<div class="resource-thumbnail resource-thumbnail-placeholder" aria-hidden="true">Canvas</div>`
}
<div class="resource-info">
<div class="resource-title">${escapeHtml(item.name)}</div>
<div class="resource-description">${escapeHtml(
item.description || "Canvas extension"
)}</div>
<div class="resource-meta">
${
item.external
? '<span class="resource-tag">External</span>'
: ""
}
${getLastUpdatedHtml(item.lastUpdated)}
</div>
</div>
</div>
<div class="resource-actions">
<button
class="btn btn-primary btn-small copy-install-url-btn"
data-install-url="${escapeHtml(
`https://github.com/github/awesome-copilot/tree/${item.ref}/${item.path.replace(
/\\/g,
"/"
)}`
)}"
data-install-url="${escapeHtml(installUrl)}"
title="Copy install URL"
${installUrl ? "" : "disabled"}
>
Install
</button>
<a href="${getGitHubUrl(
item.path
)}" class="btn btn-secondary btn-small" target="_blank" rel="noopener noreferrer" title="View on GitHub">GitHub</a>
${
sourceUrl
? `<a href="${escapeHtml(
sourceUrl
)}" class="btn btn-secondary btn-small" target="_blank" rel="noopener noreferrer" title="View source">Source</a>`
: ""
}
</div>
</article>
`
)
`;
})
.join("");
}
+63
View File
@@ -27,6 +27,30 @@ let allItems: Extension[] = [];
let currentSort: ExtensionSortOption = "title";
let actionHandlersReady = false;
function openPreviewModal(url: string, alt: string): void {
const modal = document.getElementById("extension-preview-modal");
const image = document.getElementById("extension-preview-image") as HTMLImageElement | null;
const title = document.getElementById("extension-preview-title");
if (!modal || !image || !title) return;
image.src = url;
image.alt = alt;
title.textContent = alt.replace(/ preview$/i, "");
modal.classList.remove("hidden");
modal.setAttribute("aria-hidden", "false");
document.body.style.overflow = "hidden";
}
function closePreviewModal(): void {
const modal = document.getElementById("extension-preview-modal");
if (!modal) return;
modal.classList.add("hidden");
modal.setAttribute("aria-hidden", "true");
document.body.style.overflow = "";
}
function applySortAndRender(): void {
const countEl = document.getElementById("results-count");
const results = sortExtensions(allItems, currentSort);
@@ -49,6 +73,20 @@ function setupActionHandlers(list: HTMLElement | null): void {
list.addEventListener("click", async (event) => {
const target = event.target as HTMLElement;
const thumbnailButton = target.closest(
".resource-thumbnail-btn"
) as HTMLButtonElement | null;
if (thumbnailButton) {
event.preventDefault();
event.stopPropagation();
openPreviewModal(
thumbnailButton.dataset.previewUrl || "",
thumbnailButton.dataset.previewAlt || "Extension preview"
);
return;
}
const installButton = target.closest(
".copy-install-url-btn"
) as HTMLButtonElement | null;
@@ -57,6 +95,10 @@ function setupActionHandlers(list: HTMLElement | null): void {
event.stopPropagation();
const installUrl = installButton.dataset.installUrl || "";
if (!installUrl) {
showToast("No install URL available for this extension", "error");
return;
}
const success = await copyToClipboard(installUrl);
showToast(
success ? "Install URL copied!" : "Failed to copy install URL",
@@ -64,6 +106,27 @@ function setupActionHandlers(list: HTMLElement | null): void {
);
});
const modal = document.getElementById("extension-preview-modal");
const closeButton = document.getElementById("extension-preview-close");
if (modal) {
modal.addEventListener("click", (event) => {
if (event.target === modal) {
closePreviewModal();
}
});
}
if (closeButton) {
closeButton.addEventListener("click", closePreviewModal);
}
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
closePreviewModal();
}
});
actionHandlersReady = true;
}
+133 -2
View File
@@ -1863,7 +1863,9 @@ body:has(#main-content) {
.resource-preview {
flex: 1;
min-width: 0;
display: block;
display: flex;
align-items: flex-start;
gap: 16px;
width: 100%;
padding: 0;
margin: 0;
@@ -1874,7 +1876,56 @@ body:has(#main-content) {
text-align: left;
cursor: pointer;
}
.resource-thumbnail-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
border: 0;
background: transparent;
cursor: pointer;
flex-shrink: 0;
}
.resource-thumbnail-btn:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 4px;
border-radius: var(--border-radius);
}
.resource-thumbnail {
width: clamp(120px, 24vw, 160px);
aspect-ratio: 16 / 10;
object-fit: cover;
border-radius: var(--border-radius);
border: 1px solid var(--color-glass-border);
background: var(--color-bg-tertiary);
flex-shrink: 0;
box-shadow: var(--shadow);
transition: transform var(--transition), box-shadow var(--transition);
}
.resource-thumbnail-btn:hover .resource-thumbnail,
.resource-thumbnail-btn:focus-visible .resource-thumbnail {
transform: translateY(-1px);
box-shadow: var(--shadow-lg);
}
.resource-thumbnail-placeholder {
display: flex;
align-items: center;
justify-content: center;
color: var(--color-text-muted);
font-size: 13px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
background:
linear-gradient(135deg, rgba(133, 52, 243, 0.18), rgba(254, 76, 37, 0.08)),
var(--color-bg-tertiary);
}
.resource-preview:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 4px;
@@ -1930,6 +1981,72 @@ body:has(#main-content) {
margin: 0px;
}
.extension-preview-modal {
position: fixed;
inset: 0;
z-index: 100000;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
background: rgba(5, 7, 15, 0.72);
backdrop-filter: blur(8px);
}
.extension-preview-modal.hidden {
display: none;
}
.extension-preview-dialog {
width: min(100%, 980px);
max-height: 90vh;
display: flex;
flex-direction: column;
gap: 12px;
background: var(--color-bg-secondary);
border: 1px solid var(--color-glass-border);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-lg);
overflow: hidden;
}
.extension-preview-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 16px 18px 0;
}
.extension-preview-title {
margin: 0;
font-size: 1rem;
color: var(--color-text-emphasis);
}
.extension-preview-close {
border: 1px solid var(--color-glass-border);
background: var(--color-bg-tertiary);
}
.extension-preview-body {
padding: 0 18px 18px;
display: flex;
justify-content: center;
overflow: auto;
}
.extension-preview-image {
display: block;
width: 100%;
max-width: 920px;
max-height: 72vh;
object-fit: contain;
border-radius: var(--border-radius);
border: 1px solid var(--color-glass-border);
background: var(--color-bg-tertiary);
}
/* Last Updated */
.last-updated {
font-size: 12px;
@@ -2081,6 +2198,20 @@ body:has(#main-content) {
align-items: stretch;
}
.resource-preview {
flex-direction: column;
gap: 12px;
}
.resource-thumbnail-btn {
width: 100%;
}
.resource-thumbnail {
width: min(100%, 320px);
max-width: 100%;
}
.resource-actions {
justify-content: flex-end;
}