mirror of https://github.com/mashirozx/sakura.git
238 lines
6.7 KiB
Vue
238 lines
6.7 KiB
Vue
<template>
|
|
<div class="picker__container">
|
|
<div class="flex-box">
|
|
<div class="row__wrapper--input">
|
|
<div class="input__wrapper">
|
|
<OutlinedInput v-model:content="userInput" label="Input remote URL here"></OutlinedInput>
|
|
</div>
|
|
<div class="button__wrapper" @click="add">
|
|
<NormalButton icon="fas fas fa-link" context="Add" :contained="true"></NormalButton>
|
|
</div>
|
|
<div class="button__wrapper" @click="open">
|
|
<NormalButton icon="fas fa-box-open" context="Pick" :contained="true"></NormalButton>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="flex-box">
|
|
<div class="row__wrapper--preview">
|
|
<div class="image__box" v-for="(item, index) in selection" :key="index">
|
|
<div class="image__wrapper">
|
|
<Image :src="item.url" :avatar="false" :draggable="false"></Image>
|
|
</div>
|
|
<div class="delete__button" @click="del(index)">
|
|
<span><i class="fas fa-trash-alt"></i></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { defineComponent, ref, watch, Ref } from 'vue'
|
|
import { cloneDeep, remove } from 'lodash'
|
|
import { useMessage, useIntl } from '@/hooks'
|
|
import uniqueHash from '@/utils/uniqueHash'
|
|
import { isUrl } from '@/utils/urlHelper'
|
|
import NormalButton from '@/components/buttons/NormalButton.vue'
|
|
import OutlinedInput from '@/components/inputs/OutlinedInput.vue'
|
|
|
|
export default defineComponent({
|
|
components: { NormalButton, OutlinedInput },
|
|
props: {
|
|
title: { type: String, default: 'Select Media' },
|
|
button: { type: String, default: 'Use this media' },
|
|
type: { type: String, default: 'image' }, // video
|
|
multiple: { type: Boolean, default: true },
|
|
selection: { type: Array, default: () => [] }, // [{url,id}]
|
|
},
|
|
emits: ['update:selection'],
|
|
setup(props, { emit }) {
|
|
const addMessage = useMessage()
|
|
const intl = useIntl()
|
|
|
|
const selection: Ref<{ id: number; url: string }[]> = ref(
|
|
props.selection as { id: number; url: string }[]
|
|
)
|
|
|
|
const userInput = ref('')
|
|
|
|
const frame = (window as any).wp.media({
|
|
id: `media-frame-${uniqueHash()}`,
|
|
title: props.title,
|
|
multiple: props.multiple ? 'add' : false,
|
|
allowLocalEdits: true,
|
|
displaySettings: true,
|
|
displayUserSettings: true,
|
|
library: {
|
|
// author: uid, // specific user-posted attachment
|
|
type: props.type,
|
|
},
|
|
button: { text: props.button },
|
|
})
|
|
|
|
frame.on('select', () => {
|
|
const result = (frame.state().get('selection') as any[]).map((item) => {
|
|
const { id, url } = item.attributes
|
|
return { id: id as number, url: url as string }
|
|
})
|
|
|
|
const selected = cloneDeep(selection.value)
|
|
|
|
// Delete unchecked items
|
|
remove(selected, (item) => item.id > 0 && result.map((i) => i.id).indexOf(item.id) < 0)
|
|
|
|
// Delete existing items
|
|
remove(result, (item) => selected.map((i) => i.id).indexOf(item.id) >= 0)
|
|
|
|
selection.value = [...selected, ...result]
|
|
})
|
|
|
|
// frame.on('close', () => {
|
|
// console.log(frame.state().get('selection').toJSON())
|
|
// })
|
|
|
|
frame.on('open', () => {
|
|
const result = frame.state().get('selection')
|
|
const preSelectIds = selection.value
|
|
.map((item) => (item.id ? (window as any).wp.media.attachment(item.id) : NaN))
|
|
.filter((attachment) => attachment)
|
|
result.add(preSelectIds)
|
|
})
|
|
|
|
const open = () => {
|
|
frame.open()
|
|
}
|
|
|
|
const add = () => {
|
|
const url = userInput.value
|
|
if (isUrl(url).state) {
|
|
if (selection.value.map((item) => item.url).indexOf(url) < 0) {
|
|
selection.value.push({ id: 0, url })
|
|
userInput.value = ''
|
|
} else {
|
|
addMessage({
|
|
title: intl.formatMessage({
|
|
id: 'messages.admin.uplicateUrls',
|
|
defaultMessage: 'Duplicate URLs',
|
|
}),
|
|
type: 'warning',
|
|
})
|
|
}
|
|
} else {
|
|
addMessage({
|
|
title: intl.formatMessage({
|
|
id: 'messages.admin.invalidUrl',
|
|
defaultMessage: 'Invalid URL',
|
|
}),
|
|
type: 'error',
|
|
})
|
|
}
|
|
}
|
|
|
|
const del = (index: number) => {
|
|
remove(selection.value, (item, itemIndex) => index === itemIndex)
|
|
}
|
|
|
|
watch(
|
|
selection,
|
|
(value) => {
|
|
if (!props.multiple && value.length > 1) {
|
|
selection.value = selection.value.slice(-1)
|
|
// console.log(selection.value.length)
|
|
}
|
|
// console.log(selection.value)
|
|
emit('update:selection', selection.value)
|
|
},
|
|
{ deep: true }
|
|
)
|
|
|
|
watch(
|
|
() => props.selection as { id: number; url: string }[],
|
|
(selectionProp) => {
|
|
selection.value = selectionProp
|
|
}
|
|
)
|
|
|
|
return { open, add, del, userInput, selection }
|
|
},
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@use '../variables';
|
|
@use '@/styles/mixins/polyfills';
|
|
.picker__container {
|
|
width: 100%;
|
|
display: flex;
|
|
flex-flow: column nowrap;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
@include polyfills.flex-gap(12px, 'column nowrap');
|
|
> * {
|
|
width: 100%;
|
|
}
|
|
> .flex-box > .row__wrapper {
|
|
&--input {
|
|
display: flex;
|
|
flex-flow: row nowrap;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
@include polyfills.flex-gap(12px, 'row nowrap');
|
|
> .input__wrapper {
|
|
flex: 1 1 auto;
|
|
width: 100%;
|
|
}
|
|
> .button__wrapper {
|
|
flex: 0 0 auto;
|
|
}
|
|
@media screen and (max-width: variables.$small-mobile-max-width) {
|
|
flex-flow: row wrap;
|
|
justify-content: flex-start;
|
|
@include polyfills.flex-gap(12px, 'row wrap');
|
|
}
|
|
}
|
|
&--preview {
|
|
display: flex;
|
|
flex-flow: row wrap;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
@include polyfills.flex-gap(12px, 'row wrap');
|
|
> .image__box {
|
|
position: relative;
|
|
overflow: hidden;
|
|
> .image__wrapper {
|
|
width: 200px;
|
|
height: 200px;
|
|
border: 1px solid #bdbdbd;
|
|
border-radius: 5px;
|
|
overflow: hidden;
|
|
}
|
|
> .delete__button {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
width: 30px;
|
|
height: 30px;
|
|
background: #757575;
|
|
font-size: 16px;
|
|
color: #ffffff;
|
|
border-radius: 0 5px 0 5px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
cursor: pointer;
|
|
opacity: 1;
|
|
transition: all 0.3s ease-in-out;
|
|
}
|
|
&:hover {
|
|
.delete__button {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|