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

262 lines
8.0 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, reactive, ref, watch } from 'vue'
import useLayoutStore from '../useLayoutStore'
import { Button, Form, Input, InputGroup } from 'ant-design-vue'
import { OhVueIcon, addIcons } from 'oh-vue-icons'
import { MdUpload, MdImage, MdCheck } from 'oh-vue-icons/icons'
import ImageUploader from '@/utils/ImageUploader'
import useLink from '../../utils/useLink'
import { CheckOutlined } from '@ant-design/icons-vue'
import { v4 as uuid } from 'uuid'
import type { Block } from '../layout.types'
import { ColorPicker } from 'vue3-colorpicker'
import 'vue3-colorpicker/style.css'
import { globalToast } from '@/main'
import UploadAndCut from '@/utils/UploadAndCut'
import { AddToToken } from './AdderPage'
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) {
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 && <OhVueIcon name="md-image" fill="white" scale={1.8} />}
{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 文字
})
const isGame = computed(() => layout.state.current === 0)
const debounced = ref('')
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
})
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 labelCol={{ span: 4 }} labelAlign="left">
<Form.Item label="地址">
<InputGroup compact style="display:flex">
<Input
v-model:value={form.link}
placeholder="搜索想要添加的网址导航"
class="w-0 flex-grow"
/>
<Button></Button>
</InputGroup>
</Form.Item>
<Form.Item label="名称">
<Input v-model:value={form.name} />
</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 && (
<>
<div class="flex">
<Form.Item
label="文字颜色"
class="w-0 flex-grow"
labelCol={{
span: 8
}}
>
<ColorPicker
class="shadow-lg"
format="rgb"
shape="square"
v-model:pureColor={form.color}
/>
</Form.Item>
<Form.Item
label="图标背景"
class="w-0 flex-grow"
labelCol={{
span: 8
}}
>
<ColorPicker
class="shadow-lg"
format="rgb"
shape="square"
v-model:pureColor={form.background}
/>
</Form.Item>
</div>
<Form.Item label="图标文字">
<Input v-model:value={form.text} maxlength={2} />
</Form.Item>
</>
)}
<Form.Item label=" " colon={false}>
<Button
type="primary"
size="large"
icon={<CheckOutlined />}
onClick={() => {
if (form.type === 1 && !form.text && !form.name) {
globalToast.error('文字图标请至少填写文字或者名称')
return
}
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>
)
})