improve: compatibility for windows

This commit is contained in:
alikia2x (寒寒) 2024-12-08 00:43:56 +08:00
parent 7dac731479
commit 95f982f245
15 changed files with 740 additions and 60 deletions

View File

@ -0,0 +1,16 @@
# Build Instructions
## Binaries & Libraries
### Simple
Simple is a SQLite3 FTS extension for indexing Chinese, OpenRewind use it to improve searching experience for Chinese users.
Before building, you need to download latest release of Simple at their [GitHub Release](https://github.com/wangfenjin/simple/releases),
decompress all files in the zip into `[PROJECT_ROOT]/bin/[PLATFORM]/libsimple/`, in which:
- [PROJECT_ROOT] is the root directory of OpenRewind you pulled.
- [PLATFORM] refers to the specific platform you are targeting:
- win32: Windows
- darwin: macOS
- linux: Linux

View File

@ -12,14 +12,17 @@
"output": "dist/release" "output": "dist/release"
}, },
"files": [ "files": [
"dist/dev/**/*", "dist/electron/**/*",
"dist/dev/assets/*", "dist/electron/assets/*",
"dist/dev/i18n/*", "dist/electron/i18n/*",
"dist/renderer/**/*", "dist/renderer/**/*",
"dist/renderer/assets/*" "dist/renderer/assets/*"
], ],
"win": { "win": {
"target": "nsis" "target": "nsis",
"files": [
"bin/win32"
]
}, },
"linux": { "linux": {
"target": "AppImage" "target": "AppImage"

View File

@ -1,19 +1,18 @@
import gulp from "gulp"; import gulp from "gulp";
import ts from "gulp-typescript"; import ts from "gulp-typescript";
// @ts-ignore
import clean from "gulp-clean"; import clean from "gulp-clean";
import fs from "fs"; import fs from "fs";
const tsProject = ts.createProject('tsconfig.json'); const tsProject = ts.createProject('tsconfig.json');
gulp.task('clean', function () { gulp.task('clean', function () {
return gulp.src('dist/dev', {read: false, allowEmpty: true}) return gulp.src('dist/electron', {read: false, allowEmpty: true})
.pipe(clean()); .pipe(clean());
}); });
gulp.task('scripts', () => { gulp.task('scripts', () => {
if (!fs.existsSync("dist/dev")) { if (!fs.existsSync("dist/electron")) {
fs.mkdirSync("dist/dev", { recursive: true }); fs.mkdirSync("dist/electron", { recursive: true });
} }
const tsResult = tsProject.src() const tsResult = tsProject.src()
.pipe(tsProject()); .pipe(tsProject());
@ -21,25 +20,25 @@ gulp.task('scripts', () => {
const jsFiles = gulp.src(['src/electron/**/*.js', 'src/electron/**/*.cjs']); const jsFiles = gulp.src(['src/electron/**/*.js', 'src/electron/**/*.cjs']);
return tsResult.js return tsResult.js
.pipe(gulp.dest('dist/dev')) .pipe(gulp.dest('dist/electron'))
.on('end', () => { .on('end', () => {
jsFiles.pipe(gulp.dest('dist/dev')); jsFiles.pipe(gulp.dest('dist/electron'));
}); });
}); });
gulp.task('assets', () => { gulp.task('assets', () => {
return gulp.src('src/electron/assets/**/*', { encoding: false }) return gulp.src('src/electron/assets/**/*', { encoding: false })
.pipe(gulp.dest('dist/dev/assets')); .pipe(gulp.dest('dist/electron/assets'));
}); });
gulp.task('binary', () => { gulp.task('binary', () => {
return gulp.src('bin/**/*', { encoding: false }) return gulp.src('bin/**/*', { encoding: false })
.pipe(gulp.dest('dist/dev/bin')); .pipe(gulp.dest('dist/electron/bin'));
}); });
gulp.task("locales", () => { gulp.task("locales", () => {
return gulp.src('i18n/**/*') return gulp.src('i18n/**/*')
.pipe(gulp.dest('dist/dev/i18n')); .pipe(gulp.dest('dist/electron/i18n'));
}) })
gulp.task('build', gulp.series('clean', 'scripts', 'assets', 'binary', 'locales')); gulp.task('build', gulp.series('clean', 'scripts', 'assets', 'binary', 'locales'));

View File

@ -1,23 +1,23 @@
{ {
"name": "openrewind", "name": "openrewind",
"version": "0.3.0", "version": "0.3.1",
"type": "module", "type": "module",
"description": "Your second brain, superpowered.", "description": "Your second brain, superpowered.",
"main": "dist/dev/index.js", "main": "dist/electron/index.js",
"scripts": { "scripts": {
"dev": "cross-env NODE_ENV=dev bun run dev:all", "dev": "cross-env NODE_ENV=dev bun run dev:all",
"dev:all": "concurrently -n=react,electron -c='#ff3e00',blue \"bun run dev:react\" \"bun run dev:electron\"", "dev:all": "concurrently -n=react,electron -c='#ff3e00',blue \"bun run dev:react\" \"bun run dev:electron\"",
"dev:react": "vite dev", "dev:react": "vite dev",
"dev:electron": "bunx gulp build && electron dist/dev/index.js", "dev:electron": "bunx gulp build && electron dist/electron/index.js",
"build:react": "vite build", "build:react": "vite build",
"build:app": "bunx gulp build", "build:app": "bunx gulp build",
"build:electron": "electron-builder", "build:electron": "electron-builder"
"start": "cross-env NODE_ENV=production bun run start:all"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@electron/remote": "^2.1.2",
"@unly/universal-language-detector": "^2.0.3", "@unly/universal-language-detector": "^2.0.3",
"better-sqlite3": "^11.6.0", "better-sqlite3": "^11.6.0",
"electron-context-menu": "^4.0.4", "electron-context-menu": "^4.0.4",
@ -39,7 +39,8 @@
"react-router-dom": "^7.0.1", "react-router-dom": "^7.0.1",
"sqlite3": "^5.1.7", "sqlite3": "^5.1.7",
"sqlstring": "^2.3.3", "sqlstring": "^2.3.3",
"vite-tsconfig-paths": "^5.1.3" "vite-tsconfig-paths": "^5.1.3",
"screenshot-desktop": "^1.15.0"
}, },
"devDependencies": { "devDependencies": {
"@electron/rebuild": "^3.7.1", "@electron/rebuild": "^3.7.1",
@ -57,6 +58,7 @@
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"del": "^8.0.0", "del": "^8.0.0",
"electron": "^33.2.0", "electron": "^33.2.0",
"electron-build": "^0.0.3",
"electron-builder": "^25.1.8", "electron-builder": "^25.1.8",
"eslint": "^9.13.0", "eslint": "^9.13.0",
"eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-hooks": "^5.0.0",
@ -66,7 +68,6 @@
"gulp-clean": "^0.4.0", "gulp-clean": "^0.4.0",
"gulp-typescript": "6.0.0-alpha.1", "gulp-typescript": "6.0.0-alpha.1",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"screenshot-desktop": "^1.15.0",
"tailwindcss": "^3.4.15", "tailwindcss": "^3.4.15",
"typescript": "~5.6.2", "typescript": "~5.6.2",
"typescript-eslint": "^8.11.0", "typescript-eslint": "^8.11.0",

View File

@ -8,10 +8,59 @@ import Title from "components/settings/Title.tsx";
import OpenSourceNote from "components/settings/OpenSourceNote.tsx"; import OpenSourceNote from "components/settings/OpenSourceNote.tsx";
import EnvironmentDetails from "components/settings/EnvironmentDetails.tsx"; import EnvironmentDetails from "components/settings/EnvironmentDetails.tsx";
function showFrame() {
return navigator.userAgent.includes("Mac");
}
interface SettingsGroupRefs { interface SettingsGroupRefs {
[key: string]: HTMLDivElement; [key: string]: HTMLDivElement;
} }
function TitleBar() {
const { t } = useTranslation();
if (showFrame()) {
return (
<div className="w-full flex items-center justify-center h-9" id="title-bar">
{t("settings.title")}
</div>
);
} else {
return (
<div className="w-full h-9">
<div
className="w-[calc(100%-44px)] h-9 absolute left-[22px] flex justify-center"
id="title-bar"
>
<span className="self-center">{t("settings.title")}</span>
</div>
<div
className="z-50 absolute right-2.5 top-2.5 bg-red-500 hover:bg-rose-400 h-3 w-3 rounded-full"
onClick={() => {
console.log(window.settingsWindow)
window.settingsWindow.close();
}}
>
<svg
className="hover:opacity-100 opacity-0"
xmlns="http://www.w3.org/2000/svg"
width="12"
height="12"
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeWidth="2"
d="m8.464 15.535l7.072-7.07m-7.072 0l7.072 7.07"
/>
</svg>
</div>
</div>
);
}
}
export default function SettingsPage() { export default function SettingsPage() {
const { t } = useTranslation(); const { t } = useTranslation();
const [groupRefs, setGroupRefs] = useState<SettingsGroupRefs>({}); const [groupRefs, setGroupRefs] = useState<SettingsGroupRefs>({});
@ -29,18 +78,20 @@ export default function SettingsPage() {
const key = groupName as keyof typeof groupRefs; const key = groupName as keyof typeof groupRefs;
console.log(groupRefs[key]); console.log(groupRefs[key]);
if (!groupRefs[key]) return; if (!groupRefs[key]) return;
containerRef.current!.scrollTop = groupRefs[key].getBoundingClientRect().top - containerRef.current!.scrollTop =
groupRefs[key].getBoundingClientRect().top -
titleBarRef.current!.getBoundingClientRect().height; titleBarRef.current!.getBoundingClientRect().height;
} }
return ( return (
<> <>
<title>{t("settings.title")}</title> <title>{t("settings.title")}</title>
<div className="w-full h-auto bg-white dark:bg-gray-800 !bg-opacity-80 flex flex-col <div
dark:text-white font-semibold fixed z-10 backdrop-blur-lg text-[.9rem]" ref={titleBarRef}> className="w-full h-auto bg-white dark:bg-gray-800 !bg-opacity-80 flex flex-col
<div className="w-full flex items-center justify-center h-9" id="title-bar"> dark:text-white font-semibold fixed z-10 backdrop-blur-lg text-[.9rem]"
{t("settings.title")} ref={titleBarRef}
</div> >
<TitleBar />
<div className="h-[4.5rem] pt-0 pb-2"> <div className="h-[4.5rem] pt-0 pb-2">
<div className="w-full h-full px-20 flex items-center justify-center gap-2"> <div className="w-full h-full px-20 flex items-center justify-center gap-2">
<MenuItem <MenuItem
@ -56,19 +107,23 @@ export default function SettingsPage() {
</div> </div>
</div> </div>
</div> </div>
<div className="h-full bg-slate-100 dark:bg-gray-900 w-full scroll-smooth <div
relative dark:text-white pt-28 pb-12 px-10 overflow-auto" ref={containerRef} id="settings-scroll-container"> className="h-full bg-slate-100 dark:bg-gray-900 w-full scroll-smooth
relative dark:text-white pt-28 pb-12 px-10 overflow-auto"
ref={containerRef}
id="settings-scroll-container"
>
<SettingsGroup groupName="screen" addGroupRef={addGroupRef}> <SettingsGroup groupName="screen" addGroupRef={addGroupRef}>
<Title i18nKey="settings.screen-recording"/> <Title i18nKey="settings.screen-recording" />
<div className="flex"> <div className="flex">
<p>Nothing yet.</p> <p>Nothing yet.</p>
</div> </div>
</SettingsGroup> </SettingsGroup>
<SettingsGroup groupName="about" addGroupRef={addGroupRef}> <SettingsGroup groupName="about" addGroupRef={addGroupRef}>
<Title i18nKey={"settings.about"}/> <Title i18nKey={"settings.about"} />
<IconWithText/> <IconWithText />
<OpenSourceNote/> <OpenSourceNote />
<EnvironmentDetails/> <EnvironmentDetails />
</SettingsGroup> </SettingsGroup>
</div> </div>
</> </>

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

View File

@ -3,8 +3,17 @@ import Database from "better-sqlite3";
import { __dirname } from "../dirname.js"; import { __dirname } from "../dirname.js";
import { getDatabasePath } from "../utils/backend.js"; import { getDatabasePath } from "../utils/backend.js";
function getLibSimpleExtensionPath(): string { function getLibSimpleExtensionPath() {
return path.join(__dirname, "bin", process.platform, "libsimple/libsimple.dylib"); switch (process.platform) {
case "win32":
return path.join(__dirname, "bin", process.platform, "libsimple", "simple.dll");
case "darwin":
return path.join(__dirname, "bin", process.platform, "libsimple", "libsimple.dylib");
case "linux":
return path.join(__dirname, "bin", process.platform, "libsimple", "libsimple.so");
default:
throw new Error("Unsupported platform");
}
} }
export function initDatabase() { export function initDatabase() {

View File

@ -2,6 +2,7 @@ import { app, BrowserWindow, screen } from "electron";
import { join } from "path"; import { join } from "path";
import { __dirname } from "./dirname.js"; import { __dirname } from "./dirname.js";
import windowStateManager from "electron-window-state"; import windowStateManager from "electron-window-state";
import { hideDock, showDock } from "./utils/electron.js";
function loadURL(window: BrowserWindow, path = "", vitePort: string) { function loadURL(window: BrowserWindow, path = "", vitePort: string) {
const dev = !app.isPackaged; const dev = !app.isPackaged;
@ -24,6 +25,21 @@ export function createSettingsWindow(vitePort: string, closeCallBack: Function)
defaultWidth: 650, defaultWidth: 650,
defaultHeight: 550 defaultHeight: 550
}); });
const enableFrame = process.platform === "darwin";
let icon
switch (process.platform) {
case "darwin":
icon = undefined;
break;
case "win32":
icon = join(__dirname, "assets/icon.ico");
break;
case "linux":
icon = join(__dirname, "assets/icon.png");
break;
default:
icon = undefined;
}
const window = new BrowserWindow({ const window = new BrowserWindow({
width: 650, width: 650,
height: 550, height: 550,
@ -35,10 +51,12 @@ export function createSettingsWindow(vitePort: string, closeCallBack: Function)
titleBarStyle: "hiddenInset", titleBarStyle: "hiddenInset",
resizable: false, resizable: false,
show: false, show: false,
frame: enableFrame,
icon: icon,
}); });
windowState.manage(window); windowState.manage(window);
window.on("show", () => { window.on("show", () => {
app.dock.show(); showDock();
}); });
window.on("close", (e) => { window.on("close", (e) => {
window.hide(); window.hide();
@ -47,7 +65,7 @@ export function createSettingsWindow(vitePort: string, closeCallBack: Function)
}); });
window.once("close", () => { window.once("close", () => {
window.hide(); window.hide();
app.dock.hide(); hideDock();
}); });
loadURL(window, "settings", vitePort); loadURL(window, "settings", vitePort);
return window; return window;

View File

@ -1,4 +1,4 @@
import { app, BrowserWindow, globalShortcut, Menu, nativeImage, screen, Tray } from "electron"; import { app, BrowserWindow, globalShortcut, ipcMain, Menu, nativeImage, screen, Tray } from "electron";
import contextMenu from "electron-context-menu"; import contextMenu from "electron-context-menu";
import { join } from "path"; import { join } from "path";
import initI18n from "./i18n.js"; import initI18n from "./i18n.js";
@ -7,6 +7,7 @@ import { initDatabase } from "./backend/init.js";
import { Database } from "better-sqlite3"; import { Database } from "better-sqlite3";
import { startScreenshotLoop } from "./backend/screenshot.js"; import { startScreenshotLoop } from "./backend/screenshot.js";
import { __dirname } from "./dirname.js"; import { __dirname } from "./dirname.js";
import { hideDock } from "./utils/electron.js";
const i18n = initI18n(); const i18n = initI18n();
@ -66,7 +67,7 @@ contextMenu({
}); });
app.once("ready", () => { app.once("ready", () => {
app.dock.hide(); hideDock();
}); });
app.on("activate", () => {}); app.on("activate", () => {});
@ -84,3 +85,7 @@ app.on("ready", () => {
// app.on("window-all-closed", () => { // app.on("window-all-closed", () => {
// if (process.platform !== "darwin") app.quit(); // if (process.platform !== "darwin") app.quit();
// }); // });
ipcMain.on('close-settings', () => {
settingsWindow?.hide();
});

View File

@ -1,8 +1,8 @@
const { contextBridge } = require('electron') const { contextBridge, ipcRenderer } = require("electron");
const os = require('os'); const os = require("os");
const osName = require('./os-name.cjs'); const osName = require("./os-name.cjs");
contextBridge.exposeInMainWorld('versions', { contextBridge.exposeInMainWorld("versions", {
node: () => process.versions.node, node: () => process.versions.node,
chrome: () => process.versions.chrome, chrome: () => process.versions.chrome,
electron: () => process.versions.electron, electron: () => process.versions.electron,
@ -10,4 +10,10 @@ contextBridge.exposeInMainWorld('versions', {
return `${os.platform()} ${os.release()}`; return `${os.platform()} ${os.release()}`;
}, },
osDisplay: osName osDisplay: osName
}) });
contextBridge.exposeInMainWorld("settingsWindow", {
close: () => {
ipcRenderer.send("close-settings", {});
}
});

View File

@ -0,0 +1,15 @@
import { app } from "electron";
export function hideDock(){
if (process.platform === 'darwin') {
// Hide the dock icon on macOS
app.dock.hide();
}
}
export function showDock(){
if (process.platform === 'darwin') {
// Show the dock icon on macOS
app.dock.show();
}
}

3
src/global.d.ts vendored
View File

@ -12,5 +12,8 @@ interface Window {
api: { api: {
send: (channel: any, data: any) => void, send: (channel: any, data: any) => void,
receive: (channel: any, func: any) => void receive: (channel: any, func: any) => void
},
settingsWindow: {
close: () => void,
} }
} }

View File

@ -3,7 +3,7 @@
"target": "ESNext", "target": "ESNext",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
"outDir": "./dist/dev", "outDir": "./dist/electron",
"rootDir": "./src/electron", "rootDir": "./src/electron",
"strict": true, "strict": true,
"esModuleInterop": true, "esModuleInterop": true,