From 3b8cae9baacb8ed29a8bfdd42ac0c363b25c6159 Mon Sep 17 00:00:00 2001 From: Alice Hernandez Date: Mon, 8 Jun 2026 19:54:49 +1000 Subject: [PATCH] =?UTF-8?q?=E2=99=BF=20display=20prompt=20separately=20fro?= =?UTF-8?q?m=20story=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/fileSystem.ts | 1 + .../components/Dashboard/PromptHero.tsx | 5 ++-- .../components/Editor/MarkdownEditor.tsx | 27 ++++++++++++++---- src/renderer/styles/app.css | 28 +++++++++++++++++++ src/renderer/types/borges.ts | 1 + 5 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/main/fileSystem.ts b/src/main/fileSystem.ts index ddab755..8394e62 100644 --- a/src/main/fileSystem.ts +++ b/src/main/fileSystem.ts @@ -9,6 +9,7 @@ export interface StoryMeta { wordCountTarget?: number tags?: string[] notes?: string + prompt?: string } export interface Market { diff --git a/src/renderer/components/Dashboard/PromptHero.tsx b/src/renderer/components/Dashboard/PromptHero.tsx index fc62959..652c1a8 100644 --- a/src/renderer/components/Dashboard/PromptHero.tsx +++ b/src/renderer/components/Dashboard/PromptHero.tsx @@ -72,13 +72,12 @@ export function PromptHero(): JSX.Element { } const name = `Story ${stories.length + 1}` const created = await window.api.createStory(name) + await window.api.setStoryMeta(created.id, { prompt }) const refreshed = await window.api.listStories() setStories(refreshed) const story = refreshed.find((s) => s.path === created.path) if (story) { - const initial = `> ${prompt}\n\n` - await window.api.writeStory(story.path, initial) - setActiveStory(story.path, story.id, initial) + setActiveStory(story.path, story.id, '') } } diff --git a/src/renderer/components/Editor/MarkdownEditor.tsx b/src/renderer/components/Editor/MarkdownEditor.tsx index 8e7ba98..0b8902f 100644 --- a/src/renderer/components/Editor/MarkdownEditor.tsx +++ b/src/renderer/components/Editor/MarkdownEditor.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef } from 'react' +import { useEffect, useRef, useState } from 'react' import { EditorView, keymap, Decoration, type DecorationSet, ViewPlugin, type ViewUpdate } from '@codemirror/view' import { EditorState, StateField, StateEffect, RangeSetBuilder, Compartment } from '@codemirror/state' import { markdown } from '@codemirror/lang-markdown' @@ -53,11 +53,11 @@ const annPlugin = ViewPlugin.fromClass(class { const themeCompartment = new Compartment() const fontSizeCompartment = new Compartment() -function buildTheme(fontSize: number, isDark: boolean): ReturnType { +function buildTheme(fontSize: number, isDark: boolean, hasPrompt = false): ReturnType { return EditorView.theme({ '&': { height: '100%', background: 'transparent' }, '.cm-scroller': { fontFamily: 'Georgia, "Times New Roman", serif', fontSize: `${fontSize}px`, lineHeight: '1.85', overflow: 'auto' }, - '.cm-content': { maxWidth: '680px', margin: '0 auto', padding: '48px 24px 24px', caretColor: 'var(--accent)' }, + '.cm-content': { maxWidth: '680px', margin: '0 auto', padding: `${hasPrompt ? '24px' : '48px'} 24px 24px`, caretColor: 'var(--accent)' }, '.cm-line': { padding: '0' }, '.cm-cursor': { borderLeftColor: 'var(--accent)', borderLeftWidth: '2px' }, '.cm-selectionBackground': { background: 'rgba(200,169,110,0.25)' }, @@ -85,6 +85,7 @@ export function MarkdownEditor(): JSX.Element { const viewRef = useRef(null) const lastPathRef = useRef(null) const storeTimerRef = useRef | null>(null) + const [storyPrompt, setStoryPrompt] = useState(null) // Initialize editor @@ -159,6 +160,14 @@ export function MarkdownEditor(): JSX.Element { } }, [activeStoryPath, activeStoryContent, setRevisions]) + // Load prompt from meta when story changes + useEffect(() => { + if (!activeStoryId) { setStoryPrompt(null); return } + window.api.getStoryMeta(activeStoryId).then((meta) => { + setStoryPrompt(meta.prompt ?? null) + }).catch(() => setStoryPrompt(null)) + }, [activeStoryId]) + // Sync annotations into editor useEffect(() => { const view = viewRef.current @@ -168,8 +177,8 @@ export function MarkdownEditor(): JSX.Element { // Update theme useEffect(() => { - viewRef.current?.dispatch({ effects: themeCompartment.reconfigure(buildTheme(fontSize, theme === 'dark')) }) - }, [theme, fontSize]) + viewRef.current?.dispatch({ effects: themeCompartment.reconfigure(buildTheme(fontSize, theme === 'dark', !!storyPrompt)) }) + }, [theme, fontSize, storyPrompt]) if (!activeStoryId) { return
Select a story or create a new one
@@ -178,6 +187,14 @@ export function MarkdownEditor(): JSX.Element { return (
+ {storyPrompt && ( +
+
+ Prompt + {storyPrompt} +
+
+ )}
{ diff --git a/src/renderer/styles/app.css b/src/renderer/styles/app.css index 41a7fae..2d56b47 100644 --- a/src/renderer/styles/app.css +++ b/src/renderer/styles/app.css @@ -799,3 +799,31 @@ textarea { resize: vertical; } /* Misc */ .inline-edit { background: none; border: none; padding: 0; font: inherit; color: inherit; width: 100%; outline: none; border-bottom: 1px solid var(--accent); } .no-story-placeholder { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text3); font-size: 14px; } + +/* ── Story prompt banner ─────────────────────────────────────────────────── */ +.story-prompt-banner { + flex-shrink: 0; + overflow: hidden; + font-family: Georgia, "Times New Roman", serif; +} +.story-prompt-banner-inner { + max-width: 680px; + margin: 0 auto; + padding: 28px 24px 0; + font-size: 13px; + font-style: italic; + color: var(--text3); + line-height: 1.6; +} +.story-prompt-banner-label { + display: block; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + font-style: normal; + font-size: 10px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.07em; + color: var(--text3); + margin-bottom: 6px; + opacity: 0.7; +} diff --git a/src/renderer/types/borges.ts b/src/renderer/types/borges.ts index d27d5a7..8fb98ff 100644 --- a/src/renderer/types/borges.ts +++ b/src/renderer/types/borges.ts @@ -3,6 +3,7 @@ export interface StoryMeta { wordCountTarget?: number tags?: string[] notes?: string + prompt?: string } export interface StoryFile {