diff --git a/.gitignore b/.gitignore index 6cdafec..cfef653 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,6 @@ apps/desktop/src-tauri/target/ apps/desktop/src-tauri/gen/ apps/desktop/src-tauri/tauri.release.json apps/desktop/release/ + +# Intermediate platform icon renders (final assets live under apps/). +/artifacts/icon-build/ diff --git a/apps/desktop/package.json b/apps/desktop/package.json index eb172cf..2e3b39a 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -10,7 +10,7 @@ "bundle:windows": "node inject-version.mjs && tauri build --config src-tauri/tauri.release.json --bundles nsis", "bundle:windows:cross": "node inject-version.mjs && tauri build --config src-tauri/tauri.release.json --runner cargo-xwin --target x86_64-pc-windows-msvc --bundles nsis", "tauri": "tauri", - "icons": "tauri icon ../web/public/favicon.svg" + "icons": "node ../../scripts/generate-icons.mjs" }, "devDependencies": { "@tauri-apps/cli": "^2.9.0" diff --git a/apps/desktop/src-tauri/icons/128x128.png b/apps/desktop/src-tauri/icons/128x128.png index 8c63fb5..fdcfecc 100644 Binary files a/apps/desktop/src-tauri/icons/128x128.png and b/apps/desktop/src-tauri/icons/128x128.png differ diff --git a/apps/desktop/src-tauri/icons/128x128@2x.png b/apps/desktop/src-tauri/icons/128x128@2x.png index f308b2e..538a8da 100644 Binary files a/apps/desktop/src-tauri/icons/128x128@2x.png and b/apps/desktop/src-tauri/icons/128x128@2x.png differ diff --git a/apps/desktop/src-tauri/icons/32x32.png b/apps/desktop/src-tauri/icons/32x32.png index 5987efe..59ac352 100644 Binary files a/apps/desktop/src-tauri/icons/32x32.png and b/apps/desktop/src-tauri/icons/32x32.png differ diff --git a/apps/desktop/src-tauri/icons/64x64.png b/apps/desktop/src-tauri/icons/64x64.png index 7c7a0db..b0dd30b 100644 Binary files a/apps/desktop/src-tauri/icons/64x64.png and b/apps/desktop/src-tauri/icons/64x64.png differ diff --git a/apps/desktop/src-tauri/icons/icon.icns b/apps/desktop/src-tauri/icons/icon.icns index f3e77c9..7901ff7 100644 Binary files a/apps/desktop/src-tauri/icons/icon.icns and b/apps/desktop/src-tauri/icons/icon.icns differ diff --git a/apps/desktop/src-tauri/icons/icon.ico b/apps/desktop/src-tauri/icons/icon.ico index dc81fe6..2cb2d3c 100644 Binary files a/apps/desktop/src-tauri/icons/icon.ico and b/apps/desktop/src-tauri/icons/icon.ico differ diff --git a/apps/desktop/src-tauri/icons/icon.png b/apps/desktop/src-tauri/icons/icon.png index a3c10b7..8e1e558 100644 Binary files a/apps/desktop/src-tauri/icons/icon.png and b/apps/desktop/src-tauri/icons/icon.png differ diff --git a/apps/mobile/app.config.ts b/apps/mobile/app.config.ts index d068733..66ffe6b 100644 --- a/apps/mobile/app.config.ts +++ b/apps/mobile/app.config.ts @@ -9,6 +9,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ name: 'Pipu Music', slug: 'pipu-music', scheme: 'pipu', + icon: './assets/icon.png', version, orientation: 'portrait', userInterfaceStyle: 'automatic', @@ -17,6 +18,11 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ newArchEnabled: false, backgroundColor: '#05070D', android: { + adaptiveIcon: { + foregroundImage: './assets/adaptive-icon.png', + monochromeImage: './assets/monochrome-icon.png', + backgroundColor: '#05070D', + }, package: 'app.pipu.music', versionCode, edgeToEdgeEnabled: true, diff --git a/apps/mobile/assets/adaptive-icon.png b/apps/mobile/assets/adaptive-icon.png new file mode 100644 index 0000000..db6d6cd Binary files /dev/null and b/apps/mobile/assets/adaptive-icon.png differ diff --git a/apps/mobile/assets/icon.png b/apps/mobile/assets/icon.png new file mode 100644 index 0000000..1c835bf Binary files /dev/null and b/apps/mobile/assets/icon.png differ diff --git a/apps/mobile/assets/monochrome-icon.png b/apps/mobile/assets/monochrome-icon.png new file mode 100644 index 0000000..3cb226f Binary files /dev/null and b/apps/mobile/assets/monochrome-icon.png differ diff --git a/apps/web/index.html b/apps/web/index.html index ee8ef8e..50040d2 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -5,6 +5,8 @@ + + pipu diff --git a/apps/web/public/apple-touch-icon.png b/apps/web/public/apple-touch-icon.png new file mode 100644 index 0000000..984ea87 Binary files /dev/null and b/apps/web/public/apple-touch-icon.png differ diff --git a/apps/web/public/favicon-32.png b/apps/web/public/favicon-32.png new file mode 100644 index 0000000..59ac352 Binary files /dev/null and b/apps/web/public/favicon-32.png differ diff --git a/apps/web/public/favicon.svg b/apps/web/public/favicon.svg index 4c0ef27..a5d254c 100644 --- a/apps/web/public/favicon.svg +++ b/apps/web/public/favicon.svg @@ -1 +1,17 @@ - + + + + + + + + + + + + + + + + + diff --git a/apps/web/src/shared/ui/ui.module.css b/apps/web/src/shared/ui/ui.module.css index d7c0022..e3e1e5f 100644 --- a/apps/web/src/shared/ui/ui.module.css +++ b/apps/web/src/shared/ui/ui.module.css @@ -21,9 +21,10 @@ } .logoDot { + display: inline-block; + flex: none; border-radius: 50%; - background: radial-gradient(circle at 35% 30%, #9cc6ff, #2f80ff 55%, #3a1fa8); - box-shadow: 0 0 18px rgba(47, 128, 255, 0.55); + background: url('/favicon.svg') center / contain no-repeat; } .button { diff --git a/docs/design.md b/docs/design.md index 8da36bc..1a96105 100644 --- a/docs/design.md +++ b/docs/design.md @@ -43,7 +43,13 @@ | `overlay` | `rgba(3,5,10,.66)` | `rgba(20,30,60,.32)` | Подложка диалогов | | `glass` | `rgba(12,16,28,.78)` | `rgba(255,255,255,.84)` | Стеклянные карточки (вход, диалоги) + `backdrop-filter: blur(28px) saturate(1.3)` | -Палитра волны по умолчанию: `#2F80FF`, `#7C5CFF`, `#35D3FF`. Логотип — радиальный градиент `#9CC6FF → #2F80FF → #3A1FA8`. +Палитра волны по умолчанию: `#2F80FF`, `#7C5CFF`, `#35D3FF`. Логотип — светлая «p»-нота на сфере с радиальным градиентом `#9CC6FF → #2F80FF → #6354E8 → #3A1FA8`. + +Исходник значка — `apps/web/public/favicon.svg`; он же используется в шапке веб-приложения. +Команда `pnpm icons` пересобирает PNG/ICO/ICNS для desktop, favicon PNG, Apple touch icon +и Android-ресурсы в `apps/mobile/assets/`. Android использует отдельные адаптивный цветной +и монохромный слои с отступами для масок лаунчера; фон — `#05070D`. +После изменения значков установленные приложения нужно пересобрать и обновить. ### Типографика diff --git a/package.json b/package.json index 732d909..bf7fe40 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "node": ">=22" }, "scripts": { + "icons": "node scripts/generate-icons.mjs", "build": "turbo run build", "lint": "turbo run lint", "typecheck": "turbo run typecheck", diff --git a/scripts/generate-icons.mjs b/scripts/generate-icons.mjs new file mode 100644 index 0000000..73225ca --- /dev/null +++ b/scripts/generate-icons.mjs @@ -0,0 +1,51 @@ +import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { spawnSync } from 'node:child_process'; + +// All platform assets derive from the editable web SVG. Requires workspace dependencies. +const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const desktop = join(root, 'apps/desktop'); +const require = createRequire(join(desktop, 'package.json')); +const cli = require.resolve('@tauri-apps/cli/tauri.js'); +const scratch = join(root, 'artifacts/icon-build'); +const source = join(root, 'apps/web/public/favicon.svg'); +const svg = readFileSync(source, 'utf8'); +const body = svg.replace(/]*>/, '').replace('', ''); +mkdirSync(scratch, { recursive: true }); + +function render(input, output, sizes = []) { + mkdirSync(output, { recursive: true }); + const result = spawnSync(process.execPath, [cli, 'icon', input, '--output', output, + ...sizes.flatMap(size => ['--png', String(size)])], { cwd: desktop, stdio: 'inherit' }); + if (result.error) throw result.error; + if (result.status !== 0) throw new Error(`Icon generation failed: ${input}`); +} + +function variant(name, contents, size, destination) { + const input = join(scratch, `${name}.svg`); + const output = join(scratch, name); + writeFileSync(input, `${contents}\n`); + render(input, output, [size]); + mkdirSync(dirname(destination), { recursive: true }); + copyFileSync(join(output, `${size}x${size}.png`), destination); +} + +const native = join(scratch, 'desktop'); +render(source, native); +for (const name of ['32x32.png', '64x64.png', '128x128.png', '128x128@2x.png', 'icon.png', 'icon.ico', 'icon.icns']) { + copyFileSync(join(native, name), join(desktop, 'src-tauri/icons', name)); +} +copyFileSync(join(native, '32x32.png'), join(root, 'apps/web/public/favicon-32.png')); +const background = ''; +variant('touch', background + body, 180, join(root, 'apps/web/public/apple-touch-icon.png')); +variant('mobile', background + body, 1024, join(root, 'apps/mobile/assets/icon.png')); +// The complete orb fits inside Android's central 66/108 safe-zone circle. +variant('adaptive', `${body}`, 1024, + join(root, 'apps/mobile/assets/adaptive-icon.png')); +const mono = body.replace(/[\s\S]*?<\/defs>/, '').replace(/]*\/>/, '') + .replaceAll('url(#note)', '#FFFFFF'); +variant('monochrome', `${mono}`, 1024, + join(root, 'apps/mobile/assets/monochrome-icon.png')); +console.log('Updated desktop, Android, and browser icons.');