generated from wiz4apps/templates.OnlineShop
Replace the text brand in the header and footer with the logo the source site publishes for its footer (637x220 PNG, BRAND.logoSourceUrl): - src/store/constants.ts: add BRAND (source URL, local path, dimensions). - scripts/fetch-logo.ts: mirror it into public/images/brand/logo_footer.png (idempotent, --force to refresh); `pnpm fetch:logo` runs it standalone. - scripts/dev-server.ts: ensure the logo at boot, non-fatal on failure. - public/index.html: <img class="brand__logo"> in the header (the wordmark is dark on the light header) and <img class="footer__logo"> in the footer, on a white plate because the footer is dark. - public/styles.css: logo sizing (30px / 40px from 768px) + the footer plate.
78 lines
3.1 KiB
TypeScript
78 lines
3.1 KiB
TypeScript
import { mkdir, stat, writeFile } from 'node:fs/promises';
|
||
import { dirname, join, resolve } from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
import { BRAND } from '../src/store/constants';
|
||
|
||
/**
|
||
* Mirror the store wordmark into public/images/brand/logo_footer.png.
|
||
*
|
||
* Source: the logo the site publishes for its footer (BRAND.logoSourceUrl, 637×220 PNG).
|
||
* The storefront ships that file instead of hotlinking la-rose.by — public/index.html
|
||
* points at BRAND.logoLocalPath — and this script keeps the local copy on disk.
|
||
*
|
||
* Idempotent: an existing non-empty file is kept; pass `--force` to re-download it
|
||
* (the source is a static theme asset, so a plain re-run is a no-op).
|
||
*
|
||
* pnpm fetch:logo # download only when missing
|
||
* pnpm fetch:logo -- --force # refresh the local copy
|
||
*
|
||
* The dev server also calls `ensureBrandLogo()` once at boot (scripts/dev-server.ts),
|
||
* so a fresh checkout gets the logo without an extra manual step.
|
||
*/
|
||
|
||
const USER_AGENT =
|
||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36 la-rose-seed/1.0';
|
||
const REQUEST_TIMEOUT_MS = 20_000;
|
||
|
||
const PUBLIC_DIR = fileURLToPath(new URL('../public', import.meta.url));
|
||
|
||
/** Absolute path of the local file served at BRAND.logoLocalPath. */
|
||
export const BRAND_LOGO_FILE = join(PUBLIC_DIR, ...BRAND.logoLocalPath.split('/').filter(Boolean));
|
||
|
||
export type BrandLogoStatus = 'kept' | 'downloaded';
|
||
|
||
/** Ensure the local logo copy is on disk; download it when missing (or when forced). */
|
||
export async function ensureBrandLogo(force = false): Promise<BrandLogoStatus> {
|
||
if (!force) {
|
||
const info = await stat(BRAND_LOGO_FILE).catch(() => null);
|
||
if (info && info.size > 0) return 'kept';
|
||
}
|
||
|
||
const controller = new AbortController();
|
||
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
||
try {
|
||
const response = await fetch(BRAND.logoSourceUrl, {
|
||
headers: { 'user-agent': USER_AGENT, accept: 'image/png,image/*;q=0.9,*/*;q=0.5' },
|
||
redirect: 'follow',
|
||
signal: controller.signal,
|
||
});
|
||
if (!response.ok) throw new Error(`HTTP ${response.status} ${response.statusText}`);
|
||
const contentType = response.headers.get('content-type') ?? '';
|
||
if (!contentType.startsWith('image/')) {
|
||
throw new Error(`unexpected content-type "${contentType || 'none'}"`);
|
||
}
|
||
|
||
const bytes = Buffer.from(await response.arrayBuffer());
|
||
if (bytes.length === 0) throw new Error('empty response body');
|
||
|
||
await mkdir(dirname(BRAND_LOGO_FILE), { recursive: true });
|
||
await writeFile(BRAND_LOGO_FILE, bytes);
|
||
return 'downloaded';
|
||
} finally {
|
||
clearTimeout(timer);
|
||
}
|
||
}
|
||
|
||
const isDirectRun =
|
||
process.argv[1] !== undefined && resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
||
|
||
if (isDirectRun) {
|
||
const status = await ensureBrandLogo(process.argv.includes('--force'));
|
||
const kb = ((await stat(BRAND_LOGO_FILE)).size / 1024).toFixed(1);
|
||
console.log(
|
||
status === 'kept'
|
||
? `fetch-logo: kept ${BRAND.logoLocalPath} (${kb} kB)`
|
||
: `fetch-logo: downloaded ${BRAND.logoLocalPath} (${kb} kB)`,
|
||
);
|
||
}
|