1224 lines
No EOL
29 KiB
Vue
1224 lines
No EOL
29 KiB
Vue
<template>
|
|
<q-page class="entry-detail-page">
|
|
<div class="entry-container">
|
|
<div class="entry-header">
|
|
<!-- Image Slider -->
|
|
<div v-if="allImages.length > 0" class="image-slider-container">
|
|
<q-carousel
|
|
v-model="currentSlide"
|
|
transition-prev="slide-right"
|
|
transition-next="slide-left"
|
|
swipeable
|
|
animated
|
|
control-color="white"
|
|
navigation
|
|
arrows
|
|
class="image-carousel"
|
|
>
|
|
<q-carousel-slide
|
|
v-for="(image, index) in allImages"
|
|
:key="index"
|
|
:name="index"
|
|
class="carousel-slide"
|
|
>
|
|
<div class="image-container">
|
|
<q-img
|
|
:src="image.url"
|
|
class="slide-image"
|
|
fit="cover"
|
|
/>
|
|
<div v-if="image.caption" class="image-caption">
|
|
{{ image.caption }}
|
|
</div>
|
|
<div v-if="index === 0" class="key-image-badge">
|
|
<q-icon name="star" size="sm" />
|
|
</div>
|
|
</div>
|
|
</q-carousel-slide>
|
|
</q-carousel>
|
|
</div>
|
|
|
|
<!-- Entry Title and Meta -->
|
|
<div class="entry-meta">
|
|
<h1 class="entry-title">{{ entry.title }}</h1>
|
|
<div class="entry-subtitle" v-if="entry.subtitle">{{ entry.subtitle }}</div>
|
|
<div class="entry-date-location">
|
|
<div class="entry-date">
|
|
<q-icon name="event" size="sm" class="q-mr-sm" />
|
|
{{ formatDate(entry.date) }}
|
|
<span v-if="entry.time" class="entry-time">{{ entry.time }}</span>
|
|
</div>
|
|
<div v-if="entry.location" class="entry-location">
|
|
<q-icon name="place" size="sm" class="q-mr-sm" />
|
|
{{ entry.location }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Emotional Level Indicator -->
|
|
<div class="emotional-level">
|
|
<div class="level-label">Emotional Level:</div>
|
|
<div class="level-indicator" :class="getEmotionalLevelClass(entry.level)">
|
|
{{ getEmotionalLevelText(entry.level) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Entry Description -->
|
|
<div v-if="entry.description" class="entry-description">
|
|
<p class="description-text">{{ entry.description }}</p>
|
|
</div>
|
|
|
|
<!-- Video Recordings -->
|
|
<div v-if="entry.videoRecordings && entry.videoRecordings.length > 0" class="video-section">
|
|
<div class="video-slider-container">
|
|
<q-carousel
|
|
v-model="currentVideoSlide"
|
|
transition-prev="slide-right"
|
|
transition-next="slide-left"
|
|
swipeable
|
|
animated
|
|
control-color="grey-8"
|
|
navigation
|
|
arrows
|
|
class="video-carousel"
|
|
>
|
|
<q-carousel-slide
|
|
v-for="(video, index) in entry.videoRecordings"
|
|
:key="index"
|
|
:name="index"
|
|
class="video-carousel-slide"
|
|
>
|
|
<div class="video-container">
|
|
<div class="video-thumbnail" @click="openVideoLightbox(video, index)">
|
|
<video
|
|
:src="video.url"
|
|
:poster="getVideoPoster(video)"
|
|
class="video-preview"
|
|
muted
|
|
preload="metadata"
|
|
/>
|
|
<div class="video-play-overlay">
|
|
<q-icon name="play_circle_filled" size="4rem" color="white" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-carousel-slide>
|
|
</q-carousel>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Additional Images Gallery -->
|
|
<div v-if="additionalImagesGallery.length > 0" class="additional-images-section">
|
|
<div class="additional-images-grid">
|
|
<div
|
|
v-for="(image, index) in additionalImagesGallery"
|
|
:key="index"
|
|
class="image-tile"
|
|
@click="openImageLightbox(image, index)"
|
|
>
|
|
<q-img
|
|
:src="image.thumbnail"
|
|
class="tile-image"
|
|
fit="cover"
|
|
loading="lazy"
|
|
>
|
|
<template v-slot:error>
|
|
<div class="absolute-full flex flex-center bg-grey-3 text-grey-7">
|
|
<q-icon name="broken_image" size="24px" />
|
|
</div>
|
|
</template>
|
|
</q-img>
|
|
|
|
<!-- Favorite Star Badge -->
|
|
<div v-if="image.isFavorite" class="favorite-star-badge">
|
|
<q-icon name="star" size="20px" color="amber" />
|
|
</div>
|
|
|
|
<div class="image-tile-overlay">
|
|
<q-icon name="zoom_in" size="24px" color="white" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Audio Recordings -->
|
|
<div v-if="entry.audioRecordings && entry.audioRecordings.length > 0" class="audio-section">
|
|
<div class="audio-list">
|
|
<div
|
|
v-for="(audio, index) in entry.audioRecordings"
|
|
:key="index"
|
|
class="audio-item"
|
|
>
|
|
<q-icon name="audiotrack" size="md" color="primary" class="q-mr-md" />
|
|
<div class="audio-info">
|
|
<div class="audio-name">{{ audio.name || `Recording ${index + 1}` }}</div>
|
|
<audio :src="audio.url" controls class="audio-player">
|
|
Your browser does not support the audio element.
|
|
</audio>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Related Persons -->
|
|
<div v-if="entry.relatedPersons && entry.relatedPersons.length > 0" class="persons-section">
|
|
<h3>Related Persons</h3>
|
|
<div class="persons-list">
|
|
<div
|
|
v-for="person in entry.relatedPersons"
|
|
:key="person.id"
|
|
class="person-item"
|
|
>
|
|
<div class="person-avatar">
|
|
<q-img
|
|
v-if="person.avatar"
|
|
:src="person.avatar"
|
|
class="avatar-image"
|
|
/>
|
|
<div v-else class="avatar-initials">
|
|
{{ getInitials(person.name) }}
|
|
</div>
|
|
</div>
|
|
<div class="person-info">
|
|
<div class="person-name">{{ person.name }}</div>
|
|
<div v-if="person.relation" class="person-relation">{{ person.relation }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Categories -->
|
|
<div v-if="entry.categories && entry.categories.length > 0" class="categories-section">
|
|
<h3>Categories</h3>
|
|
<div class="categories-list">
|
|
<q-chip
|
|
v-for="category in entry.categories"
|
|
:key="category.id"
|
|
:icon="category.icon"
|
|
color="primary"
|
|
text-color="white"
|
|
class="category-chip"
|
|
>
|
|
{{ category.name }}
|
|
</q-chip>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tags -->
|
|
<div v-if="entry.tags && entry.tags.length > 0" class="tags-section">
|
|
<h3>Tags</h3>
|
|
<div class="tags-list">
|
|
<q-chip
|
|
v-for="tag in entry.tags"
|
|
:key="tag.id"
|
|
:icon="tag.icon"
|
|
color="secondary"
|
|
text-color="white"
|
|
class="tag-chip"
|
|
>
|
|
{{ tag.name }}
|
|
</q-chip>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Entry Button -->
|
|
<div class="edit-entry-section">
|
|
<q-btn
|
|
color="primary"
|
|
icon="edit"
|
|
label="Edit Entry"
|
|
size="lg"
|
|
class="edit-entry-btn"
|
|
@click="editEntry"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Video Lightbox Dialog -->
|
|
<q-dialog v-model="showVideoLightbox" maximized>
|
|
<q-card class="video-lightbox-card">
|
|
<q-card-section class="video-lightbox-header">
|
|
<q-btn icon="close" flat round dense v-close-popup @click="pauseCurrentVideo" class="close-btn" />
|
|
</q-card-section>
|
|
|
|
<q-card-section class="video-lightbox-content">
|
|
<video
|
|
v-if="currentVideo"
|
|
ref="lightboxVideo"
|
|
:src="currentVideo.url"
|
|
:poster="getVideoPoster(currentVideo)"
|
|
controls
|
|
class="lightbox-video"
|
|
@loadedmetadata="onVideoLoaded"
|
|
>
|
|
Your browser does not support the video element.
|
|
</video>
|
|
</q-card-section>
|
|
|
|
<q-card-actions v-if="entry.videoRecordings && entry.videoRecordings.length > 1" align="center">
|
|
<q-btn
|
|
icon="chevron_left"
|
|
@click="previousVideo"
|
|
:disable="currentVideoIndex === 0"
|
|
flat
|
|
round
|
|
/>
|
|
<span class="video-counter">
|
|
{{ currentVideoIndex + 1 }} / {{ entry.videoRecordings.length }}
|
|
</span>
|
|
<q-btn
|
|
icon="chevron_right"
|
|
@click="nextVideo"
|
|
:disable="currentVideoIndex === entry.videoRecordings.length - 1"
|
|
flat
|
|
round
|
|
/>
|
|
</q-card-actions>
|
|
</q-card>
|
|
</q-dialog>
|
|
|
|
<!-- Image Lightbox Dialog -->
|
|
<q-dialog v-model="showImageLightbox" maximized>
|
|
<q-card class="image-lightbox-card">
|
|
<q-card-section class="image-lightbox-header">
|
|
<q-btn icon="close" flat round dense v-close-popup class="close-btn" />
|
|
</q-card-section>
|
|
|
|
<q-card-section class="image-lightbox-content">
|
|
<q-img
|
|
v-if="currentLightboxImage"
|
|
:src="currentLightboxImage.fullSize"
|
|
class="lightbox-image"
|
|
fit="contain"
|
|
>
|
|
<template v-slot:error>
|
|
<div class="absolute-full flex flex-center bg-grey-8 text-white">
|
|
<div class="text-center">
|
|
<q-icon name="broken_image" size="48px" class="q-mb-md" />
|
|
<div>Image could not be loaded</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</q-img>
|
|
</q-card-section>
|
|
|
|
<q-card-actions v-if="additionalImagesGallery.length > 1" align="center" class="image-lightbox-actions">
|
|
<q-btn
|
|
icon="chevron_left"
|
|
@click="previousImage"
|
|
:disable="currentImageIndex === 0"
|
|
flat
|
|
round
|
|
color="white"
|
|
/>
|
|
<span class="image-counter">
|
|
{{ currentImageIndex + 1 }} / {{ additionalImagesGallery.length }}
|
|
</span>
|
|
<q-btn
|
|
icon="chevron_right"
|
|
@click="nextImage"
|
|
:disable="currentImageIndex === additionalImagesGallery.length - 1"
|
|
flat
|
|
round
|
|
color="white"
|
|
/>
|
|
</q-card-actions>
|
|
</q-card>
|
|
</q-dialog>
|
|
</q-page>
|
|
</template>
|
|
|
|
<script>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { useRoute } from 'vue-router'
|
|
|
|
export default {
|
|
name: 'EntryDetailPage',
|
|
props: {
|
|
entryData: {
|
|
type: Object,
|
|
default: null
|
|
}
|
|
},
|
|
setup(props) {
|
|
const route = useRoute()
|
|
|
|
// Carousel state
|
|
const currentSlide = ref(0)
|
|
const currentVideoSlide = ref(0)
|
|
|
|
// Video lightbox state
|
|
const showVideoLightbox = ref(false)
|
|
const currentVideoIndex = ref(0)
|
|
const lightboxVideo = ref(null)
|
|
|
|
// Image lightbox state
|
|
const showImageLightbox = ref(false)
|
|
const currentImageIndex = ref(0)
|
|
|
|
// Define available gallery images from thumbs folder
|
|
const galleryImageNames = [
|
|
'aaron-huber-RLs8LZcONCA-unsplash.jpg',
|
|
'andrew-bui-z7rzbFHXym0-unsplash.jpg',
|
|
'becca-tapert--A_Sx8GrRWg-unsplash.jpg',
|
|
'fuu-j-r2nJPbEYuSQ-unsplash.jpg',
|
|
'ian-dooley-hpTH5b6mo2s-unsplash.jpg',
|
|
'ishan-seefromthesky-TobZaa8ZwI4-unsplash.jpg',
|
|
'javier-allegue-barros-55bVEzGVnzY-unsplash.jpg',
|
|
'jay-antol-Xbf_4e7YDII-unsplash.jpg',
|
|
'jorgen-hendriksen-8qg-hy6VbYE-unsplash.jpg',
|
|
'mohamed-nohassi-odxB5oIG_iA-unsplash.jpg',
|
|
'saad-chaudhry-cYpqYxGeqts-unsplash.jpg',
|
|
'taryn-kaahanui-J5b23iaAHis-unsplash.jpg',
|
|
'tirza-van-dijk-hbwdmqcmP6k-unsplash.jpg',
|
|
]
|
|
|
|
// Mark specific images as favorites (indices 2, 5, and 9)
|
|
const favoriteImageIndices = [2, 5, 9]
|
|
|
|
// Sample entry data (for testing) - Updated with poster paths
|
|
const sampleEntry = {
|
|
id: 1,
|
|
title: "Beginn des neuen Abenteuers",
|
|
subtitle: "Ein wichtiger Meilenstein in meinem Leben",
|
|
date: "2024-10-01",
|
|
time: "14:30",
|
|
location: "München, Deutschland",
|
|
level: 2,
|
|
keyImage: "/images/familie2.png",
|
|
description: "Dies war ein wirklich wichtiger Tag für mich. Nach langer Planung und Vorbereitung konnte ich endlich mein neues Abenteuer beginnen. Es war aufregend und gleichzeitig etwas beängstigenden, aber ich wusste, dass es der richtige Schritt war. Die Erfahrungen, die ich an diesem Tag gemacht habe, werden mich noch lange begleiten.",
|
|
additionalImages: [
|
|
{ url: "/images/familie2.png", caption: "Familie beim Start" },
|
|
{ url: "/images/see.png", caption: "Der schöne Ort" },
|
|
{ url: "/images/feier.png", caption: "Kleiner Umtrunk danach" }
|
|
],
|
|
audioRecordings: [
|
|
{ name: "Gedanken zum Tag", url: "/audio/sample.mp3" },
|
|
{ name: "Gespräch mit Familie", url: "/audio/sample2.mp3" }
|
|
],
|
|
videoRecordings: [
|
|
{
|
|
name: "UHD Nature Video",
|
|
url: "/videos/3191901-uhd_3840_2160_25fps.mp4",
|
|
poster: "/videos/thumbs/3191901-uhd_3840_2160_25fps_thumb.jpg"
|
|
},
|
|
{
|
|
name: "HD Landscape Video",
|
|
url: "/videos/3326928-hd_1920_1080_24fps.mp4",
|
|
poster: "/videos/thumbs/3326928-hd_1920_1080_24fps_thumb.jpg"
|
|
}
|
|
],
|
|
relatedPersons: [
|
|
{ id: 1, name: "Maria Schmidt", relation: "Freundin", avatar: null },
|
|
{ id: 2, name: "Thomas Müller", relation: "Bruder", avatar: null }
|
|
],
|
|
categories: [
|
|
{ id: 1, name: "Familie", icon: "family_restroom" },
|
|
{ id: 2, name: "Abenteuer", icon: "explore" }
|
|
],
|
|
tags: [
|
|
{ id: 1, name: "Aufregend", icon: "emoji_emotions" },
|
|
{ id: 2, name: "Neuanfang", icon: "new_releases" },
|
|
{ id: 3, name: "Wichtig", icon: "star" }
|
|
]
|
|
}
|
|
|
|
// Use prop data or sample data
|
|
const entry = computed(() => props.entryData || sampleEntry)
|
|
|
|
// Combine key image and additional images for the slider
|
|
const allImages = computed(() => {
|
|
const images = []
|
|
|
|
// Add key image first if it exists
|
|
if (entry.value.keyImage) {
|
|
images.push({
|
|
url: entry.value.keyImage,
|
|
caption: 'Key Image'
|
|
})
|
|
}
|
|
|
|
// Add additional images
|
|
if (entry.value.additionalImages) {
|
|
images.push(...entry.value.additionalImages)
|
|
}
|
|
|
|
return images
|
|
})
|
|
|
|
// Additional images gallery - Updated to include favorite status
|
|
const additionalImagesGallery = computed(() => {
|
|
return galleryImageNames.map((imageName, index) => ({
|
|
thumbnail: `/images/thumbs/${imageName}`,
|
|
fullSize: `/images/gallery/${imageName}`,
|
|
name: imageName,
|
|
isFavorite: favoriteImageIndices.includes(index)
|
|
}))
|
|
})
|
|
|
|
// Current lightbox image
|
|
const currentLightboxImage = computed(() =>
|
|
additionalImagesGallery.value[currentImageIndex.value]
|
|
)
|
|
|
|
// Current video for lightbox
|
|
const currentVideo = computed(() =>
|
|
entry.value.videoRecordings?.[currentVideoIndex.value]
|
|
)
|
|
|
|
// Methods
|
|
const formatDate = (dateString) => {
|
|
const date = new Date(dateString)
|
|
return date.toLocaleDateString('de-DE', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
})
|
|
}
|
|
|
|
const getEmotionalLevelClass = (level) => {
|
|
if (level >= 2) return 'level-very-positive'
|
|
if (level >= 1) return 'level-positive'
|
|
if (level >= -1) return 'level-neutral'
|
|
if (level >= -2) return 'level-negative'
|
|
return 'level-very-negative'
|
|
}
|
|
|
|
const getEmotionalLevelText = (level) => {
|
|
if (level >= 2) return 'Very Positive'
|
|
if (level >= 1) return 'Positive'
|
|
if (level >= -1) return 'Neutral'
|
|
if (level >= -2) return 'Negative'
|
|
return 'Very Negative'
|
|
}
|
|
|
|
const getInitials = (name) => {
|
|
return name
|
|
.split(' ')
|
|
.map(word => word.charAt(0).toUpperCase())
|
|
.join('')
|
|
.substring(0, 2)
|
|
}
|
|
|
|
// Video lightbox methods
|
|
const openVideoLightbox = (video, index) => {
|
|
currentVideoIndex.value = index
|
|
showVideoLightbox.value = true
|
|
}
|
|
|
|
const pauseCurrentVideo = () => {
|
|
if (lightboxVideo.value) {
|
|
lightboxVideo.value.pause()
|
|
}
|
|
}
|
|
|
|
const previousVideo = () => {
|
|
if (currentVideoIndex.value > 0) {
|
|
pauseCurrentVideo()
|
|
currentVideoIndex.value--
|
|
}
|
|
}
|
|
|
|
const nextVideo = () => {
|
|
if (currentVideoIndex.value < entry.value.videoRecordings.length - 1) {
|
|
pauseCurrentVideo()
|
|
currentVideoIndex.value++
|
|
}
|
|
}
|
|
|
|
const onVideoLoaded = () => {
|
|
// Video metadata loaded, can add additional logic here if needed
|
|
}
|
|
|
|
// Image lightbox methods
|
|
const openImageLightbox = (image, index) => {
|
|
currentImageIndex.value = index
|
|
showImageLightbox.value = true
|
|
}
|
|
|
|
const previousImage = () => {
|
|
if (currentImageIndex.value > 0) {
|
|
currentImageIndex.value--
|
|
}
|
|
}
|
|
|
|
const nextImage = () => {
|
|
if (currentImageIndex.value < additionalImagesGallery.value.length - 1) {
|
|
currentImageIndex.value++
|
|
}
|
|
}
|
|
|
|
const editEntry = () => {
|
|
// TODO: Navigate to edit page or open edit modal
|
|
console.log('Edit entry:', entry.value.id)
|
|
// Example: router.push(`/edit/${entry.value.id}`)
|
|
}
|
|
|
|
// New method to get video poster/thumbnail
|
|
const getVideoPoster = (video) => {
|
|
// If video has a poster property, use it
|
|
if (video.poster) {
|
|
return video.poster
|
|
}
|
|
|
|
// Otherwise, try to generate a thumbnail path based on video filename
|
|
if (video.url) {
|
|
const videoName = video.url.split('/').pop().split('.')[0]
|
|
return `/videos/thumbs/${videoName}_thumb.jpg`
|
|
}
|
|
|
|
// Fallback to a default poster image
|
|
return '/images/video-placeholder.png'
|
|
}
|
|
|
|
onMounted(() => {
|
|
// If accessing via route, you might want to load data based on route params
|
|
const entryId = route.params.id
|
|
if (entryId && !props.entryData) {
|
|
// TODO: Load entry data from API/store based on entryId
|
|
console.log('Loading entry with ID:', entryId)
|
|
}
|
|
})
|
|
|
|
return {
|
|
entry,
|
|
allImages,
|
|
additionalImagesGallery,
|
|
favoriteImageIndices,
|
|
currentSlide,
|
|
currentVideoSlide,
|
|
showVideoLightbox,
|
|
currentVideoIndex,
|
|
currentVideo,
|
|
lightboxVideo,
|
|
showImageLightbox,
|
|
currentImageIndex,
|
|
currentLightboxImage,
|
|
formatDate,
|
|
getEmotionalLevelClass,
|
|
getEmotionalLevelText,
|
|
getInitials,
|
|
getVideoPoster,
|
|
openVideoLightbox,
|
|
pauseCurrentVideo,
|
|
previousVideo,
|
|
nextVideo,
|
|
onVideoLoaded,
|
|
openImageLightbox,
|
|
previousImage,
|
|
nextImage,
|
|
editEntry
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.entry-detail-page {
|
|
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.entry-container {
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
}
|
|
|
|
.entry-header {
|
|
background: white;
|
|
border-radius: 16px;
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
overflow: hidden;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.image-slider-container {
|
|
width: 100%;
|
|
aspect-ratio: 3/2;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.image-carousel {
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
|
|
.image-carousel .q-carousel__arrow {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
z-index: 10;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
border-radius: 50%;
|
|
width: 40px;
|
|
height: 40px;
|
|
}
|
|
|
|
.image-carousel .q-carousel__prev-arrow {
|
|
left: 16px;
|
|
}
|
|
|
|
.image-carousel .q-carousel__next-arrow {
|
|
right: 16px;
|
|
}
|
|
|
|
.carousel-slide {
|
|
padding: 0;
|
|
}
|
|
|
|
.image-container {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.slide-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.image-caption {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
|
|
color: white;
|
|
padding: 20px 16px 16px;
|
|
font-size: 0.9rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.key-image-badge {
|
|
position: absolute;
|
|
top: 12px;
|
|
left: 12px;
|
|
background: rgba(255, 215, 0, 0.9);
|
|
color: #2c3e50;
|
|
padding: 4px 8px;
|
|
border-radius: 12px;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
}
|
|
|
|
.entry-meta {
|
|
padding: 24px;
|
|
}
|
|
|
|
.entry-title {
|
|
font-size: 2rem;
|
|
font-weight: 700;
|
|
color: #2c3e50;
|
|
margin: 0 0 8px 0;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.entry-subtitle {
|
|
font-size: 1.2rem;
|
|
color: #7f8c8d;
|
|
margin-bottom: 16px;
|
|
font-style: italic;
|
|
}
|
|
|
|
.entry-date-location {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.entry-date, .entry-location {
|
|
display: flex;
|
|
align-items: center;
|
|
color: #5a6c7d;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.entry-time {
|
|
margin-left: 8px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.emotional-level {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.level-label {
|
|
font-weight: 500;
|
|
color: #2c3e50;
|
|
}
|
|
|
|
.level-indicator {
|
|
padding: 6px 12px;
|
|
border-radius: 20px;
|
|
font-weight: 600;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.level-very-positive {
|
|
background: #e8f5e8;
|
|
color: #27ae60;
|
|
}
|
|
|
|
.level-positive {
|
|
background: #f0f8e8;
|
|
color: #7cb342;
|
|
}
|
|
|
|
.level-neutral {
|
|
background: #f5f5f5;
|
|
color: #5a6c7d;
|
|
}
|
|
|
|
.level-negative {
|
|
background: #fff3e0;
|
|
color: #ef6c00;
|
|
}
|
|
|
|
.level-very-negative {
|
|
background: #ffebee;
|
|
color: #e53935;
|
|
}
|
|
|
|
.entry-description,
|
|
.audio-section,
|
|
.persons-section,
|
|
.categories-section,
|
|
.tags-section {
|
|
background: white;
|
|
border-radius: 16px;
|
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
|
padding: 24px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.entry-description h3,
|
|
.audio-section h3,
|
|
.video-section h3,
|
|
.persons-section h3,
|
|
.categories-section h3,
|
|
.tags-section h3 {
|
|
color: #2c3e50;
|
|
font-size: 1.4rem;
|
|
font-weight: 600;
|
|
margin: 0 0 16px 0;
|
|
border-bottom: 2px solid #3498db;
|
|
padding-bottom: 8px;
|
|
}
|
|
|
|
.description-text {
|
|
font-size: 1.1rem;
|
|
line-height: 1.6;
|
|
color: #34495e;
|
|
margin: 0;
|
|
}
|
|
|
|
.audio-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
}
|
|
|
|
.audio-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 16px;
|
|
background: #f8f9fa;
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.audio-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.audio-name {
|
|
font-weight: 500;
|
|
color: #2c3e50;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.audio-player {
|
|
width: 100%;
|
|
height: 40px;
|
|
}
|
|
|
|
/* Video Slider Styles */
|
|
.video-section {
|
|
background: white;
|
|
border-radius: 16px;
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
overflow: hidden;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.video-slider-container {
|
|
width: 100%;
|
|
aspect-ratio: 16/9;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.video-carousel {
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
|
|
.video-carousel .q-carousel__arrow {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
z-index: 10;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
border-radius: 50%;
|
|
width: 40px;
|
|
height: 40px;
|
|
color: white !important;
|
|
}
|
|
|
|
.video-carousel .q-carousel__prev-arrow {
|
|
left: 16px;
|
|
}
|
|
|
|
.video-carousel .q-carousel__next-arrow {
|
|
right: 16px;
|
|
}
|
|
|
|
.video-carousel .q-carousel__navigation {
|
|
position: absolute;
|
|
bottom: 16px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
z-index: 10;
|
|
}
|
|
|
|
.video-carousel .q-carousel__navigation .q-btn {
|
|
background: rgba(255, 255, 255, 0.8);
|
|
color: #424242 !important;
|
|
margin: 0 4px;
|
|
min-width: 12px;
|
|
min-height: 12px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.video-carousel-slide {
|
|
padding: 0;
|
|
}
|
|
|
|
.video-container {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.video-thumbnail {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
cursor: pointer;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.video-preview {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.video-play-overlay {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: rgba(0, 0, 0, 0.6);
|
|
border-radius: 50%;
|
|
padding: 16px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.video-play-overlay:hover {
|
|
background: rgba(0, 0, 0, 0.8);
|
|
transform: translate(-50%, -50%) scale(1.1);
|
|
}
|
|
|
|
/* Video Lightbox Styles */
|
|
.video-lightbox-card {
|
|
background: #000;
|
|
}
|
|
|
|
.video-lightbox-header {
|
|
background: transparent;
|
|
color: white;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
align-items: flex-start;
|
|
padding: 16px 24px;
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
z-index: 1001;
|
|
}
|
|
|
|
.close-btn {
|
|
background: rgba(0, 0, 0, 0.5);
|
|
color: white;
|
|
}
|
|
|
|
.video-lightbox-content {
|
|
background: #000;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 60vh;
|
|
padding: 20px;
|
|
}
|
|
|
|
.lightbox-video {
|
|
max-width: 100%;
|
|
max-height: 80vh;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.video-counter {
|
|
color: white;
|
|
font-weight: 500;
|
|
margin: 0 16px;
|
|
}
|
|
|
|
.persons-list {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 16px;
|
|
}
|
|
|
|
.person-item {
|
|
display: flex;
|
|
align-items: center;
|
|
background: #f8f9fa;
|
|
padding: 12px;
|
|
border-radius: 12px;
|
|
min-width: 200px;
|
|
}
|
|
|
|
.person-avatar {
|
|
width: 48px;
|
|
height: 48px;
|
|
border-radius: 50%;
|
|
margin-right: 12px;
|
|
overflow: hidden;
|
|
background: linear-gradient(135deg, #3498db, #2980b9);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.avatar-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.avatar-initials {
|
|
color: white;
|
|
font-weight: 600;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.person-name {
|
|
font-weight: 500;
|
|
color: #2c3e50;
|
|
}
|
|
|
|
.person-relation {
|
|
font-size: 0.9rem;
|
|
color: #7f8c8d;
|
|
}
|
|
|
|
.categories-list, .tags-list {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
}
|
|
|
|
.category-chip, .tag-chip {
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.edit-entry-section {
|
|
display: flex;
|
|
justify-content: center;
|
|
margin-top: 32px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.edit-entry-btn {
|
|
min-width: 200px;
|
|
padding: 12px 24px;
|
|
font-weight: 600;
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.edit-entry-btn:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4);
|
|
}
|
|
|
|
/* Additional Images Gallery Styles */
|
|
.additional-images-section {
|
|
background: white;
|
|
border-radius: 16px;
|
|
padding: 24px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.additional-images-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
|
gap: 16px;
|
|
}
|
|
|
|
.image-tile {
|
|
position: relative;
|
|
aspect-ratio: 1;
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.image-tile:hover {
|
|
transform: translateY(-4px);
|
|
}
|
|
|
|
.tile-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.image-tile-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0, 0, 0, 0.6);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.image-tile:hover .image-tile-overlay {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* Image Lightbox Styles */
|
|
.image-lightbox-card {
|
|
background: #000;
|
|
}
|
|
|
|
.image-lightbox-header {
|
|
background: transparent;
|
|
color: white;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
align-items: flex-start;
|
|
padding: 16px 24px;
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
z-index: 1001;
|
|
}
|
|
|
|
.image-lightbox-content {
|
|
background: #000;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 80vh;
|
|
padding: 20px;
|
|
}
|
|
|
|
.lightbox-image {
|
|
max-width: 100%;
|
|
max-height: 80vh;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.image-lightbox-actions {
|
|
background: rgba(0, 0, 0, 0.8);
|
|
color: white;
|
|
padding: 16px;
|
|
}
|
|
|
|
.image-counter {
|
|
color: white;
|
|
font-weight: 500;
|
|
margin: 0 16px;
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 600px) {
|
|
.entry-container {
|
|
padding: 12px;
|
|
}
|
|
|
|
.entry-meta {
|
|
padding: 16px;
|
|
}
|
|
|
|
.entry-title {
|
|
font-size: 1.6rem;
|
|
}
|
|
|
|
.entry-date-location {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.persons-list {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.person-item {
|
|
min-width: auto;
|
|
}
|
|
|
|
.additional-images-grid {
|
|
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
|
gap: 12px;
|
|
}
|
|
|
|
.additional-images-section {
|
|
padding: 16px;
|
|
}
|
|
}
|
|
|
|
/* Favorite Star Badge */
|
|
.favorite-star-badge {
|
|
position: absolute;
|
|
top: 8px;
|
|
right: 8px;
|
|
background: rgba(255, 255, 255, 0.9);
|
|
border-radius: 50%;
|
|
width: 32px;
|
|
height: 32px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 2;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.image-tile:hover .favorite-star-badge {
|
|
background: rgba(255, 255, 255, 1);
|
|
transform: scale(1.1);
|
|
}
|
|
</style> |