Add image component for editor (#57)

* Add image component

* More image editor

* add more image changes
This commit is contained in:
KM Koushik
2024-08-23 20:59:20 +10:00
committed by GitHub
parent 1a3364ed82
commit 1824a88a16
13 changed files with 874 additions and 265 deletions

View File

@@ -0,0 +1,65 @@
import { Button } from "@unsend/ui/src/button";
import { CheckIcon } from "lucide-react";
import { useState, useCallback, useMemo } from "react";
export type TextEditorPanelProps = {
initialText?: string;
onSetInitialText: (url: string) => void;
};
export const useTextEditorState = ({
initialText,
onSetInitialText,
}: TextEditorPanelProps) => {
const [url, setUrl] = useState(initialText || "");
const onChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
setUrl(event.target.value);
}, []);
const handleSubmit = useCallback(
(e: React.FormEvent) => {
e.preventDefault();
onSetInitialText(url);
},
[url, onSetInitialText]
);
return {
url,
setUrl,
onChange,
handleSubmit,
};
};
export const TextEditorPanel = ({
onSetInitialText,
initialText,
}: TextEditorPanelProps) => {
const state = useTextEditorState({
onSetInitialText,
initialText,
});
return (
<div className="">
<form
onSubmit={state.handleSubmit}
className="flex items-center gap-2 justify-between"
>
<label className="flex items-center gap-2 p-2 rounded-lg cursor-text">
<input
className="flex-1 bg-transparent outline-none min-w-[12rem] text-black text-sm"
placeholder="Enter valid url"
value={state.url}
onChange={state.onChange}
/>
</label>
<Button variant="silent" size="sm" className="px-1">
<CheckIcon className="h-4 w-4 disabled:opacity-50" />
</Button>
</form>
</div>
);
};

View File

@@ -1,6 +1,12 @@
"use client";
import { useState } from "react";
import { Button } from "@unsend/ui/src/button";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@unsend/ui/src/popover";
import { ReactNode, useState } from "react";
import { HexAlphaColorPicker, HexColorInput } from "react-colorful";
type ColorPickerProps = {
@@ -19,7 +25,7 @@ export function ColorPicker(props: ColorPickerProps) {
};
return (
<div className="min-w-[260px] rounded-xl border bg-white p-4">
<div className="min-w-[260px] rounded-xl shadow border border-gray-200 bg-white p-4">
<HexAlphaColorPicker
color={color}
onChange={handleColorChange}
@@ -35,3 +41,36 @@ export function ColorPicker(props: ColorPickerProps) {
</div>
);
}
export function ColorPickerPopup(
props: ColorPickerProps & { trigger: ReactNode }
) {
const { color, onChange } = props;
return (
<Popover>
<PopoverTrigger asChild>
<Button variant="ghost" className="" size="sm" type="button">
{props.trigger}
</Button>
</PopoverTrigger>
<PopoverContent className="w-full rounded-none border-0 !bg-transparent !p-0 shadow-none drop-shadow-md">
<ColorPicker
color={color}
onChange={(newColor) => {
// HACK: This is a workaround for a bug in tiptap
// https://github.com/ueberdosis/tiptap/issues/3580
//
// ERROR: flushSync was called from inside a lifecycle
//
// To fix this, we need to make sure that the onChange
// callback is run after the current execution context.
queueMicrotask(() => {
onChange?.(newColor);
});
}}
/>
</PopoverContent>
</Popover>
);
}

View File

@@ -0,0 +1,17 @@
import { AlignCenterIcon, AlignLeftIcon, AlignRightIcon } from "lucide-react";
import { AllowedAlignments } from "../../../types";
export const AlignmentIcon = ({
alignment,
}: {
alignment: AllowedAlignments;
}) => {
if (alignment === "left") {
return <AlignLeftIcon className="h-4 w-4" />;
} else if (alignment === "center") {
return <AlignCenterIcon className="h-4 w-4" />;
} else if (alignment === "right") {
return <AlignRightIcon className="h-4 w-4" />;
}
return null;
};