Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
45ef6a9
Drop unreferenced code and stale baseline entries
StarkDroid Nov 3, 2026
94b3ee1
Link the source and Ko-fi from the changelog and the tray
StarkDroid Nov 3, 2026
172ffbe
Make the site free and open source, with download and changelog pages
StarkDroid Nov 3, 2026
410daaa
Rewrite the README around a banner and the open-source story
StarkDroid Nov 3, 2026
6c1c455
Deploy the site to Cloudflare Pages and publish the release feed
StarkDroid Nov 3, 2026
fc2dfcc
Patch the vulnerable Vite and sharp versions
StarkDroid Nov 3, 2026
03bedc0
Rewrite the changelog copy and fix its footer links
StarkDroid Nov 4, 2026
41e94d1
Give the changelog and download pages a way home
StarkDroid Nov 4, 2026
e11be1d
Give Ko-fi the real button and thank people after they download
StarkDroid Nov 4, 2026
f9865d4
Move the support ask off the header and onto the page corner
StarkDroid Nov 4, 2026
f1d4c32
Move every web string into the content module and simplify the downlo…
StarkDroid Nov 4, 2026
fedf192
Offer both Windows installers as peer buttons
StarkDroid Nov 4, 2026
e10c323
Keep the support pill on every page and end the cards at their buttons
StarkDroid Nov 4, 2026
4275ee8
Drop the footer's Ko-fi button, the floating pill is the ask
StarkDroid Nov 4, 2026
b4a38d7
Name the feed URL when the changelog refresh fails
StarkDroid Nov 4, 2026
ab95134
Spell out the Cloudflare go-live details that trip people up
StarkDroid Nov 4, 2026
e9366be
Keep local launch notes and the agent doc out of the repository
StarkDroid Nov 5, 2026
f1568d4
Keep the notch at the top when always-on-top is off
StarkDroid Nov 5, 2026
9632cc3
Keep the notch's frame fixed when always-on-top changes
StarkDroid Nov 5, 2026
591f178
Read the previous changelog through the release asset API
StarkDroid Nov 6, 2026
d48046e
Keep the launch film out of the repository
StarkDroid Nov 6, 2026
bd245e0
Answer a mistyped address with a real 404 page
StarkDroid Nov 6, 2026
e1d6c70
Deploy the site as a static Worker
StarkDroid Nov 6, 2026
58e2493
Count visits with cookieless Cloudflare analytics
StarkDroid Nov 6, 2026
ee577e9
Keep the Google client secret out of the repository
StarkDroid Nov 6, 2026
78162e1
Inject the Google client id as well as its secret
StarkDroid Nov 6, 2026
e6febd2
Build the site from the repository root
StarkDroid Nov 6, 2026
3c95e00
Scroll the page the way the browser does
StarkDroid Nov 7, 2026
b0a5aaa
Keep dev dependencies in the site build
StarkDroid Nov 7, 2026
867a87c
Cut the comments back to the facts
StarkDroid Nov 7, 2026
f2fcafc
Let wrangler preview run for a branch
StarkDroid Nov 7, 2026
a1d444e
Take the last long comments down to two sentences
StarkDroid Nov 7, 2026
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
28 changes: 20 additions & 8 deletions .github/scripts/changelog.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ function previewBlock({ entry, version, bump, previous, released }) {
);
} else {
const from = previous.latest
? ` — a ${bump} bump from v${previous.latest}`
: " — the first release";
? `: a ${bump} bump from v${previous.latest}`
: ": the first release";
lines.push(`Merging publishes **QuickNotch ${version}**${from}.`, "");
if (previous.latest) {
lines.push("<sub>If another pull request merges first, this becomes the next number after it.</sub>", "");
Expand All @@ -212,7 +212,7 @@ function previewBlock({ entry, version, bump, previous, released }) {
lines.push(
`<sub>${previewGuidance(entry, released, previous)}</sub>`,
"",
"<sub>This block is rewritten on every push — the text above it is yours.</sub>",
"<sub>This block is rewritten on every push. The text above it is yours.</sub>",
"",
PREVIEW_END
);
Expand All @@ -223,7 +223,7 @@ function previewBlock({ entry, version, bump, previous, released }) {
function previewGuidance(entry, released, previous) {
if (released || !entry) return "Nothing to publish from this description.";
if (!previous.latest) {
return "The first release is always 2.0.0 — labels steer the bump from the next one.";
return "The first release is always 2.0.0. Labels steer the bump from the next one.";
}
return (
"Bump: `release:major` (or `breaking`) for a major, `release:patch` (or `fix`, `bug`) for a patch," +
Expand Down Expand Up @@ -450,11 +450,23 @@ async function previousFeed() {
if (!managed) return { latest: null, releases: [], source: null };

const asset = managed.assets.find((candidate) => candidate.name === CHANGELOG_ASSET);
const response = await fetch(asset.browser_download_url, {
headers: { "User-Agent": "QuickNotch release planner" }
});

// Read the asset through the API, with the token. `browser_download_url` is
// the public link and answers a private repository with 404, which failed the
// preview on the first run against a release that exists.
const headers = { "User-Agent": "QuickNotch release planner" };
let url = asset.browser_download_url;
if (TOKEN) {
url = asset.url;
headers.Accept = "application/octet-stream";
headers.Authorization = `Bearer ${TOKEN}`;
headers["X-GitHub-Api-Version"] = "2022-11-28";
}
const response = await fetch(url, { headers, redirect: "follow" });
if (!response.ok) {
throw new Error(`previous changelog -> HTTP ${response.status} (${managed.tag_name})`);
throw new Error(
`previous changelog -> HTTP ${response.status} (${managed.tag_name}, ${asset.name})`
);
}

const feed = await response.json();
Expand Down
82 changes: 82 additions & 0 deletions .github/workflows/deploy-web.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Deploy site

# Type-checks and builds the site, then deploys it to the `quicknotch` Worker on
# Cloudflare (quicknotch.app).
#
# The repository's own Cloudflare build is the primary path: it runs on every
# push to `main` from the repository root, with build command `npm run build`
# (which delegates to `web/`) and deploy command `npx wrangler deploy` (which
# reads the root `wrangler.toml`). This job is the fallback for when that
# integration is unavailable, so it deploys only when run by hand.
#
# Two secrets are required for the deploy step:
# CLOUDFLARE_API_TOKEN Workers Scripts: Edit permission
# CLOUDFLARE_ACCOUNT_ID the account that owns the zone
# Without them the build still runs (so a broken site fails CI) and the deploy
# step is skipped with a warning.
on:
push:
branches: [main]
paths:
- "web/**"
- "package.json"
- "wrangler.toml"
- ".github/workflows/deploy-web.yml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: deploy-web
cancel-in-progress: true

jobs:
deploy:
name: Build and deploy
runs-on: ubuntu-latest
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: web/package-lock.json

- name: Install
working-directory: web
run: npm ci --include=dev

- name: Check
working-directory: web
run: npm run check

- name: Build
working-directory: web
run: npm run build

- name: Deploy credentials
id: credentials
shell: bash
run: |
if [ "${GITHUB_EVENT_NAME}" != "workflow_dispatch" ]; then
echo "ready=false" >> "$GITHUB_OUTPUT"
echo "::notice::Push builds only validate the site; the Cloudflare build deploys it."
elif [ -n "${CLOUDFLARE_API_TOKEN}" ] && [ -n "${CLOUDFLARE_ACCOUNT_ID}" ]; then
echo "ready=true" >> "$GITHUB_OUTPUT"
else
echo "ready=false" >> "$GITHUB_OUTPUT"
echo "::warning::Cloudflare secrets are missing; the built site was not deployed."
fi

- name: Deploy to Cloudflare
if: steps.credentials.outputs.ready == 'true'
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: deploy
38 changes: 38 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ jobs:
artifact: QuickNotch-macos-x64
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
# The Calendar flow needs a Google OAuth client, which is not in the
# repository. CI injects both halves; the Gradle task turns them into
# `OAuthConfig`.
env:
QUICKNOTCH_GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_OAUTH_CLIENT_ID }}
QUICKNOTCH_GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_OAUTH_CLIENT_SECRET }}
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -128,6 +134,13 @@ jobs:

- uses: gradle/actions/setup-gradle@v4

- name: Google client
shell: bash
run: |
if [ -z "${QUICKNOTCH_GOOGLE_CLIENT_ID}" ] || [ -z "${QUICKNOTCH_GOOGLE_CLIENT_SECRET}" ]; then
echo "::warning::GOOGLE_OAUTH_CLIENT_ID and/or GOOGLE_OAUTH_CLIENT_SECRET are not set; installers will ship without Calendar sign-in."
fi

- name: Build installer (Windows)
if: matrix.platform == 'windows'
shell: pwsh
Expand Down Expand Up @@ -232,3 +245,28 @@ jobs:
--notes-file release-notes.md \
--latest
fi

- name: Publish the site changelog
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ needs.plan.outputs.version }}
run: |
set -euo pipefail
# The site imports the feed at build time, so the version and the
# history are prerendered. Commit the same JSON into the site source;
# the push redeploys the site on Cloudflare.
git clone --depth 1 "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" site
cp dist/changelog.json site/web/src/lib/data/changelog.json
cd site
if git diff --quiet -- web/src/lib/data/changelog.json; then
echo "Site changelog already current."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add web/src/lib/data/changelog.json
git commit -m "Publish the site changelog for $VERSION"
if ! git push origin HEAD:main; then
echo "::warning::Could not push the site changelog to main; deploy it by hand."
fi
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,16 @@ replay_pid*

# Agent tooling state (local machine memory, never shared)
/.serena/

# Local-only notes: the launch runbook and the agent onboarding doc stay on
# this machine. They are useful here and noise in a public repository.
/agents.md
/launch.md

# The launch film's project and captures. Production material: the repository
# ships the app, the site and the release pipeline, not the 6 MB of stills and
# the rendered MP4 that live beside them.
/video/

# Wrangler login state and local build cache. Machine-specific, never shared.
/.wrangler/
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2025 StarkDroid
Copyright (c) 2025–2026 VelocityApps

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
Loading
Loading