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
4 changes: 2 additions & 2 deletions build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url';

import { Marked } from 'marked';

import { docShell, esc, GITHUB_URL, highlightTokens, SITE_URL } from './src/layout.mjs';
import { docShell, esc, EXT_ATTRS, GITHUB_URL, highlightTokens, SITE_URL } from './src/layout.mjs';
import { renderLanding } from './src/landing.mjs';
import { renderImpressum } from './src/impressum.mjs';
import { renderLicense } from './src/license.mjs';
Expand Down Expand Up @@ -128,7 +128,7 @@ const marked = new Marked({
const text = this.parser.parseInline(tokens);
const t = title ? ` title="${esc(title)}"` : '';
const url = rewriteHref(href);
const ext = /^https?:/.test(url) ? ' rel="external"' : '';
const ext = /^https?:/.test(url) ? EXT_ATTRS : '';
return `<a href="${url}"${t}${ext}>${text}</a>`;
},
code({ text, lang }) {
Expand Down
4 changes: 2 additions & 2 deletions src/impressum.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Legal notice (Impressum) - a fully static, hand-written page. Required to be
// reachable from every page under German law (§5 DDG); linked from the footer.
import { esc, pageShell } from './layout.mjs';
import { esc, EXT_ATTRS, pageShell } from './layout.mjs';

export function renderImpressum({ version }) {
const body = `<main class="section" id="main">
Expand All @@ -22,7 +22,7 @@ Email: <a href="mailto:mentorfilou@gmail.com">mentorfilou@gmail.com</a></p>

<h2>Editorial responsibility</h2>
<address>
Lennard Solterbeck and <a href="https://github.com/orgs/flashtrace/people">the flashtrace team</a>
Lennard Solterbeck and <a href="https://github.com/orgs/flashtrace/people"${EXT_ATTRS} class="ext-mark">the flashtrace team</a>
</address>
</div>
</main>`;
Expand Down
6 changes: 3 additions & 3 deletions src/landing.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// The landing page: hero with a CSS-built IDE mock, how-it-works, features,
// curated interactive examples, install snippets. All static HTML.
import { colorizeReport, examples, heroTerminal } from './examples.mjs';
import { esc, GITHUB_URL, highlightTokens, pageShell } from './layout.mjs';
import { esc, EXT_ATTRS, GITHUB_URL, highlightTokens, pageShell } from './layout.mjs';

// --- hero IDE mock -----------------------------------------------------------

Expand Down Expand Up @@ -215,7 +215,7 @@ npx flashtrace" aria-label="Copy install commands">Copy</button></div>
</div>
<div class="install-card">
<h3>Vendored, zero install</h3>
<p class="install-note">Download <a href="${rawScriptUrl}">dist/flashtrace.mjs</a> into your repository and run it directly.</p>
<p class="install-note">Download <a href="${rawScriptUrl}"${EXT_ATTRS} class="ext-mark">dist/flashtrace.mjs</a> into your repository and run it directly.</p>
<div class="cmd-block"><pre><code>node flashtrace.mjs</code></pre><button class="copy-btn" data-copy="node flashtrace.mjs" aria-label="Copy run command">Copy</button></div>
</div>
</div>
Expand All @@ -233,7 +233,7 @@ export function renderLanding({ version, gitRef }) {
<p class="hero-sub">flashtrace verifies that every requirement in your Markdown specs is covered by the code and tests it demands - with zero runtime dependencies, anywhere Node.js runs.</p>
<div class="hero-ctas">
<a class="btn btn-primary" href="/docs/">Get started</a>
<a class="btn btn-secondary" href="${GITHUB_URL}">View on GitHub</a>
<a class="btn btn-secondary" href="${GITHUB_URL}"${EXT_ATTRS}>View on GitHub</a>
</div>
</div>
${ideMock()}
Expand Down
12 changes: 8 additions & 4 deletions src/layout.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ export const SITE_URL = 'https://flashtrace.github.io';
export const GITHUB_URL = 'https://github.com/flashtrace/flashtrace';
export const DISCUSSIONS_URL = 'https://github.com/flashtrace/flashtrace/discussions';

// Attributes for links leaving the site: open a new tab. Links that should
// also show the "↗" marker add class="ext-mark" (styled in site.css).
export const EXT_ATTRS = ' target="_blank" rel="external noopener"';

export function esc(s) {
return String(s)
.replaceAll('&', '&amp;')
Expand Down Expand Up @@ -49,13 +53,13 @@ function topBar({ version, active, withSidebar }) {
<img src="/logo.svg" alt="" width="22" height="22">
<span class="brand-name">flashtrace</span>
</a>
<a class="version-badge" href="${GITHUB_URL}/releases" title="flashtrace release">${esc(version)}</a>
<a class="version-badge" href="${GITHUB_URL}/releases"${EXT_ATTRS} title="flashtrace release">${esc(version)}</a>
<nav class="topbar-nav" aria-label="Site">
${link('/', 'Home', 'home')}
${link('/docs/', 'Docs', 'docs')}
</nav>
<div class="topbar-actions">
<a class="icon-btn" href="${GITHUB_URL}" aria-label="flashtrace on GitHub">${githubIcon}</a>
<a class="icon-btn" href="${GITHUB_URL}"${EXT_ATTRS} aria-label="flashtrace on GitHub">${githubIcon}</a>
<button class="icon-btn theme-toggle" aria-label="Toggle color theme">
<span class="only-light">${moonIcon}</span><span class="only-dark">${sunIcon}</span>
</button>
Expand All @@ -73,8 +77,8 @@ function footer({ version }) {
</div>
<nav class="footer-links" aria-label="Footer">
<a href="/docs/">Docs</a>
<a href="${GITHUB_URL}">GitHub</a>
<a href="${DISCUSSIONS_URL}">Discussions</a>
<a href="${GITHUB_URL}"${EXT_ATTRS} class="ext-mark">GitHub</a>
<a href="${DISCUSSIONS_URL}"${EXT_ATTRS} class="ext-mark">Discussions</a>
<a href="/license/">License</a>
<a href="/impressum/">Legal Notice</a>
</nav>
Expand Down
4 changes: 2 additions & 2 deletions src/license.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// recognized as Apache 2.0, a GitHub-style summary panel is shown above it;
// an unrecognized license falls back to the raw text alone rather than
// risking a wrong summary.
import { esc, pageShell } from './layout.mjs';
import { esc, EXT_ATTRS, pageShell } from './layout.mjs';

// Octicons (MIT): law, check, x, info.
const lawIcon = `<svg viewBox="0 0 24 24" width="28" height="28" fill="currentColor" aria-hidden="true"><path d="M12.75 2.75V4.5h1.975c.351 0 .694.106.984.303l1.697 1.154c.041.028.09.043.14.043h4.102a.75.75 0 0 1 0 1.5H20.07l3.366 7.68a.749.749 0 0 1-.23.896c-.1.074-.203.143-.31.206a6.296 6.296 0 0 1-.79.399 7.349 7.349 0 0 1-2.856.569 7.343 7.343 0 0 1-2.855-.568 6.205 6.205 0 0 1-.79-.4 3.205 3.205 0 0 1-.307-.202l-.005-.004a.749.749 0 0 1-.23-.896l3.368-7.68h-.886c-.351 0-.694-.106-.984-.303l-1.697-1.154a.246.246 0 0 0-.14-.043H12.75v14.5h4.487a.75.75 0 0 1 0 1.5H6.763a.75.75 0 0 1 0-1.5h4.487V6H9.275a.249.249 0 0 0-.14.043L7.439 7.197c-.29.197-.633.303-.984.303h-.886l3.368 7.68a.75.75 0 0 1-.209.878c-.08.065-.16.126-.31.223a6.077 6.077 0 0 1-.792.433 6.924 6.924 0 0 1-2.876.62 6.913 6.913 0 0 1-2.876-.62 6.077 6.077 0 0 1-.792-.433 3.483 3.483 0 0 1-.309-.221.762.762 0 0 1-.21-.88L3.93 7.5H2.353a.75.75 0 0 1 0-1.5h4.102c.05 0 .099-.015.141-.043l1.695-1.154c.29-.198.634-.303.985-.303h1.974V2.75a.75.75 0 0 1 1.5 0ZM2.193 15.198a5.414 5.414 0 0 0 2.557.635 5.414 5.414 0 0 0 2.557-.635L4.75 9.368Zm14.51-.024c.082.04.174.083.275.126.53.223 1.305.45 2.272.45a5.847 5.847 0 0 0 2.547-.576L19.25 9.367Z"/></svg>`;
Expand Down Expand Up @@ -31,7 +31,7 @@ ${col('Permissions', 'lic-ok', checkIcon, ['Commercial use', 'Modification', 'Di
${col('Limitations', 'lic-no', xIcon, ['Trademark use', 'Liability', 'Warranty'])}
${col('Conditions', 'lic-info', infoIcon, ['License and copyright notice', 'State changes'])}
</div>
<p class="license-summary-note">This is not legal advice. <a href="https://choosealicense.com/licenses/apache-2.0/" rel="external">Learn more about the Apache License 2.0</a>.</p>
<p class="license-summary-note">This is not legal advice. <a href="https://choosealicense.com/licenses/apache-2.0/"${EXT_ATTRS} class="ext-mark">Learn more about the Apache License 2.0</a>.</p>
</section>`;
}

Expand Down
8 changes: 8 additions & 0 deletions src/styles/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ a:hover {
text-decoration: underline;
}

/* Opt-in "↗" marker for external links; the arrow-worthy ones add this class
next to EXT_ATTRS (\FE0E forces text over emoji presentation). */
.ext-mark::after {
content: '\2197\FE0E';
font-size: 0.75em;
margin-left: 0.15em;
}

img {
max-width: 100%;
}
Expand Down