T45 Website: native captures stand in where a browser cannot run, an OG image, no web notes
This commit is contained in:
1 parent
587e08b5cb
commit
327bdf4b7f
68 files changed
+315
-155
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { all, chapter, chapters, esc, href, storyCount, type Chapter, type Story } from "./data";
|
||||
import { icon } from "./icons";
|
||||
import { isCaptured, native } from "./native";
|
||||
import { preview } from "./preview";
|
||||
|
||||
/** Chapters on the left, a story or the index beside. */
|
||||
@@ -22,7 +23,11 @@ export function components(main: HTMLElement, path: string[]): () => void {
|
||||
}
|
||||
document.title = `${story.title} · ${current.title} · Ely`;
|
||||
body.innerHTML = detail(current, story);
|
||||
return preview(body.querySelector<HTMLElement>(".live")!, current.slug, story.slug, story.title);
|
||||
const live = body.querySelector<HTMLElement>(".live")!;
|
||||
const shots = body.querySelector<HTMLElement>(".native")!;
|
||||
if (isCaptured(current.slug, story.slug)) return native(live, current.slug, story.slug, story.title);
|
||||
const [stopLive, stopShots] = [preview(live, current.slug, story.slug, story.title), native(shots, current.slug, story.slug, story.title)];
|
||||
return () => (stopLive(), stopShots());
|
||||
}
|
||||
|
||||
function sidebar(side: HTMLElement, current?: Chapter, story?: Story): void {
|
||||
@@ -66,6 +71,7 @@ function detail(current: Chapter, story: Story): string {
|
||||
<h1>${esc(story.title)}</h1>
|
||||
<p class="names">${story.components.map(esc).join(" · ")}</p>
|
||||
<div class="live"></div>
|
||||
<div class="native"></div>
|
||||
<nav class="pager" aria-label="More stories">${pager(prev, "prev", "Previous", icon("ArrowLeft"))}${pager(next, "next", "Next", icon("ArrowRight"))}</nav>
|
||||
</article>`;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import shots from "./shots.json";
|
||||
import { esc } from "./data";
|
||||
import { mode, onMode, type Mode } from "./theme";
|
||||
|
||||
const captured = new Set<string>(shots.stories);
|
||||
const windows: Record<string, string[]> = shots.windows;
|
||||
|
||||
/** Whether the site shows this story as a native capture. */
|
||||
export function isCaptured(page: string, story: string): boolean {
|
||||
return captured.has(`${page}/${story}`);
|
||||
}
|
||||
|
||||
const src = (name: string, theme: Mode) => `/shots/${name}-${theme}.jpg`;
|
||||
|
||||
function figure(name: string, alt: string): string {
|
||||
// Captures are at twice the pixels, drawn at their size.
|
||||
return `<img class="shot" data-shot="${name}" srcset="${src(name, mode())} 2x" alt="${esc(alt)}" loading="lazy" />`;
|
||||
}
|
||||
|
||||
/** Draws the story's capture, or the windows it opens, in the site's mode. */
|
||||
export function native(host: HTMLElement, page: string, story: string, title: string): () => void {
|
||||
const key = `${page}/${story}`;
|
||||
if (captured.has(key)) {
|
||||
host.innerHTML = `<p class="label">Native capture · macOS</p>${figure(`${page}--${story}`, `${title}, captured from the native gallery`)}`;
|
||||
} else if (windows[key]) {
|
||||
host.innerHTML = `<p class="label">The windows it opens, natively</p><div class="shots">${windows[key]
|
||||
.map((name) => figure(name, `A window ${title} opens, captured natively`))
|
||||
.join("")}</div>`;
|
||||
} else {
|
||||
return () => {};
|
||||
}
|
||||
return onMode((next) => host.querySelectorAll<HTMLImageElement>("img[data-shot]").forEach((img) => (img.srcset = `${src(img.dataset.shot!, next)} 2x`)));
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"stories": [
|
||||
"files/dragdropfiles",
|
||||
"forms/fileinput-dropzone",
|
||||
"forms/pathinput",
|
||||
"media/imageupload",
|
||||
"shell/dockbadge",
|
||||
"shell/trayicon-traymenu",
|
||||
"shell/windowdragregion",
|
||||
"shell/windowresizeborder",
|
||||
"terminal/terminal-terminaltabs-terminalsplit-terminaltoolbar-shellselector-terminalsearch-terminallink",
|
||||
"theme/themeimporter-syntaxthemes"
|
||||
],
|
||||
"windows": {
|
||||
"shell/splashscreen": [
|
||||
"shell-splash-window"
|
||||
],
|
||||
"shell/aboutdialog": [
|
||||
"shell-about-window"
|
||||
],
|
||||
"shell/multiwindow-manager": [
|
||||
"shell-managed-window"
|
||||
],
|
||||
"shell/miniwindow-compactmode-pictureinpicture": [
|
||||
"shell-mini-window",
|
||||
"shell-pip-window"
|
||||
],
|
||||
"shell/updatedialog": [
|
||||
"shell-update-window"
|
||||
],
|
||||
"shell/crashreporter": [
|
||||
"shell-crash-window"
|
||||
],
|
||||
"navigation/searchpalette-spotlightsearch-quicklauncher": [
|
||||
"navigation-launcher"
|
||||
],
|
||||
"theme/platform-style-iconthemeprovider-vibrancybackground": [
|
||||
"theme-frosted-window"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,10 @@ canvas.iso { position: fixed; inset: 0; width: 100vw; height: 100vh; pointer-eve
|
||||
.stage-skip { position: absolute; left: -9999px; }
|
||||
.stage-skip:focus { position: static; display: inline-block; margin-bottom: 8px; font-size: 14px; color: var(--accent); }
|
||||
|
||||
img.shot { display: block; max-width: 100%; height: auto; margin-top: 12px; }
|
||||
.native .label { margin-top: 48px; }
|
||||
.shots { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 24px; }
|
||||
.shots img.shot { max-width: min(100%, 560px); }
|
||||
.pager { display: flex; justify-content: space-between; gap: 16px; margin-top: 32px; padding-top: 16px; border-top: 1px solid var(--line); }
|
||||
.pager a { display: flex; flex-direction: column; gap: 4px; max-width: 48%; font-size: 14px; line-height: 20px; }
|
||||
.pager a:hover { color: var(--accent); }
|
||||
|
||||
Reference in new issue
Block a user