feat: Introduce multi-selection for character assets, including UI for bulk selection and use in generation.

This commit is contained in:
xds
2026-02-04 15:47:41 +03:00
parent 83a16c8f9e
commit bb3a7955b4

View File

@@ -34,12 +34,36 @@ const API_URL = import.meta.env.VITE_API_URL
const selectedAsset = ref(null)
const isModalVisible = ref(false)
const activeTab = ref("0")
const isMultiSelectMode = ref(false)
const bulkSelectedAssetIds = ref([])
const openModal = (asset) => {
if (isMultiSelectMode.value) {
toggleBulkSelection(asset.id)
return
}
selectedAsset.value = asset
isModalVisible.value = true
}
const toggleBulkSelection = (id) => {
const idx = bulkSelectedAssetIds.value.indexOf(id)
if (idx > -1) bulkSelectedAssetIds.value.splice(idx, 1)
else bulkSelectedAssetIds.value.push(id)
}
const handleUseInGeneration = () => {
if (bulkSelectedAssetIds.value.length === 0) return
const assetsToUse = characterAssets.value.filter(a => bulkSelectedAssetIds.value.includes(a.id))
selectedAssets.value = [...assetsToUse]
activeTab.value = "0"
isMultiSelectMode.value = false
bulkSelectedAssetIds.value = []
}
const loadData = async () => {
loading.value = true
const charId = route.params.id
@@ -396,7 +420,7 @@ const handleLogout = () => {
</div>
</div>
<Tabs value="0" class="glass-panel p-1.5 rounded-xl border border-white/5"
<Tabs v-model:value="activeTab" class="glass-panel p-1.5 rounded-xl border border-white/5"
style="--p-tabs-tablist-background: transparent !important">
<TabList :pt="{
root: { class: 'border-none p-0 mb-2 inline-flex' },
@@ -651,7 +675,19 @@ const handleLogout = () => {
<div class="glass-panel p-8 rounded-3xl border border-white/5 bg-white/5">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold m-0">Linked Assets ({{ assetsTotalRecords }})</h2>
<div>
<div class="flex gap-3">
<Button v-if="isMultiSelectMode"
:label="`Use in Generation (${bulkSelectedAssetIds.length})`" icon="pi pi-bolt"
severity="success" :disabled="bulkSelectedAssetIds.length === 0"
@click="handleUseInGeneration"
class="!py-2 !px-4 !text-sm font-bold rounded-xl transition-all shadow-lg shadow-green-500/20" />
<Button :icon="isMultiSelectMode ? 'pi pi-times' : 'pi pi-list-check'"
:severity="isMultiSelectMode ? 'danger' : 'secondary'"
@click="isMultiSelectMode = !isMultiSelectMode" text
class="!p-2 hover:bg-white/10 rounded-xl transition-all"
:title="isMultiSelectMode ? 'Cancel Selection' : 'Multi-select'" />
<input type="file" ref="fileInput" class="hidden" accept="image/*"
@change="onFileSelected" />
<Button :label="isUploading ? 'Uploading...' : 'Upload Asset'"
@@ -670,10 +706,25 @@ const handleLogout = () => {
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6 gap-6">
<div v-for="asset in paginatedCharacterAssets" :key="asset.id"
@click="openModal(asset)"
class="glass-panel rounded-2xl overflow-hidden border border-white/5 transition-all duration-300 cursor-pointer hover:-translate-y-1 hover:border-white/20">
class="glass-panel rounded-2xl overflow-hidden border transition-all duration-300 cursor-pointer hover:-translate-y-1 relative"
:class="[
bulkSelectedAssetIds.includes(asset.id)
? 'border-violet-500 bg-violet-500/10 shadow-lg shadow-violet-500/10'
: isMultiSelectMode ? 'border-white/10 opacity-70 scale-[0.98]' : 'border-white/5 hover:border-white/20'
]">
<div class="h-70 relative overflow-hidden">
<img :src="API_URL + asset.url || 'https://via.placeholder.com/300'"
:alt="asset.name" class="w-full h-full object-cover" />
<div v-if="isMultiSelectMode"
class="absolute inset-0 flex items-center justify-center bg-violet-900/20 backdrop-blur-[1px] transition-all"
:class="bulkSelectedAssetIds.includes(asset.id) ? 'opacity-100' : 'opacity-0 hover:opacity-100'">
<div class="w-12 h-12 rounded-full flex items-center justify-center border-2 transition-all"
:class="bulkSelectedAssetIds.includes(asset.id) ? 'bg-violet-600 border-violet-400 scale-110 shadow-lg' : 'bg-black/40 border-white/40 scale-100'">
<i class="pi pi-check text-white text-xl"></i>
</div>
</div>
<div
class="absolute top-2 right-2 bg-black/60 backdrop-blur-sm px-2 py-1 rounded text-xs uppercase text-white">
{{ asset.type }}