Skip to content

Commit 1603796

Browse files
authored
feat: implement overlay scrollbar for app sidebar (#5820)
* feat: implement overlay scrollbar for app sidebar * pnpm prepr
1 parent 7c9a9f2 commit 1603796

8 files changed

Lines changed: 77 additions & 19 deletions

File tree

apps/app-frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"fuse.js": "^6.6.2",
3636
"intl-messageformat": "^10.7.7",
3737
"ofetch": "^1.3.4",
38+
"overlayscrollbars": "^2.15.1",
3839
"pinia": "^3.0.0",
3940
"posthog-js": "^1.158.2",
4041
"three": "^0.172.0",

apps/app-frontend/src/App.vue

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,13 @@ loading.startLoading()
428428
429429
let suspensePending = false
430430
431+
const sidebarOverlayScrollbarsOptions = Object.freeze({
432+
overflow: {
433+
x: 'hidden',
434+
y: 'scroll',
435+
},
436+
})
437+
431438
router.beforeEach(() => {
432439
suspensePending = false
433440
loading.startLoading()
@@ -1279,29 +1286,26 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
12791286
</RouterView>
12801287
</div>
12811288
<div
1282-
class="app-sidebar mt-px shrink-0 flex flex-col border-0 border-l-[1px] border-[--brand-gradient-border] border-solid overflow-auto"
1289+
v-overlay-scrollbars="sidebarOverlayScrollbarsOptions"
1290+
class="app-sidebar mt-px shrink-0 flex flex-col border-0 border-l-[1px] border-[--brand-gradient-border] border-solid"
12831291
:class="{ 'has-plus': hasPlus }"
1292+
data-overlayscrollbars-initialize
12841293
>
1285-
<div
1286-
class="app-sidebar-scrollable flex-grow shrink overflow-y-auto relative"
1287-
:class="{ 'pb-12': !hasPlus }"
1288-
>
1294+
<div class="app-sidebar-scrollable flex-grow shrink relative" :class="{ 'pb-12': !hasPlus }">
12891295
<div id="sidebar-teleport-target" class="sidebar-teleport-content"></div>
12901296
<div class="sidebar-default-content" :class="{ 'sidebar-enabled': sidebarVisible }">
1291-
<div
1292-
class="p-4 pr-1 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid"
1293-
>
1297+
<div class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
12941298
<h3 class="text-base text-primary font-medium m-0">Playing as</h3>
12951299
<suspense>
12961300
<AccountsCard ref="accounts" mode="small" />
12971301
</suspense>
12981302
</div>
1299-
<div class="py-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
1303+
<div class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
13001304
<suspense>
13011305
<FriendsList :credentials="credentials" :sign-in="() => signIn()" />
13021306
</suspense>
13031307
</div>
1304-
<div v-if="news && news.length > 0" class="p-4 pr-1 flex flex-col items-center">
1308+
<div v-if="news && news.length > 0" class="p-4 flex flex-col items-center">
13051309
<h3 class="text-base mb-4 text-primary font-medium m-0 text-left w-full">News</h3>
13061310
<div class="space-y-4 flex flex-col items-center w-full">
13071311
<NewsArticleCard
@@ -1649,6 +1653,13 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
16491653
}
16501654
</style>
16511655
<style>
1656+
.os-theme-dark,
1657+
.os-theme-light {
1658+
--os-handle-bg: var(--color-scrollbar) !important;
1659+
--os-handle-bg-hover: var(--color-scrollbar) !important;
1660+
--os-handle-bg-active: var(--color-scrollbar) !important;
1661+
}
1662+
16521663
.mac {
16531664
.app-grid-statusbar {
16541665
padding-left: 5rem;

apps/app-frontend/src/components/ui/friends/FriendsList.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ const messages = defineMessages({
288288
</div>
289289
</div>
290290
</ModalWrapper>
291-
<div v-if="userCredentials && !loading" class="flex gap-1 items-center mb-3 ml-2 mr-1">
291+
<div v-if="userCredentials && !loading" class="flex gap-1 items-center mb-3 -ml-1">
292292
<template v-if="sortedFriends.length > 0">
293293
<ButtonStyled circular type="transparent">
294294
<button
@@ -309,7 +309,7 @@ const messages = defineMessages({
309309
@keyup.esc="search = ''"
310310
/>
311311
</template>
312-
<h3 v-else class="ml-2 w-full text-base text-primary font-medium m-0">
312+
<h3 v-else class="w-full text-base text-primary font-medium m-0">
313313
{{ formatMessage(messages.friends) }}
314314
</h3>
315315
<ButtonStyled v-if="incomingRequests.length > 0" circular type="transparent">
@@ -331,11 +331,11 @@ const messages = defineMessages({
331331
</ButtonStyled>
332332
</div>
333333
<div class="flex flex-col gap-3">
334-
<h3 v-if="loading" class="ml-4 mr-1 text-base text-primary font-medium m-0">
334+
<h3 v-if="loading" class="text-base text-primary font-medium m-0">
335335
{{ formatMessage(messages.friends) }}
336336
</h3>
337337
<template v-if="loading">
338-
<div v-for="n in 5" :key="n" class="flex gap-2 items-center animate-pulse ml-4 mr-1">
338+
<div v-for="n in 5" :key="n" class="flex gap-2 items-center animate-pulse">
339339
<div class="min-w-9 min-h-9 bg-button-bg rounded-full"></div>
340340
<div class="flex flex-col w-full">
341341
<div class="h-3 bg-button-bg rounded-full w-1/2 mb-1"></div>
@@ -344,7 +344,7 @@ const messages = defineMessages({
344344
</div>
345345
</template>
346346
<template v-else-if="sortedFriends.length === 0">
347-
<div class="text-sm ml-4 mr-1">
347+
<div class="text-sm">
348348
<div v-if="!userCredentials">
349349
<IntlFormatted :message-id="messages.signInToAddFriends">
350350
<template #link="{ children }">

apps/app-frontend/src/components/ui/friends/FriendsSection.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ const messages = defineMessages({
106106
:open-by-default="openByDefault"
107107
:force-open="isSearching"
108108
:button-class="
109-
'pl-4 pr-3 flex w-full items-center bg-transparent border-0 p-0' +
109+
'flex w-full items-center bg-transparent border-0 p-0' +
110110
(isSearching
111111
? ''
112112
: ' cursor-pointer hover:brightness-[--hover-brightness] active:scale-[0.98] transition-all')
@@ -122,7 +122,7 @@ const messages = defineMessages({
122122
<div
123123
v-for="friend in friends"
124124
:key="friend.username"
125-
class="group grid items-center grid-cols-[auto_1fr_auto] gap-2 hover:bg-button-bg transition-colors rounded-full ml-4 mr-1"
125+
class="group grid items-center grid-cols-[auto_1fr_auto] gap-2 hover:bg-button-bg transition-colors rounded-full mr-1"
126126
@contextmenu.prevent.stop="
127127
(event) => friendOptions?.showMenu(event, friend, createContextMenuOptions(friend))
128128
"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { OverlayScrollbars, type PartialOptions } from 'overlayscrollbars'
2+
import type { ObjectDirective } from 'vue'
3+
4+
const defaultOverlayScrollbarsOptions = Object.freeze<PartialOptions>({
5+
scrollbars: {
6+
theme: 'os-theme-dark',
7+
autoHide: 'leave',
8+
autoHideSuspend: true,
9+
},
10+
})
11+
12+
const mergeOptions = (options: PartialOptions = {}): PartialOptions => ({
13+
...defaultOverlayScrollbarsOptions,
14+
...options,
15+
scrollbars: {
16+
...defaultOverlayScrollbarsOptions.scrollbars,
17+
...(options.scrollbars ?? {}),
18+
},
19+
})
20+
21+
export const overlayScrollbarsDirective: ObjectDirective<HTMLElement, PartialOptions | undefined> =
22+
{
23+
mounted(el, binding) {
24+
OverlayScrollbars(el, mergeOptions(binding.value))
25+
},
26+
updated(el, binding) {
27+
if (binding.value === binding.oldValue) return
28+
const instance = OverlayScrollbars(el)
29+
instance?.options(mergeOptions(binding.value))
30+
},
31+
unmounted(el) {
32+
const instance = OverlayScrollbars(el)
33+
instance?.destroy()
34+
},
35+
}

apps/app-frontend/src/main.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'floating-vue/dist/style.css'
2+
import 'overlayscrollbars/overlayscrollbars.css'
23

34
import * as Sentry from '@sentry/vue'
45
import { VueScanPlugin } from '@taijased/vue-render-tracker'
@@ -8,6 +9,7 @@ import { createPinia } from 'pinia'
89
import { createApp } from 'vue'
910

1011
import App from '@/App.vue'
12+
import { overlayScrollbarsDirective } from '@/directives/overlayScrollbars'
1113
import i18nPlugin from '@/plugins/i18n'
1214
import i18nDebugPlugin from '@/plugins/i18n-debug'
1315
import router from '@/routes'
@@ -50,5 +52,6 @@ app.use(FloatingVue, {
5052
})
5153
app.use(i18nPlugin)
5254
app.use(i18nDebugPlugin)
55+
app.directive('overlay-scrollbars', overlayScrollbarsDirective)
5356

5457
app.mount('#app')

packages/assets/generated-icons.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import type { FunctionalComponent, SVGAttributes } from 'vue'
55

6+
export type IconComponent = FunctionalComponent<SVGAttributes>
7+
68
import _AffiliateIcon from './icons/affiliate.svg?component'
79
import _AlignLeftIcon from './icons/align-left.svg?component'
810
import _ArchiveIcon from './icons/archive.svg?component'
@@ -392,8 +394,6 @@ import _XCircleIcon from './icons/x-circle.svg?component'
392394
import _ZoomInIcon from './icons/zoom-in.svg?component'
393395
import _ZoomOutIcon from './icons/zoom-out.svg?component'
394396

395-
export type IconComponent = FunctionalComponent<SVGAttributes>
396-
397397
export const AffiliateIcon = _AffiliateIcon
398398
export const AlignLeftIcon = _AlignLeftIcon
399399
export const ArchiveIcon = _ArchiveIcon

pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)