This commit is contained in:
xds
2026-02-15 12:26:14 +03:00
parent 75e33cca9a
commit 55e8db92ed
7 changed files with 1125 additions and 3 deletions

163
src/views/IdeasView.vue Normal file
View File

@@ -0,0 +1,163 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useIdeaStore } from '../stores/ideas'
import { storeToRefs } from 'pinia'
import Skeleton from 'primevue/skeleton'
import Dialog from 'primevue/dialog'
import InputText from 'primevue/inputtext'
import Textarea from 'primevue/textarea'
import Button from 'primevue/button'
import Image from 'primevue/image'
const router = useRouter()
const ideaStore = useIdeaStore()
const { ideas, loading } = storeToRefs(ideaStore)
const showCreateDialog = ref(false)
const newIdea = ref({ name: '', description: '' })
const submitting = ref(false)
const API_URL = import.meta.env.VITE_API_URL
onMounted(async () => {
await ideaStore.fetchIdeas()
})
const goToDetail = (id) => {
router.push(`/ideas/${id}`) // Navigate to IdeaDetailView
}
const createIdea = async () => {
if (!newIdea.value.name) return
submitting.value = true
try {
await ideaStore.createIdea(newIdea.value)
showCreateDialog.value = false
newIdea.value = { name: '', description: '' }
} finally {
submitting.value = false
}
}
</script>
<template>
<div class="flex flex-col h-full p-8 overflow-y-auto text-slate-100 font-sans">
<!-- Top Bar -->
<header class="flex justify-between items-end mb-8 border-b border-white/5 pb-6">
<div>
<h1
class="text-4xl font-bold m-0 bg-gradient-to-r from-violet-400 to-fuchsia-400 bg-clip-text text-transparent">
Ideas</h1>
<p class="mt-2 mb-0 text-slate-400">Your creative sessions and experiments</p>
</div>
<Button label="New Idea" icon="pi pi-plus" @click="showCreateDialog = true"
class="!bg-violet-600 hover:!bg-violet-500 !border-none" />
</header>
<!-- Loading State -->
<div v-if="loading && ideas.length === 0" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div v-for="i in 6" :key="i" class="glass-panel rounded-2xl p-6 flex flex-col gap-4">
<Skeleton height="12rem" class="w-full rounded-xl" />
<Skeleton width="60%" height="1.5rem" />
<Skeleton width="40%" height="1rem" />
</div>
</div>
<!-- Empty State -->
<div v-else-if="ideas.length === 0"
class="flex flex-col items-center justify-center h-96 text-slate-400 bg-slate-900/30 rounded-3xl border border-dashed border-white/10">
<div class="w-20 h-20 rounded-full bg-violet-500/10 flex items-center justify-center mb-6">
<i class="pi pi-lightbulb text-4xl text-violet-400"></i>
</div>
<h3 class="text-xl font-semibold text-white mb-2">No ideas yet</h3>
<p class="text-slate-400 mb-6 max-w-sm text-center">Start a new creative session to organize your
generations and prompts.</p>
<Button label="Create your first idea" icon="pi pi-plus" @click="showCreateDialog = true" />
</div>
<!-- Ideas Grid -->
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div v-for="idea in ideas" :key="idea.id"
class="glass-panel rounded-2xl p-0 flex flex-col gap-0 transition-all duration-300 cursor-pointer border border-white/5 hover:-translate-y-1 hover:bg-slate-800/80 hover:border-violet-500/30 group overflow-hidden"
@click="goToDetail(idea.id)">
<!-- Cover Image -->
<div class="aspect-video w-full bg-slate-800 relative overflow-hidden">
<div v-if="idea.cover_asset_id" class="w-full h-full">
<img :src="API_URL + '/assets/' + idea.cover_asset_id + '?thumbnail=true'"
class="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105" />
</div>
<div v-else
class="w-full h-full flex items-center justify-center bg-gradient-to-br from-slate-800 to-slate-900 group-hover:from-violet-900/20 group-hover:to-slate-900 transition-colors">
<i
class="pi pi-lightbulb text-4xl text-slate-700 group-hover:text-violet-500/50 transition-colors"></i>
</div>
<!-- Overlay Gradient -->
<div
class="absolute inset-0 bg-gradient-to-t from-slate-900 via-transparent to-transparent opacity-60">
</div>
<!-- Count Badge -->
<div
class="absolute top-3 right-3 bg-black/40 backdrop-blur-md text-white text-xs font-bold px-2 py-1 rounded-lg border border-white/10 flex items-center gap-1">
<i class="pi pi-images text-[10px]"></i>
<span>{{ idea.generation_ids?.length || 0 }}</span>
</div>
</div>
<div class="p-5">
<h3
class="m-0 mb-2 text-xl font-bold truncate text-slate-100 group-hover:text-violet-300 transition-colors">
{{ idea.name }}</h3>
<p class="m-0 text-sm text-slate-400 line-clamp-2 min-h-[2.5em] leading-relaxed">
{{ idea.description || 'No description provided.' }}
</p>
<div class="mt-4 pt-4 border-t border-white/5 flex justify-between items-center">
<span class="text-xs text-slate-500 font-mono">ID: {{ idea.id.substring(0, 8) }}...</span>
<div
class="text-xs text-violet-400 font-medium opacity-0 group-hover:opacity-100 transition-opacity flex items-center gap-1">
Open Session <i class="pi pi-arrow-right text-[10px]"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Create Idea Dialog -->
<Dialog v-model:visible="showCreateDialog" modal header="New Idea Session" :style="{ width: '500px' }"
:breakpoints="{ '960px': '75vw', '641px': '90vw' }"
:pt="{ root: { class: '!bg-slate-900 !border !border-white/10' }, header: { class: '!bg-slate-900 !border-b !border-white/5 !text-white' }, content: { class: '!bg-slate-900 !p-6' }, footer: { class: '!bg-slate-900 !border-t !border-white/5 !p-4' }, closeButton: { class: '!text-slate-400 hover:!text-white' } }">
<div class="flex flex-col gap-5">
<div class="flex flex-col gap-2">
<label for="name" class="font-semibold text-slate-300">Session Name</label>
<InputText id="name" v-model="newIdea.name"
class="w-full !bg-slate-800 !border-white/10 !text-white focus:!border-violet-500"
placeholder="e.g., Cyberpunk Character Study" autofocus />
</div>
<div class="flex flex-col gap-2">
<label for="description" class="font-semibold text-slate-300">Description</label>
<Textarea id="description" v-model="newIdea.description" rows="3"
class="w-full !bg-slate-800 !border-white/10 !text-white focus:!border-violet-500"
placeholder="What are you exploring in this session?" />
</div>
</div>
<template #footer>
<div class="flex justify-end gap-2">
<Button label="Cancel" @click="showCreateDialog = false" text
class="!text-slate-400 hover:!text-white" />
<Button label="Start Session" icon="pi pi-check" @click="createIdea" :loading="submitting"
class="!bg-violet-600 hover:!bg-violet-500 !border-none" />
</div>
</template>
</Dialog>
</div>
</template>
<style scoped>
.glass-panel {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(10px);
}
</style>