change IDE entry from redir.html? to /latest/

This commit is contained in:
Steven Hugg committed 2026-10-21 12:18:14 +02:00
1 parent 0326b0962b
commit c279cf641e
11 files changed
+88 -13

No files matched your search

+4
View File
@@ -49,6 +49,10 @@ See [extension/CHANGELOG.md](extension/CHANGELOG.md).
- Memory Map: a Modules column shows each object file's slice of every SDCC or cc65 segment (`Segment.modules`; SDCC from the `.rel` sizes in link order, with the remainder as `(libraries)`; cc65 from the ld65 map's module list, library members by name).
- Memory Browser: a symbol label covers only its reported size, and an unsized symbol stops at its segment boundary instead of running into the next segment.
### Website
- Links that open the IDE now point at `https://8bitworkshop.com/latest/`, which the server proxies to the newest build: the badge in a published project's README, the README the VS Code extension writes for a new project, the platform links on the website, and the embedding docs. Old `redir.html` links still work.
### Asset editor
- Undo/redo for edits, including binary files, and reliable undo for palette changes.
-1
View File
@@ -90,7 +90,6 @@ syncprod: distro
@[ "${VERSION}" ] || ( echo ">> No version set at HEAD, tag it first"; exit 1 )
echo Version: $(VERSION)
grep -H "var VERSION" web/redir.html
grep -H "var VERSION" web/projects/projects.js
read
cp config.js $(TMP)
#aws --profile pzp s3 sync --follow-symlinks $(TMP)/ s3://8bitworkshop.com/v$(VERSION)/
+2 -1
View File
@@ -4,6 +4,7 @@
import * as fs from 'fs';
import * as path from 'path';
import { ideLink } from '../../src/common/links';
export interface LauncherOptions {
/** VS Code's executable; ELECTRON_RUN_AS_NODE makes it plain Node */
@@ -63,7 +64,7 @@ export function writeLauncher(binDir: string, opts: LauncherOptions, platform: s
export function projectReadme(name: string, platform: { id: string, name: string, romext?: string }, mainFile: string): string {
var base = path.basename(mainFile, path.extname(mainFile));
var rom = base + (platform.romext || '.bin');
var link = `https://8bitworkshop.com/redir.html?platform=${encodeURIComponent(platform.id)}&file=${encodeURIComponent(mainFile)}`;
var link = ideLink({ platform: platform.id, file: mainFile });
return `# ${name}
A ${platform.name} program made with [8bitworkshop](${link}).
+5
View File
@@ -44,4 +44,9 @@ describe('terminalcli', () => {
assert.ok(readme.includes('8bws build game.c -o game.nes'));
assert.ok(projectReadme('x', { id: 'c64', name: 'C64' }, 'a.c').includes('-o a.bin'));
});
it('links to the IDE at /latest/', () => {
var readme = projectReadme('my-game', { id: 'nes', name: 'NES', romext: '.nes' }, 'game.c');
assert.ok(readme.includes('https://8bitworkshop.com/latest/?platform=nes&file=game.c'), readme);
});
});
+2 -2
View File
@@ -12,7 +12,7 @@
<meta name="theme-color" content="#ffffff">
<meta name="msapplication-navbutton-color" content="#ffffff">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="msapplication-starturl" content="/redir.html">
<meta name="msapplication-starturl" content="/latest/">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=yes">
<link rel="apple-touch-icon" href="/images/icon.png">
<style type="text/css" media="screen">
@@ -125,7 +125,7 @@ body {
</ul>
</li>
<!--
<hr><li><a class="dropdown-item" href="/redir.html">Use Latest Version</a></li>
<hr><li><a class="dropdown-item" href="/latest/">Use Latest Version</a></li>
-->
</ul>
</span>
+31
View File
@@ -0,0 +1,31 @@
/**
* Links into the web IDE.
*
* The IDE lives at /latest/, which the web server proxies to the newest
* build (see web/.htaccess), so these links always open the current IDE.
* The trailing slash matters: /latest without it is a 404.
*/
export const IDE_BASE_URL = 'https://8bitworkshop.com/latest/';
/**
* A link that opens the web IDE, e.g.
* ideLink({platform: 'nes', file: 'game.c'}).
* Parameter values are URL-encoded, and undefined ones are left out.
*/
export function ideLink(params: { [key: string]: string | undefined | null }): string {
var query = Object.keys(params)
.filter(key => params[key] != null)
.map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key] as string))
.join('&');
return query ? IDE_BASE_URL + '?' + query : IDE_BASE_URL;
}
/**
* The README.md a published project gets: a badge that opens the project in
* the IDE, naming the platform, the repository, and the main file.
*/
export function githubReadme(name: string, platform: string, githubURL: string, mainFile: string): string {
var link = ideLink({ platform: platform, githubURL: githubURL, file: mainFile });
return `${encodeURIComponent(name)}\n=====\n\n[Open this project in 8bitworkshop](${link}).\n`;
}
+2 -2
View File
@@ -3,7 +3,7 @@
You can embed the IDE using an IFRAME element:
```html
<iframe src="https://8bitworkshop.com/redir.html?embed=1&..."></iframe>
<iframe src="https://8bitworkshop.com/latest/?embed=1&..."></iframe>
```
Query-string parameters:
@@ -24,6 +24,6 @@ Example using Bootstrap's `embed-responsive` class:
```html
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" loading="lazy"
src="https://8bitworkshop.com/redir.html?embed=1&platform=nes&highlight=&file0_name=testembed.dasm&file0_data=..."></iframe>
src="https://8bitworkshop.com/latest/?embed=1&platform=nes&highlight=&file0_name=testembed.dasm&file0_data=..."></iframe>
</div>
```
+2 -7
View File
@@ -1,4 +1,5 @@
import { githubReadme } from "../common/links";
import { byteArrayToString, byteArrayToUTF8, isProbablyBinary, stringToByteArray } from "../common/util";
import { FileData } from "../common/workertypes";
import { CodeProject, ProjectFilesystem } from "./project";
@@ -30,8 +31,6 @@ export interface GHSession extends GHRepoMetadata {
paths?: string[];
}
const README_md_template = "$NAME\n=====\n\n[Open this project in 8bitworkshop](https://8bitworkshop.com/redir.html?platform=$PLATFORM&githubURL=$GITHUBURL&file=$MAINFILE).\n";
export function getRepos(): { [key: string]: GHRepoMetadata } {
var repos = {};
for (var i = 0; i < localStorage.length; i++) {
@@ -293,11 +292,7 @@ export class GithubService {
.then((_repo) => {
repo = _repo;
// create README.md
var s = README_md_template;
s = s.replace(/\$NAME/g, encodeURIComponent(reponame));
s = s.replace(/\$PLATFORM/g, encodeURIComponent(platform_id));
s = s.replace(/\$GITHUBURL/g, encodeURIComponent(repo.htmlUrl));
s = s.replace(/\$MAINFILE/g, encodeURIComponent(mainPath));
var s = githubReadme(reponame, platform_id, repo.htmlUrl, mainPath);
var config = {
message: '8bitworkshop: updated metadata in README.md',
content: btoa(s)
+10
View File
@@ -107,6 +107,16 @@ describe('8bws CLI', function () {
assert.strictEqual(r.data.platform, 'nes');
assert.ok(r.data.source.endsWith(path.join('src', 'hello.c')), r.data.source);
});
it('should read a README badge that links to /latest/', function () {
var dir = fs.mkdtempSync(path.join(os.tmpdir(), '8bws-dir-'));
fs.mkdirSync(path.join(dir, 'src'));
fs.copyFileSync('presets/nes/hello.c', path.join(dir, 'src', 'hello.c'));
fs.writeFileSync(path.join(dir, 'README.md'), '[x](https://8bitworkshop.com/latest/?platform=nes&githubURL=x&file=hello.c)\n');
var r = cliJSON('build', '--check', dir);
assert.ok(r.success, r.error);
assert.strictEqual(r.data.platform, 'nes');
assert.ok(r.data.source.endsWith(path.join('src', 'hello.c')), r.data.source);
});
});
describe('detect', function () {
+2
View File
@@ -25,6 +25,8 @@ describe('detect', () => {
it('reads the README badge', async () => {
var badge = parseReadmeBadge('Game\n\n[Open](http://8bitworkshop.com/redir.html?platform=vcs&githubURL=x&file=game.dasm).\n');
assert.deepStrictEqual(badge, { platform: 'vcs', mainFile: 'game.dasm' });
var latest = parseReadmeBadge('Game\n\n[Open](https://8bitworkshop.com/latest/?platform=vcs&githubURL=x&file=game.dasm).\n');
assert.deepStrictEqual(latest, { platform: 'vcs', mainFile: 'game.dasm' });
var d = await detectProject(files({ 'README.md': '[x](https://8bitworkshop.com/?platform=nes&file=main.c)', 'main.c': '' }));
assert.strictEqual(d[0].platform, 'nes');
assert.strictEqual(d[0].mainFile, 'main.c');
+28
View File
@@ -0,0 +1,28 @@
import assert from "assert";
import { describe, it } from "mocha";
import { IDE_BASE_URL, githubReadme, ideLink } from "../../src/common/links";
import { parseReadmeBadge } from "../../src/common/detect";
describe('links', () => {
it('points at the IDE under /latest/', () => {
assert.strictEqual(IDE_BASE_URL, 'https://8bitworkshop.com/latest/');
// the trailing slash matters: /latest is a 404
assert.ok(IDE_BASE_URL.endsWith('/latest/'));
});
it('builds IDE links', () => {
assert.strictEqual(ideLink({ platform: 'nes', file: 'game.c' }),
'https://8bitworkshop.com/latest/?platform=nes&file=game.c');
assert.strictEqual(ideLink({ platform: 'nes', file: 'src/my game.c' }),
'https://8bitworkshop.com/latest/?platform=nes&file=src%2Fmy%20game.c');
assert.strictEqual(ideLink({ platform: 'nes', file: undefined }),
'https://8bitworkshop.com/latest/?platform=nes');
assert.strictEqual(ideLink({}), 'https://8bitworkshop.com/latest/');
});
it('writes a README badge the detector can read', () => {
var readme = githubReadme('my-game', 'nes', 'https://github.com/me/my-game', 'game.c');
assert.ok(readme.includes('https://8bitworkshop.com/latest/?platform=nes&githubURL=https%3A%2F%2Fgithub.com%2Fme%2Fmy-game&file=game.c'), readme);
assert.deepStrictEqual(parseReadmeBadge(readme), { platform: 'nes', mainFile: 'game.c' });
});
});