fix(webapp): mobile optimization (#8516)

* - optimized header
- added possibility of extra mobile logo

* - changed behavior of NotificationMenu link get directly open for mobile

* - moved notification links to the top of the menu

* - optimized chat view for mobile

* - added logo branding structure

* - added logo branding structure

* - fixed chat height

* - fixed paddings for internal pages

* Fix linting

* Fix linting

---------

Co-authored-by: Sebastian Stein <sebastian@codepassion.de>
Co-authored-by: Wolfgang Huß <wolle.huss@pjannto.com>
This commit is contained in:
sebastian2357 2025-05-09 19:04:06 +02:00 committed by GitHub
parent ca5b1fa0b5
commit ff366a4075
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 177 additions and 59 deletions

View File

@ -1,10 +1,3 @@
// this file is duplicated in `backend/src/config/logos` and `webapp/constants/logos.js` and replaced on rebranding
// this file is duplicated in `backend/src/config/logos.ts` and `webapp/constants/logos.js` and replaced on rebranding
// this are the paths in the webapp
export default {
LOGO_HEADER_PATH: '/img/custom/logo-horizontal.svg',
LOGO_SIGNUP_PATH: '/img/custom/logo-squared.svg',
LOGO_WELCOME_PATH: '/img/custom/logo-squared.svg',
LOGO_LOGOUT_PATH: '/img/custom/logo-squared.svg',
LOGO_PASSWORD_RESET_PATH: '/img/custom/logo-squared.svg',
LOGO_MAINTENACE_RESET_PATH: '/img/custom/logo-squared.svg',
}
export default {}

View File

@ -0,0 +1,32 @@
// this file is duplicated in `backend/src/config/logos.ts` and `webapp/constants/logos.js` and replaced on rebranding
// this are the paths in the webapp
import { merge } from 'lodash'
import logos from '@config/logos'
const defaultLogos = {
LOGO_HEADER_PATH: '/img/custom/logo-horizontal.svg',
LOGO_HEADER_MOBILE_PATH: '/img/custom/logo-horizontal.svg',
LOGO_HEADER_WIDTH: '130px',
LOGO_HEADER_MOBILE_WIDTH: '100px',
LOGO_HEADER_CLICK: {
// externalLink: {
// url: 'https://ocelot.social',
// target: '_blank',
// },
externalLink: null,
internalPath: {
to: {
name: 'index',
},
scrollTo: '.main-navigation',
},
},
LOGO_SIGNUP_PATH: '/img/custom/logo-squared.svg',
LOGO_WELCOME_PATH: '/img/custom/logo-squared.svg',
LOGO_LOGOUT_PATH: '/img/custom/logo-squared.svg',
LOGO_PASSWORD_RESET_PATH: '/img/custom/logo-squared.svg',
LOGO_MAINTENACE_RESET_PATH: '/img/custom/logo-squared.svg',
}
export default merge(defaultLogos, logos)

View File

@ -11,7 +11,7 @@ import { createTransport } from 'nodemailer'
// import type Email as EmailType from '@types/email-templates'
import CONFIG, { nodemailerTransportOptions } from '@config/index'
import logosWebapp from '@config/logos'
import logosWebapp from '@config/logosBranded'
import metadata from '@config/metadata'
import { UserDbProperties } from '@db/types/User'

View File

@ -17,6 +17,7 @@
:loading-rooms="loadingRooms"
show-files="false"
show-audio="false"
:height="'calc(100dvh - 190px)'"
:styles="JSON.stringify(computedChatStyle)"
:show-footer="true"
:responsive-breakpoint="responsiveBreakpoint"

View File

@ -136,12 +136,12 @@
<ds-flex-item class="mobile-hamburger-menu">
<client-only>
<!-- chat menu -->
<div style="display: inline-flex">
<div>
<chat-notification-menu />
</div>
<!-- notification menu -->
<div style="display: inline-flex; padding-right: clamp(10px, 2.5vw, 20px)">
<notification-menu />
<div>
<notification-menu no-menu />
</div>
</client-only>
<!-- hamburger menu -->
@ -284,7 +284,7 @@ import { mapGetters } from 'vuex'
import isEmpty from 'lodash/isEmpty'
import { SHOW_GROUP_BUTTON_IN_HEADER } from '~/constants/groups.js'
import { SHOW_CONTENT_FILTER_HEADER_MENU } from '~/constants/filter.js'
import LOGOS from '~/constants/logos.js'
import LOGOS from '~/constants/logosBranded.js'
import AvatarMenu from '~/components/AvatarMenu/AvatarMenu'
import ChatNotificationMenu from '~/components/ChatNotificationMenu/ChatNotificationMenu'
import CustomButton from '~/components/CustomButton/CustomButton'
@ -409,6 +409,25 @@ export default {
flex-flow: row nowrap;
align-items: center;
justify-content: flex-end;
& > div {
display: inline-flex;
padding-right: 15px;
&:first-child {
padding-right: 10px;
}
button {
overflow: visible;
.svg {
height: 1.8em;
}
}
}
.hamburger-button .svg {
height: 1.5em;
}
}
.mobile-menu {
margin: 0 20px;

View File

@ -1,29 +1,30 @@
<template>
<component :is="tag" class="ds-logo" :class="[inverse && 'ds-logo-inverse']">
<!-- Desktop logo -->
<img
v-if="!inverse"
class="ds-logo-svg"
class="ds-logo-svg ds-logo-desktop"
:alt="metadata.APPLICATION_NAME + ' ' + logo.alt"
:src="logo.path"
:style="logoWidthStyle"
/>
<!-- Mobile logo (falls back to desktop if not provided) -->
<img
v-else
class="ds-logo-svg"
:alt="metadata.APPLICATION_NAME + ' ' + logo.alt"
:src="logo.path"
:style="logoWidthStyle"
class="ds-logo-svg ds-logo-mobile"
:alt="metadata.APPLICATION_NAME + ' ' + logo.alt + ' Mobile'"
:src="logo.mobilePath || logo.path"
:style="mobileLogoWidthStyle"
/>
</component>
</template>
<script>
import logos from '~/constants/logos.js'
import logos from '~/constants/logosBranded.js'
import metadata from '~/constants/metadata.js'
/**
* This component displays the brand's logo.
* @version 1.0.0
* @version 1.1.0
*/
export default {
name: 'Logo',
@ -42,6 +43,13 @@ export default {
type: String,
default: null,
},
/**
* Mobile logo width
*/
mobileLogoWidth: {
type: String,
default: null,
},
/**
* Inverse the logo
*/
@ -61,8 +69,10 @@ export default {
const logosObject = {
header: {
path: logos.LOGO_HEADER_PATH,
mobilePath: logos.LOGO_HEADER_MOBILE_PATH || null,
alt: 'Header',
widthDefault: logos.LOGO_HEADER_WIDTH,
mobileWidthDefault: logos.LOGO_HEADER_MOBILE_WIDTH || logos.LOGO_HEADER_WIDTH,
},
welcome: { path: logos.LOGO_WELCOME_PATH, alt: 'Welcome', widthDefault: '200px' },
signup: { path: logos.LOGO_SIGNUP_PATH, alt: 'Sign Up', widthDefault: '200px' },
@ -85,12 +95,12 @@ export default {
},
computed: {
logoWidthStyle() {
let width = ''
if (this.logoWidth === null) {
width = this.logo.widthDefault
} else {
width = this.logoWidth
}
const width = this.logoWidth === null ? this.logo.widthDefault : this.logoWidth
return `width: ${width};`
},
mobileLogoWidthStyle() {
const width =
this.mobileLogoWidth === null ? this.logo.mobileWidthDefault : this.mobileLogoWidth
return `width: ${width};`
},
},
@ -115,6 +125,25 @@ export default {
fill: #000000;
max-width: 100%;
}
/* Show desktop logo by default and hide mobile logo */
.ds-logo-desktop {
display: block;
}
.ds-logo-mobile {
display: none;
}
@media (max-width: 767px) {
.ds-logo-desktop {
display: none;
}
.ds-logo-mobile {
display: block;
}
}
</style>
<docs src="./demo.md"></docs>

View File

@ -14,6 +14,18 @@
}"
/>
</nuxt-link>
<nuxt-link v-else-if="noMenu" class="notifications-menu" :to="{ name: 'notifications' }">
<base-button
ghost
circle
v-tooltip="{
content: $t('header.notifications.tooltip'),
placement: 'bottom-start',
}"
>
<counter-icon icon="bell" :count="unreadNotificationsCount" danger />
</base-button>
</nuxt-link>
<dropdown v-else class="notifications-menu" offset="8" :placement="placement">
<template #default="{ toggleMenu }">
<base-button
@ -29,9 +41,6 @@
</base-button>
</template>
<template #popover="{ closeMenu }">
<div class="notifications-menu-popover">
<notification-list :notifications="notifications" @markAsRead="markAsRead" />
</div>
<ds-flex class="notifications-link-container">
<ds-flex-item class="notifications-link-container-item" :width="{ base: '100%' }" centered>
<nuxt-link :to="{ name: 'notifications' }">
@ -51,6 +60,9 @@
</base-button>
</ds-flex-item>
</ds-flex>
<div class="notifications-menu-popover">
<notification-list :notifications="notifications" @markAsRead="markAsRead" />
</div>
</template>
</dropdown>
</template>
@ -82,6 +94,7 @@ export default {
},
props: {
placement: { type: String },
noMenu: { type: Boolean, default: false },
},
methods: {
async markAsRead(notificationSourceId) {

View File

@ -32,3 +32,16 @@ export default {
},
}
</script>
<style lang="scss" scoped>
@media only screen and (max-width: 500px) {
.ds-container {
padding-left: 0 !important;
padding-right: 0 !important;
.base-card {
padding: 16px !important;
}
}
}
</style>

View File

@ -1,6 +1,6 @@
import { storiesOf } from '@storybook/vue'
import helpers from '~/storybook/helpers'
import logos from '~/constants/logos.js'
import logos from '~/constants/logosBranded.js'
import BaseCard from './BaseCard.vue'
storiesOf('Generic/BaseCard', module)

View File

@ -1,24 +1,3 @@
// this file is duplicated in `backend/src/config/logos.js` and `webapp/constants/logos.js` and replaced on rebranding
// this are the paths in the webapp
export default {
LOGO_HEADER_PATH: '/img/custom/logo-horizontal.svg',
LOGO_HEADER_WIDTH: '130px',
LOGO_HEADER_CLICK: {
// externalLink: {
// url: 'https://ocelot.social',
// target: '_blank',
// },
externalLink: null,
internalPath: {
to: {
name: 'index',
},
scrollTo: '.main-navigation',
},
},
LOGO_SIGNUP_PATH: '/img/custom/logo-squared.svg',
LOGO_WELCOME_PATH: '/img/custom/logo-squared.svg',
LOGO_LOGOUT_PATH: '/img/custom/logo-squared.svg',
LOGO_PASSWORD_RESET_PATH: '/img/custom/logo-squared.svg',
LOGO_MAINTENACE_RESET_PATH: '/img/custom/logo-squared.svg',
}
export default {}

View File

@ -0,0 +1,31 @@
// this file is duplicated in `backend/src/config/logos.js` and `webapp/constants/logos.js` and replaced on rebranding
// this are the paths in the webapp
import { merge } from 'lodash'
import logos from '~/constants/logos'
const defaultLogos = {
LOGO_HEADER_PATH: '/img/custom/logo-horizontal.svg',
LOGO_HEADER_MOBILE_PATH: '/img/custom/logo-horizontal.svg',
LOGO_HEADER_WIDTH: '130px',
LOGO_HEADER_MOBILE_WIDTH: '100px',
LOGO_HEADER_CLICK: {
// externalLink: {
// url: 'https://ocelot.social',
// target: '_blank',
// },
externalLink: null,
internalPath: {
to: {
name: 'index',
},
scrollTo: '.main-navigation',
},
},
LOGO_SIGNUP_PATH: '/img/custom/logo-squared.svg',
LOGO_WELCOME_PATH: '/img/custom/logo-squared.svg',
LOGO_LOGOUT_PATH: '/img/custom/logo-squared.svg',
LOGO_PASSWORD_RESET_PATH: '/img/custom/logo-squared.svg',
LOGO_MAINTENACE_RESET_PATH: '/img/custom/logo-squared.svg',
}
export default merge(defaultLogos, logos)

View File

@ -23,7 +23,7 @@
</ds-container>
</div>
<ds-container>
<div style="padding: 5rem 2rem">
<div class="content">
<nuxt />
</div>
</ds-container>
@ -61,7 +61,7 @@ export default {
}
</script>
<style lang="scss">
<style lang="scss" scoped>
.main-navigation-right {
display: flex;
justify-content: flex-end;
@ -69,4 +69,14 @@ export default {
.main-navigation-right .desktop-view {
float: right;
}
.layout-blank .content {
padding: 5rem 2rem;
}
@media only screen and (max-width: 500px) {
.layout-blank .content {
padding-left: 0 !important;
padding-right: 0 !important;
}
}
</style>

View File

@ -1,12 +1,10 @@
<template>
<div>
<ds-heading tag="h1">{{ $t('chat.page.headline') }}</ds-heading>
<add-chat-room-by-user-search
v-if="showUserSearch"
@add-chat-room="addChatRoom"
@close-user-search="showUserSearch = false"
/>
<ds-space margin-bottom="small" />
<chat
:roomId="getShowChat.showChat ? getShowChat.roomID : null"
ref="chat"