Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to handle multiple images #72

Open
gaganbiswas opened this issue Aug 7, 2024 · 0 comments
Open

How to handle multiple images #72

gaganbiswas opened this issue Aug 7, 2024 · 0 comments

Comments

@gaganbiswas
Copy link

Hello, so for my use case I want to handle multiple images. Here's a code snippet on what i am trying to do exactly. Also I followed the Twitter Carousel for this. Trying to implement something similar to instagram post.

"use client";

import React, {
  useRef,
  useState,
  useEffect,
  forwardRef,
  useImperativeHandle,
} from "react";
import { FixedCropperRef } from "react-advanced-cropper";
import "react-advanced-cropper/dist/style.css";
import Image from "next/image";
import { Cropper } from "../common/cropper";

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Button } from "../ui/button";
import {
  Images,
  RectangleHorizontal,
  RectangleVerticalIcon,
  Scaling,
  Square,
} from "lucide-react";
import { dataURLToBlob } from "@/lib/helpers";

const MediaImageCropper = forwardRef(
  (
    {
      media,
    }: {
      media: File[];
    },
    ref
  ) => {
    const cropperRef = useRef<FixedCropperRef>(null);
    const [currentImageIndex, setCurrentImageIndex] = useState(0);
    const [stencilRatio, setStencilRatio] = useState(1);

    useImperativeHandle(ref, () => ({
      handleSaveAll,
    }));

    const handleSave = (item: File, cropper: FixedCropperRef | null) => {
      if (cropper) {
        cropper.setImage(URL.createObjectURL(item));
        const canvas = cropper.getCanvas();
        if (canvas) {
          const dataURL = canvas.toDataURL("image/png");
          const blob = dataURLToBlob(dataURL);

          return { data: blob, src: dataURL };
        }
      }

      return null;
    };

    const handleSaveAll = () => {
      const allCroppedImages: any[] = [];
      media.forEach((item) => {
        const cropper = cropperRef.current;
        const cropped = handleSave(item, cropper);
        if (cropped) {
          allCroppedImages.push(cropped);
        }
      });

      return allCroppedImages;
    };

    useEffect(() => {
      if (cropperRef.current) {
        cropperRef.current.setImage(
          URL.createObjectURL(media[currentImageIndex])
        );
      }
    }, [currentImageIndex, media]);

    return (
      <div className="flex flex-col">
        <Cropper
          key={currentImageIndex}
          cropperRef={cropperRef}
          src={URL.createObjectURL(media[currentImageIndex])}
          stencilRatio={stencilRatio}
        />

        <div className="w-full flex items-center justify-between p-4">
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button size={"icon"} variant={"secondary"}>
                <Scaling className="h-5 w-5" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="start" side="top">
              <DropdownMenuLabel>Resize</DropdownMenuLabel>
              <DropdownMenuSeparator />
              <DropdownMenuItem
                className="tracking-widest text-muted-foreground font-semibold"
                onClick={() => setStencilRatio(1)}
              >
                1:1 <Square className="w-5 h-5 ml-2" />
              </DropdownMenuItem>
              <DropdownMenuItem
                className="tracking-widest text-muted-foreground font-semibold"
                onClick={() => setStencilRatio(4 / 5)}
              >
                4:5 <RectangleVerticalIcon className="w-5 h-5 ml-2" />
              </DropdownMenuItem>
              <DropdownMenuItem
                className="tracking-widest text-muted-foreground font-semibold"
                onClick={() => setStencilRatio(16 / 9)}
              >
                16:9 <RectangleHorizontal className="w-5 h-5 ml-2" />
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>

          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button size={"icon"} variant={"secondary"}>
                <Images className="h-5 w-5" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent
              align="end"
              side="top"
              className="flex items-center gap-4 p-2"
            >
              {media.map((file, index) => (
                <DropdownMenuItem
                  key={index}
                  className={`cursor-pointer ring-2 rounded-md p-0 ${
                    index === currentImageIndex ? "ring-blue-500" : "ring-muted"
                  }`}
                  onClick={() => setCurrentImageIndex(index)}
                >
                  <Image
                    src={URL.createObjectURL(file)}
                    alt={`Thumbnail ${index}`}
                    width={32}
                    height={32}
                    className="w-16 h-16 object-cover rounded-md"
                  />
                </DropdownMenuItem>
              ))}
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
      </div>
    );
  }
);

export default MediaImageCropper;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant