Skip to content

Commit ea5d3f4

Browse files
jamesmontemagnoCopilotaaronpowell
authored
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>
1 parent a34c98b commit ea5d3f4

25 files changed

Lines changed: 5482 additions & 26 deletions

File tree

eng/generate-website-data.mjs

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ function formatDisplayName(value) {
9797
.join(" ");
9898
}
9999

100+
function normalizeText(value, fallback = "") {
101+
return typeof value === "string" ? value.trim() : fallback;
102+
}
103+
100104
/**
101105
* Find the latest git-modified date for any file under a directory.
102106
*/
@@ -670,6 +674,76 @@ function generatePluginsData(gitDates) {
670674
/**
671675
* Generate canvas extensions metadata
672676
*/
677+
function getExtensionAssetInfo(extensionDir, relPath, ref) {
678+
const assetDir = path.join(extensionDir, "assets");
679+
680+
if (!fs.existsSync(assetDir)) {
681+
return null;
682+
}
683+
684+
const imageExtensions = new Set([
685+
".png",
686+
".jpg",
687+
".jpeg",
688+
".webp",
689+
".gif",
690+
]);
691+
692+
const preferredNames = [
693+
"preview.png",
694+
"preview.jpg",
695+
"preview.jpeg",
696+
"preview.webp",
697+
"preview.gif",
698+
"screenshot.png",
699+
"screenshot.jpg",
700+
"screenshot.jpeg",
701+
"screenshot.webp",
702+
"screenshot.gif",
703+
"image.png",
704+
"image.jpg",
705+
"image.jpeg",
706+
"image.webp",
707+
"image.gif",
708+
];
709+
710+
for (const candidate of preferredNames) {
711+
const candidatePath = path.join(assetDir, candidate);
712+
if (fs.existsSync(candidatePath)) {
713+
const assetPath = `${relPath}/assets/${candidate}`;
714+
return {
715+
assetPath,
716+
imageUrl: buildRepoImageUrl(assetPath, ref),
717+
};
718+
}
719+
}
720+
721+
const files = fs
722+
.readdirSync(assetDir)
723+
.filter((file) => imageExtensions.has(path.extname(file).toLowerCase()))
724+
.sort((a, b) => a.localeCompare(b));
725+
726+
if (files.length === 0) {
727+
return null;
728+
}
729+
730+
const assetFile = files[0];
731+
const assetPath = `${relPath}/assets/${assetFile}`;
732+
733+
return {
734+
assetPath,
735+
imageUrl: buildRepoImageUrl(assetPath, ref),
736+
};
737+
}
738+
739+
function buildRepoImageUrl(assetPath, ref) {
740+
const encodedAssetPath = assetPath
741+
.split("/")
742+
.map((segment) => encodeURIComponent(segment))
743+
.join("/");
744+
return `https://raw.githubusercontent.com/github/awesome-copilot/${ref}/${encodedAssetPath}`;
745+
}
746+
673747
function generateExtensionsData(gitDates, commitSha) {
674748
const extensions = [];
675749

@@ -679,19 +753,87 @@ function generateExtensionsData(gitDates, commitSha) {
679753

680754
const extensionDirs = fs
681755
.readdirSync(EXTENSIONS_DIR, { withFileTypes: true })
682-
.filter((entry) => entry.isDirectory());
756+
.filter((entry) => {
757+
if (!entry.isDirectory()) return false;
758+
const extensionEntryPoint = path.join(
759+
EXTENSIONS_DIR,
760+
entry.name,
761+
"extension.mjs"
762+
);
763+
return fs.existsSync(extensionEntryPoint);
764+
});
683765

684766
for (const dir of extensionDirs) {
685767
const relPath = `extensions/${dir.name}`;
768+
const assetInfo = getExtensionAssetInfo(
769+
path.join(EXTENSIONS_DIR, dir.name),
770+
relPath,
771+
commitSha
772+
);
773+
686774
extensions.push({
687775
id: dir.name,
688776
name: formatDisplayName(dir.name),
777+
description: "Canvas extension",
689778
path: relPath,
690779
ref: commitSha,
691780
lastUpdated: getDirectoryLastUpdated(gitDates, relPath),
781+
imageUrl: assetInfo?.imageUrl || null,
782+
assetPath: assetInfo?.assetPath || null,
783+
installUrl: `https://github.com/github/awesome-copilot/tree/${commitSha}/${relPath.replace(
784+
/\\/g,
785+
"/"
786+
)}`,
787+
sourceUrl: null,
788+
external: false,
692789
});
693790
}
694791

792+
const externalJsonPath = path.join(EXTENSIONS_DIR, "external.json");
793+
if (fs.existsSync(externalJsonPath)) {
794+
try {
795+
const externalExtensions = JSON.parse(
796+
fs.readFileSync(externalJsonPath, "utf-8")
797+
);
798+
if (Array.isArray(externalExtensions)) {
799+
for (const ext of externalExtensions) {
800+
const name = normalizeText(ext?.name);
801+
const installUrl = normalizeText(ext?.installUrl);
802+
const sourceUrl = normalizeText(ext?.sourceUrl || installUrl);
803+
if (!name || !installUrl) {
804+
continue;
805+
}
806+
807+
const id = normalizeText(ext?.id || name.toLowerCase().replace(/\s+/g, "-"));
808+
let imageUrl = normalizeText(ext?.imageUrl);
809+
let assetPath = null;
810+
const imagePath = normalizeText(ext?.imagePath);
811+
if (!imageUrl && imagePath) {
812+
const repoAssetPath = imagePath.replace(/\\/g, "/");
813+
imageUrl = buildRepoImageUrl(repoAssetPath, commitSha);
814+
assetPath = repoAssetPath;
815+
}
816+
817+
extensions.push({
818+
id,
819+
name,
820+
description: normalizeText(ext?.description, "External canvas extension"),
821+
path: null,
822+
ref: null,
823+
lastUpdated: null,
824+
imageUrl: imageUrl || null,
825+
assetPath,
826+
installUrl,
827+
sourceUrl: sourceUrl || null,
828+
external: true,
829+
});
830+
}
831+
}
832+
} catch (e) {
833+
console.warn(`Failed to parse external extensions: ${e.message}`);
834+
}
835+
}
836+
695837
const sortedExtensions = extensions.sort((a, b) =>
696838
a.name.localeCompare(b.name)
697839
);
70.8 KB
Loading
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Backlog Swipe Triage
2+
3+
Swipe-driven backlog triage canvas for reviewing open issues, applying quick decisions, and starting implementation sessions.
4+
5+
## Assets
6+
7+
- `assets/preview.png` — preferred screenshot path for the triage experience.
8+
- `assets/swipe-canvas-triage.png` — existing reference screenshot kept for compatibility.
651 KB
Loading

0 commit comments

Comments
 (0)