This repository has been archived by the owner on Jun 11, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
36 changed files
with
1,135 additions
and
213 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,5 @@ index.node | |
**/node_modules | ||
**/.DS_Store | ||
npm-debug.log* | ||
dist | ||
dist | ||
release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"Styled Components Props": { | ||
"prefix": [ | ||
"pro" | ||
], | ||
"body": [ | ||
"${props => props${0}}" | ||
], | ||
"description": "Styled Components Props" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { protocols } from '../electron-builder.json'; | ||
import { app, BrowserWindow, Menu, nativeImage, Tray } from 'electron'; | ||
|
||
import { join, resolve } from 'path'; | ||
|
||
import './ipcs/general'; | ||
import './ipcs/store'; | ||
import './ipcs/update'; | ||
import { runDeepLinkResolver } from './utils/deepLink'; | ||
|
||
global.win = null; | ||
|
||
const PROTOCOL = protocols.name; | ||
const IS_MAC = process.platform === 'darwin'; | ||
const DEV_URL = `http://localhost:3000`; | ||
const PROD_FILE_PATH = join(__dirname, '../index.html'); | ||
|
||
const RESOURCES_PATH = app.isPackaged | ||
? join(process.resourcesPath, 'resources') | ||
: join(app.getAppPath(), 'resources'); | ||
|
||
const icon = nativeImage.createFromPath( | ||
`${RESOURCES_PATH}/icons/${IS_MAC ? 'logo@512.png' : 'logo@256.ico'}`, | ||
); | ||
|
||
const trayIcon = icon.resize({ width: 20, height: 20 }); | ||
|
||
app.setAsDefaultProtocolClient(PROTOCOL); | ||
|
||
const gotTheLock = app.requestSingleInstanceLock(); | ||
|
||
if (!gotTheLock) { | ||
app.quit(); | ||
process.exit(0); | ||
} | ||
|
||
const createWindow = () => { | ||
if (global.win) { | ||
if (global.win.isMinimized()) global.win.restore(); | ||
global.win.focus(); | ||
return; | ||
} | ||
|
||
global.win = new BrowserWindow({ | ||
icon, | ||
width: 800, | ||
height: 600, | ||
show: false, | ||
webPreferences: { | ||
preload: join(__dirname, 'preload/index.js'), | ||
}, | ||
}); | ||
|
||
if (app.isPackaged) { | ||
global.win.loadFile(PROD_FILE_PATH); | ||
} else { | ||
global.win.loadURL(DEV_URL); | ||
global.win?.webContents.toggleDevTools(); | ||
} | ||
|
||
global.win.on('ready-to-show', () => { | ||
global.win?.show(); | ||
}); | ||
}; | ||
|
||
app.on('activate', () => { | ||
createWindow(); | ||
}); | ||
|
||
app.on('second-instance', (_, argv) => { | ||
console.log('second-instance'); | ||
if (!IS_MAC) { | ||
const url = argv.find(arg => arg.startsWith(`${PROTOCOL}://`)); | ||
|
||
if (url) { | ||
runDeepLinkResolver(url); | ||
} | ||
} | ||
|
||
createWindow(); | ||
}); | ||
|
||
app.on('window-all-closed', () => { | ||
global.win = null; | ||
}); | ||
|
||
app.on('open-url', (_, url) => { | ||
runDeepLinkResolver(url); | ||
}); | ||
|
||
app.whenReady().then(() => { | ||
createWindow(); | ||
|
||
let tray = new Tray(trayIcon); | ||
|
||
const contextMenu = Menu.buildFromTemplate([ | ||
{ label: 'view app screen', type: 'normal', click: () => createWindow() }, | ||
{ type: 'separator' }, | ||
{ label: 'quit', role: 'quit', type: 'normal' }, | ||
]); | ||
|
||
tray.on('double-click', () => createWindow()); | ||
tray.setToolTip('TemplateApp'); | ||
tray.setContextMenu(contextMenu); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { BrowserWindow, ipcMain, shell } from 'electron'; | ||
|
||
declare global { | ||
var win: BrowserWindow | null; | ||
} | ||
|
||
export type AppControlAction = 'devtools' | 'minimize' | 'maximize' | 'close'; | ||
|
||
// 창 닫기, 최대화, 최소화 같은 컨트롤 기능 | ||
ipcMain.on('appControl', async (_, action: AppControlAction) => { | ||
switch (action) { | ||
case 'devtools': { | ||
global.win?.webContents.toggleDevTools(); | ||
break; | ||
} | ||
|
||
case 'minimize': { | ||
global.win?.minimize(); | ||
break; | ||
} | ||
|
||
case 'maximize': { | ||
global.win?.isMaximized() ? global.win?.unmaximize() : global.win?.maximize(); | ||
break; | ||
} | ||
|
||
case 'close': { | ||
global.win?.close(); | ||
break; | ||
} | ||
} | ||
}); | ||
|
||
// 기본 브라우저로 링크 열기 | ||
ipcMain.on('openExternal', async (_, link) => { | ||
return shell.openExternal(link); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { ipcMain } from 'electron'; | ||
|
||
import { configStore } from '../stores/config'; | ||
|
||
ipcMain.handle('getConfig', async () => { | ||
return configStore.store; | ||
}); | ||
|
||
ipcMain.handle('setConfig', async (e, config) => { | ||
return (configStore.store = config); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { app, ipcMain } from 'electron'; | ||
import { autoUpdater } from 'electron-updater'; | ||
|
||
import { updateStore } from '../stores/update'; | ||
import { initlizeUpdater } from '../utils/update'; | ||
|
||
ipcMain.handle('getVersion', async () => { | ||
return app.getVersion(); | ||
}); | ||
|
||
ipcMain.handle('getUpdateStatus', async () => { | ||
return updateStore.get('status'); | ||
}); | ||
|
||
ipcMain.on('checkForUpdate', async () => { | ||
autoUpdater.checkForUpdates(); | ||
}); | ||
|
||
ipcMain.on('quitAndInstall', async () => { | ||
autoUpdater.quitAndInstall(); | ||
}); | ||
|
||
ipcMain.once('initlizeUpdater', async () => { | ||
initlizeUpdater(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { contextBridge, ipcRenderer } from 'electron'; | ||
|
||
import { AppControlAction } from '../ipcs/general'; | ||
import { ConfigStoreValues } from '../stores/config'; | ||
import { UpdateEvent, UpdateStatus } from '../utils/update'; | ||
|
||
export interface ElectronRendererContext { | ||
// general | ||
openExternal: (link: string) => void; | ||
appControl: (action: AppControlAction) => void; | ||
|
||
// update | ||
initlizeUpdater: () => void; | ||
checkForUpdate: () => void; | ||
quitAndInstall: () => void; | ||
getVersion: () => Promise<string>; | ||
getUpdateStatus: () => Promise<UpdateStatus>; | ||
onUpdate: (callback: (event: UpdateEvent, data: any) => void) => void; | ||
|
||
// config store | ||
getConfig: () => Promise<ConfigStoreValues>; | ||
setConfig: (config: ConfigStoreValues) => Promise<ConfigStoreValues>; | ||
} | ||
|
||
const electronContext: ElectronRendererContext = { | ||
appControl: action => ipcRenderer.send('appControl', action), | ||
openExternal: link => ipcRenderer.send('openExternal', link), | ||
|
||
initlizeUpdater: () => ipcRenderer.send('initlizeUpdater'), | ||
checkForUpdate: () => ipcRenderer.send('checkForUpdate'), | ||
quitAndInstall: () => ipcRenderer.send('quitAndInstall'), | ||
getVersion: () => ipcRenderer.invoke('getVersion'), | ||
getUpdateStatus: () => ipcRenderer.invoke('getUpdateStatus'), | ||
onUpdate: callback => ipcRenderer.on('update', (_, event, data) => callback(event, data)), | ||
|
||
getConfig: () => ipcRenderer.invoke('getConfig'), | ||
setConfig: config => ipcRenderer.invoke('setConfig', config), | ||
}; | ||
|
||
contextBridge.exposeInMainWorld('electron', electronContext); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import Store from 'electron-store'; | ||
|
||
export interface ConfigStoreValues { | ||
general: { | ||
theme: 'light' | 'dark'; | ||
}; | ||
} | ||
|
||
export const configStore = new Store<ConfigStoreValues>({ | ||
name: 'config', | ||
accessPropertiesByDotNotation: false, | ||
defaults: { | ||
general: { | ||
theme: 'dark', | ||
}, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Store from 'electron-store'; | ||
|
||
import { UpdateStatus } from '../utils/update'; | ||
|
||
export interface UpdateStoreValues { | ||
status: UpdateStatus; | ||
} | ||
|
||
export const updateStore = new Store<UpdateStoreValues>({ | ||
name: 'update', | ||
accessPropertiesByDotNotation: false, | ||
defaults: { | ||
status: { | ||
event: 'checking-for-update', | ||
data: null, | ||
time: new Date().getTime(), | ||
}, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { dialog } from 'electron'; | ||
|
||
import { MatchResult, match } from 'path-to-regexp'; | ||
|
||
export type DeepLinkResolvers = Record<string, (data: MatchResult<any>) => void>; | ||
|
||
export const runDeepLinkResolver = (url: string) => { | ||
const pathname = url.replace('templateapp://', '/'); | ||
|
||
for (const path in resolvers) { | ||
const data = match(path)(pathname); | ||
|
||
if (data) { | ||
resolvers[path](data); | ||
break; | ||
} | ||
} | ||
}; | ||
|
||
export const resolvers: DeepLinkResolvers = { | ||
'/test/:id': async ({ params }) => { | ||
dialog.showMessageBox({ | ||
title: 'Deep Link', | ||
message: `${params.id}`, | ||
}); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import log from 'electron-log'; | ||
import { autoUpdater } from 'electron-updater'; | ||
|
||
import { updateStore } from '../stores/update'; | ||
|
||
export interface UpdateStatus { | ||
event: UpdateEvent; | ||
data: any; | ||
time: number; | ||
} | ||
|
||
export type UpdateEvent = | ||
| 'checking-for-update' | ||
| 'update-available' | ||
| 'update-not-available' | ||
| 'error' | ||
| 'download-progress' | ||
| 'update-downloaded'; | ||
|
||
export const handleUpdateEvent = (event: UpdateEvent) => { | ||
return (data?: any) => { | ||
if (event !== 'download-progress') { | ||
updateStore.set('status', { | ||
event, | ||
data, | ||
time: new Date().getTime(), | ||
}); | ||
} | ||
|
||
global.win?.webContents.send('update', event, data); | ||
}; | ||
}; | ||
|
||
export const initlizeUpdater = () => { | ||
autoUpdater.logger = log; | ||
autoUpdater.autoInstallOnAppQuit = true; | ||
autoUpdater.fullChangelog = true; | ||
|
||
autoUpdater.on('checking-for-update', handleUpdateEvent('checking-for-update')); | ||
autoUpdater.on('update-available', handleUpdateEvent('update-available')); | ||
autoUpdater.on('update-not-available', handleUpdateEvent('update-not-available')); | ||
autoUpdater.on('download-progress', handleUpdateEvent('download-progress')); | ||
autoUpdater.on('update-downloaded', handleUpdateEvent('update-downloaded')); | ||
autoUpdater.on('error', handleUpdateEvent('error')); | ||
|
||
autoUpdater.checkForUpdates(); | ||
}; |
Oops, something went wrong.