Refactor backend CORS settings to include default origins and improve error handling in chat services: Introduce dynamic CORS origin handling, enhance RabbitMQ message sending with fallback mechanisms, and update WebSocket service to manage pending messages. Update UI components for better accessibility and responsiveness, including adjustments to dialog and navigation elements. Enhance styling for improved user experience across various components.
This commit is contained in:
@@ -1,26 +1,44 @@
|
||||
<template>
|
||||
<nav>
|
||||
<ul>
|
||||
<nav
|
||||
ref="navRoot"
|
||||
class="app-navigation"
|
||||
:class="{ 'app-navigation--suppress-hover': suppressHover }"
|
||||
>
|
||||
<div class="nav-primary">
|
||||
<ul>
|
||||
<!-- Hauptmenü -->
|
||||
<li
|
||||
v-for="(item, key) in menu"
|
||||
:key="key"
|
||||
class="mainmenuitem"
|
||||
@click="handleItem(item, $event)"
|
||||
:class="{ 'mainmenuitem--active': isItemActive(item), 'mainmenuitem--expanded': isMainExpanded(key) }"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
:aria-haspopup="hasTopLevelSubmenu(item) ? 'menu' : undefined"
|
||||
:aria-expanded="hasTopLevelSubmenu(item) ? String(isMainExpanded(key)) : undefined"
|
||||
@click="handleItem(item, $event, key)"
|
||||
@keydown.enter.prevent="handleItem(item, $event, key)"
|
||||
@keydown.space.prevent="handleItem(item, $event, key)"
|
||||
>
|
||||
<span
|
||||
v-if="item.icon"
|
||||
:style="`background-image:url('/images/icons/${item.icon}')`"
|
||||
class="menu-icon"
|
||||
> </span>
|
||||
<span>{{ $t(`navigation.${key}`) }}</span>
|
||||
<span class="mainmenuitem__label">{{ $t(`navigation.${key}`) }}</span>
|
||||
<span v-if="hasTopLevelSubmenu(item)" class="mainmenuitem__caret">▾</span>
|
||||
|
||||
<!-- Untermenü Ebene 1 -->
|
||||
<ul v-if="hasTopLevelSubmenu(item)" class="submenu1">
|
||||
<ul v-if="hasTopLevelSubmenu(item)" class="submenu1" :class="{ 'submenu1--open': isMainExpanded(key) }">
|
||||
<li
|
||||
v-for="(subitem, subkey) in item.children"
|
||||
:key="subkey"
|
||||
@click="handleItem(subitem, $event)"
|
||||
tabindex="0"
|
||||
role="menuitem"
|
||||
:class="{ 'submenu1__item--expanded': isSubExpanded(`${key}:${subkey}`) }"
|
||||
@click="handleSubItem(subitem, subkey, key, $event)"
|
||||
@keydown.enter.prevent="handleSubItem(subitem, subkey, key, $event)"
|
||||
@keydown.space.prevent="handleSubItem(subitem, subkey, key, $event)"
|
||||
>
|
||||
<span
|
||||
v-if="subitem.icon"
|
||||
@@ -37,11 +55,16 @@
|
||||
<ul
|
||||
v-if="subkey === 'forum' && forumList.length"
|
||||
class="submenu2"
|
||||
:class="{ 'submenu2--open': isSubExpanded(`${key}:${subkey}`) }"
|
||||
>
|
||||
<li
|
||||
v-for="forum in forumList"
|
||||
:key="forum.id"
|
||||
tabindex="0"
|
||||
role="menuitem"
|
||||
@click="handleItem({ action: 'openForum', params: forum.id }, $event)"
|
||||
@keydown.enter.prevent="handleItem({ action: 'openForum', params: forum.id }, $event)"
|
||||
@keydown.space.prevent="handleItem({ action: 'openForum', params: forum.id }, $event)"
|
||||
>
|
||||
{{ forum.name }}
|
||||
</li>
|
||||
@@ -51,16 +74,25 @@
|
||||
<ul
|
||||
v-else-if="subkey === 'vocabtrainer' && vocabLanguagesList.length"
|
||||
class="submenu2"
|
||||
:class="{ 'submenu2--open': isSubExpanded(`${key}:${subkey}`) }"
|
||||
>
|
||||
<li
|
||||
tabindex="0"
|
||||
role="menuitem"
|
||||
@click="handleItem({ path: '/socialnetwork/vocab/new' }, $event)"
|
||||
@keydown.enter.prevent="handleItem({ path: '/socialnetwork/vocab/new' }, $event)"
|
||||
@keydown.space.prevent="handleItem({ path: '/socialnetwork/vocab/new' }, $event)"
|
||||
>
|
||||
{{ $t('navigation.m-sprachenlernen.m-vocabtrainer.newLanguage') }}
|
||||
</li>
|
||||
<li
|
||||
v-for="lang in vocabLanguagesList"
|
||||
:key="lang.id"
|
||||
tabindex="0"
|
||||
role="menuitem"
|
||||
@click="handleItem({ path: `/socialnetwork/vocab/${lang.id}` }, $event)"
|
||||
@keydown.enter.prevent="handleItem({ path: `/socialnetwork/vocab/${lang.id}` }, $event)"
|
||||
@keydown.space.prevent="handleItem({ path: `/socialnetwork/vocab/${lang.id}` }, $event)"
|
||||
>
|
||||
{{ lang.name }}
|
||||
</li>
|
||||
@@ -70,11 +102,16 @@
|
||||
<ul
|
||||
v-else-if="subitem.children"
|
||||
class="submenu2"
|
||||
:class="{ 'submenu2--open': isSubExpanded(`${key}:${subkey}`) }"
|
||||
>
|
||||
<li
|
||||
v-for="(subsubitem, subsubkey) in subitem.children"
|
||||
:key="subsubkey"
|
||||
tabindex="0"
|
||||
role="menuitem"
|
||||
@click="handleItem(subsubitem, $event)"
|
||||
@keydown.enter.prevent="handleItem(subsubitem, $event)"
|
||||
@keydown.space.prevent="handleItem(subsubitem, $event)"
|
||||
>
|
||||
<span
|
||||
v-if="subsubitem.icon"
|
||||
@@ -91,17 +128,29 @@
|
||||
v-if="item.showLoggedinFriends === 1 && friendsList.length"
|
||||
v-for="friend in friendsList"
|
||||
:key="friend.id"
|
||||
tabindex="0"
|
||||
role="menuitem"
|
||||
@click="handleItem({ action: 'openChat', params: friend.id }, $event)"
|
||||
@keydown.enter.prevent="handleItem({ action: 'openChat', params: friend.id }, $event)"
|
||||
@keydown.space.prevent="handleItem({ action: 'openChat', params: friend.id }, $event)"
|
||||
>
|
||||
{{ friend.username }}
|
||||
<ul class="submenu2">
|
||||
<li
|
||||
tabindex="0"
|
||||
role="menuitem"
|
||||
@click="handleItem({ action: 'openChat', params: friend.id }, $event)"
|
||||
@keydown.enter.prevent="handleItem({ action: 'openChat', params: friend.id }, $event)"
|
||||
@keydown.space.prevent="handleItem({ action: 'openChat', params: friend.id }, $event)"
|
||||
>
|
||||
{{ $t('navigation.m-friends.chat') }}
|
||||
</li>
|
||||
<li
|
||||
tabindex="0"
|
||||
role="menuitem"
|
||||
@click="handleItem({ action: 'openProfile', params: friend.id }, $event)"
|
||||
@keydown.enter.prevent="handleItem({ action: 'openProfile', params: friend.id }, $event)"
|
||||
@keydown.space.prevent="handleItem({ action: 'openProfile', params: friend.id }, $event)"
|
||||
>
|
||||
{{ $t('navigation.m-friends.profile') }}
|
||||
</li>
|
||||
@@ -109,13 +158,14 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="right-block">
|
||||
<span @click="accessMailbox" class="mailbox"></span>
|
||||
<button type="button" @click="accessMailbox" class="mailbox" aria-label="Mailbox"></button>
|
||||
<span class="logoutblock">
|
||||
<span class="username">{{ user.username }}</span>
|
||||
<span @click="logout" class="menuitem">
|
||||
<span class="menuitem" @click="logout">
|
||||
{{ $t('navigation.logout') }}
|
||||
</span>
|
||||
</span>
|
||||
@@ -127,6 +177,7 @@
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { createApp } from 'vue';
|
||||
import apiClient from '@/utils/axios.js';
|
||||
import { EventBus } from '@/utils/eventBus.js';
|
||||
|
||||
import RandomChatDialog from '../dialogues/chat/RandomChatDialog.vue';
|
||||
import MultiChatDialog from '../dialogues/chat/MultiChatDialog.vue';
|
||||
@@ -146,7 +197,14 @@ export default {
|
||||
return {
|
||||
forumList: [],
|
||||
friendsList: [],
|
||||
vocabLanguagesList: []
|
||||
vocabLanguagesList: [],
|
||||
expandedMainKey: null,
|
||||
expandedSubKey: null,
|
||||
pinnedMainKey: null,
|
||||
pinnedSubKey: null,
|
||||
suppressHover: false,
|
||||
hoverReleaseTimer: null,
|
||||
isMobileNav: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -156,6 +214,9 @@ export default {
|
||||
menuNeedsUpdate(newVal) {
|
||||
if (newVal) this.loadMenu();
|
||||
},
|
||||
$route() {
|
||||
this.collapseMenus();
|
||||
},
|
||||
socket(newSocket) {
|
||||
if (newSocket) {
|
||||
newSocket.on('forumschanged', this.fetchForums);
|
||||
@@ -171,6 +232,10 @@ export default {
|
||||
this.fetchFriends();
|
||||
this.fetchVocabLanguages();
|
||||
}
|
||||
this.updateViewportState();
|
||||
window.addEventListener('resize', this.updateViewportState);
|
||||
document.addEventListener('click', this.handleDocumentClick);
|
||||
document.addEventListener('keydown', this.handleDocumentKeydown);
|
||||
},
|
||||
beforeUnmount() {
|
||||
const sock = this.socket;
|
||||
@@ -179,10 +244,88 @@ export default {
|
||||
sock.off('friendloginchanged');
|
||||
sock.off('reloadmenu');
|
||||
}
|
||||
window.removeEventListener('resize', this.updateViewportState);
|
||||
document.removeEventListener('click', this.handleDocumentClick);
|
||||
document.removeEventListener('keydown', this.handleDocumentKeydown);
|
||||
if (this.hoverReleaseTimer) {
|
||||
clearTimeout(this.hoverReleaseTimer);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['loadMenu', 'logout']),
|
||||
|
||||
updateViewportState() {
|
||||
this.isMobileNav = window.innerWidth <= 960;
|
||||
if (!this.isMobileNav) {
|
||||
this.expandedMainKey = null;
|
||||
this.expandedSubKey = null;
|
||||
}
|
||||
},
|
||||
|
||||
isMainExpanded(key) {
|
||||
return this.isMobileNav
|
||||
? this.expandedMainKey === key
|
||||
: this.pinnedMainKey === key;
|
||||
},
|
||||
|
||||
isSubExpanded(key) {
|
||||
return this.isMobileNav
|
||||
? this.expandedSubKey === key
|
||||
: this.pinnedSubKey === key;
|
||||
},
|
||||
|
||||
toggleMain(key) {
|
||||
this.expandedMainKey = this.expandedMainKey === key ? null : key;
|
||||
this.expandedSubKey = null;
|
||||
},
|
||||
|
||||
toggleSub(key) {
|
||||
this.expandedSubKey = this.expandedSubKey === key ? null : key;
|
||||
},
|
||||
|
||||
togglePinnedMain(key) {
|
||||
this.pinnedMainKey = this.pinnedMainKey === key ? null : key;
|
||||
this.pinnedSubKey = null;
|
||||
},
|
||||
|
||||
togglePinnedSub(key) {
|
||||
this.pinnedSubKey = this.pinnedSubKey === key ? null : key;
|
||||
},
|
||||
|
||||
collapseMenus() {
|
||||
this.expandedMainKey = null;
|
||||
this.expandedSubKey = null;
|
||||
this.pinnedMainKey = null;
|
||||
this.pinnedSubKey = null;
|
||||
this.suppressHover = true;
|
||||
if (this.hoverReleaseTimer) {
|
||||
clearTimeout(this.hoverReleaseTimer);
|
||||
}
|
||||
this.hoverReleaseTimer = window.setTimeout(() => {
|
||||
this.suppressHover = false;
|
||||
this.hoverReleaseTimer = null;
|
||||
}, 180);
|
||||
this.$nextTick(() => {
|
||||
if (document.activeElement && typeof document.activeElement.blur === 'function') {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleDocumentClick(event) {
|
||||
const root = this.$refs.navRoot;
|
||||
if (!root || root.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
this.collapseMenus();
|
||||
},
|
||||
|
||||
handleDocumentKeydown(event) {
|
||||
if (event.key === 'Escape') {
|
||||
this.collapseMenus();
|
||||
}
|
||||
},
|
||||
|
||||
hasChildren(item) {
|
||||
if (!item?.children) {
|
||||
return false;
|
||||
@@ -211,6 +354,18 @@ export default {
|
||||
return this.hasChildren(subitem);
|
||||
},
|
||||
|
||||
isItemActive(item) {
|
||||
if (!item?.path || !this.$route?.path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.path === '/') {
|
||||
return this.$route.path === '/';
|
||||
}
|
||||
|
||||
return this.$route.path === item.path || this.$route.path.startsWith(`${item.path}/`);
|
||||
},
|
||||
|
||||
openMultiChat() {
|
||||
// Räume können später dynamisch geladen werden, hier als Platzhalter ein Beispiel:
|
||||
const exampleRooms = [
|
||||
@@ -227,6 +382,21 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
accessMailbox() {
|
||||
const openMessages = () => {
|
||||
EventBus.emit('open-falukant-messages');
|
||||
};
|
||||
|
||||
if (this.$route?.path?.startsWith('/falukant')) {
|
||||
openMessages();
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({ name: 'FalukantOverview' }).then(() => {
|
||||
window.setTimeout(openMessages, 150);
|
||||
});
|
||||
},
|
||||
|
||||
async fetchForums() {
|
||||
try {
|
||||
const res = await apiClient.get('/api/forum');
|
||||
@@ -278,10 +448,18 @@ export default {
|
||||
* 3) Bei `action`: custom action aufrufen
|
||||
* 4) Sonst: normale Router-Navigation
|
||||
*/
|
||||
handleItem(item, event) {
|
||||
handleItem(item, event, key = null) {
|
||||
event.stopPropagation();
|
||||
|
||||
// 1) nur aufklappen, wenn es echte Untermenüs gibt (nicht bei leerem children wie bei Startseite)
|
||||
if (key && this.hasTopLevelSubmenu(item)) {
|
||||
if (this.isMobileNav) {
|
||||
this.toggleMain(key);
|
||||
} else {
|
||||
this.togglePinnedMain(key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hasChildren(item)) return;
|
||||
|
||||
// 2) view → Dialog/Window
|
||||
@@ -299,18 +477,38 @@ export default {
|
||||
} else {
|
||||
console.error(`Dialog '${item.class}' gefunden, aber keine open()-Methode verfügbar.`);
|
||||
}
|
||||
this.collapseMenus();
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) custom action (openForum, openChat, ...)
|
||||
if (item.action && typeof this[item.action] === 'function') {
|
||||
return this[item.action](item.params, event);
|
||||
this[item.action](item.params, event);
|
||||
this.collapseMenus();
|
||||
return;
|
||||
}
|
||||
|
||||
// 4) Standard‑Navigation
|
||||
if (item.path) {
|
||||
this.$router.push(item.path);
|
||||
this.collapseMenus();
|
||||
}
|
||||
},
|
||||
|
||||
handleSubItem(item, subkey, parentKey, event) {
|
||||
event.stopPropagation();
|
||||
const compoundKey = `${parentKey}:${subkey}`;
|
||||
|
||||
if (this.hasSecondLevelSubmenu(item, subkey)) {
|
||||
if (this.isMobileNav) {
|
||||
this.toggleSub(compoundKey);
|
||||
} else {
|
||||
this.togglePinnedSub(compoundKey);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleItem(item, event);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -319,36 +517,45 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
@import '../assets/styles.scss';
|
||||
|
||||
nav,
|
||||
nav > ul {
|
||||
.app-navigation,
|
||||
.nav-primary > ul {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.app-navigation {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
margin: 0 auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 6px 12px;
|
||||
flex-wrap: wrap;
|
||||
border-radius: 0;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(249, 236, 225, 0.98) 0%, rgba(246, 228, 212, 0.98) 100%);
|
||||
border-top: 1px solid rgba(93, 64, 55, 0.08);
|
||||
border-bottom: 1px solid rgba(93, 64, 55, 0.12);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.46);
|
||||
color: var(--color-text-primary);
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
nav {
|
||||
max-width: var(--shell-max-width);
|
||||
margin: 0 auto;
|
||||
align-items: stretch;
|
||||
gap: 10px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 0;
|
||||
background: var(--color-primary-orange-light);
|
||||
border-top: 1px solid rgba(93, 64, 55, 0.08);
|
||||
border-bottom: 1px solid rgba(93, 64, 55, 0.12);
|
||||
box-shadow: none;
|
||||
color: var(--color-text-primary);
|
||||
.nav-primary {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
nav > ul {
|
||||
flex: 1;
|
||||
.nav-primary > ul {
|
||||
min-width: 0;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: transparent;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@@ -358,28 +565,57 @@ ul {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
nav > ul > li {
|
||||
.mainmenuitem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 36px;
|
||||
padding: 0 12px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
border-radius: 999px;
|
||||
transition: background-color 0.25s, color 0.25s, transform 0.2s;
|
||||
border: 1px solid transparent;
|
||||
transition: background-color 0.25s, color 0.25s, transform 0.2s, border-color 0.25s, box-shadow 0.25s;
|
||||
}
|
||||
|
||||
nav > ul > li:hover {
|
||||
.mainmenuitem:focus-visible,
|
||||
.submenu1 > li:focus-visible,
|
||||
.submenu2 > li:focus-visible,
|
||||
.mailbox:focus-visible,
|
||||
.menuitem:focus-visible {
|
||||
outline: 3px solid rgba(120, 195, 138, 0.34);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.mainmenuitem:hover {
|
||||
background-color: rgba(248, 162, 43, 0.16);
|
||||
white-space: nowrap;
|
||||
border-color: rgba(248, 162, 43, 0.2);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
nav > ul > li:hover > span {
|
||||
.mainmenuitem:hover > span {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
nav > ul > li:hover > ul {
|
||||
display: inline-block;
|
||||
.mainmenuitem--expanded {
|
||||
background-color: rgba(248, 162, 43, 0.16);
|
||||
border-color: rgba(248, 162, 43, 0.2);
|
||||
}
|
||||
|
||||
.mainmenuitem--active {
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
border-color: rgba(248, 162, 43, 0.22);
|
||||
box-shadow: 0 6px 14px rgba(93, 64, 55, 0.05);
|
||||
}
|
||||
|
||||
.mainmenuitem__label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mainmenuitem__caret {
|
||||
margin-left: 6px;
|
||||
font-size: 0.7rem;
|
||||
color: rgba(95, 75, 57, 0.7);
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -390,7 +626,14 @@ a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding-left: 8px;
|
||||
padding-left: 10px;
|
||||
margin-left: auto;
|
||||
flex: 0 0 auto;
|
||||
border-left: 1px solid rgba(93, 64, 55, 0.12);
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(249, 236, 225, 0.98) 0%, rgba(246, 228, 212, 0.98) 100%);
|
||||
}
|
||||
|
||||
.logoutblock {
|
||||
@@ -411,29 +654,29 @@ a {
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
text-align: left;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 999px;
|
||||
background-color: rgba(120, 195, 138, 0.12);
|
||||
border: 1px solid rgba(93, 64, 55, 0.1);
|
||||
box-shadow: none;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mainmenuitem {
|
||||
position: relative;
|
||||
font-weight: 700;
|
||||
}
|
||||
.mainmenuitem { position: relative; font-weight: 700; }
|
||||
|
||||
.submenu1 {
|
||||
position: absolute;
|
||||
display: block;
|
||||
border: 1px solid rgba(93, 64, 55, 0.12);
|
||||
background: rgba(255, 252, 247, 0.98);
|
||||
background: rgba(255, 252, 247, 0.99);
|
||||
left: 0;
|
||||
top: calc(100% + 10px);
|
||||
min-width: 220px;
|
||||
padding: 8px;
|
||||
border-radius: 18px;
|
||||
box-shadow: 0 10px 18px rgba(93, 64, 55, 0.12);
|
||||
min-width: 240px;
|
||||
padding: 10px;
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: 0 18px 30px rgba(93, 64, 55, 0.14);
|
||||
max-height: 0;
|
||||
overflow: visible;
|
||||
opacity: 0;
|
||||
@@ -452,9 +695,19 @@ a {
|
||||
visibility 0s;
|
||||
}
|
||||
|
||||
.mainmenuitem--expanded .submenu1 {
|
||||
max-height: 500px;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition: max-height 0.25s ease-in-out,
|
||||
opacity 0.05s ease-in-out,
|
||||
visibility 0s;
|
||||
}
|
||||
|
||||
.submenu1 > li {
|
||||
display: block;
|
||||
padding: 0.75em 0.9em;
|
||||
line-height: 1em;
|
||||
line-height: 1.1em;
|
||||
color: var(--color-text-secondary);
|
||||
position: relative;
|
||||
border-radius: 14px;
|
||||
@@ -487,14 +740,15 @@ a {
|
||||
|
||||
.submenu2 {
|
||||
position: absolute;
|
||||
display: block;
|
||||
background: rgba(255, 252, 247, 0.98);
|
||||
left: calc(100% + 8px);
|
||||
top: 0;
|
||||
min-width: 220px;
|
||||
min-width: 230px;
|
||||
padding: 8px;
|
||||
border-radius: 18px;
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid rgba(71, 52, 35, 0.12);
|
||||
box-shadow: 0 10px 18px rgba(93, 64, 55, 0.12);
|
||||
box-shadow: 0 14px 24px rgba(93, 64, 55, 0.12);
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
@@ -513,6 +767,27 @@ a {
|
||||
visibility 0s;
|
||||
}
|
||||
|
||||
.submenu1__item--expanded .submenu2 {
|
||||
max-height: 500px;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition: max-height 0.25s ease-in-out,
|
||||
opacity 0.05s ease-in-out,
|
||||
visibility 0s;
|
||||
}
|
||||
|
||||
.app-navigation--suppress-hover .mainmenuitem:hover .submenu1,
|
||||
.app-navigation--suppress-hover .submenu1 > li:hover .submenu2 {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.submenu1__item--expanded {
|
||||
color: var(--color-text-primary);
|
||||
background-color: rgba(248, 162, 43, 0.08);
|
||||
}
|
||||
|
||||
.submenu2 > li {
|
||||
padding: 0.75em 0.9em;
|
||||
line-height: 1em;
|
||||
@@ -525,6 +800,12 @@ a {
|
||||
background-color: rgba(120, 195, 138, 0.14);
|
||||
}
|
||||
|
||||
.submenu1 > li:focus-visible,
|
||||
.submenu2 > li:focus-visible {
|
||||
color: var(--color-text-primary);
|
||||
background-color: rgba(248, 162, 43, 0.12);
|
||||
}
|
||||
|
||||
.subsubmenu {
|
||||
float: right;
|
||||
font-size: 8pt;
|
||||
@@ -533,34 +814,100 @@ a {
|
||||
|
||||
.username {
|
||||
font-weight: 800;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
nav {
|
||||
.app-navigation {
|
||||
margin: 0;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
padding: 8px 10px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
nav > ul,
|
||||
.nav-primary,
|
||||
.nav-primary > ul,
|
||||
.right-block {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-primary {
|
||||
overflow-x: auto;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
.nav-primary > ul {
|
||||
min-width: 0;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.right-block {
|
||||
justify-content: space-between;
|
||||
padding-left: 0;
|
||||
margin-left: 0;
|
||||
border-left: 0;
|
||||
padding-top: 6px;
|
||||
border-top: 1px solid rgba(93, 64, 55, 0.1);
|
||||
}
|
||||
|
||||
.logoutblock {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.mainmenuitem {
|
||||
min-height: 42px;
|
||||
width: calc(50% - 4px);
|
||||
justify-content: flex-start;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.submenu1,
|
||||
.submenu2 {
|
||||
position: static;
|
||||
min-width: 100%;
|
||||
margin-top: 8px;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.submenu1--open,
|
||||
.submenu2--open {
|
||||
max-height: 1200px;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.submenu1 > li,
|
||||
.submenu2 > li {
|
||||
min-height: 42px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mailbox {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.mainmenuitem {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.right-block {
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.logoutblock {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user