Blame Raw
Cohee · 51ad27fb · · 236 lines (6.0 KB)
2 contributors
1/* ─────────────────────────────────────────────────────────────────────────────
2 Streaming Display — floating toast panel for live LLM generation output.
3 Shows reasoning (thinking) and content as they stream in.
4 Used by extensions that leverage ConnectionManagerRequestService streaming.
5 ───────────────────────────────────────────────────────────────────────────── */
6
7.streaming-display {
8 position: fixed;
9 bottom: max(calc(var(--bottomFormBlockSize) + 5px), 20px);
10 right: 20px;
11 width: min(550px, calc(100vw - 40px));
12 max-height: 70vh;
13 background: var(--SmartThemeBlurTintColor);
14 border: 1px solid var(--SmartThemeBorderColor);
15 border-radius: 10px;
16 padding: 14px;
17 z-index: 9000;
18 display: flex;
19 flex-direction: column;
20 gap: 10px;
21 opacity: 0;
22 transform: translateY(20px);
23 transition: opacity var(--animation-duration, 125ms) ease, transform var(--animation-duration, 125ms) ease;
24 overflow: hidden;
25 box-shadow: 0 4px 24px rgba(0, 0, 0, 0.25);
26 backdrop-filter: blur(12px);
27}
28
29.streaming-display-visible {
30 opacity: 1;
31 transform: translateY(0);
32}
33
34/* Header label with animated activity indicator */
35.streaming-display-label {
36 font-weight: 600;
37 font-size: 0.95em;
38 color: var(--SmartThemeBodyColor);
39 display: flex;
40 align-items: center;
41 gap: 8px;
42 user-select: none;
43}
44
45/* LED status indicator - pulsing while streaming */
46.streaming-display-led {
47 display: inline-block;
48 width: 8px;
49 height: 8px;
50 border-radius: 50%;
51 background: rgb(225, 138, 36);
52 animation: streaming-display-pulse 1.5s ease-in-out infinite;
53 flex-shrink: 0;
54}
55
56/* Completed state: solid green LED */
57.streaming-display-complete .streaming-display-led {
58 background: #4caf50;
59 animation: none;
60 opacity: 1;
61 box-shadow: 0 0 8px rgba(76, 175, 80, 0.6);
62}
63
64/* Stopped state: solid red LED */
65.streaming-display-stopped .streaming-display-led {
66 background: #f44336;
67 animation: none;
68 opacity: 1;
69 box-shadow: 0 0 8px rgba(244, 67, 54, 0.6);
70}
71
72@keyframes streaming-display-pulse {
73 0%, 100% { opacity: 0.4; transform: scale(0.9); }
74 50% { opacity: 1; transform: scale(1.1); }
75}
76
77/* Label text takes available space */
78.streaming-display-label-text {
79 flex: 1;
80 min-width: 0;
81 overflow: hidden;
82 text-overflow: ellipsis;
83 white-space: nowrap;
84}
85
86/* Window control buttons container */
87.streaming-display-controls {
88 display: flex;
89 align-items: center;
90 gap: 4px;
91 margin-left: auto;
92 flex-shrink: 0;
93}
94
95/* Window control buttons */
96.streaming-display-btn {
97 width: 22px;
98 height: 22px;
99 border: none;
100 border-radius: 4px;
101 background: transparent;
102 color: var(--SmartThemeBodyColor);
103 font-size: 14px;
104 line-height: 1;
105 cursor: pointer;
106 display: flex;
107 align-items: center;
108 justify-content: center;
109 opacity: 0.6;
110 transition: opacity 0.15s ease, background-color 0.15s ease;
111}
112
113.streaming-display-btn:hover {
114 opacity: 1;
115 background-color: rgba(255, 255, 255, 0.1);
116}
117
118.streaming-display-btn-close:hover {
119 background-color: rgba(244, 67, 54, 0.2);
120}
121
122.streaming-display-btn-stop {
123 font-size: 10px;
124}
125
126.streaming-display-btn-stop:hover {
127 background-color: rgba(244, 150, 36, 0.2);
128 color: rgb(225, 138, 36);
129}
130
131/* Content container - collapsible for minimize */
132.streaming-display-content {
133 display: flex;
134 flex-direction: column;
135 gap: 10px;
136 overflow: hidden;
137 transition: max-height var(--animation-duration, 125ms) ease, opacity var(--animation-duration, 125ms) ease;
138}
139
140/* Minimized state - hide content sections */
141.streaming-display-minimized .streaming-display-content {
142 max-height: 0;
143 opacity: 0;
144}
145
146.streaming-display-minimized {
147 gap: 0;
148}
149
150/* Model/API icon in the label */
151.streaming-display-icon {
152 width: 1.1em;
153 height: 1.1em;
154 flex-shrink: 0;
155}
156
157/* Minimized state adjustments */
158.streaming-display-minimized.streaming-display {
159 padding: 10px 14px;
160}
161
162/* Reasoning (thinking) section */
163.streaming-display-reasoning {
164 background: color-mix(in srgb, var(--SmartThemeBodyColor) 5%, transparent);
165 border-radius: 6px;
166 padding: 8px 10px;
167 border-left: 3px solid color-mix(in srgb, var(--SmartThemeBodyColor) 25%, transparent);
168}
169
170.streaming-display-reasoning-label {
171 font-size: 0.8em;
172 font-weight: 600;
173 opacity: 0.5;
174 margin-bottom: 4px;
175 letter-spacing: 0.03em;
176 text-transform: uppercase;
177}
178
179.streaming-display-reasoning-content {
180 font-size: 0.82em;
181 opacity: 0.65;
182 max-height: 25vh;
183 overflow-y: auto;
184 word-break: break-word;
185 line-height: 1.45;
186 scrollbar-width: thin;
187}
188
189.streaming-display-reasoning-content p {
190 margin: 0.3em 0;
191}
192
193.streaming-display-reasoning-content p:first-child {
194 margin-top: 0;
195}
196
197.streaming-display-reasoning-content p:last-child {
198 margin-bottom: 0;
199}
200
201/* Main content section */
202.streaming-display-text {
203 border-top: 1px solid color-mix(in srgb, var(--SmartThemeBorderColor) 50%, transparent);
204 padding-top: 8px;
205 min-height: 1.5em;
206}
207
208.streaming-display-text-content {
209 font-size: 0.9em;
210 color: var(--SmartThemeBodyColor);
211 max-height: 40vh;
212 overflow-y: auto;
213 word-break: break-word;
214 line-height: 1.5;
215 scrollbar-width: thin;
216}
217
218.streaming-display-text-content p {
219 margin: 0.4em 0;
220}
221
222.streaming-display-text-content p:first-child {
223 margin-top: 0;
224}
225
226.streaming-display-text-content p:last-child {
227 margin-bottom: 0;
228}
229
230/* Strip auto-added quotes from <q> tags, as message formatting adds them */
231.streaming-display-reasoning-content q:before,
232.streaming-display-reasoning-content q:after,
233.streaming-display-text-content q:before,
234.streaming-display-text-content q:after {
235 content: '';
236}