diff --git a/dist-electron/main/main.js b/dist-electron/main/main.js index 19437d3..a8c04dd 100644 --- a/dist-electron/main/main.js +++ b/dist-electron/main/main.js @@ -1,7 +1,2 @@ -"use strict"; -require("electron"); -require("./main-Cg0vBGtL.js"); -require("electron-squirrel-startup"); -require("electron-log"); -require("bytenode"); -require("axios"); +require('bytenode') +require('./main.jsc') \ No newline at end of file diff --git a/dist-electron/preload/preload.js b/dist-electron/preload/preload.js index 2008e6b..40eab68 100644 --- a/dist-electron/preload/preload.js +++ b/dist-electron/preload/preload.js @@ -1,128 +1 @@ -"use strict"; -const electron = require("electron"); -var IPC_EVENTS = /* @__PURE__ */ ((IPC_EVENTS2) => { - IPC_EVENTS2["HOST_API_FETCH"] = "hostapi:fetch"; - IPC_EVENTS2["HOST_API_TOKEN"] = "hostapi:token"; - IPC_EVENTS2["EXTERNAL_OPEN"] = "external-open"; - IPC_EVENTS2["APP_SET_FRAMELESS"] = "app:set-frameless"; - IPC_EVENTS2["APP_LOAD_PAGE"] = "app:load-page"; - IPC_EVENTS2["LOG_TO_MAIN"] = "log-to-main"; - IPC_EVENTS2["READ_FILE"] = "read-file"; - IPC_EVENTS2["INVOKE"] = "ipc:invoke"; - IPC_EVENTS2["INVOKE_ASYNC"] = "ipc:invokeAsync"; - IPC_EVENTS2["APP_MINIMIZE"] = "app:minimize"; - IPC_EVENTS2["APP_MAXIMIZE"] = "app:maximize"; - IPC_EVENTS2["APP_QUIT"] = "app:quit"; - IPC_EVENTS2["FILE_READ"] = "file:read"; - IPC_EVENTS2["FILE_WRITE"] = "file:write"; - IPC_EVENTS2["CUSTOM_EVENT"] = "custom:event"; - IPC_EVENTS2["TIME_UPDATE"] = "time:update"; - IPC_EVENTS2["RENDERER_IS_READY"] = "renderer-ready"; - IPC_EVENTS2["SHOW_CONTEXT_MENU"] = "show-context-menu"; - IPC_EVENTS2["START_A_DIALOGUE"] = "start-a-dialogue"; - IPC_EVENTS2["OPEN_WINDOW"] = "open-window"; - IPC_EVENTS2["LOG_DEBUG"] = "log-debug"; - IPC_EVENTS2["LOG_INFO"] = "log-info"; - IPC_EVENTS2["LOG_WARN"] = "log-warn"; - IPC_EVENTS2["LOG_ERROR"] = "log-error"; - IPC_EVENTS2["CONFIG_UPDATED"] = "config-updated"; - IPC_EVENTS2["SET_CONFIG"] = "set-config"; - IPC_EVENTS2["GET_CONFIG"] = "get-config"; - IPC_EVENTS2["UPDATE_CONFIG"] = "update-config"; - IPC_EVENTS2["SET_THEME_MODE"] = "set-theme-mode"; - IPC_EVENTS2["GET_THEME_MODE"] = "get-theme-mode"; - IPC_EVENTS2["IS_DARK_THEME"] = "is-dark-theme"; - IPC_EVENTS2["THEME_MODE_UPDATED"] = "theme-mode-updated"; - IPC_EVENTS2["EXECUTE_SCRIPT"] = "execute-script"; - IPC_EVENTS2["TASK_PROGRESS"] = "task:progress"; - IPC_EVENTS2["TASK_STARTED"] = "task:started"; - IPC_EVENTS2["TASK_COMPLETED"] = "task:completed"; - IPC_EVENTS2["OPEN_CHANNEL"] = "open-channel"; - IPC_EVENTS2["SCRIPT_LIST"] = "script:list"; - IPC_EVENTS2["SCRIPT_GET"] = "script:get"; - IPC_EVENTS2["SCRIPT_SAVE"] = "script:save"; - IPC_EVENTS2["SCRIPT_DELETE"] = "script:delete"; - IPC_EVENTS2["SCRIPT_TOGGLE"] = "script:toggle"; - IPC_EVENTS2["SCRIPT_RUN"] = "script:run"; - IPC_EVENTS2["SCRIPT_RECORD_START"] = "script:record-start"; - IPC_EVENTS2["SCRIPT_RECORD_STOP"] = "script:record-stop"; - IPC_EVENTS2["SCRIPT_CODEGEN"] = "script:codegen"; - IPC_EVENTS2["GATEWAY_RPC"] = "gateway:rpc"; - IPC_EVENTS2["GATEWAY_EVENT"] = "gateway:event"; - IPC_EVENTS2["UPDATE_CHECK"] = "update:check"; - IPC_EVENTS2["UPDATE_DOWNLOAD"] = "update:download"; - IPC_EVENTS2["UPDATE_INSTALL"] = "update:install"; - IPC_EVENTS2["UPDATE_VERSION"] = "update:version"; - IPC_EVENTS2["UPDATE_STATUS_CHANGED"] = "update:status-changed"; - return IPC_EVENTS2; -})(IPC_EVENTS || {}); -const api = { - versions: process.versions, - external: { - open: (url) => electron.ipcRenderer.invoke("external-open", url) - }, - platform: process.platform, - windowMinimize: () => electron.ipcRenderer.invoke("window:minimize"), - windowMaximize: () => electron.ipcRenderer.invoke("window:maximize"), - windowClose: () => electron.ipcRenderer.invoke("window:close"), - windowIsMaximized: () => electron.ipcRenderer.invoke("window:isMaximized"), - viewIsReady: () => electron.ipcRenderer.send(IPC_EVENTS.RENDERER_IS_READY), - app: { - setFrameless: (route) => electron.ipcRenderer.invoke(IPC_EVENTS.APP_SET_FRAMELESS, route), - loadPage: (page) => electron.ipcRenderer.invoke(IPC_EVENTS.APP_LOAD_PAGE, page) - }, - // 通过 IPC 调用主进程 - readFile: (filePath) => electron.ipcRenderer.invoke(IPC_EVENTS.READ_FILE, filePath), - // 异步调用(映射为 electron 的 invoke) - invoke: (channel, ...args) => electron.ipcRenderer.invoke(channel, ...args), - // 异步调用(为了兼容老代码) - invokeAsync: (channel, ...args) => electron.ipcRenderer.invoke(channel, ...args), - // 监听主进程消息 - on: (event, callback) => { - const subscription = (_event, ...args) => callback(...args); - electron.ipcRenderer.on(event, subscription); - return () => electron.ipcRenderer.removeListener(event, subscription); - }, - // 发送消息到主进程 - send: (channel, ...args) => electron.ipcRenderer.send(channel, ...args), - // 发送日志 - logger: { - debug: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_DEBUG, message, ...meta), - info: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_INFO, message, ...meta), - warn: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_WARN, message, ...meta), - error: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_ERROR, message, ...meta) - }, - // 执行脚本 - executeScript: (params) => electron.ipcRenderer.invoke(IPC_EVENTS.EXECUTE_SCRIPT, params), - // 任务事件 - onTaskProgress: (cb) => { - const subscription = (_event, payload) => cb(payload); - electron.ipcRenderer.on(IPC_EVENTS.TASK_PROGRESS, subscription); - return () => electron.ipcRenderer.removeListener(IPC_EVENTS.TASK_PROGRESS, subscription); - }, - onTaskStarted: (cb) => { - const subscription = (_event, payload) => cb(payload); - electron.ipcRenderer.on(IPC_EVENTS.TASK_STARTED, subscription); - return () => electron.ipcRenderer.removeListener(IPC_EVENTS.TASK_STARTED, subscription); - }, - onTaskCompleted: (cb) => { - const subscription = (_event, payload) => cb(payload); - electron.ipcRenderer.on(IPC_EVENTS.TASK_COMPLETED, subscription); - return () => electron.ipcRenderer.removeListener(IPC_EVENTS.TASK_COMPLETED, subscription); - }, - // 打开渠道 - openChannel: (channels) => electron.ipcRenderer.invoke(IPC_EVENTS.OPEN_CHANNEL, channels), - // 脚本管理 - scriptApi: { - list: () => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_LIST), - get: (id) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_GET, id), - save: (input) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_SAVE, input), - delete: (id) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_DELETE, id), - toggle: (id, enabled) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_TOGGLE, id, enabled), - run: (id) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RUN, id), - startRecording: (url) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RECORD_START, url), - stopRecording: () => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_RECORD_STOP), - codegen: (id, url) => electron.ipcRenderer.invoke(IPC_EVENTS.SCRIPT_CODEGEN, id, url) - } -}; -electron.contextBridge.exposeInMainWorld("api", api); +"use strict";const r=require("electron");var i=(e=>(e.HOST_API_FETCH="hostapi:fetch",e.HOST_API_TOKEN="hostapi:token",e.EXTERNAL_OPEN="external-open",e.APP_SET_FRAMELESS="app:set-frameless",e.APP_LOAD_PAGE="app:load-page",e.LOG_TO_MAIN="log-to-main",e.READ_FILE="read-file",e.INVOKE="ipc:invoke",e.INVOKE_ASYNC="ipc:invokeAsync",e.APP_MINIMIZE="app:minimize",e.APP_MAXIMIZE="app:maximize",e.APP_QUIT="app:quit",e.FILE_READ="file:read",e.FILE_WRITE="file:write",e.CUSTOM_EVENT="custom:event",e.TIME_UPDATE="time:update",e.RENDERER_IS_READY="renderer-ready",e.SHOW_CONTEXT_MENU="show-context-menu",e.START_A_DIALOGUE="start-a-dialogue",e.OPEN_WINDOW="open-window",e.LOG_DEBUG="log-debug",e.LOG_INFO="log-info",e.LOG_WARN="log-warn",e.LOG_ERROR="log-error",e.CONFIG_UPDATED="config-updated",e.SET_CONFIG="set-config",e.GET_CONFIG="get-config",e.UPDATE_CONFIG="update-config",e.SET_THEME_MODE="set-theme-mode",e.GET_THEME_MODE="get-theme-mode",e.IS_DARK_THEME="is-dark-theme",e.THEME_MODE_UPDATED="theme-mode-updated",e.EXECUTE_SCRIPT="execute-script",e.TASK_PROGRESS="task:progress",e.TASK_STARTED="task:started",e.TASK_COMPLETED="task:completed",e.OPEN_CHANNEL="open-channel",e.SCRIPT_LIST="script:list",e.SCRIPT_GET="script:get",e.SCRIPT_SAVE="script:save",e.SCRIPT_DELETE="script:delete",e.SCRIPT_TOGGLE="script:toggle",e.SCRIPT_RUN="script:run",e.SCRIPT_RECORD_START="script:record-start",e.SCRIPT_RECORD_STOP="script:record-stop",e.SCRIPT_CODEGEN="script:codegen",e.GATEWAY_RPC="gateway:rpc",e.GATEWAY_EVENT="gateway:event",e.UPDATE_CHECK="update:check",e.UPDATE_DOWNLOAD="update:download",e.UPDATE_INSTALL="update:install",e.UPDATE_VERSION="update:version",e.UPDATE_STATUS_CHANGED="update:status-changed",e))(i||{});const p={versions:process.versions,external:{open:e=>r.ipcRenderer.invoke("external-open",e)},platform:process.platform,windowMinimize:()=>r.ipcRenderer.invoke("window:minimize"),windowMaximize:()=>r.ipcRenderer.invoke("window:maximize"),windowClose:()=>r.ipcRenderer.invoke("window:close"),windowIsMaximized:()=>r.ipcRenderer.invoke("window:isMaximized"),viewIsReady:()=>r.ipcRenderer.send(i.RENDERER_IS_READY),app:{setFrameless:e=>r.ipcRenderer.invoke(i.APP_SET_FRAMELESS,e),loadPage:e=>r.ipcRenderer.invoke(i.APP_LOAD_PAGE,e)},readFile:e=>r.ipcRenderer.invoke(i.READ_FILE,e),invoke:(e,...n)=>r.ipcRenderer.invoke(e,...n),invokeAsync:(e,...n)=>r.ipcRenderer.invoke(e,...n),on:(e,n)=>{const t=(o,...R)=>n(...R);return r.ipcRenderer.on(e,t),()=>r.ipcRenderer.removeListener(e,t)},send:(e,...n)=>r.ipcRenderer.send(e,...n),logger:{debug:(e,...n)=>r.ipcRenderer.send(i.LOG_DEBUG,e,...n),info:(e,...n)=>r.ipcRenderer.send(i.LOG_INFO,e,...n),warn:(e,...n)=>r.ipcRenderer.send(i.LOG_WARN,e,...n),error:(e,...n)=>r.ipcRenderer.send(i.LOG_ERROR,e,...n)},executeScript:e=>r.ipcRenderer.invoke(i.EXECUTE_SCRIPT,e),onTaskProgress:e=>{const n=(t,o)=>e(o);return r.ipcRenderer.on(i.TASK_PROGRESS,n),()=>r.ipcRenderer.removeListener(i.TASK_PROGRESS,n)},onTaskStarted:e=>{const n=(t,o)=>e(o);return r.ipcRenderer.on(i.TASK_STARTED,n),()=>r.ipcRenderer.removeListener(i.TASK_STARTED,n)},onTaskCompleted:e=>{const n=(t,o)=>e(o);return r.ipcRenderer.on(i.TASK_COMPLETED,n),()=>r.ipcRenderer.removeListener(i.TASK_COMPLETED,n)},openChannel:e=>r.ipcRenderer.invoke(i.OPEN_CHANNEL,e),scriptApi:{list:()=>r.ipcRenderer.invoke(i.SCRIPT_LIST),get:e=>r.ipcRenderer.invoke(i.SCRIPT_GET,e),save:e=>r.ipcRenderer.invoke(i.SCRIPT_SAVE,e),delete:e=>r.ipcRenderer.invoke(i.SCRIPT_DELETE,e),toggle:(e,n)=>r.ipcRenderer.invoke(i.SCRIPT_TOGGLE,e,n),run:e=>r.ipcRenderer.invoke(i.SCRIPT_RUN,e),startRecording:e=>r.ipcRenderer.invoke(i.SCRIPT_RECORD_START,e),stopRecording:()=>r.ipcRenderer.invoke(i.SCRIPT_RECORD_STOP),codegen:(e,n)=>r.ipcRenderer.invoke(i.SCRIPT_CODEGEN,e,n)}};r.contextBridge.exposeInMainWorld("api",p); diff --git a/dist/index.html b/dist/index.html index 2f7a431..dc28771 100644 --- a/dist/index.html +++ b/dist/index.html @@ -8,8 +8,8 @@ http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: http://8.138.234.141 https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn" /> - - + +
diff --git a/electron/service/window-service.ts b/electron/service/window-service.ts index ca8057a..2ae4585 100644 --- a/electron/service/window-service.ts +++ b/electron/service/window-service.ts @@ -266,7 +266,7 @@ class WindowService { public focus(target: BrowserWindow | void | null) { if (!target) return; const name = this.getName(target); - if (target?.isMaximized()) { + if (target?.isMinimized()) { target?.restore(); logManager.debug(`Window ${name} restored and focused`); } else { diff --git a/global.d.ts b/global.d.ts index 2bf9e5f..9c4d0e2 100644 --- a/global.d.ts +++ b/global.d.ts @@ -147,9 +147,9 @@ declare global { open: (url: string) => Promise }, platform: string; - windowMinimize: () => void; - windowMaximize: () => void; - windowClose: () => void; + windowMinimize: () => Promise; + windowMaximize: () => Promise; + windowClose: () => Promise; windowIsMaximized: () => Promise; viewIsReady: () => void; app: { diff --git a/src/components/layout/TitleBar.tsx b/src/components/layout/TitleBar.tsx index 36d5b7f..fa3ee8c 100644 --- a/src/components/layout/TitleBar.tsx +++ b/src/components/layout/TitleBar.tsx @@ -1,17 +1,24 @@ +import { useEffect, useState } from 'react'; +import { Copy, Minus, Square, X } from 'lucide-react'; import { useI18n } from '../../i18n'; type TitleBarProps = { variant?: 'default' | 'light'; + controlsTheme?: 'default' | 'white'; }; -export default function TitleBar({ variant = 'default' }: TitleBarProps) { +type WindowsTitleBarProps = { + variant: TitleBarProps['variant']; + controlsTheme: NonNullable; + closeLabel: string; + maximizeLabel: string; + minimizeLabel: string; + restoreLabel: string; +}; + +export default function TitleBar({ variant = 'default', controlsTheme }: TitleBarProps) { const { t } = useI18n(); - const platform = (window as any).api?.platform ?? ''; - - if (platform === 'linux') return null; - - const iconColorClass = - variant === 'light' ? 'text-white' : 'text-[#525866] dark:text-gray-300'; + const platform = window.api?.platform ?? ''; const borderColorClass = variant === 'light' ? 'border-b-white/30' : 'border-b-gray-300 dark:border-gray-700'; @@ -24,6 +31,64 @@ export default function TitleBar({ variant = 'default' }: TitleBarProps) { ); } + if (platform !== 'win32') { + return null; + } + + return ( + + ); +} + +function WindowsTitleBar({ + variant = 'default', + controlsTheme, + closeLabel, + maximizeLabel, + minimizeLabel, + restoreLabel, +}: WindowsTitleBarProps) { + const [maximized, setMaximized] = useState(false); + + useEffect(() => { + void syncMaximizedState(); + }, []); + + const syncMaximizedState = async () => { + const nextState = await window.api.windowIsMaximized(); + setMaximized(Boolean(nextState)); + }; + + const handleMinimize = () => { + void window.api.windowMinimize(); + }; + + const handleMaximize = async () => { + await window.api.windowMaximize(); + await syncMaximizedState(); + }; + + const handleClose = () => { + void window.api.windowClose(); + }; + + const useWhiteControls = controlsTheme === 'white'; + const iconColorClass = useWhiteControls ? 'text-white/95' : 'text-[#525866] dark:text-gray-300'; + const borderColorClass = + variant === 'light' ? 'border-b-white/30' : 'border-b-gray-300 dark:border-gray-700'; + const buttonClass = [ + 'flex h-full w-11 items-center justify-center transition-colors', + useWhiteControls ? 'hover:bg-white/15 hover:text-white' : 'hover:bg-[#999] hover:text-white', + iconColorClass, + ].join(' '); + return (
diff --git a/src/pages/Login/index.tsx b/src/pages/Login/index.tsx index e96e53b..34f09ba 100644 --- a/src/pages/Login/index.tsx +++ b/src/pages/Login/index.tsx @@ -144,7 +144,9 @@ export default function LoginPage() { /> ) : null} - +
+ +