diff options
author | firecoperana <xuqiaowei1124@gmail.com> | 2025-07-20 05:33:55 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-20 12:33:55 +0200 |
commit | d44c2d3f5aeab25a9405896f48a36082cee5d8ac (patch) | |
tree | 6768d4d8c72fb0b5c7b4a5a4187d2eccb292f0ad /examples/server/webui/src/components/ModalProvider.tsx | |
parent | f989fb03bd12752ad6e93717ca4bd298d5001d99 (diff) |
Webui: New Features for Conversations, Settings, and Chat Messages (#618)main
* Webui: add Rename/Upload conversation in header and sidebar
webui: don't change modified date when renaming conversation
* webui: add a preset feature to the settings #14649
* webui: Add editing assistant messages #13522
Webui: keep the following message while editing assistance response.
webui: change icon to edit message
* webui: DB import and export #14347
* webui: Wrap long numbers instead of infinite horizontal scroll (#14062)
fix sidebar being covered by main content #14082
---------
Co-authored-by: firecoperana <firecoperana>
Diffstat (limited to 'examples/server/webui/src/components/ModalProvider.tsx')
-rw-r--r-- | examples/server/webui/src/components/ModalProvider.tsx | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/examples/server/webui/src/components/ModalProvider.tsx b/examples/server/webui/src/components/ModalProvider.tsx new file mode 100644 index 00000000..f2ebf8e0 --- /dev/null +++ b/examples/server/webui/src/components/ModalProvider.tsx @@ -0,0 +1,151 @@ +import React, { createContext, useState, useContext } from 'react'; + +type ModalContextType = { + showConfirm: (message: string) => Promise<boolean>; + showPrompt: ( + message: string, + defaultValue?: string + ) => Promise<string | undefined>; + showAlert: (message: string) => Promise<void>; +}; +const ModalContext = createContext<ModalContextType>(null!); + +interface ModalState<T> { + isOpen: boolean; + message: string; + defaultValue?: string; + resolve: ((value: T) => void) | null; +} + +export function ModalProvider({ children }: { children: React.ReactNode }) { + const [confirmState, setConfirmState] = useState<ModalState<boolean>>({ + isOpen: false, + message: '', + resolve: null, + }); + const [promptState, setPromptState] = useState< + ModalState<string | undefined> + >({ isOpen: false, message: '', resolve: null }); + const [alertState, setAlertState] = useState<ModalState<void>>({ + isOpen: false, + message: '', + resolve: null, + }); + const inputRef = React.useRef<HTMLInputElement>(null); + + const showConfirm = (message: string): Promise<boolean> => { + return new Promise((resolve) => { + setConfirmState({ isOpen: true, message, resolve }); + }); + }; + + const showPrompt = ( + message: string, + defaultValue?: string + ): Promise<string | undefined> => { + return new Promise((resolve) => { + setPromptState({ isOpen: true, message, defaultValue, resolve }); + }); + }; + + const showAlert = (message: string): Promise<void> => { + return new Promise((resolve) => { + setAlertState({ isOpen: true, message, resolve }); + }); + }; + + const handleConfirm = (result: boolean) => { + confirmState.resolve?.(result); + setConfirmState({ isOpen: false, message: '', resolve: null }); + }; + + const handlePrompt = (result?: string) => { + promptState.resolve?.(result); + setPromptState({ isOpen: false, message: '', resolve: null }); + }; + + const handleAlertClose = () => { + alertState.resolve?.(); + setAlertState({ isOpen: false, message: '', resolve: null }); + }; + + return ( + <ModalContext.Provider value={{ showConfirm, showPrompt, showAlert }}> + {children} + + {/* Confirm Modal */} + {confirmState.isOpen && ( + <dialog className="modal modal-open z-[1100]"> + <div className="modal-box"> + <h3 className="font-bold text-lg">{confirmState.message}</h3> + <div className="modal-action"> + <button + className="btn btn-ghost" + onClick={() => handleConfirm(false)} + > + Cancel + </button> + <button + className="btn btn-error" + onClick={() => handleConfirm(true)} + > + Confirm + </button> + </div> + </div> + </dialog> + )} + + {/* Prompt Modal */} + {promptState.isOpen && ( + <dialog className="modal modal-open z-[1100]"> + <div className="modal-box"> + <h3 className="font-bold text-lg">{promptState.message}</h3> + <input + type="text" + className="input input-bordered w-full mt-2" + defaultValue={promptState.defaultValue} + ref={inputRef} + onKeyDown={(e) => { + if (e.key === 'Enter') { + handlePrompt((e.target as HTMLInputElement).value); + } + }} + /> + <div className="modal-action"> + <button className="btn btn-ghost" onClick={() => handlePrompt()}> + Cancel + </button> + <button + className="btn btn-primary" + onClick={() => handlePrompt(inputRef.current?.value)} + > + Submit + </button> + </div> + </div> + </dialog> + )} + + {/* Alert Modal */} + {alertState.isOpen && ( + <dialog className="modal modal-open z-[1100]"> + <div className="modal-box"> + <h3 className="font-bold text-lg">{alertState.message}</h3> + <div className="modal-action"> + <button className="btn" onClick={handleAlertClose}> + OK + </button> + </div> + </div> + </dialog> + )} + </ModalContext.Provider> + ); +} + +export function useModals() { + const context = useContext(ModalContext); + if (!context) throw new Error('useModals must be used within ModalProvider'); + return context; +} |