teableio/teable

View on GitHub
packages/sdk/src/components/comment/comment-editor/plate-ui/image-preview.tsx

Summary

Maintainability
A
35 mins
Test Coverage
import { cn, createPrimitiveComponent } from '@udecode/cn';
import {
  PreviewImage,
  useImagePreview,
  useImagePreviewState,
  useScaleInput,
  useScaleInputState,
} from '@udecode/plate-media/react';
import { cva } from 'class-variance-authority';

import { Icons } from './icons';

const toolButtonVariants = cva('rounded bg-[rgba(0,0,0,0.5)] px-1', {
  defaultVariants: {
    variant: 'default',
  },
  variants: {
    variant: {
      default: 'text-white',
      disabled: 'cursor-not-allowed text-gray-400',
    },
  },
});

const ScaleInput = createPrimitiveComponent('input')({
  propsHook: useScaleInput,
  stateHook: useScaleInputState,
});

const SCROLL_SPEED = 4;

export const ImagePreview = () => {
  const state = useImagePreviewState({ scrollSpeed: SCROLL_SPEED });

  const {
    closeProps,
    currentUrlIndex,
    maskLayerProps,
    nextDisabled,
    nextProps,
    prevDisabled,
    prevProps,
    scaleTextProps,
    zommOutProps,
    zoomInDisabled,
    zoomInProps,
    zoomOutDisabled,
  } = useImagePreview(state);

  const { isOpen, scale } = state;

  return (
    <div
      className={cn('fixed left-0 top-0 z-50 bottom-0 right-0', !isOpen && 'hidden')}
      {...maskLayerProps}
    >
      <div className="absolute inset-0 size-full bg-black opacity-30"></div>
      <div className="absolute inset-0 size-full bg-black opacity-30"></div>
      <div className="absolute inset-0 flex items-center justify-center ">
        <div className="relative flex max-h-screen w-full items-center">
          <PreviewImage
            className={cn(
              'mx-auto block max-h-[calc(100vh-4rem)] w-auto object-contain transition-transform'
            )}
          />
          <div
            tabIndex={0}
            role="button"
            onKeyDown={(e) => e.stopPropagation()}
            className="absolute bottom-0 left-1/2 z-40 flex w-fit -translate-x-1/2 justify-center gap-4 p-2 text-center text-white"
            onClick={(e) => e.stopPropagation()}
          >
            <div className="flex gap-1 ">
              <button
                {...prevProps}
                className={cn(
                  toolButtonVariants({
                    variant: prevDisabled ? 'disabled' : 'default',
                  })
                )}
                type="button"
              >
                <Icons.arrowLeft className="size-5" />
              </button>
              {(currentUrlIndex ?? 0) + 1}
              <button
                {...nextProps}
                className={cn(
                  toolButtonVariants({
                    variant: nextDisabled ? 'disabled' : 'default',
                  })
                )}
                type="button"
              >
                <Icons.arrowRight className="size-5" />
              </button>
            </div>
            <div className="flex ">
              <button
                className={cn(
                  toolButtonVariants({
                    variant: zoomOutDisabled ? 'disabled' : 'default',
                  })
                )}
                {...zommOutProps}
                type="button"
              >
                <Icons.minus className="size-4" />
              </button>
              <div className="mx-px">
                {state.isEditingScale ? (
                  <>
                    <ScaleInput className="w-10 rounded px-1 text-slate-500 outline" />{' '}
                    <span>%</span>
                  </>
                ) : (
                  <span {...scaleTextProps}>{scale * 100 + '%'}</span>
                )}
              </div>
              <button
                className={cn(
                  toolButtonVariants({
                    variant: zoomInDisabled ? 'disabled' : 'default',
                  })
                )}
                {...zoomInProps}
                type="button"
              >
                <Icons.add className="size-4" />
              </button>
            </div>
            {/* TODO: downLoad the image */}
            {/* <button className={cn(toolButtonVariants())} type="button">
              <Icons.downLoad className="size-4" />
            </button> */}
            <button {...closeProps} className={cn(toolButtonVariants())} type="button">
              <Icons.close className="size-4" />
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};