diff options
Diffstat (limited to 'core/src/views/Profile.vue')
-rw-r--r-- | core/src/views/Profile.vue | 604 |
1 files changed, 0 insertions, 604 deletions
diff --git a/core/src/views/Profile.vue b/core/src/views/Profile.vue deleted file mode 100644 index c7571fff148..00000000000 --- a/core/src/views/Profile.vue +++ /dev/null @@ -1,604 +0,0 @@ -<!-- - - @copyright Copyright (c) 2021 Christopher Ng <chrng8@gmail.com> - - - - @author Christopher Ng <chrng8@gmail.com> - - @author Julius Härtl <jus@bitgrid.net> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - This program is distributed in the hope that it will be useful, - - but WITHOUT ANY WARRANTY; without even the implied warranty of - - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - - GNU Affero General Public License for more details. - - - - You should have received a copy of the GNU Affero General Public License - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> - -<template> - <div class="profile"> - <div class="profile__header"> - <div class="profile__header__container"> - <div class="profile__header__container__placeholder" /> - <h2 class="profile__header__container__displayname"> - {{ displayname || userId }} - <a v-if="isCurrentUser" - class="primary profile__header__container__edit-button" - :href="settingsUrl"> - <PencilIcon class="pencil-icon" - :size="16" /> - {{ t('core', 'Edit Profile') }} - </a> - </h2> - <div v-if="status.icon || status.message" - class="profile__header__container__status-text" - :class="{ interactive: isCurrentUser }" - @click.prevent.stop="openStatusModal"> - {{ status.icon }} {{ status.message }} - </div> - </div> - </div> - - <div class="profile__wrapper"> - <div class="profile__content"> - <div class="profile__sidebar"> - <NcAvatar class="avatar" - :class="{ interactive: isCurrentUser }" - :user="userId" - :size="180" - :show-user-status="true" - :show-user-status-compact="false" - :disable-menu="true" - :disable-tooltip="true" - :is-no-user="!isUserAvatarVisible" - @click.native.prevent.stop="openStatusModal" /> - - <div class="user-actions"> - <!-- When a tel: URL is opened with target="_blank", a blank new tab is opened which is inconsistent with the handling of other URLs so we set target="_self" for the phone action --> - <PrimaryActionButton v-if="primaryAction" - class="user-actions__primary" - :href="primaryAction.target" - :icon="primaryAction.icon" - :target="primaryAction.id === 'phone' ? '_self' :'_blank'"> - {{ primaryAction.title }} - </PrimaryActionButton> - <div class="user-actions__other"> - <!-- FIXME Remove inline styles after https://github.com/nextcloud/nextcloud-vue/issues/2315 is fixed --> - <NcActions v-for="action in middleActions" - :key="action.id" - :default-icon="action.icon" - style=" - background-position: 14px center; - background-size: 16px; - background-repeat: no-repeat;" - :style="{ - backgroundImage: `url(${action.icon})`, - ...(colorMainBackground === '#181818' && { filter: 'invert(1)' }) - }"> - <NcActionLink :close-after-click="true" - :icon="action.icon" - :href="action.target" - :target="action.id === 'phone' ? '_self' :'_blank'"> - {{ action.title }} - </NcActionLink> - </NcActions> - <template v-if="otherActions"> - <NcActions :force-menu="true"> - <NcActionLink v-for="action in otherActions" - :key="action.id" - :class="{ 'icon-invert': colorMainBackground === '#181818' }" - :close-after-click="true" - :icon="action.icon" - :href="action.target" - :target="action.id === 'phone' ? '_self' :'_blank'"> - {{ action.title }} - </NcActionLink> - </NcActions> - </template> - </div> - </div> - </div> - - <div class="profile__blocks"> - <div v-if="organisation || role || address" class="profile__blocks-details"> - <div v-if="organisation || role" class="detail"> - <p>{{ organisation }} <span v-if="organisation && role">•</span> {{ role }}</p> - </div> - <div v-if="address" class="detail"> - <p> - <MapMarkerIcon class="map-icon" - :size="16" /> - {{ address }} - </p> - </div> - </div> - <template v-if="headline || biography || sections.length > 0"> - <div v-if="headline" class="profile__blocks-headline"> - <h3>{{ headline }}</h3> - </div> - <div v-if="biography" class="profile__blocks-biography"> - <p>{{ biography }}</p> - </div> - - <!-- additional entries, use it with cautious --> - <div v-for="(section, index) in sections" - :ref="'section-' + index" - :key="index" - class="profile__additionalContent"> - <component :is="section($refs['section-'+index], userId)" :userId="userId" /> - </div> - </template> - <template v-else> - <div class="profile__blocks-empty-info"> - <AccountIcon :size="60" - fill-color="var(--color-text-maxcontrast)" /> - <h3>{{ emptyProfileMessage }}</h3> - <p>{{ t('core', 'The headline and about sections will show up here') }}</p> - </div> - </template> - </div> - </div> - </div> - </div> -</template> - -<script> -import { getCurrentUser } from '@nextcloud/auth' -import { subscribe, unsubscribe } from '@nextcloud/event-bus' -import { loadState } from '@nextcloud/initial-state' -import { generateUrl } from '@nextcloud/router' -import { showError } from '@nextcloud/dialogs' - -import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar' -import NcActions from '@nextcloud/vue/dist/Components/NcActions' -import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink' -import MapMarkerIcon from 'vue-material-design-icons/MapMarker' -import PencilIcon from 'vue-material-design-icons/Pencil' -import AccountIcon from 'vue-material-design-icons/Account' - -import PrimaryActionButton from '../components/Profile/PrimaryActionButton' - -const status = loadState('core', 'status', {}) -const { - userId, - displayname, - address, - organisation, - role, - headline, - biography, - actions, - isUserAvatarVisible, -} = loadState('core', 'profileParameters', { - userId: null, - displayname: null, - address: null, - organisation: null, - role: null, - headline: null, - biography: null, - actions: [], - isUserAvatarVisible: false, -}) - -export default { - name: 'Profile', - - components: { - AccountIcon, - NcActionLink, - NcActions, - NcAvatar, - MapMarkerIcon, - PencilIcon, - PrimaryActionButton, - }, - - data() { - return { - status, - userId, - displayname, - address, - organisation, - role, - headline, - biography, - actions, - isUserAvatarVisible, - sections: OCA.Core.ProfileSections.getSections(), - } - }, - - computed: { - isCurrentUser() { - return getCurrentUser()?.uid === this.userId - }, - - allActions() { - return this.actions - }, - - primaryAction() { - if (this.allActions.length) { - return this.allActions[0] - } - return null - }, - - middleActions() { - if (this.allActions.slice(1, 4).length) { - return this.allActions.slice(1, 4) - } - return null - }, - - otherActions() { - if (this.allActions.slice(4).length) { - return this.allActions.slice(4) - } - return null - }, - - settingsUrl() { - return generateUrl('/settings/user') - }, - - colorMainBackground() { - // For some reason the returned string has prepended whitespace - return getComputedStyle(document.body).getPropertyValue('--color-main-background').trim() - }, - - emptyProfileMessage() { - return this.isCurrentUser - ? t('core', 'You have not added any info yet') - : t('core', '{user} has not added any info yet', { user: (this.displayname || this.userId) }) - }, - }, - - mounted() { - // Set the user's displayname or userId in the page title and preserve the default title of "Nextcloud" at the end - document.title = `${this.displayname || this.userId} - ${document.title}` - subscribe('user_status:status.updated', this.handleStatusUpdate) - }, - - beforeDestroy() { - unsubscribe('user_status:status.updated', this.handleStatusUpdate) - }, - - methods: { - handleStatusUpdate(status) { - if (this.isCurrentUser && status.userId === this.userId) { - this.status = status - } - }, - - openStatusModal() { - const statusMenuItem = document.querySelector('.user-status-menu-item__toggle') - // Changing the user status is only enabled if you are the current user - if (this.isCurrentUser) { - if (statusMenuItem) { - statusMenuItem.click() - } else { - showError(t('core', 'Error opening the user status modal, try hard refreshing the page')) - } - } - }, - }, -} -</script> - -<style lang="scss"> -// Override header styles -#header { - background-color: transparent !important; - background-image: none !important; -} - -#content { - padding-top: 0px; -} -</style> - -<style lang="scss" scoped> -$profile-max-width: 1024px; -$content-max-width: 640px; - -.profile { - width: 100%; - overflow-y: auto; - - &__header { - position: sticky; - height: 190px; - top: -40px; - background-color: var(--color-main-background-blur); - backdrop-filter: var(--filter-background-blur); - -webkit-backdrop-filter: var(--filter-background-blur); - - &__container { - align-self: flex-end; - width: 100%; - max-width: $profile-max-width; - margin: 0 auto; - display: grid; - grid-template-rows: max-content max-content; - grid-template-columns: 240px 1fr; - justify-content: center; - - &__placeholder { - grid-row: 1 / 3; - } - - &__displayname, &__status-text { - color: var(--color-main-text); - } - - &__displayname { - width: $content-max-width; - height: 45px; - margin-top: 128px; - // Override the global style declaration - margin-bottom: 0; - font-size: 30px; - display: flex; - align-items: center; - cursor: text; - - &:not(:last-child) { - margin-top: 100px; - margin-bottom: 4px; - } - } - - &__edit-button { - border: none; - margin-left: 18px; - margin-top: 2px; - color: var(--color-primary-element); - background-color: var(--color-primary-text); - box-shadow: 0 0 0 2px var(--color-primary-text); - border-radius: var(--border-radius-pill); - padding: 0 18px; - font-size: var(--default-font-size); - height: 44px; - line-height: 44px; - font-weight: bold; - - &:hover, - &:focus, - &:active { - color: var(--color-primary-element); - background-color: var(--color-primary-element-light); - } - - .pencil-icon { - display: inline-block; - vertical-align: middle; - margin-top: 2px; - } - } - - &__status-text { - width: max-content; - max-width: $content-max-width; - padding: 5px 10px; - margin-left: -12px; - margin-top: 2px; - - &.interactive { - cursor: pointer; - - &:hover, - &:focus, - &:active { - background-color: var(--color-main-background); - color: var(--color-main-text); - border-radius: var(--border-radius-pill); - font-weight: bold; - box-shadow: 0 3px 6px var(--color-box-shadow); - } - } - } - } - } - - &__sidebar { - position: sticky; - top: var(--header-height); - align-self: flex-start; - padding-top: 20px; - min-width: 220px; - margin: -150px 20px 0 0; - - // Specificity hack is needed to override Avatar component styles - &::v-deep .avatar.avatardiv, h2 { - text-align: center; - margin: auto; - display: block; - padding: 8px; - } - - &::v-deep .avatar.avatardiv:not(.avatardiv--unknown) { - background-color: var(--color-main-background) !important; - box-shadow: none; - } - - &::v-deep .avatar.avatardiv { - .avatardiv__user-status { - right: 14px; - bottom: 14px; - width: 34px; - height: 34px; - background-size: 28px; - border: none; - // Styles when custom status icon and status text are set - background-color: var(--color-main-background); - line-height: 34px; - font-size: 20px; - } - } - - &::v-deep .avatar.interactive.avatardiv { - .avatardiv__user-status { - cursor: pointer; - - &:hover, - &:focus, - &:active { - box-shadow: 0 3px 6px var(--color-box-shadow); - } - } - } - } - - &__wrapper { - background-color: var(--color-main-background); - min-height: 100%; - } - - &__content { - max-width: $profile-max-width; - margin: 0 auto; - display: flex; - width: 100%; - } - - &__blocks { - margin: 18px 0 80px 0; - display: grid; - gap: 16px 0; - width: $content-max-width; - - p, h3 { - overflow-wrap: anywhere; - } - - &-details { - display: flex; - flex-direction: column; - gap: 2px 0; - - .detail { - display: inline-block; - color: var(--color-text-maxcontrast); - - p .map-icon { - display: inline-block; - vertical-align: middle; - } - } - } - - &-headline { - margin-top: 10px; - - h3 { - font-weight: bold; - font-size: 20px; - margin: 0; - } - } - - &-biography { - white-space: pre-line; - } - - h3, p { - cursor: text; - } - - &-empty-info { - margin-top: 80px; - margin-right: 100px; - display: flex; - flex-direction: column; - text-align: center; - - h3 { - font-weight: bold; - font-size: 18px; - margin: 8px 0; - } - } - } -} - -@media only screen and (max-width: 1024px) { - .profile { - &__header { - height: 250px; - position: unset; - - &__container { - grid-template-columns: unset; - - &__displayname { - margin: 100px 20px 0px; - width: unset; - display: unset; - text-align: center; - } - - &__edit-button { - width: fit-content; - display: block; - margin: 30px auto; - } - } - } - - &__content { - display: block; - } - - &__blocks { - width: unset; - max-width: 600px; - margin: 0 auto; - padding: 20px 50px 50px 50px; - - &-empty-info { - margin: 0; - } - } - - &__sidebar { - margin: unset; - position: unset; - } - } -} - -.user-actions { - display: flex; - flex-direction: column; - gap: 8px 0; - margin-top: 20px; - - &__primary { - margin: 0 auto; - } - - &__other { - display: flex; - justify-content: center; - gap: 0 4px; - a { - filter: var(--background-invert-if-dark); - } - } -} - -.icon-invert { - &::v-deep .action-link__icon { - filter: invert(1); - } -} -</style> |