mirror of
https://github.com/github/awesome-copilot.git
synced 2026-06-25 08:57:43 +00:00
chore: publish from main
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
import { escapeHtml, getGitHubUrl, getLastUpdatedHtml } from "../utils";
|
||||
import {
|
||||
escapeHtml,
|
||||
getGitHubHandle,
|
||||
getGitHubUrl,
|
||||
getLastUpdatedHtml,
|
||||
sanitizeUrl,
|
||||
} from "../utils";
|
||||
import { renderEmptyStateHtml, renderSharedCardHtml } from "./card-render";
|
||||
|
||||
export interface RenderableExtension {
|
||||
@@ -34,6 +40,7 @@ export interface RenderableExtension {
|
||||
installUrl?: string | null;
|
||||
sourceUrl?: string | null;
|
||||
external?: boolean;
|
||||
author?: { name: string; url?: string } | null;
|
||||
}
|
||||
|
||||
export type ExtensionSortOption = "title" | "lastUpdated";
|
||||
@@ -92,8 +99,27 @@ export function renderExtensionsHtml(items: RenderableExtension[]): string {
|
||||
</div>
|
||||
`;
|
||||
|
||||
const authorName = item.author?.name;
|
||||
const authorUrl = item.author?.url;
|
||||
const authorHandle =
|
||||
authorName && authorUrl
|
||||
? getGitHubHandle(authorUrl, authorName)
|
||||
: authorName || "";
|
||||
const authorHtml = authorName
|
||||
? `<span class="resource-tag resource-author">by ${
|
||||
authorUrl
|
||||
? `<a href="${escapeHtml(
|
||||
sanitizeUrl(authorUrl)
|
||||
)}" target="_blank" rel="noopener noreferrer" title="${escapeHtml(
|
||||
authorName
|
||||
)}">${escapeHtml(authorHandle)}</a>`
|
||||
: escapeHtml(authorName)
|
||||
}</span>`
|
||||
: "";
|
||||
|
||||
const metaHtml = `
|
||||
${item.external ? '<span class="resource-tag">External</span>' : ""}
|
||||
${authorHtml}
|
||||
${getLastUpdatedHtml(item.lastUpdated)}
|
||||
`;
|
||||
|
||||
|
||||
@@ -12,9 +12,11 @@ import {
|
||||
copyToClipboard,
|
||||
fetchData,
|
||||
formatRelativeTime,
|
||||
getGitHubHandle,
|
||||
getGitHubUrl,
|
||||
getQueryParam,
|
||||
getQueryParamValues,
|
||||
sanitizeUrl,
|
||||
showToast,
|
||||
updateQueryParams,
|
||||
} from "../utils";
|
||||
@@ -178,6 +180,24 @@ function openDetailsModal(
|
||||
if (item.external) {
|
||||
metaParts.push('<span class="resource-tag">External</span>');
|
||||
}
|
||||
if (item.author?.name) {
|
||||
const authorName = item.author.name;
|
||||
const authorUrl = item.author.url;
|
||||
const authorHandle = authorUrl
|
||||
? getGitHubHandle(authorUrl, authorName)
|
||||
: authorName;
|
||||
metaParts.push(
|
||||
authorUrl
|
||||
? `<span class="resource-author">by <a href="${escapeHtml(
|
||||
sanitizeUrl(authorUrl)
|
||||
)}" target="_blank" rel="noopener noreferrer" title="${escapeHtml(
|
||||
authorName
|
||||
)}">${escapeHtml(authorHandle)}</a></span>`
|
||||
: `<span class="resource-author">by ${escapeHtml(
|
||||
authorName
|
||||
)}</span>`
|
||||
);
|
||||
}
|
||||
if (item.lastUpdated) {
|
||||
metaParts.push(
|
||||
`<span class="last-updated">Updated ${escapeHtml(
|
||||
|
||||
@@ -389,6 +389,31 @@ export function sanitizeUrl(url: string | null | undefined): string {
|
||||
return "#";
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a GitHub @handle from a profile URL
|
||||
* (e.g. "https://github.com/aaronpowell" -> "@aaronpowell").
|
||||
* Falls back to the provided value when the URL is not a github.com profile.
|
||||
*/
|
||||
export function getGitHubHandle(
|
||||
url: string | null | undefined,
|
||||
fallback = ""
|
||||
): string {
|
||||
if (!url) return fallback;
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
const host = parsed.hostname.replace(/^www\./, "");
|
||||
if (host === "github.com") {
|
||||
const segments = parsed.pathname.split("/").filter(Boolean);
|
||||
if (segments.length === 1) {
|
||||
return `@${segments[0]}`;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Invalid URL
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate text with ellipsis
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user