Skip to content

Commit 889ce33

Browse files
authored
Merge pull request #4 from LeagueToolkit/ui-improvements
feat: add resizable sidebar functionality (issue #3)
2 parents 4db3688 + a4ebd28 commit 889ce33

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

site/astro.config.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export default defineConfig({
3434
href: "https://github.com/LeagueToolkit/lol-meta-wiki",
3535
},
3636
],
37+
components: {
38+
Sidebar: './src/components/starlight/ResizableSidebar.astro',
39+
},
3740
sidebar: [
3841
{
3942
label: "Guides",
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
---
2+
import type { Props } from '@astrojs/starlight/props';
3+
import DefaultSidebar from '@astrojs/starlight/components/Sidebar.astro';
4+
5+
const props = Astro.props;
6+
---
7+
8+
<script is:inline>
9+
// Run immediately to restore saved width to prevent FOUC
10+
try {
11+
const savedWidth = localStorage.getItem('starlight-sidebar-width');
12+
if (savedWidth) {
13+
document.documentElement.style.setProperty('--sl-sidebar-width', savedWidth);
14+
}
15+
} catch (e) { /* ignore */ }
16+
</script>
17+
18+
<DefaultSidebar {...props} />
19+
<div id="sidebar-resize-handle" class="resize-handle" aria-hidden="true">
20+
<div class="resize-handle-line"></div>
21+
</div>
22+
23+
<script>
24+
class SidebarResizer {
25+
handle: HTMLElement;
26+
isResizing: boolean = false;
27+
startX: number = 0;
28+
startWidth: number = 0;
29+
30+
constructor(handle: HTMLElement) {
31+
this.handle = handle;
32+
33+
// Bind events
34+
this.handle.addEventListener('mousedown', this.startResize.bind(this));
35+
document.addEventListener('mousemove', this.resize.bind(this));
36+
document.addEventListener('mouseup', this.stopResize.bind(this));
37+
38+
// Reset on double click
39+
this.handle.addEventListener('dblclick', () => {
40+
document.documentElement.style.removeProperty('--sl-sidebar-width');
41+
localStorage.removeItem('starlight-sidebar-width');
42+
});
43+
}
44+
45+
startResize(e: MouseEvent) {
46+
this.isResizing = true;
47+
this.startX = e.clientX;
48+
this.handle.classList.add('resizing');
49+
50+
// Calculate current width in pixels
51+
const rootStyle = getComputedStyle(document.documentElement);
52+
const sidebarWidthVar = rootStyle.getPropertyValue('--sl-sidebar-width').trim();
53+
54+
if (sidebarWidthVar.endsWith('px')) {
55+
this.startWidth = parseFloat(sidebarWidthVar);
56+
} else if (sidebarWidthVar.endsWith('rem')) {
57+
const rootFontSize = parseFloat(rootStyle.fontSize);
58+
this.startWidth = parseFloat(sidebarWidthVar) * (rootFontSize || 16);
59+
} else {
60+
// Default fallback if something is weird
61+
this.startWidth = 288;
62+
}
63+
64+
// Prevent text selection during resize
65+
document.body.style.userSelect = 'none';
66+
document.body.style.cursor = 'col-resize';
67+
}
68+
69+
resize(e: MouseEvent) {
70+
if (!this.isResizing) return;
71+
72+
const delta = e.clientX - this.startX;
73+
const newWidth = this.startWidth + delta;
74+
75+
// Min/Max constraints (200px to 50vw)
76+
const maxW = window.innerWidth * 0.5;
77+
if (newWidth < 200 || newWidth > maxW) return;
78+
79+
const widthStr = `${newWidth}px`;
80+
document.documentElement.style.setProperty('--sl-sidebar-width', widthStr);
81+
}
82+
83+
stopResize() {
84+
if (!this.isResizing) return;
85+
86+
this.isResizing = false;
87+
this.handle.classList.remove('resizing');
88+
document.body.style.userSelect = '';
89+
document.body.style.cursor = '';
90+
91+
// Save preference
92+
const currentWidth = document.documentElement.style.getPropertyValue('--sl-sidebar-width');
93+
if (currentWidth) {
94+
localStorage.setItem('starlight-sidebar-width', currentWidth);
95+
}
96+
}
97+
}
98+
99+
// Initialize
100+
const handle = document.getElementById('sidebar-resize-handle');
101+
if (handle) {
102+
new SidebarResizer(handle);
103+
}
104+
</script>
105+
106+
<style>
107+
.resize-handle {
108+
position: fixed;
109+
top: var(--sl-nav-height, 3.5rem);
110+
bottom: 0;
111+
left: var(--sl-sidebar-width);
112+
width: 12px;
113+
margin-left: -6px; /* Center on the line */
114+
cursor: col-resize;
115+
z-index: 2000; /* Ensure it's above most things */
116+
display: none; /* Hidden by default (mobile) */
117+
align-items: center;
118+
justify-content: center;
119+
touch-action: none;
120+
}
121+
122+
/* Only show on desktop */
123+
@media (min-width: 50rem) { /* 800px - Starlight mobile breakpoint */
124+
.resize-handle {
125+
display: flex;
126+
}
127+
}
128+
129+
.resize-handle-line {
130+
width: 2px;
131+
height: 100%;
132+
background-color: transparent;
133+
transition: background-color 0.2s;
134+
}
135+
136+
.resize-handle:hover .resize-handle-line,
137+
.resize-handle.resizing .resize-handle-line {
138+
background-color: var(--sl-color-accent, var(--color-brand-primary, #7c3aed));
139+
}
140+
</style>

0 commit comments

Comments
 (0)