website: nxdns.sh on astro and starlight, with the docs and 0.0.24 screenshots
This commit is contained in:
@@ -65,7 +65,7 @@ npm ci
|
||||
npx playwright install chromium
|
||||
```
|
||||
|
||||
Then shoot all five pages in light and dark at 1440×900, 2× scale, and build a contact sheet to review them:
|
||||
Then shoot all five pages in light and dark, at 1440×900 and 2× scale for desktops and at 390×844 and 3× scale for phones, and build a contact sheet to review them:
|
||||
|
||||
```sh
|
||||
node gen/shoot.mjs shots "$(./db.sh /gen/blocked_query_id.py /data)"
|
||||
|
||||
@@ -13,14 +13,15 @@ PAGES = [
|
||||
]
|
||||
|
||||
|
||||
def img(name, scheme):
|
||||
with open(f"{SHOTS}/{name}-{scheme}.png", "rb") as f:
|
||||
def img(name, scheme, form=""):
|
||||
with open(f"{SHOTS}/{name}-{scheme}{form}.png", "rb") as f:
|
||||
data = base64.b64encode(f.read()).decode()
|
||||
return f'<figure><img alt="{name} {scheme}" src="data:image/png;base64,{data}"><figcaption>{scheme}</figcaption></figure>'
|
||||
return f'<figure><img alt="{name} {scheme}{form}" src="data:image/png;base64,{data}"><figcaption>{scheme}{form}</figcaption></figure>'
|
||||
|
||||
|
||||
rows = "\n".join(
|
||||
f'<section><h2>{html.escape(caption)}</h2><div class="pair">{img(name, "light")}{img(name, "dark")}</div></section>'
|
||||
f'<section><h2>{html.escape(caption)}</h2><div class="pair">{img(name, "light")}{img(name, "dark")}</div>'
|
||||
f'<div class="pair phone">{img(name, "light", "-phone")}{img(name, "dark", "-phone")}</div></section>'
|
||||
for name, caption in PAGES
|
||||
)
|
||||
page = f"""<!doctype html>
|
||||
@@ -33,12 +34,13 @@ body {{ margin: 0; padding: 24px 16px; background: var(--bg); color: var(--fg);
|
||||
h1 {{ font-size: 20px; margin: 0 0 24px; }}
|
||||
h2 {{ font-size: 15px; font-weight: 500; margin: 32px 0 12px; }}
|
||||
.pair {{ display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }}
|
||||
.phone {{ grid-template-columns: repeat(2, minmax(0, 300px)); margin-top: 16px; }}
|
||||
@media (max-width: 800px) {{ .pair {{ grid-template-columns: 1fr; }} }}
|
||||
figure {{ margin: 0; }}
|
||||
img {{ width: 100%; height: auto; border: 1px solid var(--line); border-radius: 6px; display: block; }}
|
||||
figcaption {{ color: var(--muted); font-size: 13px; margin-top: 4px; }}
|
||||
</style></head>
|
||||
<body><h1>nxdns admin — marketing screenshots (1440×900 @2x)</h1>
|
||||
<body><h1>nxdns admin — marketing screenshots (1440×900 @2x, phone 390×844 @3x)</h1>
|
||||
{rows}
|
||||
</body></html>
|
||||
"""
|
||||
|
||||
@@ -21,11 +21,17 @@ async function settle(page) {
|
||||
await page.waitForTimeout(2500);
|
||||
}
|
||||
|
||||
// The phone form is 390px wide, where the admin UI switches to its drawer layout, and touch-only, so
|
||||
// no hover state is drawn.
|
||||
const FORMS = [
|
||||
["", { viewport: { width: 1440, height: 900 }, deviceScaleFactor: 2 }],
|
||||
["-phone", { viewport: { width: 390, height: 844 }, deviceScaleFactor: 3, isMobile: true, hasTouch: true }],
|
||||
];
|
||||
|
||||
const browser = await chromium.launch();
|
||||
for (const scheme of ["light", "dark"]) {
|
||||
for (const [suffix, form] of FORMS) for (const scheme of ["light", "dark"]) {
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1440, height: 900 },
|
||||
deviceScaleFactor: 2,
|
||||
...form,
|
||||
colorScheme: scheme,
|
||||
timezoneId: "Europe/Paris",
|
||||
locale: "en-GB",
|
||||
@@ -38,10 +44,15 @@ for (const scheme of ["light", "dark"]) {
|
||||
await page.waitForURL((u) => !u.pathname.startsWith("/login"));
|
||||
for (const [name, path] of PAGES) {
|
||||
await page.goto(BASE + path);
|
||||
await page.mouse.move(1430, 890);
|
||||
if (!form.hasTouch) await page.mouse.move(1430, 890);
|
||||
await settle(page);
|
||||
if (name === "activity") await page.waitForTimeout(8000);
|
||||
const file = `${outDir}/${name}-${scheme}.png`;
|
||||
// A phone stacks the health cards and filters above the episodes, so the first screen shows none.
|
||||
if (name === "diagnostics" && form.hasTouch) {
|
||||
await page.getByRole("heading", { name: "Active" }).evaluate((h) => h.scrollIntoView({ block: "start" }));
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
const file = `${outDir}/${name}-${scheme}${suffix}.png`;
|
||||
await page.screenshot({ path: file });
|
||||
console.log(file);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# docker twice. The data lives in a named volume so no file in this tree is owned by that uid.
|
||||
set -eu
|
||||
DEMO=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
IMAGE=${NXDNS_IMAGE:-git.mial.net/mokhtar/nxdns:0.0.21}
|
||||
IMAGE=${NXDNS_IMAGE:-git.mial.net/mokhtar/nxdns:0.0.24}
|
||||
docker network inspect nxdemo-lan >/dev/null 2>&1 ||
|
||||
docker network create --driver bridge --subnet 192.168.50.0/24 --gateway 192.168.50.1 nxdemo-lan
|
||||
if ! docker volume inspect nxdemo-data >/dev/null 2>&1; then
|
||||
|
||||
Reference in New Issue
Block a user