mirror of
https://github.com/github/awesome-copilot.git
synced 2026-06-18 13:41:26 +00:00
Add canvas previews, external extension links, and release notes showcase (#1987)
* Add extension thumbnails and preview assets Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add clickable extension image preview modal Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update website/src/styles/global.css * Add preview assets for canvas extensions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update canvas extension preview images Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Delete extensions/backlog-swipe-triage/assets/swipe-canvas-triage.png * Support external canvas extensions and add Coffilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add homepage link to GitHub repository Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add release notes showcase canvas extension Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Enhance release notes canvas sourcing and layout Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Aaron Powell <me@aaron-powell.com>
This commit is contained in:
@@ -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("");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user