@inriver/inri 1.0.0

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 (114) hide show
  1. package/.eslintrc.js +5 -0
  2. package/componentProperties.d.ts +8 -0
  3. package/configs/base-eslint-config.js +36 -0
  4. package/configs/base-tailwind-config.js +149 -0
  5. package/i18n.ts +11 -0
  6. package/index.ts +25 -0
  7. package/package.json +36 -0
  8. package/src/components/CAutoBreadcrumbs.vue +72 -0
  9. package/src/components/CBtn.vue +98 -0
  10. package/src/components/CColorPicker.vue +55 -0
  11. package/src/components/CContextMenu.vue +29 -0
  12. package/src/components/CDatePicker.vue +51 -0
  13. package/src/components/CDeleteTileBtn.vue +52 -0
  14. package/src/components/CDialog.vue +253 -0
  15. package/src/components/CDialogCloseBtn.vue +9 -0
  16. package/src/components/CDirtyCheck.vue +68 -0
  17. package/src/components/CDrawer.vue +44 -0
  18. package/src/components/CDrawerButton.vue +91 -0
  19. package/src/components/CExpansionItem.vue +57 -0
  20. package/src/components/CExpansionItemWithCheckbox.vue +41 -0
  21. package/src/components/CFileDropzone.vue +114 -0
  22. package/src/components/CGrid.vue +101 -0
  23. package/src/components/CHeader.vue +10 -0
  24. package/src/components/CHeaderLinks.vue +61 -0
  25. package/src/components/CHeaderMenuLink.vue +51 -0
  26. package/src/components/CHeaderSearch.vue +142 -0
  27. package/src/components/CIconBtn.vue +70 -0
  28. package/src/components/CMenuItem.vue +66 -0
  29. package/src/components/CPageContainer.vue +11 -0
  30. package/src/components/CPageError.vue +24 -0
  31. package/src/components/CPageSpinner.vue +18 -0
  32. package/src/components/CSearch.vue +45 -0
  33. package/src/components/CSection.vue +29 -0
  34. package/src/components/CSectionTitle.vue +8 -0
  35. package/src/components/CSelect.vue +208 -0
  36. package/src/components/CSlideEffect.vue +62 -0
  37. package/src/components/CSpinner.vue +107 -0
  38. package/src/components/CTableActions.vue +16 -0
  39. package/src/components/CTileBtn.vue +178 -0
  40. package/src/components/CTimePicker.vue +42 -0
  41. package/src/components/CToggleGridView.vue +26 -0
  42. package/src/components/CToggleSidebarBtn.vue +19 -0
  43. package/src/components/CTooltip.vue +44 -0
  44. package/src/components/CTreeNode.vue +39 -0
  45. package/src/components/cards/CBannerCard.vue +103 -0
  46. package/src/components/cards/CSmallCard.vue +149 -0
  47. package/src/components/internal-components/ConfirmDialog.vue +78 -0
  48. package/src/composables/useDialog.ts +47 -0
  49. package/src/composables/useDirtyCheck.ts +25 -0
  50. package/src/composables/useDoubleClickListener.ts +28 -0
  51. package/src/composables/useSelectable.ts +62 -0
  52. package/src/composables/useTruncateChips.ts +46 -0
  53. package/src/i18n/de/index.ts +17 -0
  54. package/src/i18n/en/index.ts +84 -0
  55. package/src/i18n/es/index.ts +7 -0
  56. package/src/i18n/fr/index.ts +7 -0
  57. package/src/init/initInriFramework.ts +25 -0
  58. package/src/init/useInriApp.ts +55 -0
  59. package/src/layouts/CLayoutBlank.vue +7 -0
  60. package/src/layouts/CLayoutWithBackButton.vue +50 -0
  61. package/src/layouts/CLayoutWithSidebars.vue +46 -0
  62. package/src/layouts/layout-fragments/CPageAutoBreadcrumbs.vue +6 -0
  63. package/src/layouts/layout-fragments/CPageBackButton.vue +18 -0
  64. package/src/layouts/layout-fragments/CPageBlank.vue +20 -0
  65. package/src/layouts/layout-fragments/CPageFlexCol.vue +5 -0
  66. package/src/layouts/layout-fragments/CPageLeftSidebar.vue +5 -0
  67. package/src/layouts/layout-fragments/CPageMainContent.vue +5 -0
  68. package/src/layouts/layout-fragments/CPageOuterWrapper.vue +5 -0
  69. package/src/layouts/layout-fragments/CPageRightSidebar.vue +5 -0
  70. package/src/layouts/layout-fragments/CPageTitle.vue +34 -0
  71. package/src/plugins/dialog.ts +45 -0
  72. package/src/plugins/errors/ErrorFactories.ts +59 -0
  73. package/src/plugins/errors/Errors.ts +156 -0
  74. package/src/plugins/errors/Exception.ts +6 -0
  75. package/src/plugins/errors/globalErrorHandler.ts +21 -0
  76. package/src/plugins/errors/handleError.ts +34 -0
  77. package/src/plugins/errors/logger.ts +16 -0
  78. package/src/plugins/errors/vueErrorHandler.ts +26 -0
  79. package/src/plugins/globalAppConfig.ts +25 -0
  80. package/src/plugins/i18n.ts +46 -0
  81. package/src/plugins/inriIcons.ts +58 -0
  82. package/src/plugins/inriverQuasarComponentConfigurations.ts +67 -0
  83. package/src/plugins/library.ts +119 -0
  84. package/src/plugins/notify.ts +153 -0
  85. package/src/plugins/quasar-user-options.ts +19 -0
  86. package/src/plugins/validationRules.ts +292 -0
  87. package/src/shims-vue.d.ts +6 -0
  88. package/src/stores/inriStore.ts +54 -0
  89. package/src/stores/interfaceLanguageStore.ts +27 -0
  90. package/src/styles/_css-variables.scss +101 -0
  91. package/src/styles/_reset.scss +67 -0
  92. package/src/styles/_transitions.scss +9 -0
  93. package/src/styles/_utils.scss +15 -0
  94. package/src/styles/components/_breadcrumbs.scss +3 -0
  95. package/src/styles/components/_checkboxes.scss +17 -0
  96. package/src/styles/components/_chips.scss +17 -0
  97. package/src/styles/components/_forms.scss +203 -0
  98. package/src/styles/components/_menu.scss +12 -0
  99. package/src/styles/components/_notifications.scss +24 -0
  100. package/src/styles/components/_q-editor.scss +14 -0
  101. package/src/styles/components/_radio-buttons.scss +17 -0
  102. package/src/styles/components/_tables.scss +92 -0
  103. package/src/styles/components/_tooltips.scss +5 -0
  104. package/src/styles/components/_tree.scss +86 -0
  105. package/src/styles/components/_truncated-chips.scss +39 -0
  106. package/src/styles/main.scss +45 -0
  107. package/src/styles/quasar.variables.scss +50 -0
  108. package/src/typings.d.ts +70 -0
  109. package/src/utils/colorUtils.ts +73 -0
  110. package/src/utils/errorUtils.ts +37 -0
  111. package/src/utils/fileUtils.ts +57 -0
  112. package/src/utils/helpers.ts +6 -0
  113. package/src/utils/routeUtils.ts +23 -0
  114. package/tsconfig.json +37 -0
@@ -0,0 +1,208 @@
1
+ <template>
2
+ <q-select
3
+ ref="selectRef"
4
+ class="c-select"
5
+ :model-value="modelValue"
6
+ v-bind="dense ? $inri.inputDense : $inri.input"
7
+ :options="internalOptions"
8
+ :multiple="multiple"
9
+ :use-input="dense || useInput"
10
+ :placeholder="selectedPlaceholder"
11
+ :hide-selected="dense"
12
+ :emit-value="emitValue"
13
+ :option-label="optionLabel"
14
+ :option-value="optionValue"
15
+ clear-icon="mdi-close"
16
+ @blur="clearInputValue"
17
+ @filter="filter"
18
+ @update:model-value="onModelUpdate"
19
+ >
20
+ <template #no-option>
21
+ <q-item>
22
+ <q-item-section>
23
+ {{ $t('inri.select.no_results') }}
24
+ </q-item-section>
25
+ </q-item>
26
+ </template>
27
+
28
+ <!-- select all-->
29
+ <template
30
+ v-if="multiple"
31
+ #before-options
32
+ >
33
+ <q-item>
34
+ <q-item-section>
35
+ <q-checkbox
36
+ :model-value="allSelectedStatus"
37
+ v-bind="$inri.checkbox"
38
+ :label="$t('inri.select.select_all')"
39
+ tabindex="-1"
40
+ @click="onToggleAll"
41
+ />
42
+ </q-item-section>
43
+ </q-item>
44
+ </template>
45
+
46
+ <!-- list item-->
47
+ <template #option="{ itemProps, opt, selected, toggleOption }">
48
+ <!-- multi -->
49
+ <q-item
50
+ v-if="multiple"
51
+ v-bind="itemProps"
52
+ >
53
+ <q-item-section>
54
+ <q-checkbox
55
+ :model-value="selected"
56
+ v-bind="$inri.checkbox"
57
+ :label="getOptionLabel(opt)"
58
+ tabindex="-1"
59
+ @click="toggleOption(opt)"
60
+ />
61
+ </q-item-section>
62
+ </q-item>
63
+
64
+ <!-- single -->
65
+ <q-item
66
+ v-else
67
+ v-bind="itemProps"
68
+ >
69
+ <q-item-section>
70
+ {{ getOptionLabel(opt) }}
71
+ </q-item-section>
72
+ </q-item>
73
+ </template>
74
+ </q-select>
75
+ </template>
76
+
77
+ <script setup lang="ts">
78
+ import { computed, ref, toRef, useAttrs } from 'vue'
79
+ import { QSelect } from 'quasar'
80
+ import useSelectable from '../composables/useSelectable'
81
+
82
+ const emit = defineEmits(['update:modelValue'])
83
+ const attrs = useAttrs()
84
+
85
+ defineExpose({
86
+ clearInputValue,
87
+ })
88
+
89
+ const props = defineProps({
90
+ modelValue: {
91
+ type: [Object, String, Number, Boolean, Array],
92
+ default: undefined,
93
+ },
94
+ options: {
95
+ type: Array,
96
+ default: () => [],
97
+ },
98
+ multiple: Boolean,
99
+ dense: Boolean,
100
+ useInput: Boolean,
101
+ emitValue: Boolean,
102
+ optionLabel: {
103
+ type: String,
104
+ default: 'label',
105
+ },
106
+ optionValue: {
107
+ type: String,
108
+ default: 'value',
109
+ },
110
+ placeholder: {
111
+ type: String,
112
+ default: undefined,
113
+ },
114
+ })
115
+
116
+ // State etc.
117
+ const internalOptions = ref(props.options)
118
+ const selectRef = ref<QSelect>()
119
+ const { allSelectedStatus, toggleAllItemsWithEmit } = useSelectable(toRef(props, 'options'), toRef(props, 'modelValue'))
120
+
121
+ const selectedPlaceholder = computed(() => {
122
+ if (props.dense) {
123
+ const placeholder = props.placeholder || ''
124
+
125
+ if (!props.multiple) {
126
+ return props.modelValue ? getOptionLabel(props.modelValue) : placeholder
127
+ } else {
128
+ return Array.isArray(props.modelValue) && props.modelValue?.length ? `${placeholder} (${props.modelValue.length})` : placeholder
129
+ }
130
+ }
131
+
132
+ return props.placeholder
133
+ })
134
+
135
+ function getOptionLabel (opt) {
136
+ return opt[props.optionLabel] || opt
137
+ }
138
+
139
+ function filter (val, update) {
140
+ update(
141
+ () => {
142
+ const lowerCaseValue = val?.toLowerCase()
143
+ internalOptions.value = props.options.filter(option => getOptionLabel(option).toLowerCase().indexOf(lowerCaseValue) > -1)
144
+ },
145
+
146
+ // "ref" is the Vue reference to the QSelect
147
+ ref => {
148
+ if (val !== '' && ref.options.length > 0) {
149
+ // Reset optionIndex in case there is something selected
150
+ ref.setOptionIndex(-1)
151
+
152
+ // If it is possible to add new values then only try to focus on an exact match.
153
+ // If we can't add new values then always focus on the first item.
154
+ if (attrs.onNewValue) {
155
+ // Try to find a matched item.
156
+ const lowerCaseValue = val?.toLowerCase()
157
+ const optionsIndex = ref.options.findIndex(option => getOptionLabel(option).toLowerCase() === lowerCaseValue)
158
+
159
+ // If there is no exact match (casing excluded) then don't set focus.
160
+ // This is to allow adding new items, or it'll just toggle the focused item which can make it impossible to add new values.
161
+ if (optionsIndex > -1) {
162
+ // The q-select options starts at index 1.
163
+ ref.moveOptionSelection(optionsIndex + 1, true)
164
+ }
165
+ } else {
166
+ // The q-select options starts at index 1.
167
+ ref.moveOptionSelection(1, true)
168
+ }
169
+ }
170
+ },
171
+ )
172
+ }
173
+
174
+ function clearInputValue () {
175
+ if (selectRef.value) {
176
+ selectRef.value.updateInputValue('', true)
177
+ }
178
+ }
179
+
180
+ function onModelUpdate (val) {
181
+ emit('update:modelValue', val)
182
+ }
183
+
184
+ function onToggleAll (evt, emitString) {
185
+ if (selectRef.value) {
186
+ selectRef.value.hidePopup()
187
+ }
188
+
189
+ toggleAllItemsWithEmit(evt, emitString)
190
+ }
191
+ </script>
192
+
193
+ <style lang="scss">
194
+ .c-select {
195
+ ::placeholder {
196
+ color: var(--color-text);
197
+ }
198
+
199
+ // Prevent the 'input' text from being selected when navigating the list of options
200
+ ::selection {
201
+ background: none;
202
+ }
203
+
204
+ ::-moz-selection {
205
+ background: none;
206
+ }
207
+ }
208
+ </style>
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <!-- This will be create a white background behind the slide effect to make all colors work -->
3
+
4
+ <div class="absolute overflow-hidden inset-0">
5
+ <div
6
+ class="bg-white slide-box"
7
+ :class="slideOffsetClasses"
8
+ />
9
+
10
+ <!-- Slider -->
11
+ <div
12
+ class="slide-box"
13
+ :class="[transitionBg, slideOffsetClasses]"
14
+ />
15
+ </div>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import { computed } from 'vue'
20
+ import { getRelatedColors } from '../utils/colorUtils'
21
+
22
+ const props = defineProps({
23
+ parentColor: {
24
+ type: String,
25
+ default: 'primary',
26
+ },
27
+ slideEffectColor: {
28
+ type: String,
29
+ default: undefined,
30
+ },
31
+ slideRight: {
32
+ type: Boolean,
33
+ default: false,
34
+ },
35
+ })
36
+
37
+ const slideOffsetClasses = computed(() => {
38
+ if (props.slideRight) {
39
+ return '-left-full group-hover:left-0 group-focus:left-0'
40
+ }
41
+
42
+ return '-right-full group-hover:right-0 group-focus:right-0'
43
+ })
44
+
45
+ const transitionBg = computed(() => {
46
+ // Override calculated color effect
47
+ if (props.slideEffectColor) {
48
+ return 'bg-' + props.slideEffectColor
49
+ }
50
+
51
+ const color = props.parentColor
52
+ const relatedColors = getRelatedColors(color)
53
+
54
+ return relatedColors ? 'bg-' + relatedColors.effectColor : `bg-${color} opacity-60`
55
+ })
56
+ </script>
57
+
58
+ <style scoped>
59
+ .slide-box {
60
+ @apply absolute transition-all duration-500 w-full h-full top-0;
61
+ }
62
+ </style>
@@ -0,0 +1,107 @@
1
+ <template>
2
+ <div
3
+ class="c-spinner"
4
+ :style="{
5
+ width: size + 'px',
6
+ height: size + 'px',
7
+ position: absolute ? 'absolute' : 'relative',
8
+ gridGap: gap + 'px',
9
+ }"
10
+ :class="transitionColor"
11
+ >
12
+ <div />
13
+ <div />
14
+ <div />
15
+ <div />
16
+ <div />
17
+ <div />
18
+ <div />
19
+ <div />
20
+ <div />
21
+ </div>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { computed } from 'vue'
26
+ import { getRelatedColors } from '../utils/colorUtils'
27
+
28
+ const props = defineProps({
29
+ size: {
30
+ type: [String, Number],
31
+ default: 70,
32
+ },
33
+ absolute: Boolean,
34
+ gap: {
35
+ type: [String, Number],
36
+ default: 2,
37
+ },
38
+ parentColor: {
39
+ type: String,
40
+ default: 'primary',
41
+ },
42
+ color: {
43
+ type: String,
44
+ default: undefined,
45
+ },
46
+ })
47
+
48
+ // Return fixed color or calculated color based on parent color
49
+ const transitionColor = computed(() => {
50
+ if (props.color) {
51
+ return 'text-' + props.color
52
+ }
53
+
54
+ const color = props.parentColor
55
+ const relatedColors = getRelatedColors(color)
56
+
57
+ return relatedColors ? 'text-' + relatedColors.effectColor : `text-${color} opacity-60`
58
+ })
59
+
60
+ </script>
61
+
62
+ <style lang="scss">
63
+ // Based on:
64
+ // https://codepen.io/joshuaward/pen/XejbZv
65
+
66
+ .c-spinner {
67
+ display: grid;
68
+ grid-template-columns: 1fr 1fr 1fr;
69
+
70
+ > div {
71
+ position: relative;
72
+ width: 100%;
73
+ height: 100%;
74
+ background: currentColor;
75
+ transform: scale(0);
76
+ transform-origin: center center;
77
+ animation: loader 2s infinite linear;
78
+
79
+ &:nth-of-type(1),
80
+ &:nth-of-type(5),
81
+ &:nth-of-type(9) {
82
+ animation-delay: 0.4s;
83
+ }
84
+
85
+ &:nth-of-type(4),
86
+ &:nth-of-type(8) {
87
+ animation-delay: 0.2s;
88
+ }
89
+
90
+ &:nth-of-type(2),
91
+ &:nth-of-type(6) {
92
+ animation-delay: 0.6s;
93
+ }
94
+
95
+ &:nth-of-type(3) {
96
+ animation-delay: 0.8s;
97
+ }
98
+ }
99
+ }
100
+
101
+ @keyframes loader {
102
+ 0% { transform: scale(0); }
103
+ 40% { transform: scale(1); }
104
+ 80% { transform: scale(1); }
105
+ 100% { transform: scale(0); }
106
+ }
107
+ </style>
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <q-td v-bind="$attrs">
3
+ <div class="flex flex-nowrap justify-end">
4
+ <slot />
5
+ </div>
6
+ </q-td>
7
+ </template>
8
+
9
+ <script setup lang="ts">
10
+ defineProps({
11
+ alwaysVisible: {
12
+ type: Boolean,
13
+ default: false,
14
+ },
15
+ })
16
+ </script>
@@ -0,0 +1,178 @@
1
+ <template>
2
+ <q-btn
3
+ ref="button"
4
+ class="c-tile-btn group"
5
+ :class="{
6
+ 'c-tile-btn--small': small,
7
+ 'pointer-events-none': loading
8
+ }"
9
+ unelevated
10
+ :color="color"
11
+ :to="to"
12
+ :text-color="computedTextColor"
13
+ :disable="disable"
14
+ :aria-label="tooltip || tooltipLeft || tooltipRight"
15
+ >
16
+ <c-spinner
17
+ v-if="loading"
18
+ :parent-color="color"
19
+ :size="small ? 24 : 60"
20
+ absolute
21
+ gap="0"
22
+ class="-z-1"
23
+ />
24
+
25
+ <c-slide-effect
26
+ v-if="!disable"
27
+ :parent-color="color"
28
+ :slide-effect-color="slideEffectColor"
29
+ slide-right
30
+ class="-z-1"
31
+ />
32
+
33
+ <!-- MDI or inri icon -->
34
+ <template v-if="icon">
35
+ <q-icon
36
+ :name="icon"
37
+ :style="`font-size: ${iconSize}px`"
38
+ :class="iconClass"
39
+ />
40
+ </template>
41
+
42
+ <!-- Else SVG icon (or any other content)-->
43
+ <slot />
44
+
45
+ <c-tooltip
46
+ v-if="tooltip"
47
+ :data-id="tooltipDataId"
48
+ >
49
+ {{ tooltip }}
50
+ </c-tooltip>
51
+
52
+ <c-tooltip
53
+ v-if="tooltipLeft"
54
+ :data-id="tooltipLeftDataId"
55
+ left
56
+ >
57
+ {{ tooltipLeft }}
58
+ </c-tooltip>
59
+
60
+ <c-tooltip
61
+ v-if="tooltipRight"
62
+ :data-id="tooltipRightDataId"
63
+ right
64
+ >
65
+ {{ tooltipRight }}
66
+ </c-tooltip>
67
+ </q-btn>
68
+ </template>
69
+
70
+ <script setup lang="ts">
71
+ import { QBtn } from 'quasar'
72
+ import { ref, computed } from 'vue'
73
+ import { getRelatedColors } from '../utils/colorUtils'
74
+
75
+ const props = defineProps({
76
+ color: {
77
+ type: String,
78
+ default: 'secondary',
79
+ },
80
+ textColor: {
81
+ type: String,
82
+ default: undefined,
83
+ },
84
+ slideEffectColor: {
85
+ type: String,
86
+ default: undefined,
87
+ },
88
+ to: {
89
+ type: [String, Object],
90
+ default: undefined,
91
+ },
92
+ icon: {
93
+ type: String,
94
+ default: undefined,
95
+ },
96
+ iconSize: {
97
+ type: [String, Number],
98
+ default: undefined,
99
+ },
100
+ iconClass: {
101
+ type: String,
102
+ default: undefined,
103
+ },
104
+ tooltip: {
105
+ type: String,
106
+ default: undefined,
107
+ },
108
+ tooltipLeft: {
109
+ type: String,
110
+ default: undefined,
111
+ },
112
+ tooltipRight: {
113
+ type: String,
114
+ default: undefined,
115
+ },
116
+ small: Boolean,
117
+ disable: Boolean,
118
+ loading: Boolean,
119
+ })
120
+
121
+ const button = ref<InstanceType<typeof QBtn> | null>(null)
122
+
123
+ const iconSize = computed(() => {
124
+ return props.iconSize || (props.small ? 18 : 24)
125
+ })
126
+
127
+ const computedTextColor = computed(() => {
128
+ if (props.textColor) {
129
+ return props.textColor
130
+ }
131
+
132
+ const color = props.color
133
+ const relatedColors = getRelatedColors(color)
134
+
135
+ return relatedColors ? relatedColors.onColor : 'grey-darkest'
136
+ })
137
+
138
+ const buttonDataId = computed(() => {
139
+ return button.value?.$el.dataset?.id
140
+ })
141
+
142
+ const tooltipDataId = computed(() => {
143
+ return buttonDataId.value ? `${buttonDataId.value}-tooltip` : 'tile-btn-tooltip'
144
+ })
145
+
146
+ const tooltipLeftDataId = computed(() => {
147
+ return buttonDataId.value ? `${buttonDataId.value}-tooltip-left` : 'tile-btn-tooltip-left'
148
+ })
149
+
150
+ const tooltipRightDataId = computed(() => {
151
+ return buttonDataId.value ? `${buttonDataId.value}-tooltip-right` : 'tile-btn-tooltip-right'
152
+ })
153
+
154
+ </script>
155
+
156
+ <style lang="scss">
157
+ .c-tile-btn {
158
+ padding: 0;
159
+ width: 60px;
160
+ height: 60px;
161
+ border-radius: 0;
162
+ vertical-align: top;
163
+
164
+ .q-focus-helper {
165
+ display: none;
166
+ }
167
+
168
+ &.disabled {
169
+ opacity: 0.3 !important;
170
+ }
171
+ }
172
+
173
+ .c-tile-btn--small {
174
+ min-height: 24px;
175
+ width: 24px;
176
+ height: 24px;
177
+ }
178
+ </style>
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <q-input
3
+ v-bind="dense ? $inri.inputDense : $inri.input"
4
+ :model-value="modelValue"
5
+ :label="label"
6
+ mask="time"
7
+ :rules="modelValue ? ['time'] : undefined"
8
+ @update:model-value="$emit('update:model-value', $event)"
9
+ >
10
+ <template #append>
11
+ <q-icon
12
+ name="mdi-clock-outline"
13
+ class="cursor-pointer"
14
+ color="grey-dark"
15
+ size="19px"
16
+ />
17
+ </template>
18
+ <q-menu>
19
+ <q-time
20
+ :model-value="modelValue"
21
+ format24h
22
+ @update:model-value="$emit('update:model-value', $event)"
23
+ />
24
+ </q-menu>
25
+ </q-input>
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ defineEmits(['update:model-value'])
30
+
31
+ defineProps({
32
+ modelValue: {
33
+ type: String,
34
+ default: undefined,
35
+ },
36
+ label: {
37
+ type: String,
38
+ default: undefined,
39
+ },
40
+ dense: Boolean,
41
+ })
42
+ </script>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <c-tile-btn
3
+ data-id="toggle-grid-view-btn"
4
+ :icon="icon"
5
+ :tooltip-left="modelValue ? $t('inri.toggle_actions.table_view') : $t('inri.toggle_actions.grid_view')"
6
+ @click="toggleGridView"
7
+ />
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { computed } from 'vue'
12
+
13
+ const props = defineProps({
14
+ modelValue: Boolean,
15
+ })
16
+
17
+ const emit = defineEmits(['update:modelValue'])
18
+
19
+ const icon = computed(() => {
20
+ return props.modelValue ? 'inri-table-view' : 'inri-grid-view'
21
+ })
22
+
23
+ function toggleGridView () {
24
+ emit('update:modelValue', !props.modelValue)
25
+ }
26
+ </script>
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <c-tile-btn
3
+ data-id="toggle-sidebar-btn"
4
+ :icon="icon"
5
+ :tooltip-left="$t('inri.toggle_actions.sidebar')"
6
+ @click="inriStore.toggleSidebar"
7
+ />
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { computed } from 'vue'
12
+ import { useInriStore } from '../stores/inriStore'
13
+
14
+ const inriStore = useInriStore()
15
+
16
+ const icon = computed(() => {
17
+ return inriStore.state.showSidebar ? 'mdi-fullscreen' : 'mdi-fullscreen-exit'
18
+ })
19
+ </script>
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <q-tooltip
3
+ v-bind="position"
4
+ >
5
+ <slot />
6
+ </q-tooltip>
7
+ </template>
8
+
9
+ <script setup lang="ts">
10
+ import { computed } from 'vue'
11
+
12
+ const props = defineProps({
13
+ left: Boolean,
14
+ right: Boolean,
15
+ top: Boolean,
16
+ bottom: Boolean,
17
+ })
18
+
19
+ const position = computed(() => {
20
+ if (props.left) {
21
+ return {
22
+ anchor: 'center left' as const,
23
+ self: 'center right' as const,
24
+ }
25
+ } else if (props.right) {
26
+ return {
27
+ anchor: 'center right' as const,
28
+ self: 'center left' as const,
29
+ }
30
+ } else if (props.top) {
31
+ return {
32
+ anchor: 'top middle' as const,
33
+ self: 'bottom middle' as const,
34
+ }
35
+ } else if (props.bottom) {
36
+ return {
37
+ anchor: 'bottom middle' as const,
38
+ self: 'top middle' as const,
39
+ }
40
+ }
41
+
42
+ return null
43
+ })
44
+ </script>