@globalbrain/sefirot 3.49.0 → 4.0.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 (106) hide show
  1. package/config/nuxt.d.ts +4 -0
  2. package/config/nuxt.js +31 -0
  3. package/config/vite.d.ts +8 -0
  4. package/config/vite.js +69 -0
  5. package/lib/components/SActionList.vue +0 -1
  6. package/lib/components/SActionListItem.vue +3 -11
  7. package/lib/components/SAlert.vue +8 -13
  8. package/lib/components/SButton.vue +9 -10
  9. package/lib/components/SCardBlock.vue +0 -6
  10. package/lib/components/SControlActionBarClose.vue +1 -1
  11. package/lib/components/SControlActionBarCollapse.vue +2 -2
  12. package/lib/components/SControlInputSearch.vue +2 -2
  13. package/lib/components/SDescAvatar.vue +1 -2
  14. package/lib/components/SDescFile.vue +4 -6
  15. package/lib/components/SDescPill.vue +1 -2
  16. package/lib/components/SDescText.vue +1 -1
  17. package/lib/components/SDropdownSectionDateRange.vue +2 -2
  18. package/lib/components/SDropdownSectionDateRangeDateFromTo.vue +2 -2
  19. package/lib/components/SDropdownSectionDateRangeYear.vue +2 -2
  20. package/lib/components/SDropdownSectionDateRangeYearHalf.vue +2 -2
  21. package/lib/components/SDropdownSectionDateRangeYearQuarter.vue +2 -2
  22. package/lib/components/SDropdownSectionFilter.vue +4 -6
  23. package/lib/components/SIndicator.vue +10 -16
  24. package/lib/components/SInputAddon.vue +6 -8
  25. package/lib/components/SInputBase.vue +6 -8
  26. package/lib/components/SInputCheckbox.vue +7 -11
  27. package/lib/components/SInputCheckboxes.vue +3 -4
  28. package/lib/components/SInputDate.vue +3 -4
  29. package/lib/components/SInputDropdown.vue +10 -13
  30. package/lib/components/SInputDropdownItemAvatar.vue +2 -3
  31. package/lib/components/SInputDropdownItemText.vue +2 -3
  32. package/lib/components/SInputFile.vue +3 -4
  33. package/lib/components/SInputHMS.vue +4 -5
  34. package/lib/components/SInputImage.vue +5 -7
  35. package/lib/components/SInputNumber.vue +10 -11
  36. package/lib/components/SInputRadio.vue +3 -4
  37. package/lib/components/SInputRadios.vue +3 -4
  38. package/lib/components/SInputSegments.vue +3 -4
  39. package/lib/components/SInputSelect.vue +7 -9
  40. package/lib/components/SInputSwitch.vue +3 -4
  41. package/lib/components/SInputSwitches.vue +3 -4
  42. package/lib/components/SInputText.vue +7 -9
  43. package/lib/components/SInputTextarea.vue +3 -4
  44. package/lib/components/SInputYMD.vue +4 -5
  45. package/lib/components/SLink.vue +1 -1
  46. package/lib/components/SLocalNavMenu.vue +3 -4
  47. package/lib/components/SLoginPage.vue +79 -22
  48. package/lib/components/SLoginPagePasswordDialog.vue +95 -0
  49. package/lib/components/SPagination.vue +2 -2
  50. package/lib/components/SPill.vue +1 -5
  51. package/lib/components/SSnackbar.vue +2 -3
  52. package/lib/components/SStep.vue +4 -5
  53. package/lib/components/STable.vue +1 -2
  54. package/lib/components/STableCell.vue +5 -13
  55. package/lib/components/STableCellAvatar.vue +10 -27
  56. package/lib/components/STableCellAvatars.vue +6 -19
  57. package/lib/components/STableCellDay.vue +4 -11
  58. package/lib/components/STableCellNumber.vue +8 -9
  59. package/lib/components/STableCellPill.vue +5 -33
  60. package/lib/components/STableCellPills.vue +4 -14
  61. package/lib/components/STableCellState.vue +3 -3
  62. package/lib/components/STableCellText.vue +22 -50
  63. package/lib/components/STableColumn.vue +4 -6
  64. package/lib/components/STableFooter.vue +4 -5
  65. package/lib/components/STableHeader.vue +2 -19
  66. package/lib/components/STableHeaderMenu.vue +1 -2
  67. package/lib/components/STableHeaderMenuItem.vue +2 -3
  68. package/lib/components/STableItem.vue +1 -1
  69. package/lib/composables/Data.ts +8 -102
  70. package/lib/composables/Error.ts +3 -3
  71. package/lib/composables/Table.ts +17 -22
  72. package/lib/composables/Utils.ts +2 -2
  73. package/lib/composables/Validation.ts +76 -14
  74. package/lib/http/Http.ts +27 -10
  75. package/lib/mixins/Card.ts +0 -27
  76. package/lib/mixins/Fundamental.ts +0 -3
  77. package/lib/support/Day.ts +5 -5
  78. package/lib/support/Utils.ts +35 -14
  79. package/lib/validation/validators/maxLength.ts +2 -2
  80. package/lib/validation/validators/maxValue.ts +2 -2
  81. package/lib/validation/validators/minLength.ts +2 -2
  82. package/lib/validation/validators/minValue.ts +2 -2
  83. package/lib/validation/validators/required.ts +4 -4
  84. package/package.json +40 -40
  85. package/lib/components/SCardFooter.vue +0 -22
  86. package/lib/components/SCardFooterAction.vue +0 -31
  87. package/lib/components/SCardFooterActions.vue +0 -18
  88. package/lib/components/SCardHeader.vue +0 -15
  89. package/lib/components/SCardHeaderAction.vue +0 -28
  90. package/lib/components/SCardHeaderActionClose.vue +0 -27
  91. package/lib/components/SCardHeaderActionCollapse.vue +0 -47
  92. package/lib/components/SCardHeaderActions.vue +0 -13
  93. package/lib/components/SCardHeaderTitle.vue +0 -29
  94. package/lib/components/SIcon.vue +0 -13
  95. package/lib/components/SSheet.vue +0 -87
  96. package/lib/components/SSheetFooter.vue +0 -16
  97. package/lib/components/SSheetFooterAction.vue +0 -34
  98. package/lib/components/SSheetFooterActions.vue +0 -14
  99. package/lib/components/SSheetForm.vue +0 -15
  100. package/lib/components/SSheetMedium.vue +0 -72
  101. package/lib/components/SSheetTitle.vue +0 -13
  102. package/lib/components/STableHeaderActions.vue +0 -20
  103. package/lib/composables/D.ts +0 -21
  104. package/lib/composables/Form.ts +0 -109
  105. package/lib/composables/V.ts +0 -97
  106. package/lib/mixins/Sheet.ts +0 -30
@@ -1,9 +1,13 @@
1
1
  <script setup lang="ts">
2
- import IconGoogle from '@iconify-icons/ri/google-fill'
3
- import { computed } from 'vue'
2
+ import { computed, ref } from 'vue'
3
+ import { usePower } from '../composables/Power'
4
4
  import SButton from './SButton.vue'
5
5
  import SLink from './SLink.vue'
6
+ import SLoginPagePasswordDialog from './SLoginPagePasswordDialog.vue'
7
+ import SModal from './SModal.vue'
6
8
  import SIconGbLogoWhite from './icon/SIconGbLogoWhite.vue'
9
+ import IconLockKey from '~icons/ph/lock-key-fill'
10
+ import IconGoogle from '~icons/ri/google-fill'
7
11
 
8
12
  export interface CoverTitle {
9
13
  text: string
@@ -15,11 +19,20 @@ export interface CoverPhotographer {
15
19
  link: string
16
20
  }
17
21
 
18
- export interface Action {
22
+ export type Action = ActionPassword | ActionSocial
23
+
24
+ export interface ActionPassword {
25
+ type: 'password'
26
+ onSubmit(email: string, password: string): Promise<boolean>
27
+ }
28
+
29
+ export interface ActionSocial {
19
30
  type: 'google'
20
- onClick: () => Promise<void>
31
+ onClick(): Promise<void>
21
32
  }
22
33
 
34
+ export type ActionType = 'password' | 'google'
35
+
23
36
  const props = defineProps<{
24
37
  cover: string
25
38
  coverTitle: CoverTitle
@@ -27,23 +40,51 @@ const props = defineProps<{
27
40
  actions: Action[]
28
41
  }>()
29
42
 
43
+ const passwordDialog = usePower()
44
+
45
+ const selectedPasswordAction = ref<ActionPassword | null>(null)
46
+ const actionInProgress = ref(false)
47
+ const actionError = ref(false)
48
+
30
49
  const coverBgImageStyle = computed(() => `url(${props.cover})`)
31
50
 
32
- function getActionLabel(type: Action['type']) {
51
+ function getActionLabel(type: ActionType) {
33
52
  switch (type) {
53
+ case 'password':
54
+ return 'Sign in via Password'
34
55
  case 'google':
35
56
  return 'Sign in via Google'
36
- default:
37
- throw new Error('[sefirot] Invalid action type')
38
57
  }
39
58
  }
40
59
 
41
- function getIconComponent(type: Action['type']) {
60
+ function getIconComponent(type: ActionType) {
42
61
  switch (type) {
62
+ case 'password':
63
+ return IconLockKey
43
64
  case 'google':
44
65
  return IconGoogle
45
- default:
46
- throw new Error('[sefirot] Invalid action type')
66
+ }
67
+ }
68
+
69
+ function onAction(action: Action) {
70
+ switch (action.type) {
71
+ case 'password':
72
+ selectedPasswordAction.value = action
73
+ return passwordDialog.on()
74
+ case 'google':
75
+ return action.onClick()
76
+ }
77
+ }
78
+
79
+ async function onSubmit(email: string, password: string) {
80
+ actionInProgress.value = true
81
+
82
+ actionError.value = !(await selectedPasswordAction.value!.onSubmit(email, password))
83
+
84
+ actionInProgress.value = false
85
+
86
+ if (!actionError.value) {
87
+ passwordDialog.off()
47
88
  }
48
89
  }
49
90
  </script>
@@ -74,20 +115,30 @@ function getIconComponent(type: Action['type']) {
74
115
  <p class="form-lead">This is a very closed login form meant for specific audiences only. If you can’t login, well, you know who to ask.</p>
75
116
  </div>
76
117
 
77
- <div class="form-actions">
78
- <SButton
79
- v-for="action in actions"
80
- :key="action.type"
81
- size="large"
82
- mode="white"
83
- rounded
84
- :label="getActionLabel(action.type)"
85
- :icon="getIconComponent(action.type)"
86
- @click="action.onClick"
87
- />
118
+ <div class="form-actions" :class="{ multi: actions.length > 1 }">
119
+ <div v-for="action in actions" :key="action.type" class="form-action">
120
+ <SButton
121
+ size="large"
122
+ mode="white"
123
+ block
124
+ rounded
125
+ :label="getActionLabel(action.type)"
126
+ :icon="getIconComponent(action.type)"
127
+ @click="onAction(action)"
128
+ />
129
+ </div>
88
130
  </div>
89
131
  </div>
90
132
  </div>
133
+
134
+ <SModal :open="passwordDialog.state.value" @close="passwordDialog.off">
135
+ <SLoginPagePasswordDialog
136
+ :loading="actionInProgress"
137
+ :error="actionError"
138
+ @cancel="passwordDialog.off"
139
+ @submit="onSubmit"
140
+ />
141
+ </SModal>
91
142
  </div>
92
143
  </template>
93
144
 
@@ -196,9 +247,15 @@ function getIconComponent(type: Action['type']) {
196
247
  display: flex;
197
248
  flex-direction: column;
198
249
  align-items: center;
199
- gap: 8px;
250
+ gap: 16px;
200
251
  padding-top: 24px;
201
252
  text-align: center;
202
253
  margin: 0 auto;
203
254
  }
255
+
256
+ .form-actions.multi .form-action {
257
+ display: block;
258
+ width: 100%;
259
+ max-width: 256px;
260
+ }
204
261
  </style>
@@ -0,0 +1,95 @@
1
+ <script setup lang="ts">
2
+ import { useData } from '../composables/Data'
3
+ import { useValidation } from '../composables/Validation'
4
+ import { email, maxLength, required } from '../validation/rules'
5
+ import SAlert from './SAlert.vue'
6
+ import SCard from './SCard.vue'
7
+ import SCardBlock from './SCardBlock.vue'
8
+ import SContent from './SContent.vue'
9
+ import SControl from './SControl.vue'
10
+ import SControlButton from './SControlButton.vue'
11
+ import SControlRight from './SControlRight.vue'
12
+ import SDoc from './SDoc.vue'
13
+ import SInputText from './SInputText.vue'
14
+
15
+ defineProps<{
16
+ loading: boolean
17
+ error: boolean
18
+ }>()
19
+
20
+ const emit = defineEmits<{
21
+ cancel: []
22
+ submit: [email: string, password: string]
23
+ }>()
24
+
25
+ const { data } = useData({
26
+ email: null as string | null,
27
+ password: null as string | null
28
+ })
29
+
30
+ const { validation, validateAndNotify } = useValidation(data, {
31
+ email: {
32
+ required: required(),
33
+ maxLength: maxLength(255),
34
+ email: email()
35
+ },
36
+ password: {
37
+ required: required(),
38
+ maxLength: maxLength(255)
39
+ }
40
+ })
41
+
42
+ async function onSubmit() {
43
+ if (await validateAndNotify()) {
44
+ emit('submit', data.value.email!, data.value.password!)
45
+ }
46
+ }
47
+ </script>
48
+
49
+ <template>
50
+ <SCard size="small">
51
+ <SCardBlock class="s-p-24">
52
+ <SDoc>
53
+ <SContent>
54
+ <h2>Sign in to account</h2>
55
+ </SContent>
56
+ <SAlert v-if="error" mode="danger">
57
+ <p>Invalid email or password.</p>
58
+ </SAlert>
59
+ <SInputText
60
+ name="email"
61
+ type="email"
62
+ label="Email"
63
+ placeholder="john.doe@example.com"
64
+ v-model="data.email"
65
+ :validation="validation.email"
66
+ />
67
+ <SInputText
68
+ name="password"
69
+ type="password"
70
+ label="Password"
71
+ placeholder="Password"
72
+ v-model="data.password"
73
+ :validation="validation.password"
74
+ />
75
+ </SDoc>
76
+ </SCardBlock>
77
+ <SCardBlock size="xlarge" class="s-px-24">
78
+ <SControl>
79
+ <SControlRight>
80
+ <SControlButton
81
+ label="Cancel"
82
+ :disabled="loading"
83
+ @click="$emit('cancel')"
84
+ />
85
+ <SControlButton
86
+ mode="info"
87
+ label="Sign in"
88
+ :loading="loading"
89
+ @click="onSubmit"
90
+ />
91
+ </SControlRight>
92
+ </SControl>
93
+ </SCardBlock>
94
+ </SCard>
95
+ </template>
@@ -1,10 +1,10 @@
1
1
  <script setup lang="ts">
2
- import IconCaretLeft from '@iconify-icons/ph/caret-left-bold'
3
- import IconCaretRight from '@iconify-icons/ph/caret-right-bold'
4
2
  import { computed } from 'vue'
5
3
  import { useTrans } from '../composables/Lang'
6
4
  import { format } from '../support/Num'
7
5
  import SButton from './SButton.vue'
6
+ import IconCaretLeft from '~icons/ph/caret-left-bold'
7
+ import IconCaretRight from '~icons/ph/caret-right-bold'
8
8
 
9
9
  export type Size = 'mini' | 'small' | 'medium'
10
10
  export type Align = 'left' | 'center' | 'right'
@@ -12,9 +12,6 @@ const props = defineProps<{
12
12
  mode?: Mode
13
13
  label?: string
14
14
  clickable?: boolean
15
-
16
- // @deprecated Use `as` instead.
17
- tag?: string
18
15
  }>()
19
16
 
20
17
  const emit = defineEmits<{
@@ -29,8 +26,7 @@ const classes = computed(() => [
29
26
  ])
30
27
 
31
28
  const computedTag = computed(() => {
32
- const as = props.as ?? props.tag
33
- return as || (props.clickable ? 'button' : 'span')
29
+ return props.as || (props.clickable ? 'button' : 'span')
34
30
  })
35
31
 
36
32
  function onClick() {
@@ -1,8 +1,7 @@
1
1
  <script setup lang="ts">
2
- import IconX from '@iconify-icons/ph/x'
3
2
  import { type SnackbarAction, useSnackbars } from '../stores/Snackbars'
4
3
  import SButton from './SButton.vue'
5
- import SIcon from './SIcon.vue'
4
+ import IconX from '~icons/ph/x'
6
5
 
7
6
  const props = defineProps<{
8
7
  id: number
@@ -21,7 +20,7 @@ function close() {
21
20
  <template>
22
21
  <div class="SSnackbar" :class="[mode ?? 'neutral']">
23
22
  <button class="close" @click="close">
24
- <SIcon :icon="IconX" class="close-icon" />
23
+ <IconX class="close-icon" />
25
24
  </button>
26
25
 
27
26
  <p class="content">
@@ -1,9 +1,8 @@
1
1
  <script setup lang="ts">
2
- import IconCheck from '@iconify-icons/ph/check'
3
- import IconX from '@iconify-icons/ph/x'
4
2
  import { type PropType } from 'vue'
5
3
  import { type BarMode, type StepStatus } from '../composables/Step'
6
- import SIcon from './SIcon.vue'
4
+ import IconCheck from '~icons/ph/check'
5
+ import IconX from '~icons/ph/x'
7
6
 
8
7
  defineProps({
9
8
  status: { type: String as PropType<StepStatus>, required: true },
@@ -19,8 +18,8 @@ defineProps({
19
18
  <div class="bar" :class="[barLeft]" />
20
19
  <div class="point">
21
20
  <div v-if="status === 'active'" class="inner-dot" />
22
- <SIcon v-else-if="status === 'done'" :icon="IconCheck" class="icon" />
23
- <SIcon v-else-if="status === 'failed'" :icon="IconX" class="icon" />
21
+ <IconCheck v-else-if="status === 'done'" class="icon" />
22
+ <IconX v-else-if="status === 'failed'" class="icon" />
24
23
  </div>
25
24
  <div class="bar" :class="[barRight]" />
26
25
  </div>
@@ -98,7 +98,7 @@ const showFooter = computed(() => {
98
98
  return footer
99
99
  }
100
100
 
101
- return (
101
+ return !!(
102
102
  unref(props.options.page)
103
103
  && unref(props.options.perPage)
104
104
  && unref(props.options.total)
@@ -363,7 +363,6 @@ function updateSelected(selected: any) {
363
363
  :total="unref(options.total)"
364
364
  :reset="unref(options.reset)"
365
365
  :menu="unref(options.menu)"
366
- :actions="unref(options.actions)"
367
366
  :borderless="unref(options.borderless)"
368
367
  :on-reset="options.onReset"
369
368
  :selected="Array.isArray(selected) ? selected : undefined"
@@ -37,7 +37,7 @@ const computedCell = computed<TableCell | undefined>(() =>
37
37
  :record="record"
38
38
  :align="computedCell?.align"
39
39
  :icon="computedCell?.icon"
40
- :getter="computedCell?.value"
40
+ :text="computedCell?.value"
41
41
  :link="computedCell?.link"
42
42
  :color="computedCell?.color"
43
43
  :icon-color="computedCell?.iconColor"
@@ -49,7 +49,7 @@ const computedCell = computed<TableCell | undefined>(() =>
49
49
  :record="record"
50
50
  :align="computedCell.align"
51
51
  :icon="computedCell.icon"
52
- :getter="computedCell.value"
52
+ :number="computedCell.value"
53
53
  :separator="computedCell.separator"
54
54
  :link="computedCell.link"
55
55
  :color="computedCell.color"
@@ -58,29 +58,23 @@ const computedCell = computed<TableCell | undefined>(() =>
58
58
  />
59
59
  <STableCellDay
60
60
  v-else-if="computedCell.type === 'day'"
61
- :value="value"
62
- :record="record"
63
61
  :align="computedCell.align"
64
- :getter="computedCell.value"
62
+ :day="computedCell.value"
65
63
  :format="computedCell.format"
66
64
  :color="computedCell.color"
67
65
  />
68
66
  <STableCellPill
69
67
  v-else-if="computedCell.type === 'pill'"
70
- :value="value"
71
- :record="record"
72
- :getter="computedCell.value"
68
+ :pill="computedCell.value"
73
69
  :color="computedCell.color"
74
70
  />
75
71
  <STableCellPills
76
72
  v-else-if="computedCell.type === 'pills'"
77
- :value="value"
78
- :record="record"
79
73
  :pills="computedCell.pills"
80
74
  />
81
75
  <STableCellState
82
76
  v-else-if="computedCell.type === 'state'"
83
- :value="computedCell.label"
77
+ :state="computedCell.label"
84
78
  :mode="computedCell.mode"
85
79
  />
86
80
  <STableCellAvatar
@@ -95,8 +89,6 @@ const computedCell = computed<TableCell | undefined>(() =>
95
89
  />
96
90
  <STableCellAvatars
97
91
  v-else-if="computedCell.type === 'avatars'"
98
- :value="value"
99
- :record="record"
100
92
  :avatars="computedCell.avatars"
101
93
  :color="computedCell.color"
102
94
  :avatar-count="computedCell.avatarCount"
@@ -1,48 +1,31 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
3
2
  import SAvatar from './SAvatar.vue'
4
3
  import SLink from './SLink.vue'
5
4
 
6
- const props = defineProps<{
5
+ defineProps<{
7
6
  value?: any
8
7
  record?: any
9
- image?: string | null | ((value: any, record: any) => string | null | undefined)
10
- name?: string | null | ((value: any, record: any) => string | null | undefined)
11
- link?: string | null | ((value: any, record: any) => string | null | undefined)
8
+ image?: string | null
9
+ name?: string | null
10
+ link?: string | null
12
11
  color?: 'neutral' | 'soft' | 'mute'
13
12
  onClick?(value: any, record: any): void
14
13
  }>()
15
-
16
- const _image = computed(() => resolve(props.image))
17
- const _name = computed(() => resolve(props.name))
18
- const _link = computed(() => resolve(props.link))
19
-
20
- function resolve(
21
- value?: string | null | ((value: any, record: any) => string | null | undefined)
22
- ) {
23
- if (value == null || value === '') {
24
- return null
25
- }
26
-
27
- return typeof value === 'function'
28
- ? value(props.value, props.record)
29
- : value
30
- }
31
14
  </script>
32
15
 
33
16
  <template>
34
- <div class="STableCellAvatar" :class="[{ link: link || onClick }, color]">
17
+ <div class="STableCellAvatar" :class="[{ link: !!(link || onClick) }, color]">
35
18
  <SLink
36
19
  class="container"
37
- :href="_link ?? undefined"
20
+ :href="link || undefined"
38
21
  :role="onClick ? 'button' : null"
39
22
  @click="() => onClick?.(value, record)"
40
23
  >
41
- <div v-if="_image || _name" class="avatar">
42
- <SAvatar size="mini" :avatar="_image" :name="_name" />
24
+ <div v-if="image || name" class="avatar">
25
+ <SAvatar size="mini" :avatar="image" :name="name" />
43
26
  </div>
44
- <span v-if="_name" class="name">
45
- {{ _name }}
27
+ <span v-if="name" class="name">
28
+ {{ name }}
46
29
  </span>
47
30
  </SLink>
48
31
  </div>
@@ -5,9 +5,7 @@ import { type Position } from '../composables/Tooltip'
5
5
  import SAvatar from './SAvatar.vue'
6
6
 
7
7
  const props = withDefaults(defineProps<{
8
- value?: any
9
- record?: any
10
- avatars: TableCellAvatarsOption[] | ((value: any, record: any) => TableCellAvatarsOption[])
8
+ avatars: TableCellAvatarsOption[]
11
9
  color?: 'neutral' | 'soft' | 'mute'
12
10
  avatarCount?: number
13
11
  nameCount?: number
@@ -17,22 +15,16 @@ const props = withDefaults(defineProps<{
17
15
  nameCount: 2
18
16
  })
19
17
 
20
- const _avatars = computed(() => {
21
- return typeof props.avatars === 'function'
22
- ? props.avatars(props.value, props.record)
23
- : props.avatars
24
- })
25
-
26
18
  const avatarDiff = computed(() => {
27
- return _avatars.value.length - props.avatarCount
19
+ return props.avatars.length - props.avatarCount
28
20
  })
29
21
 
30
22
  const displayAvatars = computed(() => {
31
- return _avatars.value.slice(0, props.avatarCount)
23
+ return props.avatars.slice(0, props.avatarCount)
32
24
  })
33
25
 
34
26
  const nameDiff = computed(() => {
35
- return _avatars.value.length - props.nameCount
27
+ return props.avatars.length - props.nameCount
36
28
  })
37
29
 
38
30
  const displayNames = computed(() => {
@@ -41,8 +33,7 @@ const displayNames = computed(() => {
41
33
  return null
42
34
  }
43
35
 
44
- const slicedAvatars = _avatars.value.slice(0, props.nameCount)
45
-
36
+ const slicedAvatars = props.avatars.slice(0, props.nameCount)
46
37
  const names = slicedAvatars.map((avatar) => avatar.name).join(', ')
47
38
 
48
39
  if (nameDiff.value > 0) {
@@ -57,11 +48,7 @@ const displayNames = computed(() => {
57
48
  <div class="STableCellAvatars" :class="[color]">
58
49
  <div class="container">
59
50
  <div v-if="displayAvatars.length" class="avatars">
60
- <div
61
- v-for="(avatar, index) in displayAvatars"
62
- :key="index"
63
- class="avatar"
64
- >
51
+ <div v-for="(avatar, index) in displayAvatars" :key="index" class="avatar">
65
52
  <div class="avatar-box">
66
53
  <SAvatar size="mini" :avatar="avatar.image" :name="avatar.name" :tooltip="tooltip" />
67
54
  </div>
@@ -1,25 +1,18 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
3
2
  import { type Day } from '../support/Day'
4
3
 
5
- const props = defineProps<{
6
- value?: Day | null
7
- record?: any
4
+ defineProps<{
5
+ day?: Day | null
8
6
  align?: 'left' | 'center' | 'right'
9
- getter?: Day | null
10
7
  format?: string
11
8
  color?: 'neutral' | 'soft' | 'mute'
12
9
  }>()
13
-
14
- const _value = computed(() => {
15
- return props.getter ? props.getter : props.value
16
- })
17
10
  </script>
18
11
 
19
12
  <template>
20
13
  <div class="STableCellDay" :class="[align ?? 'left', color ?? 'neutral']">
21
- <div v-if="_value" class="value">
22
- {{ _value.format(format ?? 'YYYY-MM-DD HH:mm:ss') }}
14
+ <div v-if="day" class="value">
15
+ {{ day.format(format ?? 'YYYY-MM-DD HH:mm:ss') }}
23
16
  </div>
24
17
  </div>
25
18
  </template>
@@ -1,16 +1,15 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
2
+ import { type Component, computed } from 'vue'
3
3
  import { type TableCellValueColor } from '../composables/Table'
4
4
  import { format } from '../support/Num'
5
- import SIcon from './SIcon.vue'
6
5
  import SLink from './SLink.vue'
7
6
 
8
7
  const props = defineProps<{
9
8
  value?: any
10
9
  record?: any
11
10
  align?: 'left' | 'center' | 'right'
12
- icon?: any
13
- getter?: number | null
11
+ icon?: Component
12
+ number?: number | null
14
13
  separator?: boolean
15
14
  color?: TableCellValueColor
16
15
  iconColor?: TableCellValueColor
@@ -18,14 +17,14 @@ const props = defineProps<{
18
17
  onClick?(value: any, record: any): void
19
18
  }>()
20
19
 
21
- const _value = computed(() => props.getter ?? props.value)
20
+ const _value = computed(() => props.number ?? props.value)
22
21
  const _color = computed(() => props.color ?? 'neutral')
23
22
  const _iconColor = computed(() => props.iconColor ?? _color.value)
24
23
 
25
24
  const classes = computed(() => [
26
25
  props.align ?? 'left',
27
26
  _color,
28
- { link: props.link || props.onClick }
27
+ { link: !!(props.link || props.onClick) }
29
28
  ])
30
29
  </script>
31
30
 
@@ -38,10 +37,10 @@ const classes = computed(() => [
38
37
  :role="onClick ? 'button' : null"
39
38
  @click="() => onClick?.(value, record)"
40
39
  >
41
- <div v-if="icon" class="icon" :class="[_iconColor]">
42
- <SIcon :icon="icon" class="svg" />
40
+ <div v-if="icon" class="icon" :class="_iconColor">
41
+ <component :is="icon" class="svg" />
43
42
  </div>
44
- <div class="value" :class="[_color ?? 'neutral']">
43
+ <div class="value" :class="_color">
45
44
  {{ separator ? format(_value) : _value }}
46
45
  </div>
47
46
  </SLink>
@@ -1,43 +1,15 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
3
2
  import SPill, { type Mode } from './SPill.vue'
4
3
 
5
- const props = defineProps<{
6
- value?: any
7
- record?: any
8
- getter?: string | ((value: any, record: any) => string)
9
- color?: Mode | ((value: any, record: any) => Mode)
4
+ defineProps<{
5
+ pill?: string
6
+ color?: Mode
10
7
  }>()
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, props.record)
20
- })
21
-
22
- const _color = computed(() => {
23
- if (props.color === undefined) {
24
- return props.color
25
- }
26
-
27
- return typeof props.color === 'string'
28
- ? props.color
29
- : props.color(props.value, props.record)
30
- })
31
8
  </script>
32
9
 
33
10
  <template>
34
- <div class="STableCellPill" :class="[_color ?? 'neutral']">
35
- <SPill
36
- v-if="_value"
37
- size="mini"
38
- :mode="_color"
39
- :label="_value"
40
- />
11
+ <div class="STableCellPill" :class="[color || 'neutral']">
12
+ <SPill v-if="pill" size="mini" :mode="color" :label="pill" />
41
13
  </div>
42
14
  </template>
43
15