Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat/#123] 일렉트론 개발 및 빌드 환경 세팅, 다운로드 페이지 추가 #124

Merged
merged 1 commit into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ jobs:
- name: Install dependencies
run: yarn install

- name: Generate build
id: build
- name: Generate web build
id: build_web
env:
VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }}
VITE_OAUTH_KAKAO_REST_API_KEY: ${{ secrets.VITE_OAUTH_KAKAO_REST_API_KEY }}
Expand All @@ -42,6 +42,27 @@ jobs:
aws s3 sync --region ap-northeast-2 dist s3://alignlab-client --delete
continue-on-error: true

- name: Generate Electron build
id: build_electron
env:
VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }}
VITE_OAUTH_KAKAO_REST_API_KEY: ${{ secrets.VITE_OAUTH_KAKAO_REST_API_KEY }}
VITE_OAUTH_KAKAO_CLIENT_SECRET_CODE: ${{ secrets.VITE_OAUTH_KAKAO_CLIENT_SECRET_CODE }}
VITE_OAUTH_KAKAO_REDIRECT_URI: ${{ secrets.VITE_OAUTH_KAKAO_REDIRECT_URI }}
run: yarn electron:build
continue-on-error: true

- name: Deploy Electron build to S3
id: deploy_electron
if: steps.build_electron.outcome == 'success'
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
aws s3 cp out/make/squirrel.windows/AlignLabInstaller.exe s3://alignlab-client/installer/AlignLabInstaller.exe --region ap-northeast-2
aws s3 cp out/make/dmg/AlignLab.dmg s3://alignlab-client/installer/AlignLab.dmg --region ap-northeast-2
continue-on-error: true

- name: Invalidate CloudFront Cache
if: steps.deploy.outcome == 'success'
env:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@
# production
/build

# electron production
/out

# misc
.DS_Store
.env
.env.dev
.env.local
.env.development.local
.env.test.local
Expand Down
68 changes: 62 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,61 @@
{
"name": "alignlab",
"version": "1.0.0",
"main": "index.js",
"main": "dist/main.js",
"license": "MIT",
"type": "module",
"build": {
"extends": null
},
"config": {
"forge": {
"packagerConfig": {
"name": "AlignLab",
"outDir": "out/"
},
"rebuildConfig": {},
"makers": [
{
"name": "@electron-forge/maker-squirrel",
"config": {
"name": "AlignLab",
"authors": "AlignLab Inc.",
"exe": "AlignLab.exe",
"setupExe": "AlignLabInstaller.exe"
}
},
{
"name": "@electron-forge/maker-dmg",
"config": {
"name": "AlignLab",
"overwrite": true,
"format": "ULFO"
}
},
{
"name": "@electron-forge/maker-zip",
"platforms": ["darwin"]
},
{
"name": "@electron-forge/maker-deb",
"config": {}
},
{
"name": "@electron-forge/maker-rpm",
"config": {}
}
]
}
},
"scripts": {
"dev": "vite --mode dev",
"build": "tsc && vite build --mode dev",
"build:dev": "tsc && vite build --mode dev",
"build:test": "tsc && vite build --mode dev",
"build": "tsc && vite build --mode prd",
"build:dev": "tsc && vite build --mode prd",
"build:test": "tsc && vite build --mode prd",
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
"lint:fix": "eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix"
"lint:fix": "eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix",
"electron:dev": "concurrently \"yarn dev\" \"cross-env DEV= tsc-watch -p tsconfig.electron.json --onSuccess \\\"electron .\\\"\"",
"electron:preview": "yarn build && tsc -p tsconfig.electron.json && PREVIEW= electron .",
"electron:build": "tsc && yarn build && tsc -p tsconfig.electron.json && electron-forge make"
},
"dependencies": {
"@tanstack/react-query": "^5.51.23",
Expand All @@ -20,6 +65,7 @@
"dayjs": "^1.11.13",
"echarts": "^5.5.1",
"echarts-for-react": "^3.0.2",
"electron-squirrel-startup": "^1.0.0",
"lucide-react": "^0.435.0",
"p5": "^1.9.4",
"react": "^18.2.0",
Expand All @@ -31,6 +77,12 @@
"zustand": "^4.5.5"
},
"devDependencies": {
"@electron-forge/cli": "^6.0.4",
"@electron-forge/maker-deb": "^6.0.4",
"@electron-forge/maker-rpm": "^6.0.4",
"@electron-forge/maker-squirrel": "^6.0.4",
"@electron-forge/maker-zip": "^6.0.4",
"@electron-forge/maker-dmg": "^6.0.4",
"@types/node": "^20.7.1",
"@types/qs": "^6.9.7",
"@types/react": "^18.0.26",
Expand All @@ -39,6 +91,9 @@
"@typescript-eslint/parser": "^5.59.1",
"@vitejs/plugin-react": "^4.2.0",
"autoprefixer": "^10.4.14",
"concurrently": "^7.6.0",
"cross-env": "^7.0.3",
"electron": "^22.2.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.6.0",
"eslint-import-resolver-typescript": "^3.5.2",
Expand All @@ -52,6 +107,7 @@
"react-refresh": "^0.14.0",
"tailwindcss": "^3.3.1",
"ts-node": "^10.9.1",
"tsc-watch": "^6.0.0",
"typescript": "^5.1.6",
"vite": "^4.3.9",
"vite-plugin-svgr": "^4.2.0",
Expand Down
2 changes: 1 addition & 1 deletion postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export default {
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
Expand Down
3 changes: 3 additions & 0 deletions src/assets/icons/download-mac-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/download-window-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/constants/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"MYCREW": "/crew/my",
"HOME": "/home",
"SOCKET": "/socket",
"MYPAGE": "/mypage"
"MYPAGE": "/mypage",
"DOWNLOAD": "/download"
}
8 changes: 8 additions & 0 deletions src/electron/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ipcMain, IpcMainInvokeEvent } from "electron"

ipcMain.handle("node-version", (event: IpcMainInvokeEvent, msg: string): string => {
console.log(event)
console.log(msg)

return process.versions.node
})
8 changes: 8 additions & 0 deletions src/electron/globals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export {}

declare global {
interface Window {
backend: typeof import("./preload").backend
versions: typeof import("./preload").versions
}
}
47 changes: 47 additions & 0 deletions src/electron/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { app, BrowserWindow } from "electron"
import { join } from "path"

import "./api"

const isDev = process.env.DEV != undefined
const isPreview = process.env.PREVIEW != undefined

function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: join(__dirname, "preload.js"),
},
})

if (isDev) {
mainWindow.loadURL("http://localhost:3000")
mainWindow.webContents.openDevTools()
} else if (isPreview) {
mainWindow.webContents.openDevTools()
mainWindow.loadFile("dist/index.html")
} else {
mainWindow.loadFile("dist/index.html")
}
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()

app.on("activate", () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit()
})
14 changes: 14 additions & 0 deletions src/electron/preload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { contextBridge, ipcRenderer } from "electron"

export const backend = {
nodeVersion: async (msg: string): Promise<string> => await ipcRenderer.invoke("node-version", msg),
}

export const versions = {
node: process.versions.node,
chrome: process.versions.chrome,
electron: process.versions.electron,
}

contextBridge.exposeInMainWorld("backend", backend)
contextBridge.exposeInMainWorld("versions", versions)
2 changes: 1 addition & 1 deletion src/hooks/useGuidePopup.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useGuidePopupStore } from "@/store/GuidePopupStore"
import { useEffect } from "react"

export const useGuidePopup = (isClosedInitialGuidePopup: boolean = false) => {
export const useGuidePopup = (isClosedInitialGuidePopup = false) => {
const { isPopupOpen, lastClosedDate, openPopup, closePopup, setLastClosedDate } = useGuidePopupStore()

useEffect(() => {
Expand Down
55 changes: 55 additions & 0 deletions src/layouts/HomeLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import LogoImage from "@assets/icons/home-logo.svg?react"
import { Outlet } from "react-router-dom"

const REST_API_KEY = import.meta.env.VITE_OAUTH_KAKAO_REST_API_KEY
const REDIRECT_URI = import.meta.env.VITE_OAUTH_KAKAO_REDIRECT_URI
const LOGIN_LINK = `https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`

const HomeLayout: React.FC = () => {
const loginHandler = (): void => {
window.location.href = LOGIN_LINK
}

return (
<div className="flex h-screen min-h-[981px] w-screen min-w-[1440px] flex-col justify-start">
{/* header */}
<div className="flex w-full flex-none border border-[#F0F2F9] px-[120px] py-5">
{/* logo */}
<div className="flex flex-grow items-center">
<LogoImage />
</div>
<button
className="rounded-full bg-blue-600 px-6 py-1 text-sm font-semibold leading-6 text-white"
onClick={loginHandler}
>
{"로그인"}
</button>
</div>
{/* Main Content */}
<div>
<Outlet />
</div>
{/* footer */}
<div className="flex-grow bg-[#1C1D20] px-[120px] py-10">
<div className="flex items-center text-[#D9D9D9]">
<div className="mr-20 text-2xl font-bold">ALIGN LAB</div>
<div className="flex gap-20 text-sm">
<a href="https://swjg3gi.notion.site/89966f39e24a442a8eee5b1f91c4fde7" target="_blank" rel="noreferrer">
<div>개인정보처리방침</div>
</a>
<a
href="https://swjg3gi.notion.site/7c13aba015654e6f8e1acd300b440526?pvs=4"
target="_blank"
rel="noreferrer"
>
<div>이용약관</div>
</a>
</div>
</div>
<div className="mt-10 text-xs font-normal text-[#9D9DA2]">Copyright all reserved @2024</div>
</div>
</div>
)
}

export default HomeLayout
26 changes: 26 additions & 0 deletions src/pages/DownloadPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import WindowIcon from "@assets/icons/download-window-icon.svg?react"
import MacIcon from "@assets/icons/download-mac-icon.svg?react"
const DownloadPage: React.FC = () => {
return (
<div className="flex h-[704px] flex-col items-center justify-center gap-10 bg-gradient-to-b from-white via-[#BFD9FE] to-[#8BBAFE]">
{/* left */}
<div className="text-center text-5xl font-bold leading-[70px] text-zinc-900">
끈김없이 더 바른 자세 유지를 위한
<br />
PC용 앱을 다운받아보세요
</div>
<div className="flex gap-6">
<div className="flex w-[200px] cursor-pointer items-center items-center justify-center gap-2 rounded-full bg-white py-4 text-base font-semibold leading-[24px] text-zinc-900">
<WindowIcon />
<div>Window OS</div>
</div>
<div className="flex w-[200px] cursor-pointer items-center items-center justify-center gap-2 rounded-full bg-white px-7 py-4 text-base font-semibold text-zinc-900">
<MacIcon />
<div>Mac OS</div>
</div>
</div>
</div>
)
}

export default DownloadPage
Loading
Loading