mirror of
https://github.com/FoxxMD/multi-scrobbler.git
synced 2026-10-19 15:26:33 +00:00
feat(ui): add edit/search help popover
This commit is contained in:
parent
591888e97a
commit
698f56dbe8
3 changed files with 77 additions and 9 deletions
|
|
@ -6,8 +6,9 @@ import {
|
|||
Tooltip as ChakraTooltip,
|
||||
Span,
|
||||
} from "@chakra-ui/react"
|
||||
import * as React from "react"
|
||||
import { HiOutlineInformationCircle } from "react-icons/hi"
|
||||
import * as React from "react";
|
||||
import { BsQuestionCircle, BsExclamationCircle } from "react-icons/bs";
|
||||
import type { IconBaseProps } from "react-icons/lib";
|
||||
|
||||
export interface ToggleTipProps extends ChakraPopover.RootProps {
|
||||
showArrow?: boolean
|
||||
|
|
@ -67,10 +68,12 @@ export const ToggleTip = React.forwardRef<HTMLDivElement, ToggleTipProps>(
|
|||
|
||||
export interface InfoTipProps extends Partial<ToggleTipProps> {
|
||||
buttonProps?: IconButtonProps | undefined
|
||||
iconProps?: IconBaseProps
|
||||
question?: boolean
|
||||
}
|
||||
|
||||
export const InfoTip = React.forwardRef<HTMLDivElement, InfoTipProps>(
|
||||
function InfoTip(props, ref) {
|
||||
(props, ref) => {
|
||||
const { children, buttonProps, ...rest } = props
|
||||
return (
|
||||
<ToggleTip content={children} {...rest} ref={ref}>
|
||||
|
|
@ -81,13 +84,56 @@ export const InfoTip = React.forwardRef<HTMLDivElement, InfoTipProps>(
|
|||
colorPalette="gray"
|
||||
{...buttonProps}
|
||||
>
|
||||
<HiOutlineInformationCircle />
|
||||
{props.question ? <BsQuestionCircle {...props.iconProps}/> : <BsExclamationCircle />}
|
||||
</IconButton>
|
||||
</ToggleTip>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export interface InfoPopoverProps extends ChakraPopover.RootProps {
|
||||
buttonProps?: IconButtonProps | undefined
|
||||
iconProps?: IconBaseProps
|
||||
question?: boolean
|
||||
title?: string | React.JSX.Element
|
||||
}
|
||||
|
||||
export const InfoPopover = React.forwardRef<HTMLDivElement, InfoPopoverProps>(
|
||||
(props, ref) => {
|
||||
const { children, buttonProps, ...rest } = props
|
||||
return (
|
||||
<ChakraPopover.Root {...rest}>
|
||||
<ChakraPopover.Trigger asChild>
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
aria-label="info"
|
||||
size="2xs"
|
||||
colorPalette="gray"
|
||||
{...buttonProps}
|
||||
>
|
||||
{props.question ? <BsQuestionCircle {...props.iconProps}/> : <BsExclamationCircle />}
|
||||
</IconButton>
|
||||
</ChakraPopover.Trigger>
|
||||
<Portal>
|
||||
<ChakraPopover.Positioner>
|
||||
<ChakraPopover.Content width="max-content" maxWidth="90vw">
|
||||
<ChakraPopover.Arrow />
|
||||
<ChakraPopover.Body>
|
||||
{props.title ? (
|
||||
<ChakraPopover.Title fontWeight="medium">
|
||||
{props.title}
|
||||
</ChakraPopover.Title>
|
||||
) : undefined}
|
||||
{children}
|
||||
</ChakraPopover.Body>
|
||||
</ChakraPopover.Content>
|
||||
</ChakraPopover.Positioner>
|
||||
</Portal>
|
||||
</ChakraPopover.Root>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export interface TextTipProps extends Partial<ToggleTipProps> {
|
||||
text: string | React.ReactNode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ export const IdleIcon = (props: {animated?: boolean} & ComponentProps<typeof RiZ
|
|||
};
|
||||
|
||||
export const EllipsisIcon = LuEllipsis;
|
||||
export const EllipsisChakraIcon = makeChakraIcon(LuEllipsis);
|
||||
export const EllipsisButton = makeIconButton(EllipsisIcon);
|
||||
export const EllipsisVerticalIcon = LuEllipsisVertical;
|
||||
export const EllipsisVerticalButton = makeIconButton(EllipsisVerticalIcon);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { HStack, Box, Field, Stack, Fieldset, Button, IconButton, DateInput, DatePicker, Portal, EmptyState } from "@chakra-ui/react"
|
||||
import { HStack, Box, Field, Stack, Fieldset, Button, IconButton, DateInput, DatePicker, Portal, Text, Kbd, Span } from "@chakra-ui/react"
|
||||
import { playEditStrictCreateSchema, type PlayObjectMinimal, type TrackData } from '../../../core/Atomic.js';
|
||||
import { MSErrorBoundary } from '../ErrorBoundary.js';
|
||||
import { useForm, formOptions } from '@tanstack/react-form';
|
||||
import { TrackSearch } from "./TrackSearch.js";
|
||||
import { ArtistSearch } from "./ArtistSearch.js";
|
||||
import { CopyToRight, ResetIconRaw, TrashIconButton } from "../icons/ChakraIcons.js";
|
||||
import { useState } from "react";
|
||||
import { BracesIcon, CopyToRight, EllipsisChakraIcon, ResetIconRaw, TextIcon, TrashIconButton } from "../icons/ChakraIcons.js";
|
||||
import { useState, type ReactNode } from "react";
|
||||
import { AlbumSearch } from "./AlbumSearch.js";
|
||||
import { DurationSepEditable } from "./DurationEditable.js";
|
||||
import { Tooltip } from "../ToggleTip.js";
|
||||
import { InfoPopover, Tooltip } from "../ToggleTip.js";
|
||||
import { hashObject } from "../../../core/StringUtils.js";
|
||||
import { dedupAlbumArtists } from "../../../core/MusicMetadata.js";
|
||||
import { LuCalendar } from "react-icons/lu";
|
||||
|
|
@ -23,6 +23,20 @@ export interface PlayEditProps {
|
|||
onCancel?: () => void
|
||||
}
|
||||
|
||||
const IconWrapper = (props: {children: ReactNode}) => <Box paddingX="1" marginX="1" display="inline-block" rounded="md" backgroundColor="bg.emphasized">{props.children}</Box>
|
||||
|
||||
const editPopoverContent = (
|
||||
<Stack mt="4" gap="2">
|
||||
<Span>The fields of your Play data are both <strong>plain text</strong> and <strong>search fields.</strong></Span>
|
||||
<Span>Apply plain text to a field with <Kbd>Enter</Kbd> or selecting outside the field at any time.</Span>
|
||||
<Span>The contents of the field are also used to <strong>search</strong> for rich data. Use <Kbd>Down Arrow</Kbd> or the field arrow to access results.</Span>
|
||||
<Span>Select a result to apply <strong>all</strong> shown parts (album, artists, meta ids, etc...) or use the <IconWrapper><EllipsisChakraIcon size="md"/></IconWrapper> menu to apply only some parts.</Span>
|
||||
<Text fontWeight="bold" my="2">Search Mode</Text>
|
||||
<HStack><Span><strong>Context</strong><IconWrapper><BracesIcon size="md"/></IconWrapper>mode will search for results using your text and <i>all</i> filled fields + ids as hints/restrictions.</Span></HStack>
|
||||
<HStack><Span><strong>Text</strong><IconWrapper><TextIcon size="md"/></IconWrapper>mode will search for results using <i>only</i> the text in the field.</Span></HStack>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
const logSubmit: PlayEditProps['onSubmit'] = (val) => console.log(val, 'Play Edit Submit');
|
||||
const cancelNoop = () => console.log('Clicked cancel');
|
||||
|
||||
|
|
@ -161,7 +175,6 @@ export const PlayEdit = (props: PlayEditProps) => {
|
|||
|
||||
return (
|
||||
<Box position="relative">
|
||||
|
||||
<MSErrorBoundary>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
|
|
@ -169,7 +182,15 @@ export const PlayEdit = (props: PlayEditProps) => {
|
|||
e.stopPropagation()
|
||||
form.handleSubmit()
|
||||
}}>
|
||||
|
||||
<HStack justify="flex-end">
|
||||
<Box marginRight="auto">
|
||||
<InfoPopover question
|
||||
iconProps={{size: 'xl'}}
|
||||
buttonProps={{size: 'md'}}
|
||||
title={<Text fontWeight="bold" textStyle="lg">Editing and Searching</Text>}
|
||||
positioning={{ placement: "top-end" }}>{editPopoverContent}</InfoPopover>
|
||||
</Box>
|
||||
<Button loading={isSubmitting} type="submit" variant="subtle" colorPalette="blue">{context === 'edit' ? 'Save' : 'Create'}</Button>
|
||||
<Button disabled={isSubmitting} variant="subtle" colorPalette="red" onClick={() => onCancel()}>Cancel</Button>
|
||||
<form.Subscribe
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue