Make batch edits more discoverable
This commit is contained in:
parent
ed0fe9cae9
commit
34a8f2f362
@ -11,13 +11,12 @@ import {
|
||||
PATH_GRID_INFERRED,
|
||||
} from '@/app/paths';
|
||||
import { useAppState } from '@/state/AppState';
|
||||
import { IoArrowDown, IoArrowUp } from 'react-icons/io5';
|
||||
import { IoArrowDown, IoArrowUp, IoCloseSharp } from 'react-icons/io5';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import AdminAppInfoIcon from './AdminAppInfoIcon';
|
||||
import { signOutAction } from '@/auth/actions';
|
||||
import { ComponentProps } from 'react';
|
||||
import useIsKeyBeingPressed from '@/utility/useIsKeyBeingPressed';
|
||||
import IconSelectMultiple from '@/components/icons/IconSelectMultiple';
|
||||
import IconPhoto from '@/components/icons/IconPhoto';
|
||||
import IconUpload from '@/components/icons/IconUpload';
|
||||
import IconRecipe from '@/components/icons/IconRecipe';
|
||||
@ -25,6 +24,7 @@ import IconTag from '@/components/icons/IconTag';
|
||||
import IconFolder from '@/components/icons/IconFolder';
|
||||
import IconSignOut from '@/components/icons/IconSignOut';
|
||||
import IconLock from '@/components/icons/IconLock';
|
||||
import { IoMdCheckboxOutline } from 'react-icons/io';
|
||||
|
||||
export default function AdminAppMenu({
|
||||
active,
|
||||
@ -121,9 +121,14 @@ export default function AdminAppMenu({
|
||||
if (photosCountTotal) {
|
||||
items.push({
|
||||
label: isSelecting
|
||||
? 'Exit Select'
|
||||
: 'Edit Multiple',
|
||||
icon: <IconSelectMultiple {...{ isSelecting }} />,
|
||||
? 'Exit Batch Edit'
|
||||
: 'Batch Edit ...',
|
||||
icon: isSelecting
|
||||
? <IoCloseSharp
|
||||
size={18}
|
||||
className="translate-x-[-1px] translate-y-[0.5px]"
|
||||
/>
|
||||
: <IoMdCheckboxOutline size={17} className="translate-x-[-0.5px]" />,
|
||||
href: PATH_GRID_INFERRED,
|
||||
action: () => {
|
||||
if (isSelecting) {
|
||||
|
||||
@ -51,6 +51,10 @@ export default function AdminBatchEditPanelClient({
|
||||
false,
|
||||
);
|
||||
|
||||
const isFormDisabled =
|
||||
isPerformingSelectEdit ||
|
||||
selectedPhotoIds?.length === 0;
|
||||
|
||||
const renderPhotoCTA = () => selectedPhotoIds?.length === 0
|
||||
? <>
|
||||
<FaArrowDown />
|
||||
@ -105,40 +109,37 @@ export default function AdminBatchEditPanelClient({
|
||||
</LoaderButton>
|
||||
</>
|
||||
: <>
|
||||
{(selectedPhotoIds?.length ?? 0) > 0 &&
|
||||
<>
|
||||
<DeletePhotosButton
|
||||
photoIds={selectedPhotoIds}
|
||||
disabled={isPerformingSelectEdit}
|
||||
onClick={() => setIsPerformingSelectEdit?.(true)}
|
||||
onDelete={resetForm}
|
||||
onFinish={() => setIsPerformingSelectEdit?.(false)}
|
||||
/>
|
||||
<LoaderButton
|
||||
icon={<IconFavs />}
|
||||
disabled={isPerformingSelectEdit}
|
||||
confirmText={`Are you sure you want to favorite ${photosText}?`}
|
||||
onClick={() => {
|
||||
setIsPerformingSelectEdit?.(true);
|
||||
tagMultiplePhotosAction(
|
||||
TAG_FAVS,
|
||||
selectedPhotoIds ?? [],
|
||||
)
|
||||
.then(() => {
|
||||
toastSuccess(`${photosText} favorited`);
|
||||
resetForm();
|
||||
})
|
||||
.finally(() => setIsPerformingSelectEdit?.(false));
|
||||
}}
|
||||
/>
|
||||
<LoaderButton
|
||||
onClick={() => setTags('')}
|
||||
disabled={isPerformingSelectEdit}
|
||||
icon={<IconTag size={15} className="translate-y-[1.5px]" />}
|
||||
>
|
||||
Tag ...
|
||||
</LoaderButton>
|
||||
</>}
|
||||
<DeletePhotosButton
|
||||
photoIds={selectedPhotoIds}
|
||||
disabled={isFormDisabled}
|
||||
onClick={() => setIsPerformingSelectEdit?.(true)}
|
||||
onDelete={resetForm}
|
||||
onFinish={() => setIsPerformingSelectEdit?.(false)}
|
||||
/>
|
||||
<LoaderButton
|
||||
icon={<IconFavs />}
|
||||
disabled={isFormDisabled}
|
||||
confirmText={`Are you sure you want to favorite ${photosText}?`}
|
||||
onClick={() => {
|
||||
setIsPerformingSelectEdit?.(true);
|
||||
tagMultiplePhotosAction(
|
||||
TAG_FAVS,
|
||||
selectedPhotoIds ?? [],
|
||||
)
|
||||
.then(() => {
|
||||
toastSuccess(`${photosText} favorited`);
|
||||
resetForm();
|
||||
})
|
||||
.finally(() => setIsPerformingSelectEdit?.(false));
|
||||
}}
|
||||
/>
|
||||
<LoaderButton
|
||||
onClick={() => setTags('')}
|
||||
disabled={isFormDisabled}
|
||||
icon={<IconTag size={15} className="translate-y-[1.5px]" />}
|
||||
>
|
||||
Tag ...
|
||||
</LoaderButton>
|
||||
<LoaderButton
|
||||
icon={<IoCloseSharp size={19} />}
|
||||
onClick={() => setSelectedPhotoIds?.(undefined)}
|
||||
|
||||
@ -18,8 +18,9 @@ export default function DeleteButton({
|
||||
'active:bg-red-100/50! dark:active:bg-red-950/50!',
|
||||
'disabled:text-red-500/60! dark:disabled:text-red-500/60!',
|
||||
'disabled:bg-red-100/50! dark:disabled:bg-red-950/50!',
|
||||
'border-red-200! hover:border-red-300!',
|
||||
'dark:border-red-900/75! dark:hover:border-red-900!',
|
||||
'border-red-200! disabled:border-red-200! hover:border-red-300!',
|
||||
// eslint-disable-next-line max-len
|
||||
'dark:border-red-900/75! dark:disabled:border-red-900/75! dark:hover:border-red-900!',
|
||||
className,
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { clsx } from 'clsx/lite';
|
||||
import Checkbox from './primitives/Checkbox';
|
||||
import SimpleCheckbox from './primitives/SimpleCheckbox';
|
||||
import { useAppState } from '@/state/AppState';
|
||||
import Spinner from './Spinner';
|
||||
|
||||
@ -45,7 +45,7 @@ export default function SelectTileOverlay({
|
||||
className="m-[1px]"
|
||||
/>
|
||||
: null
|
||||
: <Checkbox
|
||||
: <SimpleCheckbox
|
||||
className={clsx(
|
||||
'text-white',
|
||||
// Required to prevent Safari jitter
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
import clsx from 'clsx/lite';
|
||||
import { IconBaseProps } from 'react-icons';
|
||||
import { ImCheckboxUnchecked } from 'react-icons/im';
|
||||
import { IoCloseSharp } from 'react-icons/io5';
|
||||
|
||||
export default function IconSelectMultiple({
|
||||
isSelecting,
|
||||
className,
|
||||
...props
|
||||
}: IconBaseProps & { isSelecting: boolean }) {
|
||||
return isSelecting
|
||||
? <IoCloseSharp {...{
|
||||
...props,
|
||||
className: clsx(
|
||||
'text-[18px] translate-x-[-1px] translate-y-[0.5px]',
|
||||
className,
|
||||
),
|
||||
}} />
|
||||
: <ImCheckboxUnchecked
|
||||
{...{
|
||||
...props,
|
||||
className: clsx(
|
||||
'translate-x-[-0.5px] translate-y-[0.5px] text-[0.75rem]',
|
||||
className,
|
||||
),
|
||||
}}
|
||||
/>;
|
||||
}
|
||||
@ -4,7 +4,7 @@ import { ImCheckboxUnchecked, ImCheckboxChecked } from 'react-icons/im';
|
||||
|
||||
const ICON_CLASS_NAME = 'text-[1rem]';
|
||||
|
||||
export default function Checkbox(props: {
|
||||
export default function SimpleCheckbox(props: {
|
||||
children?: ReactNode
|
||||
} & InputHTMLAttributes<HTMLInputElement>) {
|
||||
const {
|
||||
Loading…
Reference in New Issue
Block a user