Pārlūkot izejas kodu

move code to utils/file

lloydzhou 1 gadu atpakaļ
vecāks
revīzija
33450ce429
6 mainītis faili ar 88 papildinājumiem un 89 dzēšanām
  1. 3 2
      app/components/sd-panel.tsx
  2. 25 62
      app/components/sd.tsx
  3. 27 0
      app/components/ui-lib.tsx
  4. 1 0
      app/constant.ts
  5. 1 25
      app/store/sd.ts
  6. 31 0
      app/utils/file.tsx

+ 3 - 2
app/components/sd-panel.tsx

@@ -6,9 +6,10 @@ import locales from "@/app/locales";
 import { nanoid } from "nanoid";
 import { useIndexedDB } from "react-indexed-db-hook";
 import { StoreKey } from "@/app/constant";
-import { SdDbInit, useSdStore } from "@/app/store/sd";
+import { useSdStore } from "@/app/store/sd";
+import { FileDbInit } from "@/app/utils/file";
 
-SdDbInit();
+FileDbInit();
 
 const sdCommonParams = (model: string, data: any) => {
   return [

+ 25 - 62
app/components/sd.tsx

@@ -3,7 +3,7 @@ import styles from "@/app/components/sd.module.scss";
 import { IconButton } from "@/app/components/button";
 import ReturnIcon from "@/app/icons/return.svg";
 import Locale from "@/app/locales";
-import { Path, StoreKey } from "@/app/constant";
+import { Path } from "@/app/constant";
 import React, { useEffect, useMemo, useRef, useState } from "react";
 import {
   copyToClipboard,
@@ -20,7 +20,6 @@ import DeleteIcon from "@/app/icons/clear.svg";
 import CopyIcon from "@/app/icons/copy.svg";
 import PromptIcon from "@/app/icons/prompt.svg";
 import ResetIcon from "@/app/icons/reload.svg";
-import { useIndexedDB } from "react-indexed-db-hook";
 import { useSdStore } from "@/app/store/sd";
 import locales from "@/app/locales";
 import LoadingIcon from "../icons/three-dots.svg";
@@ -30,19 +29,10 @@ import {
   showConfirm,
   showImageModal,
   showModal,
+  IndexDBImage,
 } from "@/app/components/ui-lib";
 import { func } from "prop-types";
-
-function getBase64ImgUrl(base64Data: string, contentType: string) {
-  const byteCharacters = atob(base64Data);
-  const byteNumbers = new Array(byteCharacters.length);
-  for (let i = 0; i < byteCharacters.length; i++) {
-    byteNumbers[i] = byteCharacters.charCodeAt(i);
-  }
-  const byteArray = new Uint8Array(byteNumbers);
-  const blob = new Blob([byteArray], { type: contentType });
-  return URL.createObjectURL(blob);
-}
+import { useFileDB } from "@/app/utils/file";
 
 function getSdTaskStatus(item: any) {
   let s: string;
@@ -94,45 +84,6 @@ function getSdTaskStatus(item: any) {
   );
 }
 
-function IndexDBImage({ img_data, title, isMobileScreen }) {
-  const [src, setSrc] = useState(img_data);
-  const sdListDb = useIndexedDB(StoreKey.SdList);
-  const img_id = useMemo(
-    () => img_data.replace("indexeddb://", "").split("@").pop(),
-    [img_data],
-  );
-  useEffect(() => {
-    sdListDb
-      .getByID(img_id)
-      .then(({ data }) => {
-        setSrc(data);
-      })
-      .catch((e) => {
-        setSrc(img_data);
-      });
-  }, [img_data, img_id]);
-
-  return (
-    <img
-      className={styles["img"]}
-      src={`data:image/png;base64,${src}`}
-      alt={title}
-      onClick={(e) => {
-        showImageModal(
-          getBase64ImgUrl(src, "image/png"),
-          true,
-          isMobileScreen
-            ? { width: "100%", height: "fit-content" }
-            : { maxWidth: "100%", maxHeight: "100%" },
-          isMobileScreen
-            ? { width: "100%", height: "fit-content" }
-            : { width: "100%", height: "100%" },
-        );
-      }}
-    />
-  );
-}
-
 export function Sd() {
   const isMobileScreen = useMobileScreen();
   const navigate = useNavigate();
@@ -140,7 +91,7 @@ export function Sd() {
   const showMaxIcon = !isMobileScreen && !clientConfig?.isApp;
   const config = useAppConfig();
   const scrollRef = useRef<HTMLDivElement>(null);
-  const sdListDb = useIndexedDB(StoreKey.SdList);
+  const fileDb = useFileDB();
   const sdStore = useSdStore();
   const [sdImages, setSdImages] = useState(sdStore.draw);
 
@@ -197,13 +148,25 @@ export function Sd() {
                   className={styles["sd-img-item"]}
                 >
                   {item.status === "success" ? (
-                    <>
-                      <IndexDBImage
-                        img_data={item.img_data}
-                        title={item.id}
-                        isMobileScreen={isMobileScreen}
-                      />
-                    </>
+                    <IndexDBImage
+                      className={styles["img"]}
+                      db={fileDb}
+                      src={item.img_data}
+                      alt={item.id}
+                      onClick={(data, e) => {
+                        showImageModal(
+                          data,
+                          true,
+                          isMobileScreen
+                            ? { width: "100%", height: "fit-content" }
+                            : { maxWidth: "100%", maxHeight: "100%" },
+                          isMobileScreen
+                            ? { width: "100%", height: "fit-content" }
+                            : { width: "100%", height: "100%" },
+                        );
+                      }}
+                      isMobileScreen={isMobileScreen}
+                    />
                   ) : item.status === "error" ? (
                     <div className={styles["pre-img"]}>
                       <ErrorIcon />
@@ -286,7 +249,7 @@ export function Sd() {
                               created_at: new Date().toLocaleString(),
                               img_data: "",
                             };
-                            sdStore.sendTask(reqData, sdListDb);
+                            sdStore.sendTask(reqData, fileDb);
                           }}
                         />
                         <ChatAction
@@ -295,7 +258,7 @@ export function Sd() {
                           onClick={async () => {
                             if (await showConfirm(Locale.Sd.Danger.Delete)) {
                               // remove img_data + remove item in list
-                              sdListDb.deleteRecord(item.id).then(
+                              fileDb.deleteRecord(item.id).then(
                                 () => {
                                   sdStore.draw = sdImages.filter(
                                     (i: any) => i.id !== item.id,

+ 27 - 0
app/components/ui-lib.tsx

@@ -19,6 +19,7 @@ import React, {
   MouseEvent,
   useEffect,
   useState,
+  useMemo,
 } from "react";
 import { IconButton } from "./button";
 
@@ -510,3 +511,29 @@ export function Selector<T>(props: {
     </div>
   );
 }
+
+export function IndexDBImage({ src, alt, onClick, db, className }) {
+  const [data, setData] = useState(src);
+  const imgId = useMemo(
+    () => src.replace("indexeddb://", "").split("@").pop(),
+    [src],
+  );
+  useEffect(() => {
+    db.getByID(imgId)
+      .then(({ data }) => {
+        setData(`data:image/png;base64,${data}`);
+      })
+      .catch((e) => {
+        setData(src);
+      });
+  }, [src, imgId]);
+
+  return (
+    <img
+      className={className}
+      src={data}
+      alt={alt}
+      onClick={(e) => onClick(data, e)}
+    />
+  );
+}

+ 1 - 0
app/constant.ts

@@ -55,6 +55,7 @@ export enum FileName {
 }
 
 export enum StoreKey {
+  File = "chat-next-web-file",
   Chat = "chat-next-web-store",
   Access = "access-control",
   Config = "app-config",

+ 1 - 25
app/store/sd.ts

@@ -1,33 +1,9 @@
-import { initDB } from "react-indexed-db-hook";
 import { StabilityPath, StoreKey } from "@/app/constant";
 import { showToast } from "@/app/components/ui-lib";
 import { getHeaders } from "@/app/client/api";
 import { createPersistStore } from "@/app/utils/store";
 import { nanoid } from "nanoid";
 
-export const SdDbConfig = {
-  name: "@chatgpt-next-web/sd",
-  version: 1,
-  objectStoresMeta: [
-    {
-      store: StoreKey.SdList,
-      storeConfig: { keyPath: "id", autoIncrement: true },
-      storeSchema: [
-        { name: "data", keypath: "data", options: { unique: false } },
-        {
-          name: "created_at",
-          keypath: "created_at",
-          options: { unique: false },
-        },
-      ],
-    },
-  ],
-};
-
-export function SdDbInit() {
-  initDB(SdDbConfig);
-}
-
 export const useSdStore = createPersistStore<
   {
     currentId: number;
@@ -96,7 +72,7 @@ export const useSdStore = createPersistStore<
               this.updateDraw({
                 ...data,
                 status: "success",
-                img_data: `indexeddb://${StoreKey.SdList}@${data.id}`,
+                img_data: `indexeddb://${StoreKey.File}@${data.id}`,
               });
             } else {
               this.updateDraw({

+ 31 - 0
app/utils/file.tsx

@@ -0,0 +1,31 @@
+"use client";
+import { initDB } from "react-indexed-db-hook";
+import { StoreKey } from "@/app/constant";
+import { useIndexedDB } from "react-indexed-db-hook";
+
+export const FileDbConfig = {
+  name: "@chatgpt-next-web/file",
+  version: 1,
+  objectStoresMeta: [
+    {
+      store: StoreKey.File,
+      storeConfig: { keyPath: "id", autoIncrement: true },
+      storeSchema: [
+        { name: "data", keypath: "data", options: { unique: false } },
+        {
+          name: "created_at",
+          keypath: "created_at",
+          options: { unique: false },
+        },
+      ],
+    },
+  ],
+};
+
+export function FileDbInit() {
+  initDB(FileDbConfig);
+}
+
+export function useFileDB() {
+  return useIndexedDB(StoreKey.File);
+}