enhance: 下書きピッカーを改善

This commit is contained in:
yukineko 2024-04-18 18:55:09 +09:00 committed by mattyatea
parent e7c180ff89
commit 07ebc6e5e1
1 changed files with 78 additions and 25 deletions

View File

@ -9,80 +9,116 @@
<template #header>{{ i18n.ts.drafts }}</template> <template #header>{{ i18n.ts.drafts }}</template>
<div :class="$style.container"> <div :class="$style.container">
<template v-for="(note, key) of notes" :key="key"> <div v-if="notes === null" :class="$style.center">{{ i18n.ts.loading }}</div>
<div v-if="note && noteFilter(key)" class="_panel" :class="$style.note" @click="() => select(key)"> <div v-else-if="Object.keys(notes).length === 0" :class="$style.center">{{ i18n.ts.nothing }}</div>
<div v-if="key.startsWith('renote:')" :class="$style.subtext"><i class="ti ti-quote"></i> {{ i18n.ts.quote }}</div> <div v-for="(note, key) of notes" v-else :key="key" class="_panel" :class="$style.wrapper" :aria-disabled="!noteFilter(note)">
<div v-if="key.startsWith('reply:')" :class="$style.subtext"><i class="ti ti-arrow-back-up"></i> {{ i18n.ts.reply }}</div> <div v-if="note" :class="$style.note" @click="() => select(note)">
<div v-if="note.type === 'quote'" :class="$style.subtext"><i class="ti ti-quote"></i> {{ i18n.ts.quote }}</div>
<div v-if="note.type === 'reply'" :class="$style.subtext"><i class="ti ti-arrow-back-up"></i> {{ i18n.ts.reply }}</div>
<div v-if="note.type === 'channel'" :class="$style.subtext"><i class="ti ti-device-tv"></i> {{ i18n.ts.channel }}</div>
<Mfm v-if="note.data.text" :text="note.data.text" :nyaize="'respect'"/> <Mfm v-if="note.data.text" :text="note.data.text" :nyaize="'respect'"/>
<div :class="[$style.subtext, $style.bottom]"> <div :class="[$style.subtext, $style.bottom]">
<MkTime :time="note.updatedAt"/> <MkTime :time="note.updatedAt"/>
<div v-if="note.data.files.length"><i class="ti ti-photo-plus" :class="$style.icon"></i>{{ note.data.files.length }}</div> <div v-if="note.data.files.length"><i class="ti ti-photo-plus" :class="$style.icon"></i>{{ note.data.files.length }}</div>
</div> </div>
</div> </div>
</template> <div :class="$style.trash" @click="() => remove(note)"><i class="ti ti-trash"></i></div>
</div>
</div> </div>
</MkModalWindow> </MkModalWindow>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { shallowRef, computed } from 'vue'; import { shallowRef, ref, onMounted } from 'vue';
import * as noteDrafts from '@/scripts/note-drafts.js'; import * as noteDrafts from '@/scripts/note-drafts.js';
import MkModalWindow from '@/components/MkModalWindow.vue'; import MkModalWindow from '@/components/MkModalWindow.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { $i } from '@/account'; import { signinRequired } from '@/account.js';
import * as os from '@/os.js';
const props = withDefaults(defineProps<{ const $i = signinRequired();
channel: boolean;
}>(), { const props = defineProps<{
channel: false, channelId?: string;
}); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(ev: 'selected', res: string): void; (ev: 'selected', res: noteDrafts.NoteDraft): void;
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>(); const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
const notes = computed(() => noteDrafts.getAll()); const notes = ref<Record<string, noteDrafts.NoteDraft | undefined> | null>(null);
function noteFilter(note: noteDrafts.NoteDraft | undefined) {
if (!note) return false;
function noteFilter(key: string) {
// //
if (props.channel) return key.startsWith('channel:'); if (props.channelId) return note.type === 'channel' && note.auxId === props.channelId;
// //
if (key.startsWith('channel:')) return false; if (note.type === 'channel') return false;
if (key.startsWith('note:')) return key.startsWith(`note:${$i?.id}`);
return true; return true;
} }
function select(key: string) { function select(note: noteDrafts.NoteDraft) {
emit('selected', key); if (!noteFilter(note)) return;
emit('selected', note);
dialog.value?.close(); dialog.value?.close();
} }
async function remove(note: noteDrafts.NoteDraft | undefined) {
if (!note) return;
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.ts.deleteConfirm,
});
if (canceled) return;
await noteDrafts.remove(note.type, $i.id, note.uniqueId, note.auxId as string);
notes.value = await noteDrafts.getAll($i.id);
}
onMounted(async () => {
notes.value = await noteDrafts.getAll($i.id);
});
</script> </script>
<style lang="scss" module> <style lang="scss" module>
.container { .container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch;
gap: 16px; gap: 16px;
overflow-x: clip; overflow-x: clip;
padding: 16px; padding: 16px;
} }
.note { .wrapper {
display: flex; display: flex;
flex-direction: column;
padding: 10px;
gap: 6px;
border-radius: 12px; border-radius: 12px;
background-color: var(--buttonBg); background-color: var(--buttonBg);
cursor: pointer; cursor: pointer;
&:hover { &:hover:not([aria-disabled="true"]) {
background-color: var(--buttonHoverBg); background-color: var(--buttonHoverBg);
} }
&[aria-disabled="true"] {
opacity: 0.5;
cursor: not-allowed;
}
}
.note {
display: flex;
flex-direction: column;
justify-content: center;
padding: 10px;
gap: 6px;
flex-grow: 1;
} }
.subtext { .subtext {
@ -99,4 +135,21 @@ function select(key: string) {
.icon { .icon {
margin-right: 4px; margin-right: 4px;
} }
.center {
text-align: center;
}
.trash {
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
color: var(--error);
&:hover {
background-color: var(--error);
color: white;
}
}
</style> </style>