likes
This commit is contained in:
@@ -674,6 +674,11 @@ const groupedGenerations = computed(() => {
|
||||
return result
|
||||
})
|
||||
|
||||
const getChildByAssetId = (group, assetId) => {
|
||||
if (!group.isGroup) return group;
|
||||
return group.children.find(c => c.result_list?.includes(assetId)) || group;
|
||||
}
|
||||
|
||||
const hasActiveGenerations = computed(() => {
|
||||
return generations.value.some(g => ['processing', 'starting', 'running'].includes(g.status))
|
||||
})
|
||||
@@ -688,7 +693,8 @@ const allGalleryImages = computed(() => {
|
||||
assetId,
|
||||
url: API_URL + '/assets/' + assetId,
|
||||
thumbnailUrl: API_URL + '/assets/' + assetId + '?thumbnail=true',
|
||||
gen
|
||||
gen,
|
||||
is_liked: gen.liked_assets?.includes(assetId)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -889,6 +895,25 @@ async function confirmAddToPlan() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleLiked = ({ id, is_liked }) => {
|
||||
// Update local state in generations
|
||||
generations.value.forEach(gen => {
|
||||
if (gen.id === id) {
|
||||
gen.is_liked = is_liked
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const toggleLike = async (gen) => {
|
||||
if (!gen || !gen.id) return
|
||||
try {
|
||||
const response = await dataService.toggleLike(gen.id)
|
||||
handleLiked({ id: gen.id, is_liked: response.is_liked })
|
||||
} catch (e) {
|
||||
console.error('Failed to toggle like', e)
|
||||
}
|
||||
}
|
||||
|
||||
// Exit select mode when switching to feed
|
||||
watch(viewMode, (v) => {
|
||||
if (v !== 'gallery') {
|
||||
@@ -994,6 +1019,10 @@ watch(viewMode, (v) => {
|
||||
</div>
|
||||
<div
|
||||
class="flex gap-1 opacity-100 md:opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<Button :icon="gen.is_liked ? 'pi pi-heart-fill' : 'pi pi-heart'" text rounded size="small"
|
||||
class="!w-7 !h-7 !p-0"
|
||||
:class="gen.is_liked ? '!text-pink-500' : '!text-slate-400 hover:!text-pink-500'"
|
||||
v-tooltip.top="gen.is_liked ? 'Unlike' : 'Like'" @click="toggleLike(gen)" />
|
||||
<Button icon="pi pi-copy" text rounded size="small"
|
||||
class="!w-7 !h-7 !text-slate-400 hover:!text-white"
|
||||
v-tooltip.top="'Reuse Prompt'" @click="reusePrompt(gen)" />
|
||||
@@ -1016,19 +1045,32 @@ watch(viewMode, (v) => {
|
||||
class="relative group/img cursor-pointer aspect-[4/3]">
|
||||
<img :src="API_URL + '/assets/' + res + '?thumbnail=true'"
|
||||
class="w-full h-full object-cover"
|
||||
@click="openImagePreview(gen.result_list.map(r => ({ url: API_URL + '/assets/' + r, gen: gen })), resIdx)" />
|
||||
@click="openImagePreview(gen.result_list.map(r => ({ url: API_URL + '/assets/' + r, gen: getChildByAssetId(gen, r), assetId: r, is_liked: getChildByAssetId(gen, r).is_liked })), resIdx)" />
|
||||
|
||||
<!-- Liked indicator -->
|
||||
<div v-if="getChildByAssetId(gen, res).is_liked"
|
||||
class="absolute top-1.5 left-1.5 w-5 h-5 rounded-full bg-pink-500 shadow-lg flex items-center justify-center border border-pink-400 z-10">
|
||||
<i class="pi pi-heart-fill text-white text-[8px]"></i>
|
||||
</div>
|
||||
|
||||
<!-- Per-image hover overlay -->
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent opacity-0 group-hover/img:opacity-100 transition-opacity duration-200 pointer-events-none">
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-1 right-1 flex gap-1 opacity-0 group-hover/img:opacity-100 transition-opacity duration-200">
|
||||
<button @click.stop="toggleLike(getChildByAssetId(gen, res))"
|
||||
class="w-6 h-6 rounded-md backdrop-blur-sm flex items-center justify-center text-white transition-all hover:scale-110 shadow-lg"
|
||||
:class="getChildByAssetId(gen, res).is_liked ? 'bg-pink-500 hover:bg-pink-400' : 'bg-slate-700/80 hover:bg-pink-500'"
|
||||
v-tooltip.top="getChildByAssetId(gen, res).is_liked ? 'Unlike' : 'Like'">
|
||||
<i :class="getChildByAssetId(gen, res).is_liked ? 'pi pi-heart-fill' : 'pi pi-heart'" style="font-size: 10px"></i>
|
||||
</button>
|
||||
<button @click.stop="setAsReference(res)"
|
||||
class="w-6 h-6 rounded-md bg-violet-600/80 hover:bg-violet-500 backdrop-blur-sm flex items-center justify-center text-white transition-all hover:scale-110 shadow-lg"
|
||||
v-tooltip.top="'Use as Reference'">
|
||||
<i class="pi pi-pencil" style="font-size: 10px"></i>
|
||||
</button>
|
||||
<button @click.stop="deleteAssetFromGeneration(gen, res)"
|
||||
<button @click.stop="deleteAssetFromGeneration(getChildByAssetId(gen, res), res)"
|
||||
class="w-6 h-6 rounded-md bg-red-600/80 hover:bg-red-500 backdrop-blur-sm flex items-center justify-center text-white transition-all hover:scale-110 shadow-lg"
|
||||
v-tooltip.top="'Remove Image'">
|
||||
<i class="pi pi-trash" style="font-size: 10px"></i>
|
||||
@@ -1099,6 +1141,12 @@ watch(viewMode, (v) => {
|
||||
|
||||
<img :src="img.thumbnailUrl" class="w-full h-full object-cover" />
|
||||
|
||||
<!-- Liked Badge -->
|
||||
<div v-if="img.is_liked"
|
||||
class="absolute top-2 right-2 z-10 w-6 h-6 rounded-full bg-pink-500 shadow-lg flex items-center justify-center border border-pink-400">
|
||||
<i class="pi pi-heart-fill text-white text-[10px]"></i>
|
||||
</div>
|
||||
|
||||
<!-- Selection checkmark (always visible in select mode) -->
|
||||
<div v-if="isSelectMode"
|
||||
class="absolute top-2 left-2 w-7 h-7 rounded-full flex items-center justify-center transition-all shadow-lg z-10"
|
||||
@@ -1111,6 +1159,11 @@ watch(viewMode, (v) => {
|
||||
class="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity flex flex-col justify-end p-3">
|
||||
<p class="text-xs text-white line-clamp-2 mb-2">{{ img.gen.prompt }}</p>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<Button :icon="img.gen.is_liked ? 'pi pi-heart-fill' : 'pi pi-heart'" rounded text size="small"
|
||||
class="!text-white transition-colors"
|
||||
:class="img.gen.is_liked ? '!text-pink-500' : 'hover:!text-pink-500 hover:!bg-white/20'"
|
||||
v-tooltip.top="img.gen.is_liked ? 'Unlike' : 'Like'"
|
||||
@click.stop="toggleLike(img.gen)" />
|
||||
<Button icon="pi pi-pencil" rounded text size="small"
|
||||
class="!text-white hover:!bg-white/20" v-tooltip.top="'Use as Reference'"
|
||||
@click.stop="setAsReference(img.assetId)" />
|
||||
@@ -1425,6 +1478,7 @@ watch(viewMode, (v) => {
|
||||
@reuse-prompt="reusePrompt"
|
||||
@reuse-asset="reuseAssets"
|
||||
@use-result-as-asset="useResultAsAsset"
|
||||
@liked="handleLiked"
|
||||
/>
|
||||
|
||||
<!-- Add to Content Plan Dialog -->
|
||||
|
||||
Reference in New Issue
Block a user