@@ -43,7 +43,7 @@ import {
4343 Settings24Regular ,
4444} from "@fluentui/react-icons" ;
4545import { useStyles } from "./useStyles" ;
46- import { GITHUB_REPO_LINK , HISTORY_KEY , MAX_HISTORY_ITEMS } from "./constants" ;
46+ import { GITHUB_REPO_LINK } from "./constants" ;
4747import { GithubIcon } from "./icons" ;
4848import { CharacterBookTab } from "./tabs/CharacterBookTab" ;
4949import { useGlobalDrop } from "./useGlobalDrop" ;
@@ -59,6 +59,9 @@ import { ToolTab } from "./tabs/ToolTab";
5959import { useGlobalPaste } from "./useGlobalPaste" ;
6060import { StartPanel } from "./StartPanel/StartPanel" ;
6161import pkgJson from "../../package.json" ;
62+ import { cardDB } from "../db/db" ;
63+ import { deepClone } from "../common/deepclone" ;
64+ import type { CardRecord } from "../db/types" ;
6265
6366function getDefaultFormData ( ) {
6467 return {
@@ -96,7 +99,7 @@ export function App() {
9699 const [ avatarPreview , setAvatarPreview ] = useState < null | string > ( null ) ;
97100 const [ originalFile , setOriginalFile ] = useState < null | ArrayBuffer > ( null ) ;
98101 const [ originalFileName , setOriginalFileName ] = useState ( "" ) ;
99- const [ history , setHistory ] = useState < any [ ] > ( [ ] ) ;
102+ const [ history , setHistory ] = useState < CardRecord [ ] > ( [ ] ) ;
100103 const [ isHistoryDrawerOpen , setIsHistoryDrawerOpen ] = useState ( false ) ;
101104 const [ selectedTab , setSelectedTab ] = useState ( "basic" ) ;
102105 const [ isDirty , setIsDirty ] = useState ( false ) ;
@@ -109,8 +112,10 @@ export function App() {
109112 } ) ;
110113
111114 useEffect ( ( ) => {
112- const storedHistory = localStorage . getItem ( HISTORY_KEY ) ;
113- if ( storedHistory ) setHistory ( JSON . parse ( storedHistory ) ) ;
115+ ( async ( ) => {
116+ const cards = await cardDB . getAll ( ) ;
117+ setHistory ( cards ) ;
118+ } ) ( ) ;
114119 } , [ ] ) ;
115120
116121 useEffect ( ( ) => {
@@ -226,45 +231,37 @@ export function App() {
226231 ) ;
227232 } ;
228233
229- const addToHistory = (
234+ const addToHistory = async (
230235 cardData : SpecV3 . CharacterCardV3 [ "data" ] ,
231236 avatarUrl : string | null ,
232237 spec : string ,
233238 spec_version : string
234239 ) => {
235240 if ( ! cardData || ! cardData . name ) return ;
241+ const newCard = CharacterCard . from_json (
242+ {
243+ data : cardData ,
244+ spec,
245+ spec_version,
246+ } ,
247+ avatarUrl ?? undefined
248+ ) ;
249+ const record = cardDB . create ( { card : newCard . toSpecV3 ( ) , avatarUrl } ) ;
250+ try {
251+ await cardDB . addRecord ( record ) ;
252+ } catch ( error ) {
253+ console . error ( "Error adding record to history:" , error ) ;
254+ return ;
255+ }
236256 setHistory ( ( prevHistory ) => {
237257 const newHistory = prevHistory . filter (
238258 ( item ) =>
239259 ! (
240- item . data . name === cardData . name &&
241- item . data . first_mes === cardData . first_mes
260+ item . card . data . name === cardData . name &&
261+ item . card . data . first_mes === cardData . first_mes
242262 )
243263 ) ;
244- const newEntry = {
245- data : JSON . parse ( JSON . stringify ( cardData ) ) , // Deep copy
246- avatar : avatarUrl ,
247- timestamp : new Date ( ) . toISOString ( ) ,
248- spec : spec || "chara_card_v3" , // Store spec info
249- spec_version : spec_version || "3.0" ,
250- } ;
251- const updatedHistory = [ newEntry , ...newHistory ] . slice (
252- 0 ,
253- MAX_HISTORY_ITEMS
254- ) ;
255- try {
256- localStorage . setItem ( HISTORY_KEY , JSON . stringify ( updatedHistory ) ) ;
257- } catch ( error ) {
258- if ( error instanceof Error && error . name === "QuotaExceededError" ) {
259- alert (
260- "Local storage quota exceeded. Some history items may be lost."
261- ) ;
262- return prevHistory ;
263- } else {
264- throw error ;
265- }
266- }
267- return updatedHistory ;
264+ return [ record , ...newHistory ] ;
268265 } ) ;
269266 } ;
270267
@@ -276,14 +273,17 @@ export function App() {
276273 const confirmLoadFromHistory = ( index : number ) => {
277274 const item = history [ index ] ;
278275 if ( item ) {
279- const mockCard = new CharacterCard ( item ) ; // For spec/version info
276+ const mockCard = new CharacterCard (
277+ item . card ,
278+ item . avatarUrl ?? undefined
279+ ) ; // For spec/version info
280280 setCharacterCard ( mockCard ) ;
281281
282- setFormDataFromCardData ( item . data ) ;
283- setAvatarPreview ( item . avatar || null ) ;
282+ setFormDataFromCardData ( item . card . data ) ;
283+ setAvatarPreview ( mockCard . avatar || null ) ;
284284 setOriginalFile ( null ) ;
285285 setOriginalFileName (
286- `Loaded from history: ${ item . data . name || "Unnamed" } `
286+ `Loaded from history: ${ item . card . data . name || "Unnamed" } `
287287 ) ;
288288 setIsDirty ( false ) ;
289289 setSelectedTab ( "basic" ) ; // Reset to basic tab on load
@@ -292,10 +292,10 @@ export function App() {
292292 setShowHistoryLoadConfirm ( { open : false , index : - 1 } ) ;
293293 } ;
294294
295- const handleClearHistory = ( ) => {
295+ const handleClearHistory = async ( ) => {
296296 if ( confirm ( "Are you sure you want to clear all history?" ) ) {
297297 setHistory ( [ ] ) ;
298- localStorage . removeItem ( HISTORY_KEY ) ;
298+ await cardDB . clear ( ) ;
299299 }
300300 } ;
301301
@@ -407,26 +407,30 @@ export function App() {
407407 < DrawerBody className = { styles . historyDrawerBody } >
408408 { history . length > 0 ? (
409409 < >
410- { history . map ( ( item , index ) => (
411- < div
412- key = { index }
413- className = { styles . historyItem }
414- onClick = { ( ) => handleLoadFromHistory ( index ) }
415- tabIndex = { 0 }
416- onKeyDown = { ( e ) => {
417- if ( e . key === "Enter" || e . key === " " )
418- handleLoadFromHistory ( index ) ;
419- } }
420- >
421- < Text className = { styles . historyItemName } >
422- { item . data . name || t ( "Unnamed Card" ) }
423- </ Text >
424- < Text className = { styles . historyItemDate } >
425- { new Date ( item . timestamp ) . toLocaleDateString ( ) }
426- </ Text >
427- </ div >
428- ) ) }
429- < Divider style = { { margin : `${ tokens . spacingVerticalM } 0` } } />
410+ < div style = { { flex : 1 } } >
411+ { history . map ( ( item , index ) => (
412+ < div
413+ key = { index }
414+ className = { styles . historyItem }
415+ onClick = { ( ) => handleLoadFromHistory ( index ) }
416+ tabIndex = { 0 }
417+ onKeyDown = { ( e ) => {
418+ if ( e . key === "Enter" || e . key === " " )
419+ handleLoadFromHistory ( index ) ;
420+ } }
421+ >
422+ < Text className = { styles . historyItemName } >
423+ { item . card . data . name || t ( "Unnamed Card" ) }
424+ </ Text >
425+ < Text className = { styles . historyItemDate } >
426+ { new Date ( item . updatedAt ) . toLocaleDateString ( ) }
427+ </ Text >
428+ </ div >
429+ ) ) }
430+ </ div >
431+ < Divider
432+ style = { { margin : `${ tokens . spacingVerticalM } 0` , flex : 0 } }
433+ />
430434 < Button
431435 appearance = "outline"
432436 onClick = { handleClearHistory }
0 commit comments