From d26e2588e3f2662a488664d8dac8ffb386f22106 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Fri, 23 Dec 2022 02:20:36 +0100 Subject: [PATCH] client: combine selection of files & folders --- packages/client/src/components/drive.file.vue | 8 +- .../client/src/components/drive.folder.vue | 100 ++++++++++-------- packages/client/src/components/drive.vue | 86 ++++++++------- 3 files changed, 105 insertions(+), 89 deletions(-) diff --git a/packages/client/src/components/drive.file.vue b/packages/client/src/components/drive.file.vue index 6e3d38612..f6713947e 100644 --- a/packages/client/src/components/drive.file.vue +++ b/packages/client/src/components/drive.file.vue @@ -52,7 +52,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'chosen', r: foundkey.entities.DriveFile): void; + (ev: 'chosen', r: foundkey.entities.DriveFile, extendSelection: boolean): void; (ev: 'dragstart'): void; (ev: 'dragend'): void; }>(); @@ -95,9 +95,7 @@ function getMenu(): MenuItem[] { function onClick(ev: MouseEvent): void { if (props.selectMode) { - emit('chosen', props.file); - } else { - os.popupMenu(getMenu(), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined); + emit('chosen', props.file, ev.ctrlKey); } } @@ -330,7 +328,7 @@ async function deleteFile(): Promise { overflow: hidden; > .ext { - opacity: 0.5; + opacity: 0.7; } } } diff --git a/packages/client/src/components/drive.folder.vue b/packages/client/src/components/drive.folder.vue index 1584b15c0..c613571f5 100644 --- a/packages/client/src/components/drive.folder.vue +++ b/packages/client/src/components/drive.folder.vue @@ -1,10 +1,10 @@ @@ -44,7 +45,7 @@ const props = withDefaults(defineProps<{ }); const emit = defineEmits<{ - (ev: 'chosen', v: foundkey.entities.DriveFolder): void; + (ev: 'chosen', v: foundkey.entities.DriveFolder, extendSelection: boolean): void; (ev: 'move', v: foundkey.entities.DriveFolder): void; (ev: 'upload', file: File, folder: foundkey.entities.DriveFolder); (ev: 'removeFile', v: foundkey.entities.DriveFile['id']): void; @@ -59,20 +60,10 @@ const isDragging = ref(false); const title = computed(() => props.folder.name); -function checkboxClicked() { - emit('chosen', props.folder); -} - -function onClick() { - emit('move', props.folder); -} - -function onMouseover() { - hover.value = true; -} - -function onMouseout() { - hover.value = false; +function selected(ev: MouseEvent) { + if (props.selectMode) { + emit('chosen', props.folder, ev.ctrlKey); + } } function onDragover(ev: DragEvent) { @@ -260,29 +251,34 @@ function onContextmenu(ev: MouseEvent) { .rghtznwe { position: relative; padding: 8px; - height: 64px; - border-radius: 4px; + min-height: 180px; + border-radius: 8px; &, * { cursor: pointer; } - *:not(.checkbox) { - pointer-events: none; - } + > .thumbnail { + width: 110px; + height: 110px; + margin: auto; - > .checkbox { - position: absolute; - bottom: 8px; - right: 8px; - width: 16px; - height: 16px; - background: #fff; - border: solid 1px #000; + /* same style as drive-file-thumbnail.vue */ + position: relative; + display: flex; + background: var(--panel); + border-radius: 8px; + overflow: clip; - &.checked { - background: var(--accent); + > i { + pointer-events: none; + margin: auto; + font-size: 33px; + color: #777; } + + &:not(:hover) > i.hover, + &:hover > i:not(.hover) { display: none; } } &.draghover { @@ -299,23 +295,37 @@ function onContextmenu(ev: MouseEvent) { } } - > .name { - margin: 0; - font-size: 0.9em; - color: var(--desktopDriveFolderFg); + &.isSelected { + background: var(--accent); - > i { - margin-right: 4px; - margin-left: 2px; - text-align: left; + &:hover { + background: var(--accentLighten); } + + > .name { + color: #fff; + } + + > .thumbnail { + color: #fff; + } + } + + > .name { + display: block; + margin: 4px 0 0 0; + font-size: 0.8em; + text-align: center; + word-break: break-all; + color: var(--fg); + overflow: hidden; } > .upload { margin: 4px 4px; font-size: 0.8em; - text-align: right; - color: var(--desktopDriveFolderFg); + text-align: center; + opacity: 0.7; } } diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue index 1ca4f8c57..ec985ea9d 100644 --- a/packages/client/src/components/drive.vue +++ b/packages/client/src/components/drive.vue @@ -52,8 +52,9 @@ :key="f.id" v-anim="i" :file="f" - :is-selected="selectedFiles.some(x => x.id === f.id)" - @chosen="chooseFile" + :select-mode="select !== 'folder'" + :is-selected="selected.some(x => x.id === f.id)" + @chosen="choose" @dragstart="isDragSource = true" @dragend="isDragSource = false" /> @@ -62,8 +63,9 @@ :key="f.id" v-anim="i" :folder="f" - :is-selected="selectedFolders.some(x => x.id === f.id)" - @chosen="chooseFolder" + :select-mode="select !== 'file'" + :is-selected="selected.some(x => x.id === f.id)" + @chosen="choose" @move="move" @upload="upload" @removeFile="removeFile" @@ -106,7 +108,7 @@ const props = withDefaults(defineProps<{ const emit = defineEmits<{ (ev: 'selected', v: foundkey.entities.DriveFile | foundkey.entities.DriveFolder): void; - (ev: 'change-selection', v: foundkey.entities.DriveFile[] | foundkey.entities.DriveFolder[]): void; + (ev: 'change-selection', v: Array): void; (ev: 'move-root'): void; (ev: 'cd', v: foundkey.entities.DriveFolder | null): void; (ev: 'open-folder', v: foundkey.entities.DriveFolder): void; @@ -121,8 +123,7 @@ const connection = stream.useChannel('drive'); let folder = $ref(null); let hierarchyFolders = $ref([]); -let selectedFiles = $ref([]); -let selectedFolders = $ref([]); +let selected = $ref>([]); let keepOriginal = $ref(defaultStore.state.keepOriginalUploading); // ドロップされようとしているか @@ -356,42 +357,49 @@ function upload(file: File, folderToUpload?: foundkey.entities.DriveFolder | nul uploadFile(file, folderToUpload?.id ?? null, undefined, keepOriginal); } -function chooseFile(file: foundkey.entities.DriveFile) { - const isAlreadySelected = selectedFiles.some(f => f.id === file.id); - if (props.multiple) { - if (isAlreadySelected) { - selectedFiles = selectedFiles.filter(f => f.id !== file.id); - } else { - selectedFiles.push(file); - } - emit('change-selection', selectedFiles); - } else { - if (isAlreadySelected) { - emit('selected', file); - } else { - selectedFiles = [file]; - emit('change-selection', [file]); - } - } -} +function choose(choice: foundkey.entities.DriveFile | foundkey.entities.DriveFolder, extendSelection: boolean) { + const alreadySelected = selectedFiles.some(f => f.id === file.id); -function chooseFolder(folderToChoose: foundkey.entities.DriveFolder) { - const isAlreadySelected = selectedFolders.some(f => f.id === folderToChoose.id); - if (props.multiple) { - if (isAlreadySelected) { - selectedFolders = selectedFolders.filter(f => f.id !== folderToChoose.id); + const action = (() => { + if (props.select != null) { + // file picker mode, extendSelection is disregarded + if (props.multiple && alreadySelected) { + return 'remove'; + } else if (props.multiple) { + return 'add'; + } else if (!props.multiple && alreadySelected) { + return 'emit'; + } else { + return 'set'; + } } else { - selectedFolders.push(folderToChoose); - } - emit('change-selection', selectedFolders); - } else { - if (isAlreadySelected) { - emit('selected', folderToChoose); - } else { - selectedFolders = [folderToChoose]; - emit('change-selection', [folderToChoose]); + // explorer mode, props.multiple is disregarded + if (extendSelection && alreadySelected) { + return 'remove'; + } else if (extendSelection) { + return 'add'; + } else if (!alreadySelected) { + return 'set'; + } + // already selected && ! extend selection is a noop } + })(); + + switch (action) { + case 'emit': + emit('selected', choice); + return; // don't emit the change-selection event + case 'add': + selected.push(choice); + break; + case 'set': + selected = [choice]; + break; + case 'remove': + selected = selected.filter(f => f.id !== choice.id); + break; } + emit('change-selection', selected); } function move(target?: string | foundkey.entities.DriveFolder) {