8181
8282 <!-- Filter Widgets and Add Widget -->
8383 <div class =" d-flex align-center gap-4 mb-4" >
84+ <div >
85+ <v-select
86+ id =" grid-preset"
87+ width =" 56"
88+ class =" custom-v-select-field-height"
89+ v-model =" gridPresetIcon"
90+ :items =" gridPresetIconItems"
91+ item-value =" icon"
92+ variant =" solo"
93+ hide-details
94+ menu-icon =" "
95+ @update:model-value =" handleGridPresetChange"
96+ v-tooltip =" { text: 'Arrange grid', location: 'left' }"
97+ >
98+ <template #selection >
99+ <v-icon :icon =" gridPresetIcon" size =" large" ></v-icon >
100+ </template >
101+ <template #item =" { props , item } " >
102+ <div
103+ v-bind =" props"
104+ class =" v-list-item v-list-item--link d-flex justify-center align-center py-2 px-3"
105+ >
106+ <v-icon :icon =" item.icon" ></v-icon >
107+ <!-- v8 ignore start -->
108+ <v-tooltip activator =" parent" >
109+ {{ item.desc }}
110+ </v-tooltip >
111+ <!-- v8 ignore stop -->
112+ </div >
113+ <v-divider v-if =" item.name != 'col3'" ></v-divider >
114+ </template >
115+ </v-select >
116+ </div >
84117 <!-- Filter Widgets -->
85118 <v-sheet elevation =" 1" width =" 100%" rounded >
86119 <v-autocomplete
180213 @update:layout =" updateDisplayedLayoutWidgets"
181214 :key =" widgetsGridKey"
182215 :row-height =" 30"
183- :is-draggable =" true "
184- :is-resizable =" true "
216+ :is-draggable =" gridEditable "
217+ :is-resizable =" gridEditable "
185218 :responsive =" false"
186219 @selectstart.prevent
187220 >
253286
254287<script setup>
255288import { socket } from ' @/socket'
256- import { ref , inject , nextTick , onActivated , onDeactivated } from ' vue'
289+ import { computed , ref , inject , nextTick , onActivated , onDeactivated , h } from ' vue'
257290import { GridLayout , GridItem } from ' grid-layout-plus'
258291import { useRouter } from ' vue-router'
259292import {
@@ -270,6 +303,53 @@ import {
270303 mdiClose ,
271304} from ' @mdi/js'
272305
306+ const gridPresetIcons = {
307+ editable : () =>
308+ h (' svg' , { viewBox: ' 0 0 24 24' }, [
309+ h (' path' , {
310+ d: ' M4 5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5ZM14 5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1V5ZM4 16a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3ZM14 13a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1v-6Z' ,
311+ fill: ' none' ,
312+ stroke: ' #000000' ,
313+ ' stroke-width' : 2 ,
314+ ' stroke-linecap' : ' round' ,
315+ ' stroke-linejoin' : ' round' ,
316+ }),
317+ ]),
318+ col1 : () =>
319+ h (' svg' , { viewBox: ' 0 0 24 24' }, [
320+ h (' path' , {
321+ d: ' M6 5C6 4.44772 6.44772 4 7 4H17C17.5523 4 18 4.44772 18 5V19C18 19.5523 17.5523 20 17 20H7C6.44772 20 6 19.5523 6 19V5Z' ,
322+ fill: ' none' ,
323+ stroke: ' #000000' ,
324+ ' stroke-width' : 2 ,
325+ ' stroke-linecap' : ' round' ,
326+ ' stroke-linejoin' : ' round' ,
327+ }),
328+ ]),
329+ col2 : () =>
330+ h (' svg' , { viewBox: ' 0 0 24 24' }, [
331+ h (' path' , {
332+ d: ' M8,2 C9.65685425,2 11,3.34314575 11,5 L11,19 C11,20.6568542 9.65685425,22 8,22 L5,22 C3.34314575,22 2,20.6568542 2,19 L2,5 C2,3.34314575 3.34314575,2 5,2 L8,2 Z M19,2 C20.6568542,2 22,3.34314575 22,5 L22,19 C22,20.6568542 20.6568542,22 19,22 L16,22 C14.3431458,22 13,20.6568542 13,19 L13,5 C13,3.34314575 14.3431458,2 16,2 L19,2 Z M8,4 L5,4 C4.44771525,4 4,4.44771525 4,5 L4,19 C4,19.5522847 4.44771525,20 5,20 L8,20 C8.55228475,20 9,19.5522847 9,19 L9,5 C9,4.44771525 8.55228475,4 8,4 Z M19,4 L16,4 C15.4477153,4 15,4.44771525 15,5 L15,19 C15,19.5522847 15.4477153,20 16,20 L19,20 C19.5522847,20 20,19.5522847 20,19 L20,5 C20,4.44771525 19.5522847,4 19,4 Z' ,
333+ fill: ' #000000' ,
334+ }),
335+ ]),
336+ col3 : () =>
337+ h (' svg' , { viewBox: ' 0 0 24 24' }, [
338+ h (' path' , {
339+ d: 'M6.23694 3.0004C7.20344 3.0004 7.98694 3.7839 7.98694 4.7504V19.2504C7.98694 20.2169 7.20344 21.0004 6.23694 21.0004H3.73694C2.77044 21.0004 1.98694 20.2169 1.98694 19.2504V4.7504C1.98694 3.83223 2.69405 3.07921 3.59341 3.0062L3.73694 3.0004H6.23694ZM20.263 3.0004C21.2295 3.0004 22.013 3.7839 22.013 4.7504V19.2504C22.013 20.2169 21.2295 21.0004 20.263 21.0004H17.763C16.7965 21.0004 16.013 20.2169 16.013 19.2504V4.7504C16.013 3.7839 16.7965 3.0004 17.763 3.0004H20.263ZM13.2369 2.99957C14.2034 2.99957 14.9869 3.78307 14.9869 4.74957V19.2496C14.9869 20.2161 14.2034 20.9996 13.2369 20.9996H10.7369C9.77044 20.9996 8.98694 20.2161 8.98694 19.2496V4.74957C8.98694 3.78307 9.77044 2.99957 10.7369 2.99957H13.2369ZM6.23694 4.5004H3.73694L3.67962 4.50701C3.56917 4.53292 3.48694 4.63206 3.48694 4.7504V19.2504C3.48694 19.3885 3.59887 19.5004 3.73694 19.5004H6.23694C6.37501 19.5004 6.48694 19.3885 6.48694 19.2504V4.7504C6.48694 4.61233 6.37501 4.5004 6.23694 4.5004ZM20.263 4.5004H17.763C17.6249 4.5004 17.513 4.61233 17.513 4.7504V19.2504C17.513 19.3885 17.6249 19.5004 17.763 19.5004H20.263C20.4011 19.5004 20.513 19.3885 20.513 19.2504V4.7504C20.513 4.61233 20.4011 4.5004 20.263 4.5004ZM13.2369 4.49957H10.7369C10.5989 4.49957 10.4869 4.6115 10.4869 4.74957V19.2496C10.4869 19.3876 10.5989 19.4996 10.7369 19.4996H13.2369C13.375 19.4996 13.4869 19.3876 13.4869 19.2496V4.74957C13.4869 4.6115 13.375 4.49957 13.2369 4.49957Z',
340+ fill: ' #000000' ,
341+ }),
342+ ]),
343+ }
344+ const gridPresetIcon = ref (gridPresetIcons .editable )
345+ const gridPresetIconItems = ref ([
346+ { name: ' editable' , icon: gridPresetIcons .editable , desc: ' Default' },
347+ { name: ' col1' , icon: gridPresetIcons .col1 , desc: ' One column' },
348+ { name: ' col2' , icon: gridPresetIcons .col2 , desc: ' Two columns' },
349+ { name: ' col3' , icon: gridPresetIcons .col3 , desc: ' Three columns' },
350+ ])
351+ const gridEditable = ref (true )
352+
273353const router = useRouter ()
274354
275355const sessionInfoItems = [
@@ -314,6 +394,45 @@ const widgetsGridKey = ref(0)
314394const widgetOutputs = ref ({})
315395var displayedLayoutWidgets = ref ([... layoutWidgets .value ])
316396
397+ const displayedLayoutWidgetsByPosition = computed (() => {
398+ return [... displayedLayoutWidgets .value ].sort ((a , b ) => {
399+ if (a .y !== b .y ) {
400+ return a .y - b .y
401+ }
402+ return a .x - b .x
403+ })
404+ })
405+
406+ const handleGridPresetChange = (newPreset ) => {
407+ let x = () => 0
408+ let w = 12
409+ let h = 14
410+ if (newPreset === gridPresetIcons .editable ) {
411+ if (selectedLayoutWidgets .value .length == 0 ) {
412+ gridEditable .value = true
413+ displayedLayoutWidgets = ref ([... layoutWidgets .value ])
414+ return
415+ }
416+ } else if (newPreset === gridPresetIcons .col2 ) {
417+ x = (index ) => (index % 2 ) * 6
418+ w = 6
419+ h = 11
420+ } else if (newPreset === gridPresetIcons .col3 ) {
421+ x = (index ) => (index % 3 ) * 4
422+ w = 4
423+ h = 9
424+ }
425+ gridEditable .value = false
426+ displayedLayoutWidgets .value = displayedLayoutWidgetsByPosition .value .map ((item , index ) => ({
427+ ... item,
428+ x: x (index),
429+ y: 0 ,
430+ w: w,
431+ h: h,
432+ }))
433+ widgetsGridKey .value ++
434+ }
435+
317436function setAddWidgetMenuState (value ) {
318437 isAddWidgetOpen .value = value
319438}
@@ -342,6 +461,7 @@ const onWidgetsGridFilter = () => {
342461 .filter ((item ) => selectedLayoutWidgets .value .includes (item .i ))
343462 .map ((item ) => ({ ... item, x: 0 , y: 0 , w: 12 , h: 14 }))
344463 }
464+ handleGridPresetChange (gridPresetIcon .value )
345465 widgetsGridKey .value ++
346466}
347467
@@ -421,6 +541,7 @@ onActivated(() => {
421541 // v8 ignore next
422542 if (selectedLayoutWidgets .value .length == 0 ) {
423543 displayedLayoutWidgets = ref ([... layoutWidgets .value ])
544+ handleGridPresetChange (gridPresetIcon .value )
424545 widgetsGridKey .value ++
425546 }
426547 }
@@ -438,4 +559,19 @@ onDeactivated(() => {
438559})
439560 </script >
440561
441- <style scoped></style >
562+ <style scoped>
563+ /* These are required to force v-select height to 56px */
564+ .custom-v-select-field-height :deep(.v-field ) {
565+ --v-input-control-height : 56px !important ;
566+ min-height : 56px !important ;
567+ height : 56px !important ;
568+ }
569+
570+ .custom-v-select-field-height :deep(.v-field__input ) {
571+ min-height : 56px !important ;
572+ height : 56px !important ;
573+ padding-top : 0px !important ;
574+ padding-bottom : 0px !important ;
575+ align-items : center ;
576+ }
577+ </style >
0 commit comments