chore: Initial commit of Opencord base state

This commit is contained in:
Jannis Braun
2026-02-18 02:49:21 +01:00
commit 4fd17084a5
124 changed files with 17955 additions and 0 deletions
@@ -0,0 +1,91 @@
import React, { useEffect, useRef, useState } from 'react';
interface ContextMenuItem {
label: string;
onClick: () => void;
danger?: boolean;
icon?: React.ReactNode;
}
interface ContextMenuProps {
items: ContextMenuItem[];
children: React.ReactNode;
}
export function ContextMenu({ items, children }: ContextMenuProps) {
const [isOpen, setIsOpen] = useState(false);
const [position, setPosition] = useState({ x: 0, y: 0 });
const menuRef = useRef<HTMLDivElement>(null);
const handleContextMenu = (e: React.MouseEvent) => {
e.preventDefault();
setPosition({ x: e.clientX, y: e.clientY });
setIsOpen(true);
};
useEffect(() => {
const handleClick = () => setIsOpen(false);
const handleScroll = () => setIsOpen(false);
if (isOpen) {
document.addEventListener('click', handleClick);
document.addEventListener('scroll', handleScroll, true);
return () => {
document.removeEventListener('click', handleClick);
document.removeEventListener('scroll', handleScroll, true);
};
}
}, [isOpen]);
// Adjust position to keep menu in viewport
useEffect(() => {
if (isOpen && menuRef.current) {
const rect = menuRef.current.getBoundingClientRect();
const newPosition = { ...position };
if (rect.right > window.innerWidth) {
newPosition.x = window.innerWidth - rect.width - 8;
}
if (rect.bottom > window.innerHeight) {
newPosition.y = window.innerHeight - rect.height - 8;
}
if (newPosition.x !== position.x || newPosition.y !== position.y) {
setPosition(newPosition);
}
}
}, [isOpen, position]);
return (
<>
<div onContextMenu={handleContextMenu}>{children}</div>
{isOpen && (
<div
ref={menuRef}
className="fixed z-50 min-w-[180px] py-1.5 bg-[#111214] rounded-md shadow-xl border border-gray-800 animate-fade-in"
style={{ left: position.x, top: position.y }}
>
{items.map((item, i) => (
<button
key={i}
className={`w-full text-left px-2 py-1.5 mx-1.5 text-sm rounded-sm flex items-center gap-2 ${
item.danger
? 'text-discord-red hover:bg-discord-red hover:text-white'
: 'text-discord-text-secondary hover:bg-discord-blurple hover:text-white'
}`}
style={{ width: 'calc(100% - 12px)' }}
onClick={(e) => {
e.stopPropagation();
item.onClick();
setIsOpen(false);
}}
>
{item.icon && <span className="w-4 h-4">{item.icon}</span>}
{item.label}
</button>
))}
</div>
)}
</>
);
}