3
3
<IconButton icon =" LightBulbIcon" title =" Toggle dark/light preview" @click =" togglePreview" ></IconButton >
4
4
<br />
5
5
<div class =" preview" :class =" { light, dark: !light }" >
6
- <span
7
- v-for =" element in elements"
8
- :key =" element.id"
9
- :style =" {
10
- backgroundColor: `${element.data.attributes.reverse
11
- ? element.data.foregroundColor?.hex ?? (light ? '#212121' : '#fafafa')
12
- : element.data.backgroundColor?.hex ?? (light ? '#fafafa' : '#212121')} !important`,
13
- }"
14
- >
6
+ <div class =" preview-head" >
7
+ <span v-for =" element in elements.windowTitle" :key =" element.id" >
8
+ {{ element.data.type.preview(element.data.parameters) }}
9
+ </span >
10
+ <span class =" preview-window-controls" >
11
+ <MinusCircleIcon class =" icon" ></MinusCircleIcon >
12
+ <XCircleIcon class =" icon" ></XCircleIcon >
13
+ </span >
14
+ </div >
15
+ <div class =" preview-body" >
15
16
<span
16
- v-if =" element.data.type.preview(element.data.parameters) !== '\n'"
17
+ v-for =" element in elements.prompt"
18
+ :key =" element.id"
17
19
:style =" {
18
- color : `${element.data.attributes.reverse
19
- ? element.data.backgroundColor ?.hex ?? (light ? '#fafafa ' : '#212121 ')
20
- : element.data.foregroundColor ?.hex ?? (light ? '#212121 ' : '#fafafa ')} !important`,
20
+ backgroundColor : `${element.data.attributes.reverse
21
+ ? element.data.foregroundColor ?.hex ?? (light ? '#212121 ' : '#fafafa ')
22
+ : element.data.backgroundColor ?.hex ?? (light ? '#fafafa ' : '#212121 ')} !important`,
21
23
}"
22
- :class =" {
23
- 'preview-bold': element.data.attributes.bold,
24
- 'preview-dim': element.data.attributes.dim,
25
- 'preview-italic': element.data.attributes.italic,
26
- 'preview-underline': element.data.attributes.underline,
27
- 'preview-blink': element.data.attributes.blink,
28
- 'preview-overline': element.data.attributes.overline,
29
- }"
30
- >{{ element.data.type.preview(element.data.parameters) }}</span
31
24
>
32
- <br v-else />
33
- </span >
34
- <span class =" cursor" >█ ; </span >
25
+ <span
26
+ v-if =" element.data.type.preview(element.data.parameters) !== '\n'"
27
+ :style =" {
28
+ color: `${element.data.attributes.reverse
29
+ ? element.data.backgroundColor?.hex ?? (light ? '#fafafa' : '#212121')
30
+ : element.data.foregroundColor?.hex ?? (light ? '#212121' : '#fafafa')} !important`,
31
+ }"
32
+ :class =" {
33
+ 'preview-bold': element.data.attributes.bold,
34
+ 'preview-dim': element.data.attributes.dim,
35
+ 'preview-italic': element.data.attributes.italic,
36
+ 'preview-underline': element.data.attributes.underline,
37
+ 'preview-blink': element.data.attributes.blink,
38
+ 'preview-overline': element.data.attributes.overline,
39
+ }"
40
+ >{{ element.data.type.preview(element.data.parameters) }}</span
41
+ >
42
+ <br v-else />
43
+ </span >
44
+ <span class =" cursor" >█ ; </span >
45
+ </div >
35
46
</div >
36
47
</template >
37
48
38
49
<script lang="ts">
39
50
import { defineComponent } from ' vue' ;
40
51
import prompt from ' @/lib/prompt' ;
41
52
import { UniquePromptElement } from ' @/lib/promptElement' ;
53
+ import { MinusCircleIcon , XCircleIcon } from ' @heroicons/vue/24/solid' ;
42
54
import IconButton from ' ../ui/IconButton.vue' ;
43
55
44
56
/**
@@ -102,6 +114,8 @@ export default defineComponent({
102
114
name: ' PromptPreview' ,
103
115
components: {
104
116
IconButton ,
117
+ MinusCircleIcon ,
118
+ XCircleIcon ,
105
119
},
106
120
data() {
107
121
return {
@@ -119,21 +133,39 @@ export default defineComponent({
119
133
*/
120
134
elements : () => {
121
135
const elements = [... prompt .state ().elements ];
136
+
122
137
// split elements on carriage returns
123
- const crPartitions = [[]] as UniquePromptElement [][];
138
+ const crPartitions = {
139
+ prompt: [[]] as UniquePromptElement [][],
140
+ windowTitle: [[]] as UniquePromptElement [][],
141
+ };
142
+ // whether an operating system command ('Set Window Title') has been encountered and awaits an ending bell
143
+ let operatingSystemCommand: boolean = false ;
144
+
124
145
while (elements .length > 0 ) {
125
146
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
126
147
const element = elements .shift ()! ;
127
148
if (element .data .type .preview (element .data .parameters ) === ' \r ' ) {
128
- crPartitions .push ([]);
149
+ (operatingSystemCommand ? crPartitions .windowTitle : crPartitions .prompt ).push ([]);
150
+ } else if (element .data .type .name === ' Set Window Title' ) {
151
+ // any previous window title is overwritten by the new one
152
+ crPartitions .windowTitle = [[]];
153
+ operatingSystemCommand = true ;
154
+ } else if (element .data .type .name === ' Bell' && operatingSystemCommand ) {
155
+ operatingSystemCommand = false ;
156
+ } else if (operatingSystemCommand ) {
157
+ crPartitions .windowTitle [crPartitions .windowTitle .length - 1 ].push (element );
129
158
} else {
130
- crPartitions [crPartitions .length - 1 ].push (element );
159
+ crPartitions . prompt [crPartitions . prompt .length - 1 ].push (element );
131
160
}
132
161
}
133
162
134
163
// merge partitions from left to right as the third partition may overlay elements from the second partition which
135
164
// again may overlay elements from the first partition
136
- return crPartitions .reduce (mergeCrPartitions );
165
+ return {
166
+ prompt: crPartitions .prompt .reduce (mergeCrPartitions ),
167
+ windowTitle: crPartitions .windowTitle .reduce (mergeCrPartitions ),
168
+ };
137
169
},
138
170
},
139
171
methods: {
167
199
.preview
168
200
display : inline-block
169
201
margin : 1em 0 2em 0
170
- padding : 1em
171
202
font-family : ' Roboto Mono' , ' Noto Sans Mono' , monospace
172
203
text-align : left
173
204
line-height : 1.5
174
205
min-height : 1.5em
175
206
word-break : break-all
176
207
white-space : pre-wrap
208
+ border : 0.1em solid $color-dim
209
+ border-top-left-radius : 0.5em
210
+ border-top-right-radius : 0.5em
177
211
178
212
& .light
179
- background-color : #fafafa !important
180
213
color : #212121 !important
181
214
215
+ .preview-head
216
+ background-color : #e0e0e0 !important
217
+
218
+ .preview-body
219
+ background-color : #fafafa !important
220
+
182
221
& .dark
183
- background-color : #212121 !important
184
222
color : #fafafa !important
185
223
224
+ .preview-head
225
+ background-color : #111111 !important
226
+
227
+ .preview-body
228
+ background-color : #212121 !important
229
+
230
+ .preview-head
231
+ display : block
232
+ padding : 0.5em 1em
233
+ border-bottom : 0.1em solid $color-dim
234
+ border-radius : inherit
235
+
236
+ .preview-window-controls
237
+ float : right
238
+ margin-left : 1.5em
239
+ // opacity: 0.7
240
+ color : $color-button
241
+
242
+ .icon
243
+ margin : 0 0.1em
244
+ height : 1.2em
245
+ vertical-align : middle
246
+
247
+
248
+ .preview-body
249
+ padding : 1em
250
+ padding-right : 10em
251
+
186
252
// display attributes
187
253
188
254
.preview-bold
0 commit comments