Merge branch 'select-and-edit' into hosted

This commit is contained in:
Abi Raja 2024-06-05 14:49:15 -04:00
commit 7d4d62aa41
5 changed files with 46 additions and 27 deletions

View File

@ -48,6 +48,7 @@ import useBrowserTabIndicator from "./hooks/useBrowserTabIndicator";
import TipLink from "./components/core/TipLink";
import FeedbackCallNote from "./components/user-feedback/FeedbackCallNote";
import SelectAndEditModeToggleButton from "./components/select-and-edit/SelectAndEditModeToggleButton";
import { useAppStore } from "./store/app-store";
const IS_OPENAI_DOWN = false;
@ -71,6 +72,8 @@ function App({ navbarComponent }: Props) {
const { getToken } = useAuth();
const subscriberTier = useStore((state) => state.subscriberTier);
const { disableInSelectAndEditMode } = useAppStore();
// Settings
const [settings, setSettings] = usePersistedState<Settings>(
{
@ -174,6 +177,7 @@ function App({ navbarComponent }: Props) {
setAppHistory([]);
setCurrentVersion(null);
setShouldIncludeResultImage(false);
disableInSelectAndEditMode();
};
const regenerate = () => {

View File

@ -2,7 +2,6 @@ import { useEffect, useRef, useState } from "react";
import classNames from "classnames";
import useThrottle from "../hooks/useThrottle";
import EditPopup from "./select-and-edit/EditPopup";
import { useAppStore } from "../store/app-store";
interface Props {
code: string;
@ -11,8 +10,6 @@ interface Props {
}
function Preview({ code, device, doUpdate }: Props) {
const { inSelectAndEditMode } = useAppStore();
const iframeRef = useRef<HTMLIFrameElement | null>(null);
// Don't update code more often than every 200ms.
@ -51,12 +48,7 @@ function Preview({ code, device, doUpdate }: Props) {
}
)}
></iframe>
<EditPopup
event={clickEvent}
iframeRef={iframeRef}
inSelectAndEditMode={inSelectAndEditMode}
doUpdate={doUpdate}
/>
<EditPopup event={clickEvent} iframeRef={iframeRef} doUpdate={doUpdate} />
</div>
);
}

View File

@ -2,33 +2,40 @@ import React, { useEffect, useRef, useState } from "react";
import { Textarea } from "../ui/textarea";
import { Button } from "../ui/button";
import { addHighlight, getAdjustedCoordinates, removeHighlight } from "./utils";
import { useAppStore } from "../../store/app-store";
interface EditPopupProps {
event: MouseEvent | null;
inSelectAndEditMode: boolean;
doUpdate: (updateInstruction: string, selectedElement?: HTMLElement) => void;
iframeRef: React.RefObject<HTMLIFrameElement>;
doUpdate: (updateInstruction: string, selectedElement?: HTMLElement) => void;
}
const EditPopup: React.FC<EditPopupProps> = ({
event,
inSelectAndEditMode,
doUpdate,
iframeRef,
doUpdate,
}) => {
// Edit state
const [selectedElement, setSelectedElement] = useState<
HTMLElement | undefined
>(undefined);
const [updateText, setUpdateText] = useState("");
// App state
const { inSelectAndEditMode } = useAppStore();
// Create a wrapper ref to store inSelectAndEditMode so the value is not stale
// in a event listener
const inSelectAndEditModeRef = useRef(inSelectAndEditMode);
// Update the ref whenever the state changes
useEffect(() => {
inSelectAndEditModeRef.current = inSelectAndEditMode;
}, [inSelectAndEditMode]);
// Popup state
const [popupVisible, setPopupVisible] = useState(false);
const [popupPosition, setPopupPosition] = useState({ x: 0, y: 0 });
// Create a wrapper ref to store inSelectAndEditMode so the value is not stale
// in a event listener
const inSelectAndEditModeRef = useRef(inSelectAndEditMode);
// Edit state
const [selectedElement, setSelectedElement] = useState<
HTMLElement | undefined
>(undefined);
const [updateText, setUpdateText] = useState("");
// Textarea ref for focusing
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
@ -47,11 +54,6 @@ const EditPopup: React.FC<EditPopupProps> = ({
setPopupVisible(false);
}
// Update the ref whenever the state changes
useEffect(() => {
inSelectAndEditModeRef.current = inSelectAndEditMode;
}, [inSelectAndEditMode]);
// Remove highlight and reset state when not in select and edit mode
useEffect(() => {
if (!inSelectAndEditMode) {
@ -103,6 +105,15 @@ const EditPopup: React.FC<EditPopupProps> = ({
textareaRef.current?.focus();
}, [event, iframeRef]);
// Focus the textarea when the popup is visible (we can't do this only when handling the click event
// because the textarea is not rendered yet)
// We need to also do it in the click event because popupVisible doesn't change values in that event
useEffect(() => {
if (popupVisible) {
textareaRef.current?.focus();
}
}, [popupVisible]);
if (!popupVisible) return;
return (
@ -115,6 +126,12 @@ const EditPopup: React.FC<EditPopupProps> = ({
value={updateText}
onChange={(e) => setUpdateText(e.target.value)}
placeholder="Tell the AI what to change about this element..."
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
onUpdate(updateText);
}
}}
/>
<div className="flex justify-end mt-2">
<Button onClick={() => onUpdate(updateText)}>Update</Button>

View File

@ -1,3 +1,4 @@
import { GiClick } from "react-icons/gi";
import { useAppStore } from "../../store/app-store";
import { Button } from "../ui/button";
@ -10,7 +11,10 @@ function SelectAndEditModeToggleButton() {
className="flex items-center gap-x-2 dark:text-white dark:bg-gray-700 regenerate-btn"
variant={inSelectAndEditMode ? "destructive" : "default"}
>
{inSelectAndEditMode ? "Exit selection mode" : "🖱️ Select and Edit"}
<GiClick className="text-lg" />
<span>
{inSelectAndEditMode ? "Exit selection mode" : "Select and update"}
</span>
</Button>
);
}

View File

@ -5,6 +5,7 @@ interface AppStore {
inSelectAndEditMode: boolean;
inputMode: "image" | "video";
toggleInSelectAndEditMode: () => void;
disableInSelectAndEditMode: () => void;
}
export const useAppStore = create<AppStore>((set) => ({
@ -12,4 +13,5 @@ export const useAppStore = create<AppStore>((set) => ({
inSelectAndEditMode: false,
toggleInSelectAndEditMode: () =>
set((state) => ({ inSelectAndEditMode: !state.inSelectAndEditMode })),
disableInSelectAndEditMode: () => set({ inSelectAndEditMode: false }),
}));