Skip to content

Commit 513decd

Browse files
committed
colapsible menu icon added
1 parent e00abdf commit 513decd

3 files changed

Lines changed: 124 additions & 2 deletions

File tree

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,7 @@ onclick: () => openDashboardPane(outliner, element.tabName || element.paneName)
104104
* Auto: each #sym:MenuItem has an icon which i want displayed on the left side of each menu item when rendered
105105

106106
* Auto: don't add each menu item in a button looking border. Simply list them.
107-
Upon hover apply background color e6dcff and selected or active to be background color: cbb9ff
107+
Upon hover apply background color e6dcff and selected or active to be background color: cbb9ff
108+
109+
* Raptor mini: the menu dissapears not when on mobile. That is great.
110+
I want the menu to have a tiny button on the bottom margin left with an arrow to the left or right for expanding the menu or for making it small. This is only for web. When we make it small it folds and only displays the icons of teh menu items, when it is expanded it should also add the labels to the menu items.

src/mainPage/menu.css

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@
6666
z-index: 100;
6767
}
6868

69+
.app-nav {
70+
position: relative;
71+
}
72+
6973
.app-nav.mobile-hidden {
7074
transform: translateX(-100%);
7175
transition: transform 0.25s ease-in-out;
@@ -81,4 +85,48 @@
8185
transform: translateX(0);
8286
display: block;
8387
visibility: visible;
88+
}
89+
90+
.app-nav.collapsed {
91+
width: 4.5rem;
92+
min-width: 4.5rem;
93+
}
94+
95+
.app-nav.collapsed .menu-content {
96+
gap: 0.25rem;
97+
align-items: center;
98+
}
99+
100+
.app-nav.collapsed .menu-item {
101+
justify-content: center;
102+
padding-left: 0.5rem;
103+
padding-right: 0.5rem;
104+
}
105+
106+
.app-nav.collapsed .menu-item-label {
107+
display: none;
108+
}
109+
110+
.menu-collapse {
111+
position: fixed;
112+
left: 3rem;
113+
bottom: 5rem;
114+
z-index: 320;
115+
width: 1.25rem;
116+
height: 1.25rem;
117+
display: inline-flex;
118+
align-items: center;
119+
justify-content: center;
120+
border: 1px solid var(--color-border);
121+
border-radius: 999px;
122+
color: var(--color-text);
123+
font-size: 0.75rem;
124+
line-height: 1;
125+
cursor: pointer;
126+
}
127+
128+
@media (max-width: 768px) {
129+
.menu-collapse {
130+
display: none;
131+
}
84132
}

src/mainPage/menu.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,51 @@ type MenuItem = {
1313
onclick: () => void | Promise<void>
1414
}
1515

16+
const MENU_COLLAPSED_KEY = 'solid-panes-menu-collapsed'
17+
let menuCollapsed = false
18+
19+
const loadMenuCollapsedState = (): boolean => {
20+
try {
21+
return localStorage.getItem(MENU_COLLAPSED_KEY) === 'true'
22+
} catch (error) {
23+
return false
24+
}
25+
}
26+
27+
const saveMenuCollapsedState = (collapsed: boolean): void => {
28+
try {
29+
localStorage.setItem(MENU_COLLAPSED_KEY, String(collapsed))
30+
} catch (error) {
31+
// ignore storage errors
32+
}
33+
}
34+
35+
const updateMenuCollapseButton = (): void => {
36+
const collapseBtn = document.getElementById('MenuCollapseBtn') as HTMLButtonElement | null
37+
if (!collapseBtn) return
38+
collapseBtn.textContent = menuCollapsed ? '\u203A' : '\u2039'
39+
collapseBtn.setAttribute('aria-label', menuCollapsed ? 'Expand navigation menu' : 'Collapse navigation menu')
40+
}
41+
42+
const updateCollapseButtonPosition = (navMenu: HTMLElement | null, collapseBtn: HTMLButtonElement | null): void => {
43+
if (!navMenu || !collapseBtn) return
44+
const navRect = navMenu.getBoundingClientRect()
45+
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16
46+
const buttonWidth = parseFloat(getComputedStyle(collapseBtn).width) || 1.25 * rootFontSize
47+
const offsetRem = (navRect.width - buttonWidth / 2) / rootFontSize
48+
collapseBtn.style.setProperty('left', `${offsetRem.toFixed(3)}rem`, 'important')
49+
}
50+
51+
const applyMenuCollapsedState = (navMenu: HTMLElement | null): void => {
52+
if (!navMenu) return
53+
navMenu.classList.toggle('collapsed', menuCollapsed)
54+
updateMenuCollapseButton()
55+
const collapseBtn = document.getElementById('MenuCollapseBtn') as HTMLButtonElement | null
56+
updateCollapseButtonPosition(navMenu, collapseBtn)
57+
}
58+
1659
const ensureMenuSkeleton = () => {
60+
menuCollapsed = loadMenuCollapsedState()
1761
const root = document.querySelector('[role="main"]') || document.body
1862

1963
let navMenu = document.getElementById('NavMenu') as HTMLElement | null
@@ -55,6 +99,18 @@ const ensureMenuSkeleton = () => {
5599
overlay.hidden = true
56100
document.body.appendChild(overlay)
57101
}
102+
103+
let collapseBtn = document.getElementById('MenuCollapseBtn') as HTMLButtonElement | null
104+
if (!collapseBtn) {
105+
collapseBtn = document.createElement('button')
106+
collapseBtn.id = 'MenuCollapseBtn'
107+
collapseBtn.className = 'menu-collapse'
108+
collapseBtn.type = 'button'
109+
collapseBtn.setAttribute('aria-label', 'Collapse navigation menu')
110+
collapseBtn.textContent = '\u2039'
111+
collapseBtn.hidden = true
112+
document.body.appendChild(collapseBtn)
113+
}
58114
}
59115

60116
const getMenuItems = async (subject: NamedNode, outliner: any): Promise<MenuItem[]> => {
@@ -146,22 +202,28 @@ const renderMenuItems = async (subject: NamedNode, outliner: OutlineManager, con
146202
export const refreshMenu = (layout: 'mobile' | 'desktop') => {
147203
const navMenu = document.getElementById('NavMenu') as HTMLElement | null
148204
const toggle = document.getElementById('MenuToggleBtn') as HTMLButtonElement | null
205+
const collapseBtn = document.getElementById('MenuCollapseBtn') as HTMLButtonElement | null
149206
const overlay = document.getElementById('MenuOverlay') as HTMLElement | null
150207

151-
if (!navMenu || !toggle || !overlay) return
208+
if (!navMenu || !toggle || !overlay || !collapseBtn) return
152209

153210
if (layout === 'mobile') {
154211
navMenu.classList.add('mobile-hidden')
155212
navMenu.classList.remove('mobile-visible')
156213
toggle.hidden = false
214+
collapseBtn.hidden = true
157215
overlay.hidden = true
158216
navMenu.hidden = false
217+
navMenu.classList.remove('collapsed')
159218
toggle.setAttribute('aria-expanded', 'false')
160219
} else {
161220
navMenu.classList.remove('mobile-hidden', 'mobile-visible')
162221
toggle.hidden = true
222+
collapseBtn.hidden = false
163223
overlay.hidden = true
164224
navMenu.hidden = false
225+
applyMenuCollapsedState(navMenu)
226+
updateCollapseButtonPosition(navMenu, collapseBtn)
165227
toggle.setAttribute('aria-expanded', 'false')
166228
}
167229
}
@@ -200,6 +262,15 @@ export const createLeftSideMenu = async (subject: NamedNode, outliner: OutlineMa
200262
})
201263
}
202264

265+
const collapseBtn = document.getElementById('MenuCollapseBtn') as HTMLButtonElement | null
266+
if (collapseBtn) {
267+
collapseBtn.addEventListener('click', () => {
268+
menuCollapsed = !menuCollapsed
269+
saveMenuCollapsedState(menuCollapsed)
270+
applyMenuCollapsedState(navMenu)
271+
})
272+
}
273+
203274
if (menuOverlay) {
204275
menuOverlay.addEventListener('click', closeMobileMenu)
205276
}

0 commit comments

Comments
 (0)