mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-03 08:33:26 +00:00
feat: sidebar enhancement (#10157)
Some checks are pending
build-staging / prepare (push) Waiting to run
build-staging / js-build (push) Blocked by required conditions
build-staging / go-build (push) Blocked by required conditions
build-staging / staging (push) Blocked by required conditions
Release Drafter / update_release_draft (push) Waiting to run
Some checks are pending
build-staging / prepare (push) Waiting to run
build-staging / js-build (push) Blocked by required conditions
build-staging / go-build (push) Blocked by required conditions
build-staging / staging (push) Blocked by required conditions
Release Drafter / update_release_draft (push) Waiting to run
* feat: sidebar enhancement (#9748) * fix: sidebar enhancement * fix: new source btn changes * fix: shortcut order changes * fix: changes in more section collapse behaviour * fix: sidebar shortcut changes, consistency, cleanup in collapse mode * fix: sidebar pin, tooltip and other changes * feat: updated alignment issues * fix: sidenav enhancement - fixes * fix: code fix * fix: sidenav enhancement * feat: addressed comments and feedback * feat: fix default shortcut empty issue * feat: code clean and improvements * feat: refactor and cleanup * feat: refactor and addressed comment * feat: removed isscrolled * feat: corrected the ref intialization
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
}
|
||||
|
||||
.app-content {
|
||||
width: calc(100% - 64px); // width of the sidebar
|
||||
width: calc(100% - 54px); // width of the sidebar
|
||||
z-index: 0;
|
||||
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
.ant-pagination {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: calc(100% - 64px);
|
||||
width: calc(100% - 54px);
|
||||
background: rgb(18, 19, 23);
|
||||
padding: 16px;
|
||||
margin: 0;
|
||||
|
||||
@@ -442,7 +442,7 @@
|
||||
.ant-pagination {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: calc(100% - 64px);
|
||||
width: calc(100% - 54px);
|
||||
background: var(--bg-ink-500);
|
||||
padding: 16px;
|
||||
margin: 0;
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
|
||||
height: calc(100% - 64px);
|
||||
height: calc(100% - 54px);
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
height: 1rem;
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
.ant-pagination {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: calc(100% - 64px);
|
||||
width: calc(100% - 54px);
|
||||
background: var(--bg-ink-500);
|
||||
padding: 16px;
|
||||
margin: 0;
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
.nav-item-active-marker {
|
||||
background: #4e74f8;
|
||||
}
|
||||
|
||||
.nav-item-data {
|
||||
.nav-item-label {
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
@@ -27,14 +33,14 @@
|
||||
|
||||
.nav-item-data {
|
||||
color: white;
|
||||
background: var(--Slate-500, #161922);
|
||||
background: var(--bg-slate-500, #161922);
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
.nav-item-data {
|
||||
color: white;
|
||||
background: var(--Slate-500, #161922);
|
||||
background: var(--bg-slate-500, #161922);
|
||||
// color: #3f5ecc;
|
||||
}
|
||||
}
|
||||
@@ -50,9 +56,9 @@
|
||||
|
||||
.nav-item-data {
|
||||
flex-grow: 1;
|
||||
max-width: calc(100% - 24px);
|
||||
max-width: calc(100% - 20px);
|
||||
display: flex;
|
||||
margin: 0px 8px;
|
||||
margin: 0px 0px 0px 6px;
|
||||
padding: 2px 8px;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
@@ -68,7 +74,7 @@
|
||||
|
||||
background: transparent;
|
||||
|
||||
transition: 0.2s all linear;
|
||||
transition: 0.08s all ease;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
@@ -100,7 +106,7 @@
|
||||
|
||||
&:hover {
|
||||
.nav-item-label {
|
||||
color: var(--Vanilla-100, #fff);
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
}
|
||||
|
||||
.nav-item-pin-icon {
|
||||
@@ -120,6 +126,12 @@
|
||||
.nav-item-active-marker {
|
||||
background: #4e74f8;
|
||||
}
|
||||
|
||||
.nav-item-data {
|
||||
.nav-item-label {
|
||||
color: var(--bg-slate-500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||
import { Tag } from 'antd';
|
||||
import { Tag, Tooltip } from 'antd';
|
||||
import cx from 'classnames';
|
||||
import { Pin, PinOff } from 'lucide-react';
|
||||
|
||||
import { SidebarItem } from '../sideNav.types';
|
||||
|
||||
import './NavItem.styles.scss';
|
||||
import './NavItem.styles.scss';
|
||||
|
||||
export default function NavItem({
|
||||
@@ -74,21 +75,25 @@ export default function NavItem({
|
||||
)}
|
||||
|
||||
{onTogglePin && !isPinned && (
|
||||
<Pin
|
||||
size={12}
|
||||
className="nav-item-pin-icon"
|
||||
onClick={handleTogglePinClick}
|
||||
color="var(--Vanilla-400, #c0c1c3)"
|
||||
/>
|
||||
<Tooltip title="Add to shortcuts" placement="right">
|
||||
<Pin
|
||||
size={12}
|
||||
className="nav-item-pin-icon"
|
||||
onClick={handleTogglePinClick}
|
||||
color="var(--Vanilla-400, #c0c1c3)"
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{onTogglePin && isPinned && (
|
||||
<PinOff
|
||||
size={12}
|
||||
className="nav-item-pin-icon"
|
||||
onClick={handleTogglePinClick}
|
||||
color="var(--Vanilla-400, #c0c1c3)"
|
||||
/>
|
||||
<Tooltip title="Remove from shortcuts" placement="right">
|
||||
<PinOff
|
||||
size={12}
|
||||
className="nav-item-pin-icon"
|
||||
onClick={handleTogglePinClick}
|
||||
color="var(--Vanilla-400, #c0c1c3)"
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.sidenav-container {
|
||||
width: 64px;
|
||||
width: 54px;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@@ -10,47 +10,60 @@
|
||||
}
|
||||
|
||||
.sideNav {
|
||||
flex: 0 0 64px;
|
||||
flex: 0 0 54px;
|
||||
height: 100%;
|
||||
max-width: 64px;
|
||||
min-width: 64px;
|
||||
width: 64px;
|
||||
border-right: 1px solid var(--Slate-500, #161922);
|
||||
background: var(--Ink-500, #0b0c0e);
|
||||
max-width: 54px;
|
||||
min-width: 54px;
|
||||
width: 54px;
|
||||
border-right: 1px solid var(--bg-slate-500, #161922);
|
||||
background: var(--bg-ink-500, #0b0c0e);
|
||||
|
||||
padding-bottom: 48px;
|
||||
transition: all 0.2s, background 0s, border 0s;
|
||||
transition: all 0.08s ease, background 0s, border 0s;
|
||||
|
||||
.brand-container {
|
||||
padding: 8px 18px;
|
||||
padding: 8px 15px;
|
||||
max-width: 100%;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.brand-company-meta {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
gap: 32px;
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
|
||||
.brand-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
width: 20px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
height: 16px;
|
||||
width: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.brand-logo-name {
|
||||
@@ -66,6 +79,10 @@
|
||||
|
||||
.brand-title-section {
|
||||
display: none;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
position: relative;
|
||||
|
||||
.license-type {
|
||||
display: flex;
|
||||
@@ -76,7 +93,7 @@
|
||||
|
||||
color: var(--bg-vanilla-100);
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
background: var(--Slate-400, #1d212d);
|
||||
background: var(--bg-slate-400, #1d212d);
|
||||
|
||||
text-align: center;
|
||||
font-family: Inter;
|
||||
@@ -98,11 +115,11 @@
|
||||
gap: 6px;
|
||||
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
background: var(--Slate-300, #242834);
|
||||
background: var(--bg-slate-300, #242834);
|
||||
}
|
||||
|
||||
.version {
|
||||
color: var(--Vanilla-400, #c0c1c3);
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
text-align: center;
|
||||
font-variant-numeric: lining-nums tabular-nums slashed-zero;
|
||||
font-feature-settings: 'salt' on;
|
||||
@@ -156,24 +173,48 @@
|
||||
|
||||
.get-started-nav-items {
|
||||
display: flex;
|
||||
margin: 4px 13px 12px 10px;
|
||||
margin: 4px 10px 12px 8px;
|
||||
|
||||
.get-started-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
margin-left: 2px;
|
||||
gap: 8px;
|
||||
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--Slate-400, #1d212d);
|
||||
background: var(--Slate-500, #161922);
|
||||
border: 1px solid var(--bg-slate-400, #1d212d);
|
||||
background: var(--bg-slate-500, #161922);
|
||||
|
||||
box-shadow: none !important;
|
||||
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
|
||||
svg {
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
}
|
||||
|
||||
.nav-item-label {
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
}
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: var(--bg-slate-400, #1d212d);
|
||||
border-color: var(--bg-slate-400, #1d212d);
|
||||
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
|
||||
svg {
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
}
|
||||
|
||||
.nav-item-label {
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +233,10 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.nav-top-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -227,7 +272,7 @@
|
||||
}
|
||||
|
||||
.nav-section-title {
|
||||
color: var(--Slate-50, #62687c);
|
||||
color: var(--bg-slate-50, #62687c);
|
||||
font-family: Inter;
|
||||
font-size: 11px;
|
||||
font-style: normal;
|
||||
@@ -241,7 +286,7 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
padding: 0 20px;
|
||||
padding: 0 17px;
|
||||
|
||||
.nav-section-title-text {
|
||||
display: none;
|
||||
@@ -250,11 +295,17 @@
|
||||
.nav-section-title-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: opacity 0.08s ease, transform 0.08s ease;
|
||||
|
||||
&.reorder {
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
margin-left: auto;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +319,7 @@
|
||||
}
|
||||
|
||||
.nav-section-subtitle {
|
||||
color: var(--Vanilla-400, #c0c1c3);
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
font-family: Inter;
|
||||
font-size: 11px;
|
||||
font-style: normal;
|
||||
@@ -276,20 +327,20 @@
|
||||
line-height: 14px; /* 150% */
|
||||
letter-spacing: 0.4px;
|
||||
|
||||
padding: 0 20px;
|
||||
padding: 6px 20px;
|
||||
opacity: 0.6;
|
||||
|
||||
display: none;
|
||||
|
||||
transition: all 0.3s, background 0s, border 0s;
|
||||
transition-delay: 0.1s;
|
||||
transition: all 0.08s ease, background 0s, border 0s;
|
||||
transition-delay: 0.03s;
|
||||
}
|
||||
|
||||
.nav-items-section {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
transition: all 0.08s ease;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +353,7 @@
|
||||
.nav-items-section {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: all 0.4s ease;
|
||||
transition: all 0.1s ease;
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
}
|
||||
@@ -312,11 +363,34 @@
|
||||
.nav-items-section {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transition: all 0.4s ease;
|
||||
transition: all 0.1s ease;
|
||||
overflow: hidden;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.sidebar-collapsed {
|
||||
.nav-title-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-items-section {
|
||||
margin-top: 0;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transition: all 0.08s ease;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-nav-items {
|
||||
&.sidebar-collapsed {
|
||||
.nav-items-section {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-for-more-container {
|
||||
@@ -326,7 +400,7 @@
|
||||
width: 100%;
|
||||
bottom: 12px;
|
||||
bottom: 8px;
|
||||
margin-left: 50px;
|
||||
margin-left: 43px;
|
||||
|
||||
.scroll-for-more {
|
||||
display: flex;
|
||||
@@ -370,8 +444,6 @@
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
padding-top: 12px;
|
||||
|
||||
.secondary-nav-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -381,10 +453,10 @@
|
||||
overflow-x: hidden;
|
||||
padding: 8px 0;
|
||||
max-width: 100%;
|
||||
width: 64px;
|
||||
width: 54px;
|
||||
// width: 100%; // temp
|
||||
|
||||
transition: all 0.2s, background 0s, border 0s;
|
||||
transition: all 0.08s ease, background 0s, border 0s;
|
||||
|
||||
background: linear-gradient(180deg, rgba(11, 12, 14, 0) 0%, #0b0c0e 27.11%);
|
||||
|
||||
@@ -413,7 +485,7 @@
|
||||
|
||||
&.scroll-available {
|
||||
.nav-bottom-section {
|
||||
border-top: 1px solid var(--Slate-500, #161922);
|
||||
border-top: 1px solid var(--bg-slate-500, #161922);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,24 +496,53 @@
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
flex: 0 0 64px;
|
||||
max-width: 64px;
|
||||
min-width: 64px;
|
||||
width: 64px;
|
||||
flex: 0 0 54px;
|
||||
max-width: 54px;
|
||||
min-width: 54px;
|
||||
width: 54px;
|
||||
|
||||
.nav-wrapper {
|
||||
.nav-top-section {
|
||||
.shortcut-nav-items {
|
||||
.nav-section-title,
|
||||
.nav-section-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-section-subtitle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-items-section {
|
||||
display: flex;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.nav-title-section {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
gap: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.more-nav-items {
|
||||
.nav-section-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-items-section {
|
||||
display: flex;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.nav-title-section {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-bottom-section {
|
||||
.secondary-nav-items {
|
||||
width: 64px;
|
||||
width: 54px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,7 +567,7 @@
|
||||
border-radius: 12px;
|
||||
background: var(--Robin-500, #4e74f8);
|
||||
|
||||
color: var(--Vanilla-100, #fff);
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
font-variant-numeric: lining-nums tabular-nums slashed-zero;
|
||||
font-feature-settings: 'case' on, 'cpsp' on, 'dlig' on, 'salt' on;
|
||||
font-family: Inter;
|
||||
@@ -479,7 +580,7 @@
|
||||
}
|
||||
|
||||
.sidenav-beta-tag {
|
||||
color: var(--Vanilla-100, #fff);
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
font-variant-numeric: lining-nums tabular-nums slashed-zero;
|
||||
font-feature-settings: 'case' on, 'cpsp' on, 'dlig' on, 'salt' on;
|
||||
font-family: Inter;
|
||||
@@ -494,7 +595,47 @@
|
||||
background: var(--bg-slate-300);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:not(.pinned) {
|
||||
.nav-item {
|
||||
.nav-item-data {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-nav-items,
|
||||
.more-nav-items {
|
||||
.nav-section-title {
|
||||
padding: 0 17px;
|
||||
|
||||
.nav-section-title-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.dropdown-open {
|
||||
.nav-item {
|
||||
.nav-item-data {
|
||||
flex-grow: 1;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-nav-items,
|
||||
.more-nav-items {
|
||||
.nav-section-title {
|
||||
padding: 0 17px;
|
||||
|
||||
.nav-section-title-icon {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.pinned):hover,
|
||||
&.dropdown-open {
|
||||
flex: 0 0 240px;
|
||||
max-width: 240px;
|
||||
min-width: 240px;
|
||||
@@ -505,8 +646,17 @@
|
||||
z-index: 10;
|
||||
background: #0b0c0e;
|
||||
|
||||
.brand-container {
|
||||
padding: 8px 15px;
|
||||
}
|
||||
|
||||
.brand {
|
||||
justify-content: space-between;
|
||||
justify-content: flex-start;
|
||||
|
||||
.brand-company-meta {
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.brand-title-section {
|
||||
display: flex;
|
||||
@@ -533,6 +683,11 @@
|
||||
.nav-section-title-icon {
|
||||
&.reorder {
|
||||
display: flex;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -574,7 +729,7 @@
|
||||
flex-direction: row;
|
||||
gap: 3px;
|
||||
border-radius: 20px;
|
||||
background: var(--Slate-400, #1d212d);
|
||||
background: var(--bg-slate-400, #1d212d);
|
||||
|
||||
/* Drop Shadow */
|
||||
box-shadow: 0px 103px 12px 0px rgba(0, 0, 0, 0.01),
|
||||
@@ -590,7 +745,7 @@
|
||||
width: 140px;
|
||||
|
||||
.scroll-for-more-label {
|
||||
color: var(--Vanilla-400, #c0c1c3);
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
@@ -631,6 +786,13 @@
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
.nav-item-data {
|
||||
flex-grow: 1;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.get-started-nav-items {
|
||||
@@ -664,8 +826,17 @@
|
||||
z-index: 10;
|
||||
background: #0b0c0e;
|
||||
|
||||
.brand-container {
|
||||
padding: 8px 15px;
|
||||
}
|
||||
|
||||
.brand {
|
||||
justify-content: space-between;
|
||||
justify-content: flex-start;
|
||||
|
||||
.brand-company-meta {
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.brand-title-section {
|
||||
display: flex;
|
||||
@@ -692,6 +863,11 @@
|
||||
.nav-section-title-icon {
|
||||
&.reorder {
|
||||
display: flex;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -733,7 +909,7 @@
|
||||
flex-direction: row;
|
||||
gap: 3px;
|
||||
border-radius: 20px;
|
||||
background: var(--Slate-400, #1d212d);
|
||||
background: var(--bg-slate-400, #1d212d);
|
||||
|
||||
/* Drop Shadow */
|
||||
box-shadow: 0px 103px 12px 0px rgba(0, 0, 0, 0.01),
|
||||
@@ -751,7 +927,7 @@
|
||||
.scroll-for-more-label {
|
||||
display: block;
|
||||
|
||||
color: var(--Vanilla-400, #c0c1c3);
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
@@ -856,7 +1032,7 @@
|
||||
|
||||
.ant-dropdown-menu-item {
|
||||
.ant-dropdown-menu-title-content {
|
||||
color: var(--Vanilla-400, #c0c1c3);
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
@@ -864,6 +1040,12 @@
|
||||
line-height: normal;
|
||||
letter-spacing: 0.14px;
|
||||
}
|
||||
|
||||
&:hover:not(.ant-dropdown-menu-item-disabled) {
|
||||
.ant-dropdown-menu-title-content {
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -875,7 +1057,7 @@
|
||||
gap: 8px;
|
||||
|
||||
.user-settings-dropdown-label-text {
|
||||
color: var(--Slate-50, #62687c);
|
||||
color: var(--bg-slate-50, #62687c);
|
||||
font-family: Inter;
|
||||
font-size: 10px;
|
||||
font-family: Inter;
|
||||
@@ -887,7 +1069,7 @@
|
||||
}
|
||||
|
||||
.user-settings-dropdown-label-email {
|
||||
color: var(--Vanilla-400, #c0c1c3);
|
||||
color: var(--bg-vanilla-400, #c0c1c3);
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
@@ -897,12 +1079,16 @@
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item-divider {
|
||||
background-color: var(--Slate-500, #161922) !important;
|
||||
background-color: var(--bg-slate-500, #161922) !important;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item-disabled {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.settings-dropdown,
|
||||
@@ -912,6 +1098,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
.secondary-nav-items {
|
||||
.nav-item {
|
||||
position: relative;
|
||||
|
||||
.nav-item-active-marker {
|
||||
position: absolute;
|
||||
left: -5px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
margin: 0;
|
||||
width: 8px;
|
||||
height: 24px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item-data {
|
||||
margin-left: 8px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.reorder-shortcut-nav-items-modal {
|
||||
width: 384px !important;
|
||||
|
||||
@@ -1028,7 +1235,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
background: var(--Robin-500, #4e74f8) !important;
|
||||
color: var(--bg-vanilla-100) !important;
|
||||
font-family: Inter;
|
||||
@@ -1038,10 +1244,10 @@
|
||||
line-height: 24px;
|
||||
|
||||
&.secondary-btn {
|
||||
background-color: var(--Slate-500, #161922) !important;
|
||||
background-color: var(--bg-slate-500, #161922) !important;
|
||||
border: 1px solid var(--bg-slate-500) !important;
|
||||
|
||||
color: var(--Vanilla-400, #c0c1c3) !important;
|
||||
color: var(--bg-vanilla-400, #c0c1c3) !important;
|
||||
|
||||
/* button/ small */
|
||||
font-family: Inter;
|
||||
@@ -1064,6 +1270,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.help-support-dropdown li.ant-dropdown-menu-item-divider {
|
||||
background-color: var(--bg-slate-500, #161922) !important;
|
||||
}
|
||||
|
||||
.lightMode {
|
||||
.sideNav {
|
||||
background: var(--bg-vanilla-100);
|
||||
@@ -1095,8 +1305,32 @@
|
||||
.get-started-nav-items {
|
||||
.get-started-btn {
|
||||
border: 1px solid var(--bg-vanilla-300);
|
||||
background: var(--bg-vanilla-100);
|
||||
color: var(--bg-ink-400);
|
||||
background: var(--bg-vanilla-200);
|
||||
color: var(--bg-slate-50, #62687c);
|
||||
|
||||
svg {
|
||||
color: var(--bg-slate-50, #62687c);
|
||||
}
|
||||
|
||||
.nav-item-label {
|
||||
color: var(--bg-ink-400, #62687c);
|
||||
}
|
||||
|
||||
// Hover state (light mode)
|
||||
&:hover:not(:disabled) {
|
||||
background: var(--bg-vanilla-300);
|
||||
border-color: var(--bg-vanilla-300);
|
||||
|
||||
color: var(--bg-slate-500, #161922);
|
||||
|
||||
svg {
|
||||
color: var(--bg-slate-500, #161922);
|
||||
}
|
||||
|
||||
.nav-item-label {
|
||||
color: var(--bg-slate-500, #161922);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1108,7 +1342,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
.brand-container {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav-wrapper {
|
||||
.nav-top-section {
|
||||
.shortcut-nav-items {
|
||||
.nav-section-title {
|
||||
.nav-section-title-icon {
|
||||
&.reorder {
|
||||
&:hover {
|
||||
color: var(--bg-slate-400, #1d212d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.secondary-nav-items {
|
||||
border-top: 1px solid var(--bg-vanilla-300);
|
||||
|
||||
@@ -1123,8 +1375,43 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&.pinned {
|
||||
.nav-wrapper {
|
||||
.nav-top-section {
|
||||
.shortcut-nav-items {
|
||||
.nav-section-title {
|
||||
.nav-section-title-icon {
|
||||
&.reorder {
|
||||
&:hover {
|
||||
color: var(--bg-slate-400, #1d212d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.pinned):hover,
|
||||
&.dropdown-open {
|
||||
background: var(--bg-vanilla-100);
|
||||
|
||||
.nav-wrapper {
|
||||
.nav-top-section {
|
||||
.shortcut-nav-items {
|
||||
.nav-section-title {
|
||||
.nav-section-title-icon {
|
||||
&.reorder {
|
||||
&:hover {
|
||||
color: var(--bg-slate-400, #1d212d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1134,6 +1421,12 @@
|
||||
.ant-dropdown-menu-title-content {
|
||||
color: var(--bg-ink-400);
|
||||
}
|
||||
|
||||
&:hover:not(.ant-dropdown-menu-item-disabled) {
|
||||
.ant-dropdown-menu-title-content {
|
||||
color: var(--bg-ink-500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1210,6 +1503,10 @@
|
||||
color: var(--bg-ink-400);
|
||||
}
|
||||
}
|
||||
|
||||
.help-support-dropdown li.ant-dropdown-menu-item-divider {
|
||||
background-color: var(--bg-vanilla-300) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.version-tooltip-overlay {
|
||||
@@ -1222,7 +1519,7 @@
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--bg-slate-500);
|
||||
|
||||
color: var(--Vanilla-100, #fff);
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
font-family: Inter;
|
||||
font-size: 11px;
|
||||
font-style: normal;
|
||||
@@ -1237,7 +1534,7 @@
|
||||
gap: 4px;
|
||||
|
||||
.version-update-notification-tooltip-title {
|
||||
color: var(--Vanilla-100, #fff);
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
font-family: Inter;
|
||||
font-size: 11px;
|
||||
font-style: normal;
|
||||
@@ -1247,7 +1544,7 @@
|
||||
}
|
||||
|
||||
.version-update-notification-tooltip-content {
|
||||
color: var(--Vanilla-100, #fff);
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
font-family: Inter;
|
||||
font-size: 10px;
|
||||
font-style: normal;
|
||||
|
||||
@@ -157,18 +157,27 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
DefaultHelpSupportDropdownMenuItems,
|
||||
);
|
||||
|
||||
const [pinnedMenuItems, setPinnedMenuItems] = useState<SidebarItem[]>([]);
|
||||
|
||||
const [tempPinnedMenuItems, setTempPinnedMenuItems] = useState<SidebarItem[]>(
|
||||
[],
|
||||
);
|
||||
|
||||
const [secondaryMenuItems, setSecondaryMenuItems] = useState<SidebarItem[]>(
|
||||
[],
|
||||
);
|
||||
|
||||
const [hasScroll, setHasScroll] = useState(false);
|
||||
const navTopSectionRef = useRef<HTMLDivElement>(null);
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const [pinnedMenuItems, setPinnedMenuItems] = useState<SidebarItem[]>([]);
|
||||
const [secondaryMenuItems, setSecondaryMenuItems] = useState<SidebarItem[]>(
|
||||
[],
|
||||
);
|
||||
|
||||
const handleMouseEnter = useCallback(() => {
|
||||
setIsHovered(true);
|
||||
}, []);
|
||||
|
||||
const handleMouseLeave = useCallback(() => {
|
||||
setIsHovered(false);
|
||||
}, []);
|
||||
|
||||
const checkScroll = useCallback((): void => {
|
||||
if (navTopSectionRef.current) {
|
||||
@@ -217,63 +226,68 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
const isAdmin = user.role === USER_ROLES.ADMIN;
|
||||
const isEditor = user.role === USER_ROLES.EDITOR;
|
||||
|
||||
useEffect(() => {
|
||||
const navShortcuts = (userPreferences?.find(
|
||||
// Compute initial pinned items and secondary menu items synchronously to avoid flash
|
||||
const computedPinnedMenuItems = useMemo(() => {
|
||||
const navShortcutsPreference = userPreferences?.find(
|
||||
(preference) => preference.name === USER_PREFERENCES.NAV_SHORTCUTS,
|
||||
)?.value as unknown) as string[];
|
||||
);
|
||||
const navShortcuts = (navShortcutsPreference?.value as unknown) as
|
||||
| string[]
|
||||
| undefined;
|
||||
|
||||
const shouldShowIntegrations =
|
||||
(isCloudUser || isEnterpriseSelfHostedUser) && (isAdmin || isEditor);
|
||||
// If userPreferences not loaded yet, return empty to avoid showing defaults before preferences load
|
||||
if (userPreferences === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (navShortcuts && isArray(navShortcuts) && navShortcuts.length > 0) {
|
||||
// nav shortcuts is array of strings
|
||||
const pinnedItems = navShortcuts
|
||||
// If preference exists with non-empty array, use stored shortcuts
|
||||
if (isArray(navShortcuts) && navShortcuts.length > 0) {
|
||||
return navShortcuts
|
||||
.map((shortcut) =>
|
||||
defaultMoreMenuItems.find((item) => item.itemKey === shortcut),
|
||||
)
|
||||
.filter((item): item is SidebarItem => item !== undefined);
|
||||
|
||||
// Set pinned items in the order they were stored
|
||||
setPinnedMenuItems(pinnedItems);
|
||||
|
||||
setSecondaryMenuItems(
|
||||
defaultMoreMenuItems.map((item) => ({
|
||||
...item,
|
||||
isPinned: pinnedItems.some((pinned) => pinned.itemKey === item.itemKey),
|
||||
isEnabled:
|
||||
item.key === ROUTES.INTEGRATIONS
|
||||
? shouldShowIntegrations
|
||||
: item.isEnabled,
|
||||
})),
|
||||
);
|
||||
} else {
|
||||
// Set default pinned items
|
||||
const defaultPinnedItems = defaultMoreMenuItems.filter(
|
||||
(item) => item.isPinned,
|
||||
);
|
||||
setPinnedMenuItems(defaultPinnedItems);
|
||||
|
||||
setSecondaryMenuItems(
|
||||
defaultMoreMenuItems.map((item) => ({
|
||||
...item,
|
||||
isPinned: defaultPinnedItems.some(
|
||||
(pinned) => pinned.itemKey === item.itemKey,
|
||||
),
|
||||
isEnabled:
|
||||
item.key === ROUTES.INTEGRATIONS
|
||||
? shouldShowIntegrations
|
||||
: item.isEnabled,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
// No preference, or empty array → use defaults
|
||||
return defaultMoreMenuItems.filter((item) => item.isPinned);
|
||||
}, [userPreferences]);
|
||||
|
||||
const computedSecondaryMenuItems = useMemo(() => {
|
||||
const shouldShowIntegrationsValue =
|
||||
(isCloudUser || isEnterpriseSelfHostedUser) && (isAdmin || isEditor);
|
||||
|
||||
return defaultMoreMenuItems.map((item) => ({
|
||||
...item,
|
||||
isPinned: computedPinnedMenuItems.some(
|
||||
(pinned) => pinned.itemKey === item.itemKey,
|
||||
),
|
||||
isEnabled:
|
||||
item.key === ROUTES.INTEGRATIONS
|
||||
? shouldShowIntegrationsValue
|
||||
: item.isEnabled,
|
||||
}));
|
||||
}, [
|
||||
userPreferences,
|
||||
computedPinnedMenuItems,
|
||||
isCloudUser,
|
||||
isEnterpriseSelfHostedUser,
|
||||
isAdmin,
|
||||
isEditor,
|
||||
]);
|
||||
|
||||
// Track if we've done the initial sync (to avoid overwriting user actions during session)
|
||||
const hasInitializedRef = useRef(false);
|
||||
|
||||
// Sync state only on initial load when userPreferences first becomes available
|
||||
useEffect(() => {
|
||||
// Only sync once: when userPreferences loads for the first time
|
||||
if (!hasInitializedRef.current && userPreferences !== null) {
|
||||
setPinnedMenuItems(computedPinnedMenuItems);
|
||||
setSecondaryMenuItems(computedSecondaryMenuItems);
|
||||
hasInitializedRef.current = true;
|
||||
}
|
||||
}, [computedPinnedMenuItems, computedSecondaryMenuItems, userPreferences]);
|
||||
|
||||
const isOnboardingV3Enabled = featureFlags?.find(
|
||||
(flag) => flag.name === FeatureKeys.ONBOARDING_V3,
|
||||
)?.active;
|
||||
@@ -327,6 +341,17 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
.map((item) => item.itemKey)
|
||||
.filter(Boolean) as string[];
|
||||
|
||||
// Update context immediately (optimistically) so computed values reflect the change
|
||||
updateUserPreferenceInContext({
|
||||
name: USER_PREFERENCES.NAV_SHORTCUTS,
|
||||
description: USER_PREFERENCES.NAV_SHORTCUTS,
|
||||
valueType: 'array',
|
||||
defaultValue: false,
|
||||
allowedValues: [],
|
||||
allowedScopes: ['user'],
|
||||
value: navShortcuts,
|
||||
});
|
||||
|
||||
updateUserPreferenceMutation(
|
||||
{
|
||||
name: USER_PREFERENCES.NAV_SHORTCUTS,
|
||||
@@ -335,6 +360,7 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
{
|
||||
onSuccess: (response) => {
|
||||
if (response.data) {
|
||||
// Update context again on success to ensure consistency
|
||||
updateUserPreferenceInContext({
|
||||
name: USER_PREFERENCES.NAV_SHORTCUTS,
|
||||
description: USER_PREFERENCES.NAV_SHORTCUTS,
|
||||
@@ -368,13 +394,13 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
if (isCurrentlyPinned) {
|
||||
return prevItems.filter((i) => i.key !== item.key);
|
||||
}
|
||||
return [item, ...prevItems];
|
||||
return [...prevItems, item];
|
||||
});
|
||||
|
||||
// Get the updated pinned menu items for preference update
|
||||
const updatedPinnedItems = pinnedMenuItems.some((i) => i.key === item.key)
|
||||
? pinnedMenuItems.filter((i) => i.key !== item.key)
|
||||
: [item, ...pinnedMenuItems];
|
||||
: [...pinnedMenuItems, item];
|
||||
|
||||
// Update user preference with the ordered list of item keys
|
||||
updateNavShortcutsPreference(updatedPinnedItems);
|
||||
@@ -455,6 +481,10 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
pathname,
|
||||
]);
|
||||
|
||||
const isSettingsPage = useMemo(() => pathname.startsWith(ROUTES.SETTINGS), [
|
||||
pathname,
|
||||
]);
|
||||
|
||||
const userSettingsDropdownMenuItems: MenuProps['items'] = useMemo(
|
||||
() =>
|
||||
[
|
||||
@@ -594,7 +624,7 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
label: "WHAT's NEW",
|
||||
label: "WHAT'S NEW",
|
||||
},
|
||||
...dropdownItems,
|
||||
{
|
||||
@@ -750,6 +780,15 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
[secondaryMenuItems],
|
||||
);
|
||||
|
||||
// Get active "More" items that should be visible in collapsed state
|
||||
const activeMoreMenuItems = useMemo(
|
||||
() => moreMenuItems.filter((item) => activeMenuKey === item.key),
|
||||
[moreMenuItems, activeMenuKey],
|
||||
);
|
||||
|
||||
// Check if sidebar is collapsed (not pinned, not hovered, and no dropdown open)
|
||||
const isCollapsed = !isPinned && !isHovered && !isDropdownOpen;
|
||||
|
||||
const renderNavItems = (
|
||||
items: SidebarItem[],
|
||||
allowPin?: boolean,
|
||||
@@ -901,7 +940,15 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
|
||||
return (
|
||||
<div className={cx('sidenav-container', isPinned && 'pinned')}>
|
||||
<div className={cx('sideNav', isPinned && 'pinned')}>
|
||||
<div
|
||||
className={cx(
|
||||
'sideNav',
|
||||
isPinned && 'pinned',
|
||||
isDropdownOpen && 'dropdown-open',
|
||||
)}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<div className="brand-container">
|
||||
<div className="brand">
|
||||
<div className="brand-company-meta">
|
||||
@@ -999,35 +1046,43 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
{renderNavItems(primaryMenuItems)}
|
||||
</div>
|
||||
|
||||
<div className="shortcut-nav-items">
|
||||
<div className="nav-title-section">
|
||||
<div className="nav-section-title">
|
||||
<div className="nav-section-title-icon">
|
||||
<MousePointerClick size={16} />
|
||||
</div>
|
||||
{(pinnedMenuItems.length > 0 || !isCollapsed) && (
|
||||
<div
|
||||
className={cx('shortcut-nav-items', isCollapsed && 'sidebar-collapsed')}
|
||||
>
|
||||
{!isCollapsed && (
|
||||
<div className="nav-title-section">
|
||||
<div className="nav-section-title">
|
||||
<div className="nav-section-title-icon">
|
||||
<MousePointerClick size={16} />
|
||||
</div>
|
||||
|
||||
<div className="nav-section-title-text">SHORTCUTS</div>
|
||||
<div className="nav-section-title-text">SHORTCUTS</div>
|
||||
|
||||
{pinnedMenuItems.length > 1 && (
|
||||
<div
|
||||
className="nav-section-title-icon reorder"
|
||||
onClick={(): void => {
|
||||
logEvent('Sidebar V2: Manage shortcuts clicked', {});
|
||||
setIsReorderShortcutNavItemsModalOpen(true);
|
||||
}}
|
||||
>
|
||||
<Logs size={16} />
|
||||
{pinnedMenuItems.length > 1 && (
|
||||
<Tooltip title="Manage shortcuts" placement="right">
|
||||
<div
|
||||
className="nav-section-title-icon reorder"
|
||||
onClick={(): void => {
|
||||
logEvent('Sidebar V2: Manage shortcuts clicked', {});
|
||||
setIsReorderShortcutNavItemsModalOpen(true);
|
||||
}}
|
||||
>
|
||||
<Logs size={16} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{pinnedMenuItems.length === 0 && (
|
||||
<div className="nav-section-subtitle">
|
||||
You have not added any shortcuts yet.
|
||||
{pinnedMenuItems.length === 0 && (
|
||||
<div className="nav-section-subtitle">
|
||||
You have not added any shortcuts yet.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{pinnedMenuItems.length > 0 && (
|
||||
{(pinnedMenuItems.length > 0 || isCollapsed) && (
|
||||
<div className="nav-items-section">
|
||||
{renderNavItems(
|
||||
pinnedMenuItems.filter((item) => item.isEnabled),
|
||||
@@ -1036,46 +1091,60 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{moreMenuItems.length > 0 && (
|
||||
<div
|
||||
className={cx(
|
||||
'more-nav-items',
|
||||
isMoreMenuCollapsed ? 'collapsed' : 'expanded',
|
||||
isCollapsed && 'sidebar-collapsed',
|
||||
)}
|
||||
>
|
||||
<div className="nav-title-section">
|
||||
<div
|
||||
className="nav-section-title"
|
||||
onClick={(): void => {
|
||||
logEvent('Sidebar V2: More menu clicked', {
|
||||
action: isMoreMenuCollapsed ? 'expand' : 'collapse',
|
||||
});
|
||||
setIsMoreMenuCollapsed(!isMoreMenuCollapsed);
|
||||
}}
|
||||
>
|
||||
<div className="nav-section-title-icon">
|
||||
<Ellipsis size={16} />
|
||||
</div>
|
||||
{!isCollapsed && (
|
||||
<div className="nav-title-section">
|
||||
<div
|
||||
className="nav-section-title"
|
||||
onClick={(): void => {
|
||||
// Only allow toggling when sidebar is open (pinned, hovered, or dropdown open)
|
||||
if (isCollapsed) {
|
||||
return;
|
||||
}
|
||||
const newCollapsedState = !isMoreMenuCollapsed;
|
||||
logEvent('Sidebar V2: More menu clicked', {
|
||||
action: isMoreMenuCollapsed ? 'expand' : 'collapse',
|
||||
});
|
||||
setIsMoreMenuCollapsed(newCollapsedState);
|
||||
}}
|
||||
>
|
||||
<div className="nav-section-title-icon">
|
||||
<Ellipsis size={16} />
|
||||
</div>
|
||||
|
||||
<div className="nav-section-title-text">MORE</div>
|
||||
<div className="nav-section-title-text">MORE</div>
|
||||
|
||||
<div className="collapse-expand-section-icon">
|
||||
{isMoreMenuCollapsed ? (
|
||||
<ChevronDown size={16} />
|
||||
) : (
|
||||
<ChevronUp size={16} />
|
||||
)}
|
||||
<div className="collapse-expand-section-icon">
|
||||
{isMoreMenuCollapsed ? (
|
||||
<ChevronDown size={16} />
|
||||
) : (
|
||||
<ChevronUp size={16} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="nav-items-section">
|
||||
{renderNavItems(
|
||||
moreMenuItems.filter((item) => item.isEnabled),
|
||||
true,
|
||||
)}
|
||||
{/* Show all items when expanded, only active items when collapsed */}
|
||||
{isCollapsed
|
||||
? renderNavItems(
|
||||
activeMoreMenuItems.filter((item) => item.isEnabled),
|
||||
true,
|
||||
)
|
||||
: renderNavItems(
|
||||
moreMenuItems.filter((item) => item.isEnabled),
|
||||
true,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -1102,6 +1171,7 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
placement="topLeft"
|
||||
overlayClassName="nav-dropdown-overlay help-support-dropdown"
|
||||
trigger={['click']}
|
||||
onOpenChange={(open): void => setIsDropdownOpen(open)}
|
||||
>
|
||||
<div className="nav-item">
|
||||
<div className="nav-item-data" data-testid="help-support-nav-item">
|
||||
@@ -1122,8 +1192,10 @@ function SideNav({ isPinned }: { isPinned: boolean }): JSX.Element {
|
||||
placement="topLeft"
|
||||
overlayClassName="nav-dropdown-overlay settings-dropdown"
|
||||
trigger={['click']}
|
||||
onOpenChange={(open): void => setIsDropdownOpen(open)}
|
||||
>
|
||||
<div className="nav-item">
|
||||
<div className={cx('nav-item', isSettingsPage && 'active')}>
|
||||
<div className="nav-item-active-marker" />
|
||||
<div className="nav-item-data" data-testid="settings-nav-item">
|
||||
<div className="nav-item-icon">{userSettingsMenuItem.icon}</div>
|
||||
|
||||
|
||||
@@ -33,6 +33,19 @@
|
||||
height: calc(100vh - 48px);
|
||||
border-right: 1px solid var(--Slate-500, #161922);
|
||||
background: var(--Ink-500, #0b0c0e);
|
||||
margin-top: 4px;
|
||||
|
||||
.nav-item {
|
||||
.nav-item-data {
|
||||
margin: 0px 8px 0px 4px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
.nav-item-data .nav-item-label {
|
||||
color: var(--bg-vanilla-100, #fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.settings-page-content {
|
||||
@@ -81,6 +94,14 @@
|
||||
.settings-page-sidenav {
|
||||
border-right: 1px solid var(--bg-vanilla-300);
|
||||
background: var(--bg-vanilla-100);
|
||||
|
||||
.nav-item {
|
||||
&.active {
|
||||
.nav-item-data .nav-item-label {
|
||||
color: var(--bg-ink-500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.settings-page-content {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { SidebarItem } from 'container/SideNav/sideNav.types';
|
||||
import useComponentPermission from 'hooks/useComponentPermission';
|
||||
import { useGetTenantLicense } from 'hooks/useGetTenantLicense';
|
||||
import history from 'lib/history';
|
||||
import { Wrench } from 'lucide-react';
|
||||
import { Cog } from 'lucide-react';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
import { USER_ROLES } from 'types/roles';
|
||||
|
||||
@@ -236,7 +236,7 @@ function SettingsPage(): JSX.Element {
|
||||
className="settings-page-header-title"
|
||||
data-testid="settings-page-title"
|
||||
>
|
||||
<Wrench size={16} />
|
||||
<Cog size={16} />
|
||||
Settings
|
||||
</div>
|
||||
</header>
|
||||
|
||||
Reference in New Issue
Block a user