64c96e895c
* Add StreamingDisplay class for live LLM generation output with floating toast panel - Add StreamingDisplay class to show streaming reasoning and content in a floating toast panel - Extract createModelIcon() helper from insertSVGIcon() for reusable API/model icon creation - StreamingDisplay automatically appends inside topmost open dialog (same pattern as fixToastrForDialogs) - Add CSS with fade-in animation, pulsating activity indicator, and separate reasoning/content sections - Support optional model icon in header * Add ConnectionManagerRequestService.getProfileIcon() method for retrieving profile API icons - Add static getProfileIcon() method to ConnectionManagerRequestService - Returns HTMLImageElement created via createModelIcon() for a given profile's API/model - Accepts optional profileId parameter, defaults to currently selected profile - Returns null if Connection Manager is disabled, profile not found, or profile has no API - Import createModelIcon from script.js * Use animation_duration directly in hide() and CSS transition instead of constant - Remove ANIMATION_DURATION_MS constant and use animation_duration directly in hide() method - Replace hardcoded 0.3s CSS transitions with CSS variable var(--animation-duration, 125ms) - Read animation_duration value inline in hide() for accurate timing * Add /genstream slash command with live streaming display and reasoning support - Add /genstream slash command that generates text via Connection Manager with live streaming UI - Add formatReasoning() helper function (inverse of parseReasoningFromString) to format reasoning/content into template-wrapped strings - Add connectionProfiles enum provider for profile selection in slash commands - StreamingDisplay: add delay parameter to hide() method (default 1000ms) to show final result before dismiss * Add /reasoning-format slash command to format reasoning and content into template-wrapped strings - Add /reasoning-format (alias: /format-reasoning) slash command that wraps reasoning/content using Reasoning Formatting settings - Accept required 'reasoning' named argument and optional unnamed 'content' argument - Validate that prefix/suffix are configured before formatting - Return formatted string via formatReasoning() helper for use with /reasoning-parse - Show warning toasts if prefix/suffix missing * Rename /genstream command to /profile-genstream and move to appropriate module * Apply messageFormatting to StreamingDisplay reasoning and content text for proper rendering - Import messageFormatting from script.js - Replace textContent with innerHTML using messageFormatting() in updateReasoning() and updateText() - Pass isSystem=true for reasoning, isSystem=false for content to match formatting expectations - Update css to utilize pre-formatted paragraphs correctly * Strip auto-added quotes from <q> tags in StreamingDisplay and add 'mes_text' class for consistent chat message formatting - Add CSS rules to remove browser-default quotes from <q> tags in reasoning and content sections - Add 'mes_text' class to textContent div to match chat message formatting behavior - Prevents double quotes when messageFormatting already adds them via <q> tags * Add minimize/close buttons and complete state to StreamingDisplay with configurable auto-hide - Add minimize button to collapse/restore content sections while keeping header visible - Add close button to manually dismiss display (generation continues in background) - Replace CSS pseudo-element with explicit LED indicator element for better state control - Add complete() method to mark generation done: changes LED from pulsing orange to solid green - Add configurable auto-hide delay after completion * Add stop button to StreamingDisplay with abort support and onStop/onComplete closures for /profile-genstream - Add stop button to StreamingDisplay when onStop handler is provided - Add markStopped() method with solid red LED state indicator - Add AbortController integration to /profile-genstream for request cancellation - Add onStop and onComplete closure arguments to /profile-genstream command - Update complete() method signature to use options object with label and delay - Disable stop button immediately * Position StreamingDisplay above bottom form block using CSS variable with fallback - Change bottom positioning from fixed 20px to dynamic calculation - Use max() to position above --bottomFormBlockSize + 5px or minimum 20px - Ensures StreamingDisplay doesn't overlap with bottom UI elements * Rename /profile-genstream arguments for clarity: label→generating, completedLabel→completed, hideDelay→delay - Rename `label` argument to `generating` to better reflect its purpose as the in-progress state label - Rename `completedLabel` to `completed` for consistency and brevity - Rename `hideDelay` to `delay` for simpler naming - Update all internal references and variable names to match new argument names - Update argument descriptions and default values accordingly * Remove variable resolution from /profile-genstream arguments: system, length, and delay - Remove ARGUMENT_TYPE.VARIABLE_NAME from typeList for system, length, and delay arguments - Replace resolveVariable() calls with direct argument access for system, length, and delay - Simplify type checking to use typeof directly on args properties - Maintain existing default values and validation logic * Add warning toast and early return when connection profile not found in /profile-genstream - Display toastr warning when fuzzy search fails to find matching profile - Return empty string to prevent execution with invalid profile - Improves user feedback for incorrect profile names or IDs * Extract buildResultText() helper in /profile-genstream to return partial results when stopped - Add buildResultText() helper function to centralize result formatting logic - Return partial generated text when user stops generation instead of empty string - Reuse buildResultText() for both stopped and completed states - Maintains consistent reasoning formatting in both cases * fix lint * Update documentation to reflect argument name change from hideDelay to delay --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
237 lines
6.0 KiB
CSS
237 lines
6.0 KiB
CSS
/* ─────────────────────────────────────────────────────────────────────────────
|
|
Streaming Display — floating toast panel for live LLM generation output.
|
|
Shows reasoning (thinking) and content as they stream in.
|
|
Used by extensions that leverage ConnectionManagerRequestService streaming.
|
|
───────────────────────────────────────────────────────────────────────────── */
|
|
|
|
.streaming-display {
|
|
position: fixed;
|
|
bottom: max(calc(var(--bottomFormBlockSize) + 5px), 20px);
|
|
right: 20px;
|
|
width: min(550px, calc(100vw - 40px));
|
|
max-height: 70vh;
|
|
background: var(--SmartThemeBlurTintColor);
|
|
border: 1px solid var(--SmartThemeBorderColor);
|
|
border-radius: 10px;
|
|
padding: 14px;
|
|
z-index: 9000;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
opacity: 0;
|
|
transform: translateY(20px);
|
|
transition: opacity var(--animation-duration, 125ms) ease, transform var(--animation-duration, 125ms) ease;
|
|
overflow: hidden;
|
|
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.25);
|
|
backdrop-filter: blur(12px);
|
|
}
|
|
|
|
.streaming-display-visible {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* Header label with animated activity indicator */
|
|
.streaming-display-label {
|
|
font-weight: 600;
|
|
font-size: 0.95em;
|
|
color: var(--SmartThemeBodyColor);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
user-select: none;
|
|
}
|
|
|
|
/* LED status indicator - pulsing while streaming */
|
|
.streaming-display-led {
|
|
display: inline-block;
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
background: rgb(225, 138, 36);
|
|
animation: streaming-display-pulse 1.5s ease-in-out infinite;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Completed state: solid green LED */
|
|
.streaming-display-complete .streaming-display-led {
|
|
background: #4caf50;
|
|
animation: none;
|
|
opacity: 1;
|
|
box-shadow: 0 0 8px rgba(76, 175, 80, 0.6);
|
|
}
|
|
|
|
/* Stopped state: solid red LED */
|
|
.streaming-display-stopped .streaming-display-led {
|
|
background: #f44336;
|
|
animation: none;
|
|
opacity: 1;
|
|
box-shadow: 0 0 8px rgba(244, 67, 54, 0.6);
|
|
}
|
|
|
|
@keyframes streaming-display-pulse {
|
|
0%, 100% { opacity: 0.4; transform: scale(0.9); }
|
|
50% { opacity: 1; transform: scale(1.1); }
|
|
}
|
|
|
|
/* Label text takes available space */
|
|
.streaming-display-label-text {
|
|
flex: 1;
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Window control buttons container */
|
|
.streaming-display-controls {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
margin-left: auto;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Window control buttons */
|
|
.streaming-display-btn {
|
|
width: 22px;
|
|
height: 22px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
color: var(--SmartThemeBodyColor);
|
|
font-size: 14px;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
opacity: 0.6;
|
|
transition: opacity 0.15s ease, background-color 0.15s ease;
|
|
}
|
|
|
|
.streaming-display-btn:hover {
|
|
opacity: 1;
|
|
background-color: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.streaming-display-btn-close:hover {
|
|
background-color: rgba(244, 67, 54, 0.2);
|
|
}
|
|
|
|
.streaming-display-btn-stop {
|
|
font-size: 10px;
|
|
}
|
|
|
|
.streaming-display-btn-stop:hover {
|
|
background-color: rgba(244, 150, 36, 0.2);
|
|
color: rgb(225, 138, 36);
|
|
}
|
|
|
|
/* Content container - collapsible for minimize */
|
|
.streaming-display-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
overflow: hidden;
|
|
transition: max-height var(--animation-duration, 125ms) ease, opacity var(--animation-duration, 125ms) ease;
|
|
}
|
|
|
|
/* Minimized state - hide content sections */
|
|
.streaming-display-minimized .streaming-display-content {
|
|
max-height: 0;
|
|
opacity: 0;
|
|
}
|
|
|
|
.streaming-display-minimized {
|
|
gap: 0;
|
|
}
|
|
|
|
/* Model/API icon in the label */
|
|
.streaming-display-icon {
|
|
width: 1.1em;
|
|
height: 1.1em;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Minimized state adjustments */
|
|
.streaming-display-minimized.streaming-display {
|
|
padding: 10px 14px;
|
|
}
|
|
|
|
/* Reasoning (thinking) section */
|
|
.streaming-display-reasoning {
|
|
background: color-mix(in srgb, var(--SmartThemeBodyColor) 5%, transparent);
|
|
border-radius: 6px;
|
|
padding: 8px 10px;
|
|
border-left: 3px solid color-mix(in srgb, var(--SmartThemeBodyColor) 25%, transparent);
|
|
}
|
|
|
|
.streaming-display-reasoning-label {
|
|
font-size: 0.8em;
|
|
font-weight: 600;
|
|
opacity: 0.5;
|
|
margin-bottom: 4px;
|
|
letter-spacing: 0.03em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.streaming-display-reasoning-content {
|
|
font-size: 0.82em;
|
|
opacity: 0.65;
|
|
max-height: 25vh;
|
|
overflow-y: auto;
|
|
word-break: break-word;
|
|
line-height: 1.45;
|
|
scrollbar-width: thin;
|
|
}
|
|
|
|
.streaming-display-reasoning-content p {
|
|
margin: 0.3em 0;
|
|
}
|
|
|
|
.streaming-display-reasoning-content p:first-child {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.streaming-display-reasoning-content p:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
/* Main content section */
|
|
.streaming-display-text {
|
|
border-top: 1px solid color-mix(in srgb, var(--SmartThemeBorderColor) 50%, transparent);
|
|
padding-top: 8px;
|
|
min-height: 1.5em;
|
|
}
|
|
|
|
.streaming-display-text-content {
|
|
font-size: 0.9em;
|
|
color: var(--SmartThemeBodyColor);
|
|
max-height: 40vh;
|
|
overflow-y: auto;
|
|
word-break: break-word;
|
|
line-height: 1.5;
|
|
scrollbar-width: thin;
|
|
}
|
|
|
|
.streaming-display-text-content p {
|
|
margin: 0.4em 0;
|
|
}
|
|
|
|
.streaming-display-text-content p:first-child {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.streaming-display-text-content p:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
/* Strip auto-added quotes from <q> tags, as message formatting adds them */
|
|
.streaming-display-reasoning-content q:before,
|
|
.streaming-display-reasoning-content q:after,
|
|
.streaming-display-text-content q:before,
|
|
.streaming-display-text-content q:after {
|
|
content: '';
|
|
}
|