Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/FoxxMD/multi-scrobbler. Scrobble plays from multiple sources to multiple clients docs.multi-scrobbler.app
deezer docker jellyfin koito lastfm listenbrainz maloja mopidy mpris music music-assistant plex scrobble self-hosted spotify subsonic tautulli youtube-music
Something went wrong. Try again.
4.2 kB · 146 lines
TSX
at strict
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146import { Box, Collapsible, useBreakpointValue } from "@chakra-ui/react";import { type ComponentProps, type PropsWithChildren, useEffect, useMemo, useState } from "react";import { LuChevronRight } from "react-icons/lu";import { MSErrorBoundary } from "./ErrorBoundary";
//padding="0" borderWidth="0px"
interface MSCollapsibleInternalProps { indicator?: string | React.JSX.Element boxProps?: object triggerProps?: object indicatorProps?: object timeline?: boolean disableUntil?: string}
export interface MSCollapsibleExternalProps { collapsibleOpen?: boolean}
export const timelineCollapsibleProps = { indicatorProps: { }, triggerProps: { paddingBlockStart: "0.3em" }, triggerPropsClosed: { //paddingBlockStart: "0.3em", paddingBlock: 'initial' }, triggerPropsOpen: { paddingBlock: 'initial', paddingBlockEnd: "var(--chakra-spacing-3)" }}
export type MSCollapsibleProps = PropsWithChildren<ComponentProps<typeof Collapsible.Root>> & MSCollapsibleInternalProps;
const breakpoints = ['base','sm','md','lg','xl'];
export const MSCollapsible = (props: MSCollapsibleProps) => { const { indicator = 'Details', disabled, disableUntil, boxProps = {}, triggerProps = {}, indicatorProps = {}, timeline = false, defaultOpen, ...rest } = props;
const breakObj = useMemo(() => { if(disableUntil === undefined) { return { base: false, sm: false, md: false, lg: false, xl: false }; } const breaks: Record<string, boolean> = {}; let found = false; for(const b of breakpoints) { if(!found && disableUntil !== b) { breaks[b] = true; found = true; } else { breaks[b] = false; } } return breaks; }, [disableUntil])
const disableByBreakpoint = useBreakpointValue( { '2xl': false, ...breakObj, }, { fallback: '2xl' });
const currBreakpoint = useBreakpointValue( { base: "base", sm: "sm", md: "md", lg: "lg", xl: "xl", ["2xl"]: "2xl" }, { fallback: '2xl' });
const [open, setOpen] = useState(defaultOpen); const [isDisabled, setDisabled] = useState(disabled);
useEffect(() => { setOpen(defaultOpen); }, [setOpen, defaultOpen]);
useEffect(() => { if (disabled !== undefined) { setDisabled(disabled); } else { setDisabled(disableByBreakpoint); } }, [disableByBreakpoint, disabled])
const iProps = { ...(timeline ? timelineCollapsibleProps.indicatorProps : {}), ...indicatorProps }; if (isDisabled) { // @ts-ignore iProps.display = 'none'; }
const tProps = { ...(timeline ? (open? timelineCollapsibleProps.triggerPropsOpen : timelineCollapsibleProps.triggerPropsClosed) : {}), ...triggerProps }
return ( <Collapsible.Root open={open} onOpenChange={(val) => setOpen(val.open)} flexGrow="1" disabled={isDisabled} {...rest}> <Collapsible.Trigger cursor={isDisabled ? 'initial' : 'pointer'} userSelect="text" paddingY="3" display="flex" gap="2" alignItems="anchor-center" {...tProps} > <Collapsible.Indicator transition="transform 0.2s" _open={{ transform: "rotate(90deg)" }} {...iProps} > <LuChevronRight /> </Collapsible.Indicator> {indicator} </Collapsible.Trigger> <Collapsible.Content> <Box {...boxProps}> <MSErrorBoundary> {props.children} </MSErrorBoundary> </Box> </Collapsible.Content> </Collapsible.Root> )}