Update UI to match consistent layout patterns between pages
Some checks failed
Lint and Build / build (20) (push) Has been cancelled
Lint and Build / build (22) (push) Has been cancelled

- Refactor Add Stream page to match Teams page layout with glass panels
- Rename "Add Stream" to "Streams" in navigation and page title
- Add existing streams display with loading states and empty state
- Implement unified design system with modern glass morphism styling
- Add Header and Footer components with OBS status monitoring
- Update global CSS with comprehensive component styling
- Consolidate client components into main page files
- Add real-time OBS connection status with 30-second polling

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Decobus 2025-07-19 04:39:40 -04:00
parent 1d4b1eefba
commit c28baa9e44
19 changed files with 2388 additions and 567 deletions

View file

@ -19,11 +19,12 @@ export default function Dropdown({
isOpen: controlledIsOpen,
onToggle,
}: DropdownProps) {
const dropdownRef = useRef<HTMLDivElement>(null);
const dropdownRef = useRef<HTMLDivElement>(null);
const [isOpen, setIsOpen] = useState(controlledIsOpen ?? false);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => { if (!dropdownRef.current || !(event.target instanceof Node)) return;
const handleClickOutside = (event: MouseEvent) => {
if (!dropdownRef.current || !(event.target instanceof Node)) return;
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
if (onToggle) onToggle(false);
else setIsOpen(false);
@ -53,19 +54,19 @@ const dropdownRef = useRef<HTMLDivElement>(null);
};
return (
<div className="relative inline-block text-left" ref={dropdownRef}>
<div className="relative w-full" ref={dropdownRef}>
<button
type="button"
onClick={toggleDropdown}
className="inline-flex justify-between items-center w-full px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
className="dropdown-button"
>
{activeOption ? activeOption.name : label}
<span>
{activeOption ? activeOption.name : label}
</span>
<svg
xmlns="http://www.w3.org/2000/svg"
className="ml-2 h-5 w-5"
viewBox="0 0 20 20"
className={`icon-sm transition-transform duration-200 ${(controlledIsOpen ?? isOpen) ? 'rotate-180' : ''}`}
fill="currentColor"
aria-hidden="true"
viewBox="0 0 20 20"
>
<path
fillRule="evenodd"
@ -76,26 +77,24 @@ const dropdownRef = useRef<HTMLDivElement>(null);
</button>
{(controlledIsOpen ?? isOpen) && (
<div
className="absolute right-0 mt-2 w-56 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
style={{ zIndex: 50 }} // Set a high z-index value
>
<div className="py-1">
{options.map((option) => (
<button
<div className="absolute z-50 w-full dropdown-menu">
{options.length === 0 ? (
<div className="dropdown-item text-center">
No streams available
</div>
) : (
options.map((option) => (
<div
key={option.id}
type="button"
onClick={() => handleSelect(option)}
className={`block w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 ${
activeOption?.id === option.id ? 'font-bold text-blue-500' : ''
}`}
className={`dropdown-item ${activeOption?.id === option.id ? 'active' : ''}`}
>
{option.name}
</button>
))}
</div>
</div>
))
)}
</div>
)}
</div>
);
}
}