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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ Run `npm test` to check the hub, redirects, and retained download selection.

## OSS brand snapshot

Workspace (O13) uses separately vendored light and dark glyphs under
`assets/workspace/`, pinned by `provenance.json` to the canonical
[`oss-brand` v0.4.0 release](https://github.com/devslab-kr/oss-brand/releases/tag/v0.4.0).
The existing v0.3.0 snapshot stays immutable. The Workspace card links to its
project Pages documentation and demo, GitHub repository, and npm package.
The canonical brand release is published. Workspace Pages documentation and
demo publication remains a prerequisite for deploying this discovery card.

This hub vendors the public DevsLab OSS brand release rather than consuming it
at runtime. The pinned Q-line snapshot is **v0.3.0**, represented by the immutable
305-file SHA-256 manifest at
Expand Down
1 change: 1 addition & 0 deletions assets/workspace/project-mark-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/workspace/project-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions assets/workspace/provenance.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"registryId": "O13",
"sourceRepository": "https://github.com/devslab-kr/oss-brand",
"sourceCommit": "3870b9ea86f5ccc443d06b49d991592591b110da",
"sourcePullRequest": "https://github.com/devslab-kr/oss-brand/pull/4",
"version": "0.4.0",
"release": "https://github.com/devslab-kr/oss-brand/releases/tag/v0.4.0",
"files": [
{
"path": "project-mark.svg",
"sourcePath": "dist/workspace/glyph-color.svg",
"sha256": "08d9ef467188572abc68de703498412901568e349af21f8dc3583d67378e7069"
},
{
"path": "project-mark-dark.svg",
"sourcePath": "dist/workspace/glyph-dark.svg",
"sha256": "55ab7ada8a88d5b9f621d9a45b972877ae21c082c6aeb80b32b50c02a34a2418"
}
]
}
32 changes: 32 additions & 0 deletions docs/qa/workspace-discovery/verification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Workspace discovery verification

Base: `4d4649d` (hub main). Canonical mark source:
`oss-brand` commit `3870b9ea86f5ccc443d06b49d991592591b110da`.

- Local `npm test`: 45 passed, 0 failed. Publisher, consent, fonts, v0.3.0
snapshot checksums, O01–O13 ordering, all 14 Workspace translations,
destinations, and pinned O13 SVG checksums are included.
- Playwright at `http://127.0.0.1:4281/`: all 14 locales at 390px rendered
Workspace text and four links without horizontal page overflow.
- Screenshots inspected: [English dark desktop](workspace-en-dark-1440.png),
[Korean light mobile](workspace-ko-light-390.png),
[Arabic RTL dark mobile](workspace-ar-dark-390.png). Both canonical marks
loaded and the dark variant was selected in dark mode.
- The first test invocation failed: Windows checkout CRLF conversion caused
a v0.3.0 asset checksum mismatch (expected
`261f93f98c5627e7e06d56e9e61d7580ef8c40bb729076560f856eec71747c88`,
observed `4763c25e8e27d0505f6312cf710627774ed57816df20bd8b8850d3a1eb1cf560`).
Restoring the existing tracked snapshot bytes directly from HEAD corrected
that local checkout issue; no snapshot content change is in this PR.
The initial O13 insertion missed the CRLF HTML section delimiter and the
ordering/link tests failed. Inserting the card inside the final grid fixed
the failure before the 45-test pass and screenshot capture.

This is local evidence. CI, merge, Pages deployment, and production link checks
remain release steps. `/workspace/` and `/workspace/demo/` are served by the
Workspace project Pages site, so they return 404 on the standalone hub local
server. Publish the Workspace docs/demo and canonical brand release before
merging/deploying this hub change. The canonical
[v0.4.0 brand release](https://github.com/devslab-kr/oss-brand/releases/tag/v0.4.0)
is now published; Workspace Pages publication and production verification
remain pending.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 18 additions & 3 deletions index.html

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions sitemap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
<url><loc>https://devslab-kr.github.io/numkey/</loc><priority>0.9</priority></url>
<url><loc>https://devslab-kr.github.io/kokey/</loc><priority>0.9</priority></url>
<url><loc>https://devslab-kr.github.io/vue-date-rail/</loc><priority>0.9</priority></url>
<url><loc>https://devslab-kr.github.io/workspace/</loc><priority>0.9</priority></url>
</urlset>
33 changes: 31 additions & 2 deletions tests/index-brand.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,47 @@ import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import test from 'node:test';
import { fileURLToPath } from 'node:url';
import { runInNewContext } from 'node:vm';
import { createHash } from 'node:crypto';

const root = fileURLToPath(new URL('..', import.meta.url));
const html = () => readFileSync(join(root, 'index.html'), 'utf8');
const ids = Array.from({ length: 12 }, (_, index) => `O${String(index + 1).padStart(2, '0')}`);
const ids = Array.from({ length: 13 }, (_, index) => `O${String(index + 1).padStart(2, '0')}`);

test('renders exactly the O01 through O12 brand cards in registry order', () => {
test('renders exactly the O01 through O13 brand cards in registry order', () => {
const page = html();
const matches = [...page.matchAll(/data-registry-id="(O\d{2})"/g)].map((match) => match[1]);
assert.deepEqual(matches, ids);
for (const id of ids) assert.match(page, new RegExp(`data-registry-id="${id}"[\\s\\S]*?aria-label=`));
});

test('discovers Workspace with all fourteen translations and canonical destinations', () => {
const page = html();
const dictionary = runInNewContext('(' + page.match(/var I18N = (.+);/)[1] + ')');
assert.equal(Object.keys(dictionary).length, 14);
for (const [locale, messages] of Object.entries(dictionary)) {
assert.ok(messages.cards.workspace, `${locale} must translate Workspace`);
for (const adapter of ['Solid', 'React', 'Vue', 'Svelte']) assert.ok(messages.cards.workspace.includes(adapter));
}
const card = page.match(/<article class="card" data-registry-id="O13">([\s\S]*?)<\/article>/)[1];
for (const href of ['/workspace/', '/workspace/demo/', 'https://github.com/devslab-kr/workspace', 'https://www.npmjs.com/package/@devslab/workspace']) {
assert.ok(card.includes(`href="${href}"`), href);
}
assert.match(card, /<h3>Workspace<\/h3>/);
assert.ok(readFileSync(join(root, 'sitemap.xml'), 'utf8').includes('<loc>https://devslab-kr.github.io/workspace/</loc>'));
});

test('preserves the separately pinned canonical Workspace light and dark marks', () => {
const provenance = JSON.parse(readFileSync(join(root, 'assets/workspace/provenance.json'), 'utf8'));
assert.equal(provenance.registryId, 'O13');
assert.match(provenance.sourceCommit, /^[a-f0-9]{40}$/);
for (const file of provenance.files) {
const bytes = readFileSync(join(root, 'assets/workspace', file.path));
assert.equal(createHash('sha256').update(bytes).digest('hex'), file.sha256);
assert.match(bytes.toString(), /data-oss-project="O13"/);
}
});

test('publishes local favicon and complete canonical social metadata once', () => {
const page = html();
for (const name of ['canonical', 'og:title', 'og:description', 'og:url', 'og:image', 'og:image:alt', 'og:image:width', 'og:image:height', 'twitter:card', 'twitter:title', 'twitter:description', 'twitter:image', 'twitter:image:alt']) {
Expand Down
Loading