@redseed/redseed-ui-vue3 5.0.0 → 5.1.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/index.js +1 -0
- package/package.json +1 -1
- package/src/components/Card/Card.vue +1 -1
- package/src/components/Card/CardHeader.vue +1 -1
- package/src/components/Table/Table.vue +135 -0
- package/src/components/Table/Td.vue +34 -0
- package/src/components/Table/TdUser.vue +44 -0
- package/src/components/Table/Th.vue +103 -0
- package/src/components/Table/Tr.vue +39 -0
- package/src/components/Table/index.js +7 -0
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -73,7 +73,7 @@ function onClick() {
|
|
|
73
73
|
</template>
|
|
74
74
|
<style lang="scss" scoped>
|
|
75
75
|
.rsui-card {
|
|
76
|
-
@apply relative flex flex-col;
|
|
76
|
+
@apply relative flex flex-col overflow-hidden;
|
|
77
77
|
@apply select-none transition duration-200;
|
|
78
78
|
@apply rounded-xl bg-white border border-rsui-grey-400;
|
|
79
79
|
|
|
@@ -107,7 +107,7 @@ const emit = defineEmits(['click:more-actions'])
|
|
|
107
107
|
.rsui-card-header {
|
|
108
108
|
@apply flex flex-col gap-x-3 gap-y-5 overflow-hidden;
|
|
109
109
|
@apply md:flex-row md:justify-between md:items-center;
|
|
110
|
-
@apply border-b border-rsui-grey-400 py-
|
|
110
|
+
@apply border-b border-rsui-grey-400 py-4 px-4 sm:px-6;
|
|
111
111
|
|
|
112
112
|
&__header {
|
|
113
113
|
@apply flex-1 flex justify-between md:items-center gap-x-3;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { Card, CardHeader } from '../Card'
|
|
3
|
+
import Tr from './Tr.vue'
|
|
4
|
+
import Th from './Th.vue'
|
|
5
|
+
import Td from './Td.vue'
|
|
6
|
+
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
columns: {
|
|
9
|
+
type: Array,
|
|
10
|
+
default: () => [],
|
|
11
|
+
validator: value => {
|
|
12
|
+
if (value.length === 0) return true
|
|
13
|
+
return value.every(column => typeof column === 'object' && column.key && column.name !== undefined)
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
rows: {
|
|
17
|
+
type: Array,
|
|
18
|
+
default: () => [],
|
|
19
|
+
validator: value => {
|
|
20
|
+
if (value.length === 0) return true
|
|
21
|
+
return value.every(row => typeof row === 'object' && row.id)
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
clickableRows: {
|
|
25
|
+
type: Boolean,
|
|
26
|
+
default: false,
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<Card
|
|
33
|
+
:clickable="false"
|
|
34
|
+
:hoverable="false"
|
|
35
|
+
:padded="false"
|
|
36
|
+
>
|
|
37
|
+
<template #header>
|
|
38
|
+
<CardHeader
|
|
39
|
+
v-bind="$attrs.cardHeader"
|
|
40
|
+
@click:more-actions="$emit('click:more-actions')"
|
|
41
|
+
>
|
|
42
|
+
<template #avatar v-if="$slots.avatar">
|
|
43
|
+
<slot name="avatar"></slot>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<slot name="title"></slot>
|
|
47
|
+
|
|
48
|
+
<template #badge v-if="$slots.badge">
|
|
49
|
+
<slot name="badge"></slot>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<template #subtitle v-if="$slots.subtitle">
|
|
53
|
+
<slot name="subtitle"></slot>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<template #actions v-if="$slots.actions">
|
|
57
|
+
<slot name="actions"></slot>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<template #more-actions v-if="$slots['more-actions']">
|
|
61
|
+
<slot name="more-actions"></slot>
|
|
62
|
+
</template>
|
|
63
|
+
</CardHeader>
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<div class="rsui-table">
|
|
67
|
+
<div class="rsui-table__container">
|
|
68
|
+
<table>
|
|
69
|
+
<thead v-if="columns">
|
|
70
|
+
<Tr>
|
|
71
|
+
<Th v-for="column in columns"
|
|
72
|
+
:key="column.key"
|
|
73
|
+
scope="col"
|
|
74
|
+
:alignment="column?.alignment"
|
|
75
|
+
:sort="column?.sort"
|
|
76
|
+
@sort="$emit('sort', { column: { ...column, ...$event } })"
|
|
77
|
+
>
|
|
78
|
+
{{ column.name }}
|
|
79
|
+
</Th>
|
|
80
|
+
</Tr>
|
|
81
|
+
</thead>
|
|
82
|
+
|
|
83
|
+
<tbody>
|
|
84
|
+
<Tr v-for="row in rows"
|
|
85
|
+
:key="row.id"
|
|
86
|
+
:clickable="clickableRows"
|
|
87
|
+
@click="$emit('click:row', row)"
|
|
88
|
+
>
|
|
89
|
+
<Td v-for="column in columns"
|
|
90
|
+
:key="column.key"
|
|
91
|
+
>
|
|
92
|
+
<slot :name="'td-' + column.key"
|
|
93
|
+
:row="row"
|
|
94
|
+
>
|
|
95
|
+
{{ row[column.key] }}
|
|
96
|
+
</slot>
|
|
97
|
+
</Td>
|
|
98
|
+
</Tr>
|
|
99
|
+
</tbody>
|
|
100
|
+
</table>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div class="rsui-table__footer"
|
|
104
|
+
v-if="$slots.footer"
|
|
105
|
+
>
|
|
106
|
+
<slot name="footer"></slot>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</Card>
|
|
110
|
+
</template>
|
|
111
|
+
<style lang="scss" scoped>
|
|
112
|
+
.rsui-table {
|
|
113
|
+
@apply w-full;
|
|
114
|
+
|
|
115
|
+
table {
|
|
116
|
+
@apply w-full border-collapse table-auto;
|
|
117
|
+
|
|
118
|
+
tr{
|
|
119
|
+
th {
|
|
120
|
+
@apply bg-rsui-grey-100;
|
|
121
|
+
@apply font-semibold text-xs leading-5 text-rsui-grey-600 hover:text-rsui-grey-700;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&__container {
|
|
127
|
+
@apply w-full overflow-x-scroll;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&__footer {
|
|
131
|
+
@apply w-full border-t border-rsui-grey-400 overflow-hidden;
|
|
132
|
+
@apply py-3 px-6;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
alignment: {
|
|
4
|
+
type: String,
|
|
5
|
+
default: 'left',
|
|
6
|
+
validator: value => ['left', 'center', 'right'].includes(value),
|
|
7
|
+
},
|
|
8
|
+
})
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<td :class="[
|
|
13
|
+
'rsui-td',
|
|
14
|
+
{
|
|
15
|
+
'rsui-td--center': alignment === 'center',
|
|
16
|
+
'rsui-td--right': alignment === 'right',
|
|
17
|
+
},
|
|
18
|
+
]">
|
|
19
|
+
<slot></slot>
|
|
20
|
+
</td>
|
|
21
|
+
</template>
|
|
22
|
+
<style lang="scss" scoped>
|
|
23
|
+
.rsui-td {
|
|
24
|
+
@apply text-left whitespace-nowrap;
|
|
25
|
+
@apply py-3 px-6 text-sm leading-6 text-rsui-grey-700;
|
|
26
|
+
|
|
27
|
+
&--center {
|
|
28
|
+
@apply text-center;
|
|
29
|
+
}
|
|
30
|
+
&--right {
|
|
31
|
+
@apply text-right;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { UserIcon } from '@heroicons/vue/24/outline'
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<div class="rsui-td-user">
|
|
7
|
+
<div class="rsui-td-user__avatar">
|
|
8
|
+
<slot name="avatar">
|
|
9
|
+
<UserIcon class="rsui-td-user__avatar-icon" />
|
|
10
|
+
</slot>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="rsui-td-user__content">
|
|
14
|
+
<slot></slot>
|
|
15
|
+
|
|
16
|
+
<div class="rsui-td-user__supporting-text">
|
|
17
|
+
<slot name="supporting-text"></slot>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<style lang="scss" scoped>
|
|
24
|
+
.rsui-td-user {
|
|
25
|
+
@apply flex items-center gap-3;
|
|
26
|
+
|
|
27
|
+
&__avatar {
|
|
28
|
+
@apply flex items-center justify-center size-10 rounded-full overflow-hidden shrink-0;
|
|
29
|
+
@apply text-rsui-grey-600 border border-rsui-grey-200 bg-rsui-grey-100;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&__avatar-icon {
|
|
33
|
+
@apply size-6;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&__content {
|
|
37
|
+
@apply flex flex-col text-rsui-grey-900;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&__supporting-text {
|
|
41
|
+
@apply text-rsui-grey-700;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
3
|
+
import { ArrowUpIcon, ChevronUpDownIcon } from '@heroicons/vue/24/outline'
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
alignment: {
|
|
7
|
+
type: String,
|
|
8
|
+
default: 'left',
|
|
9
|
+
validator: value => ['left', 'center', 'right'].includes(value),
|
|
10
|
+
},
|
|
11
|
+
sort: {
|
|
12
|
+
type: [Boolean, String],
|
|
13
|
+
default: false,
|
|
14
|
+
validator: value => ['asc', 'desc', true, false].includes(value),
|
|
15
|
+
},
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const sortable = computed(() => props.sort !== false)
|
|
19
|
+
|
|
20
|
+
const isAsc = ref(props.sort === 'asc')
|
|
21
|
+
|
|
22
|
+
const isDesc = ref(props.sort === 'desc')
|
|
23
|
+
|
|
24
|
+
const emit = defineEmits(['sort'])
|
|
25
|
+
|
|
26
|
+
function handleSort() {
|
|
27
|
+
if (!sortable.value) return
|
|
28
|
+
|
|
29
|
+
isDesc.value = isAsc.value
|
|
30
|
+
isAsc.value = !isAsc.value
|
|
31
|
+
|
|
32
|
+
emit('sort', {
|
|
33
|
+
sort: isAsc.value ? 'asc' : 'desc',
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<th
|
|
40
|
+
:class="[
|
|
41
|
+
'rsui-th',
|
|
42
|
+
{
|
|
43
|
+
'rsui-th--center': alignment === 'center',
|
|
44
|
+
'rsui-th--right': alignment === 'right',
|
|
45
|
+
'rsui-th--sortable': sortable,
|
|
46
|
+
},
|
|
47
|
+
]"
|
|
48
|
+
@click="handleSort"
|
|
49
|
+
>
|
|
50
|
+
<div class="rsui-th__content">
|
|
51
|
+
<slot></slot>
|
|
52
|
+
|
|
53
|
+
<div v-if="sortable"
|
|
54
|
+
class="rsui-th__sort"
|
|
55
|
+
>
|
|
56
|
+
<ChevronUpDownIcon v-if="!isAsc && !isDesc"
|
|
57
|
+
class="rsui-th__sort-icon"
|
|
58
|
+
/>
|
|
59
|
+
<ArrowUpIcon v-if="isAsc || isDesc"
|
|
60
|
+
:class="[
|
|
61
|
+
'rsui-th__sort-icon',
|
|
62
|
+
{
|
|
63
|
+
'rsui-th__sort-icon--asc': isAsc,
|
|
64
|
+
'rsui-th__sort-icon--desc': isDesc,
|
|
65
|
+
},
|
|
66
|
+
]"
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</th>
|
|
71
|
+
</template>
|
|
72
|
+
<style lang="scss" scoped>
|
|
73
|
+
.rsui-th {
|
|
74
|
+
@apply text-left whitespace-nowrap;
|
|
75
|
+
@apply py-3 px-6 text-sm leading-6 text-rsui-grey-700;
|
|
76
|
+
|
|
77
|
+
&--center {
|
|
78
|
+
@apply text-center;
|
|
79
|
+
}
|
|
80
|
+
&--right {
|
|
81
|
+
@apply text-right;
|
|
82
|
+
}
|
|
83
|
+
&--sortable {
|
|
84
|
+
@apply cursor-pointer;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
&__content {
|
|
88
|
+
@apply inline-flex items-center gap-1;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&__sort {
|
|
92
|
+
@apply shrink-0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&__sort-icon {
|
|
96
|
+
@apply size-3 transition-all;
|
|
97
|
+
|
|
98
|
+
&--desc {
|
|
99
|
+
@apply rotate-180;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
clickable: {
|
|
4
|
+
type: Boolean,
|
|
5
|
+
default: false,
|
|
6
|
+
},
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
const emit = defineEmits(['click'])
|
|
10
|
+
|
|
11
|
+
function handleClick() {
|
|
12
|
+
if (!props.clickable) return
|
|
13
|
+
|
|
14
|
+
emit('click')
|
|
15
|
+
}
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<tr
|
|
20
|
+
:class="[
|
|
21
|
+
'rsui-tr',
|
|
22
|
+
{ 'rsui-tr--clickable': clickable },
|
|
23
|
+
]"
|
|
24
|
+
@click="handleClick"
|
|
25
|
+
>
|
|
26
|
+
<slot></slot>
|
|
27
|
+
</tr>
|
|
28
|
+
</template>
|
|
29
|
+
<style lang="scss" scoped>
|
|
30
|
+
.rsui-tr {
|
|
31
|
+
@apply transition-all;
|
|
32
|
+
@apply border-b border-rsui-grey-400 rounded-lg;
|
|
33
|
+
@apply last:border-b-transparent only:border-b-rsui-grey-400;
|
|
34
|
+
|
|
35
|
+
&--clickable {
|
|
36
|
+
@apply cursor-pointer hover:bg-rsui-grey-100;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
</style>
|