Browse Source

good

develop
谢亚昕 5 days ago
parent
commit
9a9eef5a7c
  1. 3
      electron.vite.config.ts
  2. 3
      package.json
  3. 7
      packages/setting/common.ts
  4. 9
      packages/setting/main.ts
  5. 7
      packages/setting/main/event.ts
  6. 12
      packages/utils/main/session/cookies.ts
  7. 16
      pnpm-lock.yaml
  8. 6
      src/main/command/Setting/command.ts
  9. 8
      src/main/command/Setting/type.d.ts
  10. 2
      src/main/command/Updater/command.ts
  11. 2
      src/renderer/auto-imports.d.ts
  12. 2
      src/renderer/components.d.ts
  13. 27
      src/renderer/src/App.vue
  14. 13
      src/renderer/src/assets/style/_anim.scss
  15. 2
      src/renderer/src/assets/style/_common.scss
  16. 10
      src/renderer/src/bridge/PopupMenu.ts
  17. 57
      src/renderer/src/components/AdjustLine.vue
  18. 55
      src/renderer/src/components/CodeEditor/code-editor.vue
  19. 33
      src/renderer/src/components/CodeEditor/hook.ts
  20. 4
      src/renderer/src/components/CodeEditor/monaco.ts
  21. 6
      src/renderer/src/components/CodeEditor/utils.ts
  22. 8
      src/renderer/src/composables/Api/Setting/useApiSetting.ts
  23. 10
      src/renderer/src/composables/Api/Updater/useApiUpdater.ts
  24. 11
      src/renderer/src/main.ts
  25. 10
      src/renderer/src/pages/index/index.vue
  26. 136
      src/renderer/src/pages/setting.vue
  27. 42
      src/renderer/src/pages/setting/dev.vue
  28. 112
      src/renderer/src/pages/setting/index.vue
  29. 72
      src/renderer/src/pages/setting/update.vue
  30. 10
      src/renderer/src/router/index.ts
  31. 12
      src/renderer/src/ui/NavBar.vue
  32. 3
      src/renderer/typed-router.d.ts
  33. 21
      src/types/global.d.ts
  34. 1
      tsconfig.node.json
  35. 7
      tsconfig.web.json

3
electron.vite.config.ts

@ -95,6 +95,9 @@ export default defineConfig({
"@vueuse/core",
VueRouterAutoImports,
{
"vue3-toastify": ["toast"],
},
{
// add any other imports you were relying on
"vue-router/auto": ["useLink"],
},

3
package.json

@ -86,6 +86,7 @@
"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"
}
}

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
}

9
packages/setting/main.ts

@ -62,6 +62,7 @@ class SettingClass {
this.init()
}
events = emitter
#cb: [IT, IOnFunc][] = []
onChange(fn: IOnFunc, that?: any)
@ -138,7 +139,7 @@ class SettingClass {
this.#sync()
}
init.call(this, this.#config)
emitter.emit("update", this.#config, this.#config)
this.events.emit("update", this.#config, this.#config)
}
config() {
return this.#config
@ -217,7 +218,11 @@ class SettingClass {
if (isChange) {
this.#sync()
this.#runCB(this.#config, oldMainConfig, changeKeys)
emitter.emit("update", 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] {

7
packages/setting/main/event.ts

@ -1,7 +1,4 @@
import { buildEmitter } from "base/event/main"
import type { IOnFunc } from "setting/main"
import { EventMaps } from "setting/common"
export const emitter = buildEmitter<{
init: IOnFunc
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

16
pnpm-lock.yaml

@ -189,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: {}
@ -3712,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:
@ -7755,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

6
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 }

2
src/main/command/Updater/command.ts

@ -9,7 +9,7 @@ export default class UpdaterCommand {
// 命令初始化
logger.debug("UpdaterCommand init")
Updater.events.on("*", (name, ...argus) => {
broadcast(name, ...argus)
broadcast("UpdaterCommand." + name, ...argus)
})
}

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

@ -101,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']
@ -405,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']>

2
src/renderer/components.d.ts

@ -12,6 +12,8 @@ declare module 'vue' {
CodeEditor: typeof import('./src/components/CodeEditor/code-editor.vue')['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']

27
src/renderer/src/App.vue

@ -1,13 +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>
@ -15,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;
}

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

@ -1,3 +1,5 @@
@use "./_anim.scss";
*,
*::before,
*::after {

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

8
src/renderer/src/composables/Api/Setting/useApiSetting.ts

@ -1,12 +1,20 @@
import { defineStore } from "pinia"
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 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(() => {

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

@ -23,19 +23,19 @@ export const useApiUpdater = defineStore(
const isNeedUpdate = ref(false)
const api = getApi<UpdaterCommand, EventMaps, "UpdaterCommand">()
api.on("error", (_, data) => {
api.on("UpdaterCommand.error", (_, data) => {
curStatus.value = ApiUpdaterStatus.Error
console.log(data)
})
api.on("update-not-available", () => {
api.on("UpdaterCommand.update-not-available", () => {
curStatus.value = ApiUpdaterStatus.UpdateNotAvailable
isNeedUpdate.value = false
})
api.on("update-available", () => {
api.on("UpdaterCommand.update-available", () => {
curStatus.value = ApiUpdaterStatus.UpdateAvailable
isNeedUpdate.value = true
})
api.on("update-progress", (_, data) => {
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
@ -43,7 +43,7 @@ export const useApiUpdater = defineStore(
now.value = data.now
isNeedUpdate.value = false
})
api.on("checking-for-update", () => {
api.on("UpdaterCommand.checking-for-update", () => {
curStatus.value = ApiUpdaterStatus.Checking
})
if (import.meta.env.PROD) {

11
src/renderer/src/main.ts

@ -4,6 +4,8 @@ import "@unocss/reset/normalize.css"
import "@/assets/style/_common.scss"
import "virtual:uno.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)

10
src/renderer/src/pages/index/index.vue

@ -2,12 +2,20 @@
// import { useUpdaterStore } from "common/event/Updater/hook"
// const UpdaterStore = useUpdaterStore()
const code = ref("")
const aa = ref(true)
</script>
<template>
<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 class="w-[calc((100%-4*20px)/5)] <lg:w-[calc((100%-2*20px)/3)]" shadow v-for="i in 20" :key="i">
<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">

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>

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

@ -1,56 +1,67 @@
<script setup lang="ts">
import Simplebar from "simplebar-vue"
const settingStore = useApiSetting()
</script>
<template>
<div h-full flex>
<Simplebar w="100px" border-r="#E5E5E5 solid 1px">
<div py-2 hover:bg-gray-100 cursor-pointer text-center text-sm>基础设置</div>
<div py-2 hover:bg-gray-100 cursor-pointer text-center text-sm>更新设置</div>
</Simplebar>
<div flex="1" w="0">
<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">
<div class="input-wrapper">
<input v-model="settingStore.config['storagePath']" class="input" readonly type="text" placeholder="请输入存储地址" />
</div>
<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 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 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 v-if="!settingStore.isSame" text-center>
<button class="submit" :disabled="settingStore.isSaving" @click="settingStore.save()">保存</button>
<button :disabled="settingStore.isSaving" @click="settingStore.reset()">重置</button>
<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>
@ -71,7 +82,7 @@
flex-basis: 100px;
}
.form-item__value {
width: 300px;
width: 600px;
}
}
}
@ -88,14 +99,13 @@
cursor: not-allowed;
}
}
// .input-wrapper {
// .input {
// width: 100%;
// padding: 8px;
// border: 1px solid #ccc;
// border-radius: 4px;
// }
// }
.input-wrapper {
width: 400px;
transition: width 0.3s ease;
&:focus-within {
width: 600px;
}
}
.radio-group {
display: inline-flex;
border: 1px solid #ccc;

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)
}
})

12
src/renderer/src/ui/NavBar.vue

@ -99,18 +99,6 @@
PlatForm.power.crash()
},
},
{
label: curLogLevel.value === LogLevel.TRACE ? "关闭调试模式" : "开启调试模式",
async click() {
if (curLogLevel.value === LogLevel.TRACE) {
await PlatForm.power.logSetLevel(LogLevel.INFO)
curLogLevel.value = LogLevel.INFO
return
}
await PlatForm.power.logSetLevel(LogLevel.TRACE)
curLogLevel.value = LogLevel.TRACE
},
},
])
const obj = e.target.getBoundingClientRect()
menu.show({ x: ~~obj.x, y: ~~(obj.y + obj.height) })

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>>,
}
}

21
src/types/global.d.ts

@ -4,12 +4,21 @@ type Api<M extends Record<string, (...argu: any[]) => void>, T extends Record<st
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: string, ...argu: Parameters<M[S]>) => any
sendSync: <S extends keyof M>(command: string, ...argu: Parameters<M[S]>) => 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
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
}

1
tsconfig.node.json

@ -23,6 +23,7 @@
],
"exclude": [
"packages/**/renderer/**/*",
"src/main/command/**/type.d.ts",
],
"compilerOptions": {
"composite": true,

7
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",
@ -37,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"
],

Loading…
Cancel
Save