Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 29 additions & 20 deletions .github/workflows/docs-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,19 @@ jobs:
mkdir -p staging/$PR_NUMBER
rm -rf staging/$PR_NUMBER/*
cp -r /tmp/site-temp/. staging/$PR_NUMBER/

# Copy 404.html to the gh-pages root so SPA redirects work for staging
# paths (GitHub Pages only serves the root-level 404.html for missing paths)
cp /tmp/site-temp/404.html 404.html

Comment on lines +185 to +188
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The staging deploy step copies the built 404.html into the gh-pages root. This means every staging deployment can overwrite the root 404 used by the main docs site, temporarily changing production 404 behavior until the next main deploy. Consider avoiding mutating the root 404 on staging runs (or only doing it when the staged 404 is identical to the current root file), so staging previews don't affect the main site.

Copilot uses AI. Check for mistakes.
rm -rf /tmp/site-temp

# Ensure .nojekyll exists at root so _framework is served
touch .nojekyll

git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .nojekyll staging/$PR_NUMBER
git add .nojekyll 404.html staging/$PR_NUMBER
if ! git diff --cached --quiet; then
git commit -m "Deploy staging docs for PR #$PR_NUMBER"
git push origin gh-pages
Expand All @@ -199,7 +204,7 @@ jobs:
comment:
runs-on: ubuntu-latest
needs: [build, deploy]
if: needs.build.outputs.is_staging == 'true' && (github.event.action == 'opened' || github.event.action == 'reopened')
if: needs.build.outputs.is_staging == 'true' && (github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize')
permissions:
pull-requests: write
steps:
Expand All @@ -211,21 +216,6 @@ jobs:
const stagingUrl = `https://mono.github.io/SkiaSharp.Extended/staging/${prNumber}/`;
const sampleUrl = `https://mono.github.io/SkiaSharp.Extended/staging/${prNumber}/sample/`;

// Only comment once; check for an existing bot comment to avoid duplicates on reopen
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const botComment = comments.data.find(c =>
c.user.type === 'Bot' &&
c.body.includes('Documentation Preview')
);
if (botComment) {
console.log('Bot comment already exists, skipping.');
return;
}

const commentBody = [
'📖 **Documentation Preview**',
'',
Expand All @@ -241,9 +231,28 @@ jobs:
'*This comment is automatically updated by the documentation staging workflow.*'
].join('\n');

await github.rest.issues.createComment({
// Update existing bot comment if present, otherwise create a new one
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: commentBody
issue_number: prNumber
});
Comment on lines +235 to 239
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

github.rest.issues.listComments is called without pagination settings. If a PR has >30 comments, the existing workflow bot comment may not be returned and the job will create a duplicate instead of updating the original. Use pagination (e.g., per_page: 100 and/or github.paginate) when searching for the existing bot comment.

Copilot uses AI. Check for mistakes.
const botComment = comments.data.find(c =>
c.user.type === 'Bot' &&
c.body.includes('Documentation Preview')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: commentBody
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: commentBody
});
}
33 changes: 33 additions & 0 deletions docs/404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>SkiaSharp Extended - Page Not Found</title>
<script>
// GitHub Pages SPA redirect: when a user navigates directly to a Blazor sample
// sub-page, GitHub Pages serves this 404.html. If the path is under a /sample/
// segment, redirect to that sample's index.html with the path encoded in the
// query string so that the Blazor router can restore the correct route.
(function () {
var l = window.location;
var pathParts = l.pathname.split('/');
var sampleIdx = pathParts.indexOf('sample');
if (sampleIdx !== -1 && sampleIdx < pathParts.length - 1 && pathParts[sampleIdx + 1] !== '') {
var basePath = pathParts.slice(0, sampleIdx + 1).join('/');
var remaining = pathParts.slice(sampleIdx + 1).join('/').replace(/&/g, '~and~');
l.replace(
l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
basePath + '/?/' + remaining +
(l.search ? '&' + l.search.slice(1).replace(/&/g, '~and~') : '') +
l.hash
);
}
})();
</script>
</head>
<body>
<h1>Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<p><a href="/SkiaSharp.Extended/">Go to the documentation</a></p>
Comment on lines +25 to +31
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-sample fallback link is hardcoded to /SkiaSharp.Extended/. On staging URLs (e.g. /SkiaSharp.Extended/staging/<pr>/...), this sends users to the main docs instead of the staging preview. Consider making this link relative (e.g. to the current site root) or computing the correct base path from window.location.pathname so it works consistently in both main and staging.

Suggested change
})();
</script>
</head>
<body>
<h1>Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<p><a href="/SkiaSharp.Extended/">Go to the documentation</a></p>
// Compute the base documentation path so the fallback link works on both
// the main site (/SkiaSharp.Extended/...) and staging URLs
// (/SkiaSharp.Extended/staging/<pr>/...).
function getDocsBasePath() {
var parts = l.pathname.split('/');
var extendedIndex = parts.indexOf('SkiaSharp.Extended');
if (extendedIndex === -1) {
// Fallback if the expected segment is not present.
return '/';
}
// Start with /SkiaSharp.Extended/
var endIndex = extendedIndex + 2; // include 'SkiaSharp.Extended'
// If this is a staging URL like /SkiaSharp.Extended/staging/<pr>/...,
// include the staging and PR segments as part of the base path.
if (parts[extendedIndex + 1] === 'staging' && parts.length > extendedIndex + 2) {
endIndex = extendedIndex + 3;
}
var base = parts.slice(0, endIndex).join('/');
if (base === '') {
base = '/';
}
// Ensure a trailing slash for consistency.
if (base.charAt(base.length - 1) !== '/') {
base += '/';
}
return base;
}
window.addEventListener('DOMContentLoaded', function () {
var link = document.getElementById('docs-link');
if (!link) {
return;
}
link.href = getDocsBasePath();
});
})();
</script>
</head>
<body>
<h1>Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<p><a id="docs-link" href="#">Go to the documentation</a></p>

Copilot uses AI. Check for mistakes.
</body>
</html>
3 changes: 2 additions & 1 deletion docs/docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"resource": [
{
"files": [
"images/**"
"images/**",
"404.html"
]
}
],
Expand Down