@dataloop-ai/components 0.17.34 → 0.17.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataloop-ai/components",
3
- "version": "0.17.34",
3
+ "version": "0.17.36",
4
4
  "exports": {
5
5
  ".": "./index.ts",
6
6
  "./models": "./models.ts",
@@ -383,7 +383,7 @@ export default defineComponent({
383
383
  gap: var(--dl-button-content-gap, 7px);
384
384
  }
385
385
 
386
- .dl-chip.first-letter-capitalized {
386
+ .dl-button-container.first-letter-capitalized {
387
387
  &::first-letter,
388
388
  & > *::first-letter {
389
389
  text-transform: capitalize;
@@ -0,0 +1,144 @@
1
+ <template>
2
+ <div
3
+ ref="grid"
4
+ :style="gridStyles"
5
+ :class="gridClass"
6
+ >
7
+ <slot />
8
+ </div>
9
+ </template>
10
+
11
+ <script lang="ts">
12
+ import { defineComponent, PropType } from 'vue-demi'
13
+ import {
14
+ getGridTemplate,
15
+ getElementAbove,
16
+ findIndexInMatrix,
17
+ swapElemensInMatrix,
18
+ isCustomEvent
19
+ } from '../DlWidget/utils'
20
+
21
+ export default defineComponent({
22
+ model: {
23
+ prop: 'modelValue',
24
+ event: 'update:modelValue'
25
+ },
26
+ props: {
27
+ modelValue: {
28
+ type: Array as PropType<number[][]>,
29
+ default: null
30
+ },
31
+ rowGap: {
32
+ type: String,
33
+ default: '10px'
34
+ },
35
+ columnGap: {
36
+ type: String,
37
+ default: '10px'
38
+ },
39
+ maxElementsPerRow: {
40
+ type: Number,
41
+ default: 3
42
+ }
43
+ },
44
+ emits: ['update:modelValue'],
45
+ computed: {
46
+ gridStyles(): object {
47
+ return {
48
+ '--row-gap': this.rowGap,
49
+ '--column-gap': this.columnGap
50
+ }
51
+ },
52
+ gridClass(): string {
53
+ return this.modelValue
54
+ ? 'dl-grid-wrapper__grid'
55
+ : 'dl-grid-wrapper__flex'
56
+ }
57
+ },
58
+ watch: {
59
+ modelValue: {
60
+ handler(val) {
61
+ this.$nextTick(() => {
62
+ if (val) this.applyGridElementStyles()
63
+ })
64
+ },
65
+ immediate: true
66
+ }
67
+ },
68
+ mounted() {
69
+ Array.from((this.$refs.grid as HTMLElement).children).forEach(
70
+ (element: Element, index: number) => {
71
+ (element as HTMLElement).dataset.index = `${index}`
72
+ }
73
+ )
74
+ },
75
+ methods: {
76
+ applyGridElementStyles() {
77
+ if (!this.modelValue) return
78
+ const gridElements = Array.from(
79
+ (this.$refs.grid as HTMLElement).children
80
+ )
81
+ const gridTemplate = getGridTemplate(this.modelValue)
82
+ if (gridElements.length !== gridTemplate.length) return
83
+
84
+ const order = this.modelValue.flat()
85
+ gridElements.forEach((element: Element, index: number) => {
86
+ const orderIndex =
87
+ order.findIndex((nr: number) => nr === index + 1) + 1
88
+ const htmlElement = element as HTMLElement
89
+ htmlElement.style.order = `${orderIndex}`
90
+ htmlElement.style.gridColumn = gridTemplate[orderIndex - 1]
91
+ htmlElement.addEventListener('change-position', (e) => {
92
+ if (!isCustomEvent(e)) return
93
+ this.changePosition(e)
94
+ })
95
+ })
96
+ },
97
+ changePosition(e: CustomEvent) {
98
+ if (!this.modelValue) return
99
+ const side = e.detail.side
100
+ const className = (this.$refs.grid as HTMLElement).children[0]
101
+ .classList[0]
102
+ const sourceIndex =
103
+ parseInt(
104
+ getElementAbove(e.detail.source, className).dataset.index
105
+ ) + 1
106
+ const targetIndex =
107
+ parseInt(
108
+ getElementAbove(e.detail.target, className).dataset.index
109
+ ) + 1
110
+ const sourceMatrixIndex = findIndexInMatrix(
111
+ this.modelValue,
112
+ sourceIndex
113
+ )
114
+ const targetMatrixIndex = findIndexInMatrix(
115
+ this.modelValue,
116
+ targetIndex
117
+ )
118
+
119
+ const newLayout = swapElemensInMatrix(
120
+ this.modelValue,
121
+ sourceMatrixIndex,
122
+ targetMatrixIndex,
123
+ side,
124
+ this.maxElementsPerRow
125
+ )
126
+ this.$emit('update:modelValue', newLayout)
127
+ }
128
+ }
129
+ })
130
+ </script>
131
+
132
+ <style lang="scss" scoped>
133
+ .dl-grid-wrapper {
134
+ &__grid {
135
+ display: grid;
136
+ row-gap: var(--row-gap);
137
+ column-gap: var(--column-gap);
138
+ }
139
+ &__flex {
140
+ display: flex;
141
+ flex-wrap: wrap;
142
+ }
143
+ }
144
+ </style>
@@ -0,0 +1,4 @@
1
+ import DlGrid from './DlGrid.vue'
2
+ import { DlGridLayout } from './types'
3
+ export { DlGrid }
4
+ export type { DlGridLayout }
@@ -0,0 +1,4 @@
1
+ export interface DlGridLayout {
2
+ name: string
3
+ value: number[][]
4
+ }
@@ -7,18 +7,16 @@
7
7
  :id="uuid"
8
8
  ref="widget"
9
9
  :class="widgetStyles"
10
+ @mouseenter="handleVisibleDragIcon(true)"
11
+ @mouseleave="handleVisibleDragIcon(false)"
10
12
  >
11
- <div
12
- class="dl-widget__header"
13
- @mouseenter="visibleDragIcon = true"
14
- @mouseleave="visibleDragIcon = false"
15
- >
13
+ <div class="dl-widget__header">
16
14
  <div class="dl-widget__header--titles">
17
15
  <slot name="header" />
18
16
  </div>
19
17
  <dl-icon
20
18
  :style="`visibility: ${
21
- visibleDragIcon ? 'visible' : 'hidden'
19
+ visibleDragIcon && !isDragging ? 'visible' : 'hidden'
22
20
  }`"
23
21
  class="dl-widget__header--drag-icon"
24
22
  icon="icon-dl-drag"
@@ -47,14 +45,7 @@
47
45
  import { v4 } from 'uuid'
48
46
  import { defineComponent } from 'vue-demi'
49
47
  import { DlIcon } from '../../essential'
50
- import {
51
- getElementAbove,
52
- addMouseEnter,
53
- removeMouseEnter,
54
- setFlexBasis,
55
- insertAfter
56
- } from './utils'
57
- import { swapNodes } from '../../../utils/swapNodes'
48
+ import { getElementAbove, addMouseEnter, removeMouseEnter } from './utils'
58
49
 
59
50
  export default defineComponent({
60
51
  name: 'DlWidget',
@@ -78,20 +69,20 @@ export default defineComponent({
78
69
  return `${this.isDragging ? 'dl-widget__drag' : 'dl-widget'}`
79
70
  }
80
71
  },
81
- mounted() {
82
- setFlexBasis()
83
- },
84
72
  methods: {
85
73
  startDragging(e: MouseEvent) {
86
74
  this.isDragging = true
75
+ document.body.style.cursor = 'grabbing'
87
76
  this.draggedWidget = getElementAbove(
88
77
  e.target as HTMLElement,
89
78
  'dl-widget'
90
79
  )
91
80
  if (this.draggedWidget) {
92
- (this.$refs.clone as HTMLElement).appendChild(
93
- this.draggedWidget.cloneNode(true)
94
- )
81
+ const clone = this.$refs.clone as HTMLElement
82
+ clone.appendChild(this.draggedWidget.cloneNode(true))
83
+ clone.style.visibility = 'visible'
84
+ clone.style.width = `${this.draggedWidget.offsetWidth}px`
85
+ clone.style.height = `${this.draggedWidget.offsetHeight}px`
95
86
  }
96
87
 
97
88
  const sourceCanvas = this.draggedWidget?.querySelector('canvas')
@@ -118,13 +109,20 @@ export default defineComponent({
118
109
  },
119
110
  stopDragging(e: MouseEvent) {
120
111
  this.isDragging = false
121
- ;(this.$refs.clone as HTMLElement).innerHTML = ''
112
+ document.body.style.cursor = 'default'
113
+ const clone = this.$refs.clone as HTMLElement
114
+ clone.style.visibility = 'hidden'
115
+ clone.innerHTML = ''
122
116
  const target = getElementAbove(e.target as HTMLElement, 'dl-widget')
117
+ const change = {
118
+ source: this.draggedWidget,
119
+ target
120
+ }
123
121
  if (target && this.draggedWidget) {
124
- swapNodes({
125
- source: this.draggedWidget,
126
- target
122
+ const event = new CustomEvent('change-position', {
123
+ detail: change
127
124
  })
125
+ ;(this.$refs.wrapper as HTMLElement).dispatchEvent(event)
128
126
  }
129
127
  window.removeEventListener('mousemove', this.moveClone)
130
128
  window.removeEventListener('mouseup', this.stopDragging)
@@ -148,30 +146,26 @@ export default defineComponent({
148
146
  this.handleMouseInsideWidget
149
147
  )
150
148
  })
151
- this.timer = setTimeout(this.insertWidget, 1000)
149
+ this.timer = setTimeout(this.insertWidget, 200)
152
150
  },
153
151
  insertWidget() {
154
152
  const targetWidget = getElementAbove(
155
153
  this.hoveredWidget,
156
154
  'widget-wrapper'
157
155
  )
158
- const targetRow = getElementAbove(this.hoveredWidget, 'dl-grid-row')
159
- if (this.isLeftSide) {
160
- targetRow.insertBefore(
161
- this.$refs.wrapper as HTMLElement,
162
- targetWidget
163
- )
164
- } else {
165
- insertAfter(
166
- this.$refs.wrapper as unknown as HTMLElement,
167
- targetWidget
168
- )
169
- }
156
+ const event = new CustomEvent('change-position', {
157
+ detail: {
158
+ source: this.$refs.wrapper,
159
+ target: targetWidget,
160
+ side: this.isLeftSide ? 'left' : 'right'
161
+ }
162
+ })
163
+ ;(this.$refs.wrapper as HTMLElement).dispatchEvent(event)
164
+ window.clearTimeout(this.timer)
170
165
  this.hoveredWidget.removeEventListener(
171
166
  'mousemove',
172
167
  this.handleMouseInsideWidget
173
168
  )
174
- setFlexBasis()
175
169
  },
176
170
  handleMouseInsideWidget(e: MouseEvent) {
177
171
  const mouseOffsetInside = e.clientX - this.hoveredWidget.offsetLeft
@@ -181,6 +175,11 @@ export default defineComponent({
181
175
  clearTimeout(this.timer)
182
176
  this.handleMouseEnter(e)
183
177
  }
178
+ },
179
+ handleVisibleDragIcon(val: boolean) {
180
+ if (!document.querySelector('.drag-clone').innerHTML.toString()) {
181
+ this.visibleDragIcon = val
182
+ }
184
183
  }
185
184
  }
186
185
  })
@@ -200,7 +199,7 @@ export default defineComponent({
200
199
 
201
200
  &--drag-icon {
202
201
  flex-grow: 1;
203
- cursor: pointer;
202
+ cursor: grab;
204
203
 
205
204
  &::v-deep .dl-icon {
206
205
  transform: rotate(90deg) !important;
@@ -223,7 +222,17 @@ export default defineComponent({
223
222
  }
224
223
 
225
224
  &__drag {
226
- visibility: hidden;
225
+ position: relative;
226
+ &::after {
227
+ content: '';
228
+ position: absolute;
229
+ width: 100%;
230
+ height: 100%;
231
+ top: 0;
232
+ left: 0;
233
+ background: var(--dl-color-separator);
234
+ border-radius: 5px;
235
+ }
227
236
  }
228
237
  }
229
238
 
@@ -236,6 +245,6 @@ export default defineComponent({
236
245
  .widget-wrapper {
237
246
  flex-basis: var(--widget-flex-basis);
238
247
  margin: var(--row-gap) var(--column-gap);
239
- transition: 0.1s;
248
+ padding: 15px;
240
249
  }
241
250
  </style>
@@ -1,5 +1,3 @@
1
1
  import DlWidget from './DlWidget.vue'
2
- import DlGrid from './DlGrid.vue'
3
- import DlGridRow from './DlGridRow.vue'
4
2
 
5
- export { DlWidget, DlGrid, DlGridRow }
3
+ export { DlWidget }
@@ -1,3 +1,30 @@
1
+ import { cloneDeep } from 'lodash'
2
+
3
+ export function leastCommonMultiple(arr: number[]) {
4
+ if (!arr) return
5
+ const gcd = (a: number, b: number): number => (a ? gcd(b % a, a) : b)
6
+ const lcm = (a: number, b: number): number => (a * b) / gcd(a, b)
7
+ return arr.reduce(lcm)
8
+ }
9
+
10
+ export function getGridTemplate(layout: number[][]) {
11
+ if (!layout) return
12
+ const flatLayout = layout.map((el) => el.length)
13
+ const template = []
14
+ const lcm = leastCommonMultiple(flatLayout)
15
+ for (let i = 0; i < flatLayout.length; i++) {
16
+ const columns = flatLayout[i]
17
+ let columnTrack = 1
18
+ for (let j = 0; j < columns; j++) {
19
+ let gridSpan = lcm / columns
20
+ template.push(`${columnTrack} / ${gridSpan + columnTrack}`)
21
+ columnTrack += gridSpan
22
+ gridSpan += gridSpan
23
+ }
24
+ }
25
+ return template
26
+ }
27
+
1
28
  export function getElementAbove(el: HTMLElement, className: string) {
2
29
  //@ts-ignore
3
30
  for (; el && el !== document; el = el.parentNode) {
@@ -22,16 +49,44 @@ export function removeMouseEnter(
22
49
  })
23
50
  }
24
51
 
25
- export function setFlexBasis() {
26
- Array.from(document.getElementsByClassName('dl-grid-row')).forEach(
27
- (row) => {
28
- Array.from(row.children).forEach((widget: any) => {
29
- widget.style.flexBasis = `${100 / row.children.length}%`
30
- })
52
+ export function findIndexInMatrix(matrix: number[][], nr: number) {
53
+ for (let i = 0; i < matrix.length; i++) {
54
+ for (let j = 0; j < matrix[i].length; j++) {
55
+ if (matrix[i][j] === nr) return { row: i, column: j }
31
56
  }
57
+ }
58
+ }
59
+
60
+ export function swapElemensInMatrix(
61
+ layout: number[][],
62
+ sourceIndex: any,
63
+ targetIndex: any,
64
+ side: string,
65
+ maxElements: number
66
+ ) {
67
+ if (targetIndex.column === sourceIndex.column + 1 && side === 'left')
68
+ return layout
69
+ const newLayout = cloneDeep(layout)
70
+
71
+ const removedElement = newLayout[sourceIndex.row].splice(
72
+ sourceIndex.column,
73
+ 1
32
74
  )
75
+ newLayout[targetIndex.row].splice(
76
+ side === 'right' ? targetIndex.column + 1 : targetIndex.column,
77
+ 0,
78
+ removedElement[0]
79
+ )
80
+
81
+ return isTooLarge(newLayout, maxElements) ? layout : newLayout
82
+ }
83
+
84
+ function isTooLarge(layout: number[][], max: number) {
85
+ const lengths = layout.map((row) => row.length)
86
+ const highest = Math.max(...lengths)
87
+ return highest > max
33
88
  }
34
89
 
35
- export function insertAfter(newNode: HTMLElement, existingNode: HTMLElement) {
36
- existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling)
90
+ export function isCustomEvent(event: Event): event is CustomEvent {
91
+ return 'detail' in event
37
92
  }
@@ -11,4 +11,5 @@ export * from './DlPanelContainer'
11
11
  export * from './DlProgressChart'
12
12
  export * from './DlEllipsis'
13
13
  export * from './DlCard'
14
+ export * from './DlGrid'
14
15
  export * from './DlMarkupTable'
@@ -225,6 +225,9 @@ export default defineComponent({
225
225
  if (event.type !== 'mousemove') {
226
226
  return
227
227
  }
228
+ const hover = !!document.querySelector('.drag-clone')
229
+ chartJS.options.plugins.tooltip.enabled = !hover
230
+ if (hover) return
228
231
  if (
229
232
  items.length === 0 ||
230
233
  chartJS.getElementsAtEventForMode(
@@ -26,14 +26,13 @@
26
26
  import { defineComponent, PropType } from 'vue-demi'
27
27
  import DlDoughnutChart from './DlDoughnutChart.vue'
28
28
  import { TDoughnutChartData } from './types/TDoughnutChartData'
29
- import { DlWidget, DlGridRow, DlGrid } from '../../../../basic'
29
+ import { DlWidget, DlGrid } from '../../../../basic'
30
30
 
31
31
  export default defineComponent({
32
32
  name: 'DlDoughnutChartWidget',
33
33
  components: {
34
34
  DlDoughnutChart,
35
35
  DlGrid,
36
- DlGridRow,
37
36
  DlWidget
38
37
  },
39
38
  props: {
@@ -68,7 +68,7 @@ export default defineComponent({
68
68
  fullWidth: { type: Boolean, default: false },
69
69
  disabled: { type: Boolean, default: false },
70
70
  modelValue: { type: String, required: true },
71
- fontSize: { type: String, default: '12px' },
71
+ fontSize: { type: String, default: '18px' },
72
72
  gap: { type: String, default: '40px' }
73
73
  },
74
74
  emits: ['update:model-value'],
@@ -14,9 +14,10 @@
14
14
  <span>
15
15
  <dl-icon
16
16
  v-if="showTooltip"
17
- size="12px"
17
+ :size="iconSize"
18
18
  icon="icon-dl-info"
19
19
  class="info-icon"
20
+ color="dl-color-darker"
20
21
  />
21
22
  <dl-tooltip v-if="showTooltip === true">
22
23
  {{ tooltip }}
@@ -46,7 +47,7 @@ export default defineComponent({
46
47
  showTooltip: { type: Boolean, default: false },
47
48
  tooltip: { type: String, default: null },
48
49
  tabindex: { type: String, default: '0' },
49
- fontSize: { type: String, default: '12px' }
50
+ fontSize: { type: String, default: '18px' }
50
51
  },
51
52
  emits: ['click'],
52
53
  data() {
@@ -55,6 +56,10 @@ export default defineComponent({
55
56
  }
56
57
  },
57
58
  computed: {
59
+ iconSize(): string {
60
+ const fontSize = Number(this.fontSize.replace('px', ''))
61
+ return `${fontSize - 2 < 0 ? 0 : fontSize - 2}px`
62
+ },
58
63
  cssFontSize(): Record<string, string> {
59
64
  return {
60
65
  '--dl-tab-font-size': this.fontSize
@@ -59,6 +59,20 @@
59
59
  >
60
60
  Lorem ipsum dolor sit amet, consectetur adipisicing elit.
61
61
  </DlAlert>
62
+ <dl-alert
63
+ style="margin-top: 20px"
64
+ fluid
65
+ type="warning"
66
+ >
67
+ this is an annoying message with link, this is an annoying message
68
+ with linkthis is an annoying message with linkthis is an annoying
69
+ message with linkthis is an annoying message with linkthis is an
70
+ annoying message with linkthis is an annoying message with linkthis
71
+ is an annoying message with link
72
+ <span>
73
+ Please
74
+ <dl-link color="dl-color-link">Contact us</dl-link>.</span>
75
+ </dl-alert>
62
76
  </div>
63
77
  </template>
64
78
 
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <div class="container">
3
+ <dl-grid>
4
+ <img
5
+ v-for="(a, index) in 10"
6
+ :key="index"
7
+ class="grid-image"
8
+ :src="getRandomImg()"
9
+ >
10
+ </dl-grid>
11
+ </div>
12
+ </template>
13
+
14
+ <script lang="ts">
15
+ import { defineComponent } from 'vue-demi'
16
+ import { DlGrid } from '../components/'
17
+
18
+ const getRandomImg = () => {
19
+ const random = Math.floor(Math.random() * 3) + 1
20
+ const link = `https://picsum.photos/${random * 100}/${
21
+ random * 100
22
+ }?random=${random}`
23
+ return link
24
+ }
25
+ export default defineComponent({
26
+ components: {
27
+ DlGrid
28
+ },
29
+ setup() {
30
+ return { getRandomImg }
31
+ }
32
+ })
33
+ </script>
34
+
35
+ <style lang="scss" scoped>
36
+ .grid-image {
37
+ border: 2px solid var(--dl-color-darker);
38
+ margin: 5px;
39
+ }
40
+ </style>
@@ -61,10 +61,12 @@
61
61
  </dl-tab-panel>
62
62
  </dl-tab-panels>
63
63
 
64
+ With smaller font 14px
64
65
  <dl-tabs
65
66
  v-model="selectedTab"
66
67
  :items="tabItems"
67
68
  style="margin-top: 100px; max-width: 60%"
69
+ font-size="14px"
68
70
  @update:model-value="handleModelValueUpdate"
69
71
  >
70
72
  <template #top-right="props">
@@ -1,11 +1,149 @@
1
+ <template>
2
+ <div>
3
+ <div class="options">
4
+ <div class="select-layout">
5
+ <select
6
+ class="select-layout__input"
7
+ @change="selectLayout"
8
+ >
9
+ <option
10
+ v-for="(layout, index) in layouts"
11
+ :key="index"
12
+ :value="index"
13
+ >
14
+ {{ layout.name }}
15
+ </option>
16
+ </select>
17
+ <button
18
+ class="select-layout__button"
19
+ @mousedown="saveLayout"
20
+ >
21
+ Save
22
+ </button>
23
+ <span class="select-layout__info">{{ hasBeenSaved }}</span>
24
+ </div>
25
+ <div class="widgets-per-row">
26
+ <span class="widgets-per-row__label"> Widgets per row: </span>
27
+ <input
28
+ v-model="widgetsPerRow"
29
+ class="widgets-per-row__input"
30
+ type="number"
31
+ >
32
+ </div>
33
+ </div>
34
+ <dl-grid
35
+ v-model="layout"
36
+ :max-elements-per-row="widgetsPerRow"
37
+ >
38
+ <dl-widget>
39
+ <template #header>
40
+ <span>Widget 1</span>
41
+ <span style="font-size: 12px; color: gray">Subtitle</span>
42
+ </template>
43
+ <template #content>
44
+ <dl-bar-chart
45
+ :legend-props="legendProps"
46
+ :data="data"
47
+ :options="options"
48
+ :items-in-view="8"
49
+ />
50
+ </template>
51
+ <template #menu>
52
+ <div class="menu-icons">
53
+ <dl-icon
54
+ size="m"
55
+ icon="icon-dl-settings"
56
+ />
57
+ <dl-icon
58
+ size="m"
59
+ icon="icon-dl-download"
60
+ />
61
+ </div>
62
+ </template>
63
+ <template #description>
64
+ <span>Lorem ipsum dolor sit amet consectetur adipisicing
65
+ elit. Libero eligendi dolore, similique possimus
66
+ veritatis in vitae quia praesentium fuga quibusdam
67
+ autem. Doloremque tenetur repudiandae a cupiditate modi
68
+ dicta eveniet veritatis?</span>
69
+ </template>
70
+ </dl-widget>
71
+
72
+ <dl-widget>
73
+ <template #header>
74
+ <span>Widget 2</span>
75
+ </template>
76
+ <template #content>
77
+ <dl-bar-chart
78
+ :legend-props="legendProps"
79
+ :data="data"
80
+ :options="options"
81
+ :items-in-view="6"
82
+ />
83
+ </template>
84
+ </dl-widget>
85
+
86
+ <dl-widget>
87
+ <template #header>
88
+ <span>Widget 3</span>
89
+ </template>
90
+ <template #content>
91
+ <dl-bar-chart
92
+ :legend-props="legendProps"
93
+ :data="data"
94
+ :options="options"
95
+ :items-in-view="6"
96
+ />
97
+ </template>
98
+ </dl-widget>
99
+
100
+ <dl-widget>
101
+ <template #header>
102
+ <span>Widget 4</span>
103
+ <span style="font-size: 12px; color: gray">Subtitle</span>
104
+ </template>
105
+ <template #content>
106
+ <dl-bar-chart
107
+ :legend-props="legendProps"
108
+ :data="data"
109
+ :options="options"
110
+ :items-in-view="8"
111
+ />
112
+ </template>
113
+ <template #description>
114
+ <span>Lorem ipsum dolor sit amet consectetur adipisicing
115
+ elit. Libero eligendi dolore, similique possimus
116
+ veritatis in vitae quia praesentium fuga quibusdam
117
+ autem. Doloremque tenetur repudiandae a cupiditate modi
118
+ dicta eveniet veritatis?</span>
119
+ </template>
120
+ </dl-widget>
121
+
122
+ <dl-widget>
123
+ <template #header>
124
+ <span>Widget 5</span>
125
+ </template>
126
+ <template #content>
127
+ <dl-bar-chart
128
+ :legend-props="legendProps"
129
+ :data="data"
130
+ :options="options"
131
+ :items-in-view="6"
132
+ />
133
+ </template>
134
+ </dl-widget>
135
+ </dl-grid>
136
+ </div>
137
+ </template>
138
+
1
139
  <script lang="ts">
2
- import { defineComponent } from 'vue-demi'
140
+ import { defineComponent, ref } from 'vue-demi'
3
141
  import {
4
142
  DlWidget,
5
- DlGridRow,
6
143
  DlGrid,
7
144
  DlBarChart,
8
- DlConfusionMatrix
145
+ DlGridLayout,
146
+ DlIcon
9
147
  } from '../components'
10
148
 
11
149
  const labelsFn = () => {
@@ -65,67 +203,85 @@ export default defineComponent({
65
203
  DlGrid,
66
204
  DlWidget,
67
205
  DlBarChart,
68
- DlGridRow,
69
- DlConfusionMatrix
206
+ DlIcon
70
207
  },
71
208
  setup() {
72
- return { data, labels, matrix }
209
+ const layout = ref([
210
+ [1, 5, 2],
211
+ [3, 4]
212
+ ])
213
+
214
+ const layouts = ref<DlGridLayout[]>([
215
+ {
216
+ name: 'Layout 1',
217
+ value: layout.value
218
+ }
219
+ ])
220
+
221
+ const widgetsPerRow = ref(3)
222
+ const hasBeenSaved = ref('')
223
+
224
+ const saveLayout = () => {
225
+ const newLayout = {
226
+ name: `Layout ${layouts.value.length + 1}`,
227
+ value: layout.value
228
+ }
229
+ layouts.value.push(newLayout)
230
+ hasBeenSaved.value = `${newLayout.name} has been saved.`
231
+ setTimeout(() => {
232
+ hasBeenSaved.value = ''
233
+ }, 2000)
234
+ }
235
+
236
+ const selectLayout = (e: InputEvent) => {
237
+ const index = parseInt((e.target as HTMLInputElement).value)
238
+ layout.value = layouts.value[index].value
239
+ }
240
+
241
+ return {
242
+ data,
243
+ layout,
244
+ layouts,
245
+ widgetsPerRow,
246
+ hasBeenSaved,
247
+ saveLayout,
248
+ selectLayout
249
+ }
73
250
  }
74
251
  })
75
252
  </script>
76
253
 
77
- <template>
78
- <div>
79
- <dl-grid gap="20px">
80
- <dl-grid-row>
81
- <dl-widget>
82
- <template #header>
83
- <span>Widget 7</span>
84
- <span style="font-size: 12px; color: gray">Subtitle</span>
85
- </template>
86
- <template #content>
87
- <dl-confusion-matrix
88
- :matrix="matrix"
89
- :labels="labels"
90
- />
91
- </template>
92
- <template #description>
93
- <span>Lorem ipsum dolor sit amet consectetur adipisicing
94
- elit. Libero eligee a cupiditate modi dicta eveniet
95
- veritatis?</span>
96
- </template>
97
- </dl-widget>
98
- </dl-grid-row>
99
-
100
- <dl-grid-row gap="20px">
101
- <dl-widget>
102
- <template #header>
103
- <span>Widget 2</span>
104
- </template>
105
- <template #content>
106
- <dl-bar-chart
107
- :legend-props="legendProps"
108
- :data="data"
109
- :options="options"
110
- :items-in-view="6"
111
- />
112
- </template>
113
- </dl-widget>
114
-
115
- <dl-widget>
116
- <template #header>
117
- <span>Widget 3</span>
118
- </template>
119
- <template #content>
120
- <dl-bar-chart
121
- :legend-props="legendProps"
122
- :data="data"
123
- :options="options"
124
- :items-in-view="6"
125
- />
126
- </template>
127
- </dl-widget>
128
- </dl-grid-row>
129
- </dl-grid>
130
- </div>
131
- </template>
254
+ <style lang="scss" scoped>
255
+ .options {
256
+ width: 100%;
257
+ display: flex;
258
+ justify-content: space-between;
259
+ }
260
+ .widgets-per-row {
261
+ &__input {
262
+ padding: 5px;
263
+ border-radius: 5px;
264
+ width: 50px;
265
+ }
266
+ }
267
+ .select-layout {
268
+ &__input,
269
+ &__button {
270
+ padding: 5px;
271
+ border-radius: 5px;
272
+ margin: 0px 2px;
273
+ }
274
+ &__info {
275
+ font-size: 0.8em;
276
+ margin-left: 10px;
277
+ }
278
+ }
279
+ .menu-icons {
280
+ display: flex;
281
+ align-items: center;
282
+ & > * {
283
+ cursor: pointer;
284
+ margin: 0px 5px;
285
+ }
286
+ }
287
+ </style>
@@ -53,6 +53,7 @@ import DlKpiDemo from './DlKpiDemo.vue'
53
53
  import DlEllipsisDemo from './DlEllipsisDemo.vue'
54
54
  import DlSeparatorDemo from './DlSeparatorDemo.vue'
55
55
  import DlCardDemo from './DlCardDemo.vue'
56
+ import DlGridDemo from './DlGridDemo.vue'
56
57
  import DlMarkupTableDemo from './DlMarkupTableDemo.vue'
57
58
  import DlVirtualScrollDemo from './DlVirtualScrollDemo.vue'
58
59
  import DlJsonEditorDemo from './DlJsonEditorDemo.vue'
@@ -113,6 +114,7 @@ export default {
113
114
  DlSeparatorDemo,
114
115
  DlKpiDemo,
115
116
  DlCardDemo,
117
+ DlGridDemo,
116
118
  DlMarkupTableDemo,
117
119
  DlVirtualScrollDemo,
118
120
  DlJsonEditorDemo
@@ -1,33 +0,0 @@
1
- <template>
2
- <div
3
- :style="rowGap"
4
- class="dl-grid"
5
- >
6
- <slot />
7
- </div>
8
- </template>
9
-
10
- <script lang="ts">
11
- import { defineComponent } from 'vue-demi'
12
-
13
- export default defineComponent({
14
- props: {
15
- gap: {
16
- type: String,
17
- default: '30px'
18
- }
19
- },
20
- computed: {
21
- rowGap(): Record<string, string> {
22
- return { '--row-gap': this.gap }
23
- }
24
- }
25
- })
26
- </script>
27
-
28
- <style lang="scss" scoped>
29
- .dl-grid {
30
- display: flex;
31
- flex-direction: column;
32
- }
33
- </style>
@@ -1,32 +0,0 @@
1
- <template>
2
- <div
3
- :style="columnGap"
4
- class="dl-grid-row"
5
- >
6
- <slot />
7
- </div>
8
- </template>
9
-
10
- <script lang="ts">
11
- import { defineComponent } from 'vue-demi'
12
-
13
- export default defineComponent({
14
- props: {
15
- gap: {
16
- type: String,
17
- default: '30px'
18
- }
19
- },
20
- computed: {
21
- columnGap(): Record<string, string> {
22
- return { '--column-gap': this.gap }
23
- }
24
- }
25
- })
26
- </script>
27
-
28
- <style scoped>
29
- .dl-grid-row {
30
- display: flex;
31
- }
32
- </style>
@@ -1,30 +0,0 @@
1
- export function swapNodes({ source, target }: NodeSwap) {
2
- const p1 = source.parentNode
3
- const p2 = target.parentNode
4
- let i1
5
- let i2
6
-
7
- if (!p1 || !p2 || p1.isEqualNode(target) || p2.isEqualNode(source)) return
8
-
9
- for (var i = 0; i < p1.children.length; i++) {
10
- if (p1.children[i].isEqualNode(source)) {
11
- i1 = i
12
- }
13
- }
14
- for (var i = 0; i < p2.children.length; i++) {
15
- if (p2.children[i].isEqualNode(target)) {
16
- i2 = i
17
- }
18
- }
19
-
20
- if (p1.isEqualNode(p2) && i1 < i2) {
21
- i2++
22
- }
23
- p1.insertBefore(target, p1.children[i1])
24
- p2.insertBefore(source, p2.children[i2])
25
- }
26
-
27
- export interface NodeSwap {
28
- source: HTMLElement
29
- target: HTMLElement
30
- }