From 33450ce429ee7b06488709d61a1afd2dae6262c1 Mon Sep 17 00:00:00 2001 From: lloydzhou Date: Mon, 15 Jul 2024 20:09:21 +0800 Subject: [PATCH] move code to utils/file --- app/components/sd-panel.tsx | 5 ++- app/components/sd.tsx | 87 +++++++++++-------------------------- app/components/ui-lib.tsx | 27 ++++++++++++ app/constant.ts | 1 + app/store/sd.ts | 26 +---------- app/utils/file.tsx | 31 +++++++++++++ 6 files changed, 88 insertions(+), 89 deletions(-) create mode 100644 app/utils/file.tsx diff --git a/app/components/sd-panel.tsx b/app/components/sd-panel.tsx index 12a54c732..36842c742 100644 --- a/app/components/sd-panel.tsx +++ b/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 [ diff --git a/app/components/sd.tsx b/app/components/sd.tsx index ece3e18a0..40e0c9abd 100644 --- a/app/components/sd.tsx +++ b/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 ( - {title} { - 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(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" ? ( - <> - - + { + 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" ? (
@@ -286,7 +249,7 @@ export function Sd() { created_at: new Date().toLocaleString(), img_data: "", }; - sdStore.sendTask(reqData, sdListDb); + sdStore.sendTask(reqData, fileDb); }} /> { 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, diff --git a/app/components/ui-lib.tsx b/app/components/ui-lib.tsx index 27555105a..a859b9695 100644 --- a/app/components/ui-lib.tsx +++ b/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(props: {
); } + +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 ( + {alt} onClick(data, e)} + /> + ); +} diff --git a/app/constant.ts b/app/constant.ts index 201843e90..509b90ee0 100644 --- a/app/constant.ts +++ b/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", diff --git a/app/store/sd.ts b/app/store/sd.ts index 7218926df..77b20d001 100644 --- a/app/store/sd.ts +++ b/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({ diff --git a/app/utils/file.tsx b/app/utils/file.tsx new file mode 100644 index 000000000..0e77840e4 --- /dev/null +++ b/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); +}