Browse Source

更改

main
betaqi 2 weeks ago
parent
commit
84a4b3443f
  1. 7
      global.types/components.d.ts
  2. 39
      src/components/common/FormBuilder.vue
  3. 40
      src/components/drawerSetting/iconSetting.vue
  4. 7
      src/components/drawerSetting/indexSetting.vue
  5. 37
      src/components/drawerSetting/wallpaperSetting.vue
  6. 31
      src/schema/iconSchema.ts
  7. 31
      src/schema/schemaTypes.type.ts
  8. 6
      src/schema/utils.ts
  9. 10
      src/schema/wallpaperSchema.ts
  10. 2
      src/views/home/index.vue

7
global.types/components.d.ts vendored

@ -11,8 +11,10 @@ declare module 'vue' {
AppSearch: typeof import('../src/components/apps/Search.vue')['default'] AppSearch: typeof import('../src/components/apps/Search.vue')['default']
ContextMenu: typeof import('./../src/components/ContextMenu.vue')['default'] ContextMenu: typeof import('./../src/components/ContextMenu.vue')['default']
ContextMenuContainer: typeof import('./../src/components/ContextMenuContainer.vue')['default'] ContextMenuContainer: typeof import('./../src/components/ContextMenuContainer.vue')['default']
DrawerSetting: typeof import('./../src/components/drawerSetting/index.vue')['default'] DrawerSetting: typeof import('../src/components/drawerSetting/indexSetting.vue')['default']
FormBuilder: typeof import('./../src/components/common/FormBuilder.vue')['default']
IconSetting: typeof import('./../src/components/dialogs/iconSetting.vue')['default'] IconSetting: typeof import('./../src/components/dialogs/iconSetting.vue')['default']
IndexSetting: typeof import('./../src/components/drawerSetting/indexSetting.vue')['default']
NButton: typeof import('naive-ui')['NButton'] NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard'] NCard: typeof import('naive-ui')['NCard']
NColorPicker: typeof import('naive-ui')['NColorPicker'] NColorPicker: typeof import('naive-ui')['NColorPicker']
@ -33,7 +35,8 @@ declare module 'vue' {
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
Search: typeof import('./../src/components/apps/Search.vue')['default'] Search: typeof import('./../src/components/apps/Search.vue')['default']
Wallpaper: typeof import('./../src/components/wallpaper.vue')['default'] Wallpaper: typeof import('./../src/components/wallpaper.vue')['default']
WallpaperSetting: typeof import('./../src/components/drawerSetting/wallpaperSetting.vue')['default']
Widget: typeof import('./../src/components/apps/widget.vue')['default'] Widget: typeof import('./../src/components/apps/widget.vue')['default']
WidgetSetting: typeof import('./../src/components/drawerSetting/widgetSetting.vue')['default'] WidgetSetting: typeof import('../src/components/drawerSetting/index.vue')['default']
} }
} }

39
src/components/common/FormBuilder.vue

@ -0,0 +1,39 @@
<script setup lang="ts">
import { NColorPicker, NSlider, NSwitch } from 'naive-ui'
interface IBuilderProps {
type: string
propsOptions: any
context?: any
}
const modelValue = defineModel()
const componentMap: Record<string, Component | undefined> = {
slider: NSlider,
switch: NSwitch,
colorPicker: NColorPicker,
}
const props = defineProps<IBuilderProps>()
const realProps = computed(() => {
if (typeof props.propsOptions === 'function') {
if (!props.context) {
console.warn('[FormBuilder] propsOptions 为函数但未传 context,已自动使用空对象')
return props.propsOptions({})
}
return props.propsOptions(props.context)
}
return props.propsOptions
})
</script>
<template>
<component
:is="componentMap[props.type]"
v-bind="realProps"
v-model:value="modelValue"
/>
</template>
<style scoped lang="scss"></style>

40
src/components/drawerSetting/iconSetting.vue

@ -13,33 +13,13 @@
class="flex justify-between items-center gap-col-12px p-x-12 h-36" class="flex justify-between items-center gap-col-12px p-x-12 h-36"
> >
<span>{{ config.label }}</span> <span>{{ config.label }}</span>
<!-- {{ config.value }} --> <FormBuilder
v-model="values[config.value]"
<template v-if="config.type === 'slider' && config.value === 'iconRadius'"> :type="config.type"
<n-slider :style="config.style"
class="flex-1" :class="config.class"
v-model:value="values[config.value]" :props-options="config.props"
v-bind="config.props" :context="{ values }"
:max="iconRadiusMax"
/>
</template>
<n-slider
v-else-if="config.type === 'slider'"
class="flex-1"
v-model:value="values[config.value]"
v-bind="config.props"
/>
<n-switch
size="small"
v-else-if="config.type === 'switch'"
v-model:value="values[config.value]"
/>
<n-color-picker
v-else-if="config.type === 'colorPicker'"
v-model:value="values[config.value]"
style="width: 28px; height: 28px"
:swatches="swatches"
/> />
<span v-if="config.unit">{{ values[config.value] }}{{ config.unit }}</span> <span v-if="config.unit">{{ values[config.value] }}{{ config.unit }}</span>
</div> </div>
@ -49,14 +29,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { useIconStore } from '@/stores/icon' import { useIconStore } from '@/stores/icon'
import FormBuilder from '@/components/common/FormBuilder.vue'
import iconSchema from '@/schema/iconSchema' import iconSchema from '@/schema/iconSchema'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { swatches } from '@/utils'
const iconStore = useIconStore() const iconStore = useIconStore()
const { values } = storeToRefs(iconStore) const { values } = storeToRefs(iconStore)
const iconRadiusMax = computed(() => {
return values.value?.iconSize / 2
})
</script> </script>

7
src/components/drawerSetting/widgetSetting.vue → src/components/drawerSetting/indexSetting.vue

@ -21,7 +21,8 @@
<script setup lang="ts"> <script setup lang="ts">
import type {MenuOption} from 'naive-ui' import type {MenuOption} from 'naive-ui'
import IconSetting from './iconSetting.vue' import IconSetting from './iconSetting.vue'
import WallpaperSetting from './index.vue' import WallpaperSetting from './wallpaperSetting.vue'
const isShowDrawer = defineModel({default: false}) const isShowDrawer = defineModel({default: false})
const props = defineProps() const props = defineProps()
@ -56,15 +57,19 @@ defineExpose({
.n-drawer-body-content-wrapper { .n-drawer-body-content-wrapper {
padding: 0 !important; padding: 0 !important;
} }
.n-layout-scroll-container { .n-layout-scroll-container {
width: 100%; width: 100%;
} }
.n-menu-item-content__icon { .n-menu-item-content__icon {
margin-right: 0px !important; margin-right: 0px !important;
} }
.n-menu-item-content { .n-menu-item-content {
padding-left: 16px !important; padding-left: 16px !important;
} }
.n-card-header { .n-card-header {
padding: 8px 12px !important; padding: 8px 12px !important;
} }

37
src/components/drawerSetting/index.vue → src/components/drawerSetting/wallpaperSetting.vue

@ -7,27 +7,7 @@
hoverable hoverable
class="border-radius-6" class="border-radius-6"
> >
<div <n-upload multiple directory-dnd :max="1" @before-upload="beforeUpload">
v-for="(config, configIndex) in section.configs"
:key="configIndex"
class="flex justify-between items-center gap-col-12px p-x-12 line-height-36"
>
<span class="w-56">{{ config.label }}</span>
<n-slider
v-if="config.type === 'slider'"
class="flex-1"
v-model:value="values[config.value]"
v-bind="config.props"
/>
<n-upload
v-if="config.type === 'imgUpload'"
multiple
directory-dnd
:max="1"
@before-upload="beforeUpload"
>
<n-upload-dragger> <n-upload-dragger>
<div class="flex flex-col items-center justify-center gap-y-10px p-t-14px"> <div class="flex flex-col items-center justify-center gap-y-10px p-t-14px">
<div class="i-mingcute:pic-ai-fill text-size-24px"></div> <div class="i-mingcute:pic-ai-fill text-size-24px"></div>
@ -35,7 +15,21 @@
</div> </div>
</n-upload-dragger> </n-upload-dragger>
</n-upload> </n-upload>
<div
v-for="(config, configIndex) in filterCustomConfigs(section.configs)"
:key="configIndex"
class="flex justify-between items-center gap-col-12px p-x-12 line-height-36"
>
<span class="w-56">{{ config.label }}</span>
<FormBuilder
v-model="values[config.value]"
:type="config.type"
:style="config.style"
:class="config.class"
:props-options="config.props"
:context="{ values }"
/>
<span v-if="config.unit">{{ values[config.value] }}{{ config.unit }}</span> <span v-if="config.unit">{{ values[config.value] }}{{ config.unit }}</span>
</div> </div>
</n-card> </n-card>
@ -48,6 +42,7 @@ import { useWallpaperStore } from '@/stores/wallpaper'
import { useMessage, type UploadFileInfo } from 'naive-ui' import { useMessage, type UploadFileInfo } from 'naive-ui'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { ref } from 'vue' import { ref } from 'vue'
import { filterCustomConfigs } from '@/schema/utils'
const message = useMessage() const message = useMessage()
const wallpaperStore = useWallpaperStore() const wallpaperStore = useWallpaperStore()

31
src/schema/iconSchema.ts

@ -1,4 +1,7 @@
export default { import type { SchemaType } from "./schemaTypes.type"
import { swatches } from '@/utils'
const iconSchema: SchemaType = {
icon: { icon: {
title: '图标', title: '图标',
type: 'icon', type: 'icon',
@ -14,6 +17,7 @@ export default {
step: 2, step: 2,
}, },
cssVar: '--icon-size', cssVar: '--icon-size',
class: 'flex-1',
unit: 'px', unit: 'px',
}, },
{ {
@ -21,12 +25,13 @@ export default {
type: 'slider', type: 'slider',
value: 'iconRadius', value: 'iconRadius',
defaultValue: 16, defaultValue: 16,
props: { props: (context) => ({
min: 0, min: 0,
max: 100, max: context?.values?.iconSize / 2 || 100,
step: 1, step: 1,
}, }),
cssVar: '--icon-radius', cssVar: '--icon-radius',
class: 'flex-1',
unit: 'px', unit: 'px',
}, },
{ {
@ -34,7 +39,7 @@ export default {
type: 'slider', type: 'slider',
value: 'iconOpacity', value: 'iconOpacity',
defaultValue: 100, defaultValue: 100,
class: 'flex-1',
props: { props: {
min: 0, min: 0,
max: 100, max: 100,
@ -55,6 +60,7 @@ export default {
value: 'iconRowSpace', value: 'iconRowSpace',
unit: 'px', unit: 'px',
defaultValue: 27, defaultValue: 27,
class: 'flex-1',
props: { props: {
min: 0, min: 0,
max: 100, max: 100,
@ -74,7 +80,9 @@ export default {
value: 'nameTextShow', value: 'nameTextShow',
defaultValue: true, defaultValue: true,
cssVar: '--icon-name', cssVar: '--icon-name',
props: {}, props: {
size: "small"
},
}, },
{ {
label: '名称颜色', label: '名称颜色',
@ -82,11 +90,19 @@ export default {
value: 'nameColor', value: 'nameColor',
defaultValue: '#fff', defaultValue: '#fff',
cssVar: '--icon-nameColor', cssVar: '--icon-nameColor',
props: {
swatches: swatches,
},
style: {
width: '28px',
height: '28px'
}
}, },
{ {
label: '字体大小', label: '字体大小',
type: 'slider', type: 'slider',
value: 'nameSize', value: 'nameSize',
class: 'flex-1',
defaultValue: 14, defaultValue: 14,
props: { props: {
min: 12, min: 12,
@ -107,6 +123,7 @@ export default {
type: 'slider', type: 'slider',
value: 'iconGridWidth', value: 'iconGridWidth',
defaultValue: 900, defaultValue: 900,
class: 'flex-1',
props: { props: {
min: 900, min: 900,
max: 2000, max: 2000,
@ -118,3 +135,5 @@ export default {
], ],
}, },
} }
export default iconSchema

31
src/schema/schemaTypes.type.ts

@ -0,0 +1,31 @@
// custom 组件不做类型约束
export interface FormBuilderContext {
values: Record<string, any>
}
export type ConfigProps =
| Record<string, any>
| ((context: FormBuilderContext) => Record<string, any>)
export interface ConfigItem {
label: string;
type: string;
value: string;
class?: string;
style?: Record<string, string>
defaultValue: number | boolean | string;
props?: ConfigProps;
cssVar?: string;
unit?: string;
}
export interface SchemaSection {
title: string;
type: string;
configs: ConfigItem[];
}
export type SchemaType = Record<string, SchemaSection>;

6
src/schema/utils.ts

@ -0,0 +1,6 @@
import type { ConfigItem } from "./schemaTypes.type";
// 过滤type中 包含 custom 的配置项
export function filterCustomConfigs(configs: ConfigItem[]) {
return configs.filter(config => !config.type.includes('custom'));
}

10
src/schema/wallpaperSchema.ts

@ -1,11 +1,13 @@
export default { import type { SchemaType } from "./schemaTypes.type";
const wallpaperSchema: SchemaType = {
wallpaper: { wallpaper: {
title: '壁纸', title: '壁纸',
type: 'wallpaper', type: 'wallpaper',
configs: [ configs: [
{ {
label: '壁纸', label: '壁纸',
type: 'imgUpload', type: 'custom-imgUpload',
value: 'wallpaperImg', value: 'wallpaperImg',
defaultValue: '', defaultValue: '',
}, },
@ -13,6 +15,7 @@ export default {
label: '模糊度', label: '模糊度',
type: 'slider', type: 'slider',
value: 'wallpaperBlur', value: 'wallpaperBlur',
class: 'flex-1',
defaultValue: 0, defaultValue: 0,
props: { props: {
min: 0, min: 0,
@ -25,6 +28,7 @@ export default {
label: '遮罩浓度', label: '遮罩浓度',
type: 'slider', type: 'slider',
value: 'wallpaperMask', value: 'wallpaperMask',
class: 'flex-1',
defaultValue: 0, defaultValue: 0,
props: { props: {
min: 0, min: 0,
@ -36,3 +40,5 @@ export default {
], ],
}, },
} }
export default wallpaperSchema

2
src/views/home/index.vue

@ -26,7 +26,7 @@ import Search from '@/components/apps/Search.vue'
import Widget from '@/components/apps/widget.vue' import Widget from '@/components/apps/widget.vue'
import type { IContextMenu, IWidget } from '../../utils/types' import type { IContextMenu, IWidget } from '../../utils/types'
import { useContextMenuManager } from '@/composables/useContextMenu' import { useContextMenuManager } from '@/composables/useContextMenu'
import DrawerSetting from '@/components/drawerSetting/widgetSetting.vue' import DrawerSetting from '@/components/drawerSetting/indexSetting.vue'
import IconSetting from '@/components/dialogs/iconSetting.vue' import IconSetting from '@/components/dialogs/iconSetting.vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useWidgetStore } from '@/stores/widget' import { useWidgetStore } from '@/stores/widget'

Loading…
Cancel
Save