feat(ui): [WIP] use new Ui components for user menu in sidebar

This commit is contained in:
upsiflu 2024-12-14 19:23:29 +01:00
parent adec453e83
commit 32cf6c2e3d
5 changed files with 171 additions and 20 deletions

View File

@ -5,7 +5,7 @@ import { hashCode, intToRGB } from '~/utils/color'
import { computed } from 'vue'
interface Props {
actor: Actor
actor: { full_username : string; preferred_username?:string; icon?:Actor["icon"] }
}
const props = defineProps<Props>()

View File

@ -36,6 +36,12 @@ const { width: popoverWidth, height: popoverHeight } = useElementBounding(popove
whenever(open, update, { immediate: true })
const { width: screenWidth, height: screenHeight } = useScreenSize()
// TODO (basic functionality):
// - I can't operate the popup with a keyboard. Remove barrier for people not using a mouse (A11y)
// - Switching to submenus is error-prone. When moving cursor into freshly opened submenu, it should not close if the cursor crosses another menu item
// - Large menus disappear. When menus get big, they need to scroll.
const position = computed(() => {
if (positioning === 'vertical' || isMobile.value) {
let offsetTop = top.value + height.value

View File

@ -25,3 +25,7 @@ emit('internal:id', id)
<slot name="after" />
</div>
</template>
<style scoped>
div { color:var(--fw-text-color); }
</style>

View File

@ -7,6 +7,8 @@ import { useStore } from '~/store'
import Input from '~/components/ui/Input.vue'
import Pill from '~/components/ui/Pill.vue'
import Link from '~/components/ui/Link.vue'
import ActorAvatar from '~/components/common/ActorAvatar.vue'
import UserMenu from './UserMenu.vue'
const searchQuery = ref('')
@ -57,25 +59,8 @@ const uploads = useUploadsStore()
</Transition>
</Link>
<Link to="/settings"
icon="bi-person-fill"
color="secondary"
variant="ghost"
>
<img
v-if="store.state.auth.authenticated && store.state.auth.profile?.avatar?.urls.medium_square_crop"
alt=""
:src="store.getters['instance/absoluteUrl'](store.state.auth.profile?.avatar.urls.medium_square_crop)"
>
<actor-avatar
v-else-if="store.state.auth.authenticated"
:actor="{preferred_username: store.state.auth.username, full_username: store.state.auth.username,}"
/>
<i
v-else
class="cog icon"
/>
</Link>
<UserMenu />
</nav>
<div class="search">

View File

@ -0,0 +1,156 @@
<script setup lang="ts">
import { SUPPORTED_LOCALES, setI18nLanguage } from '~/init/locale'
import { useI18n } from 'vue-i18n'
import { computed } from 'vue'
import { useStore } from '~/store'
import { useRoute } from 'vue-router'
import useThemeList from '~/composables/useThemeList'
import useTheme from '~/composables/useTheme'
import OptionsButton from '~/components/ui/button/Options.vue'
import Popover from '~/components/ui/Popover.vue'
import PopoverCheckbox from '~/components/ui/popover/PopoverCheckbox.vue'
import PopoverItem from '~/components/ui/popover/PopoverItem.vue'
import PopoverRadio from '~/components/ui/popover/PopoverRadio.vue'
import PopoverRadioItem from '~/components/ui/popover/PopoverRadioItem.vue'
import PopoverSubmenu from '~/components/ui/popover/PopoverSubmenu.vue'
interface Events {
(e: 'show:shortcuts-modal'): void
}
const route = useRoute()
const store = useStore()
const emit = defineEmits<Events>()
const { t, locale } = useI18n()
const themes = useThemeList()
const { theme } = useTheme()
const labels = computed(() => ({
profile: t('components.common.UserMenu.link.profile'),
settings: t('components.common.UserMenu.link.settings'),
logout: t('components.common.UserMenu.link.logout'),
about: t('components.common.UserMenu.link.about'),
shortcuts: t('components.common.UserMenu.label.shortcuts'),
support: t('components.common.UserMenu.link.support'),
forum: t('components.common.UserMenu.link.forum'),
docs: t('components.common.UserMenu.link.docs'),
language: t('components.common.UserMenu.label.language'),
theme: t('components.common.UserMenu.label.theme'),
chat: t('components.common.UserMenu.link.chat'),
git: t('components.common.UserMenu.link.git'),
login: t('components.common.UserMenu.link.login'),
signup: t('components.common.UserMenu.link.signup'),
notifications: t('components.common.UserMenu.link.notifications')
}))
</script>
<template>
<Popover>
<template #default="{ toggleOpen }">
<OptionsButton @click="toggleOpen">
<img
v-if="store.state.auth.authenticated && store.state.auth.profile?.avatar?.urls.medium_square_crop"
alt=""
:src="store.getters['instance/absoluteUrl'](store.state.auth.profile?.avatar.urls.medium_square_crop)"
>
<ActorAvatar
v-else-if="store.state.auth.authenticated"
:actor="{preferred_username: store.state.auth.username, full_username: store.state.auth.username,}"
/>
<i
v-else
class="cog icon"
/>
</OptionsButton>
</template>
<template #items>
<PopoverSubmenu>
<i class="bi bi-music-note-list" />
Change language
<template #items>
<PopoverItem v-for="(language, key) in SUPPORTED_LOCALES"
:key="key"
@click="setI18nLanguage(key)" >
{{ language }}
</PopoverItem>
</template>
</PopoverSubmenu>
<hr />
<PopoverItem>
<i class="bi bi-heart" />
Add to favorites
</PopoverItem>
<PopoverSubmenu>
<i class="bi bi-collection" />
Organize and share
<template #items>
<PopoverCheckbox v-model="bc">
Bandcamp
<template #after>
<Popover>
<template #default="{ toggleOpen }">
<Pill
@click.stop="toggleOpen"
:blue="bcPrivacy === 'pod'"
:red="bcPrivacy === 'public'"
>
{{ bcPrivacy }}
</Pill>
</template>
<template #items>
<PopoverRadio v-model="bcPrivacy" :choices="privacyChoices" />
</template>
</Popover>
</template>
</PopoverCheckbox>
<PopoverCheckbox v-model="cc">
Creative Commons
<template #after>
<Popover v-model:open="isOpen">
<template #default="{ toggleOpen }">
<Pill
@click="toggleOpen"
:blue="ccPrivacy === 'pod'"
:red="ccPrivacy === 'public'"
>
{{ ccPrivacy }}
</Pill>
</template>
<template #items>
<PopoverRadio v-model="ccPrivacy" :choices="privacyChoices" />
</template>
</Popover>
</template>
</PopoverCheckbox>
<hr />
<PopoverItem>
<i class="bi bi-plus-lg" />
New library
</PopoverItem>
<hr />
<PopoverCheckbox v-model="share">
Share by link
<template #after>
<Button @click.stop color="secondary" round icon="bi-link" />
<Button @click.stop color="secondary" round icon="bi-code" />
</template>
</PopoverCheckbox>
</template>
</PopoverSubmenu>
<PopoverItem>
<i class="bi bi-cloud-download" />
Download
</PopoverItem>
<hr />
<PopoverItem>
<i class="bi bi-exclamation" />
Report
</PopoverItem>
</template>
</Popover>
</template>