@it-enterprise/forcebpm-ui-kit 1.0.2-beta.21 → 1.0.2-beta.22

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.
@@ -0,0 +1,123 @@
1
+ <script setup>
2
+ // FTabPanel
3
+
4
+ defineProps({
5
+ tabs: {
6
+ type: Array,
7
+ default: () => [],
8
+ validator: value => {
9
+ const values = value.map(i => i.value)
10
+ const isUnique = new Set(values).size === values.length
11
+ return (
12
+ isUnique &&
13
+ value.every(
14
+ i =>
15
+ 'name' in i &&
16
+ typeof i.name === 'string' &&
17
+ 'value' in i &&
18
+ (typeof i.value === 'number' || typeof i.value === 'string') &&
19
+ (i.count === undefined || i.count === null || typeof i.count === 'number') &&
20
+ (i.loading === undefined || typeof i.loading === 'boolean') &&
21
+ (i.hide === undefined || typeof i.hide === 'boolean')
22
+ )
23
+ )
24
+ }
25
+ // Example:
26
+ // {
27
+ // name: String,
28
+ // value: Number | String,
29
+ // count: Number,
30
+ // loading: Boolean,
31
+ // hide: Boolean,
32
+ // }
33
+ },
34
+ slider: {
35
+ type: Boolean,
36
+ default: false
37
+ }
38
+ })
39
+
40
+ const modelValue = defineModel({
41
+ type: [Number, String],
42
+ default: 0
43
+ })
44
+ </script>
45
+
46
+ <template>
47
+ <v-tabs v-model="modelValue" :hide-slider="!slider" height="32" class="f-tab-panel" :class="{ 'is-slider': slider }">
48
+ <template v-for="t in tabs">
49
+ <v-tab v-if="!t.hide" :key="t.value" :value="t.value">
50
+ <!-- Loading -->
51
+ <v-skeleton-loader v-if="t.loading" width="120px" height="24px" class="f-skeleton-loader" :class="{ 'pt-2': !slider }" type="text" />
52
+
53
+ <!-- Tab name -->
54
+ <div v-else class="d-flex align-center justify-center f-tab-panel-name">
55
+ <FTruncate location="top" offset="6, 6" :text="t.name" />
56
+ &nbsp;
57
+ <span v-if="typeof t.count === 'number'" class="lh-11">({{ t.count }})</span>
58
+ </div>
59
+ </v-tab>
60
+ </template>
61
+ </v-tabs>
62
+ </template>
63
+
64
+ <style lang="scss" scoped>
65
+ .f-tab-panel {
66
+ position: relative;
67
+ bottom: -1px;
68
+ &.is-slider {
69
+ :deep(.v-slide-group__container) {
70
+ .v-slide-group__content {
71
+ .v-btn {
72
+ .v-btn__content {
73
+ .v-tab__slider {
74
+ height: 2px;
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ :deep(.v-slide-group__container) {
82
+ &::after {
83
+ content: none;
84
+ }
85
+ }
86
+ .f-tab-panel-name {
87
+ max-width: 320px;
88
+ }
89
+ &:not(.is-slider) {
90
+ :deep(.v-slide-group__container) {
91
+ .v-slide-group__content {
92
+ .v-tab {
93
+ border-bottom: 0 !important;
94
+ border-bottom-right-radius: 0 !important;
95
+ border-bottom-left-radius: 0 !important;
96
+ border-top-right-radius: 10.8px !important;
97
+ border-top-left-radius: 10.8px !important;
98
+ &::before {
99
+ content: '';
100
+ position: absolute;
101
+ bottom: 0;
102
+ left: 0;
103
+ width: 100%;
104
+ height: 1px;
105
+ background: rgb(var(--v-theme-line));
106
+ }
107
+ &.v-tab-item--selected {
108
+ background: rgb(var(--v-theme-fields));
109
+ border: 0.5px solid rgb(var(--v-theme-primary));
110
+ position: relative;
111
+ &::before {
112
+ content: none;
113
+ }
114
+ }
115
+ :deep(.v-btn__content) {
116
+ white-space: initial;
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ </style>
@@ -0,0 +1,131 @@
1
+ <script setup>
2
+ // FToolbar
3
+
4
+ defineProps({
5
+ tabs: {
6
+ type: Array,
7
+ default: () => []
8
+ },
9
+ viewers: {
10
+ type: Array,
11
+ default: () => []
12
+ },
13
+ config: {
14
+ type: Object,
15
+ default: () => ({
16
+ search: true,
17
+ sort: true,
18
+ filter: true,
19
+ menuFilter: false,
20
+ favorites: false
21
+ }),
22
+ validator: value => {
23
+ if (value.filter && value.menuFilter) {
24
+ console.warn('"filter" and "menuFilter" cannot both be true')
25
+ return false
26
+ }
27
+ return true
28
+ }
29
+ },
30
+ sortBadge: {
31
+ type: Boolean,
32
+ default: false
33
+ },
34
+ filterBadge: {
35
+ type: Boolean,
36
+ default: false
37
+ },
38
+ slider: {
39
+ type: Boolean,
40
+ default: false
41
+ }
42
+ })
43
+
44
+ const emit = defineEmits(['filterActivator'])
45
+
46
+ const activeTab = defineModel('activeTab', {
47
+ type: [Number, String],
48
+ default: 0
49
+ })
50
+ const activeViewer = defineModel('activeViewer', {
51
+ type: [Number, String],
52
+ default: 0
53
+ })
54
+ const search = defineModel('search', {
55
+ type: String,
56
+ default: ''
57
+ })
58
+ const filter = defineModel('filter', {
59
+ type: Boolean,
60
+ default: false
61
+ })
62
+ const sort = defineModel('sort', {
63
+ type: Boolean,
64
+ default: false
65
+ })
66
+ const favorites = defineModel('favorites', {
67
+ type: Boolean,
68
+ default: false
69
+ })
70
+ </script>
71
+
72
+ <template>
73
+ <div class="f-toolbar d-flex">
74
+ <slot name="prependActions"></slot>
75
+ <!-- Tabs -->
76
+ <FTabPanel v-if="tabs.length" v-model="activeTab" :slider="slider" :tabs="tabs" />
77
+
78
+ <v-spacer />
79
+
80
+ <!-- Viewers -->
81
+ <FViewerPanel v-if="viewers.length" v-model="activeViewer" :viewers="viewers" />
82
+
83
+ <!-- Actions -->
84
+ <div class="d-flex f-toolbar-actions">
85
+ <!-- Search -->
86
+ <FSearchPanel v-if="config.search" v-model="search" search-on-blur :tooltip-props="{ location: 'top', offset: '10' }" />
87
+
88
+ <!-- Dialog filter activator -->
89
+ <v-tooltip v-if="config.filter && !config.menuFilter" :text="$t('tooltip.filter')">
90
+ <template #activator="{ props: tooltipProps }">
91
+ <v-btn class="f-filter-activator" variant="text" size="30" v-bind="tooltipProps" @click="emit('filterActivator')">
92
+ <v-badge dot color="primary" :model-value="Boolean(filterBadge)" offset-x="-4" offset-y="-2">
93
+ <FIcon icon="filter" color="text" size="18" />
94
+ </v-badge>
95
+ </v-btn>
96
+ </template>
97
+ </v-tooltip>
98
+
99
+ <!-- Menu filter -->
100
+ <FFilterPanel v-if="!config.filter && config.menuFilter" v-model="filter" :badge="filterBadge">
101
+ <slot name="filter"></slot>
102
+ </FFilterPanel>
103
+
104
+ <!-- Sort -->
105
+ <FSortPanel v-if="config.sort" v-model="sort" :badge="sortBadge">
106
+ <slot name="sort"></slot>
107
+ </FSortPanel>
108
+
109
+ <!-- Favorites -->
110
+ <v-tooltip v-if="config.favorites" :text="$t('tooltip.favoritesFilter')">
111
+ <template #activator="{ props: tooltipProps }">
112
+ <v-btn variant="text" v-bind="tooltipProps" size="30" @click="favorites = !favorites">
113
+ <FIcon :icon="favorites ? 'star' : 'star-line'" color="text" />
114
+ </v-btn>
115
+ </template>
116
+ </v-tooltip>
117
+
118
+ <!-- Custom actions -->
119
+ <slot name="customActions"></slot>
120
+ </div>
121
+ </div>
122
+ </template>
123
+
124
+ <style lang="scss" scoped>
125
+ .f-toolbar {
126
+ max-height: 32px;
127
+ width: 100%;
128
+ position: relative;
129
+ border-bottom: 1px solid rgb(var(--v-theme-disabled));
130
+ }
131
+ </style>
@@ -0,0 +1,71 @@
1
+ <script setup>
2
+ // FViewerPanel
3
+ defineProps({
4
+ viewers: {
5
+ type: Array,
6
+ default: () => [],
7
+ validator: value => {
8
+ const values = value.map(i => i.value)
9
+ const isUnique = new Set(values).size === values.length
10
+
11
+ return (
12
+ isUnique &&
13
+ value.every(
14
+ i =>
15
+ 'name' in i &&
16
+ typeof i.name === 'string' &&
17
+ 'value' in i &&
18
+ (typeof i.value === 'number' || typeof i.value === 'string') &&
19
+ (i.loading === undefined || typeof i.loading === 'boolean') &&
20
+ (i.hide === undefined || typeof i.hide === 'boolean')
21
+ )
22
+ )
23
+ }
24
+ // Example:
25
+ // {
26
+ // name: String,
27
+ // value: Number | String,
28
+ // loading: Boolean,
29
+ // hide: Boolean,
30
+ // }
31
+ }
32
+ })
33
+
34
+ const modelValue = defineModel({
35
+ type: [Number, String],
36
+ default: 0
37
+ })
38
+ </script>
39
+ <template>
40
+ <v-tabs v-model="modelValue" hide-slider height="32" class="f-viewer-panel">
41
+ <template v-for="v in viewers">
42
+ <v-tab v-if="!v.hide" :key="v.value" :value="v.value" :ripple="false">
43
+ <!-- Loading -->
44
+ <v-skeleton-loader v-if="v.loading" width="120px" height="24px" class="pt-2 f-skeleton-loader" type="text" />
45
+
46
+ <!-- Viewer name -->
47
+ <template v-else>{{ v.name }}</template>
48
+ </v-tab>
49
+ </template>
50
+ </v-tabs>
51
+ </template>
52
+
53
+ <style lang="scss" scoped>
54
+ .f-viewer-panel {
55
+ background: transparent;
56
+ :deep(.v-slide-group__container) {
57
+ &::after {
58
+ content: none;
59
+ }
60
+ .v-slide-group__content {
61
+ .v-tab {
62
+ padding-left: 13.5px;
63
+ padding-right: 13.5px;
64
+ .v-btn__overlay {
65
+ display: none;
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
71
+ </style>
@@ -0,0 +1,69 @@
1
+ import { h } from 'vue'
2
+
3
+ // Component for using as <f-icon> or <FIcon>
4
+ export const FIcon = {
5
+ name: 'FIcon',
6
+ props: {
7
+ icon: {
8
+ type: String,
9
+ required: true
10
+ },
11
+ color: {
12
+ type: String,
13
+ default: 'primary'
14
+ },
15
+ size: {
16
+ type: [String, Number],
17
+ default: 20
18
+ },
19
+ height: {
20
+ type: [String, Number],
21
+ default: null
22
+ },
23
+ width: {
24
+ type: [String, Number],
25
+ default: null
26
+ }
27
+ },
28
+ render() {
29
+ const formatSize = value => {
30
+ if (typeof value === 'string') {
31
+ // If already contains unit (em, rem, px), use as is
32
+ if (value.includes('em') || value.includes('rem') || value.includes('px')) {
33
+ return value
34
+ }
35
+ // If string but no unit, treat as number
36
+ return `${parseFloat(value)}px`
37
+ }
38
+ // If number, add px
39
+ return `${value}px`
40
+ }
41
+
42
+ const height = this.height || this.size
43
+ const width = this.width || this.size
44
+
45
+ return h('i', {
46
+ class: ['f-icon', this.icon, `bg-${this.color}`],
47
+ style: {
48
+ height: formatSize(height),
49
+ width: formatSize(width),
50
+ minHeight: formatSize(height),
51
+ minWidth: formatSize(width)
52
+ }
53
+ })
54
+ }
55
+ }
56
+
57
+ // Custom icon component for Vuetify
58
+ export const forcebpmIcon = {
59
+ component: props => {
60
+ // Extract icon name from props.icon
61
+ // Example: 'f-icon:chevron-left' -> 'chevron-left'
62
+ const iconName = props.icon.replace('f-icon:', '')
63
+
64
+ return h('i', {
65
+ class: ['f-icon', iconName, props.class],
66
+ style: props.style
67
+ })
68
+ }
69
+ }
@@ -1,25 +1,25 @@
1
1
  {
2
- "buttons": {
3
- "close": "Close",
4
- "share": "Share",
5
- "yes": "Yes",
6
- "no": "No"
7
- },
8
- "noData": {
9
- "title": "No data available"
10
- },
11
- "tooltip": {
12
- "actions": "Actions"
13
- },
14
- "updating": "Updating...",
15
- "notification": {
16
- "openTask": "Open task",
17
- "openDocument": "Open document",
18
- "openDescussion": "Open discussion"
19
- },
20
- "user": {
21
- "telephone": "Phone",
22
- "position": "Position",
23
- "department": "Department"
24
- }
25
- }
2
+ "buttons": {
3
+ "close": "Close",
4
+ "share": "Share",
5
+ "yes": "Yes",
6
+ "no": "No"
7
+ },
8
+ "noData": {
9
+ "title": "No data available"
10
+ },
11
+ "tooltip": {
12
+ "actions": "Actions"
13
+ },
14
+ "updating": "Updating...",
15
+ "notification": {
16
+ "openTask": "Open task",
17
+ "openDocument": "Open document",
18
+ "openDescussion": "Open discussion"
19
+ },
20
+ "user": {
21
+ "telephone": "Phone",
22
+ "position": "Position",
23
+ "department": "Department"
24
+ }
25
+ }
@@ -1,25 +1,25 @@
1
1
  {
2
- "buttons": {
3
- "close": "Закрыть",
4
- "share": "Поделиться",
5
- "yes": "Да",
6
- "no": "Нет"
7
- },
8
- "noData": {
9
- "title": "Данные отсутствуют"
10
- },
11
- "tooltip": {
12
- "actions": "Действия"
13
- },
14
- "updating": "Обновление...",
15
- "notification": {
16
- "openTask": "Открыть задачу",
17
- "openDocument": "Открыть документ",
18
- "openDescussion": "Открыть обсуждение"
19
- },
20
- "user": {
21
- "telephone": "Телефон",
22
- "position": "Должность",
23
- "department": "Отдел"
24
- }
25
- }
2
+ "buttons": {
3
+ "close": "Закрыть",
4
+ "share": "Поделиться",
5
+ "yes": "Да",
6
+ "no": "Нет"
7
+ },
8
+ "noData": {
9
+ "title": "Данные отсутствуют"
10
+ },
11
+ "tooltip": {
12
+ "actions": "Действия"
13
+ },
14
+ "updating": "Обновление...",
15
+ "notification": {
16
+ "openTask": "Открыть задачу",
17
+ "openDocument": "Открыть документ",
18
+ "openDescussion": "Открыть обсуждение"
19
+ },
20
+ "user": {
21
+ "telephone": "Телефон",
22
+ "position": "Должность",
23
+ "department": "Отдел"
24
+ }
25
+ }
@@ -1,25 +1,25 @@
1
1
  {
2
- "buttons": {
3
- "close": "Закрити",
4
- "share": "Поділитися",
5
- "yes": "Так",
6
- "no": "Ні"
7
- },
8
- "noData": {
9
- "title": "Дані відсутні"
10
- },
11
- "tooltip": {
12
- "actions": "Дії"
13
- },
14
- "updating": "Оновлення...",
15
- "notification": {
16
- "openTask": "Відкрити задачу",
17
- "openDocument": "Відкрити документ",
18
- "openDescussion": "Відкрити обговорення"
19
- },
20
- "user": {
21
- "telephone": "Телефон",
22
- "position": "Посада",
23
- "department": "Відділ"
24
- }
25
- }
2
+ "buttons": {
3
+ "close": "Закрити",
4
+ "share": "Поділитися",
5
+ "yes": "Так",
6
+ "no": "Ні"
7
+ },
8
+ "noData": {
9
+ "title": "Дані відсутні"
10
+ },
11
+ "tooltip": {
12
+ "actions": "Дії"
13
+ },
14
+ "updating": "Оновлення...",
15
+ "notification": {
16
+ "openTask": "Відкрити задачу",
17
+ "openDocument": "Відкрити документ",
18
+ "openDescussion": "Відкрити обговорення"
19
+ },
20
+ "user": {
21
+ "telephone": "Телефон",
22
+ "position": "Посада",
23
+ "department": "Відділ"
24
+ }
25
+ }
@@ -1,6 +1,6 @@
1
1
  // Global button styles with theme support
2
2
 
3
- .v-btn {
3
+ .f-btn.v-btn {
4
4
  --v-btn-size: 1em;
5
5
  --v-btn-height: 40px;
6
6
  letter-spacing: 0.03em;
@@ -58,45 +58,3 @@
58
58
  }
59
59
  }
60
60
  }
61
-
62
- // .fbpmp-add-tab-btn.v-btn.v-btn--icon {
63
- // padding: 0 !important;
64
- // min-width: 38px !important;
65
- // width: 38px;
66
- // height: 38px !important;
67
- // border-radius: 0;
68
- // border-bottom: 1px solid var(--v-line3-base) !important;
69
- // &.v-btn--disabled {
70
- // .f-icon {
71
- // background-color: rgb(var(--v-theme-disabled) !important;
72
- // }
73
- // }
74
- // .f-icon {
75
- // height: 19px;
76
- // width: 19px;
77
- // }
78
- // }
79
- // .toolbar-icon-btn.v-btn {
80
- // min-width: 30px !important;
81
- // max-width: 30px !important;
82
- // height: 30px !important;
83
- // padding: 5px;
84
- // padding-bottom: 0;
85
- // .v-badge {
86
- // width: 30px;
87
- // }
88
- // i {
89
- // height: 15px;
90
- // width: 15px;
91
- // }
92
- // }
93
- // @media (max-width: 1350px) {
94
- // .fbpmp-add-tab-btn {
95
- // min-width: 32px !important;
96
- // width: 32px;
97
- // height: 32px !important;
98
- // .v-btn__content {
99
- // margin-right: 1px;
100
- // }
101
- // }
102
- // }
@@ -3,3 +3,9 @@
3
3
  box-shadow: var(--f-box-shadow);
4
4
  }
5
5
  }
6
+
7
+ .v-sheet,
8
+ .v-card {
9
+ background: rgb(var(--v-theme-background));
10
+ color: rgb(var(--v-theme-text));
11
+ }
@@ -1,8 +1,3 @@
1
- // .f-expansion-panels {
2
- // &.v-expansion-panels {
3
- // }
4
- // }
5
-
6
1
  .f-expansion-panel {
7
2
  &.v-expansion-panel {
8
3
  background: transparent;
@@ -6,8 +6,6 @@
6
6
  @use 'expansion';
7
7
  @use 'skeleton';
8
8
  @use 'card';
9
- @use 'checkbox';
10
9
  @use 'pagination';
11
10
  @use 'snackbar';
12
11
  // @use 'tables';
13
- // @use 'bryntum';