feat: Bootstrap the Electron application with React, Convex, and LiveKit, including a FriendsView component and a Gitea CI/CD release workflow.
Some checks failed
Build and Release / build-and-release (push) Failing after 27m21s
Some checks failed
Build and Release / build-and-release (push) Failing after 27m21s
This commit is contained in:
@@ -13,7 +13,8 @@
|
||||
"Bash(dir:*)",
|
||||
"Bash(npx vite build:*)",
|
||||
"Bash(npx tsc:*)",
|
||||
"Bash(npx -y esbuild:*)"
|
||||
"Bash(npx -y esbuild:*)",
|
||||
"WebFetch(domain:gist.github.com)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
87
.gitea/workflows/release.yml
Normal file
87
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,87 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build-and-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install Wine (for Windows cross-compile)
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y wine64 wine32
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install
|
||||
npm run install:frontend
|
||||
|
||||
- name: Read version from package.json
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(node -p "require('./FrontEnd/Electron/package.json').version")
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build Electron app
|
||||
run: |
|
||||
cd FrontEnd/Electron
|
||||
npm run build
|
||||
npx electron-builder --linux --win
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_TOKEN }}
|
||||
|
||||
- name: Delete existing latest release
|
||||
run: |
|
||||
RELEASE_ID=$(curl -s -H "Authorization: token $TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$REPO/releases/tags/latest" | jq -r '.id')
|
||||
if [ "$RELEASE_ID" != "null" ] && [ -n "$RELEASE_ID" ]; then
|
||||
curl -X DELETE -H "Authorization: token $TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$REPO/releases/$RELEASE_ID"
|
||||
# Also delete the tag so it can be recreated
|
||||
curl -X DELETE -H "Authorization: token $TOKEN" \
|
||||
"$GITEA_URL/api/v1/repos/$REPO/tags/latest"
|
||||
fi
|
||||
env:
|
||||
GITEA_URL: ${{ secrets.CI_URL }}
|
||||
REPO: ${{ gitea.repository }}
|
||||
TOKEN: ${{ secrets.CI_TOKEN }}
|
||||
|
||||
- name: Create release and upload artifacts
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
|
||||
# Create new release with latest tag
|
||||
RELEASE_ID=$(curl -s -X POST -H "Authorization: token $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"latest\",\"name\":\"v${VERSION}\",\"body\":\"Auto-release v${VERSION} from CI\"}" \
|
||||
"$GITEA_URL/api/v1/repos/$REPO/releases" | jq -r '.id')
|
||||
|
||||
echo "Created release ID: $RELEASE_ID"
|
||||
|
||||
# Upload each artifact
|
||||
for file in FrontEnd/Electron/dist/latest*.yml \
|
||||
FrontEnd/Electron/dist/*.exe \
|
||||
FrontEnd/Electron/dist/*.exe.blockmap \
|
||||
FrontEnd/Electron/dist/*.AppImage; do
|
||||
[ -f "$file" ] || continue
|
||||
FILENAME=$(basename "$file")
|
||||
echo "Uploading: $FILENAME"
|
||||
curl -X POST -H "Authorization: token $TOKEN" \
|
||||
-F "attachment=@$file" \
|
||||
"$GITEA_URL/api/v1/repos/$REPO/releases/$RELEASE_ID/assets?name=$FILENAME"
|
||||
done
|
||||
env:
|
||||
GITEA_URL: ${{ secrets.CI_URL }}
|
||||
REPO: ${{ gitea.repository }}
|
||||
TOKEN: ${{ secrets.CI_TOKEN }}
|
||||
@@ -2,6 +2,7 @@ const { app, BrowserWindow, ipcMain, shell } = require('electron');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
const { checkForUpdates } = require('./updater.cjs');
|
||||
|
||||
function createWindow() {
|
||||
const win = new BrowserWindow({
|
||||
@@ -28,8 +29,36 @@ function createWindow() {
|
||||
}
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
function createSplashWindow() {
|
||||
const splash = new BrowserWindow({
|
||||
width: 300,
|
||||
height: 350,
|
||||
frame: false,
|
||||
resizable: false,
|
||||
alwaysOnTop: true,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true
|
||||
}
|
||||
});
|
||||
splash.loadFile(path.join(__dirname, 'splash.html'));
|
||||
return splash;
|
||||
}
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
const isDev = !app.isPackaged;
|
||||
|
||||
if (isDev) {
|
||||
createWindow();
|
||||
} else {
|
||||
const splash = createSplashWindow();
|
||||
const noUpdate = await checkForUpdates(splash);
|
||||
if (noUpdate === false) {
|
||||
if (!splash.isDestroyed()) splash.close();
|
||||
createWindow();
|
||||
}
|
||||
// If update downloaded, quitAndInstall handles restart
|
||||
}
|
||||
|
||||
ipcMain.on('window-minimize', () => {
|
||||
const win = BrowserWindow.getFocusedWindow();
|
||||
|
||||
111
Frontend/Electron/package-lock.json
generated
111
Frontend/Electron/package-lock.json
generated
@@ -11,6 +11,8 @@
|
||||
"@livekit/components-react": "^2.9.17",
|
||||
"@livekit/components-styles": "^1.2.0",
|
||||
"convex": "^1.31.2",
|
||||
"electron-log": "^5.4.3",
|
||||
"electron-updater": "^6.7.3",
|
||||
"livekit-client": "^2.16.1",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
@@ -2772,7 +2774,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true,
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/assert-plus": {
|
||||
@@ -4726,6 +4727,15 @@
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-log": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/electron-log/-/electron-log-5.4.3.tgz",
|
||||
"integrity": "sha512-sOUsM3LjZdugatazSQ/XTyNcw8dfvH1SYhXWiJyfYodAAKOZdHs0txPiLDXFzOZbhXgAgshQkshH2ccq0feyLQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-publish": {
|
||||
"version": "25.1.7",
|
||||
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-25.1.7.tgz",
|
||||
@@ -4787,6 +4797,82 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/electron-updater": {
|
||||
"version": "6.7.3",
|
||||
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.7.3.tgz",
|
||||
"integrity": "sha512-EgkT8Z9noqXKbwc3u5FkJA+r48jwZ5DTUiOkJMOTEEH//n5Am6wfQGz7nvSFEA2oIAMv9jRzn5JKTyWeSKOPgg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"builder-util-runtime": "9.5.1",
|
||||
"fs-extra": "^10.1.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lazy-val": "^1.0.5",
|
||||
"lodash.escaperegexp": "^4.1.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"semver": "~7.7.3",
|
||||
"tiny-typed-emitter": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-updater/node_modules/builder-util-runtime": {
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz",
|
||||
"integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
"sax": "^1.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-updater/node_modules/fs-extra": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-updater/node_modules/jsonfile": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
|
||||
"integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-updater/node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-updater/node_modules/universalify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
||||
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/electron/node_modules/@types/node": {
|
||||
"version": "20.19.27",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz",
|
||||
@@ -5740,7 +5826,6 @@
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
@@ -6394,7 +6479,6 @@
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
@@ -6482,7 +6566,6 @@
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
|
||||
"integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lazystream": {
|
||||
@@ -6628,6 +6711,12 @@
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash.escaperegexp": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
|
||||
"integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.flatten": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
|
||||
@@ -6636,6 +6725,13 @@
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
@@ -9026,7 +9122,6 @@
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz",
|
||||
"integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
@@ -9550,6 +9645,12 @@
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-typed-emitter": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz",
|
||||
"integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "discord",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"main": "main.cjs",
|
||||
"homepage": "./",
|
||||
@@ -14,26 +14,52 @@
|
||||
"electron:build": "vite build && electron-builder"
|
||||
},
|
||||
"build": {
|
||||
"appId": "com.yourorg.discord-clone",
|
||||
"productName": "Discord Clone",
|
||||
"files": [
|
||||
"dist-react/**/*",
|
||||
"main.cjs",
|
||||
"preload.cjs",
|
||||
"updater.cjs",
|
||||
"splash.html",
|
||||
"package.json"
|
||||
],
|
||||
"directories": {
|
||||
"output": "dist"
|
||||
},
|
||||
"publish": [
|
||||
{
|
||||
"provider": "generic",
|
||||
"url": "https://gitea.moyettes.com/Moyettes/DiscordClone/releases/download/latest"
|
||||
}
|
||||
],
|
||||
"win": {
|
||||
"target": ["nsis"]
|
||||
},
|
||||
"mac": {
|
||||
"target": ["dmg", "zip"],
|
||||
"category": "public.app-category.social-networking"
|
||||
},
|
||||
"linux": {
|
||||
"target": ["AppImage"]
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": true,
|
||||
"perMachine": false
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@livekit/components-react": "^2.9.17",
|
||||
"@livekit/components-styles": "^1.2.0",
|
||||
"convex": "^1.31.2",
|
||||
"electron-log": "^5.4.3",
|
||||
"electron-updater": "^6.7.3",
|
||||
"livekit-client": "^2.16.1",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router-dom": "^7.11.0",
|
||||
"react-syntax-highlighter": "^16.1.0",
|
||||
"convex": "^1.31.2",
|
||||
"remark-gfm": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
109
Frontend/Electron/splash.html
Normal file
109
Frontend/Electron/splash.html
Normal file
@@ -0,0 +1,109 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Discord Clone</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
background: #313338;
|
||||
color: #dbdee1;
|
||||
font-family: 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
-webkit-app-region: drag;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: #5865f2;
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.logo svg {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.app-name {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #f2f3f5;
|
||||
margin-bottom: 32px;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
#status {
|
||||
font-size: 13px;
|
||||
color: #b5bac1;
|
||||
margin-bottom: 16px;
|
||||
min-height: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
width: 220px;
|
||||
height: 6px;
|
||||
background: #1e1f22;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
opacity: 1;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.progress-container.hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#progress-bar {
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
background: #5865f2;
|
||||
border-radius: 3px;
|
||||
transition: width 0.2s ease;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="logo">
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.36-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="app-name">Discord Clone</div>
|
||||
<div id="status">Starting up...</div>
|
||||
<div class="progress-container" id="progress-container">
|
||||
<div id="progress-bar"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function setStatus(text) {
|
||||
document.getElementById('status').textContent = text;
|
||||
}
|
||||
|
||||
function setProgress(percent) {
|
||||
const container = document.getElementById('progress-container');
|
||||
const bar = document.getElementById('progress-bar');
|
||||
container.classList.remove('hidden');
|
||||
bar.style.width = Math.min(100, Math.max(0, percent)) + '%';
|
||||
}
|
||||
|
||||
function hideProgress() {
|
||||
document.getElementById('progress-container').classList.add('hidden');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -74,45 +74,8 @@ const FriendsView = ({ onOpenDM }) => {
|
||||
{tab}
|
||||
</div>
|
||||
))}
|
||||
<div
|
||||
onClick={() => setActiveTab('Add Friend')}
|
||||
className="friends-tab"
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
color: activeTab === 'Add Friend' ? '#fff' : '#3ba55c',
|
||||
backgroundColor: activeTab === 'Add Friend' ? '#3ba55c' : 'transparent',
|
||||
padding: '2px 8px',
|
||||
borderRadius: '4px',
|
||||
fontWeight: 500,
|
||||
fontSize: '14px'
|
||||
}}
|
||||
>
|
||||
Add Friend
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{activeTab === 'Add Friend' && (
|
||||
<div style={{ padding: '16px 20px' }}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search for a user to start a conversation..."
|
||||
value={addFriendSearch}
|
||||
onChange={(e) => setAddFriendSearch(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
backgroundColor: 'var(--bg-tertiary)',
|
||||
border: '1px solid var(--border-subtle)',
|
||||
borderRadius: '8px',
|
||||
color: 'var(--text-normal)',
|
||||
padding: '10px 14px',
|
||||
fontSize: '14px',
|
||||
outline: 'none',
|
||||
boxSizing: 'border-box'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* List Header */}
|
||||
<div style={{ padding: '16px 20px 8px' }}>
|
||||
|
||||
61
Frontend/Electron/updater.cjs
Normal file
61
Frontend/Electron/updater.cjs
Normal file
@@ -0,0 +1,61 @@
|
||||
const { autoUpdater } = require('electron-updater');
|
||||
const log = require('electron-log');
|
||||
|
||||
autoUpdater.logger = log;
|
||||
autoUpdater.autoDownload = false;
|
||||
autoUpdater.autoInstallOnAppQuit = true;
|
||||
|
||||
function checkForUpdates(splashWindow) {
|
||||
return new Promise((resolve) => {
|
||||
function sendToSplash(js) {
|
||||
if (splashWindow && !splashWindow.isDestroyed()) {
|
||||
splashWindow.webContents.executeJavaScript(js).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
autoUpdater.on('checking-for-update', () => {
|
||||
sendToSplash('setStatus("Checking for updates...")');
|
||||
});
|
||||
|
||||
autoUpdater.on('update-available', () => {
|
||||
sendToSplash('setStatus("Downloading update...")');
|
||||
autoUpdater.downloadUpdate();
|
||||
});
|
||||
|
||||
autoUpdater.on('download-progress', (progress) => {
|
||||
const percent = Math.round(progress.percent);
|
||||
sendToSplash(`setProgress(${percent})`);
|
||||
sendToSplash(`setStatus("Downloading update... ${percent}%")`);
|
||||
});
|
||||
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
sendToSplash('setStatus("Installing update...")');
|
||||
sendToSplash('setProgress(100)');
|
||||
setTimeout(() => {
|
||||
autoUpdater.quitAndInstall();
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
autoUpdater.on('update-not-available', () => {
|
||||
sendToSplash('setStatus("Up to date!")');
|
||||
sendToSplash('hideProgress()');
|
||||
setTimeout(() => resolve(false), 1000);
|
||||
});
|
||||
|
||||
autoUpdater.on('error', (err) => {
|
||||
log.error('Auto-updater error:', err);
|
||||
sendToSplash('setStatus("Update check failed")');
|
||||
sendToSplash('hideProgress()');
|
||||
setTimeout(() => resolve(false), 2000);
|
||||
});
|
||||
|
||||
autoUpdater.checkForUpdates().catch((err) => {
|
||||
log.error('checkForUpdates failed:', err);
|
||||
sendToSplash('setStatus("Update check failed")');
|
||||
sendToSplash('hideProgress()');
|
||||
setTimeout(() => resolve(false), 2000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { checkForUpdates };
|
||||
Reference in New Issue
Block a user