feat: account switcher sidebar (#460)

* feat: account switcher sidebar

* fix: defer loading sidebar until masto initialised

* fix: only show user switcher for 2 or more accounts

* chore: use `ofetch` (newer version of `ohymfetch`)

* chore: early alpha warning

* fix: handle missing user in github preview

* refactor: avoid circular auto-import

Co-authored-by: Daniel Roe <daniel@roe.dev>
This commit is contained in:
patak 2022-12-19 16:44:14 +01:00 committed by GitHub
parent 15b59ae9b9
commit cd85871d01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 78 additions and 25 deletions

View file

@ -24,6 +24,12 @@ const featureFlags = useFeatureFlags()
> >
{{ $t('feature_flag.github_cards') }} {{ $t('feature_flag.github_cards') }}
</CommonDropdownItem> </CommonDropdownItem>
<CommonDropdownItem
:checked="featureFlags.experimentalUserSwitcherSidebar"
@click="toggleFeatureFlag('experimentalUserSwitcherSidebar')"
>
{{ $t('feature_flag.user_switcher_sidebar') }}
</CommonDropdownItem>
</template> </template>
</CommonDropdown> </CommonDropdown>
</template> </template>

View file

@ -0,0 +1,30 @@
<script setup lang="ts">
import type { UserLogin } from '~/types'
const all = useUsers()
const router = useRouter()
const switchUser = (user: UserLogin) => {
if (user.account.id === currentUser.value?.account.id)
router.push(getAccountRoute(user.account))
else
loginTo(user)
}
</script>
<template>
<div flex="~ col" pb8 px4 gap-6 w-20 h-full justify-end>
<template v-for="user of all" :key="user.id">
<button
flex rounded
cursor-pointer
aria-label="Switch user"
:class="user.account.id === currentUser?.account.id ? '' : 'grayscale'"
hover:filter-none
@click="switchUser(user)"
>
<AccountAvatar w-12 h-12 :account="user.account" :hover-card="false" />
</button>
</template>
</div>
</template>

View file

@ -4,6 +4,7 @@ export interface FeatureFlags {
experimentalVirtualScroll: boolean experimentalVirtualScroll: boolean
experimentalAvatarOnAvatar: boolean experimentalAvatarOnAvatar: boolean
experimentalGitHubCards: boolean experimentalGitHubCards: boolean
experimentalUserSwitcherSidebar: boolean
} }
export type FeatureFlagsMap = Record<string, FeatureFlags> export type FeatureFlagsMap = Record<string, FeatureFlags>
@ -12,6 +13,7 @@ export function getDefaultFeatureFlags(): FeatureFlags {
experimentalVirtualScroll: false, experimentalVirtualScroll: false,
experimentalAvatarOnAvatar: true, experimentalAvatarOnAvatar: true,
experimentalGitHubCards: true, experimentalGitHubCards: true,
experimentalUserSwitcherSidebar: true,
} }
} }
@ -31,3 +33,6 @@ export function toggleFeatureFlag(key: keyof FeatureFlags) {
else else
featureFlags[key] = true featureFlags[key] = true
} }
const userSwitcherSidebar = eagerComputed(() => useFeatureFlags().experimentalUserSwitcherSidebar)
export const showUserSwitcherSidebar = computed(() => useUsers().value.length > 1 && userSwitcherSidebar.value)

View file

@ -1,31 +1,19 @@
<template> <template>
<div h-full :class="{ zen: isZenMode }"> <div h-full :class="{ zen: isZenMode }">
<main flex w-full mxa lg:max-w-80rem> <div v-if="isMastoInitialised" v-show="showUserSwitcherSidebar" fixed h-full hidden md:block bg-code border-r-1 border-base>
<UserPicker />
</div>
<main flex w-full mxa lg:max-w-80rem :class="isMastoInitialised && showUserSwitcherSidebar ? 'md:pl-20' : ''">
<aside class="hidden md:block w-1/4 zen-hide" relative> <aside class="hidden md:block w-1/4 zen-hide" relative>
<div sticky top-0 h-screen flex="~ col"> <div sticky top-0 h-screen flex="~ col">
<slot name="left"> <slot name="left">
<NavTitle mx3 mt4 mb2 self-start /> <NavTitle mx3 mt4 mb2 self-start />
<div flex="~ col" overflow-y-auto> <div flex="~ col" overflow-y-auto justify-between h-full>
<div flex flex-col>
<NavSide /> <NavSide />
<PublishButton v-if="isMastoInitialised && currentUser" m5 /> <PublishButton v-if="isMastoInitialised && currentUser" m5 />
<div flex-auto />
</div> </div>
</slot> <div flex flex-col>
</div>
</aside>
<div class="w-full mb14 md:(w-3/4 mb0) lg:(w-2/4 mb0) min-h-screen" border="none md:l md:r base">
<div min-h-screen>
<slot />
</div>
<div sticky left-0 right-0 bottom-0 z-10 bg-base pb="[env(safe-area-inset-bottom)]" transition="padding 20">
<CommonOfflineChecker :small-screen="isHydrated && isSmallScreen" />
<NavBottom v-if="isHydrated && isSmallScreen" />
</div>
</div>
<aside class="hidden md:none lg:block w-1/4 zen-hide">
<div sticky top-0 h-screen flex="~ col">
<slot name="right">
<SearchWidget v-if="isMastoInitialised" />
<UserSignInEntry v-if="isMastoInitialised && !currentUser" /> <UserSignInEntry v-if="isMastoInitialised && !currentUser" />
<div v-if="isMastoInitialised && currentUser" py6 px4 w-full flex="~" items-center justify-between> <div v-if="isMastoInitialised && currentUser" py6 px4 w-full flex="~" items-center justify-between>
<NuxtLink <NuxtLink
@ -44,7 +32,24 @@
</template> </template>
</VDropdown> </VDropdown>
</div> </div>
</div>
</div>
</slot>
</div>
</aside>
<div class="w-full mb14 md:(w-3/4 mb0) lg:(w-2/4 mb0) min-h-screen" border="none md:l md:r base">
<div min-h-screen>
<slot />
</div>
<div sticky left-0 right-0 bottom-0 z-10 bg-base pb="[env(safe-area-inset-bottom)]" transition="padding 20">
<CommonOfflineChecker :small-screen="isHydrated && isSmallScreen" />
<NavBottom v-if="isHydrated && isSmallScreen" />
</div>
</div>
<aside class="hidden md:none lg:block w-1/4 zen-hide">
<div sticky top-0 h-screen flex="~ col" py3>
<slot name="right">
<SearchWidget v-if="isMastoInitialised" />
<div flex-auto /> <div flex-auto />
<NavFooter /> <NavFooter />
</slot> </slot>

View file

@ -82,6 +82,7 @@
"feature_flag": { "feature_flag": {
"avatar_on_avatar": "Avatar on Avatar", "avatar_on_avatar": "Avatar on Avatar",
"github_cards": "GitHub Cards", "github_cards": "GitHub Cards",
"user_switcher_sidebar": "User Switcher Sidebar",
"virtual_scroll": "Virtual Scrolling" "virtual_scroll": "Virtual Scrolling"
}, },
"help": { "help": {

View file

@ -58,6 +58,7 @@
}, },
"feature_flag": { "feature_flag": {
"github_cards": "GitHub Cards", "github_cards": "GitHub Cards",
"user_switcher_sidebar": "User Switcher Sidebar",
"virtual_scroll": "Virtuelles Scrollen" "virtual_scroll": "Virtuelles Scrollen"
}, },
"menu": { "menu": {

View file

@ -86,6 +86,7 @@
"feature_flag": { "feature_flag": {
"avatar_on_avatar": "Avatar on Avatar", "avatar_on_avatar": "Avatar on Avatar",
"github_cards": "GitHub Cards", "github_cards": "GitHub Cards",
"user_switcher_sidebar": "User Switcher Sidebar",
"virtual_scroll": "Virtual Scrolling" "virtual_scroll": "Virtual Scrolling"
}, },
"help": { "help": {

View file

@ -83,6 +83,7 @@
"feature_flag": { "feature_flag": {
"avatar_on_avatar": "Avatar en Avatar", "avatar_on_avatar": "Avatar en Avatar",
"github_cards": "GitHub Cards", "github_cards": "GitHub Cards",
"user_switcher_sidebar": "User Switcher Sidebar",
"virtual_scroll": "Virtual Scrolling" "virtual_scroll": "Virtual Scrolling"
}, },
"help": { "help": {

View file

@ -86,6 +86,7 @@
"feature_flag": { "feature_flag": {
"avatar_on_avatar": "Avatar sur avatar", "avatar_on_avatar": "Avatar sur avatar",
"github_cards": "GitHub Cards", "github_cards": "GitHub Cards",
"user_switcher_sidebar": "User Switcher Sidebar",
"virtual_scroll": "Défilement virtuel" "virtual_scroll": "Défilement virtuel"
}, },
"help": { "help": {

View file

@ -33,6 +33,7 @@
}, },
"feature_flag": { "feature_flag": {
"github_cards": "GitHub Cards", "github_cards": "GitHub Cards",
"user_switcher_sidebar": "User Switcher Sidebar",
"virtual_scroll": "仮想スクロール" "virtual_scroll": "仮想スクロール"
}, },
"menu": { "menu": {

View file

@ -85,6 +85,7 @@
"feature_flag": { "feature_flag": {
"avatar_on_avatar": "头像堆叠", "avatar_on_avatar": "头像堆叠",
"github_cards": "GitHub Cards", "github_cards": "GitHub Cards",
"user_switcher_sidebar": "User Switcher Sidebar",
"virtual_scroll": "虚拟滚动" "virtual_scroll": "虚拟滚动"
}, },
"help": { "help": {