Files
dflike/client/src/ui/LeftPanel.ts
T
2026-03-09 00:45:10 +00:00

268 lines
7.6 KiB
TypeScript

export class LeftPanel {
private container: HTMLDivElement;
private panel: HTMLDivElement;
private headerEl: HTMLDivElement;
private contentArea: HTMLDivElement;
private statsTab: HTMLDivElement;
private eventsTab: HTMLDivElement;
private inventionsTab: HTMLDivElement;
private inventionsContent: HTMLDivElement;
private notificationDot: HTMLDivElement;
private expanded = false;
private activeTab: 'stats' | 'events' | 'inventions' | null = null;
private superlativesContent: HTMLDivElement;
private eventsFeedContent: HTMLDivElement;
constructor(superlativesContent: HTMLDivElement, eventsFeedContent: HTMLDivElement, inventionsContent: HTMLDivElement) {
this.superlativesContent = superlativesContent;
this.eventsFeedContent = eventsFeedContent;
this.inventionsContent = inventionsContent;
// Outer container for positioning
this.container = document.createElement('div');
this.container.style.cssText = `
position: fixed;
left: 0;
top: 50%;
transform: translateY(-50%);
z-index: 1000;
display: flex;
flex-direction: row;
font-family: 'Press Start 2P', monospace;
transition: transform 0.35s ease;
`;
// Main panel
this.panel = document.createElement('div');
this.panel.style.cssText = `
width: 340px;
background: #1a1a2e;
border: 3px solid #e0d0b0;
border-left: none;
padding: 0;
box-sizing: border-box;
max-height: 80vh;
display: flex;
flex-direction: column;
`;
// Inner frame (EarthBound double-border)
const innerFrame = document.createElement('div');
innerFrame.style.cssText = `
border: 2px solid #8878a8;
margin: 4px;
padding: 8px;
display: flex;
flex-direction: column;
overflow: hidden;
flex: 1;
`;
// Header
this.headerEl = document.createElement('div');
this.headerEl.style.cssText = `
text-align: center;
color: #e0d0b0;
font-size: 16px;
padding: 4px 0 8px 0;
border-bottom: 1px solid #8878a8;
margin-bottom: 8px;
flex-shrink: 0;
`;
this.headerEl.textContent = 'SUPERLATIVES';
// Content area (swaps between superlatives and events)
this.contentArea = document.createElement('div');
this.contentArea.style.cssText = `
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
`;
innerFrame.appendChild(this.headerEl);
innerFrame.appendChild(this.contentArea);
this.panel.appendChild(innerFrame);
// Tab buttons container (stacked vertically on right edge)
const tabContainer = document.createElement('div');
tabContainer.style.cssText = `
display: flex;
flex-direction: column;
align-self: center;
gap: 2px;
flex-shrink: 0;
`;
// Stats tab ("S")
this.statsTab = this.createTab('S');
this.statsTab.addEventListener('click', () => {
if (this.activeTab === 'stats' && this.expanded) {
this.collapse();
} else {
this.expand('stats');
}
});
// Events tab ("E")
this.eventsTab = this.createTab('E');
this.eventsTab.addEventListener('click', () => {
if (this.activeTab === 'events' && this.expanded) {
this.collapse();
} else {
this.expand('events');
}
});
// Inventions tab ("I")
this.inventionsTab = this.createTab('I');
this.inventionsTab.style.position = 'relative';
this.notificationDot = document.createElement('div');
this.notificationDot.style.cssText = `
position: absolute;
top: 4px;
right: 4px;
width: 8px;
height: 8px;
background: #f0d060;
border-radius: 50%;
display: none;
`;
this.inventionsTab.appendChild(this.notificationDot);
this.inventionsTab.addEventListener('click', () => {
if (this.activeTab === 'inventions' && this.expanded) {
this.collapse();
} else {
this.expand('inventions');
}
});
tabContainer.appendChild(this.statsTab);
tabContainer.appendChild(this.eventsTab);
tabContainer.appendChild(this.inventionsTab);
this.container.appendChild(this.panel);
this.container.appendChild(tabContainer);
// Start collapsed
this.container.style.transform = 'translateY(-50%) translateX(-340px)';
document.body.appendChild(this.container);
}
private createTab(label: string): HTMLDivElement {
const tab = document.createElement('div');
tab.style.cssText = `
width: 32px;
height: 56px;
background: #1a1a2e;
border: 3px solid #e0d0b0;
border-left: none;
border-radius: 0 6px 6px 0;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
flex-shrink: 0;
transition: background 0.2s;
`;
const tabInner = document.createElement('div');
tabInner.style.cssText = `
color: #e0d0b0;
font-size: 20px;
`;
tabInner.textContent = label;
tab.appendChild(tabInner);
tab.addEventListener('mouseenter', () => {
if (tab.dataset.active !== 'true') {
tab.style.background = '#2a2a4e';
}
});
tab.addEventListener('mouseleave', () => {
if (tab.dataset.active !== 'true') {
tab.style.background = '#1a1a2e';
}
});
return tab;
}
private updateTabs(): void {
this.statsTab.style.background =
this.activeTab === 'stats' && this.expanded ? '#2a2a4e' : '#1a1a2e';
this.statsTab.dataset.active =
this.activeTab === 'stats' && this.expanded ? 'true' : 'false';
this.eventsTab.style.background =
this.activeTab === 'events' && this.expanded ? '#2a2a4e' : '#1a1a2e';
this.eventsTab.dataset.active =
this.activeTab === 'events' && this.expanded ? 'true' : 'false';
this.inventionsTab.style.background =
this.activeTab === 'inventions' && this.expanded ? '#2a2a4e' : '#1a1a2e';
this.inventionsTab.dataset.active =
this.activeTab === 'inventions' && this.expanded ? 'true' : 'false';
}
private showContent(tab: 'stats' | 'events' | 'inventions'): void {
// Remove current content
while (this.contentArea.firstChild) {
this.contentArea.removeChild(this.contentArea.firstChild);
}
if (tab === 'stats') {
this.headerEl.textContent = 'SUPERLATIVES';
this.contentArea.appendChild(this.superlativesContent);
} else if (tab === 'events') {
this.headerEl.textContent = 'EVENTS';
this.contentArea.appendChild(this.eventsFeedContent);
} else if (tab === 'inventions') {
this.headerEl.textContent = 'INVENTIONS';
this.contentArea.appendChild(this.inventionsContent);
}
}
expand(tab: 'stats' | 'events' | 'inventions'): void {
this.activeTab = tab;
this.expanded = true;
this.showContent(tab);
this.updateTabs();
this.container.style.transform = 'translateY(-50%) translateX(0)';
if (tab === 'inventions') {
this.hideNotificationDot();
}
document.dispatchEvent(
new CustomEvent('left-panel-opened', { detail: { tab } }),
);
}
collapse(): void {
this.expanded = false;
this.container.style.transform = 'translateY(-50%) translateX(-340px)';
this.updateTabs();
document.dispatchEvent(new CustomEvent('left-panel-closed'));
}
isExpanded(): boolean {
return this.expanded;
}
getActiveTab(): 'stats' | 'events' | 'inventions' | null {
return this.expanded ? this.activeTab : null;
}
showNotificationDot(): void {
this.notificationDot.style.display = '';
}
hideNotificationDot(): void {
this.notificationDot.style.display = 'none';
}
destroy(): void {
this.container.remove();
}
}