diff --git a/src/components/DiyEditor/components/mobile/MenuList/config.ts b/src/components/DiyEditor/components/mobile/MenuList/config.ts new file mode 100644 index 00000000..f06adfae --- /dev/null +++ b/src/components/DiyEditor/components/mobile/MenuList/config.ts @@ -0,0 +1,39 @@ +import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util' + +/** 列表导航属性 */ +export interface MenuListProperty { + // 导航菜单列表 + list: MenuListItemProperty[] + // 组件样式 + style: ComponentStyle +} +/** 列表导航项目属性 */ +export interface MenuListItemProperty { + // 图标链接 + iconUrl: string + // 标题 + title: string + // 标题颜色 + titleColor: string + // 副标题 + subtitle: string + // 副标题颜色 + subtitleColor: string + // 链接 + url: string +} + +// 定义组件 +export const component = { + id: 'MenuList', + name: '列表导航', + icon: 'fa-solid:list', + property: { + list: [], + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8 + } as ComponentStyle + } +} as DiyComponent<MenuListProperty> diff --git a/src/components/DiyEditor/components/mobile/MenuList/index.vue b/src/components/DiyEditor/components/mobile/MenuList/index.vue new file mode 100644 index 00000000..9a56fd94 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/MenuList/index.vue @@ -0,0 +1,31 @@ +<template> + <div class="min-h-42px flex flex-col"> + <div + v-for="(item, index) in property.list" + :key="index" + class="item h-42px flex flex-row items-center justify-between gap-4px p-x-12px" + > + <div class="flex flex-1 flex-row items-center gap-8px"> + <el-image v-if="item.iconUrl" class="h-16px w-16px" :src="item.iconUrl" /> + <span class="text-16px" :style="{ color: item.titleColor }">{{ item.title }}</span> + </div> + <div class="item-center flex flex-row justify-center gap-4px"> + <span class="text-12px" :style="{ color: item.subtitleColor }">{{ item.subtitle }}</span> + <Icon icon="ep-arrow-right" color="#000" :size="16" /> + </div> + </div> + </div> +</template> + +<script setup lang="ts"> +import { MenuListProperty } from './config' +/** 列表导航 */ +defineOptions({ name: 'MenuList' }) +defineProps<{ property: MenuListProperty }>() +</script> + +<style scoped lang="scss"> +.item + .item { + border-top: 1px solid #eee; +} +</style> diff --git a/src/components/DiyEditor/components/mobile/MenuList/property.vue b/src/components/DiyEditor/components/mobile/MenuList/property.vue new file mode 100644 index 00000000..51652b6e --- /dev/null +++ b/src/components/DiyEditor/components/mobile/MenuList/property.vue @@ -0,0 +1,74 @@ +<template> + <ComponentContainerProperty v-model="formData.style"> + <el-text tag="p"> 菜单设置 </el-text> + <el-text type="info" size="small"> 拖动左侧的小圆点可以调整顺序 </el-text> + + <!-- 表单 --> + <el-form label-width="60px" :model="formData" class="m-t-8px"> + <div v-if="formData.list.length"> + <VueDraggable + :list="formData.list" + item-key="index" + handle=".drag-icon" + :forceFallback="true" + :animation="200" + > + <template #item="{ element, index }"> + <div class="mb-4px flex flex-col gap-4px rounded bg-gray-100 p-8px"> + <div class="flex flex-row justify-between"> + <Icon icon="ic:round-drag-indicator" class="drag-icon cursor-move" /> + <Icon icon="ep:delete" class="text-red-500" @click="handleDeleteMenu(index)" /> + </div> + <el-form-item label="图标" prop="iconUrl"> + <UploadImg v-model="element.iconUrl" height="80px" width="80px"> + <template #tip> 建议尺寸:44 * 44 </template> + </UploadImg> + </el-form-item> + <el-form-item label="标题" prop="title"> + <InputWithColor v-model="element.title" v-model:color="element.titleColor" /> + </el-form-item> + <el-form-item label="副标题" prop="subtitle"> + <InputWithColor v-model="element.subtitle" v-model:color="element.subtitleColor" /> + </el-form-item> + <el-form-item label="链接" prop="url"> + <el-input v-model="element.url" /> + </el-form-item> + </div> + </template> + </VueDraggable> + </div> + <el-form-item label-width="0"> + <el-button @click="handleAddMenu" type="primary" plain class="m-t-8px w-full"> + <Icon icon="ep:plus" class="mr-5px" /> 添加菜单 + </el-button> + </el-form-item> + </el-form> + </ComponentContainerProperty> +</template> + +<script setup lang="ts"> +import VueDraggable from 'vuedraggable' +import { usePropertyForm } from '@/components/DiyEditor/util' +import { MenuListProperty } from '@/components/DiyEditor/components/mobile/MenuList/config' + +/** 列表导航属性面板 */ +defineOptions({ name: 'MenuListProperty' }) + +const props = defineProps<{ modelValue: MenuListProperty }>() +const emit = defineEmits(['update:modelValue']) +const { formData } = usePropertyForm(props.modelValue, emit) + +/* 添加菜单 */ +const handleAddMenu = () => { + formData.value.list.push({ + titleColor: '#333', + subtitleColor: '#bbb' + }) +} +/* 删除菜单 */ +const handleDeleteMenu = (index: number) => { + formData.value.list.splice(index, 1) +} +</script> + +<style scoped lang="scss"></style> diff --git a/src/components/DiyEditor/util.ts b/src/components/DiyEditor/util.ts index 29b44cf6..96dd4dbb 100644 --- a/src/components/DiyEditor/util.ts +++ b/src/components/DiyEditor/util.ts @@ -103,8 +103,9 @@ export const PAGE_LIBS = [ components: [ 'SearchBar', 'NoticeBar', - 'GridNavigation', - 'ListNavigation', + 'MenuSwiper', + 'MenuGrid', + 'MenuList', 'Divider', 'TitleBar' ] diff --git a/src/components/InputWithColor/index.vue b/src/components/InputWithColor/index.vue new file mode 100644 index 00000000..1932fd58 --- /dev/null +++ b/src/components/InputWithColor/index.vue @@ -0,0 +1,58 @@ +<template> + <el-input v-model="valueRef" v-bind="$attrs"> + <template #append> + <el-color-picker v-model="colorRef" :predefine="COLORS" /> + </template> + </el-input> +</template> + +<script lang="ts" setup> +import { propTypes } from '@/utils/propTypes' + +/** + * 带颜色选择器输入框 + */ +defineOptions({ name: 'InputWithColor' }) + +const props = defineProps({ + modelValue: propTypes.string.def('').isRequired, + color: propTypes.string.def('').isRequired +}) + +watch( + () => props.modelValue, + (val: string) => { + if (val === unref(valueRef)) return + valueRef.value = val + } +) + +const emit = defineEmits(['update:modelValue', 'update:color']) + +// 输入框的值 +const valueRef = ref(props.modelValue) +watch( + () => valueRef.value, + (val: string) => { + emit('update:modelValue', val) + } +) +// 颜色 +const colorRef = ref(props.color) +watch( + () => colorRef.value, + (val: string) => { + emit('update:color', val) + } +) +</script> +<style scoped lang="scss"> +:deep(.el-input-group__append) { + padding: 0; + .el-color-picker__trigger { + padding: 0; + border-left: none; + border-radius: 0 var(--el-input-border-radius) var(--el-input-border-radius) 0; + } +} +</style>