feat: make profile picture clickable (#1531)
Co-authored-by: Dominik Pschenitschni <mail@celement.de> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/1531 Reviewed-by: konrad <k@knt.li> Co-authored-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de> Co-committed-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
This commit is contained in:
parent
72d6701404
commit
eac07d3169
3 changed files with 72 additions and 66 deletions
|
@ -6,7 +6,7 @@ describe('Log out', () => {
|
||||||
|
|
||||||
cy.get('.navbar .user .username')
|
cy.get('.navbar .user .username')
|
||||||
.click()
|
.click()
|
||||||
cy.get('.navbar .user .dropdown-menu a.dropdown-item')
|
cy.get('.navbar .user .dropdown-menu .dropdown-item')
|
||||||
.contains('Logout')
|
.contains('Logout')
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<ready>
|
<ready>
|
||||||
<template v-if="authUser">
|
<template v-if="authUser">
|
||||||
<top-navigation/>
|
<TheNavigation/>
|
||||||
<content-auth/>
|
<content-auth/>
|
||||||
</template>
|
</template>
|
||||||
<content-link-share v-else-if="authLinkShare"/>
|
<content-link-share v-else-if="authLinkShare"/>
|
||||||
|
@ -27,7 +27,7 @@ import {success} from '@/message'
|
||||||
|
|
||||||
import Notification from '@/components/misc/notification.vue'
|
import Notification from '@/components/misc/notification.vue'
|
||||||
import KeyboardShortcuts from './components/misc/keyboard-shortcuts/index.vue'
|
import KeyboardShortcuts from './components/misc/keyboard-shortcuts/index.vue'
|
||||||
import TopNavigation from './components/home/topNavigation.vue'
|
import TheNavigation from '@/components/home/TheNavigation.vue'
|
||||||
import ContentAuth from './components/home/contentAuth.vue'
|
import ContentAuth from './components/home/contentAuth.vue'
|
||||||
import ContentLinkShare from './components/home/contentLinkShare.vue'
|
import ContentLinkShare from './components/home/contentLinkShare.vue'
|
||||||
import NoAuthWrapper from '@/components/misc/no-auth-wrapper.vue'
|
import NoAuthWrapper from '@/components/misc/no-auth-wrapper.vue'
|
||||||
|
|
|
@ -32,12 +32,13 @@
|
||||||
</a>
|
</a>
|
||||||
<notifications/>
|
<notifications/>
|
||||||
<div class="user">
|
<div class="user">
|
||||||
<img :src="userAvatar" alt="" class="avatar" width="40" height="40"/>
|
|
||||||
<dropdown class="is-right" ref="usernameDropdown">
|
<dropdown class="is-right" ref="usernameDropdown">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<x-button
|
<x-button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
:shadow="false">
|
:shadow="false"
|
||||||
|
>
|
||||||
|
<img :src="userAvatar" alt="" class="avatar" width="40" height="40"/>
|
||||||
<span class="username">{{ userInfo.name !== '' ? userInfo.name : userInfo.username }}</span>
|
<span class="username">{{ userInfo.name !== '' ? userInfo.name : userInfo.username }}</span>
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
<icon icon="chevron-down"/>
|
<icon icon="chevron-down"/>
|
||||||
|
@ -45,92 +46,96 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<router-link :to="{name: 'user.settings'}" class="dropdown-item">
|
<BaseButton
|
||||||
|
:to="{name: 'user.settings'}"
|
||||||
|
class="dropdown-item"
|
||||||
|
>
|
||||||
{{ $t('user.settings.title') }}
|
{{ $t('user.settings.title') }}
|
||||||
</router-link>
|
</BaseButton>
|
||||||
<a
|
<BaseButton
|
||||||
|
v-if="imprintUrl"
|
||||||
:href="imprintUrl"
|
:href="imprintUrl"
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
target="_blank"
|
>
|
||||||
rel="noreferrer noopener nofollow"
|
|
||||||
v-if="imprintUrl">
|
|
||||||
{{ $t('navigation.imprint') }}
|
{{ $t('navigation.imprint') }}
|
||||||
</a>
|
</BaseButton>
|
||||||
<a
|
<BaseButton
|
||||||
|
v-if="privacyPolicyUrl"
|
||||||
:href="privacyPolicyUrl"
|
:href="privacyPolicyUrl"
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
target="_blank"
|
>
|
||||||
rel="noreferrer noopener nofollow"
|
|
||||||
v-if="privacyPolicyUrl">
|
|
||||||
{{ $t('navigation.privacy') }}
|
{{ $t('navigation.privacy') }}
|
||||||
</a>
|
</BaseButton>
|
||||||
<a @click="$store.commit('keyboardShortcutsActive', true)" class="dropdown-item">
|
<BaseButton
|
||||||
|
@click="$store.commit('keyboardShortcutsActive', true)"
|
||||||
|
class="dropdown-item"
|
||||||
|
>
|
||||||
{{ $t('keyboardShortcuts.title') }}
|
{{ $t('keyboardShortcuts.title') }}
|
||||||
</a>
|
</BaseButton>
|
||||||
<router-link :to="{name: 'about'}" class="dropdown-item">
|
<BaseButton
|
||||||
|
:to="{name: 'about'}"
|
||||||
|
class="dropdown-item"
|
||||||
|
>
|
||||||
{{ $t('about.title') }}
|
{{ $t('about.title') }}
|
||||||
</router-link>
|
</BaseButton>
|
||||||
<a @click="logout()" class="dropdown-item">
|
<BaseButton
|
||||||
|
@click="logout()"
|
||||||
|
class="dropdown-item"
|
||||||
|
>
|
||||||
{{ $t('user.auth.logout') }}
|
{{ $t('user.auth.logout') }}
|
||||||
</a>
|
</BaseButton>
|
||||||
</dropdown>
|
</dropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup langs="ts">
|
||||||
import {mapState} from 'vuex'
|
import {ref, computed, onMounted, nextTick} from 'vue'
|
||||||
import {CURRENT_LIST, QUICK_ACTIONS_ACTIVE} from '@/store/mutation-types'
|
import {useStore} from 'vuex'
|
||||||
|
import {useRouter} from 'vue-router'
|
||||||
|
|
||||||
|
import {QUICK_ACTIONS_ACTIVE} from '@/store/mutation-types'
|
||||||
import Rights from '@/models/constants/rights.json'
|
import Rights from '@/models/constants/rights.json'
|
||||||
|
|
||||||
import Update from '@/components/home/update.vue'
|
import Update from '@/components/home/update.vue'
|
||||||
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
|
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
|
||||||
import Dropdown from '@/components/misc/dropdown.vue'
|
import Dropdown from '@/components/misc/dropdown.vue'
|
||||||
import Notifications from '@/components/notifications/notifications.vue'
|
import Notifications from '@/components/notifications/notifications.vue'
|
||||||
import Logo from '@/components/home/Logo.vue'
|
import Logo from '@/components/home/Logo.vue'
|
||||||
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
import MenuButton from '@/components/home/MenuButton.vue'
|
import MenuButton from '@/components/home/MenuButton.vue'
|
||||||
|
|
||||||
export default {
|
const store = useStore()
|
||||||
name: 'topNavigation',
|
|
||||||
components: {
|
|
||||||
Notifications,
|
|
||||||
Dropdown,
|
|
||||||
ListSettingsDropdown,
|
|
||||||
Update,
|
|
||||||
Logo,
|
|
||||||
MenuButton,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState({
|
|
||||||
userInfo: state => state.auth.info,
|
|
||||||
userAvatar: state => state.auth.avatarUrl,
|
|
||||||
userAuthenticated: state => state.auth.authenticated,
|
|
||||||
currentList: CURRENT_LIST,
|
|
||||||
background: 'background',
|
|
||||||
imprintUrl: state => state.config.legal.imprintUrl,
|
|
||||||
privacyPolicyUrl: state => state.config.legal.privacyPolicyUrl,
|
|
||||||
canWriteCurrentList: state => state.currentList.maxRight > Rights.READ,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (typeof this.$refs.usernameDropdown === 'undefined' || typeof this.$refs.listTitle === 'undefined') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const usernameWidth = this.$refs.usernameDropdown.$el.clientWidth
|
const userInfo = computed(() => store.state.auth.info)
|
||||||
this.$refs.listTitle.style.setProperty('--nav-username-width', `${usernameWidth}px`)
|
const userAvatar = computed(() => store.state.auth.avatarUrl)
|
||||||
})
|
const currentList = computed(() => store.state.currentList)
|
||||||
},
|
const background = computed(() => store.state.background)
|
||||||
methods: {
|
const imprintUrl = computed(() => store.state.config.legal.imprintUrl)
|
||||||
logout() {
|
const privacyPolicyUrl = computed(() => store.state.config.legal.privacyPolicyUrl)
|
||||||
this.$store.dispatch('auth/logout')
|
const canWriteCurrentList = computed(() => store.state.currentList.maxRight > Rights.READ)
|
||||||
this.$router.push({name: 'user.login'})
|
|
||||||
},
|
const usernameDropdown = ref()
|
||||||
openQuickActions() {
|
const listTitle = ref()
|
||||||
this.$store.commit(QUICK_ACTIONS_ACTIVE, true)
|
onMounted(async () => {
|
||||||
},
|
await nextTick()
|
||||||
},
|
if (typeof usernameDropdown.value === 'undefined' || typeof listTitle.value === 'undefined') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const usernameWidth = usernameDropdown.value.$el.clientWidth
|
||||||
|
listTitle.value.style.setProperty('--nav-username-width', `${usernameWidth}px`)
|
||||||
|
})
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
function logout() {
|
||||||
|
store.dispatch('auth/logout')
|
||||||
|
router.push({name: 'user.login'})
|
||||||
|
}
|
||||||
|
|
||||||
|
function openQuickActions() {
|
||||||
|
store.commit(QUICK_ACTIONS_ACTIVE, true)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -246,6 +251,7 @@ $hamburger-menu-icon-width: 28px;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
margin-right: var(--button-padding-horizontal);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.dropdown-trigger .button) {
|
:deep(.dropdown-trigger .button) {
|
Loading…
Reference in a new issue