chore(v028): 앱 아이콘 (assets/icon.svg → ICO/ICNS/PNG) + electron-builder config
- electron-icon-builder + sharp devDep 추가
- assets/icon.svg → build/icon.{ico,icns,png} 산출 + git 추적
- electron-icon-builder 가 SVG 직접 input 안 받음 (Jimp MIME 에러) — sharp 로 SVG → PNG 1024 변환 후 input
- scripts/svg-to-png.mjs (sharp 사용 SVG→PNG) + scripts/finalize-icons.mjs (build/icons/ → build/ 정규 위치 정리)
- package.json build.{win,mac,linux}.icon 키 추가
- .gitignore: build/icons/ 와 build/icon-source.png (중간 산출물) 무시, build/icon.* 는 추적
- typecheck 0 errors + 472/472 단위 통과 유지 (회귀 없음)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -7,3 +7,7 @@ dist/
|
|||||||
coverage/
|
coverage/
|
||||||
playwright-report/
|
playwright-report/
|
||||||
test-results/
|
test-results/
|
||||||
|
|
||||||
|
# build/ 산출물 — icon.{ico,icns,png} 만 커밋, 중간 산출물은 무시
|
||||||
|
build/icons/
|
||||||
|
build/icon-source.png
|
||||||
|
|||||||
24
assets/icon.svg
Normal file
24
assets/icon.svg
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="img" aria-label="Inkling">
|
||||||
|
<!-- 배경 -->
|
||||||
|
<rect width="1024" height="1024" rx="192" fill="#1a6b6e"/>
|
||||||
|
|
||||||
|
<!-- 화살표 marker -->
|
||||||
|
<defs>
|
||||||
|
<marker id="head" markerWidth="14" markerHeight="14" refX="6" refY="7" orient="auto" markerUnits="strokeWidth">
|
||||||
|
<path d="M 0 0 L 12 7 L 0 14 Z" fill="#5fdbc8"/>
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- sync 호 1개 (270도, 시작점 + 끝 화살표) -->
|
||||||
|
<path d="M 512 132 A 380 380 0 1 1 132 512"
|
||||||
|
stroke="#5fdbc8" stroke-width="36" stroke-linecap="round" fill="none"
|
||||||
|
marker-end="url(#head)"/>
|
||||||
|
<circle cx="512" cy="132" r="28" fill="#5fdbc8"/>
|
||||||
|
|
||||||
|
<!-- 노트 1장 (단일 흰색 paper) -->
|
||||||
|
<rect x="332" y="332" width="360" height="360" rx="32" fill="#ffffff"/>
|
||||||
|
|
||||||
|
<!-- 텍스트 라인 2개 -->
|
||||||
|
<rect x="376" y="436" width="272" height="28" rx="14" fill="#1a6b6e"/>
|
||||||
|
<rect x="376" y="510" width="200" height="28" rx="14" fill="#1a6b6e"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 988 B |
BIN
build/icon.icns
Normal file
BIN
build/icon.icns
Normal file
Binary file not shown.
BIN
build/icon.ico
Normal file
BIN
build/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 353 KiB |
BIN
build/icon.png
Normal file
BIN
build/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
3424
package-lock.json
generated
3424
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
37
package.json
37
package.json
@@ -30,7 +30,9 @@
|
|||||||
"predist:mac": "npm run rebuild:electron && npm run build",
|
"predist:mac": "npm run rebuild:electron && npm run build",
|
||||||
"dist:mac": "electron-builder --mac --arm64",
|
"dist:mac": "electron-builder --mac --arm64",
|
||||||
"predist:linux": "npm run rebuild:electron && npm run build",
|
"predist:linux": "npm run rebuild:electron && npm run build",
|
||||||
"dist:linux": "electron-builder --linux --x64"
|
"dist:linux": "electron-builder --linux --x64",
|
||||||
|
"build:icons:png": "node scripts/svg-to-png.mjs assets/icon.svg build/icon-source.png 1024",
|
||||||
|
"build:icons": "npm run build:icons:png && electron-icon-builder --input=build/icon-source.png --output=build --flatten && node scripts/finalize-icons.mjs"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "xyz.altair823.inkling",
|
"appId": "xyz.altair823.inkling",
|
||||||
@@ -44,8 +46,14 @@
|
|||||||
"**/*.node"
|
"**/*.node"
|
||||||
],
|
],
|
||||||
"win": {
|
"win": {
|
||||||
|
"icon": "build/icon.ico",
|
||||||
"target": [
|
"target": [
|
||||||
{ "target": "nsis", "arch": ["x64"] }
|
{
|
||||||
|
"target": "nsis",
|
||||||
|
"arch": [
|
||||||
|
"x64"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"nsis": {
|
"nsis": {
|
||||||
@@ -56,16 +64,33 @@
|
|||||||
"shortcutName": "Inkling"
|
"shortcutName": "Inkling"
|
||||||
},
|
},
|
||||||
"mac": {
|
"mac": {
|
||||||
|
"icon": "build/icon.icns",
|
||||||
"target": [
|
"target": [
|
||||||
{ "target": "dmg", "arch": ["arm64"] }
|
{
|
||||||
|
"target": "dmg",
|
||||||
|
"arch": [
|
||||||
|
"arm64"
|
||||||
|
]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"category": "public.app-category.productivity",
|
"category": "public.app-category.productivity",
|
||||||
"identity": null
|
"identity": null
|
||||||
},
|
},
|
||||||
"linux": {
|
"linux": {
|
||||||
|
"icon": "build/icon.png",
|
||||||
"target": [
|
"target": [
|
||||||
{ "target": "AppImage", "arch": ["x64"] },
|
{
|
||||||
{ "target": "deb", "arch": ["x64"] }
|
"target": "AppImage",
|
||||||
|
"arch": [
|
||||||
|
"x64"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target": "deb",
|
||||||
|
"arch": [
|
||||||
|
"x64"
|
||||||
|
]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"category": "Utility",
|
"category": "Utility",
|
||||||
"synopsis": "로컬 메모 캡처 + AI 태그",
|
"synopsis": "로컬 메모 캡처 + AI 태그",
|
||||||
@@ -92,8 +117,10 @@
|
|||||||
"@vitejs/plugin-react": "5.1.4",
|
"@vitejs/plugin-react": "5.1.4",
|
||||||
"electron": "41.3.0",
|
"electron": "41.3.0",
|
||||||
"electron-builder": "26.8.1",
|
"electron-builder": "26.8.1",
|
||||||
|
"electron-icon-builder": "^2.0.1",
|
||||||
"electron-vite": "5.0.0",
|
"electron-vite": "5.0.0",
|
||||||
"jsdom": "^29.1.1",
|
"jsdom": "^29.1.1",
|
||||||
|
"sharp": "^0.34.5",
|
||||||
"typescript": "6.0.3",
|
"typescript": "6.0.3",
|
||||||
"undici": "8.1.0",
|
"undici": "8.1.0",
|
||||||
"vite": "7.3.2",
|
"vite": "7.3.2",
|
||||||
|
|||||||
35
scripts/finalize-icons.mjs
Normal file
35
scripts/finalize-icons.mjs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { copyFileSync, renameSync, existsSync } from 'node:fs';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
|
||||||
|
// electron-icon-builder --flatten 은 build/icons/ 안에 icon.ico, icon.icns, <size>x<size>.png
|
||||||
|
// 들을 만든다. electron-builder 는 build/icon.ico, build/icon.icns, build/icon.png 를
|
||||||
|
// 기대 — 정규 위치로 옮긴다.
|
||||||
|
const buildDir = 'build';
|
||||||
|
const iconsDir = join(buildDir, 'icons');
|
||||||
|
|
||||||
|
const moves = [
|
||||||
|
['icon.ico', 'icon.ico'],
|
||||||
|
['icon.icns', 'icon.icns'],
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [src, dest] of moves) {
|
||||||
|
const from = join(iconsDir, src);
|
||||||
|
const to = join(buildDir, dest);
|
||||||
|
if (existsSync(from)) {
|
||||||
|
renameSync(from, to);
|
||||||
|
console.log(`Moved: ${from} -> ${to}`);
|
||||||
|
} else {
|
||||||
|
console.error(`MISSING: ${from}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const png1024 = join(iconsDir, '1024x1024.png');
|
||||||
|
const pngOut = join(buildDir, 'icon.png');
|
||||||
|
if (existsSync(png1024)) {
|
||||||
|
copyFileSync(png1024, pngOut);
|
||||||
|
console.log(`Copied: ${png1024} -> ${pngOut}`);
|
||||||
|
} else {
|
||||||
|
console.error(`MISSING: ${png1024}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
14
scripts/svg-to-png.mjs
Normal file
14
scripts/svg-to-png.mjs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import sharp from 'sharp';
|
||||||
|
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
||||||
|
import { dirname } from 'node:path';
|
||||||
|
|
||||||
|
const [, , input, output, size = '1024'] = process.argv;
|
||||||
|
if (!input || !output) {
|
||||||
|
console.error('Usage: svg-to-png.mjs <input.svg> <output.png> [size]');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
mkdirSync(dirname(output), { recursive: true });
|
||||||
|
const svg = readFileSync(input);
|
||||||
|
const png = await sharp(svg).resize(Number(size), Number(size)).png().toBuffer();
|
||||||
|
writeFileSync(output, png);
|
||||||
|
console.log(`OK: ${output} (${size}x${size})`);
|
||||||
Reference in New Issue
Block a user