diff --git a/src/components/IndexManager/IndexManager.tsx b/src/components/IndexManager/IndexManager.tsx new file mode 100644 index 0000000..6687043 --- /dev/null +++ b/src/components/IndexManager/IndexManager.tsx @@ -0,0 +1,118 @@ +import { + Box, + ButtonBase, + Dialog, + DialogContent, + DialogTitle, + IconButton, + Typography, +} from "@mui/material"; +import React, { useState } from "react"; +import { useIndexStore } from "../../state/indexes"; +import CloseIcon from "@mui/icons-material/Close"; +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; +export const IndexManager = () => { + const open = useIndexStore((state) => state.open); + const setOpen = useIndexStore((state) => state.setOpen); + const [mode, setMode] = useState(1); + + const handleClose = () => { + setOpen(null); + setMode(1); + }; + return ( + + Index manager + ({ + position: "absolute", + right: 8, + top: 8, + })} + > + + + + + setMode(1)}> + {mode === 1 && ( + <> + + + Create new index + + + + + Your indices + + + setMode(4)} + > + + Add metadata + + + + )} + + {mode === 4 && } + + + + ); +}; + +const AddMetadata = () => { + return hello; +}; diff --git a/src/context/GlobalProvider.tsx b/src/context/GlobalProvider.tsx index 4b94ccc..3e0a63b 100644 --- a/src/context/GlobalProvider.tsx +++ b/src/context/GlobalProvider.tsx @@ -5,6 +5,8 @@ import { useAppInfo } from "../hooks/useAppInfo"; import { useIdentifiers } from "../hooks/useIdentifiers"; import { Toaster } from "react-hot-toast"; import { useLocalStorage } from "../hooks/useLocalStorage"; +import { IndexManager } from "../components/IndexManager/IndexManager"; +import { useIndexes } from "../hooks/useIndexes"; @@ -17,6 +19,7 @@ lists: ReturnType; appInfo: ReturnType; identifierOperations: ReturnType localStorageOperations: ReturnType +indexOperations: ReturnType } @@ -45,8 +48,9 @@ export const GlobalProvider = ({ children, config, toastStyle = {} }: GlobalProv const lists = useResources() const identifierOperations = useIdentifiers(config.publicSalt, config.appName) const localStorageOperations = useLocalStorage(config.publicSalt, config.appName) + const indexOperations = useIndexes() // ✅ Merge all hooks into a single `contextValue` - const contextValue = useMemo(() => ({ auth, lists, appInfo, identifierOperations, localStorageOperations }), [auth, lists, appInfo, identifierOperations, localStorageOperations]); + const contextValue = useMemo(() => ({ auth, lists, appInfo, identifierOperations, localStorageOperations, indexOperations }), [auth, lists, appInfo, identifierOperations, localStorageOperations]); return ( + {children} ); diff --git a/src/hooks/useIndexes.tsx b/src/hooks/useIndexes.tsx new file mode 100644 index 0000000..8aa28df --- /dev/null +++ b/src/hooks/useIndexes.tsx @@ -0,0 +1,20 @@ +import React, { useCallback } from "react"; +import { OpenIndex, useIndexStore } from "../state/indexes"; + +export const useIndexes = () => { + const setOpen = useIndexStore((state) => state.setOpen); + const openPageIndexManager = useCallback( + ({ link, name }: OpenIndex) => { + if(!link || !name) return + setOpen({ + name, + link, + }); + }, + [setOpen] + ); + + return { + openPageIndexManager, + }; +}; diff --git a/src/index.ts b/src/index.ts index d02ed18..146862c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,8 @@ export { useResourceStatus } from './hooks/useResourceStatus'; +export { Spacer } from './common/Spacer'; import './index.css' +export { hashWordWithoutPublicSalt } from './utils/encryption'; +export { createAvatarLink } from './utils/qortal'; export { objectToBase64 } from './utils/base64'; export { generateBloomFilterBase64, isInsideBloom } from './utils/bloomFilter'; export { addAndEncryptSymmetricKeys, decryptWithSymmetricKeys, encryptWithSymmetricKeys } from './utils/encryption'; @@ -20,4 +23,3 @@ export {Service} from './types/interfaces/resources' export {ListItem} from './state/cache' export {SymmetricKeys} from './utils/encryption' - diff --git a/src/state/indexes.ts b/src/state/indexes.ts new file mode 100644 index 0000000..08ff4e8 --- /dev/null +++ b/src/state/indexes.ts @@ -0,0 +1,18 @@ +import { create } from "zustand"; + +export interface OpenIndex { + link: string + name: string +} + +interface IndexState { + open: OpenIndex | null; + setOpen: (openIndex: OpenIndex | null ) => void; +} + +// ✅ Typed Zustand Store +export const useIndexStore = create((set) => ({ + open: null, + setOpen: (openIndex) => + set({ open: openIndex }), +})); diff --git a/src/utils/encryption.ts b/src/utils/encryption.ts index 1cf33d5..bcacd34 100644 --- a/src/utils/encryption.ts +++ b/src/utils/encryption.ts @@ -48,6 +48,35 @@ export async function hashWord( } } +export async function hashWordWithoutPublicSalt( + word: string, + collisionStrength: number +): Promise { + try { + if (!crypto?.subtle?.digest) throw new Error("Web Crypto not available"); + + const encoded = new TextEncoder().encode(word); + const hashBuffer = await crypto.subtle.digest("SHA-256", encoded); + + return Buffer.from(hashBuffer) + .toString("base64") + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/, "") + .slice(0, collisionStrength); + } catch (err) { + const hash = SHA256(word); + const base64 = EncBase64.stringify(hash); + + return base64 + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/, "") + .slice(0, collisionStrength); + } +} + + const uid = new ShortUniqueId({ length: 10, dictionary: "alphanum" }); interface EntityConfig { diff --git a/src/utils/qortal.ts b/src/utils/qortal.ts new file mode 100644 index 0000000..78c3927 --- /dev/null +++ b/src/utils/qortal.ts @@ -0,0 +1,3 @@ +export const createAvatarLink = (qortalName: string)=> { + return `/arbitrary/THUMBNAIL/${encodeURIComponent(qortalName)}/qortal_avatar?async=true` +} \ No newline at end of file