@globalbrain/sefirot 3.45.0 → 3.47.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/SActionList.vue +2 -0
- package/lib/components/SActionListItem.vue +26 -44
- package/lib/components/SActionMenu.vue +1 -1
- package/lib/components/SAvatar.vue +26 -5
- package/lib/components/SAvatarStack.vue +14 -7
- package/lib/components/SButton.vue +16 -11
- package/lib/components/SCardFooterAction.vue +1 -1
- package/lib/components/SCardHeaderAction.vue +1 -1
- package/lib/components/SCardHeaderActionClose.vue +1 -1
- package/lib/components/SCardHeaderActionCollapse.vue +1 -1
- package/lib/components/SControlActionBarButton.vue +1 -1
- package/lib/components/SControlActionMenu.vue +1 -1
- package/lib/components/SControlButton.vue +1 -1
- package/lib/components/SLocalNav.vue +28 -2
- package/lib/components/SLocalNavAvatar.vue +25 -0
- package/lib/components/SLocalNavDescription.vue +19 -0
- package/lib/components/STableCell.vue +1 -0
- package/lib/components/STableCellAvatars.vue +3 -1
- package/lib/components/STooltip.vue +18 -5
- package/lib/composables/Markdown.ts +2 -2
- package/lib/composables/Table.ts +2 -0
- package/lib/http/Http.ts +31 -9
- package/package.json +20 -20
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type IconifyIcon } from '@iconify/vue/dist/offline'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
-
import
|
|
5
|
-
import SLink from './SLink.vue'
|
|
4
|
+
import SButton, { type Tooltip } from './SButton.vue'
|
|
6
5
|
|
|
7
6
|
export interface ActionListItem {
|
|
8
7
|
leadIcon?: IconifyIcon
|
|
9
8
|
link?: string
|
|
10
9
|
label?: string
|
|
11
10
|
disabled?: boolean
|
|
12
|
-
|
|
11
|
+
tooltip?: Tooltip
|
|
12
|
+
onClick?: () => void
|
|
13
13
|
|
|
14
14
|
/** @deprecated Use `:label` instead. */
|
|
15
15
|
text?: string
|
|
@@ -20,54 +20,36 @@ const props = defineProps<ActionListItem>()
|
|
|
20
20
|
const _label = computed(() => {
|
|
21
21
|
return props.label ?? props.text
|
|
22
22
|
})
|
|
23
|
+
|
|
24
|
+
const _tooltip = computed<Tooltip | undefined>(() => {
|
|
25
|
+
return props.tooltip ? { display: 'block', ...props.tooltip } : undefined
|
|
26
|
+
})
|
|
23
27
|
</script>
|
|
24
28
|
|
|
25
29
|
<template>
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
<div class="SActionListItem">
|
|
31
|
+
<SButton
|
|
32
|
+
block
|
|
33
|
+
size="small"
|
|
34
|
+
type="text"
|
|
35
|
+
:icon="leadIcon"
|
|
36
|
+
:label="_label"
|
|
37
|
+
:href="link"
|
|
38
|
+
:disabled="disabled"
|
|
39
|
+
:tooltip="_tooltip"
|
|
40
|
+
@click="onClick"
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
37
43
|
</template>
|
|
38
44
|
|
|
39
45
|
<style scoped lang="postcss">
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
gap: 8px;
|
|
43
|
-
border-radius: 6px;
|
|
44
|
-
padding: 4px 8px;
|
|
45
|
-
width: 100%;
|
|
46
|
-
text-align: left;
|
|
47
|
-
line-height: 24px;
|
|
48
|
-
font-size: 14px;
|
|
49
|
-
transition: background-color 0.25s;
|
|
50
|
-
|
|
51
|
-
&:hover {
|
|
52
|
-
background-color: var(--c-bg-mute-1);
|
|
53
|
-
}
|
|
46
|
+
.SActionListItem {
|
|
47
|
+
--button-font-size: 14px;
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
:deep(.SButton),
|
|
50
|
+
:slotted(.SButton) {
|
|
51
|
+
justify-content: flex-start;
|
|
52
|
+
font-weight: 400;
|
|
58
53
|
}
|
|
59
54
|
}
|
|
60
|
-
|
|
61
|
-
.lead-icon {
|
|
62
|
-
display: flex;
|
|
63
|
-
align-items: center;
|
|
64
|
-
height: 24px;
|
|
65
|
-
flex-shrink: 0;
|
|
66
|
-
color: var(--c-text-2);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.lead-icon-svg {
|
|
70
|
-
width: 16px;
|
|
71
|
-
height: 16px;
|
|
72
|
-
}
|
|
73
55
|
</style>
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
+
import { type Position } from '../composables/Tooltip'
|
|
4
|
+
import SFragment from './SFragment.vue'
|
|
5
|
+
import STooltip from './STooltip.vue'
|
|
3
6
|
|
|
4
7
|
export type Size =
|
|
5
8
|
| 'nano'
|
|
@@ -14,6 +17,7 @@ const props = defineProps<{
|
|
|
14
17
|
size?: Size
|
|
15
18
|
avatar?: string | null
|
|
16
19
|
name?: string | null
|
|
20
|
+
tooltip?: boolean | { position?: Position }
|
|
17
21
|
}>()
|
|
18
22
|
|
|
19
23
|
const classes = computed(() => [
|
|
@@ -22,13 +26,28 @@ const classes = computed(() => [
|
|
|
22
26
|
])
|
|
23
27
|
|
|
24
28
|
const initial = computed(() => props.name?.charAt(0).toUpperCase())
|
|
29
|
+
|
|
30
|
+
const tooltipPosition = computed(() => {
|
|
31
|
+
return (props.tooltip && typeof props.tooltip === 'object')
|
|
32
|
+
? props.tooltip.position || 'top'
|
|
33
|
+
: 'top'
|
|
34
|
+
})
|
|
25
35
|
</script>
|
|
26
36
|
|
|
27
37
|
<template>
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
<SFragment
|
|
39
|
+
:is="tooltip && name && STooltip"
|
|
40
|
+
:text="name"
|
|
41
|
+
:position="tooltipPosition"
|
|
42
|
+
display="block"
|
|
43
|
+
tag="div"
|
|
44
|
+
trigger-tag="div"
|
|
45
|
+
>
|
|
46
|
+
<div class="SAvatar" :class="classes">
|
|
47
|
+
<img v-if="avatar" class="img" :src="avatar">
|
|
48
|
+
<p v-else-if="initial" class="initial">{{ initial }}</p>
|
|
49
|
+
</div>
|
|
50
|
+
</SFragment>
|
|
32
51
|
</template>
|
|
33
52
|
|
|
34
53
|
<style lang="postcss" scoped>
|
|
@@ -36,8 +55,8 @@ const initial = computed(() => props.name?.charAt(0).toUpperCase())
|
|
|
36
55
|
display: flex;
|
|
37
56
|
justify-content: center;
|
|
38
57
|
align-items: center;
|
|
39
|
-
border-radius: 50%;
|
|
40
58
|
background-color: var(--c-bg-elv-1);
|
|
59
|
+
border-radius: 50%;
|
|
41
60
|
overflow: hidden;
|
|
42
61
|
}
|
|
43
62
|
|
|
@@ -45,6 +64,8 @@ const initial = computed(() => props.name?.charAt(0).toUpperCase())
|
|
|
45
64
|
object-fit: cover;
|
|
46
65
|
height: 100%;
|
|
47
66
|
width: 100%;
|
|
67
|
+
border-radius: 50%;
|
|
68
|
+
overflow: hidden;
|
|
48
69
|
}
|
|
49
70
|
|
|
50
71
|
.initial {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
+
import { type Position } from '../composables/Tooltip'
|
|
3
4
|
import SAvatar from './SAvatar.vue'
|
|
4
5
|
|
|
5
6
|
export type Size = 'mini' | 'small' | 'medium' | 'large' | 'jumbo'
|
|
@@ -8,6 +9,7 @@ const props = withDefaults(defineProps<{
|
|
|
8
9
|
size?: Size
|
|
9
10
|
avatars: { image?: string; name?: string }[]
|
|
10
11
|
avatarCount?: number
|
|
12
|
+
tooltip?: boolean | { position?: Position }
|
|
11
13
|
}>(), {
|
|
12
14
|
size: 'medium',
|
|
13
15
|
avatarCount: 2
|
|
@@ -30,6 +32,7 @@ const count = computed(() => {
|
|
|
30
32
|
:size="size"
|
|
31
33
|
:avatar="avatar.image"
|
|
32
34
|
:name="avatar.name"
|
|
35
|
+
:tooltip="tooltip"
|
|
33
36
|
/>
|
|
34
37
|
<div v-if="count" class="more">+{{ count }}</div>
|
|
35
38
|
</div>
|
|
@@ -39,16 +42,18 @@ const count = computed(() => {
|
|
|
39
42
|
.SAvatarStack {
|
|
40
43
|
display: flex;
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
border: 2px solid var(--c-bg-elv-2);
|
|
45
|
+
:slotted(.SAvatar), :deep(.SAvatar), .more {
|
|
44
46
|
flex-shrink: 0;
|
|
47
|
+
border: 2px solid var(--c-bg-elv-2);
|
|
48
|
+
border-radius: 50%;
|
|
49
|
+
overflow: hidden;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
&.mini >
|
|
48
|
-
&.small >
|
|
49
|
-
&.medium >
|
|
50
|
-
&.large >
|
|
51
|
-
&.jumbo >
|
|
52
|
+
&.mini > :deep(*):not(:last-child) { margin-right: -6px }
|
|
53
|
+
&.small > :deep(*):not(:last-child) { margin-right: -8px }
|
|
54
|
+
&.medium > :deep(*):not(:last-child) { margin-right: -8px }
|
|
55
|
+
&.large > :deep(*):not(:last-child) { margin-right: -12px }
|
|
56
|
+
&.jumbo > :deep(*):not(:last-child) { margin-right: -16px }
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
.more {
|
|
@@ -61,6 +66,8 @@ const count = computed(() => {
|
|
|
61
66
|
border-radius: 50%;
|
|
62
67
|
line-height: 1;
|
|
63
68
|
color: var(--c-text-2);
|
|
69
|
+
z-index: 1;
|
|
70
|
+
height: 100%;
|
|
64
71
|
|
|
65
72
|
.mini & { font-size: 10px }
|
|
66
73
|
.small & { font-size: 10px }
|
|
@@ -24,8 +24,10 @@ export type Mode =
|
|
|
24
24
|
|
|
25
25
|
export interface Tooltip {
|
|
26
26
|
tag?: string
|
|
27
|
+
triggerTag?: string
|
|
27
28
|
text?: MaybeRef<string | null>
|
|
28
29
|
position?: Position
|
|
30
|
+
display?: 'inline' | 'inline-block' | 'block'
|
|
29
31
|
trigger?: 'hover' | 'focus' | 'both'
|
|
30
32
|
timeout?: number
|
|
31
33
|
}
|
|
@@ -46,7 +48,7 @@ const props = defineProps<{
|
|
|
46
48
|
block?: boolean
|
|
47
49
|
loading?: boolean
|
|
48
50
|
disabled?: boolean
|
|
49
|
-
tooltip?: Tooltip
|
|
51
|
+
tooltip?: string | Tooltip
|
|
50
52
|
}>()
|
|
51
53
|
|
|
52
54
|
const emit = defineEmits<{
|
|
@@ -78,7 +80,10 @@ const computedTag = computed(() => {
|
|
|
78
80
|
const slots = useSlots()
|
|
79
81
|
|
|
80
82
|
const hasTooltip = computed(() => {
|
|
81
|
-
return
|
|
83
|
+
return !!(
|
|
84
|
+
slots['tooltip-text']
|
|
85
|
+
|| (typeof props.tooltip === 'object' ? unref(props.tooltip.text) : props.tooltip)
|
|
86
|
+
)
|
|
82
87
|
})
|
|
83
88
|
|
|
84
89
|
function handleClick(): void {
|
|
@@ -91,12 +96,12 @@ function handleClick(): void {
|
|
|
91
96
|
<template>
|
|
92
97
|
<SFragment
|
|
93
98
|
:is="hasTooltip && STooltip"
|
|
94
|
-
:tag="
|
|
95
|
-
:text="unref(
|
|
96
|
-
:position="
|
|
97
|
-
display="inline-block"
|
|
98
|
-
:trigger="
|
|
99
|
-
:timeout="
|
|
99
|
+
:tag="typeof tooltip === 'object' ? tooltip.tag : undefined"
|
|
100
|
+
:text="typeof tooltip === 'object' ? unref(tooltip.text) : tooltip"
|
|
101
|
+
:position="typeof tooltip === 'object' ? tooltip.position : undefined"
|
|
102
|
+
:display="typeof tooltip === 'object' ? tooltip.display ?? 'inline-block' : 'inline-block'"
|
|
103
|
+
:trigger="typeof tooltip === 'object' ? tooltip.trigger ?? 'both' : 'both'"
|
|
104
|
+
:timeout="typeof tooltip === 'object' ? tooltip.timeout : undefined"
|
|
100
105
|
:tabindex="-1"
|
|
101
106
|
>
|
|
102
107
|
<template v-if="$slots['tooltip-text']" #text><slot name="tooltip-text" /></template>
|
|
@@ -217,7 +222,7 @@ function handleClick(): void {
|
|
|
217
222
|
&.has-label { padding: var(--button-padding, 0 12px); }
|
|
218
223
|
&.has-label.has-lead-icon { padding: var(--button-padding, 0 10px 0 8px); }
|
|
219
224
|
&.has-label.has-trail-icon { padding: var(--button-padding, 0 8px 0 10px); }
|
|
220
|
-
.content { gap:
|
|
225
|
+
.content { gap: 8px; }
|
|
221
226
|
.icon-svg { width: 16px; height: 16px; }
|
|
222
227
|
}
|
|
223
228
|
|
|
@@ -230,7 +235,7 @@ function handleClick(): void {
|
|
|
230
235
|
&.has-label { padding: var(--button-padding, 0 16px); }
|
|
231
236
|
&.has-label.has-lead-icon { padding: var(--button-padding, 0 12px 0 10px); }
|
|
232
237
|
&.has-label.has-trail-icon { padding: var(--button-padding, 0 10px 0 12px); }
|
|
233
|
-
.content { gap:
|
|
238
|
+
.content { gap: 8px; }
|
|
234
239
|
.icon-svg { width: 18px; height: 18px; }
|
|
235
240
|
}
|
|
236
241
|
|
|
@@ -243,7 +248,7 @@ function handleClick(): void {
|
|
|
243
248
|
&.has-label { padding: var(--button-padding, 0 20px); }
|
|
244
249
|
&.has-label.has-lead-icon { padding: var(--button-padding, 0 14px 0 12px); }
|
|
245
250
|
&.has-label.has-trail-icon { padding: var(--button-padding, 0 12px 0 14px); }
|
|
246
|
-
.content { gap:
|
|
251
|
+
.content { gap: 8px; }
|
|
247
252
|
.icon-svg { width: 18px; height: 18px; }
|
|
248
253
|
}
|
|
249
254
|
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
+
import SLocalNavAvatar from './SLocalNavAvatar.vue'
|
|
4
|
+
import SLocalNavDescription from './SLocalNavDescription.vue'
|
|
3
5
|
import SLocalNavMenu, { type MenuItem } from './SLocalNavMenu.vue'
|
|
4
6
|
import SLocalNavTitle, { type Title } from './SLocalNavTitle.vue'
|
|
5
7
|
|
|
6
8
|
export type { Title, MenuItem }
|
|
7
9
|
|
|
10
|
+
export interface Avatar {
|
|
11
|
+
image?: string | null
|
|
12
|
+
name?: string | null
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
const props = defineProps<{
|
|
16
|
+
avatar?: Avatar
|
|
9
17
|
title: Title[]
|
|
18
|
+
description?: string
|
|
10
19
|
menu?: MenuItem[][]
|
|
11
20
|
}>()
|
|
12
21
|
|
|
@@ -20,7 +29,18 @@ const normalizedMenu = computed(() => {
|
|
|
20
29
|
|
|
21
30
|
<template>
|
|
22
31
|
<div class="SLocalNav" :class="{ 'has-menu': normalizedMenu }">
|
|
23
|
-
<
|
|
32
|
+
<div class="title-bar">
|
|
33
|
+
<div v-if="avatar" class="title-bar-avatar">
|
|
34
|
+
<SLocalNavAvatar
|
|
35
|
+
:image="avatar.image"
|
|
36
|
+
:name="avatar.name"
|
|
37
|
+
/>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="title-bar-body">
|
|
40
|
+
<SLocalNavTitle :title="title" />
|
|
41
|
+
<SLocalNavDescription v-if="description" :text="description" />
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
24
44
|
<SLocalNavMenu v-if="normalizedMenu" :menu="normalizedMenu" />
|
|
25
45
|
</div>
|
|
26
46
|
</template>
|
|
@@ -29,7 +49,7 @@ const normalizedMenu = computed(() => {
|
|
|
29
49
|
.SLocalNav {
|
|
30
50
|
display: flex;
|
|
31
51
|
flex-direction: column;
|
|
32
|
-
gap:
|
|
52
|
+
gap: 12px;
|
|
33
53
|
padding: 16px 24px;
|
|
34
54
|
background-color: var(--c-bg-elv-2);
|
|
35
55
|
|
|
@@ -45,4 +65,10 @@ const normalizedMenu = computed(() => {
|
|
|
45
65
|
padding-bottom: 0;
|
|
46
66
|
}
|
|
47
67
|
}
|
|
68
|
+
|
|
69
|
+
.title-bar {
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
gap: 16px;
|
|
73
|
+
}
|
|
48
74
|
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import SAvatar from './SAvatar.vue'
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
image?: string | null
|
|
6
|
+
name?: string | null
|
|
7
|
+
}>()
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div class="SLocalNavAvatar">
|
|
12
|
+
<SAvatar
|
|
13
|
+
size="fill"
|
|
14
|
+
:avatar="image"
|
|
15
|
+
:name="name"
|
|
16
|
+
/>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<style scoped lang="postcss">
|
|
21
|
+
.SLocalNavAvatar {
|
|
22
|
+
width: 64px;
|
|
23
|
+
height: 64px;
|
|
24
|
+
}
|
|
25
|
+
</style>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{
|
|
3
|
+
text: string
|
|
4
|
+
}>()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<div class="SLocalNavDescription">
|
|
9
|
+
{{ text }}
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<style scoped lang="postcss">
|
|
14
|
+
.SLocalNavDescription {
|
|
15
|
+
line-height: 24px;
|
|
16
|
+
font-size: 14px;
|
|
17
|
+
color: var(--c-text-2);
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
@@ -101,6 +101,7 @@ const computedCell = computed<TableCell | undefined>(() =>
|
|
|
101
101
|
:color="computedCell.color"
|
|
102
102
|
:avatar-count="computedCell.avatarCount"
|
|
103
103
|
:name-count="computedCell.nameCount"
|
|
104
|
+
:tooltip="computedCell.tooltip"
|
|
104
105
|
/>
|
|
105
106
|
<STableCellActions
|
|
106
107
|
v-else-if="computedCell.type === 'actions'"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { type TableCellAvatarsOption } from '../composables/Table'
|
|
4
|
+
import { type Position } from '../composables/Tooltip'
|
|
4
5
|
import SAvatar from './SAvatar.vue'
|
|
5
6
|
|
|
6
7
|
const props = withDefaults(defineProps<{
|
|
@@ -10,6 +11,7 @@ const props = withDefaults(defineProps<{
|
|
|
10
11
|
color?: 'neutral' | 'soft' | 'mute'
|
|
11
12
|
avatarCount?: number
|
|
12
13
|
nameCount?: number
|
|
14
|
+
tooltip?: boolean | { position?: Position }
|
|
13
15
|
}>(), {
|
|
14
16
|
avatarCount: 2,
|
|
15
17
|
nameCount: 2
|
|
@@ -61,7 +63,7 @@ const displayNames = computed(() => {
|
|
|
61
63
|
class="avatar"
|
|
62
64
|
>
|
|
63
65
|
<div class="avatar-box">
|
|
64
|
-
<SAvatar size="mini" :avatar="avatar.image" :name="avatar.name" />
|
|
66
|
+
<SAvatar size="mini" :avatar="avatar.image" :name="avatar.name" :tooltip="tooltip" />
|
|
65
67
|
</div>
|
|
66
68
|
</div>
|
|
67
69
|
<div v-if="avatarDiff > 0" class="avatar">
|
|
@@ -5,6 +5,7 @@ import { type Position, useTooltip } from '../composables/Tooltip'
|
|
|
5
5
|
|
|
6
6
|
const props = withDefaults(defineProps<{
|
|
7
7
|
tag?: string
|
|
8
|
+
triggerTag?: string
|
|
8
9
|
text?: string
|
|
9
10
|
position?: Position
|
|
10
11
|
display?: 'inline' | 'inline-block' | 'block'
|
|
@@ -13,6 +14,7 @@ const props = withDefaults(defineProps<{
|
|
|
13
14
|
tabindex?: number
|
|
14
15
|
}>(), {
|
|
15
16
|
tag: 'span',
|
|
17
|
+
triggerTag: 'span',
|
|
16
18
|
position: 'top',
|
|
17
19
|
trigger: 'hover'
|
|
18
20
|
})
|
|
@@ -96,9 +98,9 @@ onBeforeUnmount(() => {
|
|
|
96
98
|
|
|
97
99
|
<template>
|
|
98
100
|
<component ref="root" :is="tag" class="STooltip" :class="rootClasses" :tabindex="tabindex">
|
|
99
|
-
<
|
|
101
|
+
<component :is="triggerTag" class="trigger" ref="trigger">
|
|
100
102
|
<slot />
|
|
101
|
-
</
|
|
103
|
+
</component>
|
|
102
104
|
|
|
103
105
|
<Teleport to="#sefirot-modals">
|
|
104
106
|
<Transition name="fade">
|
|
@@ -123,9 +125,20 @@ onBeforeUnmount(() => {
|
|
|
123
125
|
cursor: pointer;
|
|
124
126
|
}
|
|
125
127
|
|
|
126
|
-
&.inline
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
&.inline {
|
|
129
|
+
& { display: inline; }
|
|
130
|
+
.trigger { display: inline; }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
&.inline-block {
|
|
134
|
+
& { display: inline-block; }
|
|
135
|
+
.trigger { display: inline-block; }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&.block {
|
|
139
|
+
& { display: block; }
|
|
140
|
+
.trigger { display: block; }
|
|
141
|
+
}
|
|
129
142
|
}
|
|
130
143
|
|
|
131
144
|
.trigger {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import MarkdownIt from 'markdown-it'
|
|
1
|
+
import MarkdownIt, { type Options as MarkdownItOptions } from 'markdown-it'
|
|
2
2
|
import { type Ref, onUnmounted } from 'vue'
|
|
3
3
|
import { useRouter } from 'vue-router'
|
|
4
4
|
import { type LinkAttrs, isCallbackUrl, isExternalUrl, linkPlugin } from './markdown/LinkPlugin'
|
|
5
5
|
|
|
6
6
|
export type UseMarkdown = (source: string, inline: boolean) => string
|
|
7
7
|
|
|
8
|
-
export interface UseMarkdownOptions extends
|
|
8
|
+
export interface UseMarkdownOptions extends MarkdownItOptions {
|
|
9
9
|
linkAttrs?: LinkAttrs
|
|
10
10
|
config?: (md: MarkdownIt) => void
|
|
11
11
|
}
|
package/lib/composables/Table.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type Component, type MaybeRef, type MaybeRefOrGetter } from 'vue'
|
|
|
2
2
|
import { type Mode } from '../components/SButton.vue'
|
|
3
3
|
import { type Day } from '../support/Day'
|
|
4
4
|
import { type DropdownSection } from './Dropdown'
|
|
5
|
+
import { type Position } from './Tooltip'
|
|
5
6
|
|
|
6
7
|
export interface Table<
|
|
7
8
|
O extends string = string,
|
|
@@ -163,6 +164,7 @@ export interface TableCellAvatars<V = any, R = any> extends TableCellBase {
|
|
|
163
164
|
color?: 'neutral' | 'soft' | 'mute'
|
|
164
165
|
avatarCount?: number
|
|
165
166
|
nameCount?: number
|
|
167
|
+
tooltip?: boolean | { position?: Position }
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
export interface TableCellAvatarsOption {
|
package/lib/http/Http.ts
CHANGED
|
@@ -15,6 +15,7 @@ export interface HttpOptions {
|
|
|
15
15
|
xsrfUrl?: string | false
|
|
16
16
|
client?: HttpClient
|
|
17
17
|
lang?: Lang
|
|
18
|
+
payloadKey?: string
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export class Http {
|
|
@@ -22,6 +23,7 @@ export class Http {
|
|
|
22
23
|
private static xsrfUrl: string | false = '/api/csrf-cookie'
|
|
23
24
|
private static client: HttpClient = ofetch
|
|
24
25
|
private static lang: Lang | undefined = undefined
|
|
26
|
+
private static payloadKey = '__payload__'
|
|
25
27
|
|
|
26
28
|
static config(options: HttpOptions) {
|
|
27
29
|
if (options.baseUrl) {
|
|
@@ -36,6 +38,9 @@ export class Http {
|
|
|
36
38
|
if (options.lang) {
|
|
37
39
|
Http.lang = options.lang
|
|
38
40
|
}
|
|
41
|
+
if (options.payloadKey) {
|
|
42
|
+
Http.payloadKey = options.payloadKey
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
private async ensureXsrfToken(): Promise<string | undefined> {
|
|
@@ -101,6 +106,26 @@ export class Http {
|
|
|
101
106
|
}
|
|
102
107
|
|
|
103
108
|
async post<T = any>(url: string, body?: any, options?: FetchOptions): Promise<T> {
|
|
109
|
+
if (body && !(body instanceof FormData)) {
|
|
110
|
+
let hasFile = false
|
|
111
|
+
|
|
112
|
+
const payload = JSON.stringify(body, (_, value) => {
|
|
113
|
+
if (value instanceof Blob) {
|
|
114
|
+
hasFile = true
|
|
115
|
+
return undefined
|
|
116
|
+
}
|
|
117
|
+
return value
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
if (hasFile) {
|
|
121
|
+
const formData = this.objectToFormData(body, undefined, undefined, true)
|
|
122
|
+
formData.append(Http.payloadKey, payload)
|
|
123
|
+
body = formData
|
|
124
|
+
} else {
|
|
125
|
+
body = payload
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
104
129
|
return this.performRequest<T>(url, { method: 'POST', body, ...options })
|
|
105
130
|
}
|
|
106
131
|
|
|
@@ -117,13 +142,7 @@ export class Http {
|
|
|
117
142
|
}
|
|
118
143
|
|
|
119
144
|
async upload<T = any>(url: string, body?: any, options?: FetchOptions): Promise<T> {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return this.performRequest<T>(url, {
|
|
123
|
-
method: 'POST',
|
|
124
|
-
body: formData,
|
|
125
|
-
...options
|
|
126
|
-
})
|
|
145
|
+
return this.post<T>(url, this.objectToFormData(body), options)
|
|
127
146
|
}
|
|
128
147
|
|
|
129
148
|
async download(url: string, options?: FetchOptions): Promise<void> {
|
|
@@ -143,7 +162,7 @@ export class Http {
|
|
|
143
162
|
FileSaver.saveAs(blob, filename as string)
|
|
144
163
|
}
|
|
145
164
|
|
|
146
|
-
private objectToFormData(obj: any, form?: FormData, namespace?: string) {
|
|
165
|
+
private objectToFormData(obj: any, form?: FormData, namespace?: string, onlyFiles = false) {
|
|
147
166
|
const fd = form || new FormData()
|
|
148
167
|
let formKey: string
|
|
149
168
|
|
|
@@ -163,9 +182,12 @@ export class Http {
|
|
|
163
182
|
&& !(obj[property] instanceof Blob)
|
|
164
183
|
&& obj[property] !== null
|
|
165
184
|
) {
|
|
166
|
-
this.objectToFormData(obj[property], fd, property)
|
|
185
|
+
this.objectToFormData(obj[property], fd, property, onlyFiles)
|
|
167
186
|
} else {
|
|
168
187
|
const value = obj[property] === null ? '' : obj[property]
|
|
188
|
+
if (onlyFiles && !(value instanceof Blob)) {
|
|
189
|
+
return
|
|
190
|
+
}
|
|
169
191
|
fd.append(formKey, value)
|
|
170
192
|
}
|
|
171
193
|
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalbrain/sefirot",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"packageManager": "pnpm@9.0
|
|
3
|
+
"version": "3.47.0",
|
|
4
|
+
"packageManager": "pnpm@9.1.0",
|
|
5
5
|
"description": "Vue Components for Global Brain Design System.",
|
|
6
6
|
"author": "Kia Ishii <ka.ishii@globalbrains.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"@iconify/vue": "^4.1.2",
|
|
46
46
|
"@types/body-scroll-lock": "^3.1.2",
|
|
47
47
|
"@types/lodash-es": "^4.17.12",
|
|
48
|
-
"@types/markdown-it": "^14.
|
|
49
|
-
"@vue/reactivity": "^3.4.
|
|
50
|
-
"@vue/runtime-core": "^3.4.
|
|
48
|
+
"@types/markdown-it": "^14.1.1",
|
|
49
|
+
"@vue/reactivity": "^3.4.27",
|
|
50
|
+
"@vue/runtime-core": "^3.4.27",
|
|
51
51
|
"@vuelidate/core": "^2.0.3",
|
|
52
52
|
"@vuelidate/validators": "^2.0.4",
|
|
53
53
|
"@vueuse/core": "^10.9.0",
|
|
@@ -60,17 +60,17 @@
|
|
|
60
60
|
"postcss": "^8.4.38",
|
|
61
61
|
"postcss-nested": "^6.0.1",
|
|
62
62
|
"v-calendar": "^3.1.2",
|
|
63
|
-
"vue": "^3.4.
|
|
63
|
+
"vue": "^3.4.27",
|
|
64
64
|
"vue-router": "^4.3.2"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@sentry/browser": "^8.0.0-
|
|
67
|
+
"@sentry/browser": "^8.0.0-rc.2",
|
|
68
68
|
"@tanstack/vue-virtual": "3.0.0-beta.62",
|
|
69
69
|
"@tinyhttp/content-disposition": "^2.2.0",
|
|
70
70
|
"@tinyhttp/cookie": "^2.1.0",
|
|
71
71
|
"@types/file-saver": "^2.0.7",
|
|
72
72
|
"@types/qs": "^6.9.15",
|
|
73
|
-
"dayjs": "^1.11.
|
|
73
|
+
"dayjs": "^1.11.11",
|
|
74
74
|
"file-saver": "^2.0.5",
|
|
75
75
|
"ofetch": "^1.3.4",
|
|
76
76
|
"qs": "^6.12.1"
|
|
@@ -84,20 +84,20 @@
|
|
|
84
84
|
"@release-it/conventional-changelog": "^8.0.1",
|
|
85
85
|
"@types/body-scroll-lock": "^3.1.2",
|
|
86
86
|
"@types/lodash-es": "^4.17.12",
|
|
87
|
-
"@types/markdown-it": "^14.
|
|
88
|
-
"@types/node": "^20.12.
|
|
87
|
+
"@types/markdown-it": "^14.1.1",
|
|
88
|
+
"@types/node": "^20.12.11",
|
|
89
89
|
"@vitejs/plugin-vue": "^5.0.4",
|
|
90
|
-
"@vitest/coverage-v8": "^1.
|
|
91
|
-
"@vue/reactivity": "^3.4.
|
|
92
|
-
"@vue/runtime-core": "^3.4.
|
|
93
|
-
"@vue/test-utils": "^2.4.
|
|
90
|
+
"@vitest/coverage-v8": "^1.6.0",
|
|
91
|
+
"@vue/reactivity": "^3.4.27",
|
|
92
|
+
"@vue/runtime-core": "^3.4.27",
|
|
93
|
+
"@vue/test-utils": "^2.4.6",
|
|
94
94
|
"@vuelidate/core": "^2.0.3",
|
|
95
95
|
"@vuelidate/validators": "^2.0.4",
|
|
96
96
|
"@vueuse/core": "^10.9.0",
|
|
97
97
|
"body-scroll-lock": "4.0.0-beta.0",
|
|
98
98
|
"eslint": "^8.57.0",
|
|
99
99
|
"fuse.js": "^7.0.0",
|
|
100
|
-
"happy-dom": "^14.
|
|
100
|
+
"happy-dom": "^14.10.1",
|
|
101
101
|
"histoire": "0.16.5",
|
|
102
102
|
"lodash-es": "^4.17.21",
|
|
103
103
|
"markdown-it": "^14.1.0",
|
|
@@ -106,13 +106,13 @@
|
|
|
106
106
|
"postcss": "^8.4.38",
|
|
107
107
|
"postcss-nested": "^6.0.1",
|
|
108
108
|
"punycode": "^2.3.1",
|
|
109
|
-
"release-it": "^17.2.
|
|
109
|
+
"release-it": "^17.2.1",
|
|
110
110
|
"typescript": "~5.4.5",
|
|
111
111
|
"v-calendar": "^3.1.2",
|
|
112
|
-
"vite": "^5.2.
|
|
113
|
-
"vitepress": "^1.1.
|
|
114
|
-
"vitest": "^1.
|
|
115
|
-
"vue": "^3.4.
|
|
112
|
+
"vite": "^5.2.11",
|
|
113
|
+
"vitepress": "^1.1.4",
|
|
114
|
+
"vitest": "^1.6.0",
|
|
115
|
+
"vue": "^3.4.27",
|
|
116
116
|
"vue-router": "^4.3.2",
|
|
117
117
|
"vue-tsc": "^1.8.27"
|
|
118
118
|
}
|