147 lines
3.4 KiB
Vue
147 lines
3.4 KiB
Vue
<script setup lang="ts">
|
|
import type { Node } from "~/types"
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
node: Node
|
|
showTrips?: boolean
|
|
}>(),
|
|
{
|
|
showTrips: true,
|
|
},
|
|
)
|
|
|
|
defineEmits<{
|
|
create: [name: string]
|
|
routeTime: [node: Node]
|
|
routePlace: [node: Node]
|
|
}>()
|
|
|
|
const children = computed(() => childrenOf(props.node))
|
|
const undated = computed(() => undatedChildren(children.value))
|
|
const groups = computed(() => groupChildren(children.value))
|
|
const datedCount = computed(() =>
|
|
groups.value.reduce((a, g) => a + g.events.length, 0),
|
|
)
|
|
</script>
|
|
|
|
<template>
|
|
<section class="children-view">
|
|
<CreateRow
|
|
:placeholder="
|
|
node.root
|
|
? $t('voyage.addRow.placeholder')
|
|
: $t('voyage.addRow.placeholderSub')
|
|
"
|
|
@create="$emit('create', $event)"
|
|
/>
|
|
|
|
<EmptyState
|
|
v-if="children.length === 0"
|
|
icon="carbon:tree-view-alt"
|
|
:message="$t('voyage.emptyChildren')"
|
|
/>
|
|
|
|
<div v-if="undated.length" class="undated">
|
|
<SectionLabel icon="carbon:calendar-heat-map" :count="undated.length">
|
|
{{ $t("voyage.sansDate.label") }}
|
|
</SectionLabel>
|
|
<EtapeCard
|
|
v-for="ev in undated"
|
|
:key="ev.id"
|
|
:node="ev"
|
|
@route-time="$emit('routeTime', $event)"
|
|
@route-place="$emit('routePlace', $event)"
|
|
/>
|
|
</div>
|
|
|
|
<div v-if="groups.length" class="programme">
|
|
<SectionLabel icon="carbon:roadmap" :count="datedCount">
|
|
{{ $t("voyage.frise.programme") }}
|
|
</SectionLabel>
|
|
<div
|
|
v-for="(group, gi) in groups"
|
|
:key="group.label || gi"
|
|
class="day-group"
|
|
>
|
|
<DayDivider v-if="group.label" :label="group.label" />
|
|
<template v-for="(ev, i) in group.events" :key="ev.id">
|
|
<EtapeCard
|
|
:node="ev"
|
|
@route-time="$emit('routeTime', $event)"
|
|
@route-place="$emit('routePlace', $event)"
|
|
/>
|
|
<template v-if="i < group.events.length - 1">
|
|
<div v-if="showTrips" class="trip-connector">
|
|
<span
|
|
class="trip-connector__line"
|
|
:style="{
|
|
borderTopColor: ev.trip ? 'var(--color-6)' : 'var(--neutral-30)',
|
|
}"
|
|
/>
|
|
<TripChip v-if="ev.trip" :trip="ev.trip" />
|
|
<span v-else class="trip-connector__none">
|
|
{{ $t("voyage.frise.noTrip") }}
|
|
</span>
|
|
<span
|
|
class="trip-connector__line"
|
|
:style="{
|
|
borderTopColor: ev.trip ? 'var(--color-6)' : 'var(--neutral-30)',
|
|
}"
|
|
/>
|
|
</div>
|
|
<div v-else class="trip-spacer" />
|
|
</template>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.children-view {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
}
|
|
|
|
.undated {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 7px;
|
|
}
|
|
|
|
.programme {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.day-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.trip-connector {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.trip-connector__line {
|
|
width: 18px;
|
|
border-top: 2px dashed var(--neutral-30);
|
|
}
|
|
|
|
.trip-connector__none {
|
|
font-family: var(--font-body);
|
|
font-size: 0.7rem;
|
|
color: var(--text-faint);
|
|
}
|
|
|
|
.trip-spacer {
|
|
height: 2px;
|
|
}
|
|
</style>
|