From 048cb673e0e43ca2cadc99ca0d2ef3c0940ee32c Mon Sep 17 00:00:00 2001 From: Dmitry Gusev Date: Mon, 25 May 2026 13:33:22 +0300 Subject: [PATCH] =?UTF-8?q?feat(brand):=20=D0=B0=D0=BA=D1=82=D1=83=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D1=84=D0=B0=D0=B2=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=20=D0=BF=D0=BE=20=D0=B1=D1=80=D0=B5=D0=BD=D0=B4?= =?UTF-8?q?=D0=BE=D0=B2=D0=BE=D0=BC=D1=83=20=D0=B7=D0=BD=D0=B0=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Старый favicon.svg (стилизованная «A» от скаффолдинга) заменён на оптимизированный для 16-32px вариант logo-mark: кривые-отражения + точка на тёмном фоне, тот же градиент #b794ff→#6c4ed4. - public/favicon.svg — новый 64×64 viewBox, утолщённые штрихи - public/favicon.ico — 32×32 (sharp → PNG-in-ICO) - public/apple-touch-icon.png — 180×180 для iOS - scripts/build-favicon.mjs + npm run build:favicon - BaseLayout: добавлены на ico (fallback) и apple-touch-icon --- CLAUDE.md | 7 +++++-- package.json | 3 ++- public/apple-touch-icon.png | Bin 0 -> 9118 bytes public/favicon.ico | Bin 655 -> 1412 bytes public/favicon.svg | 23 +++++++++++++++-------- scripts/build-favicon.mjs | 28 ++++++++++++++++++++++++++++ src/layouts/BaseLayout.astro | 2 ++ 7 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 public/apple-touch-icon.png create mode 100644 scripts/build-favicon.mjs diff --git a/CLAUDE.md b/CLAUDE.md index efcc665..72c3cd7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -75,7 +75,9 @@ src/ └── consts.ts (SITE_TITLE, WORLDS, ANALYTICS, CATEGORY_COLORS, plural()) public/ -├── favicon.svg +├── favicon.svg (брендовый знак на тёмном фоне, оптимизирован под 16-32px) +├── favicon.ico (32×32 PNG-in-ICO, генерируется из favicon.svg) +├── apple-touch-icon.png (180×180 для iOS home screen) ├── logo.svg, logo-mark.svg ├── og-image.png (1200×630 для расшаривания в TG/VK/Twitter) ├── og-image.svg (исходник) @@ -86,7 +88,8 @@ public/ scripts/ ├── migrate-wp.mjs (одноразовый: _wp-export.json → src/content/*.md) -└── build-og-image.mjs (sharp → public/og-image.png из SVG) +├── build-og-image.mjs (sharp → public/og-image.png из SVG) +└── build-favicon.mjs (sharp → public/favicon.ico + apple-touch-icon.png из favicon.svg; `npm run build:favicon`) Dockerfile (multi-stage: node:22-alpine builds → nginx:1.29-alpine serves) nginx.conf (gzip, кэш _astro/ 1y, MIME application/rss+xml для feed) diff --git a/package.json b/package.json index ee4b0a9..96a4466 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "preview": "astro preview", "astro": "astro", "migrate": "node scripts/migrate-wp.mjs", - "indexnow": "node scripts/indexnow.js" + "indexnow": "node scripts/indexnow.js", + "build:favicon": "node scripts/build-favicon.mjs" }, "dependencies": { "@astrojs/rss": "^4.0.12", diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..32c973bf415fc37607bbef0d009d89fe860e2e8b GIT binary patch literal 9118 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 KMNUMnLSTZRik@Qt delta 641 zcmV-{0)G933y%em8Gi!+002a!ipBr{0Q^u)R7C&)00000hlhtnMMV-45+frc;^N`} z006|q!~g&Q00000008jt@H8|uwY9YX005<>rDkSk0002-@$mov0A^-pmX?-QR#tX) zb`la2wzjr+cXy_yrY;N@XJ=$(IFj^KfOcXN@1PRA8bRY;5 zTo^_l2oo*~9JVm3|NsBwI+*4=r{p@B<~yk8Jh$gOw&^{_<2sV-KGyC)?B6$W;yH`r zIf>pkYU4VQ<$pV%=RB|IJih8Z&fqwCG`%bN0000#bW%=JQ=IH#a_&L{B{_6Lu z_3m>0bMN%+@aOmN_3G~H^8EGi>+bXO=;-|Z`uFnf==AdP{Oj-S=ltmI=<4`LcLE*& z009F@L_t(|+I`d4ZUZ3@1<*Uo7H^LoCw6-8z4wsbdw>4_Um`8Gv#bZs144|@Wkv!- zVGw~A#6+MbESiKERv`jd>E+Z>JoH2;^QBS)PslD8tZ~`pfHRUvY0Vgt{{$GdqLdZu z68d>XWk9tuXiTWXF=hCj28BvORa%^n0-X$(A3`0#aIqWX6FdNd9Yw2jnyA+p5_%a< zWe7>uZhCp@mYa%pmiT%P!bQcThpLHbC{y6gzs$_eoh>Y0J}-l{^8WjFb$$QvvX%VS$_tOPfk&mBZTh!0%b9%0gDEKD9*u) b@{s5cHWD!IoUY{M00000NkvXXu0mjfTBIln diff --git a/public/favicon.svg b/public/favicon.svg index f157bd1..f9cb2d7 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1,9 +1,16 @@ - - - + + + + + + + + + + + + + + + diff --git a/scripts/build-favicon.mjs b/scripts/build-favicon.mjs new file mode 100644 index 0000000..95156c4 --- /dev/null +++ b/scripts/build-favicon.mjs @@ -0,0 +1,28 @@ +#!/usr/bin/env node +// Генерирует public/favicon.ico (32x32 PNG-in-ICO, как у Astro по умолчанию) +// и public/apple-touch-icon.png (180x180) из public/favicon.svg. +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import sharp from 'sharp'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROOT = path.resolve(__dirname, '..'); + +const svgPath = path.join(ROOT, 'public/favicon.svg'); +const svg = fs.readFileSync(svgPath); + +const targets = [ + { out: 'public/favicon.ico', size: 32 }, + { out: 'public/apple-touch-icon.png', size: 180 }, +]; + +for (const { out, size } of targets) { + const dst = path.join(ROOT, out); + await sharp(svg, { density: 384 }) + .resize(size, size) + .png({ compressionLevel: 9 }) + .toFile(dst); + const kb = (fs.statSync(dst).size / 1024).toFixed(1); + console.log(`wrote ${out} (${size}x${size}) — ${kb} KB`); +} diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index f2ec911..5f25744 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -69,6 +69,8 @@ const jsonLd = [ + +