// Slim Budget 데스크톱(Electron) 메인 프로세스. // 라이브 사이트(https://app.sblog.kr)를 직접 로드한다 → 프론트 변경이 자동 반영(재설치 불필요), // 같은 출처라 CORS 우회도 불필요. 배포된 웹 게이트가 Electron 을 감지해 안내페이지 대신 전체 앱을 띄운다. const { app, BrowserWindow, shell, session } = require('electron') const fs = require('fs') const path = require('path') // 네이티브 대화상자(alert/confirm) 제목은 app.getName() 을 쓴다 → package.json name('sb_pt') 대신 표기. app.setName('돈돼지 가계부') const APP_URL = 'https://app.sblog.kr' // 창 크기/위치를 userData 에 저장해 다음 실행 때 복원 (기본 해상도 고정 대신 사용자가 맞춘 크기 유지) function stateFile() { return path.join(app.getPath('userData'), 'window-state.json') } function loadState() { try { return JSON.parse(fs.readFileSync(stateFile(), 'utf-8')) } catch { return null } } function saveState(win) { try { if (win.isMinimized()) return const b = win.getBounds() fs.writeFileSync(stateFile(), JSON.stringify({ ...b, maximized: win.isMaximized() })) } catch { /* 저장 실패 무시 */ } } // 오프라인/로드 실패 시 안내 화면 (다시 시도 버튼) function offlineHtml() { const html = `돈돼지 가계부

연결할 수 없습니다

인터넷 연결을 확인해 주세요.

` return 'data:text/html;charset=utf-8,' + encodeURIComponent(html) } function createWindow() { const s = loadState() const win = new BrowserWindow({ width: s?.width || 1024, height: s?.height || 720, x: s?.x, y: s?.y, minWidth: 360, minHeight: 560, backgroundColor: '#1a1a1a', title: '돈돼지 가계부', webPreferences: { contextIsolation: true, nodeIntegration: false, // 한글 IME 첫 글자 중복 입력 방지 — Chromium 맞춤법 검사기가 조합을 방해하는 Electron 알려진 버그 회피 spellcheck: false, }, }) if (s?.maximized) win.maximize() // 기본 메뉴바 제거(앱 자체 내비게이션 사용) win.removeMenu() win.loadURL(APP_URL) // 닫을 때 창 크기/위치 저장 → 다음 실행에 복원 win.on('close', () => saveState(win)) // 메인 프레임 로드 실패(오프라인 등) 시 안내 화면. -3(aborted, 리다이렉트 등)은 무시. win.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL, isMainFrame) => { if (isMainFrame && errorCode !== -3) win.loadURL(offlineHtml()) }) // 외부(앱 외 도메인) 링크는 기본 브라우저로, 앱 내 링크는 창에서 처리 win.webContents.setWindowOpenHandler(({ url }) => { if (/^https?:\/\//i.test(url) && !url.startsWith(APP_URL)) { shell.openExternal(url) return { action: 'deny' } } return { action: 'allow' } }) } app.whenReady().then(async () => { // 시작 시 HTTP 캐시 비움 → 라이브 사이트의 최신 프론트를 항상 로드(옛 HTML 캐시로 인한 미반영 방지). // localStorage(로그인 세션)는 캐시가 아니라 영향 없음. try { await session.defaultSession.clearCache() } catch { /* 캐시 클리어 실패 무시 */ } createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit() })