xyyd-fatfox/src/layout/adder/CustomAdder.tsx

305 lines
9.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { computed, defineComponent, inject, onMounted, reactive, ref, watch } from 'vue'
import useLayoutStore from '../useLayoutStore'
import { Form, Input } from 'ant-design-vue'
import { OhVueIcon, addIcons } from 'oh-vue-icons'
import { MdUpload, MdImage, MdCheck } from 'oh-vue-icons/icons'
import useLink from '../../utils/useLink'
import { v4 as uuid } from 'uuid'
import type { Block } from '../layout.types'
import 'vue3-colorpicker/style.css'
import { globalToast } from '@/main'
import UploadAndCut from '@/utils/UploadAndCut'
import { AddToToken } from './AdderPage'
import useAdderPageStore, { type EditBlockItemType } from './useAdderPageStore'
import useRouterStore from '@/useRouterStore'
import NativeColorPicker from '@/utils/NativeColorPicker'
addIcons(MdUpload, MdImage, MdCheck)
const TypeSelector = defineComponent({
props: {
value: {
type: Number,
default: 0
},
icon: {
type: String,
default: ''
},
text: {
type: String,
default: ''
},
color: {
type: String,
default: ''
},
background: {
type: String,
default: ''
},
name: {
type: String,
default: ''
}
},
emits: {
'update:value': (() => true) as (val: number) => boolean,
'update:icon': (() => true) as (val: string) => boolean
},
setup(props, ctx) {
const layout = useLayoutStore()
return () => (
<div class="flex gap-4">
<div class={'flex justify-center flex-col items-center gap-y-1'}>
<div
class="w-[47px] relative h-[47px] bg-center bg-no-repeat bg-cover rounded-lg overflow-hidden flex justify-center items-center cursor-pointer hover:scale-105 transition-all"
style={{
backgroundImage: `url('${props.icon}')`,
backgroundColor: props.icon ? '' : 'rgba(0,0,0,0.2)'
}}
onClick={() => {
ctx.emit('update:value', 0)
}}
>
{!props.icon && <img src={'/tab/icons/bgGameCloud.png'}></img>}
{props.value === 0 && (
<div
class={
'w-[20px] h-[20px] rounded bg-white/50 flex items-center justify-center absolute right-0 bottom-0'
}
>
<OhVueIcon name="md-check" fill="red" scale={0.8}></OhVueIcon>
</div>
)}
</div>
<span class={'text-[12px]'}></span>
</div>
<div class={'flex justify-center flex-col items-center gap-y-1 '}>
<div
class="w-[44px] relative h-[44px] bg-center bg-no-repeat bg-cover rounded-lg overflow-hidden flex justify-center items-center cursor-pointer hover:scale-105 transition-all"
style={{
backgroundColor: props.background || 'transparent'
}}
onClick={() => {
ctx.emit('update:value', 1)
}}
>
<span
class="text-[16px]"
style={{
color: props.color
}}
>
{props.text
? props.text.substring(0, 2)
: props.name.substring(0, 2).toLocaleUpperCase() || 'A'}
</span>
{props.value === 1 && (
<div
class={
'w-[20px] h-[20px] rounded bg-white/50 flex items-center justify-center absolute right-0 bottom-0'
}
>
<OhVueIcon name="md-check" fill="red" scale={0.8}></OhVueIcon>
</div>
)}
</div>
<span class={'text-[12px]'}></span>
</div>
<div class={'flex justify-center flex-col items-center gap-y-1'}>
<div class="w-[44px] h-[44px] rounded-lg flex overflow-hidden justify-center items-center bg-white shadow cursor-pointer hover:scale-105 transition-all">
{/* <ImageUploader
width={44}
onUpdate:value={(e) => {
ctx.emit('update:icon', e)
}}
></ImageUploader> */}
<UploadAndCut
onUpdate:value={(e) => {
ctx.emit('update:icon', e)
}}
></UploadAndCut>
</div>
<span class={'text-[12px]'}></span>
</div>
</div>
)
}
})
export default defineComponent(() => {
const layout = useLayoutStore()
const form = reactive({
link: '',
name: '',
text: '',
background: 'rgb(247,169,78)',
color: 'rgb(255,255,255)',
icon: '',
type: 0 // 0 默认1 文字
} as EditBlockItemType)
const isGame = computed(() => layout.state.current === 0)
const debounced = ref('')
const store = useAdderPageStore()
onMounted(() => {
if (store.editBlockItem !== null) {
form.link = store.editBlockItem.link
form.name = store.editBlockItem.name
form.icon = store.editBlockItem.icon
form.text = store.editBlockItem.text
form.background = store.editBlockItem.background
form.color = store.editBlockItem.color
form.type = store.editBlockItem.type
}
})
watch(
() => form.link,
(val, _, onCleanup) => {
const it = setTimeout(() => {
debounced.value = val
}, 500)
onCleanup(() => {
clearTimeout(it)
})
}
)
const info = useLink(debounced)
watch(info, (val) => {
if (val.name) form.name = val.name
if (val.icon) form.icon = val.icon
})
watch(
() => form.type,
(cur, pre) => {
if (cur === 1) {
if (!form.name) {
globalToast.error('文字图标请至少填写文字或者名称')
form.type = pre
return
} else {
form.text = form.name.substring(0, 2).toLocaleUpperCase()
}
}
}
)
const addTo = inject(AddToToken)
return () => (
<div
class={
'absolute left-0 top-0 w-full h-full rounded-2xl py-5 pl-6 pr-[30%] ' +
(isGame.value ? 'bg-white/20' : 'bg-white/70')
}
>
<Form>
<Form.Item label="地址" class={'relative'}>
<Input
v-model:value={form.link}
placeholder="搜索想要添加的网址导航"
class={isGame?.value ? '' : ' bg-black/10 '}
/>
<span
class={'absolute right-[-70px] top-1/2 -translate-y-1/2 cursor-pointer'}
onClick={() => {
debounced.value = debounced.value + ' '
}}
>
</span>
</Form.Item>
<Form.Item label="名称">
<Input v-model:value={form.name} class={isGame?.value ? '' : ' bg-black/10 '} />
</Form.Item>
<Form.Item label="图标">
<TypeSelector
v-model:value={form.type}
v-model:icon={form.icon}
name={form.name}
text={form.text}
color={form.color}
background={form.background}
/>
</Form.Item>
{form.type === 1 && (
<>
<Form.Item label="图标背景">
<NativeColorPicker
size={30}
colorList={[
'rgb(227, 127, 53)',
'rgb(239, 195, 57)',
'rgb(65, 201, 117)',
'rgb(67, 195, 195)',
'rgb(97, 182, 255)',
'rgb(153, 91, 179)'
]}
value={form.background}
onUpdate:value={(e) => {
form.background = e
}}
></NativeColorPicker>
</Form.Item>
<Form.Item label="图标文字">
<Input
v-model:value={form.text}
maxlength={2}
class={isGame?.value ? '' : ' bg-black/10 '}
/>
</Form.Item>
</>
)}
<Form.Item label=" " colon={false}>
<button
class={
'outline-none ml-[23px] mt-2 flex items-center hover:opacity-90 text-[16px] justify-center gap-x-2 text-white w-[94px] h-[40px] rounded-lg'
}
style={{
background: 'linear-gradient(180deg,#ffaa4e 0%,#ff6227 100%)'
}}
onClick={() => {
if (form.type === 1 && !form.text && !form.name) {
globalToast.error('文字图标请至少填写文字或者名称')
return
}
if (!form.link) {
globalToast.warning('请输入网站链接')
return
}
if (!form.name) {
globalToast.warning('请输入网站名称')
return
}
if (store.editBlockItem !== null) {
console.log(123)
layout.changeBlock(form, store.editBlockItem.id)
useRouterStore().back()
store.editBlockItem = null
} else {
const id = uuid()
const data: Block = {
id,
link: form.link,
name: '',
icon: form.type === 0 ? form.icon || info.icon : '',
background: form.type === 0 ? '' : form.background,
color: form.type === 0 ? '' : form.color,
w: 1,
h: 1,
text:
form.type === 0
? ''
: form.text || form.name.substring(0, 2).toLocaleUpperCase(),
label: form.name
}
layout.addBlock(data, addTo?.value)
}
}}
>
</button>
</Form.Item>
</Form>
</div>
)
})