enhance(frontend): ドライブのファイル・フォルダをドラッグしなくても移動できるように (#14318)
* feat(drive): ファイルをフォルダに移動するメニューを実装 (cherry picked from commit b89c2af6945c6a9f9f10e83f54d2bcf0f240b0b4) * tweak ui * Update Changelog * ファイル詳細からも移動できるように * feat(drive) フォルダのネストを移動するメニューを実装 (cherry picked from commit 8a7d710c6acb83f50c83f050bd1423c764d60a99) * Update Changelog * Update Changelog * lint * tweak ui --------- Co-authored-by: nafu-at <satsuki@nafusoft.dev> Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
parent
738b3ea43b
commit
45f909ef33
5 changed files with 117 additions and 17 deletions
|
@ -25,6 +25,8 @@
|
|||
- Enhance: AiScriptを0.19.0にアップデート
|
||||
- Enhance: Allow negative delay for MFM animation elements (`tada`, `jelly`, `twitch`, `shake`, `spin`, `jump`, `bounce`, `rainbow`)
|
||||
- Enhance: センシティブなメディアを開く際に確認ダイアログを出せるように
|
||||
- Enhance: ドライブのファイル・フォルダをドラッグしなくても移動できるように
|
||||
(Cherry-picked from https://github.com/nafu-at/misskey/commit/b89c2af6945c6a9f9f10e83f54d2bcf0f240b0b4, https://github.com/nafu-at/misskey/commit/8a7d710c6acb83f50c83f050bd1423c764d60a99)
|
||||
- Enhance: デッキのアンテナ・リスト選択画面からそれぞれを新規作成できるように
|
||||
- Fix: `/about#federation` ページなどで各インスタンスのチャートが表示されなくなっていた問題を修正
|
||||
- Fix: ユーザーページの追加情報のラベルを投稿者のサーバーの絵文字で表示する (#13968)
|
||||
|
|
|
@ -27,7 +27,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<p v-if="defaultStore.state.uploadFolder == folder.id" :class="$style.upload">
|
||||
{{ i18n.ts.uploadFolder }}
|
||||
</p>
|
||||
<button v-if="selectMode" class="_button" :class="[$style.checkbox, { [$style.checked]: isSelected }]" @click.prevent.stop="checkboxClicked"></button>
|
||||
<button v-if="selectMode" class="_button" :class="$style.checkboxWrapper" @click.prevent.stop="checkboxClicked">
|
||||
<div :class="[$style.checkbox, { [$style.checked]: isSelected }]"></div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -53,6 +55,7 @@ const props = withDefaults(defineProps<{
|
|||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'chosen', v: Misskey.entities.DriveFolder): void;
|
||||
(ev: 'unchose', v: Misskey.entities.DriveFolder): void;
|
||||
(ev: 'move', v: Misskey.entities.DriveFolder): void;
|
||||
(ev: 'upload', file: File, folder: Misskey.entities.DriveFolder);
|
||||
(ev: 'removeFile', v: Misskey.entities.DriveFile['id']): void;
|
||||
|
@ -68,8 +71,12 @@ const isDragging = ref(false);
|
|||
const title = computed(() => props.folder.name);
|
||||
|
||||
function checkboxClicked() {
|
||||
if (props.isSelected) {
|
||||
emit('unchose', props.folder);
|
||||
} else {
|
||||
emit('chosen', props.folder);
|
||||
}
|
||||
}
|
||||
|
||||
function onClick() {
|
||||
emit('move', props.folder);
|
||||
|
@ -222,6 +229,17 @@ function rename() {
|
|||
});
|
||||
}
|
||||
|
||||
function move() {
|
||||
os.selectDriveFolder(false).then(folder => {
|
||||
if (folder[0] && folder[0].id === props.folder.id) return;
|
||||
|
||||
misskeyApi('drive/folders/update', {
|
||||
folderId: props.folder.id,
|
||||
parentId: folder[0] ? folder[0].id : null,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteFolder() {
|
||||
misskeyApi('drive/folders/delete', {
|
||||
folderId: props.folder.id,
|
||||
|
@ -267,6 +285,10 @@ function onContextmenu(ev: MouseEvent) {
|
|||
text: i18n.ts.rename,
|
||||
icon: 'ti ti-forms',
|
||||
action: rename,
|
||||
}, {
|
||||
text: i18n.ts.move,
|
||||
icon: 'ti ti ti-folder-symlink',
|
||||
action: move,
|
||||
}, { type: 'divider' }, {
|
||||
text: i18n.ts.delete,
|
||||
icon: 'ti ti-trash',
|
||||
|
@ -310,17 +332,43 @@ function onContextmenu(ev: MouseEvent) {
|
|||
}
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
.checkboxWrapper {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
bottom: 2px;
|
||||
right: 2px;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
> .checkbox {
|
||||
position: relative;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: #fff;
|
||||
border: solid 1px #000;
|
||||
border: solid 2px var(--divider);
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.checked {
|
||||
border-color: var(--accent);
|
||||
background: var(--accent);
|
||||
|
||||
&::after {
|
||||
content: "\ea5e";
|
||||
font-family: 'tabler-icons';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--accentedBg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
:selectMode="select === 'folder'"
|
||||
:isSelected="selectedFolders.some(x => x.id === f.id)"
|
||||
@chosen="chooseFolder"
|
||||
@unchose="unchoseFolder"
|
||||
@move="move"
|
||||
@upload="upload"
|
||||
@removeFile="removeFile"
|
||||
|
@ -428,6 +429,11 @@ function chooseFolder(folderToChoose: Misskey.entities.DriveFolder) {
|
|||
}
|
||||
}
|
||||
|
||||
function unchoseFolder(folderToUnchose: Misskey.entities.DriveFolder) {
|
||||
selectedFolders.value = selectedFolders.value.filter(f => f.id !== folderToUnchose.id);
|
||||
emit('change-selection', selectedFolders.value);
|
||||
}
|
||||
|
||||
function move(target?: Misskey.entities.DriveFolder | Misskey.entities.DriveFolder['id' | 'parentId']) {
|
||||
if (!target) {
|
||||
goRoot();
|
||||
|
|
|
@ -37,11 +37,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button class="_button" :class="$style.fileAltEditBtn" @click="describe()">
|
||||
<div class="_gaps_s">
|
||||
<button class="_button" :class="$style.kvEditBtn" @click="move()">
|
||||
<MkKeyValue>
|
||||
<template #key>{{ i18n.ts.folder }}</template>
|
||||
<template #value>{{ folderHierarchy.join(' > ') }}<i class="ti ti-pencil" :class="$style.kvEditIcon"></i></template>
|
||||
</MkKeyValue>
|
||||
</button>
|
||||
<button class="_button" :class="$style.kvEditBtn" @click="describe()">
|
||||
<MkKeyValue>
|
||||
<template #key>{{ i18n.ts.description }}</template>
|
||||
<template #value>{{ file.comment ? file.comment : `(${i18n.ts.none})` }}<i class="ti ti-pencil" :class="$style.fileAltEditIcon"></i></template>
|
||||
<template #value>{{ file.comment ? file.comment : `(${i18n.ts.none})` }}<i class="ti ti-pencil" :class="$style.kvEditIcon"></i></template>
|
||||
</MkKeyValue>
|
||||
</button>
|
||||
<MkKeyValue :class="$style.fileMetaDataChildren">
|
||||
|
@ -90,6 +96,18 @@ const props = defineProps<{
|
|||
|
||||
const fetching = ref(true);
|
||||
const file = ref<Misskey.entities.DriveFile>();
|
||||
const folderHierarchy = computed(() => {
|
||||
if (!file.value) return [i18n.ts.drive];
|
||||
const folderNames = [i18n.ts.drive];
|
||||
|
||||
function get(folder: Misskey.entities.DriveFolder) {
|
||||
if (folder.parent) get(folder.parent);
|
||||
folderNames.push(folder.name);
|
||||
}
|
||||
|
||||
if (file.value.folder) get(file.value.folder);
|
||||
return folderNames;
|
||||
});
|
||||
const isImage = computed(() => file.value?.type.startsWith('image/'));
|
||||
|
||||
async function fetch() {
|
||||
|
@ -122,6 +140,19 @@ function crop() {
|
|||
});
|
||||
}
|
||||
|
||||
function move() {
|
||||
if (!file.value) return;
|
||||
|
||||
os.selectDriveFolder(false).then(folder => {
|
||||
misskeyApi('drive/files/update', {
|
||||
fileId: file.value.id,
|
||||
folderId: folder[0] ? folder[0].id : null,
|
||||
}).then(async () => {
|
||||
await fetch();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function toggleSensitive() {
|
||||
if (!file.value) return;
|
||||
|
||||
|
@ -282,14 +313,14 @@ onMounted(async () => {
|
|||
padding: .5rem 1rem;
|
||||
}
|
||||
|
||||
.fileAltEditBtn {
|
||||
.kvEditBtn {
|
||||
text-align: start;
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: .5rem 1rem;
|
||||
border-radius: var(--radius);
|
||||
|
||||
.fileAltEditIcon {
|
||||
.kvEditIcon {
|
||||
display: inline-block;
|
||||
color: transparent;
|
||||
visibility: hidden;
|
||||
|
@ -300,7 +331,7 @@ onMounted(async () => {
|
|||
color: var(--accent);
|
||||
background-color: var(--accentedBg);
|
||||
|
||||
.fileAltEditIcon {
|
||||
.kvEditIcon {
|
||||
color: var(--accent);
|
||||
visibility: visible;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,15 @@ function describe(file: Misskey.entities.DriveFile) {
|
|||
});
|
||||
}
|
||||
|
||||
function move(file: Misskey.entities.DriveFile) {
|
||||
os.selectDriveFolder(false).then(folder => {
|
||||
misskeyApi('drive/files/update', {
|
||||
fileId: file.id,
|
||||
folderId: folder[0] ? folder[0].id : null,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function toggleSensitive(file: Misskey.entities.DriveFile) {
|
||||
misskeyApi('drive/files/update', {
|
||||
fileId: file.id,
|
||||
|
@ -88,6 +97,10 @@ export function getDriveFileMenu(file: Misskey.entities.DriveFile, folder?: Miss
|
|||
text: i18n.ts.rename,
|
||||
icon: 'ti ti-forms',
|
||||
action: () => rename(file),
|
||||
}, {
|
||||
text: i18n.ts.move,
|
||||
icon: 'ti ti-folder-symlink',
|
||||
action: () => move(file),
|
||||
}, {
|
||||
text: file.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
|
||||
icon: file.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
|
||||
|
|
Loading…
Reference in a new issue