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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ Website source is in [site/](site/); the only loader source is [scans.ps1](scans

The landing page follows the PrintMaster site's Solarized palette, teal accents, wordmark, and panel styling. Standalone navigation is Scans-focused: its brand links home locally, setup and release links stay on the page, and external Scans resources are explicitly labeled. The footer separates Agent/Server downloads and fleet-monitoring links under "More from PrintMaster." Styles and the logo are local to this repository; navigation works without JavaScript, and the layout supports light/dark preferences, keyboard navigation, and reduced motion. Release rendering and copy buttons use [site/releases.js](site/releases.js).

The landing page loads GoatCounter asynchronously using `https://printmaster-scans.goatcounter.com/count`, matching the analytics integration on the main and documentation sites. This website-only integration does not change the PowerShell loader or utility.

The main website can frame `https://scans.printmaster.work/?embed=1` at `/scans/`. [site/embed.js](site/embed.js) hides this site's header/footer and locks the dark palette only after a handshake from the immediate parent at `https://printmaster.work`. Without that handshake (including direct visits and JavaScript disabled), the full standalone site remains visible. Origin- and source-checked messages report content height and anchor positions to the main site's wrapper. External links open at the top level; setup commands retain their canonical standalone URLs. The main site owns its header/footer and clipboard delegation. Deploy this embed support before the main-site wrapper.

The handshake restricts embed-mode activation, not who can frame the public standalone site. GitHub Pages cannot set a custom HTTP `Content-Security-Policy: frame-ancestors` header; a meta tag cannot enforce it. If the domain later uses a configurable edge/server, set `frame-ancestors 'self' https://printmaster.work` there and avoid `X-Frame-Options: DENY`/`SAMEORIGIN`, which would block the cross-origin main-site frame.
Expand Down
2 changes: 2 additions & 0 deletions site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,7 @@ <h2>If something goes wrong</h2>
<div class="footer-bottom"><span>PrintMaster Scans &middot; Standalone Windows utility</span><a href="https://github.com/printmaster-org/scans">Open source on GitHub <span aria-hidden="true">&nearr;</span></a></div>
</div>
</footer>
<script data-goatcounter="https://printmaster-scans.goatcounter.com/count"
async src="//gc.zgo.at/count.js"></script>
</body>
</html>
11 changes: 10 additions & 1 deletion tests/site.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ test('includes local PrintMaster branding, a home link, and the canonical Scans
assert.match(html, /<main id="main">/);
});

test('loads the Scans GoatCounter tracker once and asynchronously', () => {
const html = fs.readFileSync(path.join(__dirname, '..', 'site', 'index.html'), 'utf8');
const trackers = [...html.matchAll(/<script\b[^>]*\bdata-goatcounter="([^"]+)"[^>]*><\/script>/g)];
assert.equal(trackers.length, 1);
assert.equal(trackers[0][1], 'https://printmaster-scans.goatcounter.com/count');
assert.match(trackers[0][0], /\sasync\s/);
assert.match(trackers[0][0], /src="\/\/gc\.zgo\.at\/count\.js"/);
});

test('provides cross-site navigation and working setup anchors without JavaScript', () => {
const html = fs.readFileSync(path.join(__dirname, '..', 'site', 'index.html'), 'utf8');
assert.match(html, /href="https:\/\/printmaster\.work\/downloads"/);
Expand All @@ -45,7 +54,7 @@ test('provides cross-site navigation and working setup anchors without JavaScrip
assert.ok(ids.includes(id), `missing release/copy hook ${id}`);
}
for (const match of html.matchAll(/(?:src|href)="([^"#]+)"/g)) {
if (/^https?:/.test(match[1])) continue;
if (/^(?:https?:)?\/\//.test(match[1])) continue;
if (match[1] === 'releases.json') continue;
const relative = match[1] === 'scans.ps1' || match[1].startsWith('img/') ? match[1] : path.join('site', match[1]);
assert.ok(fs.existsSync(path.join(__dirname, '..', relative)), `missing site asset ${match[1]}`);
Expand Down
Loading