file.tsx 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { useState, useMemo, useEffect } from "react";
  2. import { initDB } from "react-indexed-db-hook";
  3. import { StoreKey } from "@/app/constant";
  4. import { useIndexedDB } from "react-indexed-db-hook";
  5. export const FileDbConfig = {
  6. name: "@chatgpt-next-web/file",
  7. version: 1,
  8. objectStoresMeta: [
  9. {
  10. store: StoreKey.File,
  11. storeConfig: { keyPath: "id", autoIncrement: true },
  12. storeSchema: [
  13. { name: "data", keypath: "data", options: { unique: false } },
  14. {
  15. name: "created_at",
  16. keypath: "created_at",
  17. options: { unique: false },
  18. },
  19. ],
  20. },
  21. ],
  22. };
  23. export function FileDbInit() {
  24. if (typeof window !== "undefined") {
  25. initDB(FileDbConfig);
  26. }
  27. }
  28. export function useFileDB() {
  29. return useIndexedDB(StoreKey.File);
  30. }
  31. export function base64Image2Blob(base64Data: string, contentType: string) {
  32. const byteCharacters = atob(base64Data);
  33. const byteNumbers = new Array(byteCharacters.length);
  34. for (let i = 0; i < byteCharacters.length; i++) {
  35. byteNumbers[i] = byteCharacters.charCodeAt(i);
  36. }
  37. const byteArray = new Uint8Array(byteNumbers);
  38. return new Blob([byteArray], { type: contentType });
  39. }
  40. export function saveFileData(db: any, fileId: string, data: Blob | string) {
  41. // save file content and return url start with `indexeddb://`
  42. db.add({ id: fileId, data });
  43. return `indexeddb://${StoreKey.File}@${fileId}`;
  44. }
  45. export async function getFileData(
  46. db: any,
  47. fileId: string,
  48. contentType = "image/png",
  49. ) {
  50. const { data } = await db.getByID(fileId);
  51. if (typeof data == "object") {
  52. return URL.createObjectURL(data);
  53. }
  54. return `data:${contentType};base64,${data}`;
  55. }
  56. export function IndexDBImage({
  57. src,
  58. alt,
  59. onClick,
  60. db,
  61. className,
  62. }: {
  63. src: string;
  64. alt: string;
  65. onClick: any;
  66. db: any;
  67. className: string;
  68. }) {
  69. const [data, setData] = useState(src);
  70. const imgId = useMemo(
  71. () => src.replace("indexeddb://", "").split("@").pop(),
  72. [src],
  73. );
  74. useEffect(() => {
  75. getFileData(db, imgId as string)
  76. .then((data) => setData(data))
  77. .catch((e) => setData(src));
  78. }, [src, imgId]);
  79. return (
  80. <img
  81. className={className}
  82. src={data}
  83. alt={alt}
  84. onClick={(e) => onClick(data, e)}
  85. />
  86. );
  87. }