mirror of
https://github.com/mashirozx/sakura.git
synced 2024-12-12 09:54:35 +08:00
Add admin page component
This commit is contained in:
parent
edeab203e0
commit
4f0c68a46b
@ -79,6 +79,8 @@ class AdminPageHelper extends ViteHelper
|
||||
|
||||
public function enqueue_common_scripts()
|
||||
{
|
||||
wp_enqueue_media();
|
||||
|
||||
wp_enqueue_style('style.css', get_template_directory_uri() . '/style.css');
|
||||
|
||||
wp_enqueue_style('fontawesome-free', 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/all.min.css');
|
||||
|
@ -30,12 +30,16 @@
|
||||
"@formatjs/intl": "^1.13.2",
|
||||
"@material/button": "^12.0.0-canary.068fd5028.0",
|
||||
"@material/card": "^12.0.0-canary.068fd5028.0",
|
||||
"@material/checkbox": "^12.0.0-canary.e1703bed9.0",
|
||||
"@material/chips": "^12.0.0-canary.068fd5028.0",
|
||||
"@material/dialog": "^12.0.0-canary.068fd5028.0",
|
||||
"@material/elevation": "^12.0.0-canary.068fd5028.0",
|
||||
"@material/form-field": "^12.0.0-canary.e1703bed9.0",
|
||||
"@material/list": "^12.0.0-canary.068fd5028.0",
|
||||
"@material/menu": "^12.0.0-canary.068fd5028.0",
|
||||
"@material/radio": "^12.0.0-canary.9f68a932e.0",
|
||||
"@material/ripple": "^12.0.0-canary.068fd5028.0",
|
||||
"@material/switch": "^12.0.0-canary.9f68a932e.0",
|
||||
"@material/tab-bar": "^12.0.0-canary.22d29cbb4.0",
|
||||
"@material/textfield": "^12.0.0-canary.068fd5028.0",
|
||||
"@material/theme": "^12.0.0-canary.068fd5028.0",
|
||||
@ -95,7 +99,8 @@
|
||||
"vite": "^2.4.2",
|
||||
"vite-plugin-svgicon": "^1.0.0-alpha.0",
|
||||
"vue-jest": "^5.0.0-alpha.10",
|
||||
"vue-tsc": "^0.2.0"
|
||||
"vue-tsc": "^0.2.0",
|
||||
"wp-types": "^2.10.0"
|
||||
},
|
||||
"engines": {
|
||||
"npm": "please-use-yarn",
|
||||
|
@ -16,32 +16,49 @@
|
||||
v-for="(tabKey, tabKeyIndex) in tabKeys"
|
||||
:key="tabKeyIndex"
|
||||
>
|
||||
<div class="tab-page__content mdc-typography">
|
||||
<h1 class="mdc-typography--headline5">{{ options[tabKey].title }}</h1>
|
||||
<div class="tab-page__content">
|
||||
<h1 class="row__wrapper--title">{{ options[tabKey].title }}</h1>
|
||||
<p class="row__wrapper--desc" v-if="options[tabKey].desc"> {{ options[tabKey].desc }} </p>
|
||||
<div
|
||||
class="row__wrapper--options"
|
||||
v-for="(option, optionIndex) in options[tabKey].options"
|
||||
:key="optionIndex"
|
||||
>
|
||||
{{ option.namespace }}
|
||||
<OptionItem :option="option"></OptionItem>
|
||||
</div>
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
<div class="buttons__wrapper">
|
||||
<NormalButton icon="fas fa-save" context="Save" :contained="true"></NormalButton>
|
||||
<NormalButton icon="fas fa-upload" context="Import" :contained="true"></NormalButton>
|
||||
<NormalButton icon="fas fa-download" context="Export" :contained="true"></NormalButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, Ref, watch, nextTick } from 'vue'
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
Ref,
|
||||
watch,
|
||||
nextTick,
|
||||
watchEffect,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
} from 'vue'
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue'
|
||||
import { Swiper as SwiperInterface } from 'swiper'
|
||||
import { useInjector } from '@/hooks'
|
||||
import store from './store'
|
||||
import options from '@/admin/options'
|
||||
import TabBar from '@/components/tabBar/TabBar.vue'
|
||||
import OptionItem from './OptionItem.vue'
|
||||
import NormalButton from '@/components/buttons/NormalButton.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { TabBar, Swiper, SwiperSlide },
|
||||
components: { TabBar, Swiper, SwiperSlide, OptionItem, NormalButton },
|
||||
setup() {
|
||||
// UI controllers
|
||||
const currentTabIndex: Ref<number> = ref(0)
|
||||
@ -55,7 +72,16 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
watch(currentTabIndex, (current) => swiperRef.value?.slideTo(current))
|
||||
nextTick(() => swiperRef.value?.updateAutoHeight(100))
|
||||
|
||||
const updateAutoHeight = () => swiperRef.value?.updateAutoHeight(0)
|
||||
|
||||
// nextTick(() => updateAutoHeight())
|
||||
// watchEffect(() => updateAutoHeight())
|
||||
|
||||
onMounted(() => {
|
||||
const timer = setInterval(() => updateAutoHeight(), 100)
|
||||
onBeforeUnmount(() => clearInterval(timer))
|
||||
})
|
||||
|
||||
// data controllers
|
||||
const { config, setConfig } = useInjector(store)
|
||||
@ -87,5 +113,14 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
}
|
||||
> .buttons__wrapper {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
width: calc(100% - 24px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,24 +1,168 @@
|
||||
<template>
|
||||
<div class="option__container">
|
||||
<h1 class="mdc-typography--headline6">{{ $props.namespace }}</h1>
|
||||
<h3 class="column__wrapper--label"> {{ title }} </h3>
|
||||
<div class="column__wrapper--main">
|
||||
<div class="row__wrapper--option">
|
||||
<OutlinedInput
|
||||
v-if="type === 'string'"
|
||||
v-model:content="optionResultRef"
|
||||
v-bind="binds"
|
||||
></OutlinedInput>
|
||||
<OutlinedTextarea
|
||||
v-else-if="type === 'longString'"
|
||||
v-model:content="optionResultRef"
|
||||
v-bind="binds"
|
||||
></OutlinedTextarea>
|
||||
<Selection
|
||||
v-else-if="type === 'selection'"
|
||||
v-model:result="optionResultRef"
|
||||
v-bind="binds"
|
||||
></Selection>
|
||||
<Choose
|
||||
v-else-if="type === 'choose'"
|
||||
v-model:result="optionResultRef"
|
||||
v-bind="binds"
|
||||
></Choose>
|
||||
<MediaPicker
|
||||
v-else-if="type === 'mediaPicker'"
|
||||
v-model:selection="optionResultRef"
|
||||
v-bind="binds"
|
||||
></MediaPicker>
|
||||
<Switcher
|
||||
v-else-if="type === 'switcher'"
|
||||
v-model:checked="optionResultRef"
|
||||
v-bind="binds"
|
||||
></Switcher>
|
||||
</div>
|
||||
<p class="row__wrapper--desc" v-if="desc">
|
||||
<i class="fas fa-info-circle"></i> <span v-html="desc"></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import { useInjector } from '@/hooks'
|
||||
import store from './store'
|
||||
|
||||
const defaultOption = {}
|
||||
import validator from './validator'
|
||||
import OutlinedInput from '@/components/inputs/OutlinedInput.vue'
|
||||
import OutlinedTextarea from '@/components/inputs/OutlinedTextarea.vue'
|
||||
import Selection from '@/components/checkbox/Selection.vue'
|
||||
import MediaPicker from '@/admin/components/MediaPicker.vue'
|
||||
import Choose from '@/components/radio/Choose.vue'
|
||||
import Switcher from '@/components/switcher/Switcher.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { OutlinedInput, OutlinedTextarea, Selection, MediaPicker, Choose, Switcher },
|
||||
props: {
|
||||
options: { type: Object, default: () => defaultOption },
|
||||
option: { type: Object, required: true },
|
||||
},
|
||||
emits: [],
|
||||
setup(props, { emit }) {
|
||||
const { config, setConfig } = useInjector(store)
|
||||
return {}
|
||||
const { namespace, type, title, desc, binds } = props.option
|
||||
const { config, updateOption } = useInjector(store)
|
||||
const optionResultRef = ref(config.value[namespace] ?? props.option.default)
|
||||
|
||||
watch(
|
||||
optionResultRef,
|
||||
(result) => {
|
||||
if (validator(result, type).pass) {
|
||||
updateOption(config, namespace, result)
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
|
||||
return { config, optionResultRef, type, title, desc, binds }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.option__container {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: space-between;
|
||||
justify-content: flex-start;
|
||||
> .column__wrapper {
|
||||
&--label {
|
||||
flex: 0 0 auto;
|
||||
width: 200px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
&--main {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: space-between;
|
||||
justify-content: flex-start;
|
||||
padding-top: 12px;
|
||||
> .row__wrapper {
|
||||
&--option {
|
||||
width: 100%;
|
||||
}
|
||||
&--desc {
|
||||
font-size: 14px;
|
||||
color: #646970;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// custom
|
||||
// ::v-deep() {
|
||||
// .mdc-checkbox {
|
||||
// transform: translateX(-13px);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Polyfill WP default styles
|
||||
::v-deep() {
|
||||
input.disabled,
|
||||
input:disabled,
|
||||
select.disabled,
|
||||
select:disabled,
|
||||
textarea.disabled,
|
||||
textarea:disabled {
|
||||
background: unset;
|
||||
border-color: unset;
|
||||
box-shadow: unset;
|
||||
color: unset;
|
||||
}
|
||||
input[type='checkbox'],
|
||||
input[type='radio'] {
|
||||
border: unset;
|
||||
}
|
||||
|
||||
input[type='checkbox']:focus,
|
||||
input[type='color']:focus,
|
||||
input[type='date']:focus,
|
||||
input[type='datetime-local']:focus,
|
||||
input[type='datetime']:focus,
|
||||
input[type='email']:focus,
|
||||
input[type='month']:focus,
|
||||
input[type='number']:focus,
|
||||
input[type='password']:focus,
|
||||
input[type='radio']:focus,
|
||||
input[type='search']:focus,
|
||||
input[type='tel']:focus,
|
||||
input[type='text']:focus,
|
||||
input[type='time']:focus,
|
||||
input[type='url']:focus,
|
||||
input[type='week']:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
border-color: unset;
|
||||
box-shadow: unset;
|
||||
outline: unset;
|
||||
}
|
||||
|
||||
.notice-error,
|
||||
div.error {
|
||||
border-left-color: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1 +0,0 @@
|
||||
# The admin's panel sub-project
|
194
src/admin/components/MediaPicker.vue
Normal file
194
src/admin/components/MediaPicker.vue
Normal file
@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div class="picker__container">
|
||||
<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 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>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch, Ref } from 'vue'
|
||||
import { cloneDeep, remove } from 'lodash'
|
||||
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 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 {
|
||||
// TODO
|
||||
console.warn('Duplicate URLs')
|
||||
}
|
||||
} else {
|
||||
// TODO
|
||||
console.warn('Invalid URL')
|
||||
}
|
||||
}
|
||||
|
||||
const del = (index: number) => {
|
||||
remove(selection.value, (item, itemIndex) => index === itemIndex)
|
||||
}
|
||||
|
||||
watch(selection, (value) => emit('update:selection', value), { deep: true })
|
||||
|
||||
return { open, add, del, userInput, selection }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.picker__container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
> * {
|
||||
width: 100%;
|
||||
}
|
||||
> .row__wrapper {
|
||||
&--input {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
> .input__wrapper {
|
||||
flex: 1 1 auto;
|
||||
width: 100%;
|
||||
}
|
||||
> .button__wrapper {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
&--preview {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
> .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: 0;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
&:hover {
|
||||
.delete__button {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -2,13 +2,18 @@
|
||||
@use '@material/elevation/mdc-elevation';
|
||||
@use '@material/button/mdc-button';
|
||||
@use "@material/textfield/mdc-text-field";
|
||||
@use '@material/chips/deprecated/mdc-chips';
|
||||
@use '@material/list/mdc-list';
|
||||
// @use '@material/chips/deprecated/mdc-chips';
|
||||
// @use '@material/list/mdc-list';
|
||||
@use '@material/card/mdc-card';
|
||||
|
||||
// local only
|
||||
@use "@material/tab-bar/mdc-tab-bar";
|
||||
@use "@material/tab-scroller/mdc-tab-scroller";
|
||||
@use "@material/tab-indicator/mdc-tab-indicator";
|
||||
@use "@material/tab/mdc-tab";
|
||||
@use '@material/typography/mdc-typography';
|
||||
// @use '@material/typography/mdc-typography';
|
||||
|
||||
@use "@material/checkbox/mdc-checkbox";
|
||||
// @use "@material/form-field/mdc-form-field";
|
||||
@use "@material/radio/mdc-radio";
|
||||
// @use "@material/switch/deprecated/mdc-switch";
|
||||
@use '@material/switch/styles';
|
||||
|
@ -1,11 +1,15 @@
|
||||
export interface Options {
|
||||
[tag: string]: {
|
||||
title: string
|
||||
desc?: string
|
||||
icon: string
|
||||
options: Array<{
|
||||
namespace: string
|
||||
title: string
|
||||
desc?: string
|
||||
type: string
|
||||
default: any
|
||||
binds?: { [key: string]: any }
|
||||
}>
|
||||
}
|
||||
}
|
||||
@ -13,17 +17,87 @@ export interface Options {
|
||||
const options: Options = {
|
||||
basic: {
|
||||
title: 'Basic',
|
||||
desc: 'The basic options',
|
||||
icon: 'fas fa-address-card',
|
||||
options: [
|
||||
{
|
||||
namespace: 'basic.siteTitle',
|
||||
title: 'Site title',
|
||||
desc: 'The site title',
|
||||
type: 'string',
|
||||
default: 'Opps',
|
||||
},
|
||||
{
|
||||
namespace: 'basic.userName',
|
||||
type: 'string',
|
||||
default: 'Mashiro',
|
||||
namespace: 'basic.switcher',
|
||||
title: 'Switcher',
|
||||
type: 'switcher',
|
||||
default: true,
|
||||
binds: {
|
||||
positiveLabel: 'current on',
|
||||
negativeLabel: 'current off',
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
namespace: 'basic.chooseTest',
|
||||
title: 'Choose Test',
|
||||
desc: 'wooooo',
|
||||
type: 'choose',
|
||||
default: NaN,
|
||||
binds: {
|
||||
options: [
|
||||
{ label: 'op 1', disabled: false },
|
||||
{ label: 'op 2', disabled: false },
|
||||
{ label: 'op 3', disabled: false },
|
||||
{ label: 'op 4', disabled: true },
|
||||
],
|
||||
max: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
namespace: 'basic.optionsTest',
|
||||
title: 'Option Test',
|
||||
desc: 'wooooo',
|
||||
type: 'selection',
|
||||
default: [true, false, true],
|
||||
binds: {
|
||||
options: [
|
||||
{ label: 'op 1', disabled: false },
|
||||
{ label: 'op 2', disabled: false },
|
||||
{ label: 'op 3', disabled: false },
|
||||
{ label: 'op 4', disabled: true },
|
||||
],
|
||||
max: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
namespace: 'basic.longString',
|
||||
title: 'Long string',
|
||||
desc: 'A long string',
|
||||
type: 'longString',
|
||||
default: 'Opps',
|
||||
},
|
||||
{
|
||||
namespace: 'basic.mediaPicker',
|
||||
title: 'Image picker',
|
||||
desc: 'Media picker',
|
||||
type: 'mediaPicker',
|
||||
default: [
|
||||
{
|
||||
id: 0,
|
||||
url: 'https://view.moezx.cc/images/2021/07/02/d5ab73174d18652d890e2f4d1b9bef8f.gif',
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
url: 'https://view.moezx.cc/images/2021/07/02/a90553bf5b67770e87a89b2ce204eaa7.gif',
|
||||
},
|
||||
],
|
||||
binds: {
|
||||
title: 'Select Media',
|
||||
button: 'Use this media',
|
||||
type: 'image',
|
||||
multiple: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -31,8 +105,14 @@ const options: Options = {
|
||||
title: 'Social',
|
||||
icon: 'fas fa-users',
|
||||
options: [
|
||||
{ namespace: 'social.github', type: 'string', default: 'mashirozx' },
|
||||
{ namespace: 'social.weibo', type: 'string', default: 'mashirozx' },
|
||||
{
|
||||
namespace: 'social.github',
|
||||
title: 'Github username',
|
||||
desc: 'Your <a href="https://github.com" target="_blank">Github</a> username',
|
||||
type: 'string',
|
||||
default: 'mashirozx',
|
||||
},
|
||||
{ namespace: 'social.weibo', title: 'Weibo username', type: 'string', default: 'mashirozx' },
|
||||
],
|
||||
},
|
||||
other: {
|
||||
@ -41,6 +121,7 @@ const options: Options = {
|
||||
options: [
|
||||
{
|
||||
namespace: 'other.hello',
|
||||
title: 'Hello world',
|
||||
type: 'string',
|
||||
default: 'world',
|
||||
},
|
||||
|
@ -35,5 +35,5 @@ export default function auth(): object {
|
||||
// return data
|
||||
// }
|
||||
|
||||
return { config, setConfig }
|
||||
return { config, updateOption }
|
||||
}
|
||||
|
20
src/admin/validator.ts
Normal file
20
src/admin/validator.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import logger from '@/utils/logger'
|
||||
export default function validator<T>(value: T, type: string): { pass: boolean; msg?: string } {
|
||||
switch (type) {
|
||||
case 'string':
|
||||
case 'longString':
|
||||
return { pass: typeof value === 'string' }
|
||||
case 'choose':
|
||||
return { pass: typeof value === 'number' }
|
||||
case 'switcher':
|
||||
return { pass: typeof value === 'boolean' }
|
||||
case 'selection':
|
||||
return { pass: value instanceof Array }
|
||||
case 'mediaPicker':
|
||||
return { pass: value instanceof Array }
|
||||
default:
|
||||
const msg = `No such type ${type}`
|
||||
logger('error', msg)
|
||||
return { pass: false, msg }
|
||||
}
|
||||
}
|
93
src/components/checkbox/Checkbox.vue
Normal file
93
src/components/checkbox/Checkbox.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="checkbox__container">
|
||||
<div class="mdc-checkbox mdc-checkbox--touch" :ref="setElRef" @change="handleChange">
|
||||
<input type="checkbox" class="mdc-checkbox__native-control" :id="`checkbox-${id}`" />
|
||||
<div class="mdc-checkbox__background">
|
||||
<svg class="mdc-checkbox__checkmark" viewBox="0 0 24 24">
|
||||
<path
|
||||
class="mdc-checkbox__checkmark-path"
|
||||
fill="none"
|
||||
d="M1.73,12.91 8.1,19.28 22.79,4.59"
|
||||
/>
|
||||
</svg>
|
||||
<div class="mdc-checkbox__mixedmark"></div>
|
||||
</div>
|
||||
<div class="mdc-checkbox__ripple"></div>
|
||||
</div>
|
||||
<label class="label" :for="`checkbox-${id}`" :id="`checkbox-label-${id}`">
|
||||
{{ $props.label }}
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, watch, ref } from 'vue'
|
||||
import { useElementRef } from '@/hooks'
|
||||
import useMDCCheckbox from '@/hooks/mdc/useMDCCheckbox'
|
||||
import uniqueHash from '@/utils/uniqueHash'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
label: { type: String, default: 'This is the label' },
|
||||
checked: { type: Boolean, default: false },
|
||||
disabled: { type: Boolean, default: false },
|
||||
},
|
||||
emits: ['update:checked'],
|
||||
setup(props, { emit }) {
|
||||
const id = uniqueHash()
|
||||
|
||||
const [elRef, setElRef] = useElementRef()
|
||||
const MDCCheckboxRef = useMDCCheckbox(elRef)
|
||||
|
||||
const checked = ref(props.checked)
|
||||
|
||||
const handleChange = () => {
|
||||
if (MDCCheckboxRef.value) {
|
||||
checked.value = MDCCheckboxRef.value.checked
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.checked,
|
||||
(value) => {
|
||||
checked.value = value
|
||||
if (MDCCheckboxRef.value) MDCCheckboxRef.value.checked = value
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.disabled,
|
||||
(value) => {
|
||||
if (MDCCheckboxRef.value) {
|
||||
MDCCheckboxRef.value.disabled = value
|
||||
// MDCCheckboxRef.value.indeterminate = value
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(MDCCheckboxRef, (MDCCheckbox) => {
|
||||
if (MDCCheckbox) {
|
||||
MDCCheckbox.checked = checked.value
|
||||
MDCCheckbox.disabled = props.disabled
|
||||
// MDCCheckbox.indeterminate = props.disabled
|
||||
}
|
||||
})
|
||||
|
||||
watch(checked, (value) => emit('update:checked', value))
|
||||
|
||||
return { checked, id, setElRef, handleChange }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.checkbox__container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.label {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
</style>
|
52
src/components/checkbox/Selection.vue
Normal file
52
src/components/checkbox/Selection.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<section class="selection__container">
|
||||
<div class="checkbox__wrapper" v-for="(option, index) in $props.options" :key="index">
|
||||
<Checkbox
|
||||
v-model:checked="resultRef[index]"
|
||||
:label="option.label"
|
||||
:disabled="(isMax && !resultRef[index]) || option.disabled"
|
||||
></Checkbox>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch, computed } from 'vue'
|
||||
import Checkbox from './Checkbox.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { Checkbox },
|
||||
props: {
|
||||
max: { type: Number, default: -1 },
|
||||
result: { type: Array, default: () => [true, false, true] },
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => [
|
||||
{ label: 'op 1', disabled: false },
|
||||
{ label: 'op 2', disabled: false },
|
||||
{ label: 'op 3', disabled: false },
|
||||
],
|
||||
},
|
||||
},
|
||||
emits: ['update:result'],
|
||||
setup(props, { emit }) {
|
||||
const resultRef = ref(props.result)
|
||||
|
||||
const isMax = computed(() => {
|
||||
const { max } = props
|
||||
if (max < 0) {
|
||||
return false
|
||||
} else {
|
||||
const count = resultRef.value.filter((x) => x).length
|
||||
return count >= max
|
||||
}
|
||||
})
|
||||
|
||||
// watch(resultRef,result=>{
|
||||
// if()
|
||||
// })
|
||||
|
||||
return { resultRef, isMax }
|
||||
},
|
||||
})
|
||||
</script>
|
@ -3,6 +3,7 @@
|
||||
:class="[
|
||||
'mdc-text-field',
|
||||
'mdc-text-field--outlined',
|
||||
{ 'mdc-text-field--no-label': !$props.label },
|
||||
{ 'mdc-text-field--with-leading-icon': $props.leadingIcon },
|
||||
{ 'mdc-text-field--with-trailing-icon': $props.trailingIcon },
|
||||
]"
|
||||
@ -10,7 +11,7 @@
|
||||
>
|
||||
<span class="mdc-notched-outline">
|
||||
<span class="mdc-notched-outline__leading"></span>
|
||||
<span class="mdc-notched-outline__notch">
|
||||
<span class="mdc-notched-outline__notch" v-if="$props.label">
|
||||
<span class="mdc-floating-label" :id="id">{{ $props.label }}</span>
|
||||
</span>
|
||||
<span class="mdc-notched-outline__trailing"></span>
|
||||
@ -37,8 +38,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import { MD5 } from 'crypto-js'
|
||||
import { useElementRef, useMDCTextField } from '@/hooks'
|
||||
import uniqueHash from '@/utils/uniqueHash'
|
||||
import { useElementRef } from '@/hooks'
|
||||
import useMDCTextField from '@/hooks/mdc/useMDCTextField'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@ -51,7 +53,7 @@ export default defineComponent({
|
||||
},
|
||||
emits: ['update:content', 'blur'],
|
||||
setup(props, { emit }) {
|
||||
const id = MD5(Math.random().toString()).toString().slice(0, 8)
|
||||
const id = uniqueHash()
|
||||
const [textareaRef, setTextareaRef] = useElementRef()
|
||||
useMDCTextField(textareaRef)
|
||||
|
||||
|
@ -4,13 +4,14 @@
|
||||
'mdc-text-field',
|
||||
'mdc-text-field--outlined',
|
||||
'mdc-text-field--textarea',
|
||||
{ 'mdc-text-field--no-label': !$props.label },
|
||||
{ 'mdc-text-field--with-internal-counter': showCounter },
|
||||
]"
|
||||
:ref="setTextareaRef"
|
||||
>
|
||||
<span class="mdc-notched-outline">
|
||||
<span class="mdc-notched-outline__leading"></span>
|
||||
<span class="mdc-notched-outline__notch">
|
||||
<span class="mdc-notched-outline__notch" v-if="$props.label">
|
||||
<span class="mdc-floating-label" :id="id">{{ label }}</span>
|
||||
</span>
|
||||
<span class="mdc-notched-outline__trailing"></span>
|
||||
@ -31,8 +32,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref, watch } from 'vue'
|
||||
import { MD5 } from 'crypto-js'
|
||||
import { useElementRef, useMDCTextField } from '@/hooks'
|
||||
import uniqueHash from '@/utils/uniqueHash'
|
||||
import { useElementRef } from '@/hooks'
|
||||
import useMDCTextField from '@/hooks/mdc/useMDCTextField'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@ -47,7 +49,7 @@ export default defineComponent({
|
||||
},
|
||||
emits: ['update:content'],
|
||||
setup(props, { emit }) {
|
||||
const id = MD5(Math.random().toString()).toString().slice(0, 8)
|
||||
const id = uniqueHash()
|
||||
|
||||
const [textareaRef, setTextareaRef] = useElementRef()
|
||||
useMDCTextField(textareaRef)
|
||||
|
82
src/components/radio/Choose.vue
Normal file
82
src/components/radio/Choose.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<section class="selection__container">
|
||||
<div class="checkbox__wrapper" v-for="(option, index) in $props.options" :key="index">
|
||||
<RadioButton
|
||||
v-model:checked="arrayRef[index]"
|
||||
:label="option.label"
|
||||
:disabled="option.disabled"
|
||||
></RadioButton>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch, computed, Ref } from 'vue'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import RadioButton from './RadioButton.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { RadioButton },
|
||||
props: {
|
||||
result: { type: Number, default: () => NaN },
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => [
|
||||
{ label: 'op 1', disabled: false },
|
||||
{ label: 'op 2', disabled: false },
|
||||
{ label: 'op 3', disabled: false },
|
||||
],
|
||||
},
|
||||
},
|
||||
emits: ['update:result'],
|
||||
setup(props, { emit }) {
|
||||
const arrayRef: Ref<boolean[]> = ref(
|
||||
Array(props.options.length)
|
||||
.fill(false)
|
||||
.map((item, index) => index === props.result)
|
||||
)
|
||||
|
||||
// TODO: watcher's bug on deep mode: https://github.com/vuejs/vue/issues/2164
|
||||
const cacheArrayRef = computed(() => cloneDeep(arrayRef.value))
|
||||
|
||||
watch(
|
||||
cacheArrayRef,
|
||||
(n, o) => {
|
||||
if (n.indexOf(true) < 0) return
|
||||
n.forEach((_n, index) => {
|
||||
if (_n && _n !== o[index]) {
|
||||
const a = cloneDeep(arrayRef.value)
|
||||
a.fill(false)
|
||||
a[index] = true
|
||||
arrayRef.value = a
|
||||
}
|
||||
})
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
arrayRef,
|
||||
(arr) => {
|
||||
const value = arr.indexOf(true)
|
||||
if (value > -1) {
|
||||
emit('update:result', value)
|
||||
} else {
|
||||
emit('update:result', NaN)
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.options,
|
||||
(options) =>
|
||||
(arrayRef.value = Array(options.length)
|
||||
.fill(false)
|
||||
.map((item, index) => index === props.result))
|
||||
)
|
||||
|
||||
return { arrayRef }
|
||||
},
|
||||
})
|
||||
</script>
|
91
src/components/radio/RadioButton.vue
Normal file
91
src/components/radio/RadioButton.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="radio__container">
|
||||
<div class="mdc-radio" :ref="setElRef">
|
||||
<input
|
||||
class="mdc-radio__native-control"
|
||||
type="checkbox"
|
||||
:id="`radio-${id}`"
|
||||
:name="`radio-${id}`"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<div class="mdc-radio__background">
|
||||
<div class="mdc-radio__outer-circle"></div>
|
||||
<div class="mdc-radio__inner-circle"></div>
|
||||
</div>
|
||||
<div class="mdc-radio__ripple"></div>
|
||||
</div>
|
||||
<label class="label" :for="`radio-${id}`">{{ $props.label }}</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, watch, ref } from 'vue'
|
||||
import { useElementRef } from '@/hooks'
|
||||
import uniqueHash from '@/utils/uniqueHash'
|
||||
import useMDCRadio from '@/hooks/mdc/useMDCRadio'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
label: { type: String, default: 'This is the label' },
|
||||
checked: { type: Boolean, default: false },
|
||||
disabled: { type: Boolean, default: false },
|
||||
},
|
||||
emits: ['update:checked'],
|
||||
setup(props, { emit }) {
|
||||
const id = uniqueHash()
|
||||
|
||||
const [elRef, setElRef] = useElementRef()
|
||||
|
||||
const MDCRadioRef = useMDCRadio(elRef)
|
||||
|
||||
const checked = ref(props.checked)
|
||||
|
||||
const handleChange = (event: Event) => {
|
||||
if (!props.disabled) checked.value = !checked.value
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.checked,
|
||||
(value) => {
|
||||
checked.value = value
|
||||
if (MDCRadioRef.value) MDCRadioRef.value.checked = value
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.disabled,
|
||||
(value) => {
|
||||
if (MDCRadioRef.value) {
|
||||
MDCRadioRef.value.disabled = value
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(MDCRadioRef, (MDCCheckbox) => {
|
||||
if (MDCCheckbox) {
|
||||
MDCCheckbox.checked = checked.value
|
||||
MDCCheckbox.disabled = props.disabled
|
||||
}
|
||||
})
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (MDCRadioRef.value) MDCRadioRef.value.checked = value
|
||||
emit('update:checked', value)
|
||||
})
|
||||
|
||||
return { checked, id, setElRef, handleChange }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.radio__container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.label {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
</style>
|
106
src/components/switcher/Switcher.vue
Normal file
106
src/components/switcher/Switcher.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div class="switcher__container">
|
||||
<button
|
||||
:id="`switch-${id}`"
|
||||
class="mdc-switch mdc-switch--unselected"
|
||||
role="switch"
|
||||
:aria-checked="checked"
|
||||
:ref="setElRef"
|
||||
@click="handleChange"
|
||||
>
|
||||
<div class="mdc-switch__track"></div>
|
||||
<div class="mdc-switch__handle-track">
|
||||
<div class="mdc-switch__handle">
|
||||
<div class="mdc-switch__shadow">
|
||||
<div class="mdc-elevation-overlay"></div>
|
||||
</div>
|
||||
<div class="mdc-switch__ripple"></div>
|
||||
<div class="mdc-switch__icons">
|
||||
<svg class="mdc-switch__icon mdc-switch__icon--on" viewBox="0 0 24 24">
|
||||
<path d="M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z" />
|
||||
</svg>
|
||||
<svg class="mdc-switch__icon mdc-switch__icon--off" viewBox="0 0 24 24">
|
||||
<path d="M20 13H4v-2h16v2z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<label class="label" :for="`switch-${id}`">
|
||||
{{ checked ? $props.positiveLabel : $props.negativeLabel }}
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import uniqueHash from '@/utils/uniqueHash'
|
||||
import { useElementRef } from '@/hooks'
|
||||
import useMDCSwitch from '@/hooks/mdc/useMDCSwitch'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
positiveLabel: { type: String, default: 'current on' },
|
||||
negativeLabel: { type: String, default: 'current off' },
|
||||
checked: { type: Boolean, default: true },
|
||||
disabled: { type: Boolean, default: false },
|
||||
},
|
||||
emits: ['update:checked'],
|
||||
setup(props, { emit }) {
|
||||
const id = uniqueHash()
|
||||
|
||||
const [elRef, setElRef] = useElementRef()
|
||||
const MDCSwitchRef = useMDCSwitch(elRef)
|
||||
|
||||
const checked = ref(props.checked)
|
||||
|
||||
const handleChange = () => {
|
||||
if (MDCSwitchRef.value) {
|
||||
checked.value = !MDCSwitchRef.value.selected
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.checked,
|
||||
(value) => {
|
||||
checked.value = value
|
||||
if (MDCSwitchRef.value) MDCSwitchRef.value.selected = !value
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.disabled,
|
||||
(value) => {
|
||||
if (MDCSwitchRef.value) {
|
||||
MDCSwitchRef.value.disabled = value
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(MDCSwitchRef, (MDCCheckbox) => {
|
||||
if (MDCCheckbox) {
|
||||
MDCCheckbox.selected = checked.value
|
||||
MDCCheckbox.disabled = props.disabled
|
||||
}
|
||||
})
|
||||
|
||||
watch(checked, (value) => emit('update:checked', value))
|
||||
|
||||
return { id, setElRef, handleChange, checked }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.switcher__container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.label {
|
||||
user-select: none;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -33,7 +33,8 @@
|
||||
import { defineComponent, onMounted, watch } from 'vue'
|
||||
import { useState } from '@/hooks'
|
||||
import { MD5 } from 'crypto-js'
|
||||
import { useElementRef, useMDCTabBar } from '@/hooks'
|
||||
import { useElementRef } from '@/hooks'
|
||||
import useMDCTabBar from '@/hooks/mdc/useMDCTabBar'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
|
@ -7,7 +7,7 @@ import useResizeObserver from './useResizeObserver'
|
||||
import useReachElementSide from './useReachElementSide'
|
||||
import { useElementRef, useElementRefs } from './useElementRef'
|
||||
import useOffsetDistance from './useOffsetDistance'
|
||||
import { useMDCRipple, useMDCDialog, useMDCTextField, useMDCTabBar } from './mdc'
|
||||
import useMDCRipple from './mdc/useMDCRipple'
|
||||
|
||||
export {
|
||||
useState,
|
||||
@ -22,9 +22,6 @@ export {
|
||||
useWindowResize,
|
||||
useResizeObserver,
|
||||
useMDCRipple,
|
||||
useMDCDialog,
|
||||
useMDCTextField,
|
||||
useMDCTabBar,
|
||||
useReachElementSide,
|
||||
useElementRef,
|
||||
useElementRefs,
|
||||
|
@ -1,95 +0,0 @@
|
||||
import { ref, Ref, watch, onBeforeUnmount } from 'vue'
|
||||
import { MDCRipple } from '@material/ripple'
|
||||
import { MDCDialog } from '@material/dialog'
|
||||
import { MDCTextField } from '@material/textfield'
|
||||
import { MDCTabBar } from '@material/tab-bar'
|
||||
|
||||
export const useMDCRipple = <El>(
|
||||
elementRef: El extends Element ? Element : Ref<Element | null>,
|
||||
unbounded = false
|
||||
) => {
|
||||
const rippleRef: Ref<MDCRipple | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
rippleRef.value = new MDCRipple(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
rippleRef.value = new MDCRipple(element)
|
||||
if (unbounded) rippleRef.value.unbounded = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
rippleRef.value?.destroy()
|
||||
})
|
||||
|
||||
return rippleRef
|
||||
}
|
||||
|
||||
export const useMDCDialog = <El>(
|
||||
elementRef: El extends Element ? Element : Ref<Element | null>
|
||||
) => {
|
||||
const dialogRef: Ref<MDCDialog | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
dialogRef.value = new MDCDialog(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
dialogRef.value = new MDCDialog(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
dialogRef.value?.destroy()
|
||||
})
|
||||
|
||||
return dialogRef
|
||||
}
|
||||
|
||||
export const useMDCTextField = <El>(
|
||||
elementRef: El extends Element ? Element : Ref<Element | null>
|
||||
) => {
|
||||
const textFieldRef: Ref<MDCTextField | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
textFieldRef.value = new MDCTextField(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
textFieldRef.value = new MDCTextField(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
textFieldRef.value?.destroy()
|
||||
})
|
||||
|
||||
return textFieldRef
|
||||
}
|
||||
|
||||
export const useMDCTabBar = <El>(
|
||||
elementRef: El extends Element ? Element : Ref<Element | null>
|
||||
) => {
|
||||
const tabBarRef: Ref<MDCTabBar | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
tabBarRef.value = new MDCTabBar(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
tabBarRef.value = new MDCTabBar(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
tabBarRef.value?.destroy()
|
||||
})
|
||||
|
||||
return tabBarRef
|
||||
}
|
24
src/hooks/mdc/useMDCCheckbox.ts
Normal file
24
src/hooks/mdc/useMDCCheckbox.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ref, Ref, watch, onBeforeUnmount } from 'vue'
|
||||
import { MDCCheckbox } from '@material/checkbox'
|
||||
|
||||
const useMDCCheckbox = <El>(elementRef: El extends Element ? Element : Ref<Element | null>) => {
|
||||
const mdcRef: Ref<MDCCheckbox | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
mdcRef.value = new MDCCheckbox(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
mdcRef.value = new MDCCheckbox(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
mdcRef.value?.destroy()
|
||||
})
|
||||
|
||||
return mdcRef
|
||||
}
|
||||
|
||||
export default useMDCCheckbox
|
24
src/hooks/mdc/useMDCDialog.ts
Normal file
24
src/hooks/mdc/useMDCDialog.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ref, Ref, watch, onBeforeUnmount } from 'vue'
|
||||
import { MDCDialog } from '@material/dialog'
|
||||
|
||||
const useMDCDialog = <El>(elementRef: El extends Element ? Element : Ref<Element | null>) => {
|
||||
const mdcRef: Ref<MDCDialog | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
mdcRef.value = new MDCDialog(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
mdcRef.value = new MDCDialog(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
mdcRef.value?.destroy()
|
||||
})
|
||||
|
||||
return mdcRef
|
||||
}
|
||||
|
||||
export default useMDCDialog
|
24
src/hooks/mdc/useMDCRadio.ts
Normal file
24
src/hooks/mdc/useMDCRadio.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ref, Ref, watch, onBeforeUnmount } from 'vue'
|
||||
import { MDCRadio } from '@material/radio'
|
||||
|
||||
const useMDCRadio = <El>(elementRef: El extends Element ? Element : Ref<Element | null>) => {
|
||||
const mdcRef: Ref<MDCRadio | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
mdcRef.value = new MDCRadio(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
mdcRef.value = new MDCRadio(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
mdcRef.value?.destroy()
|
||||
})
|
||||
|
||||
return mdcRef
|
||||
}
|
||||
|
||||
export default useMDCRadio
|
28
src/hooks/mdc/useMDCRipple.ts
Normal file
28
src/hooks/mdc/useMDCRipple.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { ref, Ref, watch, onBeforeUnmount } from 'vue'
|
||||
import { MDCRipple } from '@material/ripple'
|
||||
|
||||
const useMDCRipple = <El>(
|
||||
elementRef: El extends Element ? Element : Ref<Element | null>,
|
||||
unbounded = false
|
||||
) => {
|
||||
const rippleRef: Ref<MDCRipple | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
rippleRef.value = new MDCRipple(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
rippleRef.value = new MDCRipple(element)
|
||||
if (unbounded) rippleRef.value.unbounded = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
rippleRef.value?.destroy()
|
||||
})
|
||||
|
||||
return rippleRef
|
||||
}
|
||||
|
||||
export default useMDCRipple
|
24
src/hooks/mdc/useMDCSwitch.ts
Normal file
24
src/hooks/mdc/useMDCSwitch.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ref, Ref, watch, onBeforeUnmount } from 'vue'
|
||||
import { MDCSwitch } from '@material/switch'
|
||||
|
||||
const useMDCSwitch = <El>(elementRef: El extends Element ? Element : Ref<Element | null>) => {
|
||||
const mdcRef: Ref<MDCSwitch | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
mdcRef.value = new MDCSwitch(elementRef as HTMLButtonElement)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
mdcRef.value = new MDCSwitch(element as HTMLButtonElement)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
mdcRef.value?.destroy()
|
||||
})
|
||||
|
||||
return mdcRef
|
||||
}
|
||||
|
||||
export default useMDCSwitch
|
24
src/hooks/mdc/useMDCTabBar.ts
Normal file
24
src/hooks/mdc/useMDCTabBar.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ref, Ref, watch, onBeforeUnmount } from 'vue'
|
||||
import { MDCTabBar } from '@material/tab-bar'
|
||||
|
||||
const useMDCTabBar = <El>(elementRef: El extends Element ? Element : Ref<Element | null>) => {
|
||||
const tabBarRef: Ref<MDCTabBar | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
tabBarRef.value = new MDCTabBar(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
tabBarRef.value = new MDCTabBar(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
tabBarRef.value?.destroy()
|
||||
})
|
||||
|
||||
return tabBarRef
|
||||
}
|
||||
|
||||
export default useMDCTabBar
|
24
src/hooks/mdc/useMDCTextField.ts
Normal file
24
src/hooks/mdc/useMDCTextField.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ref, Ref, watch, onBeforeUnmount } from 'vue'
|
||||
import { MDCTextField } from '@material/textfield'
|
||||
|
||||
const useMDCTextField = <El>(elementRef: El extends Element ? Element : Ref<Element | null>) => {
|
||||
const textFieldRef: Ref<MDCTextField | null> = ref(null)
|
||||
|
||||
if (elementRef instanceof Element) {
|
||||
textFieldRef.value = new MDCTextField(elementRef)
|
||||
} else {
|
||||
watch(elementRef, (element) => {
|
||||
if (element) {
|
||||
textFieldRef.value = new MDCTextField(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
textFieldRef.value?.destroy()
|
||||
})
|
||||
|
||||
return textFieldRef
|
||||
}
|
||||
|
||||
export default useMDCTextField
|
5
src/utils/uniqueHash.ts
Normal file
5
src/utils/uniqueHash.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { MD5 } from 'crypto-js'
|
||||
|
||||
export default function () {
|
||||
return MD5(Math.random().toString()).toString().slice(0, 8)
|
||||
}
|
13
src/utils/urlHelper.ts
Normal file
13
src/utils/urlHelper.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export const isUrl = (url: string): { state: boolean; msg?: any } => {
|
||||
try {
|
||||
new URL(url)
|
||||
} catch (error) {
|
||||
return {
|
||||
state: false,
|
||||
msg: error,
|
||||
}
|
||||
}
|
||||
return {
|
||||
state: true,
|
||||
}
|
||||
}
|
253
yarn.lock
253
yarn.lock
@ -685,6 +685,20 @@
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/animation@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/animation/download/@material/animation-12.0.0-canary.9f68a932e.0.tgz#8deafa2e91db38d4f4ec4303c1eeba8a7e6b1586"
|
||||
integrity sha1-jer6LpHbONT07EMDwe66in5rFYY=
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/animation@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/animation/download/@material/animation-12.0.0-canary.e1703bed9.0.tgz#d3f758c0ae65223b9459cfc3c35cd1313bb377bc"
|
||||
integrity sha1-0/dYwK5lIjuUWc/Dw1zRMTuzd7w=
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/base@12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/base/download/@material/base-12.0.0-canary.068fd5028.0.tgz#ba4403e153550bfd44c6f4d74af27c43be94b23b"
|
||||
@ -699,6 +713,20 @@
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/base@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/base/download/@material/base-12.0.0-canary.9f68a932e.0.tgz#416b1ea1646de2585b9f6334b721eb32f27e1b62"
|
||||
integrity sha1-QWseoWRt4lhbn2M0tyHrMvJ+G2I=
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/base@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/base/download/@material/base-12.0.0-canary.e1703bed9.0.tgz#b516620d7217a18955e694589c230d536ec04acd"
|
||||
integrity sha1-tRZiDXIXoYlV5pRYnCMNU27ASs0=
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/button@12.0.0-canary.068fd5028.0", "@material/button@^12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/button/download/@material/button-12.0.0-canary.068fd5028.0.tgz#dea53b2914e4bd48c94fd8d6c3915c377ff6a326"
|
||||
@ -745,6 +773,21 @@
|
||||
"@material/touch-target" "12.0.0-canary.068fd5028.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/checkbox@^12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/checkbox/download/@material/checkbox-12.0.0-canary.e1703bed9.0.tgz#97956408491070c2ffdf1bb718af23a35b5370c0"
|
||||
integrity sha1-l5VkCEkQcML/3xu3GK8jo1tTcMA=
|
||||
dependencies:
|
||||
"@material/animation" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/base" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/density" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/dom" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/feature-targeting" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/ripple" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/theme" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/touch-target" "12.0.0-canary.e1703bed9.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/chips@^12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/chips/download/@material/chips-12.0.0-canary.068fd5028.0.tgz#92f1f6fa3aef8906a34b3fe9e3f351861d0ab6df"
|
||||
@ -779,6 +822,20 @@
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/density@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/density/download/@material/density-12.0.0-canary.9f68a932e.0.tgz#e1aba9fb3242c3e94223700da4cbf6178bfe3170"
|
||||
integrity sha1-4aup+zJCw+lCI3ANpMv2F4v+MXA=
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/density@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/density/download/@material/density-12.0.0-canary.e1703bed9.0.tgz#6f73f9a73dbc607c20f06a4dfa69bc041fac9a31"
|
||||
integrity sha1-b3P5pz28YHwg8GpN+mm8BB+smjE=
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/dialog@^12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/dialog/download/@material/dialog-12.0.0-canary.068fd5028.0.tgz#ad0990c32b4c3538ce469297ca2b7f1f71abc84a"
|
||||
@ -815,6 +872,22 @@
|
||||
"@material/feature-targeting" "12.0.0-canary.22d29cbb4.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/dom@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/dom/download/@material/dom-12.0.0-canary.9f68a932e.0.tgz#e9baf1e7622cad75689245a703165e7d3c3eb16b"
|
||||
integrity sha1-6brx52IsrXVokkWnAxZefTw+sWs=
|
||||
dependencies:
|
||||
"@material/feature-targeting" "12.0.0-canary.9f68a932e.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/dom@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/dom/download/@material/dom-12.0.0-canary.e1703bed9.0.tgz#46fddbf9a0171409f144d5df618a4fc3887cc432"
|
||||
integrity sha1-Rv3b+aAXFAnxRNXfYYpPw4h8xDI=
|
||||
dependencies:
|
||||
"@material/feature-targeting" "12.0.0-canary.e1703bed9.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/elevation@12.0.0-canary.068fd5028.0", "@material/elevation@^12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/elevation/download/@material/elevation-12.0.0-canary.068fd5028.0.tgz#0c670ae52c8f83491b06e31c95917c7ea37ca9ea"
|
||||
@ -837,6 +910,17 @@
|
||||
"@material/theme" "12.0.0-canary.22d29cbb4.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/elevation@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/elevation/download/@material/elevation-12.0.0-canary.9f68a932e.0.tgz#3bd2d5b30b27e43f5f4d822abe0693e52c6ce297"
|
||||
integrity sha1-O9LVswsn5D9fTYIqvgaT5Sxs4pc=
|
||||
dependencies:
|
||||
"@material/animation" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/base" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/feature-targeting" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/theme" "12.0.0-canary.9f68a932e.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/feature-targeting@12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/feature-targeting/download/@material/feature-targeting-12.0.0-canary.068fd5028.0.tgz#e043d1f549bfd1a6e647486a354dcb7b04c7afb3"
|
||||
@ -851,6 +935,20 @@
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/feature-targeting@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/feature-targeting/download/@material/feature-targeting-12.0.0-canary.9f68a932e.0.tgz#8ec6b30b59558f8a84f63aa00dd2ce870ff6844c"
|
||||
integrity sha1-jsazC1lVj4qE9jqgDdLOhw/2hEw=
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/feature-targeting@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/feature-targeting/download/@material/feature-targeting-12.0.0-canary.e1703bed9.0.tgz#ce6d8a3111c1b20ecaab13c73c975fa8bd9d59b6"
|
||||
integrity sha1-zm2KMRHBsg7KqxPHPJdfqL2dWbY=
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/floating-label@12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/floating-label/download/@material/floating-label-12.0.0-canary.068fd5028.0.tgz#db76cda2d1de4482ddca5df854e1c1e5efe73ac5"
|
||||
@ -865,6 +963,19 @@
|
||||
"@material/typography" "12.0.0-canary.068fd5028.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/form-field@^12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/form-field/download/@material/form-field-12.0.0-canary.e1703bed9.0.tgz#82788ff08eeed0494598bde00b73992f14c7a585"
|
||||
integrity sha1-gniP8I7u0ElFmL3gC3OZLxTHpYU=
|
||||
dependencies:
|
||||
"@material/base" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/feature-targeting" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/ripple" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/rtl" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/theme" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/typography" "12.0.0-canary.e1703bed9.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/icon-button@12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/icon-button/download/@material/icon-button-12.0.0-canary.068fd5028.0.tgz#eccd2bc14fd984817ae090e9c09433b1e94e1f46"
|
||||
@ -949,6 +1060,21 @@
|
||||
"@material/theme" "12.0.0-canary.068fd5028.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/radio@^12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/radio/download/@material/radio-12.0.0-canary.9f68a932e.0.tgz#8c329ccb1057aafff079cf28a2efeb01d341d156"
|
||||
integrity sha1-jDKcyxBXqv/wec8oou/rAdNB0VY=
|
||||
dependencies:
|
||||
"@material/animation" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/base" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/density" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/dom" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/feature-targeting" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/ripple" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/theme" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/touch-target" "12.0.0-canary.9f68a932e.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/ripple@12.0.0-canary.068fd5028.0", "@material/ripple@^12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/ripple/download/@material/ripple-12.0.0-canary.068fd5028.0.tgz#e1570b1e45b47bdb6166198abb47236bce3be689"
|
||||
@ -973,6 +1099,30 @@
|
||||
"@material/theme" "12.0.0-canary.22d29cbb4.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/ripple@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/ripple/download/@material/ripple-12.0.0-canary.9f68a932e.0.tgz#cd923b2560250698215775cd67bd446b6a5e5e9b"
|
||||
integrity sha1-zZI7JWAlBpghV3XNZ71Ea2peXps=
|
||||
dependencies:
|
||||
"@material/animation" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/base" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/dom" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/feature-targeting" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/theme" "12.0.0-canary.9f68a932e.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/ripple@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/ripple/download/@material/ripple-12.0.0-canary.e1703bed9.0.tgz#2fc99d599b4d4fc67834e62e3abc06719a561652"
|
||||
integrity sha1-L8mdWZtNT8Z4NOYuOrwGcZpWFlI=
|
||||
dependencies:
|
||||
"@material/animation" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/base" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/dom" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/feature-targeting" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/theme" "12.0.0-canary.e1703bed9.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/rtl@12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/rtl/download/@material/rtl-12.0.0-canary.068fd5028.0.tgz#e7a24ffdc7ef2419433a29c9fed4a0bd79e9086b"
|
||||
@ -989,6 +1139,22 @@
|
||||
"@material/theme" "12.0.0-canary.22d29cbb4.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/rtl@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/rtl/download/@material/rtl-12.0.0-canary.9f68a932e.0.tgz#268bff8f0d9d6eb43803269ecd401b5a7e69c909"
|
||||
integrity sha1-Jov/jw2dbrQ4AyaezUAbWn5pyQk=
|
||||
dependencies:
|
||||
"@material/theme" "12.0.0-canary.9f68a932e.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/rtl@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/rtl/download/@material/rtl-12.0.0-canary.e1703bed9.0.tgz#52c0a7b09ce2dc52cac5df126e56be36ef8557fa"
|
||||
integrity sha1-UsCnsJzi3FLKxd8Sbla+Nu+FV/o=
|
||||
dependencies:
|
||||
"@material/theme" "12.0.0-canary.e1703bed9.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/shape@12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/shape/download/@material/shape-12.0.0-canary.068fd5028.0.tgz#e68f58979314a23a3486105a8f91482b8c8e9130"
|
||||
@ -999,6 +1165,34 @@
|
||||
"@material/theme" "12.0.0-canary.068fd5028.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/shape@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/shape/download/@material/shape-12.0.0-canary.9f68a932e.0.tgz#cb0466b1e8409c3c9e6143fe6d28d6d97d9ee11a"
|
||||
integrity sha1-ywRmsehAnDyeYUP+bSjW2X2e4Ro=
|
||||
dependencies:
|
||||
"@material/feature-targeting" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/rtl" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/theme" "12.0.0-canary.9f68a932e.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/switch@^12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/switch/download/@material/switch-12.0.0-canary.9f68a932e.0.tgz#2089bcad64039c7d93917faa321392f5dd7dc5cd"
|
||||
integrity sha1-IIm8rWQDnH2TkX+qMhOS9d19xc0=
|
||||
dependencies:
|
||||
"@material/animation" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/base" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/density" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/dom" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/elevation" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/feature-targeting" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/ripple" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/rtl" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/shape" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/theme" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/tokens" "12.0.0-canary.9f68a932e.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/tab-bar@^12.0.0-canary.22d29cbb4.0":
|
||||
version "12.0.0-canary.22d29cbb4.0"
|
||||
resolved "https://registry.nlark.com/@material/tab-bar/download/@material/tab-bar-12.0.0-canary.22d29cbb4.0.tgz#294a67f387e80cccade1700ab15ae79d9faee394"
|
||||
@ -1090,6 +1284,29 @@
|
||||
"@material/feature-targeting" "12.0.0-canary.22d29cbb4.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/theme@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/theme/download/@material/theme-12.0.0-canary.9f68a932e.0.tgz#58cc520689b3c3c3a2852c42117376b0c363cf75"
|
||||
integrity sha1-WMxSBomzw8OihSxCEXN2sMNjz3U=
|
||||
dependencies:
|
||||
"@material/feature-targeting" "12.0.0-canary.9f68a932e.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/theme@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/theme/download/@material/theme-12.0.0-canary.e1703bed9.0.tgz#f898b0ba756c183219750776b3e13b91e5ed1de8"
|
||||
integrity sha1-+JiwunVsGDIZdQd2s+E7keXtHeg=
|
||||
dependencies:
|
||||
"@material/feature-targeting" "12.0.0-canary.e1703bed9.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/tokens@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/tokens/download/@material/tokens-12.0.0-canary.9f68a932e.0.tgz#3e3b906ad0145c80fdca5b8e362939f177866b29"
|
||||
integrity sha1-PjuQatAUXID9yluONik58XeGayk=
|
||||
dependencies:
|
||||
"@material/elevation" "12.0.0-canary.9f68a932e.0"
|
||||
|
||||
"@material/touch-target@12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/touch-target/download/@material/touch-target-12.0.0-canary.068fd5028.0.tgz#542c3fa5e729fe542c21a8668a5fdd820b05e415"
|
||||
@ -1099,6 +1316,24 @@
|
||||
"@material/feature-targeting" "12.0.0-canary.068fd5028.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/touch-target@12.0.0-canary.9f68a932e.0":
|
||||
version "12.0.0-canary.9f68a932e.0"
|
||||
resolved "https://registry.nlark.com/@material/touch-target/download/@material/touch-target-12.0.0-canary.9f68a932e.0.tgz#c8d4a5c292fbf0d6442fd31e4b6eb77915f94087"
|
||||
integrity sha1-yNSlwpL78NZEL9MeS263eRX5QIc=
|
||||
dependencies:
|
||||
"@material/base" "12.0.0-canary.9f68a932e.0"
|
||||
"@material/feature-targeting" "12.0.0-canary.9f68a932e.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/touch-target@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/touch-target/download/@material/touch-target-12.0.0-canary.e1703bed9.0.tgz#2df8ab02cfe7cd5ddf951338c77ae5a890c78c8b"
|
||||
integrity sha1-LfirAs/nzV3flRM4x3rlqJDHjIs=
|
||||
dependencies:
|
||||
"@material/base" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/feature-targeting" "12.0.0-canary.e1703bed9.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/typography@12.0.0-canary.068fd5028.0", "@material/typography@^12.0.0-canary.068fd5028.0":
|
||||
version "12.0.0-canary.068fd5028.0"
|
||||
resolved "https://registry.nlark.com/@material/typography/download/@material/typography-12.0.0-canary.068fd5028.0.tgz#3a3e536239cd1e55eec9921229877ef9cde4f288"
|
||||
@ -1117,6 +1352,15 @@
|
||||
"@material/theme" "12.0.0-canary.22d29cbb4.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@material/typography@12.0.0-canary.e1703bed9.0":
|
||||
version "12.0.0-canary.e1703bed9.0"
|
||||
resolved "https://registry.nlark.com/@material/typography/download/@material/typography-12.0.0-canary.e1703bed9.0.tgz#f82960566f8afc7eafce0c60eda6fc60ef5e4839"
|
||||
integrity sha1-+ClgVm+K/H6vzgxg7ab8YO9eSDk=
|
||||
dependencies:
|
||||
"@material/feature-targeting" "12.0.0-canary.e1703bed9.0"
|
||||
"@material/theme" "12.0.0-canary.e1703bed9.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.4":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.npm.taobao.org/@nodelib/fs.scandir/download/@nodelib/fs.scandir-2.1.4.tgz?cache=0&sync_timestamp=1609074618762&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40nodelib%2Ffs.scandir%2Fdownload%2F%40nodelib%2Ffs.scandir-2.1.4.tgz"
|
||||
@ -6699,7 +6943,7 @@ typescript-vscode-sh-plugin@^0.6.14:
|
||||
resolved "https://registry.nlark.com/typescript-vscode-sh-plugin/download/typescript-vscode-sh-plugin-0.6.14.tgz#a81031b502f6346a26ea49ce082438c3e353bb38"
|
||||
integrity sha1-qBAxtQL2NGom6knOCCQ4w+NTuzg=
|
||||
|
||||
typescript@^4.0, typescript@^4.3.5:
|
||||
typescript@>=3, typescript@^4.0, typescript@^4.3.5:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"
|
||||
integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
|
||||
@ -7392,6 +7636,13 @@ word-wrap@^1.2.3, word-wrap@~1.2.3:
|
||||
resolved "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz?cache=0&sync_timestamp=1589683603678&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fword-wrap%2Fdownload%2Fword-wrap-1.2.3.tgz"
|
||||
integrity sha1-YQY29rH3A4kb00dxzLF/uTtHB5w=
|
||||
|
||||
wp-types@^2.10.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.nlark.com/wp-types/download/wp-types-2.10.0.tgz#f816346d37026563fe97bf502d4a5da3397c60f9"
|
||||
integrity sha1-+BY0bTcCZWP+l79QLUpdozl8YPk=
|
||||
dependencies:
|
||||
typescript ">=3"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
|
Loading…
Reference in New Issue
Block a user