From b96300f0a5f1b4e3b250b45c02725ec1a39b514b Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 16 Apr 2026 10:52:49 +0700 Subject: [PATCH] website: expandable and resizable promptbox --- .../CreateMediaPageShell.tsx | 26 +-------- .../src/components/prompt-box/PromptBox.tsx | 57 ++++++++++++++++--- frontend/apps/artcraft-website/src/styles.css | 24 ++++++++ .../apps/artcraft-website/tsconfig.app.json | 3 + frontend/apps/artcraft-website/tsconfig.json | 3 + .../components/gallery-modal/tsconfig.json | 9 ++- .../gallery-modal/tsconfig.lib.json | 9 ++- 7 files changed, 92 insertions(+), 39 deletions(-) diff --git a/frontend/apps/artcraft-website/src/components/generation-gallery/CreateMediaPageShell.tsx b/frontend/apps/artcraft-website/src/components/generation-gallery/CreateMediaPageShell.tsx index aa8801bd87..8fd232ea8d 100644 --- a/frontend/apps/artcraft-website/src/components/generation-gallery/CreateMediaPageShell.tsx +++ b/frontend/apps/artcraft-website/src/components/generation-gallery/CreateMediaPageShell.tsx @@ -6,7 +6,7 @@ import { type IconDefinition, } from "@fortawesome/pro-solid-svg-icons"; import { Button } from "@storyteller/ui-button"; -import { PopoverMenu, type PopoverItem } from "@storyteller/ui-popover"; +import { type PopoverItem } from "@storyteller/ui-popover"; import Seo from "../../components/seo"; import Footer from "../../components/footer"; @@ -49,8 +49,6 @@ export function CreateMediaPageShell({ emptyStateTitle, emptyStateSubtitle, bottomOffset, - modelItems, - onModelChange, glowOrbs, gridContent, promptBox, @@ -146,28 +144,6 @@ export function CreateMediaPageShell({ )} {promptBox} - -
-
- -
-
diff --git a/frontend/apps/artcraft-website/src/components/prompt-box/PromptBox.tsx b/frontend/apps/artcraft-website/src/components/prompt-box/PromptBox.tsx index 011641ae91..6211ba70fa 100644 --- a/frontend/apps/artcraft-website/src/components/prompt-box/PromptBox.tsx +++ b/frontend/apps/artcraft-website/src/components/prompt-box/PromptBox.tsx @@ -10,6 +10,8 @@ import { import { twMerge } from "tailwind-merge"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { + faChevronDown, + faChevronUp, faMusic, faUserGroup, faVideo, @@ -143,8 +145,21 @@ export const PromptBox = forwardRef( const highlightRef = useRef(null); const mentionEditorRef = useRef(null); const [isFocused, setIsFocused] = useState(false); + const [isExpanded, setIsExpanded] = useState(false); const [showImagePrompts, setShowImagePrompts] = useState(false); + const EXPANDED_HEIGHT = "clamp(120px, calc(100vh - 700px), 500px)"; + + const toggleExpand = () => { + setIsExpanded((prev) => { + const next = !prev; + if (textareaRef.current) { + textareaRef.current.style.height = next ? EXPANDED_HEIGHT : "auto"; + } + return next; + }); + }; + // @-mention state const [mentionOpen, setMentionOpen] = useState(false); const [mentionFilter, setMentionFilter] = useState(""); @@ -167,13 +182,14 @@ export const PromptBox = forwardRef( ); }, [mentionItems, mentionFilter]); - // Auto-resize textarea + // Auto-resize textarea (skip when expanded) useEffect(() => { + if (isExpanded) return; if (textareaRef.current) { textareaRef.current.style.height = "auto"; textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; } - }, [prompt]); + }, [prompt, isExpanded]); // Move caret to end on mount so autoFocus doesn't leave it at position 0 useEffect(() => { @@ -402,7 +418,10 @@ export const PromptBox = forwardRef( onChange={onPromptChange} mentionItems={mentionItems} placeholder={placeholder} - className="max-h-[5.5em] w-full text-white" + className={twMerge( + "w-full text-white", + isExpanded ? "max-h-[500px]" : "max-h-[5.5em]", + )} colorMap={mentionColorMap} onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey && !e.metaKey) { @@ -419,7 +438,10 @@ export const PromptBox = forwardRef(
{renderHighlightedPrompt()}
@@ -431,7 +453,8 @@ export const PromptBox = forwardRef( autoFocus placeholder={placeholder} className={twMerge( - "max-h-[5.5em] w-full flex-1 resize-none overflow-y-auto bg-transparent text-md text-white placeholder-white/50 focus:outline-none", + "promptbox-scrollbar min-h-[2.5em] w-full flex-1 resize-y overflow-y-auto bg-transparent text-md text-white placeholder-white/50 focus:outline-none", + isExpanded ? "max-h-[500px]" : "max-h-[5.5em]", hasMentionItems && "text-transparent caret-white", )} value={prompt} @@ -515,9 +538,7 @@ export const PromptBox = forwardRef( {/* Toolbar */}
- {modelSelector && ( -
{modelSelector}
- )} + {modelSelector} {leftToolbar}
@@ -533,6 +554,26 @@ export const PromptBox = forwardRef(
+ + {/* Expand / Collapse toggle */} +
+ + + +
diff --git a/frontend/apps/artcraft-website/src/styles.css b/frontend/apps/artcraft-website/src/styles.css index 08a0a15be8..b25cd1fef5 100644 --- a/frontend/apps/artcraft-website/src/styles.css +++ b/frontend/apps/artcraft-website/src/styles.css @@ -71,6 +71,30 @@ background-color: rgba(46, 46, 49, 0.85) !important; } +/* Minimal thin scrollbar for prompt textareas */ +.promptbox-scrollbar { + scrollbar-width: thin; + scrollbar-color: rgba(255, 255, 255, 0.2) transparent; +} + +.promptbox-scrollbar::-webkit-scrollbar { + width: 4px; +} + +.promptbox-scrollbar::-webkit-scrollbar-track { + background: transparent; +} + +.promptbox-scrollbar::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.2); + border-radius: 9999px; +} + +.promptbox-scrollbar::-webkit-scrollbar-thumb:hover { + background-color: rgba(255, 255, 255, 0.35); +} + + @keyframes fade-in-up { from { opacity: 0; diff --git a/frontend/apps/artcraft-website/tsconfig.app.json b/frontend/apps/artcraft-website/tsconfig.app.json index 3ac4496b4b..c3c1ecdcc9 100644 --- a/frontend/apps/artcraft-website/tsconfig.app.json +++ b/frontend/apps/artcraft-website/tsconfig.app.json @@ -40,6 +40,9 @@ { "path": "../../libs/components/gravatar/tsconfig.lib.json" }, + { + "path": "../../libs/components/slider-v2/tsconfig.lib.json" + }, { "path": "../../libs/components/tab-selector/tsconfig.lib.json" }, diff --git a/frontend/apps/artcraft-website/tsconfig.json b/frontend/apps/artcraft-website/tsconfig.json index 97bb13b891..777630abae 100644 --- a/frontend/apps/artcraft-website/tsconfig.json +++ b/frontend/apps/artcraft-website/tsconfig.json @@ -5,6 +5,9 @@ { "path": "../../libs/components/gravatar" }, + { + "path": "../../libs/components/slider-v2" + }, { "path": "../../libs/components/tab-selector" }, diff --git a/frontend/libs/components/gallery-modal/tsconfig.json b/frontend/libs/components/gallery-modal/tsconfig.json index 8b91c78596..74bd24731f 100644 --- a/frontend/libs/components/gallery-modal/tsconfig.json +++ b/frontend/libs/components/gallery-modal/tsconfig.json @@ -9,7 +9,7 @@ "path": "../../common" }, { - "path": "../loading-spinner" + "path": "../../api" }, { "path": "../close-button" @@ -24,10 +24,10 @@ "path": "../modal" }, { - "path": "../../tauri-api" + "path": "../toaster" }, { - "path": "../../api" + "path": "../../tauri-api" }, { "path": "../action-reminder-modal" @@ -38,6 +38,9 @@ { "path": "../tooltip" }, + { + "path": "../loading-spinner" + }, { "path": "./tsconfig.lib.json" }, diff --git a/frontend/libs/components/gallery-modal/tsconfig.lib.json b/frontend/libs/components/gallery-modal/tsconfig.lib.json index f1fd283917..0f7fdbbf8a 100644 --- a/frontend/libs/components/gallery-modal/tsconfig.lib.json +++ b/frontend/libs/components/gallery-modal/tsconfig.lib.json @@ -50,7 +50,7 @@ "path": "../../common/tsconfig.lib.json" }, { - "path": "../loading-spinner/tsconfig.lib.json" + "path": "../../api/tsconfig.lib.json" }, { "path": "../close-button/tsconfig.lib.json" @@ -65,10 +65,10 @@ "path": "../modal/tsconfig.lib.json" }, { - "path": "../../tauri-api/tsconfig.lib.json" + "path": "../toaster/tsconfig.lib.json" }, { - "path": "../../api/tsconfig.lib.json" + "path": "../../tauri-api/tsconfig.lib.json" }, { "path": "../action-reminder-modal/tsconfig.lib.json" @@ -78,6 +78,9 @@ }, { "path": "../tooltip/tsconfig.lib.json" + }, + { + "path": "../loading-spinner/tsconfig.lib.json" } ] }