2026-09-13 21:02:25 +03:30
|
|
|
<template>
|
|
|
|
|
<!--
|
|
|
|
|
Replacement for legacy henza_admin/src/layouts/components/vertical-nav-menu/
|
|
|
|
|
(VerticalNavMenu.vue + VerticalNavMenuGroup/Item/Header, ~700 lines of Vuesax-
|
|
|
|
|
specific markup). Vuesax has no Vue 3 build, so the tree is rendered with
|
|
|
|
|
ant-design-vue's a-menu instead.
|
|
|
|
|
|
|
|
|
|
What is preserved exactly: the menu DATA (navMenuItems.ts, byte-exact), the
|
|
|
|
|
permission filtering rule, the header/group/item nesting, and the Farsi labels.
|
|
|
|
|
What changes: the DOM/classes, because the underlying component library changed.
|
|
|
|
|
-->
|
|
|
|
|
<a-layout-sider
|
|
|
|
|
:collapsed="collapsed"
|
|
|
|
|
:trigger="null"
|
|
|
|
|
collapsible
|
|
|
|
|
width="260"
|
|
|
|
|
class="vertical-nav-menu"
|
|
|
|
|
theme="light"
|
|
|
|
|
>
|
2026-10-14 04:33:24 +03:30
|
|
|
<div class="nav-header" :class="{ 'is-collapsed': collapsed }">
|
|
|
|
|
<span class="nav-logo">
|
|
|
|
|
<img src="../../assets/images/logo/montzar-icon.png" alt="" />
|
|
|
|
|
</span>
|
|
|
|
|
<span v-if="!collapsed" class="nav-brand">
|
|
|
|
|
<span class="nav-title">{{ title }}</span>
|
|
|
|
|
<span class="nav-subtitle">پنل مدیریت</span>
|
|
|
|
|
</span>
|
2026-09-13 21:02:25 +03:30
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<a-menu
|
2026-10-14 04:33:24 +03:30
|
|
|
class="nav-menu"
|
2026-09-13 21:02:25 +03:30
|
|
|
mode="inline"
|
|
|
|
|
theme="light"
|
2026-09-14 15:20:47 +03:30
|
|
|
:inline-collapsed="collapsed"
|
2026-09-13 21:02:25 +03:30
|
|
|
:selected-keys="selectedKeys"
|
|
|
|
|
:open-keys="openKeys"
|
|
|
|
|
@update:openKeys="(k: string[]) => (openKeys = k)"
|
|
|
|
|
@click="onClick"
|
|
|
|
|
>
|
|
|
|
|
<template v-for="(node, i) in visibleMenu" :key="node.url || node.header || i">
|
2026-09-14 15:20:47 +03:30
|
|
|
<!-- header node: a section divider carrying `items` (ant has no icon
|
|
|
|
|
slot on a menu-item-group; it's a label-only divider, so its
|
2026-09-19 12:05:59 +03:30
|
|
|
children still carry their own icons below). Each child renders
|
|
|
|
|
through NavMenuNode, which recurses into however many submenu
|
|
|
|
|
levels it has. -->
|
2026-09-13 21:02:25 +03:30
|
|
|
<a-menu-item-group v-if="node.header" :title="node.i18n || node.header">
|
2026-09-19 12:05:59 +03:30
|
|
|
<NavMenuNode
|
|
|
|
|
v-for="(child, j) in visibleChildren(node.items)"
|
|
|
|
|
:key="child.url || `${i}-${j}`"
|
|
|
|
|
:node="child"
|
|
|
|
|
:menu-key="child.url || subKey(child, j)"
|
|
|
|
|
/>
|
2026-09-13 21:02:25 +03:30
|
|
|
</a-menu-item-group>
|
|
|
|
|
|
2026-09-19 12:05:59 +03:30
|
|
|
<!-- group / leaf node -->
|
|
|
|
|
<NavMenuNode v-else :node="node" :menu-key="node.url || subKey(node, i)" />
|
2026-09-13 21:02:25 +03:30
|
|
|
</template>
|
|
|
|
|
</a-menu>
|
|
|
|
|
</a-layout-sider>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { computed, ref, watch } from 'vue';
|
|
|
|
|
import { useRoute, useRouter } from 'vue-router';
|
2026-09-19 12:05:59 +03:30
|
|
|
import { getMenu, type NavMenuNode as NavMenuNodeData } from '../navMenuItems';
|
2026-09-13 21:02:25 +03:30
|
|
|
import { useUsersStore } from '../../stores/users';
|
2026-09-14 15:20:47 +03:30
|
|
|
import { resolveIcon } from '../../components/icons';
|
2026-09-19 12:05:59 +03:30
|
|
|
import NavMenuNode from './NavMenuNode.vue';
|
2026-09-13 21:02:25 +03:30
|
|
|
|
|
|
|
|
withDefaults(defineProps<{ title?: string; collapsed?: boolean }>(), {
|
2026-09-16 11:59:35 +03:30
|
|
|
title: 'منتزر',
|
2026-09-13 21:02:25 +03:30
|
|
|
collapsed: false,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const users = useUsersStore();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Legacy's visibility rule, from the v-if on each nav item:
|
|
|
|
|
* a node with no permissionId is ALWAYS visible; otherwise it needs the rid.
|
|
|
|
|
*
|
|
|
|
|
* That "no permissionId = public" rule is why the banker-list and shopkeeper-list
|
|
|
|
|
* items (whose permissionId is commented out in the legacy data) show for everyone.
|
|
|
|
|
* Preserved deliberately — see docs/ADMIN-PORT-PLAN.md.
|
|
|
|
|
*/
|
2026-09-19 12:05:59 +03:30
|
|
|
function canSee(node: NavMenuNodeData): boolean {
|
2026-10-14 04:33:24 +03:30
|
|
|
if (node.superAdminOnly && !users.isSuperAdmin) return false;
|
2026-09-13 21:02:25 +03:30
|
|
|
if (!node.permissionId) return true;
|
|
|
|
|
return Boolean(users.hasPermission(node.permissionId));
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-19 12:05:59 +03:30
|
|
|
function visibleChildren(nodes?: NavMenuNodeData[]): NavMenuNodeData[] {
|
2026-09-13 21:02:25 +03:30
|
|
|
return (nodes ?? []).filter(canSee);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Hides a group whose children are all hidden, as legacy did. */
|
2026-09-19 12:05:59 +03:30
|
|
|
function hasVisibleContent(node: NavMenuNodeData): boolean {
|
2026-09-13 21:02:25 +03:30
|
|
|
if (node.header) return visibleChildren(node.items).length > 0;
|
|
|
|
|
if (node.submenu) return visibleChildren(node.submenu).length > 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const visibleMenu = computed(() =>
|
|
|
|
|
getMenu().filter((n) => canSee(n) && hasVisibleContent(n)),
|
|
|
|
|
);
|
|
|
|
|
|
2026-09-19 12:05:59 +03:30
|
|
|
const subKey = (node: NavMenuNodeData, i: number) => `sub-${node.name ?? ''}-${i}`;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Finds the chain of sub-menu keys that must be open so the current route's
|
|
|
|
|
* menu item is visible, at any nesting depth. Mirrors the key each
|
|
|
|
|
* NavMenuNode instance is actually given (node.url, or menuKey-derived for
|
|
|
|
|
* url-less group nodes), so a match here really is a key ant's a-menu knows
|
|
|
|
|
* about.
|
|
|
|
|
*/
|
|
|
|
|
function findOpenKeysIn(nodes: NavMenuNodeData[], path: string, parentKey: string): string[] | null {
|
|
|
|
|
for (let i = 0; i < nodes.length; i++) {
|
|
|
|
|
const node = nodes[i];
|
|
|
|
|
const key = node.url || `${parentKey}-${i}`;
|
|
|
|
|
if (!node.submenu) {
|
|
|
|
|
if (node.url === path) return [];
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const nested = findOpenKeysIn(visibleChildren(node.submenu), path, key);
|
|
|
|
|
if (nested) return [key, ...nested];
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2026-09-13 21:02:25 +03:30
|
|
|
|
2026-09-14 15:20:47 +03:30
|
|
|
/**
|
|
|
|
|
* Finds the sub-menu key(s) that must be open so the current route's menu
|
|
|
|
|
* item is visible. Previously openKeys only ever changed via user clicks
|
|
|
|
|
* (@update:openKeys), so a direct link or a page refresh landed with every
|
|
|
|
|
* submenu collapsed even when the active item was nested inside one.
|
|
|
|
|
*/
|
|
|
|
|
function findOpenKeysFor(path: string): string[] {
|
|
|
|
|
for (let i = 0; i < visibleMenu.value.length; i++) {
|
|
|
|
|
const node = visibleMenu.value[i];
|
|
|
|
|
|
|
|
|
|
if (node.header) {
|
|
|
|
|
const children = visibleChildren(node.items);
|
|
|
|
|
for (let j = 0; j < children.length; j++) {
|
|
|
|
|
const child = children[j];
|
2026-09-19 12:05:59 +03:30
|
|
|
if (!child.submenu) continue;
|
|
|
|
|
const childKey = child.url || subKey(child, j);
|
|
|
|
|
const nested = findOpenKeysIn(visibleChildren(child.submenu), path, childKey);
|
|
|
|
|
if (nested) return [childKey, ...nested];
|
2026-09-14 15:20:47 +03:30
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-19 12:05:59 +03:30
|
|
|
if (node.submenu) {
|
|
|
|
|
const nodeKey = node.url || subKey(node, i);
|
|
|
|
|
const nested = findOpenKeysIn(visibleChildren(node.submenu), path, nodeKey);
|
|
|
|
|
if (nested) return [nodeKey, ...nested];
|
2026-09-14 15:20:47 +03:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-13 21:02:25 +03:30
|
|
|
const selectedKeys = ref<string[]>([route.path]);
|
2026-09-14 15:20:47 +03:30
|
|
|
const openKeys = ref<string[]>(findOpenKeysFor(route.path));
|
2026-09-13 21:02:25 +03:30
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => route.path,
|
|
|
|
|
(p) => {
|
|
|
|
|
selectedKeys.value = [p];
|
2026-09-14 15:20:47 +03:30
|
|
|
const needed = findOpenKeysFor(p);
|
|
|
|
|
for (const key of needed) {
|
|
|
|
|
if (!openKeys.value.includes(key)) openKeys.value = [...openKeys.value, key];
|
|
|
|
|
}
|
2026-09-13 21:02:25 +03:30
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
function onClick({ key }: { key: string | number }) {
|
|
|
|
|
const path = String(key);
|
|
|
|
|
if (path.startsWith('/') && path !== route.path) {
|
|
|
|
|
router.push(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.vertical-nav-menu {
|
2026-09-19 12:05:59 +03:30
|
|
|
height: 100vh;
|
2026-10-14 04:33:24 +03:30
|
|
|
border-left: 1px solid #eef0f5;
|
|
|
|
|
box-shadow: -4px 0 24px -16px rgba(16, 24, 40, 0.12);
|
|
|
|
|
}
|
|
|
|
|
.vertical-nav-menu :deep(.ant-layout-sider-children) {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
height: 100%;
|
2026-09-13 21:02:25 +03:30
|
|
|
}
|
|
|
|
|
.nav-header {
|
|
|
|
|
height: 61px; /* legacy ara/ant.less @layout-header-height */
|
2026-10-14 04:33:24 +03:30
|
|
|
flex-shrink: 0;
|
2026-09-13 21:02:25 +03:30
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
2026-10-14 04:33:24 +03:30
|
|
|
gap: 12px;
|
|
|
|
|
padding: 0 20px;
|
|
|
|
|
border-bottom: 1px solid #eef0f5;
|
|
|
|
|
}
|
|
|
|
|
.nav-header.is-collapsed {
|
2026-09-13 21:02:25 +03:30
|
|
|
justify-content: center;
|
2026-10-14 04:33:24 +03:30
|
|
|
padding: 0;
|
|
|
|
|
}
|
|
|
|
|
.nav-logo {
|
|
|
|
|
width: 38px;
|
|
|
|
|
height: 38px;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
display: grid;
|
|
|
|
|
place-items: center;
|
|
|
|
|
border-radius: 11px;
|
|
|
|
|
background: #fff;
|
|
|
|
|
border: 1px solid #eef0f5;
|
|
|
|
|
box-shadow: 0 4px 12px -6px rgba(28, 45, 86, 0.35);
|
|
|
|
|
}
|
|
|
|
|
.nav-logo img {
|
|
|
|
|
width: 64%;
|
|
|
|
|
}
|
|
|
|
|
.nav-brand {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
min-width: 0;
|
|
|
|
|
line-height: 1.3;
|
2026-09-13 21:02:25 +03:30
|
|
|
}
|
|
|
|
|
.nav-title {
|
2026-10-14 04:33:24 +03:30
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: 500;
|
2026-09-13 21:02:25 +03:30
|
|
|
color: #1c2d56;
|
|
|
|
|
}
|
2026-10-14 04:33:24 +03:30
|
|
|
.nav-subtitle {
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
color: #8a94a6;
|
|
|
|
|
}
|
|
|
|
|
/* pinned in place; only the menu scrolls if it's taller than the viewport */
|
|
|
|
|
.nav-menu {
|
|
|
|
|
flex: 1;
|
|
|
|
|
min-height: 0;
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
overflow-x: hidden;
|
|
|
|
|
padding: 12px 0 24px;
|
|
|
|
|
scrollbar-width: thin;
|
|
|
|
|
scrollbar-color: #e3e7ef transparent;
|
|
|
|
|
}
|
|
|
|
|
.nav-menu::-webkit-scrollbar {
|
|
|
|
|
width: 6px;
|
|
|
|
|
}
|
|
|
|
|
.nav-menu::-webkit-scrollbar-thumb {
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
background: #e3e7ef;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
Unscoped: the mobile drawer teleports outside #app and ant's collapsed popups
|
|
|
|
|
teleport to <body>. :is(#app, ...) also out-ranks utilities.less's
|
|
|
|
|
`body #app .ant-menu-item-selected`.
|
|
|
|
|
-->
|
|
|
|
|
<style>
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .nav-menu.ant-menu {
|
|
|
|
|
border-inline-end: none !important;
|
|
|
|
|
background: transparent;
|
|
|
|
|
font-size: 13.5px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* section titles */
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-item-group-title {
|
|
|
|
|
padding: 18px 24px 6px;
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
letter-spacing: 0.3px;
|
|
|
|
|
color: #a0a8b8;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-inline-collapsed .ant-menu-item-group-title {
|
|
|
|
|
padding: 12px 0 4px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
font-size: 0;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-inline-collapsed .ant-menu-item-group-title::after {
|
|
|
|
|
content: '';
|
|
|
|
|
display: inline-block;
|
|
|
|
|
width: 18px;
|
|
|
|
|
height: 2px;
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
background: #e3e7ef;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* items + submenu titles */
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-inline .ant-menu-item,
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-inline .ant-menu-submenu-title {
|
|
|
|
|
height: 42px;
|
|
|
|
|
line-height: 42px;
|
|
|
|
|
margin: 2px 12px;
|
|
|
|
|
width: calc(100% - 24px);
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
color: #475467;
|
|
|
|
|
transition: background 0.2s ease, color 0.2s ease;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-item .ant-menu-item-icon,
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-submenu-title .ant-menu-item-icon {
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
color: #98a2b3;
|
|
|
|
|
transition: color 0.2s ease;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-item:not(.ant-menu-item-selected):hover,
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-submenu-title:hover {
|
|
|
|
|
background: #f5f7fb !important;
|
|
|
|
|
color: #1c2d56 !important;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-item:hover .ant-menu-item-icon,
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-submenu-title:hover .ant-menu-item-icon {
|
|
|
|
|
color: #1c2d56;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* active item */
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-item-selected {
|
|
|
|
|
position: relative;
|
|
|
|
|
background: rgba(28, 45, 86, 0.08) !important;
|
|
|
|
|
color: #1c2d56 !important;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-item-selected .ant-menu-item-icon {
|
|
|
|
|
color: #1c2d56;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-inline .ant-menu-item-selected::after {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset-inline-start: 0;
|
|
|
|
|
inset-inline-end: auto;
|
|
|
|
|
top: 10px;
|
|
|
|
|
bottom: 10px;
|
|
|
|
|
width: 3px;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
background: #1c2d56;
|
|
|
|
|
opacity: 1;
|
|
|
|
|
transform: none;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-submenu-selected > .ant-menu-submenu-title,
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-submenu-selected > .ant-menu-submenu-title .ant-menu-item-icon {
|
|
|
|
|
color: #1c2d56;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* nested lists: no grey slab, a soft guide line instead */
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-sub.ant-menu-inline {
|
|
|
|
|
position: relative;
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-sub.ant-menu-inline::before {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset-inline-start: 32px;
|
|
|
|
|
top: 4px;
|
|
|
|
|
bottom: 4px;
|
|
|
|
|
width: 1px;
|
|
|
|
|
background: #e8ebf2;
|
|
|
|
|
}
|
|
|
|
|
:is(#app, .mobile-nav-drawer) .vertical-nav-menu .ant-menu-sub .ant-menu-item {
|
|
|
|
|
height: 38px;
|
|
|
|
|
line-height: 38px;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* collapsed rail: submenus open as popups teleported to <body> */
|
|
|
|
|
.nav-popup.ant-menu-submenu-popup > .ant-menu {
|
|
|
|
|
padding: 6px;
|
|
|
|
|
border-radius: 14px;
|
|
|
|
|
background: #fff;
|
|
|
|
|
border: 1px solid #eef0f5;
|
|
|
|
|
box-shadow: 0 12px 32px -12px rgba(16, 24, 40, 0.25);
|
|
|
|
|
}
|
|
|
|
|
.nav-popup .ant-menu-item,
|
|
|
|
|
.nav-popup .ant-menu-submenu-title {
|
|
|
|
|
height: 40px;
|
|
|
|
|
line-height: 40px;
|
|
|
|
|
margin: 2px 0;
|
|
|
|
|
width: 100%;
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
color: #475467;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
transition: background 0.2s ease, color 0.2s ease;
|
|
|
|
|
}
|
|
|
|
|
.nav-popup .ant-menu-item .ant-menu-item-icon,
|
|
|
|
|
.nav-popup .ant-menu-submenu-title .ant-menu-item-icon {
|
|
|
|
|
color: #98a2b3;
|
|
|
|
|
}
|
|
|
|
|
.nav-popup .ant-menu-item:not(.ant-menu-item-selected):hover,
|
|
|
|
|
.nav-popup .ant-menu-submenu-title:hover {
|
|
|
|
|
background: #f5f7fb !important;
|
|
|
|
|
color: #1c2d56 !important;
|
|
|
|
|
}
|
|
|
|
|
.nav-popup .ant-menu-item-selected {
|
|
|
|
|
position: relative;
|
|
|
|
|
background: rgba(28, 45, 86, 0.08) !important;
|
|
|
|
|
color: #1c2d56 !important;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
.nav-popup .ant-menu-item-selected .ant-menu-item-icon {
|
|
|
|
|
color: #1c2d56;
|
|
|
|
|
}
|
|
|
|
|
.nav-popup .ant-menu-item-selected::after {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset-inline-start: 0;
|
|
|
|
|
inset-inline-end: auto;
|
|
|
|
|
top: 10px;
|
|
|
|
|
bottom: 10px;
|
|
|
|
|
width: 3px;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
background: #1c2d56;
|
|
|
|
|
opacity: 1;
|
|
|
|
|
transform: none;
|
|
|
|
|
}
|
|
|
|
|
.nav-popup .ant-menu-submenu-selected > .ant-menu-submenu-title {
|
|
|
|
|
color: #1c2d56;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* collapsed rail: the icon of the group holding the active page */
|
|
|
|
|
#app .vertical-nav-menu .ant-menu-inline-collapsed .ant-menu-submenu-selected > .ant-menu-submenu-title,
|
|
|
|
|
#app .vertical-nav-menu .ant-menu-inline-collapsed > .ant-menu-item-selected {
|
|
|
|
|
background: rgba(28, 45, 86, 0.08) !important;
|
|
|
|
|
color: #1c2d56 !important;
|
|
|
|
|
}
|
2026-09-13 21:02:25 +03:30
|
|
|
</style>
|