feat: Introduce multi-selection for character assets, including UI for bulk selection and use in generation.
This commit is contained in:
@@ -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 }}
|
||||
|
||||
Reference in New Issue
Block a user