Files
awesome-copilot/website/src/scripts/pages/extensions-render.ts
T
James Montemagno fb1b124ed7 Fix canvas extension install links (#2109)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Aaron Powell <me@aaron-powell.com>
2026-06-24 12:08:25 +10:00

134 lines
3.7 KiB
TypeScript

import { escapeHtml, getGitHubUrl, getLastUpdatedHtml } from "../utils";
import { renderEmptyStateHtml, renderSharedCardHtml } from "./card-render";
export interface RenderableExtension {
id: string;
canvasId?: string;
extensionId?: string;
extensionName?: string;
name: string;
path?: string | null;
ref?: string | null;
version?: string | null;
description?: string;
lastUpdated?: string | null;
keywords?: string[];
screenshots?: {
icon?: {
path?: string | null;
type?: string | null;
} | null;
gallery?:
| {
path?: string | null;
type?: string | null;
}
| Array<{
path?: string | null;
type?: string | null;
}>
| null;
} | null;
imageUrl?: string | null;
assetPath?: string | null;
installUrl?: string | null;
sourceUrl?: string | null;
external?: boolean;
}
export type ExtensionSortOption = "title" | "lastUpdated";
export function sortExtensions<T extends RenderableExtension>(
items: T[],
sort: ExtensionSortOption
): T[] {
return [...items].sort((a, b) => {
if (sort === "lastUpdated") {
const dateA = a.lastUpdated ? new Date(a.lastUpdated).getTime() : 0;
const dateB = b.lastUpdated ? new Date(b.lastUpdated).getTime() : 0;
return dateB - dateA;
}
return a.name.localeCompare(b.name);
});
}
export function renderExtensionsHtml(items: RenderableExtension[]): string {
if (items.length === 0) {
return renderEmptyStateHtml(
"No extensions found",
"No canvas extensions are available right now."
);
}
return items
.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) : "");
const previewMediaHtml = item.imageUrl
? `<div class="resource-thumbnail-btn" data-extension-id="${escapeHtml(item.id)}" aria-hidden="true">
<img class="resource-thumbnail" src="${escapeHtml(item.imageUrl)}" alt="${escapeHtml(item.name)} preview" loading="lazy" />
</div>`
: `<div class="resource-thumbnail resource-thumbnail-placeholder" aria-hidden="true">Canvas</div>`;
const infoExtraHtml = `
<div class="resource-keywords">
${
item.keywords && item.keywords.length > 0
? item.keywords
.map((kw) => `<span class="keyword-tag">${escapeHtml(kw)}</span>`)
.join("")
: ""
}
</div>
`;
const metaHtml = `
${item.external ? '<span class="resource-tag">External</span>' : ""}
${getLastUpdatedHtml(item.lastUpdated)}
`;
const actionsHtml = `
<button
class="btn btn-primary btn-small copy-install-url-btn"
data-install-url="${escapeHtml(installUrl)}"
title="Copy install URL"
${installUrl ? "" : "disabled"}
>
Copy URL
</button>
${
sourceUrl
? `<a href="${escapeHtml(
sourceUrl
)}" class="btn btn-secondary btn-small" target="_blank" rel="noopener noreferrer" title="View source">Source</a>`
: ""
}
`;
return renderSharedCardHtml({
title: item.name,
description: item.description || "Canvas extension",
previewMediaHtml,
infoExtraHtml,
metaHtml,
actionsHtml,
tabIndex: 0,
articleAttributes: {
id: item.id,
"data-extension-id": item.id,
},
});
})
.join("");
}