Compare commits

...

5 Commits

Author SHA1 Message Date
谢亚昕 9a9eef5a7c good 5 days ago
谢亚昕 fe33e9fd1a 优化组件声明文件中未使用的图标组件 6 days ago
谢亚昕 9a5776d586 重构了代码,主进程和渲染进程交互方式不变 6 days ago
谢亚昕 f1833df97b add 1 week ago
谢亚昕 403e6608d3 ad 2 weeks ago
  1. 113
      .github/workflows/Build.yml
  2. 0
      backup/Tabs/index.ts
  3. 0
      backup/Tabs/main/command.ts
  4. 3
      changelog/0.0.1.md
  5. 9
      electron.vite.config.ts
  6. 6
      package.json
  7. 5
      packages/base/api/abstract.ts
  8. 0
      packages/base/api/browser.ts
  9. 2
      packages/base/api/electron.ts
  10. 26
      packages/base/event/main/index.ts
  11. 0
      packages/helper/db/custom.ts
  12. 20
      packages/helper/db/index.ts
  13. 14
      packages/helper/updater/common.ts
  14. 97
      packages/helper/updater/main/index.ts
  15. 3
      packages/locales/main.ts
  16. 3
      packages/logger/main.ts
  17. 3
      packages/logger/renderer-error.ts
  18. 7
      packages/setting/common.ts
  19. 8
      packages/setting/main.ts
  20. 6
      packages/setting/main/event.ts
  21. 12
      packages/utils/main/session/cookies.ts
  22. 12
      packages/utils/main/session/index.ts
  23. 102
      pnpm-lock.yaml
  24. 5
      src/common/event/PlatForm/hook.ts
  25. 5
      src/common/event/Snippet/hook.ts
  26. 18
      src/common/event/Snippet/index.ts
  27. 16
      src/common/event/Updater/hook.ts
  28. 7
      src/common/readme.md
  29. 165
      src/main/App copy.ts
  30. 3
      src/main/App.ts
  31. 2
      src/main/_ioc.ts
  32. 7
      src/main/command/PlatForm/command.ts
  33. 6
      src/main/command/Setting/command.ts
  34. 8
      src/main/command/Setting/type.d.ts
  35. 0
      src/main/command/Snippet/command.ts
  36. 8
      src/main/command/Updater/command.ts
  37. 18
      src/main/command/_ioc.ts
  38. 6
      src/main/controller/BasicService.ts
  39. 9
      src/main/modules/_ioc.ts
  40. 3
      src/preload/index.ts
  41. 0
      src/preload/plugin.ts
  42. 6
      src/renderer/about.html
  43. 12
      src/renderer/auto-imports.d.ts
  44. 9
      src/renderer/components.d.ts
  45. 28
      src/renderer/src/App.vue
  46. 13
      src/renderer/src/assets/style/_anim.scss
  47. 3
      src/renderer/src/assets/style/_common.scss
  48. 5
      src/renderer/src/assets/style/global/_index.scss
  49. 10
      src/renderer/src/bridge/PopupMenu.ts
  50. 57
      src/renderer/src/components/AdjustLine.vue
  51. 55
      src/renderer/src/components/CodeEditor/code-editor.vue
  52. 33
      src/renderer/src/components/CodeEditor/hook.ts
  53. 4
      src/renderer/src/components/CodeEditor/monaco.ts
  54. 6
      src/renderer/src/components/CodeEditor/utils.ts
  55. 2
      src/renderer/src/composables/Api/Platform/_/index.ts
  56. 41
      src/renderer/src/composables/Api/Platform/useApiPlatForm.ts
  57. 2
      src/renderer/src/composables/Api/Setting/_/index.ts
  58. 12
      src/renderer/src/composables/Api/Setting/useApiSetting.ts
  59. 2
      src/renderer/src/composables/Api/Updater/_/index.ts
  60. 70
      src/renderer/src/composables/Api/Updater/useApiUpdater.ts
  61. 3
      src/renderer/src/composables/useTest.ts
  62. 15
      src/renderer/src/main.ts
  63. 48
      src/renderer/src/pages/index/index copy.vue
  64. 30
      src/renderer/src/pages/index/index.vue
  65. 136
      src/renderer/src/pages/setting.vue
  66. 42
      src/renderer/src/pages/setting/dev.vue
  67. 141
      src/renderer/src/pages/setting/index.vue
  68. 72
      src/renderer/src/pages/setting/update.vue
  69. 10
      src/renderer/src/router/index.ts
  70. 63
      src/renderer/src/ui/NavBar.vue
  71. 76
      src/renderer/src/ui/Update.vue
  72. 3
      src/renderer/typed-router.d.ts
  73. 31
      src/types/global.d.ts
  74. 3
      temp/dev.yml
  75. 11
      tsconfig.node.json
  76. 14
      tsconfig.web.json

113
.github/workflows/Build.yml

@ -0,0 +1,113 @@
# https://zhuanlan.zhihu.com/p/164901026
# https://www.antmoe.com/posts/18c087cf/
# https://zhuanlan.zhihu.com/p/348712087
# https://cloud.tencent.com/developer/article/1949574
# 此工作流的名字
name: Build
# 工作流的执行时机,可以设定为定时执行,每次push后执行,手动执行等
on:
# workflow_dispatch为在Github仓库的Actions面板中手动执行
# workflow_dispatch:
push:
branches:
- master
# 工作/任务,这里的工作是可以并行的。
jobs:
# 工作的名称“编译windows版”
build:
# 运行的操作系统 windows
runs-on: ${{ matrix.os }}
env:
GH_TOKEN: ${{ secrets.ELECTRON_TOKEN }}
IS_ACTIONS: true
strategy:
matrix:
# https://www.likecs.com/ask-314443.html
node-version: [18.17.1]
os: [windows-2022, ubuntu-latest]
# 步骤
steps:
# 使用预制action:拉取最新的代码
- uses: actions/checkout@v3
with:
ref: master
# https://pnpm.io/zh/continuous-integration/#github-actions
- uses: pnpm/action-setup@v2.2.4
name: Install pnpm
id: pnpm-install
with:
version: 8.7.6
# 安装node
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
# 安装python
- name: Use Python 3.9.13
uses: actions/setup-python@v4
with:
python-version: 3.9.13
env:
PYTHON_VERSION: 3.9.13
# https://docs.microsoft.com/zh-cn/visualstudio/releases/2017/vs2017-system-requirements-vs
# 将windows设置成windows-2016,2016要取消支持了,可换成2022
# - name: set msvs
# run: npm config set msvs_version 2022
# https://github.com/wxWidgets/wxWidgets/blob/master/.github/workflows/ci_msw.yml
# https://github.com/microsoft/setup-msbuild
- name: Add msbuild to PATH
if: matrix.os == 'windows-2022'
uses: microsoft/setup-msbuild@v1.1
with:
vs-prerelease: true
# 步骤一的名称:
- name: Build
# 该步骤运行的终端命令,运行编译命令
run: npm run build
# 步骤二的名称:将编译后的结果上传
# - name: Upload File
# # 使用预制action:上传文件,可以将执行路径打包成zip上传
# uses: actions/upload-artifact@v3
# with:
# # 上传后文件的名称
# name: windows
# # 打包的路径以及文件过滤,此为仅打包dist目录下的exe文件
# path: out/*exe
- name: 读取当前版本号
id: version
uses: ashley-taylor/read-json-property-action@v1.1
with:
path: ./dist/package.json
property: version
- name: 读取描述文件
id: description
uses: juliangruber/read-file-action@v1
with:
path: ./changelog/${{steps.version.outputs.value}}.md
# step5: cleanup artifacts in dist_electron
# - name: 清理不必要的资产
# run: |
# npx rimraf "out/!(*.exe|*.dmg)"
# - name: Generate release tag
# id: tag
# run: |
# echo "::set-output name=release_tag::UserBuild_$(date +"%Y.%m.%d_%H-%M")"
- name: Generate release tag
id: tag
run: |
echo "::set-output name=release_tag::v${{steps.version.outputs.value}}"
# echo "release_tag=v${{steps.version.outputs.value}}" >> $GITHUB_OUTPUT
- name: release # https://github.com/softprops/action-gh-release/issues/20
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.tag.outputs.release_tag }}
name: ${{ steps.tag.outputs.release_tag }}
files: "out/*exe,out/*dmg,out/*AppImage,out/*yml"
body: ${{steps.description.outputs.content}}
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.ELECTRON_TOKEN }}

0
src/common/event/Tabs/index.ts → backup/Tabs/index.ts

0
src/common/event/Tabs/main/command.ts → backup/Tabs/main/command.ts

3
changelog/0.0.1.md

@ -0,0 +1,3 @@
## 0.0.1
第一个版本

9
electron.vite.config.ts

@ -31,7 +31,7 @@ export default defineConfig({
lib: {
entry: {
index: resolve(__dirname, "./src/preload/index.ts"),
plugin: resolve(__dirname, "./src/preload/plugin.ts"),
// plugin: resolve(__dirname, "./src/preload/plugin.ts"),
},
},
},
@ -50,7 +50,7 @@ export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/assets/style/global" as *;\n`,
additionalData: `@use "@/assets/style/global/_index.scss";\n`,
api: "modern-compiler",
},
},
@ -95,13 +95,16 @@ export default defineConfig({
"@vueuse/core",
VueRouterAutoImports,
{
"vue3-toastify": ["toast"],
},
{
// add any other imports you were relying on
"vue-router/auto": ["useLink"],
},
"vue-i18n",
],
dts: true,
dirs: ["src/composables"],
dirs: ["src/composables/**/*.ts", "!src/composables/**/_/**/*.ts"],
vueTemplate: true,
}),
// https://github.com/antfu/vite-plugin-components

6
package.json

@ -51,6 +51,7 @@
"@vue/eslint-config-typescript": "^13.0.0",
"@vueuse/core": "^12.7.0",
"base": "workspace:*",
"bulma": "^1.0.4",
"debug": "^4.4.0",
"electron": "^31.7.7",
"electron-builder": "^24.13.3",
@ -73,18 +74,19 @@
"simplebar-vue": "^2.4.0",
"typescript": "^5.7.3",
"unocss": "^0.64.1",
"utils": "workspace:*",
"unplugin-auto-import": "^19.1.0",
"unplugin-icons": "^22.1.0",
"unplugin-vue-components": "^28.4.0",
"unplugin-vue-macros": "^2.14.2",
"unplugin-vue-router": "^0.11.2",
"utils": "workspace:*",
"vite": "^5.4.14",
"vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-vue-layouts": "^0.11.0",
"vue": "^3.5.13",
"vue-i18n": "^11.1.1",
"vue-router": "^4.5.0",
"vue-tsc": "^2.1.10"
"vue-tsc": "^2.1.10",
"vue3-toastify": "^0.2.8"
}
}

5
src/common/lib/abstract.ts → packages/base/api/abstract.ts

@ -1,5 +1,5 @@
import { ElectronApiClient } from "common/lib/electron"
import { BrowserApiClient } from "common/lib/browser"
import { ElectronApiClient } from "./electron"
import { BrowserApiClient } from "./browser"
import { BaseSingleton } from "base/index"
// 定义抽象 API 接口
@ -49,6 +49,7 @@ export class ApiFactory {
static getApiClient(): IApiClient {
if (this.instance instanceof NullApiClient) {
// 根据环境选择合适的 API 客户端
// @ts-ignore 忽略类型检查
if (window.api && window.electron) {
this.instance = new ElectronApiClient()
} else {

0
src/common/lib/browser.ts → packages/base/api/browser.ts

2
src/common/lib/electron.ts → packages/base/api/electron.ts

@ -1,3 +1,5 @@
// @ts-nocheck window.api 不需要检查
import { IApiClient } from "./abstract"
export class ElectronApiClient implements IApiClient {

26
packages/base/event/main/index.ts

@ -8,17 +8,31 @@ class FireEvent<T extends Record<string | symbol, FireFN>> {
console.log(`${key}: ${this.#events[key]}\n`)
})
}
on<S extends keyof T>(name: S, fn: T[S]) {
on<S extends keyof T | "*">(name: S, fn: S extends "*" ? (...argus: [keyof T, T[keyof T]]) => void : T[S]) {
if (!this.#events[name]) {
this.#events[name] = []
}
this.#events[name].push(fn)
this.#events[name].push(fn as any)
}
emit<S extends keyof T>(name: S, ...argu: Parameters<T[S]>) {
async emit<S extends keyof T>(name: S, ...argu: Parameters<T[S]>) {
if (this.#events[name]) {
this.#events[name].forEach(fn => {
fn(...argu)
})
const returnValues: any = []
for (let i = 0; i < this.#events[name].length; i++) {
const fn = this.#events[name][i]
let r
if (Object.prototype.toString.call(fn) === "[object AsyncFunction]") {
r = await fn(...argu)
} else {
r = fn(...argu)
}
returnValues.push(r)
}
}
if (this.#events["*"]) {
for (let i = 0; i < this.#events["*"].length; i++) {
const fn = this.#events["*"][i]
fn(name, ...argu)
}
}
}
off<S extends keyof T>(name: S, fn?: T[S]) {

0
src/main/modules/db/custom.ts → packages/helper/db/custom.ts

20
src/main/modules/db/index.ts → packages/helper/db/index.ts

@ -1,27 +1,13 @@
import { injectable } from "inversify"
import Setting from "setting/main"
import { CustomAdapter, CustomLow } from "./custom"
import path from "node:path"
import BaseClass from "main/base/base"
import _logger from "logger/main"
// import _logger from "logger/main"
const logger = _logger.createNamespace("db")
// const logger = _logger.createNamespace("db")
@injectable()
class DB extends BaseClass {
destroy() {
logger.debug(`DB destroy`)
}
class DB {
Modules: Record<string, CustomLow<any>> = {}
constructor() {
super()
}
init() {
console.log("DB Init")
}
create(filepath) {
const adapter = new CustomAdapter<any>(filepath)
const db = new CustomLow<object>(adapter, {})

14
packages/helper/updater/common.ts

@ -1,3 +1,15 @@
import { UpdateInfo } from "electron-updater"
export interface UpdaterCommand {
checkForUpdates: () => void
}
export type EventMaps = {
"update-progress": (data: { percent: number; all: number; now: number }) => void
"update-progress": (data: { speed: number; percent: number; all: number; now: number }) => void
error: (err: any) => void
"updater:error": (info: UpdateInfo) => void
"checking-for-update": () => void
"update-available": (info: UpdateInfo) => void
"update-not-available": (info: UpdateInfo) => void
"updater:downloaded": (p: any) => void
}

97
packages/helper/updater/main/index.ts

@ -1,17 +1,19 @@
import pkg from "electron-updater"
import { app, dialog } from "electron"
import { NsisUpdater } from "electron-updater"
import { app, BrowserWindow, dialog } from "electron"
import { is } from "@electron-toolkit/utils"
import Setting from "setting/main"
import { BaseSingleton } from "base"
import { fetchHotUpdatePackage, flagNeedUpdate } from "./hot"
import Locales from "locales/main"
import _logger from "logger/main"
import { buildEmitter } from "base/event/main"
import { EventMaps } from "../common"
import path from "path"
const logger = _logger.createNamespace("updater")
const { autoUpdater } = pkg
class _Updater extends BaseSingleton {
public events = buildEmitter()
public events = buildEmitter<EventMaps>()
private timer: ReturnType<typeof setInterval> | null = null
// autoReplace = false
async triggerHotUpdate(autoReplace = false) {
@ -28,42 +30,83 @@ class _Updater extends BaseSingleton {
}
}
updateInfo: ConstructorParameters<typeof NsisUpdater>[0]
autoUpdater: NsisUpdater
constructor() {
super()
this.autoUpdater = new NsisUpdater({
provider: "github",
owner: "npmrun",
repo: "electron-app",
})
Setting.onChange("update.allowDowngrade", () => {
this.autoUpdater.allowDowngrade = Setting.values("update.allowDowngrade")
})
Setting.onChange("update.allowPrerelease", () => {
this.autoUpdater.allowPrerelease = Setting.values("update.allowPrerelease")
})
Setting.onChange(["update.owner", "update.repo"], () => {
this.autoUpdater.setFeedURL({
provider: "github",
owner: "npmrun",
repo: "electron-app",
})
})
// 配置自动更新
autoUpdater.autoDownload = false
autoUpdater.autoInstallOnAppQuit = true
this.autoUpdater.autoDownload = false
this.autoUpdater.autoInstallOnAppQuit = true
this.autoUpdater.allowPrerelease = true
this.autoUpdater.allowDowngrade = true
this.autoUpdater.forceDevUpdateConfig = is.dev
if (is.dev) {
this.autoUpdater.updateConfigPath = path.resolve(process.cwd(), "temp/dev.yml")
}
// 检查更新错误
autoUpdater.on("error", error => {
this.autoUpdater.on("error", error => {
logger.debug("Update error:", error)
this.events.emit("error", error)
})
// 检查更新
autoUpdater.on("checking-for-update", () => {
this.autoUpdater.on("checking-for-update", () => {
logger.debug("Checking for updates...")
this.events.emit("checking-for-update")
})
// 有可用更新
autoUpdater.on("update-available", info => {
this.autoUpdater.on("update-available", info => {
logger.debug("Update available:", info)
this.promptUserToUpdate()
this.events.emit("update-available", info)
this.promptUserToUpdate(info.releaseNotes)
})
// 没有可用更新
autoUpdater.on("update-not-available", info => {
this.autoUpdater.on("update-not-available", info => {
logger.debug("Update not available:", info)
this.events.emit("update-not-available", info)
})
// 更新下载进度
autoUpdater.on("download-progress", progressObj => {
this.autoUpdater.on("download-progress", progressObj => {
logger.debug(
`Download speed: ${progressObj.bytesPerSecond} - Downloaded ${progressObj.percent}% (${progressObj.transferred}/${progressObj.total})`,
)
this.events.emit("update-progress", {
speed: progressObj.bytesPerSecond,
percent: progressObj.percent,
all: progressObj.total,
now: progressObj.transferred,
})
})
// 更新下载完成
autoUpdater.on("update-downloaded", info => {
this.autoUpdater.on("update-downloaded", info => {
logger.debug("Update downloaded:", info)
this.promptUserToInstall()
})
@ -89,44 +132,40 @@ class _Updater extends BaseSingleton {
}
}
private async checkForUpdates() {
if (app.isPackaged) {
try {
await autoUpdater.checkForUpdates()
logger.debug("Updater初始化检查成功.")
} catch (error) {
logger.debug("Failed to check for updates:", error)
}
} else {
logger.debug("正在开发模式,跳过更新检查.")
async checkForUpdates() {
try {
logger.debug("Update开始检查更新.")
await this.autoUpdater.checkForUpdates()
} catch (error) {
logger.debug("Failed to check for updates:", error)
}
}
private async promptUserToUpdate() {
private async promptUserToUpdate(releaseNotes) {
const result = await dialog.showMessageBox({
type: "info",
title: "发现新版本",
message: "是否下载新版本?",
message: releaseNotes, // "是否下载新版本?",
buttons: ["下载", "暂不更新"],
defaultId: 0,
})
if (result.response === 0) {
autoUpdater.downloadUpdate()
this.autoUpdater.downloadUpdate()
}
}
private async promptUserToInstall() {
const result = await dialog.showMessageBox({
const result = await dialog.showMessageBox(BrowserWindow.getFocusedWindow()!, {
type: "info",
title: "更新已就绪",
message: "新版本已下载完成,是否立即安装?",
buttons: ["立即安装", "稍后安装"],
buttons: ["立即安装"],
defaultId: 0,
})
if (result.response === 0) {
autoUpdater.quitAndInstall(false, true)
this.autoUpdater.quitAndInstall(false, true)
}
}
}

3
packages/locales/main.ts

@ -21,7 +21,7 @@ class Locale {
try {
this.locale = app.getLocale()
} catch (e) {
console.log(e)
console.error(e)
}
}
@ -40,7 +40,6 @@ class Locale {
if (replacements) {
// 替换所有形如 {key} 的占位符
Object.entries(replacements).forEach(([key, value]) => {
console.log(text)
text = text.replace(new RegExp(`{${key}}`, "g"), value)
})
}

3
packages/logger/main.ts

@ -260,6 +260,9 @@ export class Logger {
// 默认实例
const logger = Logger.getInstance()
logger.init()
emitter.on("init", setting => {
logger.setLevel(setting["dev:debug"])
})
emitter.on("update", setting => {
logger.setLevel(setting["dev:debug"])
})

3
packages/logger/renderer-error.ts

@ -107,7 +107,7 @@ const formatError = (error: any, options: ErrorHandlerOptions): ErrorDetail => {
return errorDetail
}
// @ts-ignore
// @ts-ignore 忽略preload层不存在的问题
const preloadErrorHandler = window.preloadErrorHandler
/**
@ -223,6 +223,7 @@ const errorHandler = createRendererErrorHandler()
// 安装全局错误处理器
errorHandler.installGlobalHandlers()
// @ts-ignore 忽略全局问题
window.errorHandler = errorHandler
/**

7
packages/setting/common.ts

@ -0,0 +1,7 @@
import type { IOnFunc } from "setting/main"
export type EventMaps = {
init: IOnFunc
update: IOnFunc
change: (key: string, value: any) => void
}

8
packages/setting/main.ts

@ -5,6 +5,7 @@ import { cloneDeep } from "lodash"
import Config from "config"
import type { IConfig } from "config"
import _logger from "logger/main"
import { emitter } from "./main/event"
const logger = _logger.createNamespace("setting")
@ -61,6 +62,7 @@ class SettingClass {
this.init()
}
events = emitter
#cb: [IT, IOnFunc][] = []
onChange(fn: IOnFunc, that?: any)
@ -137,6 +139,7 @@ class SettingClass {
this.#sync()
}
init.call(this, this.#config)
this.events.emit("update", this.#config, this.#config)
}
config() {
return this.#config
@ -215,6 +218,11 @@ class SettingClass {
if (isChange) {
this.#sync()
this.#runCB(this.#config, oldMainConfig, changeKeys)
this.events.emit("update", this.#config, oldMainConfig, changeKeys)
for (let i = 0; i < changeKeys.length; i++) {
const k = changeKeys[i]
this.events.emit("change", k, this.#config[k])
}
}
}
values<T extends keyof IConfig>(key: T): IConfig[T] {

6
packages/setting/main/event.ts

@ -1,6 +1,4 @@
import { buildEmitter } from "base/event/main"
import type { IOnFunc } from "setting/main"
import { EventMaps } from "setting/common"
export const emitter = buildEmitter<{
update: IOnFunc
}>()
export const emitter = buildEmitter<EventMaps>()

12
packages/utils/main/session/cookies.ts

@ -2,12 +2,12 @@ import { BrowserView, BrowserWindow } from "electron"
const cookies = {
getCurrCookies(params = {}, currWin: BrowserView | BrowserWindow) {
let currSession = currWin.webContents.session
const currSession = currWin.webContents.session
return currSession.cookies.get(Object.assign({}, params))
},
removeCurrCookies(cookies = [], currWin: BrowserView | BrowserWindow) {
let currSession = currWin.webContents.session
let err = []
const currSession = currWin.webContents.session
const err = []
let apiCount = 0
return new Promise((resove, reject) => {
cookies.forEach(async (item: any) => {
@ -22,8 +22,8 @@ const cookies = {
})
},
setCurrCookies(cookies = [], currWin: BrowserView | BrowserWindow) {
let currSession = currWin.webContents.session
let err = []
const currSession = currWin.webContents.session
const err = []
let apiCount = 0
return new Promise((resove, reject) => {
cookies.forEach(async (item: any) => {
@ -44,4 +44,4 @@ const cookies = {
},
}
export default cookies
export default cookies

12
packages/utils/main/session/index.ts

@ -11,7 +11,7 @@ function createLoginWin(partition) {
partition = partition || `persist:${Math.random()}`
// const charset = require("superagent-charset")
// const request = charset(require("superagent")) // HTTP
let presWindow = new BrowserWindow({
const presWindow = new BrowserWindow({
width: 1280,
height: 768,
title: "用户登陆",
@ -21,14 +21,14 @@ function createLoginWin(partition) {
partition,
},
})
let webContents = presWindow.webContents
return new Promise(function (resove, _) {
const webContents = presWindow.webContents
return new Promise(function (resove) {
// webContents.openDevTools();
presWindow.loadURL("https://login.taobao.com/member/login.jhtml")
webContents.on("did-navigate-in-page", async function () {
// 这里可以看情况进行参数的传递,获取制定的 cookies
const cookies = await webContents.session.cookies.get({})
let obj = { partition, cookies }
const obj = { partition, cookies }
resove(obj)
// webContents.session.cookies.get({}, function (err, cookies) {
// if (err) {
@ -77,6 +77,4 @@ function createLoginWin(partition) {
})
}
export {
createLoginWin
}
export { createLoginWin }

102
pnpm-lock.yaml

@ -81,6 +81,9 @@ importers:
base:
specifier: workspace:*
version: link:packages/base
bulma:
specifier: ^1.0.4
version: 1.0.4
debug:
specifier: ^4.4.0
version: 4.4.0
@ -146,7 +149,7 @@ importers:
version: 5.7.3
unocss:
specifier: ^0.64.1
version: 0.64.1(postcss@8.4.49)(rollup@4.26.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.85.0))(vue@3.5.13(typescript@5.7.3))
version: 0.64.1(postcss@8.5.4)(rollup@4.26.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.85.0))(vue@3.5.13(typescript@5.7.3))
unplugin-auto-import:
specifier: ^19.1.0
version: 19.1.0(@nuxt/kit@3.16.2)(@vueuse/core@12.7.0(typescript@5.7.3))
@ -186,6 +189,9 @@ importers:
vue-tsc:
specifier: ^2.1.10
version: 2.1.10(typescript@5.7.3)
vue3-toastify:
specifier: ^0.2.8
version: 0.2.8(vue@3.5.13(typescript@5.7.3))
packages/base: {}
@ -773,20 +779,20 @@ packages:
resolution: {integrity: sha512-4iEsUZ3aF7jXY19CJFN5VP+pPyLITD9FVsjB13z9TU1UxaZLlFsmNhvRxlPDSOfHAP5RpNF2QKKdZ3DHVf4Yzw==}
engines: {node: '>= 16'}
'@intlify/message-compiler@12.0.0-alpha.2':
resolution: {integrity: sha512-PD9C+oQbb7BF52hec0+vLnScaFkvnfX+R7zSbODYuRo/E2niAtGmHd0wPvEMsDhf9Z9b8f/qyDsVeZnD/ya9Ug==}
'@intlify/message-compiler@12.0.0-alpha.3':
resolution: {integrity: sha512-mDDTN3gfYOHhBnpnlby19UHyvMaOnzdlpsIrxUfs44R/vCATfn8pMOkE8PXD2t410xkocEj3FpDcC9XC/0v4Dg==}
engines: {node: '>= 16'}
'@intlify/shared@11.1.1':
resolution: {integrity: sha512-2kGiWoXaeV8HZlhU/Nml12oTbhv7j2ufsJ5vQaa0VTjzUmZVdd/nmKFRAOJ/FtjO90Qba5AnZDwsrY7ZND5udA==}
engines: {node: '>= 16'}
'@intlify/shared@11.1.5':
resolution: {integrity: sha512-+I4vRzHm38VjLr/CAciEPJhGYFzWWW4HMTm+6H3WqknXLh0ozNX9oC8ogMUwTSXYR/wGUb1/lTpNziiCH5MybQ==}
'@intlify/shared@11.1.11':
resolution: {integrity: sha512-RIBFTIqxZSsxUqlcyoR7iiC632bq7kkOwYvZlvcVObHfrF4NhuKc4FKvu8iPCrEO+e3XsY7/UVpfgzg+M7ETzA==}
engines: {node: '>= 16'}
'@intlify/shared@12.0.0-alpha.2':
resolution: {integrity: sha512-P2DULVX9nz3y8zKNqLw9Es1aAgQ1JGC+kgpx5q7yLmrnAKkPR5MybQWoEhxanefNJgUY5ehsgo+GKif59SrncA==}
'@intlify/shared@12.0.0-alpha.3':
resolution: {integrity: sha512-ryaNYBvxQjyJUmVuBBg+HHUsmGnfxcEUPR0NCeG4/K9N2qtyFE35C80S15IN6iYFE2MGWLN7HfOSyg0MXZIc9w==}
engines: {node: '>= 16'}
'@intlify/unplugin-vue-i18n@6.0.3':
@ -904,25 +910,21 @@ packages:
resolution: {integrity: sha512-eEwxY+0Cf76HnQwr1+Qy48qwf4dAebTHaKhzEgxLqLK6szbglnK6SThjY95YHrYWwsH1GujWiFoX51jwZNYfSw==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@oxc-resolver/binding-linux-arm64-musl@3.0.3':
resolution: {integrity: sha512-LdxbLv8qVkzro4/ZoP9MuytIL6NOVsbhoZ5Wl1KXOa/2DSxBiksrAPMSChCTyeLy6P3ebSHxQSb52ku18t1LBA==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@oxc-resolver/binding-linux-x64-gnu@3.0.3':
resolution: {integrity: sha512-bN8elR9AV/DZZPdcteOWWElkz8KyxLtOvmfVl7Dnehcs6f9e+fWYKyqiKvva1jsxG4znGKCPT1gfMhpYW8QuKg==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@oxc-resolver/binding-linux-x64-musl@3.0.3':
resolution: {integrity: sha512-Zy1U49BjriwbAds2ho6CGjZIk2KVn0+lrc/G5bvhQg7UJYxEkAueMGBuA5rULIhx9xVtIPsT9Q+J5Xhb4ffVNw==}
cpu: [x64]
os: [linux]
libc: [musl]
'@oxc-resolver/binding-wasm32-wasi@3.0.3':
resolution: {integrity: sha512-7rteQnn7i5f9nkFZs1VRdBqFhvOx3zWavyKkWjXYVxc9vsSLTg0moh2MRZw5dw5m/bEi1u/p3YAKJ9gdHyBhNQ==}
@ -968,42 +970,36 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.0':
resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.0':
resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.0':
resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.0':
resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.0':
resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.0':
resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==}
@ -1090,55 +1086,46 @@ packages:
resolution: {integrity: sha512-paHF1bMXKDuizaMODm2bBTjRiHxESWiIyIdMugKeLnjuS1TCS54MF5+Y5Dx8Ui/1RBPVRE09i5OUlaLnv8OGnA==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.26.0':
resolution: {integrity: sha512-cwxiHZU1GAs+TMxvgPfUDtVZjdBdTsQwVnNlzRXC5QzIJ6nhfB4I1ahKoe9yPmoaA/Vhf7m9dB1chGPpDRdGXg==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.26.0':
resolution: {integrity: sha512-4daeEUQutGRCW/9zEo8JtdAgtJ1q2g5oHaoQaZbMSKaIWKDQwQ3Yx0/3jJNmpzrsScIPtx/V+1AfibLisb3AMQ==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.26.0':
resolution: {integrity: sha512-eGkX7zzkNxvvS05ROzJ/cO/AKqNvR/7t1jA3VZDi2vRniLKwAWxUr85fH3NsvtxU5vnUUKFHKh8flIBdlo2b3Q==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-powerpc64le-gnu@4.26.0':
resolution: {integrity: sha512-Odp/lgHbW/mAqw/pU21goo5ruWsytP7/HCC/liOt0zcGG0llYWKrd10k9Fj0pdj3prQ63N5yQLCLiE7HTX+MYw==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.26.0':
resolution: {integrity: sha512-MBR2ZhCTzUgVD0OJdTzNeF4+zsVogIR1U/FsyuFerwcqjZGvg2nYe24SAHp8O5sN8ZkRVbHwlYeHqcSQ8tcYew==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-s390x-gnu@4.26.0':
resolution: {integrity: sha512-YYcg8MkbN17fMbRMZuxwmxWqsmQufh3ZJFxFGoHjrE7bv0X+T6l3glcdzd7IKLiwhT+PZOJCblpnNlz1/C3kGQ==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.26.0':
resolution: {integrity: sha512-ZuwpfjCwjPkAOxpjAEjabg6LRSfL7cAJb6gSQGZYjGhadlzKKywDkCUnJ+KEfrNY1jH5EEoSIKLCb572jSiglA==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.26.0':
resolution: {integrity: sha512-+HJD2lFS86qkeF8kNu0kALtifMpPCZU80HvwztIKnYwym3KnA1os6nsX4BGSTLtS2QVAGG1P3guRgsYyMA0Yhg==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.26.0':
resolution: {integrity: sha512-WUQzVFWPSw2uJzX4j6YEbMAiLbs0BUysgysh8s817doAYhR5ybqTI1wtKARQKo6cGop3pHnrUJPFCsXdoFaimQ==}
@ -1853,6 +1840,9 @@ packages:
builder-util@24.13.1:
resolution: {integrity: sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA==}
bulma@1.0.4:
resolution: {integrity: sha512-Ffb6YGXDiZYX3cqvSbHWqQ8+LkX6tVoTcZuVB3lm93sbAVXlO0D6QlOTMnV6g18gILpAXqkG2z9hf9z4hCjz2g==}
bundle-require@5.0.0:
resolution: {integrity: sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -2890,6 +2880,11 @@ packages:
muggle-string@0.4.1:
resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@ -3068,6 +3063,10 @@ packages:
resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
engines: {node: ^10 || ^12 || >=14}
postcss@8.5.4:
resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==}
engines: {node: ^10 || ^12 || >=14}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@ -3716,6 +3715,15 @@ packages:
peerDependencies:
typescript: '>=5.0.0'
vue3-toastify@0.2.8:
resolution: {integrity: sha512-8jDOqsJaBZEbGpCbhWDETJc11D1lZefvgFPq/IPdM+U7+qyXoVPDvK6uq/FIgyV7qV0NcNzvGBMEzjsLQqGROw==}
engines: {node: '>=20', npm: '>=9.0.0'}
peerDependencies:
vue: '>=3.2.0'
peerDependenciesMeta:
vue:
optional: true
vue@3.5.13:
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
peerDependencies:
@ -4331,8 +4339,8 @@ snapshots:
'@intlify/bundle-utils@10.0.0(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))':
dependencies:
'@intlify/message-compiler': 12.0.0-alpha.2
'@intlify/shared': 12.0.0-alpha.2
'@intlify/message-compiler': 12.0.0-alpha.3
'@intlify/shared': 12.0.0-alpha.3
acorn: 8.14.0
escodegen: 2.1.0
estree-walker: 2.0.2
@ -4353,23 +4361,23 @@ snapshots:
'@intlify/shared': 11.1.1
source-map-js: 1.2.1
'@intlify/message-compiler@12.0.0-alpha.2':
'@intlify/message-compiler@12.0.0-alpha.3':
dependencies:
'@intlify/shared': 12.0.0-alpha.2
'@intlify/shared': 12.0.0-alpha.3
source-map-js: 1.2.1
'@intlify/shared@11.1.1': {}
'@intlify/shared@11.1.5': {}
'@intlify/shared@11.1.11': {}
'@intlify/shared@12.0.0-alpha.2': {}
'@intlify/shared@12.0.0-alpha.3': {}
'@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@8.57.1)(rollup@4.26.0)(typescript@5.7.3)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1)
'@intlify/bundle-utils': 10.0.0(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))
'@intlify/shared': 11.1.5
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.5)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
'@intlify/shared': 11.1.11
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.11)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
'@rollup/pluginutils': 5.1.4(rollup@4.26.0)
'@typescript-eslint/scope-manager': 8.25.0
'@typescript-eslint/typescript-estree': 8.25.0(typescript@5.7.3)
@ -4391,11 +4399,11 @@ snapshots:
- supports-color
- typescript
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.5)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.11)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
dependencies:
'@babel/parser': 7.26.9
optionalDependencies:
'@intlify/shared': 11.1.5
'@intlify/shared': 11.1.11
'@vue/compiler-dom': 3.5.13
vue: 3.5.13(typescript@5.7.3)
vue-i18n: 11.1.1(vue@3.5.13(typescript@5.7.3))
@ -4902,13 +4910,13 @@ snapshots:
transitivePeerDependencies:
- vue
'@unocss/postcss@0.64.1(postcss@8.4.49)':
'@unocss/postcss@0.64.1(postcss@8.5.4)':
dependencies:
'@unocss/config': 0.64.1
'@unocss/core': 0.64.1
'@unocss/rule-utils': 0.64.1
css-tree: 3.0.1
postcss: 8.4.49
postcss: 8.5.4
tinyglobby: 0.2.10
transitivePeerDependencies:
- supports-color
@ -5674,6 +5682,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
bulma@1.0.4: {}
bundle-require@5.0.0(esbuild@0.21.5):
dependencies:
esbuild: 0.21.5
@ -6837,6 +6847,8 @@ snapshots:
muggle-string@0.4.1: {}
nanoid@3.3.11: {}
nanoid@3.3.7: {}
natural-compare@1.4.0: {}
@ -7015,6 +7027,12 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
postcss@8.5.4:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
prelude-ls@1.2.1: {}
prettier-linter-helpers@1.0.0:
@ -7476,12 +7494,12 @@ snapshots:
universalify@2.0.1: {}
unocss@0.64.1(postcss@8.4.49)(rollup@4.26.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.85.0))(vue@3.5.13(typescript@5.7.3)):
unocss@0.64.1(postcss@8.5.4)(rollup@4.26.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.85.0))(vue@3.5.13(typescript@5.7.3)):
dependencies:
'@unocss/astro': 0.64.1(rollup@4.26.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.85.0))(vue@3.5.13(typescript@5.7.3))
'@unocss/cli': 0.64.1(rollup@4.26.0)
'@unocss/core': 0.64.1
'@unocss/postcss': 0.64.1(postcss@8.4.49)
'@unocss/postcss': 0.64.1(postcss@8.5.4)
'@unocss/preset-attributify': 0.64.1
'@unocss/preset-icons': 0.64.1
'@unocss/preset-mini': 0.64.1
@ -7749,6 +7767,10 @@ snapshots:
semver: 7.6.3
typescript: 5.7.3
vue3-toastify@0.2.8(vue@3.5.13(typescript@5.7.3)):
optionalDependencies:
vue: 3.5.13(typescript@5.7.3)
vue@3.5.13(typescript@5.7.3):
dependencies:
'@vue/compiler-dom': 3.5.13

5
src/common/event/PlatForm/hook.ts

@ -1,5 +0,0 @@
import { PlatForm } from "."
export function usePlatForm() {
return PlatForm.getInstance<PlatForm>()
}

5
src/common/event/Snippet/hook.ts

@ -1,5 +0,0 @@
import { Snippet } from "."
export function useSnippet() {
return Snippet.getInstance()
}

18
src/common/event/Snippet/index.ts

@ -1,18 +0,0 @@
import { BaseSingleton } from "base"
import { ApiFactory } from "common/lib/abstract"
class Snippet extends BaseSingleton {
constructor() {
super()
}
private get api() {
return ApiFactory.getApiClient()
}
getTree = async () => {
return this.api.call("SnippetCommand.getTree")
}
}
export { Snippet }

16
src/common/event/Updater/hook.ts

@ -1,16 +0,0 @@
import { EventMaps } from "helper/updater/common"
import { defineStore } from "pinia"
export const useSettingStore = defineStore(
"Updater",
() => {
getApi<EventMaps>().on("update-progress", (_, data) => {
console.log(data)
})
return {}
},
{
persist: false,
},
)

7
src/common/readme.md

@ -1,7 +0,0 @@
## event
通用事件处理模块
- main/**/* 处理主进程的模块
- main/command.ts 会通过ioc收集,进入依赖管理中
- 其他 处理渲染进程的模块

165
src/main/App copy.ts

@ -1,165 +0,0 @@
import { inject, injectable } from "inversify"
// import Setting from "./modules/setting"
// import DB from "./modules/db"
import Api from "./modules/api"
import WindowManager from "./modules/window-manager"
import { app, nativeTheme, protocol, WebContentsView } from "electron"
import { electronApp } from "@electron-toolkit/utils"
// import Tabs from "./modules/tabs/Tabs"
import { getFileUrl } from "./utils"
import BaseClass from "./base/base"
protocol.registerSchemesAsPrivileged([
// {
// scheme: "http",
// privileges: { standard: true, bypassCSP: true, allowServiceWorkers: true, supportFetchAPI: true, corsEnabled: true, stream: true },
// },
// {
// scheme: "https",
// privileges: { standard: true, bypassCSP: true, allowServiceWorkers: true, supportFetchAPI: true, corsEnabled: true, stream: true },
// },
// { scheme: "mailto", privileges: { standard: true } },
{
scheme: "api",
privileges: {
standard: true,
secure: true,
supportFetchAPI: true,
},
},
])
@injectable()
class App extends BaseClass {
destroy() {
// destroyAll()
// 这里是应用正常退出
}
// private _setting: Setting
// private _db: DB
private _Api: Api
private _windowManager: WindowManager
// private _tabs: Tabs
constructor(
// @inject(Setting) setting: Setting,
// @inject(DB) db: DB,
@inject(Api) Api: Api,
@inject(WindowManager) windowManager: WindowManager,
// @inject(Tabs) tabs: Tabs,
) {
super()
// this._setting = setting
// this._db = db
this._Api = Api
this._windowManager = windowManager
// this._tabs = tabs
}
async init() {
this._windowManager.init()
app.whenReady().then(() => {
electronApp.setAppUserModelId("top.xieyaxin")
this.create()
this._Api.init()
})
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit()
}
})
app.on("will-quit", () => {
this.destroy()
})
}
create() {
this._windowManager.showMainWindow()
const mainWindow = this._windowManager.getMainWindow()
if (mainWindow) {
nativeTheme.themeSource = "light"
mainWindow.setTitleBarOverlay({
height: 29, // the smallest size of the title bar on windows accounting for the border on windows 11
color: "#F8F8F8",
symbolColor: "#000000",
})
this._windowManager.showWindow("main-top")
const mainTopWindow = this._windowManager.get("main-top")
setTimeout(() => {
// console.log(mainWindow.getParentWindow());
setTimeout(() => {
mainWindow.contentView.children.length = 0
const view = new WebContentsView()
view.addChildView(mainTopWindow!.contentView)
view.webContents.loadURL(getFileUrl("about.html"))
// mainTopWindow!.contentView.setBounds({ x: 0, y: 0, width: 100, height: 30 })
// view.setBounds({ x: 0, y: 0, width: 100, height: 30 })
mainWindow.contentView.addChildView(view)
// mainWindow.contentView.children.sort()
console.log(mainWindow.contentView.children)
}, 5000)
// mainWindow.webContents = mainTopWindow!.webContents
mainWindow.reload()
console.log(mainWindow.webContents.getURL())
// mainTopWindow?.destroy()
// mainWindow.contentView.addChildView(mainWindow.contentView)
console.log(`child count: `, mainWindow.contentView.children.length)
}, 2000)
// if (mainTopWindow) {
// mainTopWindow.setParentWindow(mainWindow)
// mainTopWindow.setIgnoreMouseEvents(true, { forward: false })
// const listenMove = () => {
// if (mainWindow && mainTopWindow) {
// const pos = mainWindow.getPosition()
// mainTopWindow.setPosition(pos[0], pos[1])
// }
// }
// mainWindow?.on("move", listenMove)
// const listenResize = () => {
// if (mainWindow && mainTopWindow) {
// const size = mainWindow.getSize()
// console.log(size)
// mainTopWindow.setSize(size[0], size[1])
// const pos = mainWindow.getPosition()
// mainTopWindow.setPosition(pos[0], pos[1])
// }
// }
// listenResize()
// mainWindow?.on("resize", listenResize)
// }
}
// 考虑双browserwindow模式
/**
* browserwindow可以设置穿透tab放在底层window上window上
*/
// const webContentsView = new WebContentsView({
// webPreferences: {
// preload: join(__dirname, "../preload/index.mjs"),
// transparent: true,
// nodeIntegration: true,
// spellcheck: false,
// contextIsolation: true,
// },
// })
// // mainWindow!.contentView = webContentsView
// // setTimeout(() => {
// mainWindow!.contentView.addChildView(webContentsView)
// // mainWindow?.setIgnoreMouseEvents(true, { forward: true })
// // }, 2000);
// webContentsView.webContents.loadURL(getFileUrl("index.html"))
// const listenResize = () => {
// const size = mainWindow!.getSize()
// webContentsView.setBounds({ x: 0, y: 0, width: size[0], height: size[1] })
// }
// listenResize()
// mainWindow!.addListener("resize", listenResize)
// this._tabs.add("https://baidu.com", true)
// this._tabs.add("https://zhihu.com")
return mainWindow
}
}
export default App
export { App }

3
src/main/App.ts

@ -8,7 +8,6 @@ import { electronApp } from "@electron-toolkit/utils"
import Command from "./modules/commands"
import BaseClass from "./base/base"
import IOC from "./_ioc"
import DB from "./modules/db"
import Zephyr from "./modules/zephyr"
import { crashHandler } from "logger/crash-handler"
import logger from "logger/main"
@ -53,7 +52,6 @@ class App extends BaseClass {
@inject(IOC) private _IOC: IOC,
@inject(Api) private _Api: Api,
@inject(Command) private _Command: Command,
@inject(DB) private _DB: DB,
@inject(WindowManager) private _WindowManager: WindowManager,
@inject(Zephyr) private _Zephyr: Zephyr,
) {
@ -68,7 +66,6 @@ class App extends BaseClass {
// 开启硬件加速
app.disableHardwareAcceleration()
crashHandler.init()
this._DB.init()
this._Command.init()
this._WindowManager.init()
app.whenReady().then(() => {

2
src/main/_ioc.ts

@ -2,7 +2,7 @@ import IOC from "./_iocClass"
import { Container } from "inversify"
import iocModules, { destroyAllModules } from "./modules/_ioc"
import iocController, { destroyAllController } from "./controller/_ioc"
import iocCommand, { destroyAllCommand } from "common/_ioc.main"
import iocCommand, { destroyAllCommand } from "./command/_ioc"
import App from "./App"
async function destroyAll() {

7
src/common/event/PlatForm/main/command.ts → src/main/command/PlatForm/command.ts

@ -1,7 +1,6 @@
import { app, dialog, nativeTheme, TitleBarOverlayOptions } from "electron"
import { inject } from "inversify"
import errorHandler from "logger/main-error"
import Tabs from "main/modules/tabs"
import WindowManager from "main/modules/window-manager"
import icon from "@res/icon.png?asset"
import setting from "setting/main"
@ -9,10 +8,7 @@ import { LogLevel } from "logger/common"
import { getFileUrl } from "utils/main"
export default class PlatFormCommand {
constructor(
@inject(WindowManager) private _WindowManager: WindowManager,
@inject(Tabs) private _Tabs: Tabs,
) {}
constructor(@inject(WindowManager) private _WindowManager: WindowManager) {}
setTheme(theme: typeof nativeTheme.themeSource) {
nativeTheme.themeSource = theme
@ -115,7 +111,6 @@ export default class PlatFormCommand {
return
}
}
this._Tabs.closeAll()
focusedWindow!.reload()
}
}

6
src/common/event/Setting/main/command.ts → src/main/command/Setting/command.ts

@ -1,8 +1,12 @@
import Setting, { IConfig } from "setting/main"
import { broadcast } from "utils/main"
export default class SettingCommand {
static init() {
console.log("SettingCommand init")
Setting.events.on("change", (k, value) => {
console.log(k, value)
broadcast("SettingCommand.change", k, value)
})
}
sync() {
return Setting.config()

8
src/main/command/Setting/type.d.ts

@ -0,0 +1,8 @@
import type { EventMaps } from "setting/common"
export interface SettingCommand {
save: () => void
reset: () => void
}
export { EventMaps }

0
src/common/event/Snippet/main/command.ts → src/main/command/Snippet/command.ts

8
src/common/event/Updater/main/command.ts → src/main/command/Updater/command.ts

@ -1,5 +1,6 @@
import Updater from "helper/updater/main"
import _logger from "logger/main"
import { broadcast } from "utils/main"
const logger = _logger.createNamespace("UpdaterCommand")
@ -7,9 +8,16 @@ export default class UpdaterCommand {
static init() {
// 命令初始化
logger.debug("UpdaterCommand init")
Updater.events.on("*", (name, ...argus) => {
broadcast("UpdaterCommand." + name, ...argus)
})
}
async triggerHotUpdate() {
Updater.triggerHotUpdate()
}
checkForUpdates() {
return Updater.checkForUpdates()
}
}

18
src/common/_ioc.main.ts → src/main/command/_ioc.ts

@ -1,9 +1,12 @@
import { Container, ContainerModule } from "inversify"
import _logger from "logger/main"
const logger = _logger.createNamespace("command")
/**
*
*/
const commandModules = import.meta.glob("./event/**/main/command.{ts,js}", { eager: true })
const commandModules = import.meta.glob("./**/command.{ts,js}", { eager: true })
const modules = new ContainerModule(bind => {
// 自动绑定所有命令类
@ -12,6 +15,7 @@ const modules = new ContainerModule(bind => {
const CommandClass = (module as { default: any }).default
if (CommandClass) {
const className = CommandClass.name.replace("Command", "")
logger.debug(`绑定命令类: ${className}Command`)
if (CommandClass["init"]) {
CommandClass["init"]()
}
@ -27,6 +31,18 @@ const modules = new ContainerModule(bind => {
* @param ioc - Inversify
*/
async function destroyAllCommand(ioc: Container) {
const allIOC: any[] = []
Object.values(commandModules).forEach(module => {
const CommandClass = (module as { default: any }).default
if (CommandClass) {
const className = CommandClass.name.replace("Command", "")
const m = ioc.get(className + "Command") as any
if (m && m.destroy) {
allIOC.push(m.destroy())
}
}
})
await Promise.all(allIOC)
await ioc.unloadAsync(modules)
}

6
src/main/controller/BasicService.ts

@ -1,13 +1,13 @@
import { inject, injectable } from "inversify"
import BaseContainer from "main/base/baseContainer"
import Tabs from "main/modules/tabs"
// import Tabs from "main/modules/tabs"
import WindowManager from "main/modules/window-manager"
@injectable()
class BasicService extends BaseContainer {
constructor(
@inject(WindowManager) private _WindowManager: WindowManager,
@inject(Tabs) private _Tabs: Tabs,
// @inject(Tabs) private _Tabs: Tabs,
) {
super()
}
@ -21,7 +21,7 @@ class BasicService extends BaseContainer {
openTabDevtool() {
// this._Tabs.reload(0)
this._Tabs.openDevtool(0)
// this._Tabs.openDevtool(0)
}
}

9
src/main/modules/_ioc.ts

@ -1,8 +1,7 @@
import { Container, ContainerModule } from "inversify"
import { DB } from "./db"
import { Api } from "./api"
import { WindowManager } from "./window-manager"
import { Tabs } from "./tabs"
// import { Tabs } from "./tabs"
import Commands from "./commands"
import Zephyr from "./zephyr"
@ -11,8 +10,7 @@ const modules = new ContainerModule(bind => {
bind(Api).toSelf().inSingletonScope()
bind(WindowManager).toSelf().inSingletonScope()
bind(Commands).toSelf().inSingletonScope()
bind(Tabs).toSelf().inSingletonScope()
bind(DB).toSelf().inSingletonScope()
// bind(Tabs).toSelf().inSingletonScope()
})
async function destroyAllModules(ioc: Container) {
@ -20,9 +18,8 @@ async function destroyAllModules(ioc: Container) {
ioc.get(WindowManager).destroy(),
ioc.get(Commands).destroy(),
ioc.get(Zephyr).destroy(),
ioc.get(Tabs).destroy(),
// ioc.get(Tabs).destroy(),
ioc.get(Api).destroy(),
ioc.get(DB).destroy(),
])
ioc.unloadAsync(modules)
}

3
src/preload/index.ts

@ -67,6 +67,7 @@ ipcRenderer.once("bind-window-manager", (_, name: string) => {
if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld("electron", electronAPI)
contextBridge.exposeInMainWorld("getApi", () => api)
contextBridge.exposeInMainWorld("api", api)
} catch (error) {
console.error(error)
@ -76,4 +77,6 @@ if (process.contextIsolated) {
window.electron = electronAPI
// @ts-ignore (define in dts)
window.api = api
// @ts-ignore (define in dts)
window.getApi = () => api
}

0
src/preload/plugin.ts

6
src/renderer/about.html

@ -4,7 +4,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>关于</title>
<title>关于本应用</title>
<style>
html,
body {
@ -22,9 +22,9 @@
<body>
<article>
<h1>环境</h1>
<h1>关于</h1>
<ul>
<li>111</li>
<li>MIT开源</li>
</ul>
</article>
</body>

12
src/renderer/auto-imports.d.ts

@ -6,6 +6,7 @@
// biome-ignore lint: disable
export {}
declare global {
const ApiUpdaterStatus: typeof import('./src/composables/Api/Updater/useApiUpdater')['ApiUpdaterStatus']
const EffectScope: typeof import('vue')['EffectScope']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
@ -100,6 +101,7 @@ declare global {
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const toast: typeof import('vue3-toastify')['toast']
const triggerRef: typeof import('vue')['triggerRef']
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
@ -111,6 +113,9 @@ declare global {
const until: typeof import('@vueuse/core')['until']
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
const useAnimate: typeof import('@vueuse/core')['useAnimate']
const useApiPlatForm: typeof import('./src/composables/Api/Platform/useApiPlatForm')['useApiPlatForm']
const useApiSetting: typeof import('./src/composables/Api/Setting/useApiSetting')['useApiSetting']
const useApiUpdater: typeof import('./src/composables/Api/Updater/useApiUpdater')['useApiUpdater']
const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
@ -247,7 +252,6 @@ declare global {
const useSwipe: typeof import('@vueuse/core')['useSwipe']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
const useTest: typeof import('./src/composables/useTest')['useTest']
const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
@ -307,6 +311,7 @@ import { UnwrapRef } from 'vue'
declare module 'vue' {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly ApiUpdaterStatus: UnwrapRef<typeof import('./src/composables/Api/Updater/useApiUpdater')['ApiUpdaterStatus']>
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
@ -401,6 +406,7 @@ declare module 'vue' {
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
readonly toast: UnwrapRef<typeof import('vue3-toastify')['toast']>
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']>
readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']>
@ -412,6 +418,9 @@ declare module 'vue' {
readonly until: UnwrapRef<typeof import('@vueuse/core')['until']>
readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']>
readonly useAnimate: UnwrapRef<typeof import('@vueuse/core')['useAnimate']>
readonly useApiPlatForm: UnwrapRef<typeof import('./src/composables/Api/Platform/useApiPlatForm')['useApiPlatForm']>
readonly useApiSetting: UnwrapRef<typeof import('./src/composables/Api/Setting/useApiSetting')['useApiSetting']>
readonly useApiUpdater: UnwrapRef<typeof import('./src/composables/Api/Updater/useApiUpdater')['useApiUpdater']>
readonly useArrayDifference: UnwrapRef<typeof import('@vueuse/core')['useArrayDifference']>
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']>
readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']>
@ -548,7 +557,6 @@ declare module 'vue' {
readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']>
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
readonly useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']>
readonly useTest: UnwrapRef<typeof import('./src/composables/useTest')['useTest']>
readonly useTextDirection: UnwrapRef<typeof import('@vueuse/core')['useTextDirection']>
readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']>
readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']>

9
src/renderer/components.d.ts

@ -10,14 +10,15 @@ declare module 'vue' {
export interface GlobalComponents {
AdjustLine: typeof import('./src/components/AdjustLine.vue')['default']
CodeEditor: typeof import('./src/components/CodeEditor/code-editor.vue')['default']
IconFluentCollections24Regular: typeof import('~icons/fluent/collections24-regular')['default']
IconHugeiconsInbox: typeof import('~icons/hugeicons/inbox')['default']
IconMynauiTrash: typeof import('~icons/mynaui/trash')['default']
IconSolarHome2Outline: typeof import('~icons/solar/home2-outline')['default']
'IconBxs:error': typeof import('~icons/bxs/error')['default']
'IconGrommetIcons:update': typeof import('~icons/grommet-icons/update')['default']
'IconIx:reset': typeof import('~icons/ix/reset')['default']
'IconMaterialSymbols:save': typeof import('~icons/material-symbols/save')['default']
'IconStash:arrowReplyDuotone': typeof import('~icons/stash/arrow-reply-duotone')['default']
NavBar: typeof import('./src/ui/NavBar.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Update: typeof import('./src/ui/Update.vue')['default']
Versions: typeof import('./src/components/Versions.vue')['default']
}
}

28
src/renderer/src/App.vue

@ -1,14 +1,24 @@
<script setup lang="ts">
const getKey = route => {
if (route.matched.length > 0) {
for (let i = 0; i < route.matched.length; i++) {
const r = route.matched[i]
if (r.meta?.isLayout) {
return r.path
}
}
}
return route.fullPath
}
</script>
<template>
<div h-full flex flex-col overflow-hidden>
<NavBar></NavBar>
<div flex-1 h-0 overflow-hidden flex flex-col relative id="page-container" style="transform: scale(1);">
<div id="page-container" flex-1 h-0 overflow-hidden flex flex-col relative style="transform: scale(1)">
<router-view v-slot="{ Component, route }">
<Transition name="slide-fade" mode="out-in">
<component :is="Component" :key="route.fullPath" />
<component :is="Component" :key="getKey(route)" />
</Transition>
</router-view>
</div>
@ -16,17 +26,5 @@
</template>
<style lang="scss" scoped>
.slide-fade-enter-active {
transition: all 0.2s ease-out;
}
.slide-fade-leave-active {
transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
// transform: translateX(20px);
opacity: 0;
}
</style>

13
src/renderer/src/assets/style/_anim.scss

@ -0,0 +1,13 @@
.slide-fade-enter-active {
transition: all 0.2s ease-out;
}
.slide-fade-leave-active {
transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
// transform: translateX(20px);
opacity: 0;
}

3
src/renderer/src/assets/style/_common.scss

@ -1,3 +1,5 @@
@use "./_anim.scss";
*,
*::before,
*::after {
@ -11,6 +13,7 @@ html {
--text-hover: #000000;
height: 100%;
color: var(--text-normal);
overflow: hidden;
}
body {

5
src/renderer/src/assets/style/global/_index.scss

@ -0,0 +1,5 @@
@use "bulma/sass/base";
@use "bulma/sass/themes";
@use "bulma/sass/elements/button";
@use "bulma/sass/form/input-textarea";

10
src/renderer/src/bridge/PopupMenu.ts

@ -15,14 +15,14 @@ export class PopupMenu {
private _id: string
private _items: IMenuItemOption[]
private _offs: any[] = []
private clickEvent: Function = ()=>{}
private clickEvent: (...args: any[]) => void = () => {}
constructor(menu_items: IMenuItemOption[]) {
this._id = `popup_menu_${Math.floor(Math.random() * 1e8)}`
this._items = menu_items
}
setClickEvent(fn: Function) {
setClickEvent(fn: () => void) {
this.clickEvent = fn
}
@ -34,11 +34,11 @@ export class PopupMenu {
function readMenu(_items: IMenuItemOption[]) {
return _items.map(i => {
const d = { ...i }
if(!d.click) {
if (!d.click) {
const r = Math.floor(Math.random() * 1e8)
const evt = `popup_menu_item_${_idx++}_${r}`
const off = api.once(evt, (...argus)=>{
console.log(1231);
const off = api.once(evt, (...argus) => {
console.log(1231)
that.clickEvent(i, ...argus)
})
that._offs.push(off)

57
src/renderer/src/components/AdjustLine.vue

@ -10,9 +10,6 @@
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref, watch, computed, onBeforeUnmount, onErrorCaptured } from "vue"
import { useDebounceFn } from "@vueuse/core"
const adjustLineEL = ref<HTMLElement>()
//
@ -153,32 +150,32 @@
if (nextContainer && el && container && parentContainer) {
if (props.direction === "left" || props.direction === "right") {
if (props.mid) {
let w = localStorage.getItem(props.mid)
const w = localStorage.getItem(props.mid)
if (w != undefined) {
container.style.width = w + "px"
}
}
el.onmousedown = function (e) {
let width = container.clientWidth
let nwidth = nextContainer.clientWidth
const width = container.clientWidth
const nwidth = nextContainer.clientWidth
// let owidth = nwidth + width
let owidth = parentContainer.clientWidth
let wwidth = watchContainer?.clientWidth ?? 0
const wwidth = watchContainer?.clientWidth ?? 0
if (isThree) {
owidth = nwidth + width
}
let startX = e.clientX
const startX = e.clientX
let lastPointerEvents = document.body.style.pointerEvents
let lastUserSelect = document.body.style.userSelect
let lastOnmousemove = document.onmousemove
let lastOnmouseup = document.onmouseup
const lastPointerEvents = document.body.style.pointerEvents
const lastUserSelect = document.body.style.userSelect
const lastOnmousemove = document.onmousemove
const lastOnmouseup = document.onmouseup
document.onmousemove = function (e) {
let nowX = e.clientX
const nowX = e.clientX
let w = 0
let offset = startX - nowX
const offset = startX - nowX
if (props.direction == "left") {
w = width + offset
}
@ -203,7 +200,7 @@
document.body.style.pointerEvents = "none"
document.body.style.userSelect = "none"
if (!isThree && watchContainer) {
let ww = wwidth - offset
const ww = wwidth - offset
if (width >= -offset) {
watchContainer.style.width = ww + "px"
}
@ -226,7 +223,7 @@
document.body.style.pointerEvents = lastPointerEvents
document.body.style.userSelect = lastUserSelect
if (props.mid) {
let width = container.clientWidth
const width = container.clientWidth
localStorage.setItem(props.mid, String(width))
}
}
@ -234,40 +231,38 @@
}
if (props.direction === "top" || props.direction === "bottom") {
if (props.mid) {
let w = localStorage.getItem(props.mid)
const w = localStorage.getItem(props.mid)
if (w != undefined) {
container.style.height = w + "px"
}
}
el.onmousedown = function (e) {
let height = container.clientHeight
let nheight = nextContainer.clientHeight
const height = container.clientHeight
const nheight = nextContainer.clientHeight
// let oheight = nheight + height
let oheight = parentContainer.clientHeight
let hheight = watchContainer?.clientHeight ?? 0
const hheight = watchContainer?.clientHeight ?? 0
if (isThree) {
oheight = nheight + height
}
let startY = e.clientY
const startY = e.clientY
let lastPointerEvents = document.body.style.pointerEvents
let lastUserSelect = document.body.style.userSelect
let lastOnmousemove = document.onmousemove
let lastOnmouseup = document.onmouseup
const lastPointerEvents = document.body.style.pointerEvents
const lastUserSelect = document.body.style.userSelect
const lastOnmousemove = document.onmousemove
const lastOnmouseup = document.onmouseup
document.onmousemove = function (e) {
let nowY = e.clientY
const nowY = e.clientY
let h = 0
let offset = startY - nowY
const offset = startY - nowY
if (props.direction == "top") {
h = height + startY - nowY
}
if (props.direction == "bottom") {
h = height - offset
}
console.log(oheight)
if (h >= oheight) {
h = oheight
}
@ -286,7 +281,7 @@
document.body.style.pointerEvents = "none"
document.body.style.userSelect = "none"
if (!isThree && watchContainer) {
let hh = hheight - offset
const hh = hheight - offset
if (height >= -offset) {
watchContainer.style.height = hh + "px"
}
@ -309,7 +304,7 @@
document.body.style.pointerEvents = lastPointerEvents
document.body.style.userSelect = lastUserSelect
if (props.mid) {
let height = container.clientHeight
const height = container.clientHeight
localStorage.setItem(props.mid, String(height))
}
}

55
src/renderer/src/components/CodeEditor/code-editor.vue

@ -7,6 +7,25 @@
const editorRef = ref<HTMLDivElement>()
let editor: monaco.editor.IStandaloneCodeEditor | null = null
let placeholderWidget: PlaceholderContentWidget | null = null
function getOptions(): monaco.editor.IStandaloneEditorConstructionOptions {
return {
...{
fontSize: 14,
readOnly: false,
theme: "vs-light",
fontFamily: "Cascadia Mono, Consolas, 'Courier New', monospace",
lineHeight: 22,
scrollBeyondLastLine: false,
automaticLayout: true,
minimap: {
enabled: false,
},
},
...(props.options ?? {}),
}
}
const props = withDefaults(
defineProps<{
modelValue?: string
@ -14,8 +33,7 @@
logoType?: "bg" | "logo"
logo?: string
placeholder?: string
fontFamily?: string
readonly?: boolean
options?: ReturnType<typeof getOptions>
}>(),
{
logo: DefaultLogo,
@ -94,7 +112,7 @@
const model: monaco.editor.ITextModel = monaco.editor.createModel(content ?? "", file?.language ?? "txt")
model.onDidChangeContent(() => {
if (model) {
if(isInnerChange === "out") {
if (isInnerChange === "out") {
isInnerChange = "waitting"
return
}
@ -118,14 +136,7 @@
onMounted(() => {
if (editorRef.value && !editor) {
editor = monaco.editor.create(editorRef.value, {
theme: "vs-light",
fontFamily: props.fontFamily ?? "Cascadia Mono, Consolas, 'Courier New', monospace",
readOnly: props.readonly,
minimap: {
autohide: true,
},
}) as monaco.editor.IStandaloneCodeEditor
editor = monaco.editor.create(editorRef.value, getOptions()) as monaco.editor.IStandaloneCodeEditor
editor.onDidChangeCursorPosition(e => {
emit("cursor:position", [e.position.lineNumber, e.position.column])
})
@ -152,7 +163,7 @@
watch(
() => props.modelValue,
async str => {
if(isInnerChange === "waitting") {
if (isInnerChange === "waitting") {
isInnerChange = "out"
}
if (editor && isInnerChange === "out") {
@ -172,23 +183,11 @@
},
{ immediate: true },
)
watch(
() => props.readonly,
() => {
if (editor) {
editor.updateOptions({
readOnly: props.readonly,
})
}
},
)
watch(
() => props.fontFamily,
watchDeep(
() => props.options,
() => {
if (editor) {
editor.updateOptions({
fontFamily: props.fontFamily,
})
editor.updateOptions(getOptions())
}
},
)
@ -272,7 +271,7 @@
<template>
<div class="monaco-wrapper">
<div class="monaco-editor" ref="editorRef"></div>
<div ref="editorRef" class="monaco-editor"></div>
<div class="monaco-bg" :style="style">
<img v-if="logoType === 'logo' && getLogo" class="monaco-logo" :src="getLogo" alt="" />
</div>

33
src/renderer/src/components/CodeEditor/hook.ts

@ -0,0 +1,33 @@
import { monaco } from "./monaco"
const defaultOptions: monaco.editor.IStandaloneEditorConstructionOptions = {
fontSize: 14,
readOnly: false,
theme: "vs-light",
fontFamily: "Cascadia Mono, Consolas, 'Courier New', monospace",
lineHeight: 22,
scrollBeyondLastLine: false,
automaticLayout: true,
minimap: {
enabled: false,
},
}
function getOptions(opt = {}) {
return {
...defaultOptions,
...opt,
}
}
export function useMonacoEditor(editor: HTMLDivElement) {
let editor: monaco.editor.IStandaloneCodeEditor | null = null
let placeholderWidget: PlaceholderContentWidget | null = null
return {
scrollTop() {
}
}
}

4
src/renderer/src/components/CodeEditor/monaco.ts

@ -1,7 +1,7 @@
// import 'monaco-editor/esm/vs/editor/editor.all.js';
// import 'monaco-editor/esm/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.js';
// import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import * as monaco from "monaco-editor/esm/vs/editor/editor.api"
// import 'monaco-editor/esm/vs/basic-languages/monaco.contribution.js';
// import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution.js';
@ -11,6 +11,6 @@
// import 'monaco-editor/esm/vs/basic-languages/java/java.contribution.js';
// 导入全部特性
import * as monaco from "monaco-editor"
// import * as monaco from "monaco-editor"
export { monaco }

6
src/renderer/src/components/CodeEditor/utils.ts

@ -1,6 +1,6 @@
export function judgeFile(filename: string) {
if (!filename) return
let ext = [
const ext = [
{ language: "vue", ext: ".vue", index: -1 },
{ language: "javascript", ext: ".js", index: -1 },
{ language: "css", ext: ".css", index: -1 },
@ -16,13 +16,13 @@ export function judgeFile(filename: string) {
for (let i = 0; i < ext.length; i++) {
const e = ext[i]
if (e.ext && filename.endsWith(e.ext)) {
let index = filename.lastIndexOf(e.ext)
const index = filename.lastIndexOf(e.ext)
e.index = index
cur = e
break
}
if (e.pre && filename.startsWith(e.pre)) {
let index = filename.indexOf(e.pre)
const index = filename.indexOf(e.pre)
e.index = index
cur = e
break

2
src/common/event/PlatForm/index.ts → src/renderer/src/composables/Api/Platform/_/index.ts

@ -1,4 +1,4 @@
import { ApiFactory } from "common/lib/abstract"
import { ApiFactory } from "base/api/abstract"
import { BaseSingleton } from "base"
import { LogLevel } from "packages/logger/common"

41
src/renderer/src/composables/Api/Platform/useApiPlatForm.ts

@ -0,0 +1,41 @@
import { LogLevel } from "logger/common"
import { PlatForm } from "./_"
export function useApiPlatForm() {
const plat = PlatForm.getInstance<PlatForm>()
// 全屏状态
const isFullScreen = ref(false)
;(async () => {
isFullScreen.value = await plat.isFullScreen()
})()
const toggleFullScreen = async () => {
await plat.toggleFullScreen()
isFullScreen.value = !isFullScreen.value
}
// 全屏状态 END
const curLogLevel = ref<LogLevel>()
;(async () => {
curLogLevel.value = await plat.logGetLevel()
})()
const isOpenDebug = computed(() => curLogLevel.value === LogLevel.TRACE)
const toggleDebugMode = async () => {
if (curLogLevel.value === LogLevel.TRACE) {
await plat.logSetLevel(LogLevel.INFO)
curLogLevel.value = LogLevel.INFO
return
}
await plat.logSetLevel(LogLevel.TRACE)
curLogLevel.value = LogLevel.TRACE
}
return {
power: plat,
isOpenDebug,
toggleDebugMode,
toggleFullScreen,
isFullScreen,
}
}

2
src/common/event/Setting/index.ts → src/renderer/src/composables/Api/Setting/_/index.ts

@ -1,4 +1,4 @@
import { ApiFactory } from "common/lib/abstract"
import { ApiFactory } from "base/api/abstract"
import { BaseSingleton } from "base"
import { IConfig } from "config"

12
src/common/event/Setting/hook.ts → src/renderer/src/composables/Api/Setting/useApiSetting.ts

@ -1,12 +1,20 @@
import { defineStore } from "pinia"
import { Setting } from "."
import { Setting } from "./_"
import type { IConfig } from "config"
import type { EventMaps, SettingCommand } from "command/Setting/type"
let rawConfig: IConfig = Setting.getInstance().sync() as unknown as IConfig
export const useSettingStore = defineStore(
export const useApiSetting = defineStore(
"Setting",
() => {
const api = getApi<SettingCommand, EventMaps, "SettingCommand">()
api.on("SettingCommand.change", (_, k, v) => {
rawConfig[k] = v
config.value = JSON.parse(JSON.stringify(rawConfig))
})
const config = ref(JSON.parse(JSON.stringify(rawConfig)))
const diffKeys = ref<(keyof IConfig)[]>([])
const isSame = computed(() => {

2
src/common/event/Updater/index.ts → src/renderer/src/composables/Api/Updater/_/index.ts

@ -1,4 +1,4 @@
import { BaseEvent } from "common/lib/abstract"
import { BaseEvent } from "base/api/abstract"
class Updater extends BaseEvent {
constructor() {

70
src/renderer/src/composables/Api/Updater/useApiUpdater.ts

@ -0,0 +1,70 @@
import { EventMaps, UpdaterCommand } from "helper/updater/common"
import { defineStore } from "pinia"
export const enum ApiUpdaterStatus {
Idle = "idle",
Checking = "checking",
StartChecking = "start-checking",
UpdateAvailable = "update-available",
UpdateNotAvailable = "update-not-available",
Downloading = "downloading",
Error = "error",
}
export const useApiUpdater = defineStore(
"Updater",
() => {
const curStatus = ref(ApiUpdaterStatus.Idle)
const speed = ref(0)
const percent = ref(0)
const all = ref(0)
const now = ref(0)
const isNeedUpdate = ref(false)
const api = getApi<UpdaterCommand, EventMaps, "UpdaterCommand">()
api.on("UpdaterCommand.error", (_, data) => {
curStatus.value = ApiUpdaterStatus.Error
console.log(data)
})
api.on("UpdaterCommand.update-not-available", () => {
curStatus.value = ApiUpdaterStatus.UpdateNotAvailable
isNeedUpdate.value = false
})
api.on("UpdaterCommand.update-available", () => {
curStatus.value = ApiUpdaterStatus.UpdateAvailable
isNeedUpdate.value = true
})
api.on("UpdaterCommand.update-progress", (_, data) => {
curStatus.value = ApiUpdaterStatus.Downloading
speed.value = +(data.speed / 1000).toFixed(2) // Convert to KB/s
percent.value = data.percent
all.value = data.all
now.value = data.now
isNeedUpdate.value = false
})
api.on("UpdaterCommand.checking-for-update", () => {
curStatus.value = ApiUpdaterStatus.Checking
})
if (import.meta.env.PROD) {
api.callLong("UpdaterCommand.checkForUpdates")
}
return {
status: curStatus,
speed: speed,
percent: percent,
all: all,
now: now,
isNeedUpdate,
checkForUpdates() {
if (curStatus.value === ApiUpdaterStatus.Checking) return
if (curStatus.value === ApiUpdaterStatus.Downloading) return
curStatus.value = ApiUpdaterStatus.StartChecking
api.callLong("UpdaterCommand.checkForUpdates")
},
}
},
{
persist: false,
},
)

3
src/renderer/src/composables/useTest.ts

@ -1,3 +0,0 @@
export function useTest() {
console.log("test")
}

15
src/renderer/src/main.ts

@ -1,9 +1,11 @@
import 'logger/renderer-error'
import "logger/renderer-error"
import "simplebar-vue/dist/simplebar.min.css"
import "@unocss/reset/normalize.css"
import "@/assets/style/_common.scss"
import "virtual:uno.css"
import 'nprogress/nprogress.css';
import "nprogress/nprogress.css"
import Vue3Toastify, { type ToastContainerOptions } from "vue3-toastify"
import "vue3-toastify/dist/index.css"
import { createApp } from "vue"
import App from "./App.vue"
@ -28,6 +30,15 @@ if (import.meta.env.DEV) {
app.config.performance = true
}
app.use(Vue3Toastify, {
autoClose: 3000,
clearOnUrlChange: false,
pauseOnFocusLoss: false,
newestOnTop: true,
style: {
top: "40px",
},
} as ToastContainerOptions)
app.use(i18n)
app.use(pinia)
app.use(router)

48
src/renderer/src/pages/index/index copy.vue

@ -1,34 +1,34 @@
<script setup lang="ts">
import { useSnippet } from "common/event/Snippet/hook"
definePage({
meta: {
home: true,
},
})
// import { useSnippet } from "common/event/Snippet/hook"
// definePage({
// meta: {
// home: true,
// },
// })
const { getTree } = useSnippet()
// const { getTree } = useSnippet()
const activeLeft = ref<number | null>(null)
function clickActive(e: any) {
const el = e.target as HTMLDivElement
const { x } = el.getBoundingClientRect()
const { width: parentWidth } = el.parentElement!.getBoundingClientRect()
const newLeft = +((x / parentWidth) * 100).toFixed(2)
if (newLeft === activeLeft.value) {
activeLeft.value = null
return
}
activeLeft.value = +((x / parentWidth) * 100).toFixed(2)
}
// const activeLeft = ref<number | null>(null)
// function clickActive(e: any) {
// const el = e.target as HTMLDivElement
// const { x } = el.getBoundingClientRect()
// const { width: parentWidth } = el.parentElement!.getBoundingClientRect()
// const newLeft = +((x / parentWidth) * 100).toFixed(2)
// if (newLeft === activeLeft.value) {
// activeLeft.value = null
// return
// }
// activeLeft.value = +((x / parentWidth) * 100).toFixed(2)
// }
async function click() {
console.log(await getTree())
}
// async function click() {
// console.log(await getTree())
// }
</script>
<template>
<div h-full flex>
<div border-r-coolGray-200 border-r-1 border-r-solid flex flex-col max-w-300px w="3/10">
<!-- <div border-r-coolGray-200 border-r-1 border-r-solid flex flex-col max-w-300px w="3/10">
<div class="list">
<div v-if="activeLeft !== null" class="active" :style="{ left: activeLeft + '%' }"></div>
<div class="item" @click="clickActive">
@ -51,7 +51,7 @@
<div @click="click">文件树</div>
</div>
<div max-w-300px w="3/10" border-r-coolGray-200 border-r-1 border-r-solid>文件树</div>
<div>aa</div>
<div>aa</div> -->
</div>
</template>

30
src/renderer/src/pages/index/index.vue

@ -1,7 +1,33 @@
<script setup lang="ts"></script>
<script setup lang="ts">
// import { useUpdaterStore } from "common/event/Updater/hook"
// const UpdaterStore = useUpdaterStore()
const code = ref("")
const aa = ref(true)
</script>
<template>
<div h-full flex flex-col>sad</div>
<div gap="20px" h-full>
<input type="text" v-model="code" placeholder="请输入文本" class="input" />
<input type="checkbox" v-model="aa"> {{ aa }}
<div h-300px>
<code-editor :options="{ readOnly: aa }" v-model="code" placeholder="请输入文本"></code-editor>
</div>
<div p="20px" flex flex-wrap items-start gap="20px" justify-start rounded>
<div v-for="i in 20" :key="i" class="w-[calc((100%-4*20px)/5)] <lg:w-[calc((100%-2*20px)/3)]" shadow>
<div p-2 text-lg font-bold>MarkdownUtils</div>
<div p-2 pt-0 text-sm>这是一个导航站</div>
<div flex gap="10px" px-4 py-2 tex border-t="1px solid #E5E5E5">
<div cursor="pointer" text-sm leading-1 py-2 px-3 border="1px solid #E5E5E5" rounded>查看</div>
<div cursor="pointer" text-sm leading-1 py-2 px-3 border="1px solid #E5E5E5" rounded>访问</div>
</div>
</div>
<button class="button">Button</button>
<!-- <button @click="UpdaterStore.checkForUpdates()">更新</button> -->
<button @click="$router.push('/browser')">浏览器</button>
</div>
</div>
</template>
<style lang="scss" scoped></style>

136
src/renderer/src/pages/setting.vue

@ -0,0 +1,136 @@
<script setup lang="ts">
import Simplebar from "simplebar-vue"
const settingStore = useApiSetting()
const router = useRouter()
const active = ref(0)
const allApp = reactive([
{ label: "基础设置", path: "/setting/" },
{ label: "更新设置", path: "/setting/update" },
{ label: "开发设置", path: "/setting/dev" },
])
watchEffect(() => {
const currentPath = router.currentRoute.value.path
const index = allApp.findIndex(app => app.path === currentPath)
if (index !== -1) {
active.value = index
}
})
function onClick(app: any, index: number) {
active.value = index
router.replace(app.path)
}
function onClickSave() {
settingStore
.save()
.then(() => {
toast("设置已保存", { type: "success" })
})
.catch(() => {
toast("保存失败,请重试", { type: "error" })
})
}
function onClickReset() {
settingStore.reset()
toast("设置已重置", { type: "info" })
}
</script>
<template>
<div h-full flex>
<div w="100px" h-full relative max-w="500px" min-w="100px">
<Simplebar h-full>
<div
v-for="(app, index) in allApp"
:key="index"
p="8px 10px"
text="12px"
border
border-b
h="30px"
cursor="pointer"
hover:bg-gray-50
class="item"
transition-all
:class="{ active: active === index }"
@click="onClick(app, index)"
>
<div class="text" transition-all position="absolute" left="10px">{{ app.label }}</div>
</div>
</Simplebar>
<AdjustLine></AdjustLine>
</div>
<div class="content" relative b-l="1px solid #E5E5E5" flex-1 w-0 overflow-auto flex flex-col>
<RouterView v-slot="{ Component, route }">
<Transition name="slide-fade" mode="out-in">
<component :is="Component" :key="route.fullPath" />
</Transition>
</RouterView>
</div>
<div v-if="!settingStore.isSame" absolute bottom-20px right-20px flex flex-col gap-20px>
<div
:disabled="settingStore.isSaving"
shadow
flex-center
cursor-pointer
rounded="50%"
p="10px"
bg="blue-500"
color="white"
@click="onClickSave"
>
<icon-material-symbols:save></icon-material-symbols:save>
</div>
<div :disabled="settingStore.isSaving" shadow flex-center cursor-pointer rounded="50%" p="10px" bg="white" @click="onClickReset">
<icon-ix:reset></icon-ix:reset>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.item {
position: relative;
display: flex;
align-items: center;
white-space: nowrap;
&::before {
content: "";
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 6px;
background-color: #f3f4f6;
transition: all linear 300ms;
}
&:hover {
&::before {
width: 30px;
}
.text {
left: 20px;
}
}
&.active {
@apply: text-black;
&::before {
width: 100%;
}
.text {
left: 50%;
transform: translateX(-50%);
}
}
.text {
transition-duration: 300ms;
}
}
</style>

42
src/renderer/src/pages/setting/dev.vue

@ -0,0 +1,42 @@
<script setup lang="ts">
const settingStore = useApiSetting()
</script>
<template>
<div h-full>
<div class="form">
<div class="form-item" :class="{ ['not-save']: settingStore.diffKeys.includes('dev:debug') }">
<div class="form-item__label">存储地址</div>
<div class="form-item__value">
<div class="select">
<select v-model="settingStore.config['dev:debug']">
<option :value="0">开启调试模式</option>
<option :value="2">关闭调试模式</option>
</select>
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.form {
padding: 20px;
.form-item {
display: flex;
align-items: center;
+ .form-item {
margin-top: 15px;
}
.form-item__label {
width: 100px;
font-weight: bold;
flex-basis: 100px;
}
.form-item__value {
width: 600px;
}
}
}
</style>

141
src/renderer/src/pages/setting/index.vue

@ -1,18 +1,133 @@
<script setup lang="ts">
const settingStore = useApiSetting()
</script>
<template>
<div h-full flex>
<div w="200px" border-r="#E5E5E5 solid 1px">左侧菜单</div>
<div flex="1" w="0">
{{ settingStore.isSame }}--{{ settingStore.diffKeys }}
<input v-model="settingStore.config['update.repo']" type="text" />
{{ settingStore.config["update.repo"] }}
<button v-if="!settingStore.isSame" :disabled="settingStore.isSaving" @click="settingStore.save()">保存</button>
<div h-full>
<div class="form">
<div class="form-item" :class="{ ['not-save']: settingStore.diffKeys.includes('storagePath') }">
<div class="form-item__label">存储地址</div>
<div class="form-item__value" flex gap="10px" items-center>
<div class="input-wrapper">
<input v-model="settingStore.config['storagePath']" class="input" readonly type="text" placeholder="请输入存储地址" />
</div>
<button class="button">打开</button>
</div>
</div>
<div class="form-item" :class="{ ['not-save']: settingStore.diffKeys.includes('common.theme') }">
<div class="form-item__label">主题</div>
<div class="form-item__value">
<div class="radio-group">
<div
class="radio"
:class="{ active: settingStore.config['common.theme'] === 'auto' }"
@click="settingStore.config['common.theme'] = 'auto'"
>
Auto
</div>
<div
class="radio"
:class="{ active: settingStore.config['common.theme'] === 'light' }"
@click="settingStore.config['common.theme'] = 'light'"
>
亮色
</div>
<div
class="radio"
:class="{ active: settingStore.config['common.theme'] === 'dark' }"
@click="settingStore.config['common.theme'] = 'dark'"
>
暗色
</div>
</div>
</div>
</div>
<div class="form-item" :class="{ ['not-save']: settingStore.diffKeys.includes('language') }">
<div class="form-item__label">语言</div>
<div class="form-item__value">
<div class="radio-group">
<div
class="radio"
:class="{ active: settingStore.config['language'] === 'zh' }"
@click="settingStore.config['language'] = 'zh'"
>
汉语
</div>
<div
class="radio"
:class="{ active: settingStore.config['language'] === 'en' }"
@click="settingStore.config['language'] = 'en'"
>
中文
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useSettingStore } from "common/event/Setting/hook"
const settingStore = useSettingStore()
console.log(settingStore.config)
</script>
<style lang="scss" scoped>
.form {
padding: 20px;
.form-item {
display: flex;
align-items: center;
+ .form-item {
margin-top: 15px;
}
.form-item__label {
width: 100px;
font-weight: bold;
flex-basis: 100px;
}
.form-item__value {
width: 600px;
}
}
}
.submit {
margin: 20px;
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
&:disabled {
background-color: #ccc;
cursor: not-allowed;
}
}
.input-wrapper {
width: 400px;
transition: width 0.3s ease;
&:focus-within {
width: 600px;
}
}
.radio-group {
display: inline-flex;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
.radio {
flex: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
&:hover {
background-color: #f0f0f0;
}
&.active {
background-color: #e0e0e0;
font-weight: bold;
}
+ .radio {
border-left: 1px solid #ccc;
}
}
}
</style>

72
src/renderer/src/pages/setting/update.vue

@ -0,0 +1,72 @@
<script setup lang="ts">
</script>
<template>
<div h-full flex>dasd</div>
</template>
<style lang="scss" scoped>
.form {
padding: 20px;
.form-item {
display: flex;
align-items: center;
+ .form-item {
margin-top: 15px;
}
.form-item__label {
width: 100px;
font-weight: bold;
flex-basis: 100px;
}
.form-item__value {
width: 300px;
}
}
}
.submit {
margin: 20px;
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
&:disabled {
background-color: #ccc;
cursor: not-allowed;
}
}
// .input-wrapper {
// .input {
// width: 100%;
// padding: 8px;
// border: 1px solid #ccc;
// border-radius: 4px;
// }
// }
.radio-group {
display: inline-flex;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
.radio {
flex: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
&:hover {
background-color: #f0f0f0;
}
&.active {
background-color: #e0e0e0;
font-weight: bold;
}
+ .radio {
border-left: 1px solid #ccc;
}
}
}
</style>

10
src/renderer/src/router/index.ts

@ -1,7 +1,7 @@
import { createWebHashHistory, createRouter, isNavigationFailure } from "vue-router"
import { routes as generatedRoutes, handleHotUpdate } from "vue-router/auto-routes"
import { setupLayouts } from "virtual:generated-layouts"
import NProgress from 'nprogress'
import NProgress from "nprogress"
NProgress.configure({ showSpinner: false, parent: "#page-container" })
@ -12,15 +12,15 @@ const router = createRouter({
routes,
})
router.beforeEach((_to, _from, next)=>{
NProgress.start();
router.beforeEach((_to, _from, next) => {
NProgress.start()
return next()
})
router.afterEach((_to, _from, failure) => {
NProgress.done();
NProgress.done()
if (isNavigationFailure(failure)) {
console.log('failed navigation', failure)
console.log("failed navigation", failure)
}
})

63
src/renderer/src/ui/NavBar.vue

@ -4,7 +4,7 @@
h="30px"
leading="29px"
pr="137px"
:style="{ paddingRight: isFullScreen ? '0' : '' }"
:style="{ paddingRight: PlatForm.isFullScreen.value ? '0' : '' }"
select-none
border-b="1px solid #E5E5E5"
bg="#F8F8F8"
@ -19,6 +19,7 @@
</div>
</div>
<div float-right h-full flex items-center relative style="-webkit-app-region: no-drag">
<Update />
<div
v-if="!isHome"
text-sm
@ -34,19 +35,6 @@
>
<icon-stash:arrow-reply-duotone></icon-stash:arrow-reply-duotone>
</div>
<!-- <div
v-if="!isHome"
text-sm
px-2
hover:rounded-md
hover:bg-gray-2
hover:cursor-pointer
text="hover:hover"
title="返回首页"
@click="backHome"
>
🏠
</div> -->
<div text-sm px-2 hover:rounded-md hover:bg-gray-2 hover:cursor-pointer text="hover:hover" @click="onClickAbout">关于</div>
</div>
</div>
@ -57,19 +45,18 @@
import icon from "@res/icon.png"
import Config from "config"
import { PopupMenu } from "@/bridge/PopupMenu"
import { usePlatForm } from "common/event/PlatForm/hook"
// import { usePlatForm } from "common/event/PlatForm/hook"
import { LogLevel } from "logger/common"
import Update from "./Update.vue"
const PlatForm = usePlatForm()
const PlatForm = useApiPlatForm()
const router = useRouter()
const route = useRoute()
const isFullScreen = ref(false)
const curLogLevel = ref<LogLevel>()
onBeforeMount(async () => {
isFullScreen.value = await PlatForm.isFullScreen()
curLogLevel.value = await PlatForm.logGetLevel()
curLogLevel.value = await PlatForm.power.logGetLevel()
})
const isHome = computed(() => {
@ -97,31 +84,19 @@
{
label: t("browser.navbar.menu.toggleDevTools"),
async click() {
PlatForm.toggleDevTools()
PlatForm.power.toggleDevTools()
},
},
{
label: "重载",
async click() {
PlatForm.reload()
PlatForm.power.reload()
},
},
{
label: "崩溃",
async click() {
PlatForm.crash()
},
},
{
label: curLogLevel.value === LogLevel.TRACE ? "关闭调试模式" : "开启调试模式",
async click() {
if (curLogLevel.value === LogLevel.TRACE) {
await PlatForm.logSetLevel(LogLevel.INFO)
curLogLevel.value = LogLevel.INFO
return
}
await PlatForm.logSetLevel(LogLevel.TRACE)
curLogLevel.value = LogLevel.TRACE
PlatForm.power.crash()
},
},
])
@ -134,10 +109,9 @@
async click(e) {
const menu = new PopupMenu([
{
label: isFullScreen.value ? t("browser.navbar.menu.quit-fullscreen") : t("browser.navbar.menu.fullscreen"),
label: PlatForm.isFullScreen.value ? t("browser.navbar.menu.quit-fullscreen") : t("browser.navbar.menu.fullscreen"),
async click() {
await PlatForm.toggleFullScreen()
isFullScreen.value = !isFullScreen.value
PlatForm.toggleFullScreen()
},
},
])
@ -148,7 +122,7 @@
]
const onClickAbout = () => {
PlatForm.showAbout()
PlatForm.power.showAbout()
}
</script>
@ -161,4 +135,17 @@
@apply: text-sm px-2 hover:rounded-md hover:bg-gray-2 hover:cursor-pointer text="hover:hover";
}
}
.rotate {
animation: rotate 1.5s linear infinite forwards running;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>

76
src/renderer/src/ui/Update.vue

@ -0,0 +1,76 @@
<template>
<div
v-if="UpdaterStore.isNeedUpdate"
text-sm
px-2
py-1
flex
items-center
hover:bg-gray-2
hover:cursor-pointer
text="hover:hover"
@click="UpdaterStore.checkForUpdates"
>
<icon-grommet-icons:update
v-if="
UpdaterStore.status === ApiUpdaterStatus.StartChecking ||
UpdaterStore.status === ApiUpdaterStatus.Checking ||
UpdaterStore.status === ApiUpdaterStatus.UpdateAvailable
"
:class="{ rotate: UpdaterStore.status === ApiUpdaterStatus.Checking }"
></icon-grommet-icons:update>
<icon-bxs:error v-if="UpdaterStore.status === ApiUpdaterStatus.Error" title="更新失败" class="text-red-400"></icon-bxs:error>
</div>
<div
v-if="UpdaterStore.status === ApiUpdaterStatus.Downloading"
class="progress"
style="font-size: 12px"
px-2
flex
items-center
bg-gray-2
hover:cursor-pointer
text="hover:hover"
>
<div class="line" :style="{ width: UpdaterStore.percent + '%' }"></div>
<div class="speed">{{ UpdaterStore.speed }} KB/s</div>
</div>
</template>
<script lang="ts" setup>
const UpdaterStore = useApiUpdater()
</script>
<style lang="scss" scoped>
.rotate {
animation: rotate 1.5s linear infinite forwards running;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.progress {
background-color: rgba(229, 231, 235, 100);
position: relative;
.speed {
position: relative;
z-index: 3;
color: red;
}
.line {
content: "";
z-index: 2;
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 0;
background-color: rgb(239, 156, 156);
}
}
</style>

3
src/renderer/typed-router.d.ts

@ -24,6 +24,9 @@ declare module 'vue-router/auto-routes' {
'about': RouteRecordInfo<'about', '/about', Record<never, never>, Record<never, never>>,
'/browser': RouteRecordInfo<'/browser', '/browser', Record<never, never>, Record<never, never>>,
'/demo': RouteRecordInfo<'/demo', '/demo', Record<never, never>, Record<never, never>>,
'/setting': RouteRecordInfo<'/setting', '/setting', Record<never, never>, Record<never, never>>,
'/setting/': RouteRecordInfo<'/setting/', '/setting', Record<never, never>, Record<never, never>>,
'/setting/dev': RouteRecordInfo<'/setting/dev', '/setting/dev', Record<never, never>, Record<never, never>>,
'/setting/update': RouteRecordInfo<'/setting/update', '/setting/update', Record<never, never>, Record<never, never>>,
}
}

31
src/types/global.d.ts

@ -1,21 +1,30 @@
type FireFN = (...argu: any[]) => void
type Api<T extends Record<string | symbol, FireFN>> = {
call: (command: string, ...args: any[]) => any
callLong: (command: string, ...args: any[]) => any
callSync: (command: string, ...args: any[]) => any
send: (command: string, ...argu: any[]) => any
sendSync: (command: string, ...argu: any[]) => any
on: <S extends keyof T>(command: S, cb: (event: IpcRendererEventIpcRendererEvent, ...args: Parameters<T[S]>) => void) => () => void
once: <S extends keyof T>(command: S, cb: (event: IpcRendererEvent, ...args: Parameters<T[S]>) => void) => () => void
off: <S extends keyof T>(command: S, cb: (event: IpcRendererEvent, ...args: Parameters<T[S]>) => void) => void
offAll: <S extends keyof T>(command: S) => void
type Api<M extends Record<string, (...argu: any[]) => void>, T extends Record<string, FireFN>, N extends string> = {
call: <S extends keyof M>(command: `${N}${N extends string ? "." : ""}${S}`, ...args: Parameters<M[S]>) => any
callLong: <S extends keyof M>(command: `${N}${N extends string ? "." : ""}${S}`, ...args: Parameters<M[S]>) => any
callSync: <S extends keyof M>(command: `${N}${N extends string ? "." : ""}${S}`, ...args: Parameters<M[S]>) => any
send: <S extends keyof M>(command: `${N}${N extends string ? "." : ""}${S}`, ...argu: Parameters<M[S]>) => any
sendSync: <S extends keyof M>(command: `${N}${N extends string ? "." : ""}${S}`, ...argu: Parameters<M[S]>) => any
on: <S extends keyof T>(
command: `${N}${N extends string ? "." : ""}${S}`,
cb: (event: IpcRendererEventIpcRendererEvent, ...args: Parameters<T[S]>) => void,
) => () => void
once: <S extends keyof T>(
command: `${N}${N extends string ? "." : ""}${S}`,
cb: (event: IpcRendererEvent, ...args: Parameters<T[S]>) => void,
) => () => void
off: <S extends keyof T>(
command: `${N}${N extends string ? "." : ""}${S}`,
cb: (event: IpcRendererEvent, ...args: Parameters<T[S]>) => void,
) => void
offAll: <S extends keyof T>(command: `${N}${N extends string ? "." : ""}${S}`) => void
popupMenu: (options: IPopupMenuOption) => void
}
declare const electron: typeof import("@electron-toolkit/preload").electronAPI
declare const api: Api
declare const getApi: <T>() => Api<T>
declare const getApi: <M, T, N>() => Api<M, T, N>
interface Window {
electron: typeof import("@electron-toolkit/preload").electronAPI

3
temp/dev.yml

@ -0,0 +1,3 @@
provider: "github"
owner: "npmrun"
repo: "wood-desktop"

11
tsconfig.node.json

@ -19,15 +19,11 @@
"packages/**/main.ts",
"packages/**/*.common.ts",
"packages/**/common.ts",
"packages/**/*",
"src/common/**/*.main.ts",
"src/common/**/main/**/*",
"src/common/**/main.ts",
"src/common/**/*.common.ts",
"src/common/**/common.ts"
"packages/**/*"
],
"exclude": [
"packages/**/renderer/**/*",
"src/main/command/**/type.d.ts",
],
"compilerOptions": {
"composite": true,
@ -54,9 +50,6 @@
"main/*": [
"src/main/*"
],
"common/*": [
"src/common/*"
],
"@res/*": [
"resources/*"
],

14
tsconfig.web.json

@ -6,6 +6,7 @@
"src/renderer/src/env.d.ts",
"src/renderer/src/**/*",
"src/renderer/src/**/*.vue",
"src/main/command/**/type.d.ts",
"packages/locales/**/*.ts",
"packages/setting/**/*.ts",
"packages/logger/**/*.ts",
@ -13,7 +14,6 @@
"src/types/**/*",
"config/**/*",
"./typed-router.d.ts",
"src/common/**/*",
"packages/**/*",
"packages/**/renderer/**/*",
],
@ -26,9 +26,6 @@
"packages/**/main/**/*",
"packages/**/*.main.ts",
"packages/**/main.ts",
"src/common/**/main/**/*",
"src/common/**/*.main.ts",
"src/common/**/main.ts"
],
"vueCompilerOptions": {
"plugins": [
@ -41,9 +38,13 @@
"moduleResolution": "Bundler",
"types": [
"unplugin-vue-macros/macros-global",
"vite-plugin-vue-layouts/client"
"vite-plugin-vue-layouts/client",
"vue3-toastify/global"
],
"paths": {
"command/*": [
"src/main/command/*"
],
"#": [
"src/types/index"
],
@ -56,9 +57,6 @@
"config/*": [
"config/*"
],
"common/*": [
"src/common/*"
],
"@/*": [
"src/renderer/src/*"
],

Loading…
Cancel
Save