More website tweaks (#977)

* Some layout tweaks

* SSR resource listing pages

Render resource listing pages in Astro for first paint and hydrate client filtering/search behavior on top.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fixing font path

* removing feature plugin reference as we don't track that anymore

* button alignment

* rendering markdown

* Improve skills modal file browsing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Improving the layout of the search/filter section

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Aaron Powell
2026-03-12 11:48:54 +11:00
committed by GitHub
parent 494d6ac783
commit e65c8359b1
32 changed files with 2808 additions and 1245 deletions

View File

@@ -1,3 +1,5 @@
import { getEmbeddedData as getEmbeddedPageData } from "./embedded-data";
/**
* Utility functions for the Awesome Copilot website
*/
@@ -43,6 +45,9 @@ export function getBasePath(): string {
export async function fetchData<T = unknown>(
filename: string
): Promise<T | null> {
const embeddedData = getEmbeddedPageData<T>(filename);
if (embeddedData !== null) return embeddedData;
try {
const basePath = getBasePath();
const response = await fetch(`${basePath}data/${filename}`);
@@ -54,6 +59,17 @@ export async function fetchData<T = unknown>(
}
}
let jsZipPromise: Promise<typeof import("./jszip")> | null = null;
/**
* Lazy-load JSZip only when downloads are requested
*/
export async function loadJSZip() {
jsZipPromise ??= import("./jszip");
const { default: JSZip } = await jsZipPromise;
return JSZip;
}
/**
* Fetch raw file content from GitHub
*/
@@ -209,9 +225,12 @@ export function debounce<T extends (...args: unknown[]) => void>(
* Escape HTML to prevent XSS
*/
export function escapeHtml(text: string): string {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
return text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}
/**
@@ -246,10 +265,8 @@ export function truncate(text: string | undefined, maxLength: number): string {
export function getResourceType(filePath: string): string {
if (filePath.endsWith(".agent.md")) return "agent";
if (filePath.endsWith(".instructions.md")) return "instruction";
if (/(^|\/)skills\//.test(filePath) && filePath.endsWith("SKILL.md"))
return "skill";
if (/(^|\/)hooks\//.test(filePath) && filePath.endsWith("README.md"))
return "hook";
if (/(^|\/)skills\//.test(filePath)) return "skill";
if (/(^|\/)hooks\//.test(filePath)) return "hook";
if (/(^|\/)workflows\//.test(filePath) && filePath.endsWith(".md"))
return "workflow";
// Check for plugin directories (e.g., plugins/<id>, plugins/<id>/)