Something went wrong. Try again.
fork of ozone with nix stuff
Something went wrong. Try again.
4.4 kB · 113 lines
TSX
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114'use client'import { useSearchParams } from 'next/navigation'import { MagnifyingGlassIcon } from '@heroicons/react/20/solid'import { SidebarNav } from './SidebarNav'import { MobileMenuProvider, MobileMenu, MobileMenuBtn } from './MobileMenu'import { ProfileMenu } from './ProfileMenu'import { OnlineModeratorsIndicator } from '../team/OnlineModeratorsIndicator'
import { useCommandPaletteAsyncSearch } from './CommandPalette/useAsyncSearch'import { useFluentReportSearchUpdate } from '@/reports/useFluentReportSearch'import { useSyncedState } from '@/lib/useSyncedState'import Image from 'next/image'import { Suspense } from 'react'
export function Shell({ children }: React.PropsWithChildren) { useCommandPaletteAsyncSearch()
return ( <MobileMenuProvider> <div className="flex h-full"> {/* Narrow sidebar */} <div className="hidden w-28 overflow-y-auto bg-rose-700 dark:bg-teal-800 md:block"> <div className="flex w-full flex-col items-center py-6"> <div className="flex flex-shrink-0 items-center"> <Image width={100} height={100} className="h-8 w-auto" src="/img/logo-white.png" alt="Ozone - ATProto Moderation Service" title="Icon from Flaticon: https://www.flaticon.com/free-icons/lifeguard-tower" /> </div> <SidebarNav /> </div> </div>
{/* Mobile menu */} <MobileMenu />
{/* Content area */} <div className="flex flex-1 flex-col overflow-hidden"> <header className="w-full"> <div className="relative z-10 flex h-16 flex-shrink-0 border-b border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-900"> <MobileMenuBtn /> <div className="flex flex-1 justify-between px-4 sm:px-6"> <div className="flex flex-1"> <form className="flex w-full md:ml-0" action="#" method="GET"> <label htmlFor="search-field" className="sr-only"> Search </label> <div className="relative w-full text-gray-400 focus-within:text-gray-600"> <div className="pointer-events-none absolute inset-y-0 left-0 flex items-center"> <MagnifyingGlassIcon className="h-5 w-5 flex-shrink-0" aria-hidden="true" /> </div> {/* This is only needed because we use useSearchParams inside this component */} <Suspense fallback={<div></div>}> <SearchInput /> </Suspense> </div> </form> </div> <div className="ml-2 flex items-center gap-6 sm:ml-6 sm:gap-6"> {/* Online moderators indicator */} <OnlineModeratorsIndicator /> {/* Profile dropdown */} <ProfileMenu /> </div> </div> </div> </header>
{/* Main content */} <div className="flex flex-1 items-stretch overflow-hidden"> <main className="flex-1 overflow-y-auto dark:bg-slate-900"> {/* Primary column */} <section aria-labelledby="primary-heading" className="flex h-full min-w-0 flex-1 flex-col lg:order-last" > {children} </section> </main> </div> </div> </div> </MobileMenuProvider> )}
function SearchInput() { const params = useSearchParams() const updateParams = useFluentReportSearchUpdate() const [termInput, setTermInput] = useSyncedState(params.get('term') ?? '')
return ( <input id="term" name="term" className="h-full w-full border-transparent py-2 pl-8 pr-3 text-base text-gray-900 placeholder-gray-500 focus:border-transparent focus:placeholder-gray-400 focus:outline-none focus:ring-0 dark:bg-slate-900 dark:text-gray-100" placeholder="Search" type="search" value={termInput} onChange={(ev) => { setTermInput(ev.target.value) updateParams(ev.target.value) }} /> )}