@globalbrain/sefirot 2.35.0 → 2.37.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.
- package/lib/components/SDropdownSectionFilter.vue +1 -0
- package/lib/components/SLink.vue +16 -3
- package/lib/components/STable.vue +6 -1
- package/lib/components/STableCell.vue +16 -0
- package/lib/components/STableCellDay.vue +8 -3
- package/lib/components/STableCellNumber.vue +145 -0
- package/lib/components/STableCellPills.vue +1 -0
- package/lib/components/STableCellText.vue +35 -30
- package/lib/components/STableHeader.vue +28 -11
- package/lib/components/STableHeaderMenu.vue +52 -0
- package/lib/components/STableHeaderMenuItem.vue +109 -0
- package/lib/composables/Data.ts +1 -2
- package/lib/composables/Dropdown.ts +1 -2
- package/lib/composables/Flyout.ts +1 -2
- package/lib/composables/Grid.ts +1 -2
- package/lib/composables/Markdown.ts +2 -4
- package/lib/composables/Table.ts +26 -3
- package/lib/composables/Utils.ts +2 -4
- package/lib/composables/Validation.ts +1 -3
- package/lib/support/Day.ts +1 -2
- package/package.json +1 -1
package/lib/components/SLink.vue
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
|
|
4
|
-
const props = defineProps
|
|
5
|
-
href
|
|
4
|
+
const props = withDefaults(defineProps<{
|
|
5
|
+
href?: string | null
|
|
6
|
+
external?: boolean | null
|
|
7
|
+
}>(), {
|
|
8
|
+
external: null
|
|
6
9
|
})
|
|
7
10
|
|
|
8
11
|
const OUTBOUND_REGEX = /^[a-z]+:/i
|
|
9
12
|
|
|
10
|
-
const isExternal = computed(() =>
|
|
13
|
+
const isExternal = computed(() => {
|
|
14
|
+
if (!props.href) {
|
|
15
|
+
return false
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (props.external !== null) {
|
|
19
|
+
return props.external
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return OUTBOUND_REGEX.test(props.href)
|
|
23
|
+
})
|
|
11
24
|
|
|
12
25
|
const component = computed(() => {
|
|
13
26
|
if (!props.href) {
|
|
@@ -60,7 +60,11 @@ const showHeader = computed(() => {
|
|
|
60
60
|
return header
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
return
|
|
63
|
+
return (
|
|
64
|
+
unref(props.options.total) != null
|
|
65
|
+
|| !!unref(props.options.reset)
|
|
66
|
+
|| !!unref(props.options.menu)
|
|
67
|
+
)
|
|
64
68
|
})
|
|
65
69
|
|
|
66
70
|
const showFooter = computed(() => {
|
|
@@ -216,6 +220,7 @@ function getCell(key: string, index: number) {
|
|
|
216
220
|
v-if="showHeader"
|
|
217
221
|
:total="unref(options.total)"
|
|
218
222
|
:reset="unref(options.reset)"
|
|
223
|
+
:menu="unref(options.menu)"
|
|
219
224
|
:borderless="unref(options.borderless)"
|
|
220
225
|
:on-reset="options.onReset"
|
|
221
226
|
/>
|
|
@@ -5,6 +5,7 @@ import STableCellAvatar from './STableCellAvatar.vue'
|
|
|
5
5
|
import STableCellAvatars from './STableCellAvatars.vue'
|
|
6
6
|
import STableCellDay from './STableCellDay.vue'
|
|
7
7
|
import STableCellEmpty from './STableCellEmpty.vue'
|
|
8
|
+
import STableCellNumber from './STableCellNumber.vue'
|
|
8
9
|
import STableCellPill from './STableCellPill.vue'
|
|
9
10
|
import STableCellPills from './STableCellPills.vue'
|
|
10
11
|
import STableCellState from './STableCellState.vue'
|
|
@@ -32,6 +33,7 @@ const computedCell = computed<TableCell | undefined>(() =>
|
|
|
32
33
|
v-if="!computedCell || computedCell.type === 'text'"
|
|
33
34
|
:value="value"
|
|
34
35
|
:record="record"
|
|
36
|
+
:align="computedCell?.align"
|
|
35
37
|
:icon="computedCell?.icon"
|
|
36
38
|
:getter="computedCell?.value"
|
|
37
39
|
:link="computedCell?.link"
|
|
@@ -39,10 +41,24 @@ const computedCell = computed<TableCell | undefined>(() =>
|
|
|
39
41
|
:icon-color="computedCell?.iconColor"
|
|
40
42
|
:on-click="computedCell?.onClick"
|
|
41
43
|
/>
|
|
44
|
+
<STableCellNumber
|
|
45
|
+
v-else-if="computedCell.type === 'number'"
|
|
46
|
+
:value="value"
|
|
47
|
+
:record="record"
|
|
48
|
+
:align="computedCell.align"
|
|
49
|
+
:icon="computedCell.icon"
|
|
50
|
+
:getter="computedCell.value"
|
|
51
|
+
:separator="computedCell.separator"
|
|
52
|
+
:link="computedCell.link"
|
|
53
|
+
:color="computedCell.color"
|
|
54
|
+
:icon-color="computedCell.iconColor"
|
|
55
|
+
:on-click="computedCell.onClick"
|
|
56
|
+
/>
|
|
42
57
|
<STableCellDay
|
|
43
58
|
v-else-if="computedCell.type === 'day'"
|
|
44
59
|
:value="value"
|
|
45
60
|
:record="record"
|
|
61
|
+
:align="computedCell.align"
|
|
46
62
|
:getter="computedCell.value"
|
|
47
63
|
:format="computedCell.format"
|
|
48
64
|
:color="computedCell.color"
|
|
@@ -5,6 +5,7 @@ import { type Day } from '../support/Day'
|
|
|
5
5
|
const props = defineProps<{
|
|
6
6
|
value?: Day | null
|
|
7
7
|
record: any
|
|
8
|
+
align?: 'left' | 'center' | 'right'
|
|
8
9
|
getter?: Day | null
|
|
9
10
|
format?: string
|
|
10
11
|
color?: 'neutral' | 'soft' | 'mute'
|
|
@@ -16,9 +17,9 @@ const _value = computed(() => {
|
|
|
16
17
|
</script>
|
|
17
18
|
|
|
18
19
|
<template>
|
|
19
|
-
<div class="STableCellDay" :class="[color ?? 'neutral']">
|
|
20
|
+
<div class="STableCellDay" :class="[align ?? 'left', color ?? 'neutral']">
|
|
20
21
|
<div v-if="_value" class="value">
|
|
21
|
-
{{ _value.format(format ?? 'YYYY
|
|
22
|
+
{{ _value.format(format ?? 'YYYY-MM-DD HH:mm:ss') }}
|
|
22
23
|
</div>
|
|
23
24
|
</div>
|
|
24
25
|
</template>
|
|
@@ -31,14 +32,18 @@ const _value = computed(() => {
|
|
|
31
32
|
|
|
32
33
|
.value {
|
|
33
34
|
line-height: 24px;
|
|
34
|
-
font-family: var(--font-family-number);
|
|
35
35
|
font-size: var(--table-cell-font-size);
|
|
36
36
|
font-weight: var(--table-cell-font-weight);
|
|
37
|
+
font-feature-settings: "tnum";
|
|
37
38
|
white-space: nowrap;
|
|
38
39
|
overflow: hidden;
|
|
39
40
|
text-overflow: ellipsis;
|
|
40
41
|
transition: color 0.25s;
|
|
41
42
|
|
|
43
|
+
.STableCellDay.left & { text-align: left; }
|
|
44
|
+
.STableCellDay.center & { text-align: center; }
|
|
45
|
+
.STableCellDay.right & { text-align: right; }
|
|
46
|
+
|
|
42
47
|
.STableCellDay.neutral & { color: var(--c-text-1); }
|
|
43
48
|
.STableCellDay.soft & { color: var(--c-text-2); }
|
|
44
49
|
.STableCellDay.mute & { color: var(--c-text-3); }
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { format } from 'sefirot/support/Num'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { type TableCellValueColor } from '../composables/Table'
|
|
5
|
+
import SIcon from './SIcon.vue'
|
|
6
|
+
import SLink from './SLink.vue'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
value?: any
|
|
10
|
+
record: any
|
|
11
|
+
align?: 'left' | 'center' | 'right'
|
|
12
|
+
icon?: any
|
|
13
|
+
getter?: number | null
|
|
14
|
+
separator?: boolean
|
|
15
|
+
color?: TableCellValueColor
|
|
16
|
+
iconColor?: TableCellValueColor
|
|
17
|
+
link?: string | null
|
|
18
|
+
onClick?(value: any, record: any): void
|
|
19
|
+
}>()
|
|
20
|
+
|
|
21
|
+
const _value = computed(() => props.getter ?? props.value)
|
|
22
|
+
const _color = computed(() => props.color ?? 'neutral')
|
|
23
|
+
const _iconColor = computed(() => props.iconColor ?? _color.value)
|
|
24
|
+
|
|
25
|
+
const classes = computed(() => [
|
|
26
|
+
props.align ?? 'left',
|
|
27
|
+
_color,
|
|
28
|
+
{ link: props.link || props.onClick }
|
|
29
|
+
])
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<div class="STableCellNumber" :class="classes">
|
|
34
|
+
<SLink
|
|
35
|
+
v-if="_value"
|
|
36
|
+
class="container"
|
|
37
|
+
:href="link"
|
|
38
|
+
:role="onClick ? 'button' : null"
|
|
39
|
+
@click="() => onClick?.(value, record)"
|
|
40
|
+
>
|
|
41
|
+
<div v-if="icon" class="icon" :class="[_iconColor]">
|
|
42
|
+
<SIcon :icon="icon" class="svg" />
|
|
43
|
+
</div>
|
|
44
|
+
<div class="value" :class="[_color ?? 'neutral']">
|
|
45
|
+
{{ separator ? format(_value) : _value }}
|
|
46
|
+
</div>
|
|
47
|
+
</SLink>
|
|
48
|
+
</div>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<style scoped lang="postcss">
|
|
52
|
+
.STableCellNumber {
|
|
53
|
+
min-height: 40px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.container {
|
|
57
|
+
display: flex;
|
|
58
|
+
gap: 4px;
|
|
59
|
+
padding: 8px 16px;
|
|
60
|
+
|
|
61
|
+
.STableCellNumber.left & { justify-content: flex-start; }
|
|
62
|
+
.STableCellNumber.center & { justify-content: center; }
|
|
63
|
+
.STableCellNumber.right & { justify-content: flex-end; }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.value {
|
|
67
|
+
line-height: 24px;
|
|
68
|
+
font-size: var(--table-cell-font-size);
|
|
69
|
+
font-weight: var(--table-cell-font-weight);
|
|
70
|
+
font-feature-settings: "tnum";
|
|
71
|
+
white-space: nowrap;
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
text-overflow: ellipsis;
|
|
74
|
+
transition: color 0.25s;
|
|
75
|
+
|
|
76
|
+
&.neutral { color: var(--c-text-1); }
|
|
77
|
+
&.soft { color: var(--c-text-2); }
|
|
78
|
+
&.mute { color: var(--c-text-3); }
|
|
79
|
+
&.info { color: var(--c-info-text); }
|
|
80
|
+
&.success { color: var(--c-success-text); }
|
|
81
|
+
&.warning { color: var(--c-warning-text); }
|
|
82
|
+
&.danger { color: var(--c-danger-text); }
|
|
83
|
+
|
|
84
|
+
.STableCellNumber.link & { color: var(--c-info-text); }
|
|
85
|
+
.STableCellNumber.link:hover & { color: var(--c-info-text-dark); }
|
|
86
|
+
|
|
87
|
+
.STableCellNumber.link &.neutral { color: var(--c-text-1); }
|
|
88
|
+
.STableCellNumber.link:hover &.neutral { color: var(--c-info-text); }
|
|
89
|
+
.STableCellNumber.link &.soft { color: var(--c-text-2); }
|
|
90
|
+
.STableCellNumber.link:hover &.soft { color: var(--c-info-text); }
|
|
91
|
+
.STableCellNumber.link &.mute { color: var(--c-text-3); }
|
|
92
|
+
.STableCellNumber.link:hover &.mute { color: var(--c-text-3); }
|
|
93
|
+
.STableCellNumber.link &.info { color: var(--c-info-text); }
|
|
94
|
+
.STableCellNumber.link:hover &.info { color: var(--c-info-text-dark); }
|
|
95
|
+
.STableCellNumber.link &.success { color: var(--c-success-text); }
|
|
96
|
+
.STableCellNumber.link:hover &.success { color: var(--c-success-text-dark); }
|
|
97
|
+
.STableCellNumber.link &.warning { color: var(--c-warning-text); }
|
|
98
|
+
.STableCellNumber.link:hover &.warning { color: var(--c-warning-text-darker); }
|
|
99
|
+
.STableCellNumber.link &.danger { color: var(--c-danger-text); }
|
|
100
|
+
.STableCellNumber.link:hover &.danger { color: var(--c-danger-text-dark); }
|
|
101
|
+
|
|
102
|
+
.STableCell.summary & {
|
|
103
|
+
font-weight: var(--table-cell-summary-font-weight);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.icon {
|
|
108
|
+
display: flex;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
align-items: center;
|
|
111
|
+
flex-shrink: 0;
|
|
112
|
+
margin-left: -3px;
|
|
113
|
+
width: 24px;
|
|
114
|
+
height: 24px;
|
|
115
|
+
transition: color 0.25s;
|
|
116
|
+
|
|
117
|
+
&.neutral { color: var(--c-text-1); }
|
|
118
|
+
&.soft { color: var(--c-text-2); }
|
|
119
|
+
&.mute { color: var(--c-text-3); }
|
|
120
|
+
|
|
121
|
+
.STableCellNumber.link & { color: var(--c-info-text); }
|
|
122
|
+
.STableCellNumber.link:hover & { color: var(--c-info-text-dark); }
|
|
123
|
+
|
|
124
|
+
.STableCellNumber.link &.neutral { color: var(--c-text-1); }
|
|
125
|
+
.STableCellNumber.link:hover &.neutral { color: var(--c-info-text); }
|
|
126
|
+
.STableCellNumber.link &.soft { color: var(--c-text-2); }
|
|
127
|
+
.STableCellNumber.link:hover &.soft { color: var(--c-info-text); }
|
|
128
|
+
.STableCellNumber.link &.mute { color: var(--c-text-3); }
|
|
129
|
+
.STableCellNumber.link:hover &.mute { color: var(--c-info-text); }
|
|
130
|
+
.STableCellNumber.link &.info { color: var(--c-info-text); }
|
|
131
|
+
.STableCellNumber.link:hover &.info { color: var(--c-info-text-dark); }
|
|
132
|
+
.STableCellNumber.link &.success { color: var(--c-success-text); }
|
|
133
|
+
.STableCellNumber.link:hover &.success { color: var(--c-success-text-dark); }
|
|
134
|
+
.STableCellNumber.link &.warning { color: var(--c-warning-text); }
|
|
135
|
+
.STableCellNumber.link:hover &.warning { color: var(--c-warning-text-dark); }
|
|
136
|
+
.STableCellNumber.link &.danger { color: var(--c-danger-text); }
|
|
137
|
+
.STableCellNumber.link:hover &.danger { color: var(--c-danger-text-dark); }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.svg {
|
|
141
|
+
width: 18px;
|
|
142
|
+
height: 18px;
|
|
143
|
+
fill: currentColor;
|
|
144
|
+
}
|
|
145
|
+
</style>
|
|
@@ -15,6 +15,7 @@ export type Color =
|
|
|
15
15
|
const props = defineProps<{
|
|
16
16
|
value?: any
|
|
17
17
|
record: any
|
|
18
|
+
align?: 'left' | 'center' | 'right'
|
|
18
19
|
icon?: any
|
|
19
20
|
getter?: string | null | ((value: any, record: any) => string | null)
|
|
20
21
|
color?: Color | ((value: any, record: any) => Color)
|
|
@@ -42,12 +43,12 @@ const _color = computed(() => {
|
|
|
42
43
|
const _iconColor = computed(() => {
|
|
43
44
|
return typeof props.iconColor === 'function'
|
|
44
45
|
? props.iconColor(props.value, props.record)
|
|
45
|
-
: props.iconColor ??
|
|
46
|
+
: props.iconColor ?? _color.value
|
|
46
47
|
})
|
|
47
48
|
</script>
|
|
48
49
|
|
|
49
50
|
<template>
|
|
50
|
-
<div class="STableCellText" :class="[{ link: link || onClick }, _color]">
|
|
51
|
+
<div class="STableCellText" :class="[align ?? 'left', { link: link || onClick }, _color]">
|
|
51
52
|
<SLink
|
|
52
53
|
v-if="_value"
|
|
53
54
|
class="container"
|
|
@@ -74,6 +75,10 @@ const _iconColor = computed(() => {
|
|
|
74
75
|
display: flex;
|
|
75
76
|
gap: 4px;
|
|
76
77
|
padding: 8px 16px;
|
|
78
|
+
|
|
79
|
+
.STableCellText.left & { justify-content: flex-start; }
|
|
80
|
+
.STableCellText.center & { justify-content: center; }
|
|
81
|
+
.STableCellText.right & { justify-content: flex-end; }
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
.text {
|
|
@@ -88,28 +93,28 @@ const _iconColor = computed(() => {
|
|
|
88
93
|
&.neutral { color: var(--c-text-1); }
|
|
89
94
|
&.soft { color: var(--c-text-2); }
|
|
90
95
|
&.mute { color: var(--c-text-3); }
|
|
91
|
-
&.info { color: var(--c-info); }
|
|
92
|
-
&.success { color: var(--c-success); }
|
|
93
|
-
&.warning { color: var(--c-warning); }
|
|
94
|
-
&.danger { color: var(--c-danger); }
|
|
96
|
+
&.info { color: var(--c-info-text); }
|
|
97
|
+
&.success { color: var(--c-success-text); }
|
|
98
|
+
&.warning { color: var(--c-warning-text); }
|
|
99
|
+
&.danger { color: var(--c-danger-text); }
|
|
95
100
|
|
|
96
|
-
.STableCellText.link & { color: var(--c-info); }
|
|
97
|
-
.STableCellText.link:hover & { color: var(--c-info-dark); }
|
|
101
|
+
.STableCellText.link & { color: var(--c-info-text); }
|
|
102
|
+
.STableCellText.link:hover & { color: var(--c-info-text-dark); }
|
|
98
103
|
|
|
99
104
|
.STableCellText.link &.neutral { color: var(--c-text-1); }
|
|
100
|
-
.STableCellText.link:hover &.neutral { color: var(--c-info); }
|
|
105
|
+
.STableCellText.link:hover &.neutral { color: var(--c-info-text); }
|
|
101
106
|
.STableCellText.link &.soft { color: var(--c-text-2); }
|
|
102
|
-
.STableCellText.link:hover &.soft { color: var(--c-info); }
|
|
107
|
+
.STableCellText.link:hover &.soft { color: var(--c-info-text); }
|
|
103
108
|
.STableCellText.link &.mute { color: var(--c-text-3); }
|
|
104
109
|
.STableCellText.link:hover &.mute { color: var(--c-text-3); }
|
|
105
|
-
.STableCellText.link &.info { color: var(--c-info); }
|
|
106
|
-
.STableCellText.link:hover &.info { color: var(--c-info-dark); }
|
|
107
|
-
.STableCellText.link &.success { color: var(--c-success); }
|
|
108
|
-
.STableCellText.link:hover &.success { color: var(--c-success-dark); }
|
|
109
|
-
.STableCellText.link &.warning { color: var(--c-warning); }
|
|
110
|
-
.STableCellText.link:hover &.warning { color: var(--c-warning-darker); }
|
|
111
|
-
.STableCellText.link &.danger { color: var(--c-danger); }
|
|
112
|
-
.STableCellText.link:hover &.danger { color: var(--c-danger-dark); }
|
|
110
|
+
.STableCellText.link &.info { color: var(--c-info-text); }
|
|
111
|
+
.STableCellText.link:hover &.info { color: var(--c-info-text-dark); }
|
|
112
|
+
.STableCellText.link &.success { color: var(--c-success-text); }
|
|
113
|
+
.STableCellText.link:hover &.success { color: var(--c-success-text-dark); }
|
|
114
|
+
.STableCellText.link &.warning { color: var(--c-warning-text); }
|
|
115
|
+
.STableCellText.link:hover &.warning { color: var(--c-warning-text-darker); }
|
|
116
|
+
.STableCellText.link &.danger { color: var(--c-danger-text); }
|
|
117
|
+
.STableCellText.link:hover &.danger { color: var(--c-danger-text-dark); }
|
|
113
118
|
|
|
114
119
|
.STableCell.summary & {
|
|
115
120
|
font-weight: var(--table-cell-summary-font-weight);
|
|
@@ -130,23 +135,23 @@ const _iconColor = computed(() => {
|
|
|
130
135
|
&.soft { color: var(--c-text-2); }
|
|
131
136
|
&.mute { color: var(--c-text-3); }
|
|
132
137
|
|
|
133
|
-
.STableCellText.link & { color: var(--c-info); }
|
|
134
|
-
.STableCellText.link:hover & { color: var(--c-info-dark); }
|
|
138
|
+
.STableCellText.link & { color: var(--c-info-text); }
|
|
139
|
+
.STableCellText.link:hover & { color: var(--c-info-text-dark); }
|
|
135
140
|
|
|
136
141
|
.STableCellText.link &.neutral { color: var(--c-text-1); }
|
|
137
|
-
.STableCellText.link:hover &.neutral { color: var(--c-info); }
|
|
142
|
+
.STableCellText.link:hover &.neutral { color: var(--c-info-text); }
|
|
138
143
|
.STableCellText.link &.soft { color: var(--c-text-2); }
|
|
139
|
-
.STableCellText.link:hover &.soft { color: var(--c-info); }
|
|
144
|
+
.STableCellText.link:hover &.soft { color: var(--c-info-text); }
|
|
140
145
|
.STableCellText.link &.mute { color: var(--c-text-3); }
|
|
141
|
-
.STableCellText.link:hover &.mute { color: var(--c-info); }
|
|
142
|
-
.STableCellText.link &.info { color: var(--c-info); }
|
|
146
|
+
.STableCellText.link:hover &.mute { color: var(--c-info-text); }
|
|
147
|
+
.STableCellText.link &.info { color: var(--c-info-text); }
|
|
143
148
|
.STableCellText.link:hover &.info { color: var(--c-info-dark); }
|
|
144
|
-
.STableCellText.link &.success { color: var(--c-success); }
|
|
145
|
-
.STableCellText.link:hover &.success { color: var(--c-success-dark); }
|
|
146
|
-
.STableCellText.link &.warning { color: var(--c-warning); }
|
|
147
|
-
.STableCellText.link:hover &.warning { color: var(--c-warning-dark); }
|
|
148
|
-
.STableCellText.link &.danger { color: var(--c-danger); }
|
|
149
|
-
.STableCellText.link:hover &.danger { color: var(--c-danger-dark); }
|
|
149
|
+
.STableCellText.link &.success { color: var(--c-success-text); }
|
|
150
|
+
.STableCellText.link:hover &.success { color: var(--c-success-text-dark); }
|
|
151
|
+
.STableCellText.link &.warning { color: var(--c-warning-text); }
|
|
152
|
+
.STableCellText.link:hover &.warning { color: var(--c-warning-text-dark); }
|
|
153
|
+
.STableCellText.link &.danger { color: var(--c-danger-text); }
|
|
154
|
+
.STableCellText.link:hover &.danger { color: var(--c-danger-text-dark); }
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
.svg {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { type TableMenu } from '../composables/Table'
|
|
2
3
|
import { format } from '../support/Num'
|
|
3
4
|
import { isNullish } from '../support/Utils'
|
|
5
|
+
import STableHeaderMenu from './STableHeaderMenu.vue'
|
|
4
6
|
|
|
5
7
|
defineProps<{
|
|
6
8
|
total?: number | null
|
|
7
9
|
reset?: boolean
|
|
10
|
+
menu?: TableMenu[] | TableMenu[][]
|
|
8
11
|
borderless?: boolean
|
|
9
12
|
onReset?(): void
|
|
10
13
|
}>()
|
|
@@ -13,14 +16,18 @@ defineProps<{
|
|
|
13
16
|
<template>
|
|
14
17
|
<div class="STableHeader" :class="{ borderless }">
|
|
15
18
|
<div class="container">
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
<div class="stat">
|
|
20
|
+
<p v-if="!isNullish(total)" class="total">
|
|
21
|
+
{{ format(total) }} {{ (total) > 1 ? 'records' : 'record' }}
|
|
22
|
+
</p>
|
|
23
|
+
<div v-if="reset" class="reset">
|
|
24
|
+
<button class="button" @click="onReset">
|
|
25
|
+
Reset filters
|
|
26
|
+
</button>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<div v-if="menu && menu.length" class="menu">
|
|
30
|
+
<STableHeaderMenu :menu="menu" />
|
|
24
31
|
</div>
|
|
25
32
|
</div>
|
|
26
33
|
</div>
|
|
@@ -36,13 +43,18 @@ defineProps<{
|
|
|
36
43
|
|
|
37
44
|
.container {
|
|
38
45
|
display: flex;
|
|
39
|
-
padding: 0 16px;
|
|
40
46
|
min-height: 48px;
|
|
41
47
|
}
|
|
42
48
|
|
|
49
|
+
.stat {
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-grow: 1;
|
|
52
|
+
padding: 0 16px;
|
|
53
|
+
}
|
|
54
|
+
|
|
43
55
|
.total {
|
|
44
56
|
margin: 0;
|
|
45
|
-
padding:
|
|
57
|
+
padding: 12px 0;
|
|
46
58
|
line-height: 24px;
|
|
47
59
|
font-size: 12px;
|
|
48
60
|
font-weight: 500;
|
|
@@ -68,7 +80,7 @@ defineProps<{
|
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
.button {
|
|
71
|
-
padding:
|
|
83
|
+
padding: 12px 0;
|
|
72
84
|
line-height: 24px;
|
|
73
85
|
font-size: 12px;
|
|
74
86
|
font-weight: 500;
|
|
@@ -79,4 +91,9 @@ defineProps<{
|
|
|
79
91
|
color: var(--c-info-text-dark);
|
|
80
92
|
}
|
|
81
93
|
}
|
|
94
|
+
|
|
95
|
+
.menu {
|
|
96
|
+
flex-shrink: 0;
|
|
97
|
+
padding-right: 8px;
|
|
98
|
+
}
|
|
82
99
|
</style>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { type TableMenu } from '../composables/Table'
|
|
4
|
+
import { isArray } from '../support/Utils'
|
|
5
|
+
import STableHeaderMenuItem from './STableHeaderMenuItem.vue'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
menu: TableMenu[] | TableMenu[][]
|
|
9
|
+
}>()
|
|
10
|
+
|
|
11
|
+
const normalizedMenu = computed(() => {
|
|
12
|
+
return isArray(props.menu[0])
|
|
13
|
+
? props.menu as TableMenu[][]
|
|
14
|
+
: [props.menu] as TableMenu[][]
|
|
15
|
+
})
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div class="STableHeaderMenu">
|
|
20
|
+
<div v-for="items, index in normalizedMenu" :key="index" class="group">
|
|
21
|
+
<div v-if="index > 0" class="divider" />
|
|
22
|
+
<div v-for="item in items" :key="item.label" class="item">
|
|
23
|
+
<STableHeaderMenuItem
|
|
24
|
+
:label="item.label"
|
|
25
|
+
:state="item.state"
|
|
26
|
+
:dropdown="item.dropdown"
|
|
27
|
+
/>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<style scoped lang="postcss">
|
|
34
|
+
.STableHeaderMenu {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
height: 48px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.group {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
height: 48px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.divider {
|
|
47
|
+
margin: 0 8px;
|
|
48
|
+
width: 1px;
|
|
49
|
+
height: 16px;
|
|
50
|
+
background-color: var(--c-divider-2);
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import IconCaretDown from '@iconify-icons/ph/caret-down-bold'
|
|
3
|
+
import { type DropdownSection } from '../composables/Dropdown'
|
|
4
|
+
import { useFlyout } from '../composables/Flyout'
|
|
5
|
+
import SDropdown from './SDropdown.vue'
|
|
6
|
+
import SIcon from './SIcon.vue'
|
|
7
|
+
|
|
8
|
+
defineProps<{
|
|
9
|
+
label: string
|
|
10
|
+
state?: 'inactive' | 'active' | 'indicate'
|
|
11
|
+
dropdown: DropdownSection[]
|
|
12
|
+
}>()
|
|
13
|
+
|
|
14
|
+
const { container, isOpen, toggle } = useFlyout()
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<div class="STableHeaderMenuItem" ref="container">
|
|
19
|
+
<button class="button" :class="[state]" @click="toggle">
|
|
20
|
+
<span class="label">{{ label }}</span>
|
|
21
|
+
<span v-if="state !== 'indicate'" class="caret">
|
|
22
|
+
<SIcon class="caret-svg" :icon="IconCaretDown" />
|
|
23
|
+
</span>
|
|
24
|
+
<span v-else class="indicator">
|
|
25
|
+
<span class="indicator-dot" />
|
|
26
|
+
</span>
|
|
27
|
+
</button>
|
|
28
|
+
<Transition name="fade">
|
|
29
|
+
<div v-if="isOpen" class="dialog">
|
|
30
|
+
<SDropdown :sections="dropdown" />
|
|
31
|
+
</div>
|
|
32
|
+
</Transition>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<style scoped lang="postcss">
|
|
37
|
+
.STableHeaderMenuItem {
|
|
38
|
+
position: relative;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.button {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: 6px;
|
|
45
|
+
border-radius: 6px;
|
|
46
|
+
padding: 6px 7px 6px 9px;
|
|
47
|
+
transition: background-color 0.25s;
|
|
48
|
+
|
|
49
|
+
&:hover {
|
|
50
|
+
background-color: var(--c-mute);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.label {
|
|
55
|
+
font-size: 12px;
|
|
56
|
+
color: var(--c-text-2);
|
|
57
|
+
transition: color 0.25s;
|
|
58
|
+
|
|
59
|
+
.button:hover & {
|
|
60
|
+
color: var(--c-text-1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.button.active &,
|
|
64
|
+
.button.indicate & {
|
|
65
|
+
color: var(--c-text-1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.caret-svg {
|
|
70
|
+
width: 12px;
|
|
71
|
+
height: 12px;
|
|
72
|
+
color: var(--c-text-2);
|
|
73
|
+
transition: color 0.25s;
|
|
74
|
+
|
|
75
|
+
.button:hover & {
|
|
76
|
+
color: var(--c-text-1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.indicator {
|
|
81
|
+
display: flex;
|
|
82
|
+
justify-content: center;
|
|
83
|
+
align-items: center;
|
|
84
|
+
width: 12px;
|
|
85
|
+
height: 12px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.indicator-dot {
|
|
89
|
+
display: block;
|
|
90
|
+
border-radius: 6px;
|
|
91
|
+
width: 6px;
|
|
92
|
+
height: 6px;
|
|
93
|
+
background-color: var(--c-info-text);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.dialog {
|
|
97
|
+
position: absolute;
|
|
98
|
+
top: 32px;
|
|
99
|
+
right: 0;
|
|
100
|
+
z-index: var(--z-index-dropdown);
|
|
101
|
+
transition: opacity 0.25s, transform 0.25s;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.dialog.fade-enter-from,
|
|
105
|
+
.dialog.fade-leave-to {
|
|
106
|
+
opacity: 0;
|
|
107
|
+
transform: translateY(-4px);
|
|
108
|
+
}
|
|
109
|
+
</style>
|
package/lib/composables/Data.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { watchOnce } from '@vueuse/core'
|
|
2
2
|
import cloneDeep from 'lodash-es/cloneDeep'
|
|
3
|
-
import { type WatchSource } from 'vue'
|
|
4
|
-
import { reactive } from 'vue'
|
|
3
|
+
import { type WatchSource, reactive } from 'vue'
|
|
5
4
|
import { isNullish, isObject } from '../support/Utils'
|
|
6
5
|
|
|
7
6
|
export interface Data<T extends Record<string, any>> {
|
package/lib/composables/Grid.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import MarkdownIt from 'markdown-it'
|
|
2
|
-
import { type Ref } from 'vue'
|
|
3
|
-
import { onUnmounted } from 'vue'
|
|
2
|
+
import { type Ref, onUnmounted } from 'vue'
|
|
4
3
|
import { useRouter } from 'vue-router'
|
|
5
|
-
import { type LinkAttrs } from './markdown/LinkPlugin'
|
|
6
|
-
import { isCallbackUrl, isExternalUrl, linkPlugin } from './markdown/LinkPlugin'
|
|
4
|
+
import { type LinkAttrs, isCallbackUrl, isExternalUrl, linkPlugin } from './markdown/LinkPlugin'
|
|
7
5
|
|
|
8
6
|
export type UseMarkdown = (source: string, inline: boolean) => string
|
|
9
7
|
|
package/lib/composables/Table.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface Table<
|
|
|
10
10
|
> {
|
|
11
11
|
orders: MaybeRef<O[]>
|
|
12
12
|
columns: MaybeRef<TableColumns<O, R, SR>>
|
|
13
|
+
menu?: MaybeRef<TableMenu[] | TableMenu[][]>
|
|
13
14
|
records?: MaybeRef<R[] | null | undefined>
|
|
14
15
|
header?: MaybeRef<boolean | undefined>
|
|
15
16
|
footer?: MaybeRef<boolean | undefined>
|
|
@@ -48,6 +49,7 @@ export type TableColumnCellFn<V, R> = (value: V, record: R) => TableCell
|
|
|
48
49
|
|
|
49
50
|
export type TableCell =
|
|
50
51
|
| TableCellText
|
|
52
|
+
| TableCellNumber
|
|
51
53
|
| TableCellDay
|
|
52
54
|
| TableCellPill
|
|
53
55
|
| TableCellPills
|
|
@@ -59,6 +61,7 @@ export type TableCell =
|
|
|
59
61
|
|
|
60
62
|
export type TableCellType =
|
|
61
63
|
| 'text'
|
|
64
|
+
| 'number'
|
|
62
65
|
| 'day'
|
|
63
66
|
| 'pill'
|
|
64
67
|
| 'pills'
|
|
@@ -74,15 +77,28 @@ export interface TableCellBase {
|
|
|
74
77
|
|
|
75
78
|
export interface TableCellText extends TableCellBase {
|
|
76
79
|
type: 'text'
|
|
80
|
+
align?: 'left' | 'center' | 'right'
|
|
77
81
|
icon?: any
|
|
78
82
|
value?: string | null | ((value: any, record: any) => string | null)
|
|
79
83
|
link?(value: any, record: any): string
|
|
80
|
-
color?:
|
|
81
|
-
iconColor?:
|
|
84
|
+
color?: TableCellValueColor | ((value: any, record: any) => TableCellValueColor)
|
|
85
|
+
iconColor?: TableCellValueColor | ((value: any, record: any) => TableCellValueColor)
|
|
82
86
|
onClick?(value: any, record: any): void
|
|
83
87
|
}
|
|
84
88
|
|
|
85
|
-
export
|
|
89
|
+
export interface TableCellNumber extends TableCellBase {
|
|
90
|
+
type: 'number'
|
|
91
|
+
align?: 'left' | 'center' | 'right'
|
|
92
|
+
icon?: any
|
|
93
|
+
value?: number | null
|
|
94
|
+
separator?: boolean
|
|
95
|
+
link?: string | null
|
|
96
|
+
color?: TableCellValueColor
|
|
97
|
+
iconColor?: TableCellValueColor
|
|
98
|
+
onClick?(value: any, record: any): void
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type TableCellValueColor =
|
|
86
102
|
| 'neutral'
|
|
87
103
|
| 'soft'
|
|
88
104
|
| 'mute'
|
|
@@ -93,6 +109,7 @@ export type TableCellTextColor =
|
|
|
93
109
|
|
|
94
110
|
export interface TableCellDay extends TableCellBase {
|
|
95
111
|
type: 'day'
|
|
112
|
+
align?: 'left' | 'center' | 'right'
|
|
96
113
|
value?: Day | null
|
|
97
114
|
format?: string
|
|
98
115
|
color?: 'neutral' | 'soft' | 'mute'
|
|
@@ -152,6 +169,12 @@ export interface TableCellState extends TableCellBase {
|
|
|
152
169
|
mode?: 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
153
170
|
}
|
|
154
171
|
|
|
172
|
+
export interface TableMenu {
|
|
173
|
+
label: string
|
|
174
|
+
state?: 'inactive' | 'active' | 'indicate'
|
|
175
|
+
dropdown: DropdownSection[]
|
|
176
|
+
}
|
|
177
|
+
|
|
155
178
|
export function useTable<
|
|
156
179
|
O extends string,
|
|
157
180
|
R extends Record<string, any>,
|
package/lib/composables/Utils.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { type MaybeRefOrGetter } from '@vueuse/core'
|
|
2
|
-
import {
|
|
3
|
-
import { type ComputedRef } from 'vue'
|
|
4
|
-
import { computed } from 'vue'
|
|
1
|
+
import { type MaybeRefOrGetter, resolveUnref } from '@vueuse/core'
|
|
2
|
+
import { type ComputedRef, computed } from 'vue'
|
|
5
3
|
|
|
6
4
|
export type WhenCondition<T> = MaybeRefOrGetter<T>
|
|
7
5
|
|
package/lib/support/Day.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { type ConfigType, type Dayjs } from 'dayjs'
|
|
2
|
-
import dayjs from 'dayjs'
|
|
1
|
+
import dayjs, { type ConfigType, type Dayjs } from 'dayjs'
|
|
3
2
|
import PluginRelativeTime from 'dayjs/plugin/relativeTime'
|
|
4
3
|
import PluginTimezone from 'dayjs/plugin/timezone'
|
|
5
4
|
import PluginUtc from 'dayjs/plugin/utc'
|