35 changed files with 559 additions and 180 deletions
@ -0,0 +1,7 @@ |
|||
import type { IOnFunc } from "setting/main" |
|||
|
|||
export type EventMaps = { |
|||
init: IOnFunc |
|||
update: IOnFunc |
|||
change: (key: string, value: any) => void |
|||
} |
@ -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>() |
|||
|
@ -0,0 +1,8 @@ |
|||
import type { EventMaps } from "setting/common" |
|||
|
|||
export interface SettingCommand { |
|||
save: () => void |
|||
reset: () => void |
|||
} |
|||
|
|||
export { EventMaps } |
@ -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; |
|||
} |
@ -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() { |
|||
|
|||
} |
|||
} |
|||
} |
@ -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> |
@ -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> |
@ -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> |
Loading…
Reference in new issue