Spaces:
Running
Running
real html compare
Browse files
components/editor/ask-ai/index.tsx
CHANGED
@@ -1,13 +1,12 @@
|
|
1 |
"use client";
|
2 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
3 |
-
import { useState, useRef } from "react";
|
4 |
import classNames from "classnames";
|
5 |
import { toast } from "sonner";
|
6 |
import { useLocalStorage, useUpdateEffect } from "react-use";
|
7 |
import { ArrowUp, ChevronDown, Crosshair } from "lucide-react";
|
8 |
import { FaStopCircle } from "react-icons/fa";
|
9 |
|
10 |
-
import { defaultHTML } from "@/lib/consts";
|
11 |
import ProModal from "@/components/pro-modal";
|
12 |
import { Button } from "@/components/ui/button";
|
13 |
import { MODELS } from "@/lib/providers";
|
@@ -22,6 +21,7 @@ import { Tooltip, TooltipTrigger } from "@/components/ui/tooltip";
|
|
22 |
import { TooltipContent } from "@radix-ui/react-tooltip";
|
23 |
import { SelectedHtmlElement } from "./selected-html-element";
|
24 |
import { FollowUpTooltip } from "./follow-up-tooltip";
|
|
|
25 |
|
26 |
export function AskAI({
|
27 |
html,
|
@@ -84,7 +84,7 @@ export function AskAI({
|
|
84 |
setController(abortController);
|
85 |
try {
|
86 |
onNewPrompt(prompt);
|
87 |
-
if (isFollowUp && !redesignMarkdown &&
|
88 |
const selectedElementHtml = selectedElement
|
89 |
? selectedElement.outerHTML
|
90 |
: "";
|
@@ -135,7 +135,7 @@ export function AskAI({
|
|
135 |
prompt,
|
136 |
provider,
|
137 |
model,
|
138 |
-
html:
|
139 |
redesignMarkdown,
|
140 |
}),
|
141 |
headers: {
|
@@ -276,6 +276,10 @@ export function AskAI({
|
|
276 |
}
|
277 |
}, [isThinking]);
|
278 |
|
|
|
|
|
|
|
|
|
279 |
return (
|
280 |
<div className="px-3">
|
281 |
<div className="relative bg-neutral-800 border border-neutral-700 rounded-2xl ring-[4px] focus-within:ring-neutral-500/30 focus-within:border-neutral-600 ring-transparent z-10 w-full group">
|
@@ -371,7 +375,7 @@ export function AskAI({
|
|
371 |
<div className="flex items-center justify-between gap-2 px-4 pb-3">
|
372 |
<div className="flex-1 flex items-center justify-start gap-1.5">
|
373 |
<ReImagine onRedesign={(md) => callAi(md)} />
|
374 |
-
{
|
375 |
<Tooltip>
|
376 |
<TooltipTrigger asChild>
|
377 |
<Button
|
@@ -408,7 +412,7 @@ export function AskAI({
|
|
408 |
onModelChange={setModel}
|
409 |
open={openProvider}
|
410 |
error={providerError}
|
411 |
-
isFollowUp={
|
412 |
onClose={setOpenProvider}
|
413 |
/>
|
414 |
<Button
|
@@ -426,7 +430,7 @@ export function AskAI({
|
|
426 |
open={openProModal}
|
427 |
onClose={() => setOpenProModal(false)}
|
428 |
/>
|
429 |
-
{
|
430 |
<div className="absolute top-0 right-0 -translate-y-[calc(100%+8px)] select-none text-xs text-neutral-400 flex items-center justify-center gap-2 bg-neutral-800 border border-neutral-700 rounded-md p-1 pr-2.5">
|
431 |
<label
|
432 |
htmlFor="diff-patch-checkbox"
|
|
|
1 |
"use client";
|
2 |
/* eslint-disable @typescript-eslint/no-explicit-any */
|
3 |
+
import { useState, useRef, useMemo } from "react";
|
4 |
import classNames from "classnames";
|
5 |
import { toast } from "sonner";
|
6 |
import { useLocalStorage, useUpdateEffect } from "react-use";
|
7 |
import { ArrowUp, ChevronDown, Crosshair } from "lucide-react";
|
8 |
import { FaStopCircle } from "react-icons/fa";
|
9 |
|
|
|
10 |
import ProModal from "@/components/pro-modal";
|
11 |
import { Button } from "@/components/ui/button";
|
12 |
import { MODELS } from "@/lib/providers";
|
|
|
21 |
import { TooltipContent } from "@radix-ui/react-tooltip";
|
22 |
import { SelectedHtmlElement } from "./selected-html-element";
|
23 |
import { FollowUpTooltip } from "./follow-up-tooltip";
|
24 |
+
import { isTheSameHtml } from "@/lib/compare-html-diff";
|
25 |
|
26 |
export function AskAI({
|
27 |
html,
|
|
|
84 |
setController(abortController);
|
85 |
try {
|
86 |
onNewPrompt(prompt);
|
87 |
+
if (isFollowUp && !redesignMarkdown && !isSameHtml) {
|
88 |
const selectedElementHtml = selectedElement
|
89 |
? selectedElement.outerHTML
|
90 |
: "";
|
|
|
135 |
prompt,
|
136 |
provider,
|
137 |
model,
|
138 |
+
html: isSameHtml ? "" : html,
|
139 |
redesignMarkdown,
|
140 |
}),
|
141 |
headers: {
|
|
|
276 |
}
|
277 |
}, [isThinking]);
|
278 |
|
279 |
+
const isSameHtml = useMemo(() => {
|
280 |
+
return isTheSameHtml(html);
|
281 |
+
}, [html]);
|
282 |
+
|
283 |
return (
|
284 |
<div className="px-3">
|
285 |
<div className="relative bg-neutral-800 border border-neutral-700 rounded-2xl ring-[4px] focus-within:ring-neutral-500/30 focus-within:border-neutral-600 ring-transparent z-10 w-full group">
|
|
|
375 |
<div className="flex items-center justify-between gap-2 px-4 pb-3">
|
376 |
<div className="flex-1 flex items-center justify-start gap-1.5">
|
377 |
<ReImagine onRedesign={(md) => callAi(md)} />
|
378 |
+
{!isSameHtml && (
|
379 |
<Tooltip>
|
380 |
<TooltipTrigger asChild>
|
381 |
<Button
|
|
|
412 |
onModelChange={setModel}
|
413 |
open={openProvider}
|
414 |
error={providerError}
|
415 |
+
isFollowUp={!isSameHtml}
|
416 |
onClose={setOpenProvider}
|
417 |
/>
|
418 |
<Button
|
|
|
430 |
open={openProModal}
|
431 |
onClose={() => setOpenProModal(false)}
|
432 |
/>
|
433 |
+
{!isSameHtml && (
|
434 |
<div className="absolute top-0 right-0 -translate-y-[calc(100%+8px)] select-none text-xs text-neutral-400 flex items-center justify-center gap-2 bg-neutral-800 border border-neutral-700 rounded-md p-1 pr-2.5">
|
435 |
<label
|
436 |
htmlFor="diff-patch-checkbox"
|
components/editor/index.tsx
CHANGED
@@ -25,6 +25,7 @@ import { DeployButton } from "./deploy-button";
|
|
25 |
import { Project } from "@/types";
|
26 |
import { SaveButton } from "./save-button";
|
27 |
import { LoadProject } from "../my-projects/load-project";
|
|
|
28 |
|
29 |
export const AppEditor = ({ project }: { project?: Project | null }) => {
|
30 |
const [htmlStorage, , removeHtmlStorage] = useLocalStorage("html_content");
|
@@ -148,7 +149,7 @@ export const AppEditor = ({ project }: { project?: Project | null }) => {
|
|
148 |
|
149 |
// Prevent accidental navigation away when AI is working or content has changed
|
150 |
useEvent("beforeunload", (e) => {
|
151 |
-
if (isAiWorking || html
|
152 |
e.preventDefault();
|
153 |
return "";
|
154 |
}
|
|
|
25 |
import { Project } from "@/types";
|
26 |
import { SaveButton } from "./save-button";
|
27 |
import { LoadProject } from "../my-projects/load-project";
|
28 |
+
import { isTheSameHtml } from "@/lib/compare-html-diff";
|
29 |
|
30 |
export const AppEditor = ({ project }: { project?: Project | null }) => {
|
31 |
const [htmlStorage, , removeHtmlStorage] = useLocalStorage("html_content");
|
|
|
149 |
|
150 |
// Prevent accidental navigation away when AI is working or content has changed
|
151 |
useEvent("beforeunload", (e) => {
|
152 |
+
if (isAiWorking || !isTheSameHtml(html)) {
|
153 |
e.preventDefault();
|
154 |
return "";
|
155 |
}
|
components/login-modal/index.tsx
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
import { useLocalStorage } from "react-use";
|
2 |
-
import { defaultHTML } from "@/lib/consts";
|
3 |
import { Button } from "@/components/ui/button";
|
4 |
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
|
5 |
import { useUser } from "@/hooks/useUser";
|
|
|
6 |
|
7 |
export const LoginModal = ({
|
8 |
open,
|
@@ -20,7 +20,7 @@ export const LoginModal = ({
|
|
20 |
const { openLoginWindow } = useUser();
|
21 |
const [, setStorage] = useLocalStorage("html_content");
|
22 |
const handleClick = async () => {
|
23 |
-
if (html && html
|
24 |
setStorage(html);
|
25 |
}
|
26 |
openLoginWindow();
|
|
|
1 |
import { useLocalStorage } from "react-use";
|
|
|
2 |
import { Button } from "@/components/ui/button";
|
3 |
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
|
4 |
import { useUser } from "@/hooks/useUser";
|
5 |
+
import { isTheSameHtml } from "@/lib/compare-html-diff";
|
6 |
|
7 |
export const LoginModal = ({
|
8 |
open,
|
|
|
20 |
const { openLoginWindow } = useUser();
|
21 |
const [, setStorage] = useLocalStorage("html_content");
|
22 |
const handleClick = async () => {
|
23 |
+
if (html && !isTheSameHtml(html)) {
|
24 |
setStorage(html);
|
25 |
}
|
26 |
openLoginWindow();
|
components/pro-modal/index.tsx
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
import { useLocalStorage } from "react-use";
|
2 |
-
import { defaultHTML } from "@/lib/consts";
|
3 |
import { Button } from "../ui/button";
|
4 |
import { Dialog, DialogContent } from "../ui/dialog";
|
5 |
import { CheckCheck } from "lucide-react";
|
|
|
6 |
|
7 |
export const ProModal = ({
|
8 |
open,
|
@@ -15,7 +15,7 @@ export const ProModal = ({
|
|
15 |
}) => {
|
16 |
const [, setStorage] = useLocalStorage("html_content");
|
17 |
const handleProClick = () => {
|
18 |
-
if (html
|
19 |
setStorage(html);
|
20 |
}
|
21 |
window.open("https://huggingface.co/subscribe/pro?from=DeepSite", "_blank");
|
|
|
1 |
import { useLocalStorage } from "react-use";
|
|
|
2 |
import { Button } from "../ui/button";
|
3 |
import { Dialog, DialogContent } from "../ui/dialog";
|
4 |
import { CheckCheck } from "lucide-react";
|
5 |
+
import { isTheSameHtml } from "@/lib/compare-html-diff";
|
6 |
|
7 |
export const ProModal = ({
|
8 |
open,
|
|
|
15 |
}) => {
|
16 |
const [, setStorage] = useLocalStorage("html_content");
|
17 |
const handleProClick = () => {
|
18 |
+
if (!isTheSameHtml(html)) {
|
19 |
setStorage(html);
|
20 |
}
|
21 |
window.open("https://huggingface.co/subscribe/pro?from=DeepSite", "_blank");
|
lib/compare-html-diff.ts
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { defaultHTML } from "./consts";
|
2 |
+
|
3 |
+
export const isTheSameHtml = (currentHtml: string): boolean => {
|
4 |
+
const normalize = (html: string): string =>
|
5 |
+
html
|
6 |
+
.replace(/<!--[\s\S]*?-->/g, "")
|
7 |
+
.replace(/\s+/g, " ")
|
8 |
+
.trim();
|
9 |
+
|
10 |
+
return normalize(defaultHTML) === normalize(currentHtml);
|
11 |
+
};
|