feat(bulk): GalleryItem select-mode click + checkbox/order-badge overlay
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-card
|
<v-card
|
||||||
class="fc-gallery-item" elevation="0" @click="$emit('open', image.id)"
|
class="fc-gallery-item" elevation="0"
|
||||||
:aria-label="`Open image ${image.id}`" tabindex="0"
|
:class="{ 'fc-gallery-item--selected': selected }"
|
||||||
@keydown.enter="$emit('open', image.id)"
|
@click="onClick"
|
||||||
@keydown.space.prevent="$emit('open', image.id)"
|
:aria-label="`Image ${image.id}`" tabindex="0"
|
||||||
|
@keydown.enter="onClick"
|
||||||
|
@keydown.space.prevent="onClick"
|
||||||
>
|
>
|
||||||
<div class="fc-gallery-item__media">
|
<div class="fc-gallery-item__media">
|
||||||
<img
|
<img
|
||||||
@@ -17,21 +19,35 @@
|
|||||||
<div v-if="thumbError" class="fc-gallery-item__placeholder">
|
<div v-if="thumbError" class="fc-gallery-item__placeholder">
|
||||||
<v-icon size="32" icon="mdi-image-broken-variant" />
|
<v-icon size="32" icon="mdi-image-broken-variant" />
|
||||||
</div>
|
</div>
|
||||||
|
<template v-if="sel.isSelectMode">
|
||||||
|
<div class="fc-gallery-item__checkbox" :class="{ on: selected }">
|
||||||
|
<v-icon v-if="selected" size="16" icon="mdi-check" />
|
||||||
|
</div>
|
||||||
|
<div v-if="selected" class="fc-gallery-item__order">{{ orderNum }}</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</v-card>
|
</v-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
import { useGallerySelectionStore } from '../../stores/gallerySelection.js'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({ image: { type: Object, required: true } })
|
||||||
image: { type: Object, required: true }
|
const emit = defineEmits(['open'])
|
||||||
})
|
|
||||||
defineEmits(['open'])
|
|
||||||
|
|
||||||
|
const sel = useGallerySelectionStore()
|
||||||
const thumbError = ref(false)
|
const thumbError = ref(false)
|
||||||
const isVideo = computed(() => props.image.mime && props.image.mime.startsWith('video/'))
|
const isVideo = computed(
|
||||||
|
() => props.image.mime && props.image.mime.startsWith('video/')
|
||||||
|
)
|
||||||
|
const selected = computed(() => sel.isSelected(props.image.id))
|
||||||
|
const orderNum = computed(() => sel.order.indexOf(props.image.id) + 1)
|
||||||
|
|
||||||
|
function onClick() {
|
||||||
|
if (sel.isSelectMode) sel.toggle(props.image.id)
|
||||||
|
else emit('open', props.image.id)
|
||||||
|
}
|
||||||
function onThumbError() { thumbError.value = true }
|
function onThumbError() { thumbError.value = true }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -46,6 +62,10 @@ function onThumbError() { thumbError.value = true }
|
|||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
outline: 2px solid rgb(var(--v-theme-accent));
|
outline: 2px solid rgb(var(--v-theme-accent));
|
||||||
}
|
}
|
||||||
|
.fc-gallery-item--selected {
|
||||||
|
outline: 3px solid rgb(var(--v-theme-accent));
|
||||||
|
outline-offset: -3px;
|
||||||
|
}
|
||||||
.fc-gallery-item__media {
|
.fc-gallery-item__media {
|
||||||
position: relative;
|
position: relative;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
@@ -58,7 +78,7 @@ function onThumbError() { thumbError.value = true }
|
|||||||
.fc-gallery-item__video-thumb { position: relative; height: 100%; }
|
.fc-gallery-item__video-thumb { position: relative; height: 100%; }
|
||||||
.fc-gallery-item__video-badge {
|
.fc-gallery-item__video-badge {
|
||||||
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
||||||
color: rgba(232, 228, 216, 0.85); /* parchment with alpha */
|
color: rgba(232, 228, 216, 0.85);
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@@ -66,4 +86,25 @@ function onThumbError() { thumbError.value = true }
|
|||||||
position: absolute; inset: 0; display: grid; place-items: center;
|
position: absolute; inset: 0; display: grid; place-items: center;
|
||||||
background: rgb(var(--v-theme-surface-light));
|
background: rgb(var(--v-theme-surface-light));
|
||||||
}
|
}
|
||||||
|
.fc-gallery-item__checkbox {
|
||||||
|
position: absolute; top: 8px; left: 8px;
|
||||||
|
width: 22px; height: 22px; border-radius: 4px;
|
||||||
|
border: 2px solid rgba(232, 228, 216, 0.8);
|
||||||
|
background: rgba(20, 23, 26, 0.45);
|
||||||
|
display: grid; place-items: center;
|
||||||
|
color: #14171A; z-index: 11;
|
||||||
|
}
|
||||||
|
.fc-gallery-item__checkbox.on {
|
||||||
|
background: rgb(var(--v-theme-accent));
|
||||||
|
border-color: rgb(var(--v-theme-accent));
|
||||||
|
}
|
||||||
|
.fc-gallery-item__order {
|
||||||
|
position: absolute; top: 6px; right: 6px;
|
||||||
|
min-width: 22px; height: 22px; padding: 0 5px;
|
||||||
|
border-radius: 11px;
|
||||||
|
background: rgb(var(--v-theme-accent));
|
||||||
|
color: #14171A; font-size: 12px; font-weight: 700;
|
||||||
|
display: grid; place-items: center; z-index: 11;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user