Files
ti2026h/src/components/LiveView.vue
T

98 lines
1.8 KiB
Vue

<script setup lang="ts">
defineProps<{
streamUrl: string | null
isLive: boolean
error: string | null
}>()
</script>
<template>
<div class="live-view">
<div class="video-container">
<!-- Native <img> handles MJPEG (multipart/x-mixed-replace) natively — no CORS issues -->
<img
v-if="streamUrl && isLive"
:key="streamUrl"
:src="streamUrl"
alt="MJPEG Stream"
class="video-frame"
/>
<!-- Placeholder when no stream -->
<div v-else class="video-placeholder">
<span v-if="error" class="error-text">{{ error }}</span>
<span v-else>Stream not started — configure and apply a stream URL above</span>
</div>
<!-- Live indicator -->
<div v-if="isLive" class="live-badge">
<span class="live-dot"></span>
LIVE
</div>
</div>
</div>
</template>
<style scoped>
.live-view {
width: 100%;
}
.video-container {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
background: #1a1a2e;
border-radius: 8px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.video-frame {
width: 100%;
height: 100%;
object-fit: contain;
}
.video-placeholder {
color: #666;
font-size: 1.1rem;
text-align: center;
padding: 2rem;
}
.error-text {
color: #e74c3c;
}
.live-badge {
position: absolute;
top: 12px;
left: 12px;
display: flex;
align-items: center;
gap: 6px;
background: rgba(0, 0, 0, 0.65);
color: #ff4444;
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0.1em;
padding: 4px 10px;
border-radius: 4px;
}
.live-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #ff4444;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
</style>