@bildvitta/quasar-ui-asteroid 3.20.0-beta.2 → 3.20.0-beta.21

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.
Files changed (102) hide show
  1. package/package.json +3 -3
  2. package/src/asteroid.js +8 -1
  3. package/src/components/actions/QasActions.vue +12 -2
  4. package/src/components/actions-menu/QasActionsMenu.vue +18 -5
  5. package/src/components/alert/QasAlert.vue +89 -64
  6. package/src/components/app-user/QasAppUser.vue +2 -1
  7. package/src/components/board-generator/QasBoardGenerator.vue +883 -162
  8. package/src/components/board-generator/QasBoardGenerator.yml +83 -2
  9. package/src/components/board-generator/private/PvBoardGeneratorCardsContainer.vue +25 -0
  10. package/src/components/box/QasBox.vue +16 -3
  11. package/src/components/box/QasBox.yml +10 -0
  12. package/src/components/btn/QasBtn.vue +27 -5
  13. package/src/components/btn/QasBtn.yml +10 -1
  14. package/src/components/btn-dropdown/QasBtnDropdown.vue +13 -1
  15. package/src/components/card/QasCard.vue +97 -25
  16. package/src/components/card/QasCard.yml +10 -0
  17. package/src/components/card-image/QasCardImage.vue +10 -1
  18. package/src/components/card-image/QasCardImage.yml +5 -0
  19. package/src/components/chart-view/QasChartView.vue +4 -3
  20. package/src/components/chart-view/QasChartView.yml +5 -0
  21. package/src/components/checkbox/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  22. package/src/components/copy/QasCopy.vue +6 -1
  23. package/src/components/copy/QasCopy.yml +5 -0
  24. package/src/components/date-time-input/QasDateTimeInput.vue +30 -6
  25. package/src/components/dialog/QasDialog.vue +308 -91
  26. package/src/components/dialog/QasDialog.yml +51 -23
  27. package/src/components/dialog/composables/use-cancel.js +1 -1
  28. package/src/components/dialog/composables/use-dynamic-components.js +2 -2
  29. package/src/components/dialog/composables/use-ok.js +1 -0
  30. package/src/components/dialog-router/QasDialogRouter.vue +1 -1
  31. package/src/components/drawer/QasDrawer.vue +76 -26
  32. package/src/components/drawer/QasDrawer.yml +10 -0
  33. package/src/components/expansion-item/QasExpansionItem.yml +5 -0
  34. package/src/components/filters/QasFilters.vue +2 -1
  35. package/src/components/filters/private/PvFiltersActions.vue +79 -13
  36. package/src/components/form-generator/QasFormGenerator.vue +8 -1
  37. package/src/components/form-generator/QasFormGenerator.yml +10 -0
  38. package/src/components/form-view/QasFormView.vue +20 -11
  39. package/src/components/form-view/QasFormView.yml +6 -0
  40. package/src/components/gallery/composables/use-delete.js +2 -3
  41. package/src/components/gallery/private/PvGalleryCarouselDialog.vue +8 -7
  42. package/src/components/grid-item/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  43. package/src/components/header/QasHeader.vue +66 -11
  44. package/src/components/header/QasHeader.yml +16 -1
  45. package/src/components/infinite-scroll/QasInfiniteScroll.vue +1 -1
  46. package/src/components/label/QasLabel.vue +3 -1
  47. package/src/components/layout/QasLayout.vue +16 -1
  48. package/src/components/layout/private/PvLayoutNotificationsDrawer.vue +2 -1
  49. package/src/components/layout/private/PvLayoutOverlayDrawer.vue +4 -2
  50. package/src/components/lazy-loading-components/QasLazyLoadingComponents.vue +262 -0
  51. package/src/components/lazy-loading-components/QasLazyLoadingComponents.yml +49 -0
  52. package/src/components/list-view/QasListView.vue +12 -4
  53. package/src/components/list-view/QasListView.yml +12 -0
  54. package/src/components/page-header/QasPageHeader.vue +49 -3
  55. package/src/components/page-header/QasPageHeader.yml +5 -0
  56. package/src/components/router-link/QasRouterLink.vue +72 -0
  57. package/src/components/router-link/QasRouterLink.yml +24 -0
  58. package/src/components/search-box/QasSearchBox.vue +1 -1
  59. package/src/components/select/QasSelect.vue +8 -1
  60. package/src/components/select-list-dialog/QasSelectListDialog.vue +40 -20
  61. package/src/components/select-list-dialog/QasSelectListDialog.yml +14 -2
  62. package/src/components/signature-uploader/QasSignatureUploader.vue +5 -18
  63. package/src/components/single-view/QasSingleView.vue +2 -2
  64. package/src/components/skeleton/QasSkeleton.vue +139 -0
  65. package/src/components/skeleton/QasSkeleton.yml +48 -0
  66. package/src/components/sortable/QasSortable.vue +1 -1
  67. package/src/components/stepper/QasStepper.vue +24 -2
  68. package/src/components/table-generator/QasTableGenerator.vue +186 -35
  69. package/src/components/table-generator/QasTableGenerator.yml +6 -1
  70. package/src/components/tabs-generator/QasTabsGenerator.vue +14 -3
  71. package/src/components/tabs-generator/QasTabsGenerator.yml +5 -1
  72. package/src/components/text-truncate/QasTextTruncate.vue +61 -12
  73. package/src/components/text-truncate/QasTextTruncate.yml +5 -0
  74. package/src/components/toggle-visibility/QasToggleVisibility.vue +2 -1
  75. package/src/components/tooltip/QasTooltip.vue +6 -1
  76. package/src/components/tree-generator/QasTreeGenerator.vue +4 -6
  77. package/src/components/uploader/QasUploader.vue +12 -2
  78. package/src/composables/private/use-view.js +1 -1
  79. package/src/composables/use-overlay-navigation.js +116 -10
  80. package/src/composables/use-screen.js +17 -1
  81. package/src/css/components/button.scss +82 -3
  82. package/src/css/components/item.scss +6 -0
  83. package/src/css/utils/background.scss +5 -0
  84. package/src/css/utils/border.scss +6 -0
  85. package/src/css/utils/container.scss +4 -3
  86. package/src/css/utils/text.scss +9 -0
  87. package/src/helpers/copy-to-clipboard.js +2 -1
  88. package/src/helpers/filters.js +1 -1
  89. package/src/helpers/promise-handler.js +2 -1
  90. package/src/helpers/set-scroll-gradient.js +31 -8
  91. package/src/helpers/set-scroll-on-grab.js +10 -3
  92. package/src/index.scss +1 -0
  93. package/src/mixins/search-filter.js +7 -1
  94. package/src/plugins/delete/Delete.js +7 -9
  95. package/src/plugins/delete/Delete.yml +1 -1
  96. package/src/plugins/dialog/Dialog.yml +1 -1
  97. package/src/plugins/notify-error/NotifyError.yml +1 -1
  98. package/src/plugins/notify-success/NotifySuccess.yml +1 -1
  99. package/src/plugins/screen/Screen.js +17 -1
  100. package/src/plugins/screen/Screen.yml +5 -1
  101. package/src/vue-plugin.js +5 -7
  102. package/src/plugins/index.js +0 -5
@@ -97,8 +97,8 @@ props:
97
97
  type: Number
98
98
  default: 12
99
99
 
100
- use-mark-raw:
101
- desc: Define se os valores dos itens das colunas irão ser atribuídos utilizando o "markRaw", onde somente a primeira camada do model será reativa. (https://vuejs.org/api/reactivity-advanced.html#markraw)
100
+ skeleton:
101
+ desc: Exibe o estado de esqueleto de carregamento das colunas. Enquanto `true`, cada coluna renderiza cards fictícios no lugar dos itens reais.
102
102
  type: Boolean
103
103
  default: true
104
104
 
@@ -115,6 +115,10 @@ props:
115
115
  default: "{ animation: 500, swapThreshold: 1, delay: 50, delayOnTouchOnly: true, emptyInsertThreshold: 0 }"
116
116
  debugger: true
117
117
 
118
+ use-confirm-dialog:
119
+ desc: Controla se o dialog de confirmação para o drag and drop será utilizado. Caso seja "true", o dialog é aberto utilizando as props passadas em "confirm-dialog-props" e as ações de confirmar e cancelar são feitas por padrão no componente. Caso seja "false", o drag and drop é realizado sem confirmação.
120
+ type: Boolean
121
+
118
122
  use-drag-and-drop-x:
119
123
  desc: Controla se irá ter drag and drop no eixo X (entre colunas).
120
124
  type: Boolean
@@ -150,11 +154,26 @@ slots:
150
154
  column-item:
151
155
  desc: Slot para acessar o item da coluna.
152
156
  scope:
157
+ column-index:
158
+ desc: Índice da coluna atual.
159
+ type: Number
160
+ default: 0
161
+
153
162
  fields:
154
163
  desc: Fields referente à coluna atual do template.
155
164
  type: Object
156
165
  default: {}
157
166
 
167
+ header:
168
+ desc: Informações do header da coluna atual.
169
+ type: Object
170
+ default: {}
171
+
172
+ is-updating-position:
173
+ desc: Indica se o item está sendo atualizado via drag-and-drop (aguardando retorno da API de update).
174
+ type: Boolean
175
+ default: false
176
+
158
177
  item:
159
178
  desc: Informações de cada item da coluna que foi buscado através da API.
160
179
  type: Object
@@ -219,3 +238,65 @@ methods:
219
238
 
220
239
  'fetchColumn: (header) => void':
221
240
  desc: Busca uma coluna específica com base no header fornecido.
241
+
242
+ 'refreshColumn: (header) => void':
243
+ desc: Reinicia a paginação da coluna e refaz a busca, substituindo completamente os itens existentes.
244
+ params:
245
+ header:
246
+ desc: Header da coluna a ser recarregada (mesmo formato da prop `headers`).
247
+ type: Object
248
+ required: true
249
+
250
+ 'removeItemFromList: ({ headerKey, itemId }) => void':
251
+ desc: Remove um item da lista de uma coluna localmente, sem realizar nenhuma requisição. Também decrementa o contador de paginação.
252
+ params:
253
+ headerKey:
254
+ desc: Chave identificadora da coluna de origem (valor correspondente à prop `column-id-key`).
255
+ type: String | Number
256
+ required: true
257
+ itemId:
258
+ desc: ID do item a ser removido (valor correspondente à prop `item-id-key`).
259
+ type: String | Number
260
+ required: true
261
+
262
+ 'updateItemInList: ({ headerKey, itemId, updatedItem }) => void':
263
+ desc: Substitui os dados de um item existente em uma coluna localmente, sem realizar nenhuma requisição.
264
+ params:
265
+ headerKey:
266
+ desc: Chave identificadora da coluna (valor correspondente à prop `column-id-key`).
267
+ type: String | Number
268
+ required: true
269
+ itemId:
270
+ desc: ID do item a ser atualizado (valor correspondente à prop `item-id-key`).
271
+ type: String | Number
272
+ required: true
273
+ updatedItem:
274
+ desc: Dados atualizados que substituirão o item original.
275
+ type: Object
276
+ required: true
277
+
278
+ 'refetchColumns: () => void':
279
+ desc: Alias de `fetchColumns`. Busca novamente todas as colunas com base nos headers fornecidos.
280
+
281
+ 'transferItemToColumn: ({ itemId, fromColumnId, toColumnId, updatedItem? }) => void':
282
+ desc: |
283
+ Transfere um item de uma coluna para outra localmente, sem realizar nenhuma requisição.
284
+ O item é sempre inserido como primeiro elemento na coluna de destino.
285
+ Após a transferência, o SortableJS continua funcionando normalmente sobre os elementos do DOM atualizados pelo Vue.
286
+ params:
287
+ itemId:
288
+ desc: ID do item a ser movido (valor correspondente à prop `item-id-key`).
289
+ type: String | Number
290
+ required: true
291
+ fromColumnId:
292
+ desc: ID da coluna de origem (valor correspondente à prop `column-id-key`).
293
+ type: String | Number
294
+ required: true
295
+ toColumnId:
296
+ desc: ID da coluna de destino (valor correspondente à prop `column-id-key`).
297
+ type: String | Number
298
+ required: true
299
+ updatedItem:
300
+ desc: Dados atualizados do item. Quando informado, sobrescreve o item original na coluna de destino.
301
+ type: Object
302
+ required: false
@@ -0,0 +1,25 @@
1
+ <template>
2
+ <div ref="columnContainer">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+ import setScrollGradient from '../../../helpers/set-scroll-gradient'
9
+
10
+ import { ref, onMounted, onBeforeUnmount } from 'vue'
11
+
12
+ defineOptions({ name: 'PvBoardGeneratorCardsContainer' })
13
+
14
+ // refs
15
+ const columnContainer = ref(null)
16
+
17
+ // consts
18
+ const { initializeScrollGradient, removeScrollGradient } = setScrollGradient({
19
+ styles: { gradientLevel: 2 }
20
+ })
21
+
22
+ // hooks
23
+ onMounted(() => initializeScrollGradient(columnContainer.value))
24
+ onBeforeUnmount(() => removeScrollGradient(columnContainer.value))
25
+ </script>
@@ -1,14 +1,20 @@
1
1
  <template>
2
- <div class="bg-white rounded-borders" :class="boxClasses">
3
- <slot />
2
+ <div class="bg-white qas-box rounded-borders" :class="boxClasses">
3
+ <div ref="content" class="relative-position">
4
+ <slot />
5
+
6
+ <qas-skeleton v-if="props.skeleton" use-overlay />
7
+ </div>
4
8
  </div>
5
9
  </template>
6
10
 
7
11
  <script setup>
12
+ import QasSkeleton from '../skeleton/QasSkeleton.vue'
13
+
8
14
  import { Spacing } from '../../enums/Spacing'
9
15
  import { useOverlayNavigation } from '../../composables'
10
16
 
11
- import { computed, provide } from 'vue'
17
+ import { computed, provide, ref } from 'vue'
12
18
 
13
19
  defineOptions({ name: 'QasBox' })
14
20
 
@@ -23,6 +29,10 @@ const props = defineProps({
23
29
  default: undefined
24
30
  },
25
31
 
32
+ skeleton: {
33
+ type: Boolean
34
+ },
35
+
26
36
  spacingX: {
27
37
  default: Spacing.Md,
28
38
  type: String,
@@ -47,6 +57,9 @@ provide('isBox', true)
47
57
  // composables
48
58
  const { isOverlay } = useOverlayNavigation()
49
59
 
60
+ // template refs
61
+ const content = ref(null)
62
+
50
63
  // computed
51
64
  const defaultOutlined = computed(() => props.outlined ?? isOverlay)
52
65
  const defaultUnelevated = computed(() => props.unelevated ?? isOverlay)
@@ -12,6 +12,11 @@ props:
12
12
  desc: Remove a sombra do componente.
13
13
  type: Boolean
14
14
 
15
+ skeleton:
16
+ desc: Exibe um esqueleto de carregamento no lugar do conteúdo.
17
+ default: false
18
+ type: Boolean
19
+
15
20
  spacing-x:
16
21
  desc: Espaçamento horizontal do componente.
17
22
  type: String
@@ -27,3 +32,8 @@ props:
27
32
  use-spacing:
28
33
  desc: Controla espaçamento do componente.
29
34
  type: Boolean
35
+
36
+ provide:
37
+ is-box:
38
+ desc: Identificador booleano que indica quando um componente está dentro do contexto de um QasBox.
39
+ type: Boolean
@@ -10,7 +10,7 @@
10
10
 
11
11
  <q-icon v-if="hasIcon" :class="iconClasses" :name="props.icon" />
12
12
 
13
- <div v-if="showLabel" :class="labelClasses">
13
+ <div v-if="showLabel" class="qas-btn__label" :class="labelClasses">
14
14
  {{ props.label }}
15
15
  </div>
16
16
 
@@ -22,10 +22,13 @@
22
22
  <slot />
23
23
 
24
24
  <qas-tooltip v-if="hasTooltip" :text="tooltipText" />
25
+
26
+ <qas-skeleton v-if="props.skeleton" use-contrast use-overlay />
25
27
  </q-btn>
26
28
  </template>
27
29
 
28
30
  <script setup>
31
+ import QasSkeleton from '../skeleton/QasSkeleton.vue'
29
32
  import QasTooltip from '../tooltip/QasTooltip.vue'
30
33
 
31
34
  import { useScreen } from '../../composables'
@@ -83,6 +86,10 @@ const props = defineProps({
83
86
  type: Boolean
84
87
  },
85
88
 
89
+ skeleton: {
90
+ type: Boolean
91
+ },
92
+
86
93
  variant: {
87
94
  default: undefined,
88
95
  type: String,
@@ -105,12 +112,17 @@ const props = defineProps({
105
112
  useHoverOnWhiteColor: {
106
113
  default: true,
107
114
  type: Boolean
115
+ },
116
+
117
+ useMagicAiColor: {
118
+ type: Boolean
108
119
  }
109
120
  })
110
121
 
111
122
  // globals
112
123
  const injectedDefaults = inject('btnPropsDefaults', {}) // Inject reativo ou não reativo com fallback vazio
113
124
  const isInsideBox = inject('isBox', false)
125
+ const isInsideHeader = inject('isHeader', false)
114
126
 
115
127
  // composables
116
128
  const attrs = useAttrs()
@@ -121,9 +133,10 @@ const screen = useScreen()
121
133
  /**
122
134
  * Seta os valores padrões, dando prioridade:
123
135
  * 1. Props
124
- * 2. Injetado (pode ser reativo ou não reativo)
125
- * 3. Caso esteja dentro do QasBox, seta o size para 'sm' se for primary ou secondary.
126
- * 4. Hardcoded (tertiary, md, primary)
136
+ * 2. Caso esteja dentro do QasHeader, seta o size para 'lg'.
137
+ * 3. Injetado (pode ser reativo ou não reativo)
138
+ * 4. Caso esteja dentro do QasBox, seta o size para 'sm' se for primary ou secondary.
139
+ * 5. Hardcoded (tertiary, lg, primary)
127
140
  */
128
141
  const btnPropsDefaults = computed(() => {
129
142
  const defaultProps = isRef(injectedDefaults) ? injectedDefaults.value : injectedDefaults
@@ -134,7 +147,10 @@ const btnPropsDefaults = computed(() => {
134
147
  size: isInsideBox && isSmallVariant ? 'sm' : 'lg',
135
148
  variant: 'tertiary',
136
149
  color: 'primary',
137
- ...defaultProps
150
+ ...defaultProps,
151
+
152
+ // Header tem prioridade sobre o injetado
153
+ ...(isInsideHeader && { size: 'lg' })
138
154
  }
139
155
  })
140
156
 
@@ -177,6 +193,9 @@ const classes = computed(() => {
177
193
  'qas-btn--secondary': isSecondary.value,
178
194
  'qas-btn--tertiary': isTertiary.value,
179
195
 
196
+ // skeleton
197
+ 'overflow-hidden': props.skeleton,
198
+
180
199
  // color
181
200
  [`qas-btn--tertiary-${defaultColor.value}`]: isTertiary.value,
182
201
  [`qas-btn--primary-${defaultColor.value}`]: isPrimary.value,
@@ -194,6 +213,9 @@ const classes = computed(() => {
194
213
  // loading
195
214
  'qas-btn--loading': props.loading,
196
215
 
216
+ // magic ai
217
+ 'qas-btn--magic-ai': props.useMagicAiColor,
218
+
197
219
  // ellipsis
198
220
  'full-width': props.useEllipsis
199
221
  }
@@ -30,6 +30,11 @@ props:
30
30
  desc: Ícone a direita.
31
31
  type: String
32
32
 
33
+ skeleton:
34
+ desc: Exibe um esqueleto de carregamento no lugar do conteúdo.
35
+ default: false
36
+ type: Boolean
37
+
33
38
  size:
34
39
  desc: Tamanho do botão, podendo ser "sm", "md" ou "lg".
35
40
  default: lg
@@ -51,7 +56,6 @@ props:
51
56
  default: true
52
57
  type: Boolean
53
58
 
54
-
55
59
  label:
56
60
  desc: Rótulo do botão.
57
61
  type: String
@@ -60,6 +64,11 @@ props:
60
64
  desc: Texto do tooltip que aparecerá ao passar o mouse sobre o botão.
61
65
  type: String
62
66
 
67
+ use-magic-ai-color:
68
+ desc: Aplica o estilo de cores de inteligência artificial (magic AI) ao botão, usando um gradiente como cor principal. O comportamento varia conforme a variante do botão. Na variante "primary", o gradiente substitui a cor de fundo. Na "secondary", o gradiente é aplicado na cor do texto e na borda. Na "tertiary", o gradiente é aplicado apenas na cor do texto. O hover em todas as variantes utiliza a cor "$secondary-contrast".
69
+ default: false
70
+ type: Boolean
71
+
63
72
  variant:
64
73
  desc: Variantes do botão, que define para qual comportamento o botão será usado, podendo ser "primary", "secondary" ou "tertiary".
65
74
  default: tertiary
@@ -3,7 +3,7 @@
3
3
  <div v-if="hasButtons" :class="classes.list">
4
4
  <div v-for="(buttonProps, key, index) in props.buttonsPropsList" :key="key">
5
5
  <div class="flex no-wrap">
6
- <qas-btn v-bind="buttonProps" :data-btn-dropdown="key" :disable="props.disable" no-wrap variant="tertiary" @click="onClick">
6
+ <qas-btn :data-btn-dropdown="key" :disable="props.disable" v-bind="getButtonProps(buttonProps)" no-wrap variant="tertiary" @click="onClick">
7
7
  <slot v-if="hasBtnContentSlot(key)" :name="`btn-content-${key}`" />
8
8
 
9
9
  <q-menu v-else-if="hasMenuOnLeftSide" v-model="isMenuOpened" anchor="bottom right" :auto-close="props.useAutoClose" class="qas-menu" self="top right" @update:model-value="onUpdateMenuValue">
@@ -63,6 +63,10 @@ const props = defineProps({
63
63
  type: Boolean
64
64
  },
65
65
 
66
+ skeleton: {
67
+ type: Boolean
68
+ },
69
+
66
70
  useMenuPadding: {
67
71
  type: Boolean
68
72
  },
@@ -117,6 +121,7 @@ const splittedButtonProps = computed(() => {
117
121
 
118
122
  return {
119
123
  color: 'grey-10',
124
+ skeleton: props.skeleton,
120
125
  disable: props.disable,
121
126
  [iconKey]: props.dropdownIcon,
122
127
  variant: 'tertiary',
@@ -148,6 +153,13 @@ function hasSeparator (index) {
148
153
  function hasBtnContentSlot (name) {
149
154
  return !!slots[`btn-content-${name}`]
150
155
  }
156
+
157
+ function getButtonProps (buttonProps) {
158
+ return {
159
+ ...buttonProps,
160
+ skeleton: buttonProps.skeleton || props.skeleton
161
+ }
162
+ }
151
163
  </script>
152
164
 
153
165
  <style lang="scss">
@@ -4,38 +4,62 @@
4
4
  <q-card class="column full-height overflow-hidden shadow-0">
5
5
  <header v-if="hasHeader" class="full-width items-center justify-between no-wrap q-mb-sm row">
6
6
  <slot name="header">
7
- <div class="ellipsis flex no-wrap">
7
+ <div class="ellipsis flex full-width no-wrap">
8
8
  <slot v-if="props.useSelection" name="header-left">
9
- <qas-checkbox v-model="selected" :false-value="props.falseValue" :true-value="props.trueValue" />
9
+ <qas-skeleton v-if="props.skeleton" class="q-mr-sm" type="QasCheckbox" />
10
+
11
+ <qas-checkbox v-else v-model="selected" :false-value="props.falseValue" :true-value="props.trueValue" />
10
12
  </slot>
11
13
 
12
- <component :is="titleComponent.is" class="ellipsis text-h5 text-no-decoration" v-bind="titleComponent.props">
13
- <slot name="title">
14
- {{ props.title }}
15
- </slot>
14
+ <component :is="titleComponent.is" class="ellipsis full-width text-h5 text-no-decoration" v-bind="titleComponent.props">
15
+ <qas-skeleton v-if="props.skeleton" type="text" use-contrast />
16
+
17
+ <span v-else>
18
+ <slot name="title">
19
+ {{ props.title }}
20
+ </slot>
16
21
 
17
- <qas-tooltip v-if="props.tooltip" :text="props.tooltip" />
22
+ <qas-tooltip v-if="props.tooltip" :text="props.tooltip" />
23
+ </span>
18
24
  </component>
19
25
  </div>
20
26
 
21
- <qas-actions-menu v-if="hasActions" v-bind="formattedActionsMenuProps" />
27
+ <div v-if="hasActions">
28
+ <qas-skeleton v-if="props.skeleton" class="q-ml-sm" type="QasBtn" width="24px" />
29
+
30
+ <qas-actions-menu v-else v-bind="formattedActionsMenuProps" />
31
+ </div>
22
32
  </slot>
23
33
  </header>
24
34
 
25
- <div class="qas-card__content" :class="contentClasses">
26
- <slot name="default" />
35
+ <div class="qas-card__content relative-position" :class="contentClasses">
36
+ <qas-skeleton v-if="props.skeleton" height="100px" />
37
+
38
+ <slot v-else name="default" />
27
39
  </div>
28
40
 
29
- <div class="q-mt-auto">
30
- <q-separator v-if="hasFooter" class="q-mb-sm" />
41
+ <div class="full-width q-mt-auto">
42
+ <q-separator v-if="hasFooter" />
31
43
 
32
- <slot name="footer">
33
- <q-expansion-item v-if="hasExpansion" class="full-width" dense expand-icon-class="text-primary" header-class="q-pa-none text-primary" :label="props.expansionProps.label">
34
- <slot name="expansion-content">
35
- {{ props.expansionProps.content }}
36
- </slot>
37
- </q-expansion-item>
38
- </slot>
44
+ <div v-if="hasExpansion">
45
+ <div v-if="props.skeleton" class="flex justify-between q-mt-sm">
46
+ <qas-skeleton type="text" use-contrast width="150px" />
47
+
48
+ <qas-skeleton size="24px" type="QasBtn" />
49
+ </div>
50
+
51
+ <slot v-else name="footer">
52
+ <q-expansion-item v-if="hasExpansion" class="full-width" dense expand-icon-class="text-grey-10" header-class="qas-card__expansion-header q-mt-sm q-pa-none" :label="props.expansionProps.label">
53
+ <div class="q-mt-xs">
54
+ <q-separator vertical />
55
+
56
+ <slot name="expansion-content">
57
+ {{ props.expansionProps.content }}
58
+ </slot>
59
+ </div>
60
+ </q-expansion-item>
61
+ </slot>
62
+ </div>
39
63
  </div>
40
64
  </q-card>
41
65
  </qas-box>
@@ -43,10 +67,12 @@
43
67
  </template>
44
68
 
45
69
  <script setup>
70
+ import QasRouterLink from '../router-link/QasRouterLink.vue'
46
71
  import QasTooltip from '../tooltip/QasTooltip.vue'
47
72
  import QasActionsMenu from '../actions-menu/QasActionsMenu.vue'
48
73
  import QasCheckbox from '../checkbox/QasCheckbox.vue'
49
74
  import QasBox from '../box/QasBox.vue'
75
+ import QasSkeleton from '../skeleton/QasSkeleton.vue'
50
76
 
51
77
  import { computed, useSlots, inject } from 'vue'
52
78
  import { colors } from 'quasar'
@@ -69,6 +95,15 @@ const props = defineProps({
69
95
  default: false
70
96
  },
71
97
 
98
+ gradientStatusColor: {
99
+ type: String,
100
+ default: ''
101
+ },
102
+
103
+ skeleton: {
104
+ type: Boolean
105
+ },
106
+
72
107
  route: {
73
108
  type: Object,
74
109
  default: () => ({})
@@ -94,6 +129,10 @@ const props = defineProps({
94
129
  default: true
95
130
  },
96
131
 
132
+ useOverlayRoute: {
133
+ type: Boolean
134
+ },
135
+
97
136
  useSelection: {
98
137
  type: Boolean
99
138
  }
@@ -135,14 +174,16 @@ const contentClasses = computed(() => hasFooter.value && 'q-mb-sm')
135
174
  const boxClasses = computed(() => props.statusColor ? 'rounded-borders-right' : 'rounded-borders')
136
175
 
137
176
  const titleComponent = computed(() => {
138
- const hasRoute = !!Object.keys(props.route).length
177
+ const hasRoute = !!Object.keys(props.route).length && !props.skeleton
139
178
 
140
179
  return {
141
- is: hasRoute ? 'router-link' : 'h5',
180
+ is: hasRoute ? QasRouterLink : 'h5',
181
+
142
182
  props: {
143
183
  ...(hasRoute && {
144
- to: props.route,
145
- class: 'qas-card__router'
184
+ route: props.route,
185
+ useOverlayRoute: props.useOverlayRoute,
186
+ title: props.title
146
187
  })
147
188
  }
148
189
  }
@@ -153,8 +194,14 @@ const style = computed(() => {
153
194
 
154
195
  const { getPaletteColor } = colors
155
196
 
197
+ const palletColor = getPaletteColor(props.statusColor)
198
+
156
199
  return {
157
- borderLeft: `4px solid ${getPaletteColor(props.statusColor)} !important`
200
+ backgroundImage: props.gradientStatusColor
201
+ ? `linear-gradient(270deg, ${props.gradientStatusColor} 0%, #FFFFFF 60%) !important`
202
+ : undefined,
203
+
204
+ borderLeft: `4px solid ${palletColor} !important`
158
205
  }
159
206
  })
160
207
 
@@ -179,13 +226,38 @@ const formattedActionsMenuProps = computed(() => {
179
226
 
180
227
  <style lang="scss">
181
228
  .qas-card {
229
+ // $
230
+
182
231
  &__content {
183
232
  max-width: 100%;
184
233
  }
185
234
 
186
- &__router {
235
+ .q-card {
236
+ background-color: transparent;
237
+ }
238
+
239
+ &__expansion-header {
240
+ transition: color var(--qas-generic-transition);
241
+
242
+ &.q-item {
243
+ min-height: auto !important;
244
+ }
245
+
246
+ // pega apenas o primeiro .q-item__label
247
+ .q-item__label:first-of-type {
248
+ @include set-typography($h6);
249
+ }
250
+
251
+ .q-expansion-item__toggle-icon {
252
+ font-size: 20px;
253
+ }
254
+
187
255
  &:hover {
188
256
  color: $primary;
257
+
258
+ .q-expansion-item__toggle-icon {
259
+ color: $primary;
260
+ }
189
261
  }
190
262
  }
191
263
  }
@@ -19,11 +19,21 @@ props:
19
19
  default: false
20
20
  type: [Boolean, String, Number, Array, Object]
21
21
 
22
+ skeleton:
23
+ desc: Exibe um esqueleto de carregamento no lugar do conteúdo.
24
+ default: false
25
+ type: Boolean
26
+
22
27
  route:
23
28
  desc: Rota que será utilizada ao clicar no título.
24
29
  default: {}
25
30
  type: Object
26
31
 
32
+ use-overlay-route:
33
+ desc: Quando verdadeiro, o clique no título abre a rota no overlay em vez de navegar normalmente. Ao abrir em uma nova guia, o comportamento padrão do `router-link` é mantido.
34
+ default: false
35
+ type: Boolean
36
+
27
37
  status-color:
28
38
  desc: Insere uma borda na esquerda para indicar o status do card.
29
39
  default: ''
@@ -15,11 +15,15 @@
15
15
  <slot name="carousel-header" />
16
16
  </div>
17
17
  </slot>
18
+
19
+ <qas-skeleton v-if="props.skeleton" use-overlay />
18
20
  </header>
19
21
 
20
22
  <q-card-section class="col-grow column full-width justify-between">
21
- <div class="full-width" :class="gutterClass">
23
+ <div class="full-width relative-position" :class="gutterClass">
22
24
  <slot />
25
+
26
+ <qas-skeleton v-if="props.skeleton" use-overlay />
23
27
  </div>
24
28
  </q-card-section>
25
29
 
@@ -31,6 +35,7 @@
31
35
  </template>
32
36
 
33
37
  <script setup>
38
+ import QasSkeleton from '../skeleton/QasSkeleton.vue'
34
39
  import QasBtn from '../btn/QasBtn.vue'
35
40
 
36
41
  import { Spacing } from '../../enums/Spacing'
@@ -64,6 +69,10 @@ const props = defineProps({
64
69
  type: Boolean
65
70
  },
66
71
 
72
+ skeleton: {
73
+ type: Boolean
74
+ },
75
+
67
76
  useHeader: {
68
77
  type: Boolean
69
78
  }
@@ -24,6 +24,11 @@ props:
24
24
  desc: Insere uma borda sólida em volta do componente.
25
25
  type: Boolean
26
26
 
27
+ skeleton:
28
+ desc: Exibe um esqueleto de carregamento no lugar do conteúdo.
29
+ default: false
30
+ type: Boolean
31
+
27
32
  unelevated:
28
33
  desc: Remove a sombra do componente.
29
34
  type: Boolean
@@ -15,14 +15,13 @@
15
15
  </slot>
16
16
  </div>
17
17
 
18
- <q-inner-loading :showing="isFetching">
19
- <q-spinner color="grey" size="3em" />
20
- </q-inner-loading>
18
+ <qas-skeleton v-if="isFetching" use-overlay />
21
19
  </div>
22
20
  </component>
23
21
  </template>
24
22
 
25
23
  <script>
24
+ import QasSkeleton from '../skeleton/QasSkeleton.vue'
26
25
  import QasBox from '../box/QasBox.vue'
27
26
  import QasEmptyResultText from '../empty-result-text/QasEmptyResultText.vue'
28
27
  import QasFilters from '../filters/QasFilters.vue'
@@ -74,6 +73,7 @@ export default {
74
73
  QasBox,
75
74
  QasEmptyResultText,
76
75
  QasFilters,
76
+ QasSkeleton,
77
77
  QasHeader
78
78
  },
79
79
 
@@ -339,6 +339,7 @@ export default {
339
339
  return {
340
340
  alignColumns: 'end',
341
341
  description: this.subtitle,
342
+ skeleton: this.isFetching,
342
343
  labelProps: {
343
344
  label: this.title
344
345
  }