Skip to content

Commit 6ee551c

Browse files
committed
feat: make it possible to jump to another year
closes #70
1 parent b83d48d commit 6ee551c

File tree

4 files changed

+144
-5
lines changed

4 files changed

+144
-5
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<template>
2+
<span :class="$style.container">
3+
<span :class="$style.placeholder">{{ value }}</span>
4+
<span ref="textWheelSelect" :class="[$style.textWheelSelect, { [$style.open]: showList }]">
5+
<button
6+
v-for="v of values"
7+
ref="items"
8+
:key="v"
9+
:data-value="v"
10+
type="button"
11+
:class="$style.value"
12+
@click="select(v)"
13+
>
14+
{{ v }}
15+
</button>
16+
</span>
17+
</span>
18+
</template>
19+
20+
<script lang="ts" setup generic="T extends string | number">
21+
import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
22+
import { useOutOfElementClick } from '@composables';
23+
24+
const emit = defineEmits<{
25+
change: (value: T) => void;
26+
}>();
27+
28+
const props = defineProps<{
29+
values: T[];
30+
value: T;
31+
}>();
32+
33+
const showList = ref(false);
34+
const textWheelSelect = useTemplateRef('textWheelSelect');
35+
const items = useTemplateRef('items');
36+
37+
const visibleItemsWhenOpen = computed(() => Math.min(3, props.values.length));
38+
39+
useOutOfElementClick([textWheelSelect, items], () => (showList.value = false));
40+
41+
const focusValue = () =>
42+
items.value
43+
.find((el: HTMLButtonElement) => el.dataset.value === String(props.value))
44+
?.scrollIntoView({ block: 'start' });
45+
46+
const select = (v: T) => {
47+
if (!showList.value) {
48+
showList.value = true;
49+
} else {
50+
emit('change', v);
51+
showList.value = false;
52+
}
53+
};
54+
55+
watch(() => props.value, focusValue);
56+
watch(showList, () => nextTick(focusValue));
57+
</script>
58+
59+
<style lang="scss" module>
60+
.container {
61+
display: flex;
62+
align-items: center;
63+
justify-content: center;
64+
z-index: 1;
65+
}
66+
67+
.placeholder {
68+
visibility: hidden;
69+
font-size: var(--font-size-xs);
70+
}
71+
72+
.textWheelSelect {
73+
overflow: auto;
74+
height: 22px;
75+
border-radius: var(--border-radius-l);
76+
top: 0;
77+
background: var(--c-primary);
78+
position: absolute;
79+
display: inline-grid;
80+
grid-auto-flow: row;
81+
-ms-overflow-style: none;
82+
scrollbar-width: none;
83+
84+
&.open {
85+
height: calc(22px * v-bind(visibleItemsWhenOpen));
86+
87+
.value {
88+
padding: 0 7px;
89+
}
90+
}
91+
}
92+
93+
.textWheelSelect::-webkit-scrollbar {
94+
display: none;
95+
}
96+
97+
.value {
98+
all: unset;
99+
cursor: pointer;
100+
height: 22px;
101+
padding: 0 3px;
102+
font-size: var(--font-size-xs);
103+
color: var(--c-text-light);
104+
105+
&.transition {
106+
transition: transform var(--transition-s);
107+
}
108+
}
109+
</style>

src/app/components/feature/Pane.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ useScrollShadow(header, content, 'var(--app-scroll-box-shadow)');
5656
background: var(--app-background);
5757
animation: var(--animation-fade-in-right) var(--transition-s);
5858
transition: all var(--transition-m);
59+
z-index: 1;
5960
6061
.title {
6162
display: flex;

src/app/components/feature/YearToggle.vue

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<template>
2-
<template v-if="state.years.length > 1">
2+
<span v-if="multiYear" :class="$style.toggle">
33
<Button :icon="RiArrowLeftSLine" rounded @click="rotateYear(-1)" />
4+
<TextWheelSelect :values="allYears" :value="state.activeYear" @change="changeYear" />
45
<Button :icon="RiArrowRightSLine" rounded @click="rotateYear(1)" />
5-
</template>
6+
</span>
67
<i18n-t tag="span" :keypath="keyPath" scope="global">
78
<template #year>
89
<TextWheel :values="allYears" :value="state.activeYear" />
@@ -13,6 +14,7 @@
1314
<script lang="ts" setup>
1415
import Button from '@components/base/button/Button.vue';
1516
import TextWheel from '@components/base/text-wheel/TextWheel.vue';
17+
import TextWheelSelect from '@components/base/text-wheel-select/TextWheelSelect.vue';
1618
import { RiArrowLeftSLine, RiArrowRightSLine } from '@remixicon/vue';
1719
import { useDataStore } from '@store/state';
1820
import { computed } from 'vue';
@@ -23,6 +25,7 @@ defineProps<{
2325
2426
const { state, changeYear } = useDataStore();
2527
28+
const multiYear = computed(() => state.years.length > 1);
2629
const allYears = computed(() => state.years.map((v) => v.year));
2730
2831
const rotateYear = (dir: -1 | 1) => {
@@ -33,3 +36,31 @@ const rotateYear = (dir: -1 | 1) => {
3336
changeYear(newYear);
3437
};
3538
</script>
39+
40+
<style lang="scss" module>
41+
.text {
42+
display: flex;
43+
align-items: center;
44+
gap: 4px;
45+
46+
&.multiYear {
47+
gap: 6px;
48+
}
49+
}
50+
51+
.toggle {
52+
position: relative;
53+
display: flex;
54+
align-items: center;
55+
background: var(--c-primary);
56+
border-radius: 100px;
57+
gap: 5px;
58+
filter: drop-shadow(0 0 3px rgba(black, 0.15)); // TODO: What the fuck
59+
60+
.year {
61+
all: unset;
62+
font-size: var(--font-size-xs);
63+
cursor: pointer;
64+
}
65+
}
66+
</style>

src/app/pages/dashboard/Dashboard.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
{{ t('page.dashboard.allTimeFromTo', { from: state.years[0].year, to: state.years.at(-1)?.year }) }}
88
</span>
99
</template>
10-
<template v-else>
11-
<YearToggle key-path="page.dashboard.budgetFor" />
12-
</template>
10+
<YearToggle v-else key-path="page.dashboard.budgetFor" />
1311
</template>
1412
<template #header>
1513
<div :class="$style.viewButtons">

0 commit comments

Comments
 (0)