@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.
Files changed (97) hide show
  1. package/README.md +6 -6
  2. package/lib/components/SAvatar.vue +17 -17
  3. package/lib/components/SButton.vue +512 -267
  4. package/lib/components/SButtonGroup.vue +149 -0
  5. package/lib/components/SDropdown.vue +26 -150
  6. package/lib/components/SDropdownSection.vue +48 -0
  7. package/lib/components/SDropdownSectionFilter.vue +189 -0
  8. package/lib/components/SDropdownSectionFilterItem.vue +21 -0
  9. package/lib/components/SDropdownSectionFilterItemAvatar.vue +31 -0
  10. package/lib/components/SDropdownSectionFilterItemText.vue +20 -0
  11. package/lib/components/SDropdownSectionMenu.vue +39 -0
  12. package/lib/components/SIcon.vue +13 -0
  13. package/lib/components/SInputBase.vue +31 -31
  14. package/lib/components/SInputCheckbox.vue +1 -1
  15. package/lib/components/SInputCheckboxes.vue +74 -0
  16. package/lib/components/SInputDate.vue +182 -0
  17. package/lib/components/SInputDropdown.vue +158 -157
  18. package/lib/components/SInputDropdownItem.vue +46 -48
  19. package/lib/components/{SInputDropdownItemUserTag.vue → SInputDropdownItemAvatar.vue} +43 -44
  20. package/lib/components/SInputDropdownItemText.vue +79 -16
  21. package/lib/components/SInputFile.vue +55 -60
  22. package/lib/components/SInputHMS.vue +120 -110
  23. package/lib/components/SInputNumber.vue +38 -9
  24. package/lib/components/SInputRadio.vue +39 -36
  25. package/lib/components/SInputRadios.vue +40 -53
  26. package/lib/components/SInputSelect.vue +3 -3
  27. package/lib/components/SInputSwitch.vue +193 -0
  28. package/lib/components/SInputSwitches.vue +88 -0
  29. package/lib/components/SInputText.vue +206 -62
  30. package/lib/components/SInputTextarea.vue +46 -32
  31. package/lib/components/SInputYMD.vue +123 -126
  32. package/lib/components/SMarkdown.vue +52 -0
  33. package/lib/components/SModal.vue +25 -63
  34. package/lib/components/SMount.vue +19 -0
  35. package/lib/components/SSheet.vue +49 -55
  36. package/lib/components/SSheetFooter.vue +1 -1
  37. package/lib/components/SSheetFooterAction.vue +24 -17
  38. package/lib/components/SSheetFooterActions.vue +1 -4
  39. package/lib/components/SSheetForm.vue +15 -0
  40. package/lib/components/SSheetMedium.vue +8 -10
  41. package/lib/components/SSheetTitle.vue +7 -14
  42. package/lib/components/SSnackbar.vue +55 -45
  43. package/lib/components/{SPortalSnackbars.vue → SSnackbars.vue} +17 -20
  44. package/lib/components/SStep.vue +106 -0
  45. package/lib/components/SSteps.vue +59 -0
  46. package/lib/components/STable.vue +241 -0
  47. package/lib/components/STableCell.vue +82 -0
  48. package/lib/components/STableCellAvatar.vue +69 -0
  49. package/lib/components/STableCellAvatars.vue +93 -0
  50. package/lib/components/STableCellDay.vue +40 -0
  51. package/lib/components/STableCellPill.vue +84 -0
  52. package/lib/components/STableCellText.vue +102 -0
  53. package/lib/components/STableColumn.vue +255 -0
  54. package/lib/components/STableFooter.vue +115 -0
  55. package/lib/components/STableHeader.vue +74 -0
  56. package/lib/components/STableItem.vue +38 -0
  57. package/lib/components/STooltip.vue +112 -0
  58. package/lib/composables/Dropdown.ts +40 -99
  59. package/lib/composables/Form.ts +21 -18
  60. package/lib/composables/Grid.ts +117 -0
  61. package/lib/composables/Markdown.ts +138 -0
  62. package/lib/composables/Step.ts +7 -0
  63. package/lib/composables/Table.ts +103 -0
  64. package/lib/composables/Tooltip.ts +91 -0
  65. package/lib/composables/Validation.ts +5 -9
  66. package/lib/composables/markdown/LinkPlugin.ts +45 -0
  67. package/lib/mixins/Sheet.ts +5 -3
  68. package/lib/stores/Snackbars.ts +48 -0
  69. package/lib/{assets/styles → styles}/base.css +0 -0
  70. package/lib/{assets/styles → styles}/bootstrap.css +1 -0
  71. package/lib/{assets/styles → styles}/variables.css +55 -48
  72. package/lib/support/Day.ts +8 -0
  73. package/lib/support/Num.ts +3 -0
  74. package/lib/support/Time.ts +5 -2
  75. package/lib/support/Utils.ts +4 -3
  76. package/lib/types/shims.d.ts +3 -0
  77. package/lib/validation/validators/requiredYmd.ts +1 -1
  78. package/lib/validation/validators/ymd.ts +4 -4
  79. package/package.json +57 -37
  80. package/CHANGELOG.md +0 -47
  81. package/lib/.DS_Store +0 -0
  82. package/lib/components/.DS_Store +0 -0
  83. package/lib/components/SDialog.vue +0 -140
  84. package/lib/components/SDropdownItem.vue +0 -78
  85. package/lib/components/SDropdownItemText.vue +0 -22
  86. package/lib/components/SDropdownItemUser.vue +0 -40
  87. package/lib/components/SInputDropdownItemTextTag.vue +0 -94
  88. package/lib/components/SInputDropdownItemUser.vue +0 -41
  89. package/lib/components/SPortalModals.vue +0 -74
  90. package/lib/components/icons/.DS_Store +0 -0
  91. package/lib/composables/Dialog.ts +0 -38
  92. package/lib/composables/Modal.ts +0 -34
  93. package/lib/composables/Snackbar.ts +0 -18
  94. package/lib/store/Sefirot.ts +0 -17
  95. package/lib/store/dialog/index.ts +0 -42
  96. package/lib/store/modal/index.ts +0 -61
  97. package/lib/store/snackbars/index.ts +0 -70
@@ -0,0 +1,241 @@
1
+ <script setup lang="ts">
2
+ import { reactive, ref, computed, watch, toRefs } from 'vue'
3
+ import { Table } from '../composables/Table'
4
+ import STableCell from './STableCell.vue'
5
+ import STableColumn from './STableColumn.vue'
6
+ import STableFooter from './STableFooter.vue'
7
+ import STableHeader from './STableHeader.vue'
8
+ import STableItem from './STableItem.vue'
9
+ import SIconPreloader from './icons/SIconPreloader.vue'
10
+
11
+ const props = defineProps<{
12
+ options: Table
13
+ }>()
14
+
15
+ const {
16
+ orders,
17
+ columns,
18
+ records,
19
+ total,
20
+ page,
21
+ perPage,
22
+ reset,
23
+ borderless,
24
+ loading,
25
+ onPrev,
26
+ onNext,
27
+ onReset,
28
+ } = toRefs(props.options)
29
+
30
+ const head = ref<HTMLElement | null>(null)
31
+ const body = ref<HTMLElement | null>(null)
32
+
33
+ let headLock = false
34
+ let bodyLock = false
35
+
36
+ const colWidths = reactive<Record<string, string>>({})
37
+
38
+ const showHeader = computed(() => {
39
+ return total?.value !== undefined
40
+ })
41
+
42
+ const showFooter = computed(() => {
43
+ return !loading?.value && page?.value && total?.value
44
+ })
45
+
46
+ watch(() => records?.value, () => {
47
+ headLock = true
48
+ bodyLock = true
49
+ }, { flush: 'pre' })
50
+
51
+ watch(() => records?.value, () => {
52
+ syncScroll(head.value, body.value)
53
+ headLock = false
54
+ bodyLock = false
55
+ }, { flush: 'post' })
56
+
57
+ function syncHeadScroll() {
58
+ bodyLock || syncScroll(head.value, body.value)
59
+ }
60
+
61
+ function syncBodyScroll() {
62
+ headLock || syncScroll(body.value, head.value)
63
+ }
64
+
65
+ function syncScroll(from: HTMLElement | null, to: HTMLElement | null) {
66
+ if (from && to) {
67
+ to.scrollLeft = from.scrollLeft
68
+ }
69
+ }
70
+
71
+ function lockHead(value: boolean) {
72
+ headLock = value
73
+ }
74
+
75
+ function lockBody(value: boolean) {
76
+ bodyLock = value
77
+ }
78
+
79
+ function updateColWidth(key: string, value: string) {
80
+ colWidths[key] = value
81
+ }
82
+ </script>
83
+
84
+ <template>
85
+ <div class="STable" :class="{ borderless }" ref="el">
86
+ <div class="box">
87
+ <STableHeader
88
+ v-if="showHeader"
89
+ :total="total"
90
+ :reset="reset"
91
+ :borderless="borderless"
92
+ :on-reset="onReset"
93
+ />
94
+
95
+ <div class="table" role="grid">
96
+ <div
97
+ class="container head"
98
+ ref="head"
99
+ @mouseenter="lockHead(true)"
100
+ @mouseleave="lockHead(false)"
101
+ @scroll="syncHeadScroll"
102
+ >
103
+ <div class="block">
104
+ <div class="row">
105
+ <STableItem v-for="key in orders" :key="key" :name="key" :width="colWidths[key]">
106
+ <STableColumn
107
+ :name="key"
108
+ :label="columns[key].label"
109
+ :dropdown="columns[key].dropdown"
110
+ @resize="(value) => updateColWidth(key, value)"
111
+ />
112
+ </STableItem>
113
+ </div>
114
+ </div>
115
+ </div>
116
+
117
+ <div
118
+ v-if="!loading && records && records.length"
119
+ class="container body"
120
+ ref="body"
121
+ @mouseenter="lockBody(true)"
122
+ @mouseleave="lockBody(false)"
123
+ @scroll="syncBodyScroll"
124
+ >
125
+ <div class="block">
126
+ <div v-for="(record, rIndex) in records" :key="rIndex" class="row">
127
+ <STableItem v-for="key in orders" :key="key" :name="key" :width="colWidths[key]">
128
+ <STableCell
129
+ :name="key"
130
+ :cell="columns[key].cell"
131
+ :value="record[key]"
132
+ :record="record"
133
+ :records="records"
134
+ />
135
+ </STableItem>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </div>
140
+
141
+ <div v-if="!loading && records && !records.length" class="missing">
142
+ <p class="missing-text">
143
+ No results matched your search.
144
+ </p>
145
+ </div>
146
+
147
+ <div v-if="loading" class="loading">
148
+ <div class="loading-icon">
149
+ <SIconPreloader class="loading-svg" />
150
+ </div>
151
+ </div>
152
+
153
+ <STableFooter
154
+ v-if="showFooter"
155
+ :total="total"
156
+ :page="page"
157
+ :per-page="perPage"
158
+ :borderless="borderless"
159
+ :on-prev="onPrev"
160
+ :on-next="onNext"
161
+ />
162
+ </div>
163
+ </div>
164
+ </template>
165
+
166
+ <style scoped lang="postcss">
167
+ .box {
168
+ position: relative;
169
+ border: 1px solid var(--c-divider-light);
170
+ border-radius: 6px;
171
+ width: 100%;
172
+
173
+ .STable.borderless & {
174
+ border-right: 0;
175
+ border-left: 0;
176
+ border-radius: 0;
177
+ }
178
+ }
179
+
180
+ .table {
181
+ position: relative;
182
+ min-width: 100%;
183
+ white-space: nowrap;
184
+ }
185
+
186
+ .container {
187
+ position: static;
188
+ width: 100%;
189
+ min-width: 100%;
190
+ overflow-x: auto;
191
+
192
+ &.head {
193
+ position: var(--table-head-position, static);
194
+ top: var(--table-head-top, auto);
195
+ z-index: 20;
196
+ background-color: var(--bg-elv);
197
+
198
+ &::-webkit-scrollbar {
199
+ display: none;
200
+ }
201
+ }
202
+ }
203
+
204
+ .block {
205
+ display: inline-block;
206
+ min-width: 100%;
207
+ }
208
+
209
+ .row {
210
+ display: flex;
211
+ border-bottom: 1px solid var(--c-divider-light);
212
+ }
213
+
214
+ .missing {
215
+ border-radius: 0 0 6px 6px;
216
+ padding: 48px 32px;
217
+ text-align: center;
218
+ background-color: var(--c-bg-elv-up);
219
+ line-height: 24px;
220
+ font-size: 14px;
221
+ font-weight: 500;
222
+ color: var(--c-text-3);
223
+ }
224
+
225
+ .loading {
226
+ border-radius: 0 0 6px 6px;
227
+ padding: 64px 32px;
228
+ background-color: var(--c-bg-elv-up);
229
+ }
230
+
231
+ .loading-icon {
232
+ margin: 0 auto;
233
+ width: 48px;
234
+ height: 48px;
235
+ }
236
+
237
+ .loading-svg {
238
+ width: 48px;
239
+ height: 48px;
240
+ }
241
+ </style>
@@ -0,0 +1,82 @@
1
+ <script setup lang="ts">
2
+ import { TableCell } from '../composables/Table'
3
+ import STableCellAvatar from './STableCellAvatar.vue'
4
+ import STableCellAvatars from './STableCellAvatars.vue'
5
+ import STableCellDay from './STableCellDay.vue'
6
+ import STableCellPill from './STableCellPill.vue'
7
+ import STableCellText from './STableCellText.vue'
8
+
9
+ defineProps<{
10
+ name: string
11
+ cell?: TableCell
12
+ value: any
13
+ record: any
14
+ records: Record<string, any>
15
+ }>()
16
+ </script>
17
+
18
+ <template>
19
+ <div class="STableCell" :class="[`col-${name}`]">
20
+ <STableCellText
21
+ v-if="!cell || cell.type === 'text'"
22
+ :value="value"
23
+ :record="record"
24
+ :icon="cell?.icon"
25
+ :getter="cell?.value"
26
+ :link="cell?.link"
27
+ :color="cell?.color"
28
+ :icon-color="cell?.iconColor"
29
+ />
30
+ <STableCellDay
31
+ v-else-if="cell.type === 'day'"
32
+ :value="value"
33
+ :record="record"
34
+ :format="cell.format"
35
+ :color="cell.color"
36
+ />
37
+ <STableCellPill
38
+ v-else-if="cell.type === 'pill'"
39
+ :value="value"
40
+ :record="record"
41
+ :getter="cell.value"
42
+ :color="cell.color"
43
+ />
44
+ <STableCellAvatar
45
+ v-else-if="cell.type === 'avatar'"
46
+ :value="value"
47
+ :record="record"
48
+ :image="cell.image"
49
+ :name="cell.name"
50
+ :link="cell.link"
51
+ :color="cell.color"
52
+ />
53
+ <STableCellAvatars
54
+ v-else-if="cell.type === 'avatars'"
55
+ :value="value"
56
+ :record="record"
57
+ :avatars="cell.avatars"
58
+ :color="cell.color"
59
+ />
60
+ </div>
61
+ </template>
62
+
63
+ <style scoped lang="postcss">
64
+ .STableCell {
65
+ background-color: var(--c-bg-elv-up);
66
+ transition: background-color 0.1s;
67
+ overflow: hidden;
68
+
69
+ .row:hover & {
70
+ background-color: var(--c-bg-elv);
71
+ }
72
+
73
+ .STableItem:first-child & {
74
+ padding-left: var(--table-padding-left);
75
+ }
76
+
77
+ .STableItem:last-child & {
78
+ border-right: 0;
79
+ padding-right: var(--table-padding-right);
80
+ }
81
+ }
82
+ </style>
@@ -0,0 +1,69 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import SAvatar from './SAvatar.vue'
4
+ import SLink from './SLink.vue'
5
+
6
+ const props = defineProps<{
7
+ value?: any
8
+ record?: any
9
+ image?(value: any, record: any): string | undefined
10
+ name?(value: any, record: any): string
11
+ link?(value: any, record: any): string
12
+ color?: 'neutral' | 'soft' | 'mute'
13
+ }>()
14
+
15
+ const _image = computed(() => props.image?.(props.value, props.record))
16
+ const _name = computed(() => props.name?.(props.value, props.record))
17
+ </script>
18
+
19
+ <template>
20
+ <div class="STableCellAvatar" :class="[{ link}, color]">
21
+ <SLink class="container" :href="link?.(value, record)">
22
+ <div v-if="_image" class="avatar">
23
+ <SAvatar size="mini" :avatar="_image" :name="_name" />
24
+ </div>
25
+ <span v-if="_name" class="name">{{ _name }}</span>
26
+ </SLink>
27
+ </div>
28
+ </template>
29
+
30
+ <style scoped lang="postcss">
31
+ .STableCellAvatar {
32
+ min-height: 40px;
33
+ }
34
+
35
+ .container {
36
+ display: flex;
37
+ padding: 8px 16px;
38
+ }
39
+
40
+ .avatar {
41
+ flex-shrink: 0;
42
+ }
43
+
44
+ .name {
45
+ display: inline-block;
46
+ margin-left: 12px;
47
+ line-height: 24px;
48
+ font-size: 12px;
49
+ font-weight: 500;
50
+ white-space: nowrap;
51
+ overflow: hidden;
52
+ text-overflow: ellipsis;
53
+ transition: color 0.25s;
54
+
55
+ .STableCellAvatar.soft & { color: var(--c-text-2); }
56
+ .STableCellAvatar.mute & { color: var(--c-text-3); }
57
+
58
+ .STableCellAvatar.neutral.link & { color: var(--c-tex-1); }
59
+ .STableCellAvatar.soft.link & { color: var(--c-text-2); }
60
+ .STableCellAvatar.mute.link & { color: var(--c-text-3); }
61
+
62
+ .STableCellAvatar.link & { color: var(--c-info); }
63
+ .STableCellAvatar.link:hover & { color: var(--c-info-dark); }
64
+
65
+ .STableCellAvatar.neutral.link:hover & { color: var(--c-info); }
66
+ .STableCellAvatar.soft.link:hover & { color: var(--c-info); }
67
+ .STableCellAvatar.mute.link:hover & { color: var(--c-info); }
68
+ }
69
+ </style>
@@ -0,0 +1,93 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import type { TableCellAvatarsOption } from '../composables/Table'
4
+ import SAvatar from './SAvatar.vue'
5
+
6
+ const props = defineProps<{
7
+ value?: any
8
+ record?: any
9
+ avatars(value: any, record: any): TableCellAvatarsOption[]
10
+ color?: 'neutral' | 'soft' | 'mute'
11
+ }>()
12
+
13
+ const _avatars = computed(() => {
14
+ return props.avatars(props.value, props.record)
15
+ })
16
+
17
+ const displayAvatars = computed(() => {
18
+ return _avatars.value.slice(0, 3)
19
+ })
20
+
21
+ const names = computed(() => {
22
+ if (_avatars.value.length === 0) {
23
+ return null
24
+ }
25
+
26
+ if (_avatars.value.length === 1) {
27
+ return _avatars.value[0].name
28
+ }
29
+
30
+ if (_avatars.value.length === 2) {
31
+ return `${_avatars.value[0].name} and ${_avatars.value[1].name}`
32
+ }
33
+
34
+ return `${_avatars.value[0].name} +${_avatars.value.length - 1}`
35
+ })
36
+ </script>
37
+
38
+ <template>
39
+ <div class="STableCellAvatars" :class="[color]">
40
+ <div class="container">
41
+ <div class="avatars">
42
+ <div v-for="(avatar, index) in displayAvatars" :key="index" class="avatar">
43
+ <div class="avatar-box">
44
+ <SAvatar size="mini" :avatar="avatar.image" :name="avatar.name" />
45
+ </div>
46
+ </div>
47
+ </div>
48
+ <div class="names">
49
+ {{ names }}
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </template>
54
+
55
+ <style scoped lang="postcss">
56
+ .STableCellAvatars {
57
+ min-height: 40px;
58
+ }
59
+
60
+ .container {
61
+ display: flex;
62
+ gap: 16px;
63
+ padding: 6px 16px 6px 12px;
64
+ }
65
+
66
+ .avatars {
67
+ display: flex;
68
+ }
69
+
70
+ .avatar {
71
+ position: relative;
72
+ width: 20px;
73
+
74
+ &:nth-child(1) { z-index: 30; }
75
+ &:nth-child(2) { z-index: 20; }
76
+ &:nth-child(3) { z-index: 10; }
77
+ }
78
+
79
+ .avatar-box {
80
+ border: 2px solid var(--c-bg-elv-up);
81
+ border-radius: 50%;
82
+ width: 28px;
83
+ }
84
+
85
+ .names {
86
+ line-height: 28px;
87
+ font-size: 12px;
88
+ font-weight: 500;
89
+
90
+ .STableCellAvatars.soft & { color: var(--c-text-2); }
91
+ .STableCellAvatars.mute & { color: var(--c-text-3); }
92
+ }
93
+ </style>
@@ -0,0 +1,40 @@
1
+ <script setup lang="ts">
2
+ import type { Day } from '../support/Day'
3
+
4
+ defineProps<{
5
+ value?: Day | null
6
+ record: any
7
+ format?: string
8
+ color?: 'neutral' | 'soft' | 'mute'
9
+ }>()
10
+ </script>
11
+
12
+ <template>
13
+ <div class="STableCellDay" :class="[color ?? 'neutral']">
14
+ <div v-if="value" class="value">
15
+ {{ value.format(format ?? 'YYYY / MM / DD HH:mm:ss') }}
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+ <style scoped lang="postcss">
21
+ .STableCellDay {
22
+ padding: 8px 16px;
23
+ min-height: 40px;
24
+ }
25
+
26
+ .value {
27
+ line-height: 24px;
28
+ font-family: var(--font-family-number);
29
+ font-size: 12px;
30
+ font-weight: 500;
31
+ white-space: nowrap;
32
+ overflow: hidden;
33
+ text-overflow: ellipsis;
34
+ transition: color 0.25s;
35
+
36
+ .STableCellDay.neutral & { color: var(--c-text-1); }
37
+ .STableCellDay.soft & { color: var(--c-text-2); }
38
+ .STableCellDay.mute & { color: var(--c-text-3); }
39
+ }
40
+ </style>
@@ -0,0 +1,84 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import type { TableCellPillColor } from '../composables/Table'
4
+
5
+ const props = defineProps<{
6
+ value?: any
7
+ record: any
8
+ getter?: string | ((value: any) => string)
9
+ color?: TableCellPillColor | ((value: any) => TableCellPillColor)
10
+ }>()
11
+
12
+ const _value = computed(() => {
13
+ if (props.getter === undefined) {
14
+ return props.value
15
+ }
16
+
17
+ return typeof props.getter === 'string'
18
+ ? props.getter
19
+ : props.getter(props.value)
20
+ })
21
+
22
+ const _color = computed(() => {
23
+ if (props.color === undefined) {
24
+ return null
25
+ }
26
+
27
+ return typeof props.color === 'string'
28
+ ? props.color
29
+ : props.color(props.value)
30
+ })
31
+ </script>
32
+
33
+ <template>
34
+ <div class="STableCellPill" :class="[_color ?? 'mute']">
35
+ <div class="value">{{ _value }}</div>
36
+ </div>
37
+ </template>
38
+
39
+ <style scoped lang="postcss">
40
+ .STableCellPill {
41
+ padding: 9px 16px 10px;
42
+ min-height: 40px;
43
+ }
44
+
45
+ .value {
46
+ display: inline-block;
47
+ border: 1px solid transparent;
48
+ border-radius: 14px;
49
+ padding: 0 8px;
50
+ line-height: 18px;
51
+ font-size: 12px;
52
+ font-weight: 500;
53
+
54
+ .STableCellPill.info & {
55
+ border-color: var(--c-info);
56
+ color: var(--c-info);
57
+ background-color: var(--c-info-bg);
58
+ }
59
+
60
+ .STableCellPill.success & {
61
+ border-color: var(--c-success);
62
+ color: var(--c-success);
63
+ background-color: var(--c-success-bg);
64
+ }
65
+
66
+ .STableCellPill.warning & {
67
+ border-color: var(--c-warning);
68
+ color: var(--c-warning);
69
+ background-color: var(--c-warning-bg);
70
+ }
71
+
72
+ .STableCellPill.danger & {
73
+ border-color: var(--c-danger);
74
+ color: var(--c-danger);
75
+ background-color: var(--c-danger-bg);
76
+ }
77
+
78
+ .STableCellPill.mute & {
79
+ border-color: var(--c-divider);
80
+ color: var(--c-text-2);
81
+ background-color: var(--c-bg-elv);
82
+ }
83
+ }
84
+ </style>
@@ -0,0 +1,102 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import SLink from './SLink.vue'
4
+
5
+ const props = defineProps<{
6
+ value?: any
7
+ record: any
8
+ icon?: any
9
+ getter?: string | ((value: any) => string)
10
+ color?: 'neutral' | 'soft' | 'mute'
11
+ iconColor?: 'neutral' | 'soft' | 'mute'
12
+ link?(value: any, record: any): string
13
+ }>()
14
+
15
+ const _value = computed(() => {
16
+ if (props.getter === undefined) {
17
+ return props.value
18
+ }
19
+
20
+ return typeof props.getter === 'string'
21
+ ? props.getter
22
+ : props.getter(props.value)
23
+ })
24
+ </script>
25
+
26
+ <template>
27
+ <div class="STableCellText" :class="[{ link }, color ?? 'neutral']">
28
+ <SLink v-if="_value" class="container" :href="link?.(value, record)">
29
+ <div v-if="icon" class="icon" :class="[iconColor ?? color ?? 'neutral']">
30
+ <component class="svg" :is="icon" />
31
+ </div>
32
+ <div class="text" :class="[color ?? 'neutral']">
33
+ {{ _value }}
34
+ </div>
35
+ </SLink>
36
+ </div>
37
+ </template>
38
+
39
+ <style scoped lang="postcss">
40
+ .STableCellText {
41
+ padding: 8px 16px;
42
+ min-height: 40px;
43
+ }
44
+
45
+ .container {
46
+ display: flex;
47
+ gap: 4px;
48
+ }
49
+
50
+ .text {
51
+ line-height: 24px;
52
+ font-size: 12px;
53
+ font-weight: 500;
54
+ white-space: nowrap;
55
+ overflow: hidden;
56
+ text-overflow: ellipsis;
57
+ transition: color 0.25s;
58
+
59
+ &.neutral { color: var(--c-text-1); }
60
+ &.soft { color: var(--c-text-2); }
61
+ &.mute { color: var(--c-text-3); }
62
+
63
+ .STableCellText.link & { color: var(--c-info); }
64
+ .STableCellText.link:hover & { color: var(--c-info-dark); }
65
+
66
+ .STableCellText.link &.neutral { color: var(--c-text-1); }
67
+ .STableCellText.link:hover &.neutral { color: var(--c-info); }
68
+ .STableCellText.link &.soft { color: var(--c-text-2); }
69
+ .STableCellText.link:hover &.soft { color: var(--c-info); }
70
+ .STableCellText.link &.mute { color: var(--c-text-3); }
71
+ .STableCellText.link:hover &.mute { color: var(--c-info); }
72
+ }
73
+
74
+ .icon {
75
+ display: flex;
76
+ justify-content: center;
77
+ align-items: center;
78
+ width: 24px;
79
+ height: 24px;
80
+ transition: color 0.25s;
81
+
82
+ &.neutral { color: var(--c-text-1); }
83
+ &.soft { color: var(--c-text-2); }
84
+ &.mute { color: var(--c-text-3); }
85
+
86
+ .STableCellText.link & { color: var(--c-info); }
87
+ .STableCellText.link:hover & { color: var(--c-info-dark); }
88
+
89
+ .STableCellText.link &.neutral { color: var(--c-text-1); }
90
+ .STableCellText.link:hover &.neutral { color: var(--c-info); }
91
+ .STableCellText.link &.soft { color: var(--c-text-2); }
92
+ .STableCellText.link:hover &.soft { color: var(--c-info); }
93
+ .STableCellText.link &.mute { color: var(--c-text-3); }
94
+ .STableCellText.link:hover &.mute { color: var(--c-info); }
95
+ }
96
+
97
+ .svg {
98
+ width: 16px;
99
+ height: 16px;
100
+ fill: currentColor;
101
+ }
102
+ </style>