20-02-2026

This commit is contained in:
Kevin Adametz 2026-02-20 17:56:18 +01:00
parent c62234e1ca
commit 98084de7d0
80 changed files with 9804 additions and 1771 deletions

View file

@ -0,0 +1,110 @@
<template>
<div
class="glow-dot"
:class="{
'glow-dot--ghost': isGhost,
'glow-dot--selected': selected,
'glow-dot--dimmed': isDimmed
}"
:style="dotStyle"
@click.stop="onSelect"
>
<!-- White inner circle shader provides the glow -->
<div class="glow-dot__inner">
<img
v-if="event.image"
:src="event.image"
class="glow-dot__image"
alt=""
/>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { useEventsStore } from 'stores/events'
import { useSettingsStore } from 'stores/settings'
const props = defineProps({
event: { type: Object, required: true },
x: { type: Number, default: 0 },
isGhost: { type: Boolean, default: false },
selected: { type: Boolean, default: false }
})
const emit = defineEmits(['select'])
const eventsStore = useEventsStore()
const settingsStore = useSettingsStore()
// Match shader circle: CSS diameter = 2 * circleRadiusPx / dpr
const dpr = Math.min(window.devicePixelRatio || 1, 2)
const dotSize = computed(() => {
return 2 * settingsStore.floatingLines.circleRadius / dpr
})
// Y position: emotion +1 top (15%), 0 middle (50%), -1 bottom (85%)
const yPercent = computed(() => {
return 50 - props.event.emotion * 35
})
const dotStyle = computed(() => ({
left: `${props.x}px`,
top: `${yPercent.value}%`,
width: `${dotSize.value}px`,
height: `${dotSize.value}px`
}))
const isDimmed = computed(() => {
return eventsStore.selectedEventId !== null && !props.selected && !props.isGhost
})
function onSelect() {
if (!props.isGhost) {
emit('select')
}
}
</script>
<style scoped>
.glow-dot {
position: absolute;
transform: translate(-50%, -50%);
cursor: pointer;
z-index: 10;
transition: opacity 0.3s ease, transform 0.15s ease;
}
/* Clean inner circle — shader provides the glow around it */
.glow-dot__inner {
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
background: #fff;
overflow: hidden;
}
.glow-dot__image {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* States */
.glow-dot--ghost {
opacity: 0.7;
cursor: default;
}
.glow-dot--selected {
transform: translate(-50%, -50%) scale(1.15);
z-index: 15;
}
.glow-dot--dimmed {
opacity: 0.5;
}
</style>