Spaces:
Sleeping
Sleeping
| <template> | |
| <div class="step-selection [ stack ]" data-composition="step-container"> | |
| <div v-if="!storiesStore.currentStory" class="[ selection-placeholder ] [ d-flex flex-column align-center justify-center w-full ]" data-state="empty"> | |
| <!-- Centered Header Block --> | |
| <div class="text-center mb-10"> | |
| <h2 class="text-step-title mb-2">ÉTAPE 1 : CHOISISSEZ UNE HISTOIRE</h2> | |
| <p class="text-red font-bold">Sélectionnez un projet existant ou créez-en un nouveau pour commencer.</p> | |
| </div> | |
| <!-- Modular Card with Strict Sizing --> | |
| <div class="empty-card [ d-flex flex-column align-center justify-center pa-10 ]" style="width: 100%; max-width: 540px"> | |
| <div class="text-xl font-black text-white mb-4 tracking-widest"> | |
| NO STORY SELECTED | |
| </div> | |
| <p class="text-muted text-center mb-8" style="font-size: 0.85rem; max-width: 300px"> | |
| Choose a story from the sidebar or create a new project to begin your dark media production. | |
| </p> | |
| <Button | |
| label="+ NEW STORY" | |
| @click="showCreateModal = true" | |
| severity="danger" | |
| class="w-full p-button-lg font-black no-glow" | |
| /> | |
| </div> | |
| </div> | |
| <div v-else class="[ story-details ] [ stack ]" data-state="selected" style="gap: 1.5rem"> | |
| <div class="selected-story-hero [ flex-column ]" style="padding: 2rem; border-radius: 12px; gap: 1.5rem"> | |
| <div class="flex justify-between items-start"> | |
| <div class="flex-column" style="gap: 1.5rem"> | |
| <div class="flex-column" style="gap: 0.5rem"> | |
| <span class="text-tiny uppercase font-black text-red" style="letter-spacing: 0.15rem">Histoire sélectionnée</span> | |
| <h3 class="selected-title">{{ storiesStore.currentStory.title.value }}</h3> | |
| </div> | |
| <div class="cluster"> | |
| <span class="category-tag">{{ storiesStore.currentStory.category || 'Général' }}</span> | |
| <span class="text-tiny text-muted uppercase font-bold tracking-widest ml-4">Statut: Actif / Édition</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="action-area [ pt-6 ]" style="border-top: 1px solid rgba(255,255,255,0.05)"> | |
| <Button label="CONTINUER VERS LES VISUELS" icon="pi pi-arrow-right" iconPos="right" @click="nextStep" severity="danger" class="p-button-lg font-black no-glow" /> | |
| </div> | |
| </div> | |
| <!-- Media Gallery Integration --> | |
| <div v-if="storiesStore.isAssetsLoading" class="[ d-flex flex-column align-center pa-12 ]"> | |
| <ProgressSpinner style="width: 40px; height: 40px" strokeWidth="4" /> | |
| <span class="text-tiny uppercase text-muted mt-4 tracking-widest">Chargement des médias...</span> | |
| </div> | |
| <MediaGallery v-else :assets="storiesStore.currentAssets" /> | |
| </div> | |
| <!-- PrimeVue Dialog for Creation --> | |
| <Dialog v-model:visible="showCreateModal" modal header="Nouvelle Histoire" :style="{ width: '400px' }"> | |
| <div class="stack" data-stack-gap="small" style="margin-top: 10px"> | |
| <label class="property-label">Titre de l'histoire</label> | |
| <InputText v-model="newStoryTitle" placeholder="Ex: Le Manoir des Brumes" @keyup.enter="handleCreate" style="width: 100%" autofocus /> | |
| <small v-if="error" class="p-error">{{ error }}</small> | |
| </div> | |
| <template #footer> | |
| <Button label="ANNULER" icon="pi pi-times" @click="showCreateModal = false" text severity="secondary" /> | |
| <Button label="CRÉER" icon="pi pi-check" @click="handleCreate" :loading="isSubmitting" severity="primary" /> | |
| </template> | |
| </Dialog> | |
| </div> | |
| </template> | |
| <script setup lang="ts"> | |
| import { ref } from 'vue'; | |
| import { useStoriesStore, useUIStore } from '@presentation/stores'; | |
| import Button from 'primevue/button'; | |
| import Card from 'primevue/card'; | |
| import InputText from 'primevue/inputtext'; | |
| import Dialog from 'primevue/dialog'; | |
| import ProgressSpinner from 'primevue/progressspinner'; | |
| import MediaGallery from '../ui/MediaGallery.vue'; | |
| const storiesStore = useStoriesStore(); | |
| const uiStore = useUIStore(); | |
| const showCreateModal = ref(false); | |
| const newStoryTitle = ref(''); | |
| const isSubmitting = ref(false); | |
| const error = ref(''); | |
| const nextStep = () => { | |
| uiStore.setStep(2); | |
| }; | |
| const handleCreate = async () => { | |
| if (newStoryTitle.value.length < 3) { | |
| error.value = 'Le titre doit faire au moins 3 caractères'; | |
| return; | |
| } | |
| isSubmitting.value = true; | |
| error.value = ''; | |
| try { | |
| await storiesStore.createStory(newStoryTitle.value); | |
| showCreateModal.value = false; | |
| newStoryTitle.value = ''; | |
| } catch (err: any) { | |
| error.value = err.message || 'Erreur lors de la création'; | |
| } finally { | |
| isSubmitting.value = false; | |
| } | |
| }; | |
| </script> | |
| <style scoped> | |
| /* Block Styles (CUBE CSS - Block Layer) */ | |
| .step-selection { | |
| padding: 1.5rem 2.5rem 6rem 2.5rem; | |
| flex: 1; | |
| width: 100%; | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .selection-placeholder { | |
| flex: 1; | |
| animation: fadeIn 0.5s ease-out; | |
| } | |
| .empty-card { | |
| border: 1px dashed #cc0000; | |
| background: rgba(204, 0, 0, 0.05); | |
| border-radius: 12px; | |
| transition: all 0.3s ease; | |
| } | |
| .empty-card:hover { | |
| background: rgba(204, 0, 0, 0.1); | |
| transform: none; | |
| box-shadow: 0 0 30px rgba(204, 0, 0, 0.1); | |
| } | |
| .text-step-title { | |
| font-size: 2.5rem; | |
| font-weight: 900; | |
| letter-spacing: -0.02em; | |
| color: #fff ; | |
| text-transform: uppercase; | |
| } | |
| .no-glow { | |
| box-shadow: none ; | |
| } | |
| .p-button.p-button-danger { | |
| background: #cc0000 ; | |
| border-color: #cc0000 ; | |
| } | |
| .selected-title { | |
| font-size: 4rem; | |
| font-weight: 900; | |
| color: #fff; | |
| margin: 0; | |
| letter-spacing: -0.03em; | |
| line-height: 0.9; | |
| text-shadow: 0 0 30px rgba(204, 0, 0, 0.2); | |
| } | |
| .category-tag { | |
| background: rgba(204, 0, 0, 0.15); | |
| border: 1px solid rgba(204, 0, 0, 0.3); | |
| color: var(--accent-red-bright); | |
| padding: 6px 16px; | |
| border-radius: 99px; | |
| font-size: 0.65rem; | |
| font-weight: 900; | |
| text-transform: uppercase; | |
| letter-spacing: 0.2rem; | |
| box-shadow: 0 0 15px rgba(204, 0, 0, 0.1); | |
| } | |
| .selected-story-hero { | |
| border: 1px solid rgba(255, 255, 255, 0.05); | |
| background: linear-gradient(135deg, rgba(20, 20, 20, 0.9) 0%, rgba(5, 5, 5, 0.95) 100%); | |
| box-shadow: 0 30px 60px rgba(0, 0, 0, 0.6); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .selected-story-hero::after { | |
| content: ''; | |
| position: absolute; | |
| top: -50%; | |
| right: -20%; | |
| width: 300px; | |
| height: 300px; | |
| background: radial-gradient(circle, rgba(204, 0, 0, 0.05) 0%, transparent 70%); | |
| pointer-events: none; | |
| } | |
| /* Composition & Utilities */ | |
| .stack { | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: flex-start; | |
| } | |
| .stack[data-stack-gap="tiny"] { gap: 4px; } | |
| .stack[data-stack-gap="small"] { gap: 12px; } | |
| .stack[data-stack-gap="large"] { gap: 32px; } | |
| .action-area :deep(.p-button) { | |
| padding: 1.25rem 2.5rem; | |
| font-size: 1rem; | |
| border-radius: 12px; | |
| } | |
| .cluster { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: var(--gutter, 12px); | |
| align-items: center; | |
| } | |
| .justify-center { justify-content: center; } | |
| .flex { display: flex; } | |
| .items-center { align-items: center; } | |
| .justify-between { justify-content: space-between; } | |
| .mb-4 { margin-bottom: 1rem; } | |
| .mt-4 { margin-top: 1rem; } | |
| .pt-4 { padding-top: 1rem; } | |
| .badge { | |
| padding: 2px 8px; | |
| border-radius: 999px; | |
| font-size: 0.7rem; | |
| font-weight: 700; | |
| text-transform: uppercase; | |
| background: var(--border-color); | |
| } | |
| .text-xl { font-size: 1.25rem; font-weight: 700; } | |
| .text-center { text-align: center; } | |
| </style> | |