@globalbrain/sefirot 2.34.0 → 2.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/lib/components/SButton.vue +7 -5
  2. package/lib/components/SCard.vue +70 -0
  3. package/lib/components/SCardBlock.vue +33 -0
  4. package/lib/components/SCardFooter.vue +14 -0
  5. package/lib/components/SCardFooterAction.vue +31 -0
  6. package/lib/components/SCardFooterActions.vue +15 -0
  7. package/lib/components/SCardHeader.vue +15 -0
  8. package/lib/components/SCardHeaderAction.vue +28 -0
  9. package/lib/components/SCardHeaderActionClose.vue +27 -0
  10. package/lib/components/SCardHeaderActionCollapse.vue +47 -0
  11. package/lib/components/SCardHeaderActions.vue +13 -0
  12. package/lib/components/SCardHeaderTitle.vue +15 -0
  13. package/lib/components/SDropdown.vue +6 -11
  14. package/lib/components/SDropdownSection.vue +0 -25
  15. package/lib/components/SDropdownSectionActions.vue +3 -2
  16. package/lib/components/SDropdownSectionFilter.vue +60 -26
  17. package/lib/components/SDropdownSectionFilterItemAvatar.vue +1 -1
  18. package/lib/components/SDropdownSectionFilterItemText.vue +1 -2
  19. package/lib/components/SDropdownSectionMenu.vue +3 -2
  20. package/lib/components/SIcon.vue +1 -1
  21. package/lib/components/SModal.vue +2 -2
  22. package/lib/components/STableCell.vue +1 -0
  23. package/lib/components/STableCellAvatar.vue +8 -2
  24. package/lib/components/STableColumn.vue +3 -3
  25. package/lib/components/STableHeader.vue +2 -0
  26. package/lib/composables/Card.ts +45 -0
  27. package/lib/composables/Flyout.ts +1 -1
  28. package/lib/composables/Form.ts +4 -4
  29. package/lib/composables/Table.ts +1 -0
  30. package/lib/composables/Tooltip.ts +9 -10
  31. package/lib/composables/Utils.ts +2 -2
  32. package/lib/mixins/Card.ts +30 -0
  33. package/lib/styles/variables.css +214 -86
  34. package/lib/support/Num.ts +7 -0
  35. package/package.json +40 -40
@@ -86,12 +86,12 @@ function handleClick(): void {
86
86
  <template>
87
87
  <SFragment
88
88
  :is="hasTooltip && STooltip"
89
- :tag="tooltip?.tag"
90
- :text="unref(tooltip?.text)"
91
- :position="tooltip?.position"
89
+ :tag="props.tooltip?.tag"
90
+ :text="unref(props.tooltip?.text)"
91
+ :position="props.tooltip?.position"
92
92
  display="inline-block"
93
- :trigger="tooltip?.trigger ?? 'both'"
94
- :timeout="tooltip?.timeout"
93
+ :trigger="props.tooltip?.trigger ?? 'both'"
94
+ :timeout="props.tooltip?.timeout"
95
95
  :tabindex="-1"
96
96
  >
97
97
  <template v-if="$slots['tooltip-text']" #text><slot name="tooltip-text" /></template>
@@ -125,6 +125,7 @@ function handleClick(): void {
125
125
  .SButton {
126
126
  position: relative;
127
127
  display: inline-flex;
128
+ justify-content: center;
128
129
  align-items: center;
129
130
  letter-spacing: 0;
130
131
  text-align: center;
@@ -705,6 +706,7 @@ function handleClick(): void {
705
706
 
706
707
  .SButton.block {
707
708
  display: flex;
709
+ justify-content: center;
708
710
  width: 100%;
709
711
  }
710
712
 
@@ -0,0 +1,70 @@
1
+ <script setup lang="ts">
2
+ import { provideCardState } from '../composables/Card'
3
+
4
+ export type Size = 'small' | 'medium'
5
+
6
+ defineProps<{
7
+ size?: Size
8
+ }>()
9
+
10
+ const { isCollapsed } = provideCardState()
11
+ </script>
12
+
13
+ <template>
14
+ <div class="SCard" :class="[size, { collapsed: isCollapsed }]">
15
+ <slot />
16
+ </div>
17
+ </template>
18
+
19
+ <style scoped lang="postcss">
20
+ .SCard {
21
+ display: grid;
22
+ gap: 1px;
23
+ border: 1px solid var(--c-divider-2);
24
+ border-radius: 6px;
25
+ background-color: var(--c-gutter);
26
+ }
27
+
28
+ .SCard.collapsed {
29
+ height: 48px;
30
+ overflow: hidden;
31
+ }
32
+
33
+ .SModal > .SCard {
34
+ margin: 12px 12px 128px;
35
+ box-shadow: var(--shadow-depth-3);
36
+ transition: opacity 0.25s, transform 0.25s;
37
+
38
+ @media (min-width: 512px) {
39
+ margin: 24px 24px 128px;
40
+ }
41
+
42
+ @media (min-width: 768px) {
43
+ margin: 48px 48px 128px;
44
+ }
45
+
46
+ &.small {
47
+ @media (min-width: 560px) {
48
+ margin: 24px auto 128px;
49
+ max-width: 512px;
50
+ }
51
+
52
+ @media (min-width: 768px) {
53
+ margin: 48px auto 128px;
54
+ }
55
+ }
56
+
57
+ &.medium {
58
+ @media (min-width: 864px) {
59
+ margin: 48px auto 128px;
60
+ max-width: 768px;
61
+ }
62
+ }
63
+ }
64
+
65
+ .SModal.fade-enter-from > .SCard,
66
+ .SModal.fade-leave-to > .SCard {
67
+ opacity: 0;
68
+ transform: translateY(8px);
69
+ }
70
+ </style>
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ export type Space = 'compact' | 'wide'
3
+
4
+ defineProps<{
5
+ space?: Space
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <div class="SCardBlock" :class="[space]">
11
+ <slot />
12
+ </div>
13
+ </template>
14
+
15
+ <style scoped lang="postcss">
16
+ .SCardBlock {
17
+ padding: var(--card-padding, 0);
18
+ background-color: var(--c-bg-elv-3);
19
+
20
+ &.compact { padding: 24px; }
21
+ &.wide { padding: 48px; }
22
+ }
23
+
24
+ .SCard > .SCardBlock:first-child {
25
+ border-top-left-radius: 5px;
26
+ border-top-right-radius: 5px;
27
+ }
28
+
29
+ .SCard > .SCardBlock:last-child {
30
+ border-bottom-right-radius: 5px;
31
+ border-bottom-left-radius: 5px;
32
+ }
33
+ </style>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <div class="SCardFooter">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <style scoped lang="postcss">
8
+ .SCardFooter {
9
+ display: flex;
10
+ align-items: center;
11
+ border-radius: 0 0 5px 5px;
12
+ background-color: var(--c-bg-elv-3);
13
+ }
14
+ </style>
@@ -0,0 +1,31 @@
1
+ <script setup lang="ts">
2
+ import SButton, { type Mode, type Tooltip } from './SButton.vue'
3
+
4
+ defineProps<{
5
+ mode?: Mode
6
+ label?: string
7
+ labelMode?: Mode
8
+ loading?: boolean
9
+ disabled?: boolean
10
+ tooltip?: Tooltip
11
+ }>()
12
+
13
+ defineEmits<{
14
+ (e: 'click'): void
15
+ }>()
16
+ </script>
17
+
18
+ <template>
19
+ <div class="SCardFooterAction">
20
+ <SButton
21
+ size="medium"
22
+ :mode="mode"
23
+ :label="label"
24
+ :label-mode="labelMode"
25
+ :loading="loading"
26
+ :disabled="disabled"
27
+ :tooltip="tooltip"
28
+ @click="$emit('click')"
29
+ />
30
+ </div>
31
+ </template>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <div class="SCardFooterActions">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <style scoped lang="postcss">
8
+ .SCardFooterActions {
9
+ display: flex;
10
+ justify-content: flex-end;
11
+ flex-grow: 1;
12
+ gap: 12px;
13
+ padding: 12px 24px;
14
+ }
15
+ </style>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <div class="SCardHeader">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <style scoped lang="postcss">
8
+ .SCardHeader {
9
+ display: flex;
10
+ align-items: center;
11
+ border-radius: 5px 5px 0 0;
12
+ height: 48px;
13
+ background-color: var(--c-bg-soft);
14
+ }
15
+ </style>
@@ -0,0 +1,28 @@
1
+ <script setup lang="ts">
2
+ import { type IconifyIcon } from '@iconify/vue/dist/offline'
3
+ import SButton, { type Tooltip } from './SButton.vue'
4
+
5
+ defineProps<{
6
+ icon: IconifyIcon
7
+ disabled?: boolean
8
+ tooltip?: Tooltip
9
+ }>()
10
+
11
+ defineEmits<{
12
+ (e: 'click'): void
13
+ }>()
14
+ </script>
15
+
16
+ <template>
17
+ <div class="SCardHeaderAction">
18
+ <SButton
19
+ type="text"
20
+ mode="mute"
21
+ size="small"
22
+ :icon="icon"
23
+ :disabled="disabled"
24
+ :tooltip="tooltip"
25
+ @click="$emit('click')"
26
+ />
27
+ </div>
28
+ </template>
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ import IconX from '@iconify-icons/ph/x-bold'
3
+ import SButton, { type Tooltip } from './SButton.vue'
4
+
5
+ defineProps<{
6
+ disabled?: boolean
7
+ tooltip?: Tooltip
8
+ }>()
9
+
10
+ defineEmits<{
11
+ (e: 'click'): void
12
+ }>()
13
+ </script>
14
+
15
+ <template>
16
+ <div class="SCardHeaderActionClose">
17
+ <SButton
18
+ type="text"
19
+ mode="mute"
20
+ size="small"
21
+ :icon="IconX"
22
+ :disabled="disabled"
23
+ :tooltip="tooltip"
24
+ @click="$emit('click')"
25
+ />
26
+ </div>
27
+ </template>
@@ -0,0 +1,47 @@
1
+ <script setup lang="ts">
2
+ import IconArrowsInLineVertical from '@iconify-icons/ph/arrows-in-line-vertical-bold'
3
+ import IconArrowsOutLineVertical from '@iconify-icons/ph/arrows-out-line-vertical-bold'
4
+ import { computed, shallowRef } from 'vue'
5
+ import { useCardState } from '../composables/Card'
6
+ import SButton, { type Tooltip } from './SButton.vue'
7
+
8
+ const props = defineProps<{
9
+ collapsed?: boolean
10
+ disabled?: boolean
11
+ tooltip?: Tooltip
12
+ }>()
13
+
14
+ defineEmits<{
15
+ (e: 'click'): void
16
+ }>()
17
+
18
+ const { isCollapsed, setCollapse, toggleCollapse } = useCardState()
19
+
20
+ setCollapse(props.collapsed)
21
+
22
+ const el = shallowRef<HTMLElement | null>(null)
23
+
24
+ const icon = computed(() => {
25
+ return isCollapsed.value
26
+ ? IconArrowsOutLineVertical
27
+ : IconArrowsInLineVertical
28
+ })
29
+ </script>
30
+
31
+ <template>
32
+ <div
33
+ class="SCardHeaderActionCollapse"
34
+ :class="{ collapsed: isCollapsed }"
35
+ ref="el"
36
+ >
37
+ <SButton
38
+ type="text"
39
+ mode="mute"
40
+ size="small"
41
+ :icon="icon"
42
+ :disabled="disabled"
43
+ :tooltip="tooltip"
44
+ @click="toggleCollapse"
45
+ />
46
+ </div>
47
+ </template>
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <div class="SCardHeaderActions">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <style scoped lang="postcss">
8
+ .SCardHeaderActions {
9
+ display: flex;
10
+ justify-content: flex-end;
11
+ padding-right: 8px;
12
+ }
13
+ </style>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <p class="SCardHeaderTitle">
3
+ <slot />
4
+ </p>
5
+ </template>
6
+
7
+ <style scoped lang="postcss">
8
+ .SCardHeaderTitle {
9
+ flex-grow: 1;
10
+ padding-left: 24px;
11
+ line-height: 32px;
12
+ font-size: 14px;
13
+ font-weight: 600;
14
+ }
15
+ </style>
@@ -19,25 +19,20 @@ defineProps<{
19
19
 
20
20
  <style scoped lang="postcss">
21
21
  .SDropdown {
22
- border: 1px solid var(--c-divider-light);
23
- border-radius: 12px;
22
+ border: 1px solid var(--c-divider-2);
23
+ border-radius: 6px;
24
24
  min-width: 256px;
25
25
  max-height: 384px;
26
- background-color: var(--c-bg);
27
26
  overflow-y: auto;
28
27
 
29
28
  &::-webkit-scrollbar {
30
29
  display: none;
31
30
  }
32
-
33
- .dark & {
34
- background-color: var(--c-bg-mute);
35
- }
36
31
  }
37
32
 
38
- .section {
39
- & + & {
40
- border-top: 1px solid var(--c-divider-light);
41
- }
33
+ .container {
34
+ display: grid;
35
+ gap: 1px;
36
+ background-color: var(--c-gutter);
42
37
  }
43
38
  </style>
@@ -31,28 +31,3 @@ defineProps<{
31
31
  :comp="section.component"
32
32
  />
33
33
  </template>
34
-
35
- <style scoped lang="postcss">
36
- .SDropdown {
37
- border: 1px solid var(--c-divider-light);
38
- border-radius: 12px;
39
- min-width: 256px;
40
- max-height: 384px;
41
- background-color: var(--c-bg);
42
- overflow-y: auto;
43
-
44
- &::-webkit-scrollbar {
45
- display: none;
46
- }
47
-
48
- .dark & {
49
- background-color: var(--c-bg-mute);
50
- }
51
- }
52
-
53
- .section {
54
- & + & {
55
- border-top: 1px solid var(--c-divider-light);
56
- }
57
- }
58
- </style>
@@ -20,7 +20,9 @@ defineProps<{
20
20
  .SDropdownSectionActions {
21
21
  display: flex;
22
22
  justify-content: flex-end;
23
+ gap: 4px;
23
24
  padding: 8px;
25
+ background-color: var(--c-bg-elv-3);
24
26
  }
25
27
 
26
28
  .button {
@@ -30,8 +32,7 @@ defineProps<{
30
32
  width: 100%;
31
33
  text-align: left;
32
34
  line-height: 32px;
33
- font-size: 12px;
34
- font-weight: 500;
35
+ font-size: 14px;
35
36
  transition: color 0.25s, background-color 0.25s;
36
37
 
37
38
  &.neutral { color: var(--button-text-neutral-text-color); }
@@ -74,11 +74,14 @@ function handleClick(option: DropdownSectionFilterOption, value: string | number
74
74
  @keyup.down.prevent="focusNext"
75
75
  @click="handleClick(option, option.value)"
76
76
  >
77
- <span class="checkbox">
77
+ <span v-if="isArray(unref(selected))" class="checkbox">
78
78
  <span class="checkbox-box">
79
79
  <SIcon :icon="IconCheck" class="checkbox-icon" />
80
80
  </span>
81
81
  </span>
82
+ <span v-else class="radio">
83
+ <span class="radio-dot" />
84
+ </span>
82
85
  <span class="option-item">
83
86
  <SDropdownSectionFilterItem :option="option" />
84
87
  </span>
@@ -93,33 +96,34 @@ function handleClick(option: DropdownSectionFilterOption, value: string | number
93
96
  </template>
94
97
 
95
98
  <style scoped lang="postcss">
99
+ .SDropdownSectionFilter {
100
+ background-color: var(--c-bg-elv-3);
101
+ }
102
+
96
103
  .search {
97
104
  position: sticky;
98
105
  top: 0;
99
- border-bottom: 1px solid var(--c-divider-light);
106
+ border-bottom: 1px solid var(--c-gutter);
100
107
  padding: 8px;
101
108
  background-color: var(--c-bg-elv-up);
102
109
  }
103
110
 
104
111
  .input {
105
- border: 1px solid var(--c-divider);
112
+ border: 1px solid var(--c-divider-1);
106
113
  border-radius: 6px;
107
114
  padding: 0 8px;
108
115
  width: 100%;
109
116
  font-size: 14px;
110
117
  line-height: 32px;
111
- background-color: var(--c-bg);
118
+ background-color: var(--input-bg-color);
112
119
  transition: border-color 0.25s;
113
120
 
114
121
  &::placeholder {
115
- color: var(--c-text-3);
122
+ color: var(--input-placeholder-color);
116
123
  }
117
124
 
118
- &:hover { border-color: var(--c-black); }
119
- &:focus { border-color: var(--c-info); }
120
-
121
- .dark &:hover { border-color: var(--c-gray); }
122
- .dark &:focus { border-color: var(--c-info); }
125
+ &:hover { border-color: var(--input-hover-border-color); }
126
+ &:focus { border-color: var(--input-focus-border-color); }
123
127
  }
124
128
 
125
129
  .list {
@@ -136,33 +140,29 @@ function handleClick(option: DropdownSectionFilterOption, value: string | number
136
140
 
137
141
  &:hover,
138
142
  &:focus {
139
- background-color: var(--c-bg-mute);
140
- }
141
-
142
- .dark &:hover,
143
- .dark &:focus {
144
- background-color: var(--c-bg);
143
+ background-color: var(--c-mute);
145
144
  }
146
145
  }
147
146
 
148
147
  .checkbox {
149
148
  display: block;
150
149
  padding-top: 8px;
150
+ padding-bottom: 8px;
151
151
  }
152
152
 
153
153
  .checkbox-box {
154
154
  display: flex;
155
155
  justify-content: center;
156
156
  align-items: center;
157
- border: 1px solid var(--c-divider);
157
+ border: 1px solid var(--c-divider-1);
158
158
  border-radius: 4px;
159
159
  width: 16px;
160
160
  height: 16px;
161
- background-color: var(--c-bg);
161
+ background-color: var(--input-bg-color);
162
162
  transition: border-color 0.1s, background-color 0.1s;
163
163
 
164
164
  .button.active & {
165
- border-color: var(--c-info);
165
+ border-color: var(--c-info-text);
166
166
  background-color: var(--c-info);
167
167
  }
168
168
  }
@@ -180,19 +180,53 @@ function handleClick(option: DropdownSectionFilterOption, value: string | number
180
180
  }
181
181
  }
182
182
 
183
+ .radio {
184
+ position: relative;
185
+ flex-shrink: 0;
186
+ border: 1px solid var(--c-divider-1);
187
+ border-radius: 50%;
188
+ margin-top: 8px;
189
+ margin-bottom: 8px;
190
+ width: 16px;
191
+ height: 16px;
192
+ background-color: var(--input-bg-color);
193
+ transition: border-color 0.25s;
194
+
195
+ .button.active & {
196
+ border-color: var(--c-info-light);
197
+ }
198
+ }
199
+
200
+ .radio-dot {
201
+ position: absolute;
202
+ top: 0;
203
+ right: 0;
204
+ bottom: 0;
205
+ left: 0;
206
+ display: flex;
207
+ justify-content: center;
208
+ align-items: center;
209
+ border-radius: 50%;
210
+ width: 100%;
211
+ background-color: var(--c-info-light);
212
+ opacity: 0;
213
+ transform: scale(0);
214
+ transition: opacity 0.25s, transform 0.1s;
215
+
216
+ .button.active & {
217
+ opacity: 1;
218
+ transform: scale(0.6);
219
+ }
220
+ }
221
+
183
222
  .option-item {
184
- padding-left: 8px;
223
+ padding-left: 12px;
185
224
  width: 100%;
186
225
  }
187
226
 
188
227
  .empty {
189
- padding: 16px;
228
+ padding: 14px 16px;
190
229
  font-size: 12px;
191
- font-weight: 500;
192
230
  color: var(--c-text-2);
193
-
194
- .search + & {
195
- border-top: 1px solid var(--c-divider-light);
196
- }
197
231
  }
198
232
  </style>
@@ -31,7 +31,7 @@ defineProps<{
31
31
  .name {
32
32
  display: inline-block;
33
33
  padding-left: 8px;
34
- font-size: 12px;
34
+ font-size: 14px;
35
35
  font-weight: 400;
36
36
  white-space: nowrap;
37
37
  overflow: hidden;
@@ -15,13 +15,12 @@ defineProps<{
15
15
  display: inline-block;
16
16
  padding: 6px 0;
17
17
  line-height: 20px;
18
- font-size: 12px;
19
18
  }
20
19
 
21
20
  .text {
22
21
  display: inline-block;
23
22
  line-height: 20px;
24
- font-size: 12px;
23
+ font-size: 14px;
25
24
  font-weight: 400;
26
25
  }
27
26
  </style>
@@ -19,6 +19,7 @@ defineProps<{
19
19
  <style scoped lang="postcss">
20
20
  .SDropdownSectionMenu {
21
21
  padding: 8px;
22
+ background-color: var(--c-bg-elv-3);
22
23
  }
23
24
 
24
25
  .button {
@@ -28,12 +29,12 @@ defineProps<{
28
29
  width: 100%;
29
30
  text-align: left;
30
31
  line-height: 32px;
31
- font-size: 12px;
32
+ font-size: 14px;
32
33
  font-weight: 400;
33
34
  transition: color 0.25s, background-color 0.25s;
34
35
 
35
36
  &:hover {
36
- background-color: var(--c-bg-elv-down);
37
+ background-color: var(--c-mute);
37
38
  }
38
39
  }
39
40
  </style>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { Icon, IconifyIcon } from '@iconify/vue/dist/offline'
2
+ import { Icon, type IconifyIcon } from '@iconify/vue/dist/offline'
3
3
  import { type DefineComponent } from 'vue'
4
4
 
5
5
  defineProps<{
@@ -29,11 +29,11 @@ function onClick(e: MouseEvent) {
29
29
 
30
30
  <template>
31
31
  <Teleport to="#sefirot-modals">
32
- <transition name="fade">
32
+ <Transition name="fade">
33
33
  <div v-if="open" class="SModal" ref="el" @mousedown="onClick">
34
34
  <slot />
35
35
  </div>
36
- </transition>
36
+ </Transition>
37
37
  </Teleport>
38
38
  </template>
39
39
 
@@ -73,6 +73,7 @@ const computedCell = computed<TableCell | undefined>(() =>
73
73
  :name="computedCell.name"
74
74
  :link="computedCell.link"
75
75
  :color="computedCell.color"
76
+ :on-click="computedCell.onClick"
76
77
  />
77
78
  <STableCellAvatars
78
79
  v-else-if="computedCell.type === 'avatars'"