refactor: media-caption component as composition api
This commit is contained in:
parent
0ae09f2e80
commit
b64f266483
1 changed files with 85 additions and 111 deletions
|
@ -1,137 +1,111 @@
|
||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" @click="done(true)" @closed="$emit('closed')">
|
<MkModal ref="modal" @click="done(true)" @closed="$emit('closed')">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="fullwidth top-caption">
|
<div class="fullwidth top-caption">
|
||||||
<div class="mk-dialog">
|
<div class="mk-dialog">
|
||||||
<header>
|
<header>
|
||||||
<Mfm v-if="title" class="title" :text="title"/>
|
<Mfm v-if="title" class="title" :text="title"/>
|
||||||
<span class="text-count" :class="{ over: remainingLength < 0 }">{{ remainingLength }}</span>
|
<span class="text-count" :class="{ over: remainingLength < 0 }">{{ remainingLength }}</span>
|
||||||
</header>
|
</header>
|
||||||
<textarea v-model="inputValue" autofocus :placeholder="input.placeholder" @keydown="onInputKeydown"></textarea>
|
<textarea v-model="inputValue" autofocus :placeholder="input.placeholder" @keydown="onInputKeydown"></textarea>
|
||||||
<div v-if="(showOkButton || showCancelButton)" class="buttons">
|
<div v-if="(showOkButton || showCancelButton)" class="buttons">
|
||||||
<MkButton inline primary :disabled="remainingLength < 0" @click="ok">{{ $ts.ok }}</MkButton>
|
<MkButton inline primary :disabled="remainingLength < 0" @click="ok">{{ $ts.ok }}</MkButton>
|
||||||
<MkButton inline @click="cancel" >{{ $ts.cancel }}</MkButton>
|
<MkButton inline @click="cancel">{{ $ts.cancel }}</MkButton>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hdrwpsaf fullwidth">
|
|
||||||
<header>{{ image.name }}</header>
|
|
||||||
<img :src="image.url" :alt="image.comment" :title="image.comment" @click="$refs.modal.close()"/>
|
|
||||||
<footer>
|
|
||||||
<span>{{ image.type }}</span>
|
|
||||||
<span>{{ bytes(image.size) }}</span>
|
|
||||||
<span v-if="image.properties && image.properties.width">{{ number(image.properties.width) }}px × {{ number(image.properties.height) }}px</span>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</MkModal>
|
<div class="hdrwpsaf fullwidth">
|
||||||
|
<header>{{ image.name }}</header>
|
||||||
|
<img :src="image.url" :alt="image.comment" :title="image.comment" @click="modal.close()"/>
|
||||||
|
<footer>
|
||||||
|
<span>{{ image.type }}</span>
|
||||||
|
<span>{{ bytes(image.size) }}</span>
|
||||||
|
<span v-if="image.properties && image.properties.width">{{ number(image.properties.width) }}px × {{ number(image.properties.height) }}px</span>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MkModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { onBeforeUnmount, onMounted, computed } from 'vue';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
|
import * as misskey from 'misskey-js';
|
||||||
import MkModal from '@/components/ui/modal.vue';
|
import MkModal from '@/components/ui/modal.vue';
|
||||||
import MkButton from '@/components/ui/button.vue';
|
import MkButton from '@/components/ui/button.vue';
|
||||||
import bytes from '@/filters/bytes';
|
import bytes from '@/filters/bytes';
|
||||||
import number from '@/filters/number';
|
import number from '@/filters/number';
|
||||||
|
|
||||||
export default defineComponent({
|
type Input = {
|
||||||
components: {
|
placeholder?: string;
|
||||||
MkModal,
|
default?: any;
|
||||||
MkButton,
|
};
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
const props = withDefaults(defineProps<{
|
||||||
image: {
|
image: misskey.entities.DriveFile;
|
||||||
type: Object,
|
title?: string;
|
||||||
required: true,
|
input: Input;
|
||||||
},
|
showOkButton: boolean;
|
||||||
title: {
|
showCancelButton: boolean;
|
||||||
type: String,
|
cancelableByBgClick: boolean;
|
||||||
required: false
|
}>(), {
|
||||||
},
|
title: undefined,
|
||||||
input: {
|
showOkButton: true,
|
||||||
required: true
|
showCancelButton: true,
|
||||||
},
|
cancelableByBgClick: true,
|
||||||
showOkButton: {
|
});
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
showCancelButton: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
cancelableByBgClick: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
emits: ['done', 'closed'],
|
const emit = defineEmits<{
|
||||||
|
(ev: 'done', v: { canceled: boolean, result?: string }): void,
|
||||||
|
(ev: 'closed'): void,
|
||||||
|
}>();
|
||||||
|
|
||||||
data() {
|
let inputValue: string | undefined = $ref(props.input.default ?? undefined);
|
||||||
return {
|
let modal = $ref<InstanceType<typeof MkModal>>();
|
||||||
inputValue: this.input.default ? this.input.default : null
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
function done(canceled: boolean, result?: string): void {
|
||||||
remainingLength(): number {
|
emit('done', { canceled, result });
|
||||||
if (typeof this.inputValue !== "string") return 512;
|
modal.close();
|
||||||
return 512 - length(this.inputValue);
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
async function ok(): Promise<void> {
|
||||||
document.addEventListener('keydown', this.onKeydown);
|
if (!props.showOkButton) return;
|
||||||
},
|
|
||||||
|
|
||||||
beforeUnmount() {
|
const result = inputValue;
|
||||||
document.removeEventListener('keydown', this.onKeydown);
|
done(false, result);
|
||||||
},
|
}
|
||||||
|
|
||||||
methods: {
|
function cancel(): void {
|
||||||
bytes,
|
done(true);
|
||||||
number,
|
}
|
||||||
|
|
||||||
done(canceled, result?) {
|
function onKeydown(evt: KeyboardEvent): void {
|
||||||
this.$emit('done', { canceled, result });
|
if (evt.key === 'Escape') {
|
||||||
this.$refs.modal.close();
|
cancel();
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async ok() {
|
function onInputKeydown(evt: KeyboardEvent): void {
|
||||||
if (!this.showOkButton) return;
|
if (evt.key === 'Enter') {
|
||||||
|
if (evt.ctrlKey) {
|
||||||
const result = this.inputValue;
|
evt.preventDefault();
|
||||||
this.done(false, result);
|
evt.stopPropagation();
|
||||||
},
|
ok();
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.done(true);
|
|
||||||
},
|
|
||||||
|
|
||||||
onBgClick() {
|
|
||||||
if (this.cancelableByBgClick) {
|
|
||||||
this.cancel();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onKeydown(evt) {
|
|
||||||
if (evt.which === 27) { // ESC
|
|
||||||
this.cancel();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onInputKeydown(evt) {
|
|
||||||
if (evt.which === 13) { // Enter
|
|
||||||
if (evt.ctrlKey) {
|
|
||||||
evt.preventDefault();
|
|
||||||
evt.stopPropagation();
|
|
||||||
this.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const remainingLength = computed((): number => {
|
||||||
|
if (typeof inputValue !== 'string') return 512;
|
||||||
|
return 512 - length(inputValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('keydown', onKeydown);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
document.removeEventListener('keydown', onKeydown);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue