From 5707bfef5e6506fb0b034489771c80e887daa252 Mon Sep 17 00:00:00 2001 From: Pabloader Date: Thu, 26 Mar 2026 12:03:50 +0000 Subject: [PATCH] Highlight the last edited text --- src/games/storywriter/assets/editor.module.css | 5 +++++ src/games/storywriter/components/editor.tsx | 17 +++++++++++++++-- src/games/storywriter/contexts/state.tsx | 7 +++++-- src/games/storywriter/utils/tools.ts | 2 +- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/games/storywriter/assets/editor.module.css b/src/games/storywriter/assets/editor.module.css index 7728cde..aa5c147 100644 --- a/src/games/storywriter/assets/editor.module.css +++ b/src/games/storywriter/assets/editor.module.css @@ -75,6 +75,11 @@ word-break: break-word; } +.editable mark { + background: var(--bg-active); + color: inherit; +} + .tab { padding: 12px 16px; background: transparent; diff --git a/src/games/storywriter/components/editor.tsx b/src/games/storywriter/components/editor.tsx index acbfbf9..ce4ecd9 100644 --- a/src/games/storywriter/components/editor.tsx +++ b/src/games/storywriter/components/editor.tsx @@ -50,9 +50,22 @@ export const Editor = () => { if (contentRef.current) { contentRef.current.scrollTop = contentRef.current.scrollHeight; } - }, [currentStory?.currentTab]); + }, [currentStory?.id, currentStory?.currentTab]); + + const storyValue = useMemo(() => { + if (!currentStory) return ''; + + const { text, lastEditedText } = currentStory; + if (!lastEditedText) return highlight(text); + + const idx = text.lastIndexOf(lastEditedText); + if (idx === -1) return highlight(text); + + const marked = text.slice(0, idx) + '' + lastEditedText + '' + text.slice(idx + lastEditedText.length); + + return highlight(marked); + }, [currentStory?.text, currentStory?.lastEditedText]); - const storyValue = useMemo(() => currentStory ? highlight(currentStory.text) : '', [currentStory?.text]); const promptPreview = useMemo(() => { if (currentStory?.currentTab !== 'prompt') return ''; const text = Prompt.formatSystemPrompt(appState); diff --git a/src/games/storywriter/contexts/state.tsx b/src/games/storywriter/contexts/state.tsx index 97a15b0..6ac867a 100644 --- a/src/games/storywriter/contexts/state.tsx +++ b/src/games/storywriter/contexts/state.tsx @@ -74,6 +74,7 @@ export interface Story { currentTab: Tab; chatMessages: ChatMessage[]; chapters: Chapters.Chapter[]; + lastEditedText?: string; } // ─── State ─────────────────────────────────────────────────────────────────── @@ -93,7 +94,7 @@ interface IState { type Action = | { type: 'CREATE_STORY'; title: string } | { type: 'RENAME_STORY'; id: string; title: string } - | { type: 'EDIT_STORY'; id: string; text: string } + | { type: 'EDIT_STORY'; id: string; text: string; highlightText?: string } | { type: 'EDIT_SCRATCHPAD'; id: string; text: string } | { type: 'ADD_LORE_ENTRY'; storyId: string; entry: LoreEntry } | { type: 'EDIT_LORE_ENTRY'; storyId: string; entryId: string; updates: Partial } @@ -190,7 +191,9 @@ function reducer(state: IState, action: Action): IState { return { ...state, stories: state.stories.map(s => - s.id === action.id ? { ...s, text: action.text } : s + s.id === action.id + ? { ...s, text: action.text, lastEditedText: action.highlightText } + : s ), }; } diff --git a/src/games/storywriter/utils/tools.ts b/src/games/storywriter/utils/tools.ts index b6c702a..6e0cfd9 100644 --- a/src/games/storywriter/utils/tools.ts +++ b/src/games/storywriter/utils/tools.ts @@ -342,7 +342,7 @@ export namespace Tools { const dispatchEdit = (text: string) => appState.dispatch( isScratchpad ? { type: 'EDIT_SCRATCHPAD', id: appState.currentStory!.id, text } - : { type: 'EDIT_STORY', id: appState.currentStory!.id, text } + : { type: 'EDIT_STORY', id: appState.currentStory!.id, text, highlightText: args.new_text } ); // Append mode: when old_text is not provided, append new_text