Skip to content
This repository was archived by the owner on Jun 11, 2024. It is now read-only.

Commit d853a84

Browse files
committed
v1.1.0
1 parent 73459d6 commit d853a84

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+10506
-690
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ target
22
index.node
33
**/node_modules
44
**/.DS_Store
5-
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
67
dist
8+
/resources/windows/chromium
9+
chrome_data
710
release

.prettierrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
"useTabs": false,
88
"printWidth": 100,
99
"semi": true,
10-
"importOrder": ["electron", "react", "^[^.~]+", "^~.+$", "^\\..+$"],
10+
"importOrder": ["^electron", "^react", "^[^.~@]+", "^@app", "^~.+$", "^\\..+$"],
1111
"importOrderSeparation": true
1212
}

.vscode/typescript.code-snippets

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,45 @@
11
{
2-
"Styled Components Props": {
2+
"Styled Components Export": {
3+
"prefix": [
4+
"sc"
5+
],
6+
"body": [
7+
"import styled from 'styled-components';",
8+
"\n",
9+
"export const ${TM_DIRECTORY/^.+\\/(.*)$/$1/}Styled = styled.div`",
10+
" $0",
11+
"`"
12+
],
13+
"description": "Styled Components 내보내기"
14+
},
15+
"Styled Components Props Theme": {
316
"prefix": [
417
"pro"
518
],
619
"body": [
7-
"${props => props${0}}"
20+
"${props => props.theme${0}}"
21+
],
22+
"description": "Styled Components Props 자동완성"
23+
},
24+
"Component styled": {
25+
"prefix": [
26+
"cs"
27+
],
28+
"body": [
29+
"import clsx from 'clsx';\n",
30+
"import { ${TM_DIRECTORY/^.+\\/(.*)$/$1/}Styled } from './styled';\n",
31+
"interface ${TM_DIRECTORY/^.+\\/(.*)$/$1/}Props {",
32+
" className?: string;",
33+
"}\n",
34+
"const ${TM_DIRECTORY/^.+\\/(.*)$/$1/} = ({ className }: ${TM_DIRECTORY/^.+\\/(.*)$/$1/}Props) => {",
35+
" return (",
36+
" <${TM_DIRECTORY/^.+\\/(.*)$/$1/}Styled className={clsx('${TM_DIRECTORY/^.+\\/(.*)$/$1/}', className)}>",
37+
" $0",
38+
" </${TM_DIRECTORY/^.+\\/(.*)$/$1/}Styled>",
39+
" )",
40+
"}\n",
41+
"export default ${TM_DIRECTORY/^.+\\/(.*)$/$1/}"
842
],
9-
"description": "Styled Components Props"
43+
"description": "컴포넌트 생성 & Styled Components 사용"
1044
}
1145
}

app/app.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { app, BrowserWindow, Menu, nativeImage, Tray } from 'electron';
2+
3+
import { join } from 'path';
4+
5+
import { productName, protocols } from '../electron-builder.json';
6+
7+
export type MyAppType = InstanceType<typeof MyApp>;
8+
export type ModuleFunction = (app: MyAppType) => void | Promise<void>;
9+
10+
class MyApp {
11+
// deep link protocol
12+
readonly PROTOCOL = protocols.name;
13+
14+
// is mac os
15+
readonly IS_MAC = process.platform === 'darwin';
16+
17+
// dev mode - url
18+
readonly DEV_URL = `http://localhost:3000/#`;
19+
20+
// production mode - load file
21+
readonly PROD_LOAD_FILE_PATH = join(__dirname, '../index.html');
22+
readonly PROD_LOAD_FILE_HASH = '#';
23+
24+
// resources directory
25+
readonly RESOURCES_PATH = app.isPackaged
26+
? join(process.resourcesPath, 'resources')
27+
: join(app.getAppPath(), 'resources');
28+
29+
// native icon
30+
readonly ICON = nativeImage.createFromPath(
31+
`${this.RESOURCES_PATH}/icons/${this.IS_MAC ? '[email protected]' : '[email protected]'}`,
32+
);
33+
34+
// electron window
35+
window: BrowserWindow | null = null;
36+
37+
async bootstrap() {
38+
await this.initliazeElectron();
39+
await this.autoload();
40+
}
41+
42+
async initliazeElectron() {
43+
const gotTheLock = app.requestSingleInstanceLock();
44+
45+
if (!gotTheLock) {
46+
app.quit();
47+
process.exit(0);
48+
}
49+
50+
app.setAsDefaultProtocolClient(this.PROTOCOL);
51+
52+
app.on('activate', () => {
53+
this.createWindow();
54+
});
55+
56+
app.on('window-all-closed', () => {
57+
this.window = null;
58+
});
59+
60+
await app.whenReady();
61+
await this.createWindow();
62+
await this.createTray();
63+
}
64+
65+
// create electron window
66+
async createWindow() {
67+
if (this.window) {
68+
if (this.window.isMinimized()) this.window.restore();
69+
this.window.focus();
70+
return;
71+
}
72+
73+
this.window = new BrowserWindow({
74+
width: 1800,
75+
height: 1000,
76+
backgroundColor: '#36393F',
77+
darkTheme: true,
78+
show: false,
79+
autoHideMenuBar: true,
80+
frame: false,
81+
icon: this.ICON,
82+
webPreferences: {
83+
preload: join(__dirname, 'preload/index.js'),
84+
},
85+
});
86+
87+
if (app.isPackaged) {
88+
this.window.loadFile(this.PROD_LOAD_FILE_PATH, {
89+
hash: this.PROD_LOAD_FILE_HASH,
90+
});
91+
92+
this.window.webContents.openDevTools(); // FIXME: Remove this line
93+
} else {
94+
this.window.loadURL(this.DEV_URL);
95+
this.window.webContents.openDevTools(); // FIXME: Remove this line
96+
}
97+
98+
this.window.on('ready-to-show', () => {
99+
this.window?.show();
100+
});
101+
}
102+
103+
async createTray() {
104+
let tray = new Tray(this.ICON.resize({ width: 20, height: 20 }));
105+
106+
const contextMenu = Menu.buildFromTemplate([
107+
{ label: 'view app screen', type: 'normal', click: () => this.createWindow() },
108+
{ type: 'separator' },
109+
{ label: 'quit', role: 'quit', type: 'normal' },
110+
]);
111+
112+
tray.on('double-click', () => this.createWindow());
113+
tray.setToolTip(productName);
114+
tray.setContextMenu(contextMenu);
115+
}
116+
117+
async register(module: ModuleFunction) {
118+
await module(this);
119+
}
120+
121+
async autoload() {
122+
const modules = import.meta.glob<{ default: ModuleFunction }>('./modules/**/index.ts', {
123+
eager: true,
124+
});
125+
126+
for (const module of Object.values(modules)) {
127+
await this.register(module.default);
128+
}
129+
}
130+
}
131+
132+
export default MyApp;

app/index.ts

Lines changed: 5 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,6 @@
1-
import { protocols } from '../electron-builder.json';
2-
import { app, BrowserWindow, Menu, nativeImage, Tray } from 'electron';
1+
import MyApp from './app';
32

4-
import { join, resolve } from 'path';
5-
6-
import './ipcs/general';
7-
import './ipcs/store';
8-
import './ipcs/update';
9-
import { runDeepLinkResolver } from './utils/deepLink';
10-
11-
global.win = null;
12-
13-
const PROTOCOL = protocols.name;
14-
const IS_MAC = process.platform === 'darwin';
15-
const DEV_URL = `http://localhost:3000`;
16-
const PROD_FILE_PATH = join(__dirname, '../index.html');
17-
18-
const RESOURCES_PATH = app.isPackaged
19-
? join(process.resourcesPath, 'resources')
20-
: join(app.getAppPath(), 'resources');
21-
22-
const icon = nativeImage.createFromPath(
23-
`${RESOURCES_PATH}/icons/${IS_MAC ? '[email protected]' : '[email protected]'}`,
24-
);
25-
26-
const trayIcon = icon.resize({ width: 20, height: 20 });
27-
28-
app.setAsDefaultProtocolClient(PROTOCOL);
29-
30-
const gotTheLock = app.requestSingleInstanceLock();
31-
32-
if (!gotTheLock) {
33-
app.quit();
34-
process.exit(0);
35-
}
36-
37-
const createWindow = () => {
38-
if (global.win) {
39-
if (global.win.isMinimized()) global.win.restore();
40-
global.win.focus();
41-
return;
42-
}
43-
44-
global.win = new BrowserWindow({
45-
icon,
46-
width: 800,
47-
height: 600,
48-
show: false,
49-
webPreferences: {
50-
preload: join(__dirname, 'preload/index.js'),
51-
},
52-
});
53-
54-
if (app.isPackaged) {
55-
global.win.loadFile(PROD_FILE_PATH);
56-
} else {
57-
global.win.loadURL(DEV_URL);
58-
global.win?.webContents.toggleDevTools();
59-
}
60-
61-
global.win.on('ready-to-show', () => {
62-
global.win?.show();
63-
});
64-
};
65-
66-
app.on('activate', () => {
67-
createWindow();
68-
});
69-
70-
app.on('second-instance', (_, argv) => {
71-
console.log('second-instance');
72-
if (!IS_MAC) {
73-
const url = argv.find(arg => arg.startsWith(`${PROTOCOL}://`));
74-
75-
if (url) {
76-
runDeepLinkResolver(url);
77-
}
78-
}
79-
80-
createWindow();
81-
});
82-
83-
app.on('window-all-closed', () => {
84-
global.win = null;
85-
});
86-
87-
app.on('open-url', (_, url) => {
88-
runDeepLinkResolver(url);
89-
});
90-
91-
app.whenReady().then(() => {
92-
createWindow();
93-
94-
let tray = new Tray(trayIcon);
95-
96-
const contextMenu = Menu.buildFromTemplate([
97-
{ label: 'view app screen', type: 'normal', click: () => createWindow() },
98-
{ type: 'separator' },
99-
{ label: 'quit', role: 'quit', type: 'normal' },
100-
]);
101-
102-
tray.on('double-click', () => createWindow());
103-
tray.setToolTip('TemplateApp');
104-
tray.setContextMenu(contextMenu);
105-
});
3+
(async () => {
4+
const myApp = new MyApp();
5+
await myApp.bootstrap();
6+
})();

app/ipcs/general.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.

app/ipcs/store.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

app/ipcs/update.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)