120 lines
3.4 KiB
Vue

<script setup lang="ts">
import { storeToRefs } from 'pinia';
import logoSvg from '~/public/logo/logo.svg?raw';
import { Day } from '~/src/calendar/helpers.ts';
import { loadCalendar } from '~/src/data.ts';
import { ImmutableArray } from '~/src/helpers.ts';
import { useMainStore } from '~/store/index.ts';
const props = withDefaults(defineProps<{
flag?: boolean;
forceShowFlag?: boolean;
day?: Day;
}>(), {
day: () => Day.today(),
});
const selectedDay = storeToRefs(useMainStore()).selectedDay;
const calendar = await loadCalendar();
const svg = ref(logoSvg.replace('/></svg>', 'fill="currentColor"/></svg>'));
const flagName = ref<string | null>(null);
const forceShowFlagDyn = ref(false);
const selectFlag = (): string | null => {
const events = calendar.getCurrentYear()!.eventsByDate[(selectedDay.value || props.day).toString()];
if (!events) {
return null;
}
return new ImmutableArray(...events)
.filter((e) => e.display.type === 'flag' && !e.display.name.startsWith('_'))
.sorted((a, b) => b.level - a.level)
.groupBy((e) => e.level)
.indexOrFallback(0, ['0', new ImmutableArray()])[1]
.map((e) => e.display.name)
.randomElement();
};
watch(selectedDay, () => {
forceShowFlagDyn.value = !!selectedDay.value;
// removing the flag from the selected day is deferred until the transition has finished
// so that it does not suddenly change
if (selectedDay.value !== null) {
flagName.value = selectFlag();
}
});
const resetFlagIfNotOverwritten = (): void => {
if (selectedDay.value === null) {
flagName.value = selectFlag();
}
};
</script>
<template>
<span
v-if="flag"
:class="['logo-wrapper rounded-circle d-inline-flex justify-content-center align-items-center', forceShowFlag || forceShowFlagDyn ? 'logo-flag-forced' : '', flagName ? 'logo-has-flag' : '', $attrs.class]"
:style="flagName ? `--flag: url('/flags/${flagName}.png')` : ''"
@transitionend="resetFlagIfNotOverwritten"
>
<span class="logo" v-html="svg"></span>
</span>
<span v-else :class="['logo', $attrs.class]" v-html="svg"></span>
</template>
<style lang="scss">
.logo-wrapper {
width: 1.3em;
height: 1.3em;
position: relative;
overflow: hidden;
&:before {
content: ' ';
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-image: var(--flag);
background-position: center;
background-size: cover;
background-repeat: no-repeat;
z-index: -5;
opacity: 0;
transition: all .25s ease-in-out;
}
}
.logo {
height: 1em;
width: 1em;
display: inline-block;
vertical-align: middle;
svg {
vertical-align: baseline !important;
}
}
.logo-wrapper.logo-flag-forced.logo-has-flag, a:hover .logo-wrapper.logo-has-flag {
svg path {
stroke: white;
stroke-width: 10;
}
&:before {
opacity: 1;
}
}
body[data-theme="dark"] {
.logo-wrapper.logo-flag-forced.logo-has-flag, a:hover .logo-wrapper.logo-has-flag {
svg path {
stroke: black;
}
}
}
</style>