Replace all textarea to contenteditable
This commit is contained in:
parent
42d88394c7
commit
ad8895430b
|
|
@ -71,6 +71,7 @@
|
|||
min-height: 80px;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
resize: vertical;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ export const ChaptersEditor = () => {
|
|||
)}
|
||||
<div class={styles.chunkPreview}>{body}</div>
|
||||
<ContentEditable
|
||||
autoLines
|
||||
class={styles.summaryEditable}
|
||||
value={highlight(summary ?? '')}
|
||||
placeholder="Not summarized yet..."
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { useAppState, type Character } from "../contexts/state";
|
|||
import { useState } from "preact/hooks";
|
||||
import styles from '../assets/character-editor.module.css';
|
||||
import LLM from "../utils/llm";
|
||||
import { ContentEditable } from "@common/components/ContentEditable";
|
||||
|
||||
export const CharacterEditor = () => {
|
||||
const { currentStory, dispatch, connection, model } = useAppState();
|
||||
|
|
@ -174,12 +175,12 @@ export const CharacterEditor = () => {
|
|||
|
||||
<div class={styles.field}>
|
||||
<div class={styles.label}>Description</div>
|
||||
<textarea
|
||||
<ContentEditable
|
||||
autoLines
|
||||
class={styles.textarea}
|
||||
value={character.description}
|
||||
onInput={(e) => handleEditCharacter(character.id, 'description', e.currentTarget.value)}
|
||||
onInput={(e) => handleEditCharacter(character.id, 'description', e.currentTarget.textContent)}
|
||||
placeholder="Full character description..."
|
||||
rows={4}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { useAppState, type Location, LocationScale } from "../contexts/state";
|
|||
import { useState } from "preact/hooks";
|
||||
import styles from '../assets/location-editor.module.css';
|
||||
import LLM from "../utils/llm";
|
||||
import { ContentEditable } from "@common/components/ContentEditable";
|
||||
|
||||
const SCALE_OPTIONS = Object.entries(LocationScale)
|
||||
.filter(([, value]) => typeof value === 'number')
|
||||
|
|
@ -138,12 +139,12 @@ export const LocationEditor = () => {
|
|||
|
||||
<div class={styles.field}>
|
||||
<div class={styles.label}>Description</div>
|
||||
<textarea
|
||||
<ContentEditable
|
||||
autoLines
|
||||
class={styles.textarea}
|
||||
value={location.description}
|
||||
onInput={(e) => handleEditLocation(location.id, 'description', e.currentTarget.value)}
|
||||
onInput={(e) => handleEditLocation(location.id, 'description', e.currentTarget.textContent)}
|
||||
placeholder="Full location description..."
|
||||
rows={4}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export namespace Tools {
|
|||
appState.dispatch({
|
||||
type: 'EDIT_STORY',
|
||||
id: appState.currentStory.id,
|
||||
text: appState.currentStory.text + args.text,
|
||||
text: appState.currentStory.text + '\n' + args.text,
|
||||
});
|
||||
appState.dispatch({
|
||||
type: 'SET_CURRENT_TAB',
|
||||
|
|
@ -50,7 +50,7 @@ export namespace Tools {
|
|||
appState.dispatch({
|
||||
type: 'EDIT_LORE',
|
||||
id: appState.currentStory.id,
|
||||
lore: appState.currentStory.lore + args.text
|
||||
lore: appState.currentStory.lore + '\n' + args.text,
|
||||
});
|
||||
appState.dispatch({
|
||||
type: 'SET_CURRENT_TAB',
|
||||
|
|
@ -296,7 +296,11 @@ export namespace Tools {
|
|||
if (!appState.currentStory) {
|
||||
return 'Error: No story selected';
|
||||
}
|
||||
const lines = appState.currentStory.text.split('\n');
|
||||
const source = args.source === 'lore'
|
||||
? appState.currentStory.lore
|
||||
: appState.currentStory.text;
|
||||
|
||||
const lines = source.split('\n');
|
||||
const matches: { line: number; content: string }[] = [];
|
||||
const pattern = new RegExp(args.pattern, args.case_sensitive ? 'g' : 'gi');
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
|
|
@ -317,11 +321,14 @@ export namespace Tools {
|
|||
}
|
||||
return result;
|
||||
},
|
||||
description: 'Search for a pattern in the story text',
|
||||
description: 'Search for a pattern in the story text or lore',
|
||||
parameters: Type.Object({
|
||||
pattern: Type.String({ description: 'The regex pattern to search for' }),
|
||||
case_sensitive: Type.Optional(Type.Boolean({ description: 'If true, search is case-sensitive (default: false)' })),
|
||||
limit: Type.Optional(Type.Integer({ description: 'Maximum number of matches to return (default: 20)' })),
|
||||
source: Type.Optional(Type.Enum(['lore', 'story'],
|
||||
{ description: 'Source to search (story or lore, default: story)' },
|
||||
)),
|
||||
}),
|
||||
})
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue