Skip to content

feat: add Cloudflare Pages HTML frontend#4

Merged
PythonSmall-Q merged 2 commits intomasterfrom
copilot/create-html-frontend
Mar 22, 2026
Merged

feat: add Cloudflare Pages HTML frontend#4
PythonSmall-Q merged 2 commits intomasterfrom
copilot/create-html-frontend

Conversation

Copy link
Contributor

Copilot AI commented Mar 22, 2026

Static landing page for ELXMOJ deployable to Cloudflare Pages with no build step required.

docs/index.html

Single self-contained file — no dependencies, no build tooling.

  • Nav — sticky, frosted-glass, smooth-scroll to all sections
  • Hero — tagline + "立即下载" / "查看源码" CTAs
  • Features — 6-card grid covering userscript injection, update detection, dual channels (stable/preview), settings persistence, cross-platform, self-check
  • Download — fetches releases/latest from GitHub API at runtime; renders per-OS cards (Windows/macOS/Linux) with filename + size; falls back to a GitHub Releases link on API failure
  • How it works — 3-step guide
  • Footer — GitHub, Releases, issues, XMOJ, license

Design matches the existing green palette (#0a7a4f) from src/settings.html.

docs/_headers

Cloudflare Pages security headers applied to /*:

X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()

Deploy

In the Cloudflare Pages dashboard set Build output directory to docs; leave build command empty.


📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com>
Agent-Logs-Url: https://github.com/XMOJ-Script-dev/ELXMOJ/sessions/64320354-8da8-471e-b22d-04461a839d1e
Copilot AI changed the title [WIP] Add HTML frontend for deployment to Cloudflare Pages feat: add Cloudflare Pages HTML frontend Mar 22, 2026
Copilot AI requested a review from PythonSmall-Q March 22, 2026 03:48
@PythonSmall-Q PythonSmall-Q marked this pull request as ready for review March 22, 2026 03:49
Copilot AI review requested due to automatic review settings March 22, 2026 03:49
@PythonSmall-Q PythonSmall-Q merged commit a808d48 into master Mar 22, 2026
5 checks passed
@PythonSmall-Q PythonSmall-Q deleted the copilot/create-html-frontend branch March 22, 2026 03:50
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a static, no-build landing page under docs/ intended for deployment to Cloudflare Pages, including runtime GitHub Releases fetching and baseline security headers.

Changes:

  • Added a self-contained docs/index.html landing page (hero/features/download/how/footer) with runtime download rendering via GitHub Releases API.
  • Added Cloudflare Pages _headers to apply basic security headers site-wide.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
docs/index.html New static landing page with styling + JS that fetches and renders latest release download assets.
docs/_headers Cloudflare Pages security headers applied to all routes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +773 to +776
const links = assets.map(a => `
<a class="dl-link" href="${a.browser_download_url}" target="_blank" rel="noopener">
<span class="dl-name">${formatLabel(a.name)}</span>
<span class="dl-size">${formatBytes(a.size)}</span>
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

The download cards are constructed with template literals and injected via innerHTML, interpolating asset.name / browser_download_url from the GitHub API. This makes the page vulnerable to DOM XSS if any of those fields contain unexpected HTML (even if unlikely). Prefer building DOM nodes and setting textContent/href attributes, or at minimum HTML-escape interpolated text before assigning to innerHTML.

Copilot uses AI. Check for mistakes.
const date = isNaN(rawDate.getTime())
? release.published_at || ""
: rawDate.toLocaleDateString("zh-CN", { year: "numeric", month: "long", day: "numeric" });
versionTag.innerHTML = `最新版本:<a href="${release.html_url}" target="_blank" rel="noopener">${release.tag_name}</a> · 发布于 ${date}`;
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

versionTag.innerHTML = ... interpolates release.tag_name and release.html_url from the GitHub API into HTML. To avoid potential DOM XSS and malformed markup, set textContent for the tag name/date and set the anchor href via DOM APIs instead of using innerHTML.

Suggested change
versionTag.innerHTML = `最新版本:<a href="${release.html_url}" target="_blank" rel="noopener">${release.tag_name}</a> · 发布于 ${date}`;
versionTag.textContent = "最新版本:";
const versionLink = document.createElement("a");
versionLink.href = release.html_url || RELEASES_PAGE;
versionLink.target = "_blank";
versionLink.rel = "noopener";
versionLink.textContent = release.tag_name || "";
versionTag.appendChild(versionLink);
if (date) {
versionTag.appendChild(document.createTextNode(" · 发布于 " + date));
}

Copilot uses AI. Check for mistakes.
Comment on lines +803 to +806
const rawDate = new Date(release.published_at);
const date = isNaN(rawDate.getTime())
? release.published_at || ""
: rawDate.toLocaleDateString("zh-CN", { year: "numeric", month: "long", day: "numeric" });
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

new Date(release.published_at) will produce a valid date (epoch 1970-01-01) when published_at is null/missing (e.g., certain API edge cases), so the isNaN check won't catch it and the UI would show an incorrect publish date. Consider explicitly checking release.published_at truthiness before formatting, and fall back to an empty string or "未知" when absent.

Suggested change
const rawDate = new Date(release.published_at);
const date = isNaN(rawDate.getTime())
? release.published_at || ""
: rawDate.toLocaleDateString("zh-CN", { year: "numeric", month: "long", day: "numeric" });
let date = "未知";
if (release.published_at) {
const rawDate = new Date(release.published_at);
date = isNaN(rawDate.getTime())
? release.published_at
: rawDate.toLocaleDateString("zh-CN", { year: "numeric", month: "long", day: "numeric" });
}

Copilot uses AI. Check for mistakes.
/* ── RESPONSIVE ──────────────────────────────── */
@media (max-width: 600px) {
nav .nav-links {
display: none;
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

On small screens (max-width: 600px) the primary nav links are set to display: none, which removes in-page navigation for mobile users (and for screen readers at that breakpoint). Consider replacing this with a collapsible menu or a horizontally scrollable nav instead of hiding the links entirely.

Suggested change
display: none;
overflow-x: auto;
white-space: nowrap;

Copilot uses AI. Check for mistakes.
<meta property="og:title" content="ELXMOJ — XMOJ 桌面端" />
<meta property="og:description" content="ELXMOJ 是一款基于 Electron 的 XMOJ 桌面客户端,自动注入 XMOJ-Script,支持脚本自动更新、设置持久化。" />
<meta property="og:type" content="website" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

<link rel="icon" ... href="favicon.ico" /> will 404 when deploying with Cloudflare Pages output directory set to docs because docs/ currently doesn't include favicon.ico (it's at repo root). Either copy the icon into docs/ or change the href to a path that will exist in the deployed site.

Suggested change
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />

Copilot uses AI. Check for mistakes.
Comment on lines +732 to +733
if (n.includes("win")) return { os: "win", label: "Windows" };
if (n.includes("mac") || n.includes("darwin")) return { os: "mac", label: "macOS" };
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

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

classifyAsset() checks n.includes("win") before checking for "darwin". Asset names containing "darwin" (common for mac builds) will match the "win" branch and be misclassified as Windows. Reorder the checks (mac/darwin before win) or use stricter matching to avoid substring collisions.

Suggested change
if (n.includes("win")) return { os: "win", label: "Windows" };
if (n.includes("mac") || n.includes("darwin")) return { os: "mac", label: "macOS" };
if (n.includes("mac") || n.includes("darwin")) return { os: "mac", label: "macOS" };
if (n.includes("win")) return { os: "win", label: "Windows" };

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants