Skip to content

Commit 295fa51

Browse files
committed
fix(reactive): move route overflow to settings dropdown
1 parent 393cced commit 295fa51

File tree

7 files changed

+134
-20
lines changed

7 files changed

+134
-20
lines changed

src/components/common/navbar/NavbarComponent.vue

+17-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { NavbarService } from '~/services/navbar.service';
1616
import { useExtensionSettingsStoreRefs } from '~/stores/settings/extension.store';
1717
import { Header } from '~/styles/layout.style';
1818
import { useI18n } from '~/utils/i18n.utils';
19+
import { watchMedia } from '~/utils/window.utils';
1920
2021
const props = defineProps({
2122
disabled: {
@@ -48,6 +49,16 @@ const navigate = (to: Route) => {
4849
4950
const { enabledRoutes } = useExtensionSettingsStoreRefs();
5051
52+
const isCompact = watchMedia('(max-width: 500px)');
53+
const isTiny = watchMedia('(max-width: 400px)');
54+
const threshold = computed(() => (isTiny.value ? 3 : 4));
55+
const visibleRoutes = computed(() =>
56+
isCompact.value ? enabledRoutes.value.slice(0, threshold.value) : enabledRoutes.value,
57+
);
58+
const overflowRoutes = computed(() =>
59+
isCompact.value ? enabledRoutes.value.slice(threshold.value) : [],
60+
);
61+
5162
const activableRoutes = computed(() => [...enabledRoutes.value, Route.Settings]);
5263
5364
const activeRoute = computed(() => {
@@ -190,7 +201,7 @@ const onTouchEnd = (e: TouchEvent) => {
190201
'--n-color-segment': 'inherit',
191202
}"
192203
>
193-
<template v-for="_route in enabledRoutes" :key="_route">
204+
<template v-for="_route in visibleRoutes" :key="_route">
194205
<NTab
195206
class="tab"
196207
:style="
@@ -214,7 +225,11 @@ const onTouchEnd = (e: TouchEvent) => {
214225
type="segment"
215226
@click="navigate(Route.Settings)"
216227
>
217-
<NavbarSettingsDropdown v-if="navElement" :parent-element="navElement" />
228+
<NavbarSettingsDropdown
229+
v-if="navElement"
230+
:parent-element="navElement"
231+
:routes="overflowRoutes"
232+
/>
218233
</NTab>
219234
</NTabs>
220235
<div

src/components/common/navbar/NavbarSettingsDopdown.vue

+33-17
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,15 @@ import { computed, defineProps, h, ref } from 'vue';
1010
import { useRouter } from 'vue-router';
1111
1212
import type { ArrayElement } from '@dvcol/common-utils/common';
13-
import type { DropdownProps } from 'naive-ui';
14-
import type { Component } from 'vue';
13+
import type { DropdownOption, DropdownProps } from 'naive-ui';
14+
import type { Component, PropType } from 'vue';
1515
1616
import IconAccount from '~/components/icons/IconAccount.vue';
1717
import IconAccountAdd from '~/components/icons/IconAccountAdd.vue';
18-
import IconCog from '~/components/icons/IconCog.vue';
1918
import IconExternalLink from '~/components/icons/IconExternalLink.vue';
20-
import IconLightBulb from '~/components/icons/IconLightBulb.vue';
2119
import IconLogOut from '~/components/icons/IconLogOut.vue';
2220
23-
import { Route } from '~/models/router.model';
21+
import { getRouteIcon, Route } from '~/models/router.model';
2422
import { Logger } from '~/services/logger.service';
2523
import { NavbarService } from '~/services/navbar.service';
2624
import { TraktService } from '~/services/trakt.service';
@@ -49,11 +47,16 @@ const onAvatarError = (event: Event) => {
4947
fallback.value = true;
5048
};
5149
52-
defineProps({
50+
const { routes } = defineProps({
5351
parentElement: {
5452
type: HTMLElement,
5553
required: true,
5654
},
55+
routes: {
56+
type: Array as PropType<Route[]>,
57+
required: false,
58+
default: () => [],
59+
},
5760
});
5861
5962
const users = computed(() => {
@@ -82,19 +85,31 @@ const toOption = (
8285
};
8386
};
8487
85-
const options = computed<DropdownProps['options']>(() => {
86-
const baseOptions: DropdownProps['options'] = [
87-
toOption('settings', IconCog),
88-
toOption('about', IconLightBulb),
88+
const { floating, reverse } = useAppStateStoreRefs();
89+
const options = computed<DropdownOption[]>(() => {
90+
const baseOptions: DropdownOption[] = [
91+
toOption(Route.Settings, getRouteIcon(Route.Settings)),
92+
toOption(Route.About, getRouteIcon(Route.About)),
8993
{ type: 'divider', key: 'external-links' },
9094
toOption('trakt', IconExternalLink),
9195
{ type: 'divider', key: 'session-divider' },
9296
toOption('login', IconAccountAdd),
9397
toOption('logout', IconLogOut),
9498
];
9599
96-
if (!users.value.length) return baseOptions;
100+
const _routes = [];
101+
if (routes?.length) {
102+
_routes.push(
103+
...routes.map(route =>
104+
toOption(route, getRouteIcon(route), i18n(route.toLowerCase(), 'route')),
105+
),
106+
);
107+
_routes.push({ type: 'divider', key: 'routes-divider' });
108+
}
109+
110+
if (!users.value.length) return [..._routes, ...baseOptions];
97111
return [
112+
..._routes,
98113
...users.value.map(([key, value]) =>
99114
toOption(
100115
`user-${key}`,
@@ -108,14 +123,14 @@ const options = computed<DropdownProps['options']>(() => {
108123
];
109124
});
110125
126+
const optionsReversed = computed(() =>
127+
reverse.value ? [...options.value].reverse() : options.value,
128+
);
129+
111130
const { loadUser, logout } = useLogout();
112131
113132
const onSelect: DropdownProps['onSelect'] = async (key: string, { label }) => {
114133
switch (key) {
115-
case 'settings':
116-
return router.push(Route.Settings);
117-
case 'about':
118-
return router.push(Route.About);
119134
case 'trakt':
120135
return createTab({
121136
url: ExternaLinks.trakt[TraktService.isStaging ? 'staging' : 'production'],
@@ -125,14 +140,15 @@ const onSelect: DropdownProps['onSelect'] = async (key: string, { label }) => {
125140
case 'logout':
126141
return logout();
127142
default:
143+
if (Object.values(Route).includes(key as Route)) return router.push(key);
128144
if (typeof label === 'string' && key.startsWith('user-')) {
129145
return loadUser(label);
130146
}
131147
Logger.error('Unknown key:', key);
132148
}
133149
};
150+
134151
const { dropdown } = NavbarService;
135-
const { floating, reverse } = useAppStateStoreRefs();
136152
const placement = computed(() => {
137153
if (reverse.value) return 'top';
138154
if (floating.value) return 'bottom';
@@ -143,7 +159,7 @@ const placement = computed(() => {
143159
<template>
144160
<NDropdown
145161
trigger="hover"
146-
:options="options"
162+
:options="optionsReversed"
147163
:to="parentElement"
148164
:placement="placement"
149165
size="small"

src/components/icons/IconSearch.vue

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<template>
2+
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
3+
<g
4+
fill="none"
5+
stroke="currentColor"
6+
stroke-linecap="round"
7+
stroke-linejoin="round"
8+
stroke-width="1.5"
9+
>
10+
<path
11+
stroke-dasharray="40"
12+
stroke-dashoffset="40"
13+
d="M10.76 13.24c-2.34 -2.34 -2.34 -6.14 0 -8.49c2.34 -2.34 6.14 -2.34 8.49 0c2.34 2.34 2.34 6.14 0 8.49c-2.34 2.34 -6.14 2.34 -8.49 0Z"
14+
>
15+
<animate
16+
fill="freeze"
17+
attributeName="stroke-dashoffset"
18+
dur="0.5s"
19+
values="40;0"
20+
/>
21+
</path>
22+
<path stroke-dasharray="12" stroke-dashoffset="12" d="M10.5 13.5l-7.5 7.5">
23+
<animate
24+
fill="freeze"
25+
attributeName="stroke-dashoffset"
26+
begin="0.5s"
27+
dur="0.2s"
28+
values="12;0"
29+
/>
30+
</path>
31+
</g>
32+
</svg>
33+
</template>

src/components/views/calendar/CalendarNavbar.vue

+4
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ const open = ref(false);
125125
.search-input {
126126
flex: 1 1 33%;
127127
min-width: 12rem;
128+
129+
@media (width < 600px) {
130+
min-width: auto;
131+
}
128132
}
129133
}
130134
</style>

src/components/views/history/HistoryNavbar.vue

+5-1
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,18 @@ const open = ref(false);
118118
min-width: 14rem;
119119
120120
@media (width < 600px) {
121-
flex: 1 0 9rem;
121+
flex: 1 0 7rem;
122122
min-width: auto;
123123
}
124124
}
125125
126126
.search-input {
127127
flex: 2 1 calc(46% - 5rem);
128128
min-width: 12rem;
129+
130+
@media (width < 600px) {
131+
min-width: auto;
132+
}
129133
}
130134
}
131135
</style>

src/components/views/watchlist/WatchlistNavbar.vue

+4
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ const renderTag = ({ option }: { option: SelectOption }) => option.label?.toStri
176176
.search-input {
177177
flex: 1 1 auto;
178178
min-width: 12rem;
179+
180+
@media (width < 600px) {
181+
min-width: auto;
182+
}
179183
}
180184
}
181185
</style>

src/models/router.model.ts

+38
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
import type { Component } from 'vue';
2+
3+
import IconCalendar from '~/components/icons/IconCalendar.vue';
4+
import IconClipboard from '~/components/icons/IconClipboard.vue';
5+
import IconCog from '~/components/icons/IconCog.vue';
6+
import IconExternalLinkRounded from '~/components/icons/IconExternalLinkRounded.vue';
7+
import IconLightBulb from '~/components/icons/IconLightBulb.vue';
8+
import IconList from '~/components/icons/IconList.vue';
9+
import IconLogIn from '~/components/icons/IconLogIn.vue';
10+
import IconMovie from '~/components/icons/IconMovie.vue';
11+
import IconRestore from '~/components/icons/IconRestore.vue';
12+
import IconSearch from '~/components/icons/IconSearch.vue';
13+
114
export const RouterStorageKey = {
215
LastRoute: 'app.state.last-route',
316
} as const;
@@ -13,3 +26,28 @@ export enum Route {
1326
About = 'about',
1427
Login = 'login',
1528
}
29+
30+
export const getRouteIcon = (route: Route): Component => {
31+
switch (route) {
32+
case Route.Progress:
33+
return IconClipboard;
34+
case Route.Calendar:
35+
return IconCalendar;
36+
case Route.Releases:
37+
return IconMovie;
38+
case Route.History:
39+
return IconRestore;
40+
case Route.Watchlist:
41+
return IconList;
42+
case Route.Search:
43+
return IconSearch;
44+
case Route.Settings:
45+
return IconCog;
46+
case Route.About:
47+
return IconLightBulb;
48+
case Route.Login:
49+
return IconLogIn;
50+
default:
51+
return IconExternalLinkRounded;
52+
}
53+
};

0 commit comments

Comments
 (0)