@globalbrain/sefirot 2.0.0-draft.8 → 2.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.
- package/README.md +6 -6
- package/lib/components/SAvatar.vue +17 -17
- package/lib/components/SButton.vue +512 -267
- package/lib/components/SButtonGroup.vue +149 -0
- package/lib/components/SDropdown.vue +26 -150
- package/lib/components/SDropdownSection.vue +48 -0
- package/lib/components/SDropdownSectionFilter.vue +189 -0
- package/lib/components/SDropdownSectionFilterItem.vue +21 -0
- package/lib/components/SDropdownSectionFilterItemAvatar.vue +31 -0
- package/lib/components/SDropdownSectionFilterItemText.vue +20 -0
- package/lib/components/SDropdownSectionMenu.vue +39 -0
- package/lib/components/SIcon.vue +13 -0
- package/lib/components/SInputBase.vue +31 -31
- package/lib/components/SInputCheckbox.vue +1 -1
- package/lib/components/SInputCheckboxes.vue +74 -0
- package/lib/components/SInputDate.vue +182 -0
- package/lib/components/SInputDropdown.vue +158 -157
- package/lib/components/SInputDropdownItem.vue +46 -48
- package/lib/components/{SInputDropdownItemUserTag.vue → SInputDropdownItemAvatar.vue} +43 -44
- package/lib/components/SInputDropdownItemText.vue +79 -16
- package/lib/components/SInputFile.vue +55 -60
- package/lib/components/SInputHMS.vue +120 -110
- package/lib/components/SInputNumber.vue +38 -9
- package/lib/components/SInputRadio.vue +39 -36
- package/lib/components/SInputRadios.vue +40 -53
- package/lib/components/SInputSelect.vue +3 -3
- package/lib/components/SInputSwitch.vue +193 -0
- package/lib/components/SInputSwitches.vue +88 -0
- package/lib/components/SInputText.vue +206 -62
- package/lib/components/SInputTextarea.vue +46 -32
- package/lib/components/SInputYMD.vue +123 -126
- package/lib/components/SMarkdown.vue +52 -0
- package/lib/components/SModal.vue +25 -63
- package/lib/components/SMount.vue +19 -0
- package/lib/components/SSheet.vue +49 -55
- package/lib/components/SSheetFooter.vue +1 -1
- package/lib/components/SSheetFooterAction.vue +24 -17
- package/lib/components/SSheetFooterActions.vue +1 -4
- package/lib/components/SSheetForm.vue +15 -0
- package/lib/components/SSheetMedium.vue +8 -10
- package/lib/components/SSheetTitle.vue +7 -14
- package/lib/components/SSnackbar.vue +55 -45
- package/lib/components/{SPortalSnackbars.vue → SSnackbars.vue} +17 -20
- package/lib/components/SStep.vue +106 -0
- package/lib/components/SSteps.vue +59 -0
- package/lib/components/STable.vue +241 -0
- package/lib/components/STableCell.vue +82 -0
- package/lib/components/STableCellAvatar.vue +69 -0
- package/lib/components/STableCellAvatars.vue +93 -0
- package/lib/components/STableCellDay.vue +40 -0
- package/lib/components/STableCellPill.vue +84 -0
- package/lib/components/STableCellText.vue +102 -0
- package/lib/components/STableColumn.vue +255 -0
- package/lib/components/STableFooter.vue +115 -0
- package/lib/components/STableHeader.vue +74 -0
- package/lib/components/STableItem.vue +38 -0
- package/lib/components/STooltip.vue +112 -0
- package/lib/composables/Dropdown.ts +40 -99
- package/lib/composables/Form.ts +21 -18
- package/lib/composables/Grid.ts +117 -0
- package/lib/composables/Markdown.ts +138 -0
- package/lib/composables/Step.ts +7 -0
- package/lib/composables/Table.ts +103 -0
- package/lib/composables/Tooltip.ts +91 -0
- package/lib/composables/Validation.ts +5 -9
- package/lib/composables/markdown/LinkPlugin.ts +45 -0
- package/lib/mixins/Sheet.ts +5 -3
- package/lib/stores/Snackbars.ts +48 -0
- package/lib/{assets/styles → styles}/base.css +0 -0
- package/lib/{assets/styles → styles}/bootstrap.css +1 -0
- package/lib/{assets/styles → styles}/variables.css +55 -48
- package/lib/support/Day.ts +8 -0
- package/lib/support/Num.ts +3 -0
- package/lib/support/Time.ts +5 -2
- package/lib/support/Utils.ts +4 -3
- package/lib/types/shims.d.ts +3 -0
- package/lib/validation/validators/requiredYmd.ts +1 -1
- package/lib/validation/validators/ymd.ts +4 -4
- package/package.json +57 -37
- package/CHANGELOG.md +0 -47
- package/lib/.DS_Store +0 -0
- package/lib/components/.DS_Store +0 -0
- package/lib/components/SDialog.vue +0 -140
- package/lib/components/SDropdownItem.vue +0 -78
- package/lib/components/SDropdownItemText.vue +0 -22
- package/lib/components/SDropdownItemUser.vue +0 -40
- package/lib/components/SInputDropdownItemTextTag.vue +0 -94
- package/lib/components/SInputDropdownItemUser.vue +0 -41
- package/lib/components/SPortalModals.vue +0 -74
- package/lib/components/icons/.DS_Store +0 -0
- package/lib/composables/Dialog.ts +0 -38
- package/lib/composables/Modal.ts +0 -34
- package/lib/composables/Snackbar.ts +0 -18
- package/lib/store/Sefirot.ts +0 -17
- package/lib/store/dialog/index.ts +0 -42
- package/lib/store/modal/index.ts +0 -61
- package/lib/store/snackbars/index.ts +0 -70
|
@@ -1,27 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import SButton, { Type, Mode } from './SButton.vue'
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
type?: Type
|
|
6
|
+
mode?: Mode
|
|
7
|
+
label: string
|
|
8
|
+
loading?: boolean
|
|
9
|
+
}>()
|
|
10
|
+
|
|
11
|
+
defineEmits<{
|
|
12
|
+
(e: 'click'): void
|
|
13
|
+
}>()
|
|
14
|
+
</script>
|
|
15
|
+
|
|
1
16
|
<template>
|
|
2
17
|
<div class="SSheetFooterAction">
|
|
3
18
|
<SButton
|
|
4
|
-
size="
|
|
5
|
-
:type="type
|
|
6
|
-
:mode="mode
|
|
19
|
+
size="medium"
|
|
20
|
+
:type="type"
|
|
21
|
+
:mode="mode"
|
|
7
22
|
:label="label"
|
|
23
|
+
:loading="loading"
|
|
8
24
|
block
|
|
9
25
|
@click="$emit('click')"
|
|
10
26
|
/>
|
|
11
27
|
</div>
|
|
12
28
|
</template>
|
|
13
29
|
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
defineProps<{
|
|
21
|
-
type?: Type
|
|
22
|
-
mode?: Mode
|
|
23
|
-
label?: string
|
|
24
|
-
}>()
|
|
25
|
-
|
|
26
|
-
defineEmits(['click'])
|
|
27
|
-
</script>
|
|
30
|
+
<style scoped lang="postcss">
|
|
31
|
+
.SSheetFooterAction {
|
|
32
|
+
min-width: 88px;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
@@ -4,20 +4,17 @@
|
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
|
-
<style lang="postcss"
|
|
7
|
+
<style scoped lang="postcss">
|
|
8
8
|
.SSheetMedium {
|
|
9
|
-
padding:
|
|
9
|
+
padding: 32px;
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
padding:
|
|
11
|
+
.SSheetTitle + & {
|
|
12
|
+
padding-top: 0;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
.SSheetMedium :deep(p) {
|
|
17
|
-
margin: 16px
|
|
18
|
-
line-height: 24px;
|
|
19
|
-
font-size: 14px;
|
|
20
|
-
font-weight: 400;
|
|
17
|
+
margin-bottom: 16px;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
20
|
.SSheetMedium :deep(p:first-child) {
|
|
@@ -49,7 +46,7 @@
|
|
|
49
46
|
.SSheetMedium :deep(li) {
|
|
50
47
|
position: relative;
|
|
51
48
|
padding-left: 20px;
|
|
52
|
-
font-size:
|
|
49
|
+
font-size: 16px;
|
|
53
50
|
font-weight: 400;
|
|
54
51
|
}
|
|
55
52
|
|
|
@@ -65,10 +62,11 @@
|
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
.SSheetMedium :deep(li + li) {
|
|
68
|
-
margin-top:
|
|
65
|
+
margin-top: 8px;
|
|
69
66
|
}
|
|
70
67
|
|
|
71
68
|
.SSheetMedium :deep(li > ul) {
|
|
72
69
|
margin: 4px 0 0;
|
|
70
|
+
margin-bottom: 16px;
|
|
73
71
|
}
|
|
74
72
|
</style>
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
</h1>
|
|
6
|
-
</header>
|
|
2
|
+
<div class="SSheetTitle">
|
|
3
|
+
<p class="title"><slot /></p>
|
|
4
|
+
</div>
|
|
7
5
|
</template>
|
|
8
6
|
|
|
9
|
-
<style lang="postcss"
|
|
10
|
-
.
|
|
11
|
-
padding:
|
|
12
|
-
line-height: 28px;
|
|
7
|
+
<style scoped lang="postcss">
|
|
8
|
+
.SSheetTitle {
|
|
9
|
+
padding: 32px 32px 16px;
|
|
13
10
|
font-size: 20px;
|
|
14
|
-
font-weight:
|
|
15
|
-
|
|
16
|
-
@media (min-width: 512px) {
|
|
17
|
-
padding: 24px 64px 0 24px;
|
|
18
|
-
}
|
|
11
|
+
font-weight: 600;
|
|
19
12
|
}
|
|
20
13
|
</style>
|
|
@@ -1,77 +1,84 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { SnackbarAction, useSnackbars } from '../stores/Snackbars'
|
|
3
|
+
import SButton from './SButton.vue'
|
|
4
|
+
import SIconX from './icons/SIconX.vue'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
id: number
|
|
8
|
+
mode?: 'neutral' | 'info' | 'warning' | 'danger'
|
|
9
|
+
text: string
|
|
10
|
+
actions?: SnackbarAction[]
|
|
11
|
+
}>()
|
|
12
|
+
|
|
13
|
+
const snackbars = useSnackbars()
|
|
14
|
+
|
|
15
|
+
function close() {
|
|
16
|
+
snackbars.pop(props.id)
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
1
20
|
<template>
|
|
2
|
-
<div class="SSnackbar">
|
|
21
|
+
<div class="SSnackbar" :class="[mode ?? 'neutral']">
|
|
3
22
|
<button class="close" @click="close">
|
|
4
23
|
<SIconX class="close-icon" />
|
|
5
24
|
</button>
|
|
6
25
|
|
|
7
|
-
<p class="content">
|
|
26
|
+
<p class="content">
|
|
27
|
+
{{ text }}
|
|
28
|
+
</p>
|
|
8
29
|
|
|
9
30
|
<div v-if="actions" class="actions">
|
|
10
31
|
<div v-for="(action, index) in actions" :key="index" class="action">
|
|
11
32
|
<SButton
|
|
12
|
-
|
|
33
|
+
size="medium"
|
|
34
|
+
type="text"
|
|
13
35
|
:label="action.label"
|
|
14
|
-
|
|
15
|
-
@click="handleCallback(action)"
|
|
36
|
+
@click="action.onClick"
|
|
16
37
|
/>
|
|
17
38
|
</div>
|
|
18
39
|
</div>
|
|
19
40
|
</div>
|
|
20
41
|
</template>
|
|
21
42
|
|
|
22
|
-
<
|
|
23
|
-
import { PropType } from 'vue'
|
|
24
|
-
import { useStore } from 'vuex'
|
|
25
|
-
import { Action } from '../store/snackbars'
|
|
26
|
-
import SIconX from './icons/SIconX.vue'
|
|
27
|
-
import SButton from './SButton.vue'
|
|
28
|
-
|
|
29
|
-
const props = defineProps({
|
|
30
|
-
id: { type: Number, required: true },
|
|
31
|
-
text: { type: String, required: true },
|
|
32
|
-
actions: { type: Array as PropType<Action[]>, default: null }
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
const store = useStore()
|
|
36
|
-
|
|
37
|
-
function close() {
|
|
38
|
-
store.dispatch('snackbars/pop', props.id)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function handleCallback(action: Action) {
|
|
42
|
-
action.callback()
|
|
43
|
-
}
|
|
44
|
-
</script>
|
|
45
|
-
|
|
46
|
-
<style lang="postcss" scoped>
|
|
43
|
+
<style scoped lang="postcss">
|
|
47
44
|
.SSnackbar {
|
|
48
45
|
position: relative;
|
|
49
|
-
border: 1px solid
|
|
50
|
-
border-radius:
|
|
46
|
+
border: 1px solid var(--c-divider-light);
|
|
47
|
+
border-radius: 6px;
|
|
51
48
|
width: 100%;
|
|
52
|
-
color: var(--c-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
background-color: var(--c-bg-elv-up);
|
|
50
|
+
box-shadow: var(--shadow-depth-3);
|
|
51
|
+
overflow: hidden;
|
|
52
|
+
|
|
53
|
+
&::before {
|
|
54
|
+
position: absolute;
|
|
55
|
+
top: 0;
|
|
56
|
+
left: 0;
|
|
57
|
+
bottom: 0;
|
|
58
|
+
width: 3px;
|
|
59
|
+
content: "";
|
|
60
|
+
}
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
&.neutral::before { background-color: var(--c-gray); }
|
|
63
|
+
&.info::before { background-color: var(--c-info); }
|
|
64
|
+
&.warning::before { background-color: var(--c-warning); }
|
|
65
|
+
&.danger::before { background-color: var(--c-danger); }
|
|
59
66
|
}
|
|
60
67
|
|
|
61
68
|
.close {
|
|
62
69
|
position: absolute;
|
|
63
|
-
top:
|
|
64
|
-
right:
|
|
70
|
+
top: 2px;
|
|
71
|
+
right: 0;
|
|
65
72
|
z-index: 20;
|
|
66
73
|
display: flex;
|
|
67
74
|
justify-content: center;
|
|
68
75
|
align-items: center;
|
|
69
76
|
width: 48px;
|
|
70
|
-
height:
|
|
77
|
+
height: 45px;
|
|
71
78
|
|
|
72
79
|
&:hover {
|
|
73
80
|
.close-icon {
|
|
74
|
-
fill: var(--c-text-
|
|
81
|
+
fill: var(--c-text-1);
|
|
75
82
|
}
|
|
76
83
|
}
|
|
77
84
|
}
|
|
@@ -79,26 +86,29 @@ function handleCallback(action: Action) {
|
|
|
79
86
|
.close-icon {
|
|
80
87
|
width: 16px;
|
|
81
88
|
height: 16px;
|
|
82
|
-
fill: var(--c-text-
|
|
89
|
+
fill: var(--c-text-3);
|
|
83
90
|
transition: fill .25s;
|
|
84
91
|
}
|
|
85
92
|
|
|
86
93
|
.content {
|
|
87
94
|
position: relative;
|
|
88
95
|
z-index: 10;
|
|
89
|
-
padding:
|
|
96
|
+
padding: 14px 68px 14px 16px;
|
|
97
|
+
line-height: 20px;
|
|
90
98
|
font-size: 14px;
|
|
99
|
+
color: var(--c-text-1);
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
.actions {
|
|
94
103
|
display: flex;
|
|
95
104
|
justify-content: flex-end;
|
|
105
|
+
margin-top: -8px;
|
|
96
106
|
padding: 0 8px 8px;
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
.action {
|
|
100
110
|
& + & {
|
|
101
|
-
padding-left:
|
|
111
|
+
padding-left: 4px;
|
|
102
112
|
}
|
|
103
113
|
}
|
|
104
114
|
</style>
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useSnackbars } from '../stores/Snackbars'
|
|
3
|
+
import SSnackbar from './SSnackbar.vue'
|
|
4
|
+
|
|
5
|
+
const snackbars = useSnackbars()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
1
8
|
<template>
|
|
2
9
|
<transition name="fade">
|
|
3
|
-
<div v-if="
|
|
10
|
+
<div v-if="snackbars.items.length" class="SSnackbars">
|
|
4
11
|
<transition-group name="fade-up">
|
|
5
|
-
<div v-for="item in items" :key="item.id" class="item">
|
|
12
|
+
<div v-for="item in snackbars.items" :key="item.id" class="item">
|
|
6
13
|
<SSnackbar
|
|
7
14
|
:id="item.id"
|
|
15
|
+
:mode="item.mode"
|
|
8
16
|
:text="item.text"
|
|
9
17
|
:actions="item.actions"
|
|
10
18
|
/>
|
|
@@ -14,19 +22,8 @@
|
|
|
14
22
|
</transition>
|
|
15
23
|
</template>
|
|
16
24
|
|
|
17
|
-
<script setup lang="ts">
|
|
18
|
-
import { computed } from 'vue'
|
|
19
|
-
import { useStore } from 'vuex'
|
|
20
|
-
import SSnackbar from './SSnackbar.vue'
|
|
21
|
-
|
|
22
|
-
const store = useStore()
|
|
23
|
-
|
|
24
|
-
const items = computed(() => store.state.snackbars.items)
|
|
25
|
-
const hasItem = computed(() => items.value.length > 0)
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
25
|
<style lang="postcss" scoped>
|
|
29
|
-
.
|
|
26
|
+
.SSnackbars {
|
|
30
27
|
position: fixed;
|
|
31
28
|
bottom: 0;
|
|
32
29
|
left: 0;
|
|
@@ -34,26 +31,26 @@ const hasItem = computed(() => items.value.length > 0)
|
|
|
34
31
|
padding: 16px;
|
|
35
32
|
width: 100%;
|
|
36
33
|
max-width: 560px;
|
|
37
|
-
transition: opacity .25s, transform .25s;
|
|
34
|
+
transition: opacity 0.25s, transform 0.25s;
|
|
38
35
|
|
|
39
36
|
@media (min-width: 768px) {
|
|
40
37
|
padding: 24px;
|
|
41
38
|
}
|
|
42
39
|
}
|
|
43
40
|
|
|
44
|
-
.
|
|
41
|
+
.SSnackbars.fade-enter-from {
|
|
45
42
|
opacity: 0;
|
|
46
|
-
transform: translateY(
|
|
43
|
+
transform: translateY(24px);
|
|
47
44
|
}
|
|
48
45
|
|
|
49
|
-
.
|
|
46
|
+
.SSnackbars.fade-leave-to {
|
|
50
47
|
opacity: 0;
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
.item {
|
|
54
51
|
width: 100%;
|
|
55
52
|
max-width: 512px;
|
|
56
|
-
transition: opacity .25s, transform .25s;
|
|
53
|
+
transition: opacity 0.25s, transform 0.25s;
|
|
57
54
|
|
|
58
55
|
& + & {
|
|
59
56
|
padding-top: 8px;
|
|
@@ -70,6 +67,6 @@ const hasItem = computed(() => items.value.length > 0)
|
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
.item.fade-up-enter-from {
|
|
73
|
-
transform: translateY(
|
|
70
|
+
transform: translateY(24px);
|
|
74
71
|
}
|
|
75
72
|
</style>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="SStep" :class="[status]">
|
|
3
|
+
<div class="indicator">
|
|
4
|
+
<div class="bar" :class="[barLeft]" />
|
|
5
|
+
<div class="point">
|
|
6
|
+
<div v-if="status === 'active'" class="inner-dot" />
|
|
7
|
+
<SIconCheck v-else-if="status === 'done'" class="icon" />
|
|
8
|
+
<SIconX v-else-if="status === 'failed'" class="icon" />
|
|
9
|
+
</div>
|
|
10
|
+
<div class="bar" :class="[barRight]" />
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<p v-if="text" class="text">{{ text }}</p>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
import { PropType } from 'vue'
|
|
19
|
+
import { StepStatus, BarMode } from '../composables/Step'
|
|
20
|
+
import SIconCheck from './icons/SIconCheck.vue'
|
|
21
|
+
import SIconX from './icons/SIconX.vue'
|
|
22
|
+
|
|
23
|
+
defineProps({
|
|
24
|
+
status: { type: String as PropType<StepStatus>, required: true },
|
|
25
|
+
barLeft: { type: String as PropType<BarMode | null>, default: null },
|
|
26
|
+
barRight: { type: String as PropType<BarMode | null>, default: null },
|
|
27
|
+
text: { type: String, default: null }
|
|
28
|
+
})
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<style lang="postcss" scoped>
|
|
32
|
+
.SStep.upcoming {
|
|
33
|
+
.point { border-color: var(--c-divider); }
|
|
34
|
+
.text { color: var(--c-text-2); }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.SStep.active {
|
|
38
|
+
.point { border-color: var(--c-success); }
|
|
39
|
+
.text { color: var(--c-success); }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.SStep.done {
|
|
43
|
+
.point {
|
|
44
|
+
border-color: var(--c-success);
|
|
45
|
+
background-color: var(--c-success);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.text { color: var(--c-text-1); }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.SStep.failed {
|
|
52
|
+
.point {
|
|
53
|
+
border-color: var(--c-danger);
|
|
54
|
+
background-color: var(--c-danger);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.text { color: var(--c-danger); }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.indicator {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
width: 100%;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.point {
|
|
67
|
+
display: flex;
|
|
68
|
+
justify-content: center;
|
|
69
|
+
align-items: center;
|
|
70
|
+
border: 1px solid transparent;
|
|
71
|
+
border-radius: 50%;
|
|
72
|
+
width: 16px;
|
|
73
|
+
height: 16px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.inner-dot {
|
|
77
|
+
border-radius: 50%;
|
|
78
|
+
width: 6px;
|
|
79
|
+
height: 6px;
|
|
80
|
+
background-color: var(--c-success);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.icon {
|
|
84
|
+
width: 10px;
|
|
85
|
+
height: 10px;
|
|
86
|
+
fill: var(--c-white);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.bar {
|
|
90
|
+
width: calc(50% - 8px);
|
|
91
|
+
height: 2px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.bar.mute { background-color: var(--c-divider-light); }
|
|
95
|
+
.bar.active { background-color: var(--c-success); }
|
|
96
|
+
.bar.failed { background-color: var(--c-danger); }
|
|
97
|
+
|
|
98
|
+
.text {
|
|
99
|
+
margin: 0;
|
|
100
|
+
padding: 8px 8px 0;
|
|
101
|
+
text-align: center;
|
|
102
|
+
line-height: 16px;
|
|
103
|
+
font-size: 12px;
|
|
104
|
+
font-weight: 500;
|
|
105
|
+
}
|
|
106
|
+
</style>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="SSteps">
|
|
3
|
+
<SStep
|
|
4
|
+
v-for="(step, index) in steps"
|
|
5
|
+
:key="index"
|
|
6
|
+
class="item"
|
|
7
|
+
:style="{ width }"
|
|
8
|
+
:bar-left="getBarLeftMode(index)"
|
|
9
|
+
:bar-right="getBarRightMode(index)"
|
|
10
|
+
v-bind="step"
|
|
11
|
+
/>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import { computed, PropType } from 'vue'
|
|
17
|
+
import { Step, BarMode } from '../composables/Step'
|
|
18
|
+
import SStep from './SStep.vue'
|
|
19
|
+
|
|
20
|
+
const props = defineProps({
|
|
21
|
+
steps: { type: Array as PropType<Step[]>, required: true }
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const width = computed(() => {
|
|
25
|
+
return `calc(100% / ${props.steps.length})`
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
function getBarLeftMode(index: number): BarMode | null {
|
|
29
|
+
if (index === 0) {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const current = props.steps[index]
|
|
34
|
+
const prev = props.steps[index - 1]
|
|
35
|
+
|
|
36
|
+
return isActive(prev) && isActive(current) ? 'active' : 'mute'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getBarRightMode(index: number): BarMode | null {
|
|
40
|
+
if (index === props.steps.length - 1) {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const current = props.steps[index]
|
|
45
|
+
const next = props.steps[index + 1]
|
|
46
|
+
|
|
47
|
+
return isActive(current) && isActive(next) ? 'active' : 'mute'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isActive(step: Step): boolean {
|
|
51
|
+
return step.status === 'active' || step.status === 'done'
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style lang="postcss" scoped>
|
|
56
|
+
.SSteps {
|
|
57
|
+
display: flex;
|
|
58
|
+
}
|
|
59
|
+
</style>
|