cynx-ui 1.3.24 → 1.3.26
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/components/Badge.jsx +93 -68
- package/components/Card.jsx +132 -62
- package/components/Pagination.jsx +52 -41
- package/index.js +97 -97
- package/package.json +1 -1
package/components/Badge.jsx
CHANGED
|
@@ -1,34 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
1
3
|
const VARIANTS = {
|
|
2
|
-
ok:
|
|
3
|
-
err:
|
|
4
|
-
warn:
|
|
5
|
-
blue:
|
|
6
|
-
dim:
|
|
7
|
-
purple:
|
|
8
|
-
teal:
|
|
9
|
-
pink:
|
|
10
|
-
ghost:
|
|
11
|
-
paid: { bg: 'var(--pd, rgba(30,41,59,.08))', color: 'var(--t, #1e293b)', border: 'var(--accent-border, rgba(30,41,59,.15))', dot: 'var(--t, #1e293b)' },
|
|
12
|
-
invoiced: { bg: 'rgba(120,120,130,.08)', color: 'var(--t2, #787882)', border: 'rgba(120,120,130,.15)', dot: 'var(--t2, #787882)' },
|
|
13
|
-
verified: { bg: 'var(--sd, rgba(34,197,94,.08))', color: 'var(--s, #22c55e)', border: 'var(--sd, rgba(34,197,94,.15))', dot: 'var(--s, #22c55e)' },
|
|
14
|
-
partial: { bg: 'rgba(100,100,110,.08)', color: '#64646e', border: 'rgba(100,100,110,.15)', dot: '#64646e' },
|
|
15
|
-
deleted: { bg: 'var(--dd, rgba(239,68,68,.08))', color: 'var(--d, #ef4444)', border: 'var(--dd, rgba(239,68,68,.15))', dot: 'var(--d, #ef4444)' },
|
|
16
|
-
update: { bg: 'var(--wd, rgba(249,115,22,.08))', color: 'var(--w, #f97316)', border: 'var(--wd, rgba(249,115,22,.15))', dot: 'var(--w, #f97316)' },
|
|
17
|
-
ready: { bg: 'var(--wd, rgba(234,179,8,.08))', color: 'var(--w, #eab308)', border: 'var(--wd, rgba(234,179,8,.15))', dot: 'var(--w, #eab308)' },
|
|
18
|
-
new: { bg: 'var(--infd, rgba(59,130,246,.08))', color: 'var(--inf, #3b82f6)', border: 'var(--infd, rgba(59,130,246,.15))', dot: 'var(--inf, #3b82f6)' },
|
|
19
|
-
active: { bg: 'transparent', color: 'var(--s, #22c55e)', border: 'none', dot: 'var(--s, #22c55e)', noPad: true },
|
|
20
|
-
inactive: { bg: 'transparent', color: 'var(--d, #ef4444)', border: 'none', dot: 'var(--d, #ef4444)', noPad: true },
|
|
21
|
-
pending: { bg: 'transparent', color: 'var(--w, #d97706)', border: 'none', dot: 'var(--w, #d97706)', noPad: true, pulse: true },
|
|
4
|
+
ok: { bg: 'var(--success-bg,rgba(39,174,96,.1))', color: 'var(--success,#27ae60)', border: 'var(--sd, rgba(39,174,96,.2))', dot: 'var(--success,#27ae60)' },
|
|
5
|
+
err: { bg: 'var(--danger-bg,rgba(246,71,71,.1))', color: 'var(--danger,#f64747)', border: 'var(--dd, rgba(246,71,71,.2))', dot: 'var(--danger,#f64747)' },
|
|
6
|
+
warn: { bg: 'var(--accent-bg,rgba(249,158,44,.1))', color: 'var(--accent,#f99e2c)', border: 'var(--accent-border,rgba(249,158,44,.25))', dot: 'var(--accent,#f99e2c)' },
|
|
7
|
+
blue: { bg: 'var(--blue-bg,rgba(39,130,228,.1))', color: 'var(--blue,#2782e4)', border: 'var(--infd, rgba(39,130,228,.2))', dot: 'var(--blue,#2782e4)' },
|
|
8
|
+
dim: { bg: 'var(--grey-1,#f5f5f8)', color: 'var(--grey-4,#797b8d)', border: 'var(--border,#d7d8e0)', dot: 'var(--grey-4,#797b8d)' },
|
|
9
|
+
purple: { bg: 'rgba(139,92,246,.1)', color: '#8b5cf6', border: 'rgba(139,92,246,.2)', dot: '#8b5cf6' },
|
|
10
|
+
teal: { bg: 'rgba(20,184,166,.1)', color: '#14b8a6', border: 'rgba(20,184,166,.2)', dot: '#14b8a6' },
|
|
11
|
+
pink: { bg: 'rgba(236,72,153,.1)', color: '#ec4899', border: 'rgba(236,72,153,.2)', dot: '#ec4899' },
|
|
12
|
+
ghost: { bg: 'transparent', color: 'var(--t2,var(--grey-4,#797b8d))', border: 'var(--bd,var(--border,#d7d8e0))', dot: 'var(--t3,var(--grey-4,#797b8d))' },
|
|
22
13
|
};
|
|
23
14
|
|
|
24
15
|
const SHAPES = {
|
|
25
16
|
ok: 'circle', err: 'circle', warn: 'circle', blue: 'circle', dim: 'circle',
|
|
26
17
|
purple: 'circle', teal: 'circle', pink: 'circle', ghost: 'circle',
|
|
27
|
-
paid: 'circle', invoiced: 'circle', verified: 'circle', partial: 'semicircle',
|
|
28
|
-
deleted: 'circle', update: 'triangle', ready: 'diamond', new: 'circle',
|
|
29
18
|
};
|
|
30
19
|
|
|
31
|
-
const KEYFRAMES = `@keyframes badge-pulse{0%,100%{opacity:1}50%{opacity:.4}}`;
|
|
20
|
+
const KEYFRAMES = `@keyframes badge-pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(0.85)}}`;
|
|
32
21
|
let _id = 'cynx-badge-styles';
|
|
33
22
|
|
|
34
23
|
function ensureStyles() {
|
|
@@ -41,28 +30,26 @@ function ensureStyles() {
|
|
|
41
30
|
}
|
|
42
31
|
|
|
43
32
|
const SIZE_MAP = {
|
|
44
|
-
xs: { padding: '1.5px 6px', fontSize: '
|
|
45
|
-
sm: { padding: '2px
|
|
46
|
-
md: { padding: '3px 9px', fontSize: '
|
|
47
|
-
lg: { padding: '4px 12px', fontSize: '
|
|
33
|
+
xs: { padding: '1.5px 6px', plainPadding: '1px 0', fontSize: '9.5px', dotSize: 5, iconSize: 11, gap: 4 },
|
|
34
|
+
sm: { padding: '2px 8px', plainPadding: '2px 0', fontSize: '11px', dotSize: 6, iconSize: 12, gap: 5 },
|
|
35
|
+
md: { padding: '3px 9px', plainPadding: '2px 0', fontSize: '12px', dotSize: 6.5, iconSize: 13, gap: 6 },
|
|
36
|
+
lg: { padding: '4px 12px', plainPadding: '3px 0', fontSize: '13px', dotSize: 8, iconSize: 15, gap: 7 },
|
|
48
37
|
};
|
|
49
38
|
|
|
50
39
|
const SHAPE_STYLE = {
|
|
51
|
-
circle:
|
|
52
|
-
triangle:
|
|
53
|
-
diamond:
|
|
40
|
+
circle: (c) => ({ width: 7, height: 7, borderRadius: '50%', background: c, border: 'none' }),
|
|
41
|
+
triangle: (c) => ({ width: 0, height: 0, borderLeft: '4px solid transparent', borderRight: '4px solid transparent', borderBottom: `7px solid ${c}`, background: 'none', borderTop: 'none' }),
|
|
42
|
+
diamond: (c) => ({ width: 7, height: 7, borderRadius: 1, transform: 'rotate(45deg)', background: c, border: 'none' }),
|
|
54
43
|
semicircle:(c) => ({ width: 7, height: 7, borderRadius: '50%', border: 'none', borderTop: '2px solid var(--bg,#fff)', background: c }),
|
|
55
44
|
};
|
|
56
45
|
|
|
57
46
|
const COLOR_MAP = {
|
|
58
|
-
green: '#10b981',
|
|
59
|
-
yellow: '#f59e0b',
|
|
60
|
-
red: '#ef4444',
|
|
61
|
-
blue: '#3b82f6',
|
|
62
|
-
purple: '#8b5cf6', violet: '#8b5cf6',
|
|
63
|
-
|
|
64
|
-
cyan: '#06b6d4',
|
|
65
|
-
teal: '#14b8a6',
|
|
47
|
+
green: '#10b981', ok: '#10b981', success: '#10b981', emerald: '#10b981',
|
|
48
|
+
yellow: '#f59e0b', warn: '#f97316', warning: '#f97316', amber: '#f59e0b', orange: '#f97316',
|
|
49
|
+
red: '#ef4444', err: '#ef4444', danger: '#ef4444', error: '#ef4444', critical: '#ef4444',
|
|
50
|
+
blue: '#3b82f6', info: '#3b82f6', sky: '#0284c7',
|
|
51
|
+
purple: '#8b5cf6', violet: '#8b5cf6', indigo: '#6366f1',
|
|
52
|
+
cyan: '#06b6d4', teal: '#14b8a6',
|
|
66
53
|
pink: '#ec4899', rose: '#f43f5e',
|
|
67
54
|
grey: '#6b7280', gray: '#6b7280', dim: '#6b7280',
|
|
68
55
|
};
|
|
@@ -83,6 +70,11 @@ export default function Badge({
|
|
|
83
70
|
dot = false,
|
|
84
71
|
shape = null,
|
|
85
72
|
icon = null,
|
|
73
|
+
iconPosition = 'left',
|
|
74
|
+
iconSize = null,
|
|
75
|
+
pulse = false,
|
|
76
|
+
plain = false,
|
|
77
|
+
minimal = false,
|
|
86
78
|
onClick = null,
|
|
87
79
|
style = {},
|
|
88
80
|
className = '',
|
|
@@ -91,15 +83,59 @@ export default function Badge({
|
|
|
91
83
|
|
|
92
84
|
const v = VARIANTS[variant] || VARIANTS.dim;
|
|
93
85
|
const sz = SIZE_MAP[size] || SIZE_MAP.md;
|
|
86
|
+
const isPlain = plain || minimal;
|
|
94
87
|
const shapeType = (shape === 'none' || shape === false) ? null : (shape || SHAPES[variant] || null);
|
|
95
88
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
const customColor = resolveBadgeColor(color);
|
|
90
|
+
let colorStyle = {};
|
|
91
|
+
|
|
92
|
+
if (customColor) {
|
|
93
|
+
if (isPlain) {
|
|
94
|
+
colorStyle = { color: customColor, background: 'transparent', border: 'none' };
|
|
95
|
+
} else if (customColor.startsWith('#')) {
|
|
96
|
+
colorStyle = {
|
|
97
|
+
color: customColor,
|
|
98
|
+
background: `${customColor}18`,
|
|
99
|
+
border: `1px solid ${customColor}33`,
|
|
100
|
+
};
|
|
101
|
+
} else {
|
|
102
|
+
colorStyle = {
|
|
103
|
+
color: customColor,
|
|
104
|
+
background: `color-mix(in srgb, ${customColor} 12%, transparent)`,
|
|
105
|
+
border: `1px solid color-mix(in srgb, ${customColor} 25%, transparent)`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
} else if (isPlain) {
|
|
109
|
+
colorStyle = {
|
|
110
|
+
color: v.color,
|
|
111
|
+
background: 'transparent',
|
|
112
|
+
border: 'none',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const dotColor = customColor || v.dot || v.color;
|
|
117
|
+
const actualDotSize = sz.dotSize || 6;
|
|
118
|
+
const actualIconSize = iconSize || sz.iconSize || 13;
|
|
119
|
+
|
|
120
|
+
const renderIcon = () => {
|
|
121
|
+
if (!icon) return null;
|
|
122
|
+
return (
|
|
123
|
+
<span style={{
|
|
124
|
+
display: 'inline-flex',
|
|
125
|
+
alignItems: 'center',
|
|
126
|
+
justifyContent: 'center',
|
|
127
|
+
flexShrink: 0,
|
|
128
|
+
color: dotColor,
|
|
129
|
+
}}>
|
|
130
|
+
{React.isValidElement(icon)
|
|
131
|
+
? React.cloneElement(icon, {
|
|
132
|
+
size: icon.props?.size || actualIconSize,
|
|
133
|
+
color: icon.props?.color || dotColor,
|
|
134
|
+
})
|
|
135
|
+
: icon}
|
|
136
|
+
</span>
|
|
137
|
+
);
|
|
138
|
+
};
|
|
103
139
|
|
|
104
140
|
return (
|
|
105
141
|
<span
|
|
@@ -107,31 +143,32 @@ export default function Badge({
|
|
|
107
143
|
style={{
|
|
108
144
|
display: 'inline-flex',
|
|
109
145
|
alignItems: 'center',
|
|
110
|
-
gap: 5,
|
|
111
|
-
padding:
|
|
112
|
-
borderRadius: 'var(--rfull,99px)',
|
|
146
|
+
gap: sz.gap || 5,
|
|
147
|
+
padding: isPlain ? sz.plainPadding : sz.padding,
|
|
148
|
+
borderRadius: isPlain ? 0 : 'var(--rfull,99px)',
|
|
113
149
|
fontSize: sz.fontSize,
|
|
114
|
-
fontWeight: 600,
|
|
115
|
-
border: `1px solid ${v.border}`,
|
|
116
|
-
background: v.bg,
|
|
150
|
+
fontWeight: isPlain ? 500 : 600,
|
|
151
|
+
border: isPlain ? 'none' : `1px solid ${v.border}`,
|
|
152
|
+
background: isPlain ? 'transparent' : v.bg,
|
|
117
153
|
color: v.color,
|
|
118
154
|
whiteSpace: 'nowrap',
|
|
119
155
|
transition: 'all .15s',
|
|
120
156
|
cursor: onClick ? 'pointer' : undefined,
|
|
157
|
+
lineHeight: 1.2,
|
|
121
158
|
...colorStyle,
|
|
122
159
|
...style,
|
|
123
160
|
}}
|
|
124
161
|
onClick={onClick}
|
|
125
162
|
>
|
|
163
|
+
{icon && iconPosition === 'left' && renderIcon()}
|
|
126
164
|
{dot && (
|
|
127
165
|
<span style={{
|
|
128
|
-
width:
|
|
129
|
-
height:
|
|
166
|
+
width: actualDotSize,
|
|
167
|
+
height: actualDotSize,
|
|
130
168
|
borderRadius: '50%',
|
|
131
169
|
flexShrink: 0,
|
|
132
|
-
marginTop: -2,
|
|
133
170
|
background: dotColor,
|
|
134
|
-
animation:
|
|
171
|
+
animation: pulse ? 'badge-pulse 1.5s ease-in-out infinite' : undefined,
|
|
135
172
|
}} />
|
|
136
173
|
)}
|
|
137
174
|
{shapeType && !dot && (
|
|
@@ -142,20 +179,8 @@ export default function Badge({
|
|
|
142
179
|
...(SHAPE_STYLE[shapeType] ? SHAPE_STYLE[shapeType](dotColor) : {}),
|
|
143
180
|
}} />
|
|
144
181
|
)}
|
|
145
|
-
{icon && (
|
|
146
|
-
<span style={{
|
|
147
|
-
display: 'inline-flex',
|
|
148
|
-
alignItems: 'center',
|
|
149
|
-
justifyContent: 'center',
|
|
150
|
-
width: 14,
|
|
151
|
-
height: 14,
|
|
152
|
-
flexShrink: 0,
|
|
153
|
-
color: dotColor,
|
|
154
|
-
}}>
|
|
155
|
-
{icon}
|
|
156
|
-
</span>
|
|
157
|
-
)}
|
|
158
182
|
{children}
|
|
183
|
+
{icon && iconPosition === 'right' && renderIcon()}
|
|
159
184
|
</span>
|
|
160
185
|
);
|
|
161
186
|
}
|
package/components/Card.jsx
CHANGED
|
@@ -1,62 +1,132 @@
|
|
|
1
|
-
import { Pagination } from './Pagination';
|
|
2
|
-
|
|
3
|
-
export function PageShell({ title, children }) {
|
|
4
|
-
return (
|
|
5
|
-
<div style={{
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
1
|
+
import { Pagination } from './Pagination';
|
|
2
|
+
|
|
3
|
+
export function PageShell({ title, children, style = {} }) {
|
|
4
|
+
return (
|
|
5
|
+
<div style={{
|
|
6
|
+
flex: 1,
|
|
7
|
+
display: 'flex',
|
|
8
|
+
flexDirection: 'column',
|
|
9
|
+
minHeight: 0,
|
|
10
|
+
height: '100%',
|
|
11
|
+
padding: '20px 24px',
|
|
12
|
+
boxSizing: 'border-box',
|
|
13
|
+
overflow: 'hidden',
|
|
14
|
+
...style,
|
|
15
|
+
}}>
|
|
16
|
+
{children}
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function TableCard({ children, style = {} }) {
|
|
22
|
+
return (
|
|
23
|
+
<div style={{
|
|
24
|
+
flex: 1,
|
|
25
|
+
display: 'flex',
|
|
26
|
+
flexDirection: 'column',
|
|
27
|
+
minHeight: 0,
|
|
28
|
+
height: '100%',
|
|
29
|
+
overflow: 'hidden',
|
|
30
|
+
...style,
|
|
31
|
+
}}>
|
|
32
|
+
{children}
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function TableCardFilters({ children, style = {} }) {
|
|
38
|
+
return (
|
|
39
|
+
<div style={{
|
|
40
|
+
flexShrink: 0,
|
|
41
|
+
display: 'flex',
|
|
42
|
+
alignItems: 'center',
|
|
43
|
+
gap: 8,
|
|
44
|
+
padding: '8px 0',
|
|
45
|
+
borderBottom: '1px solid var(--border-light, #ebebf0)',
|
|
46
|
+
...style,
|
|
47
|
+
}}>
|
|
48
|
+
{children}
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function TableCardBody({ children, style = {} }) {
|
|
54
|
+
return (
|
|
55
|
+
<div style={{
|
|
56
|
+
flex: 1,
|
|
57
|
+
overflowY: 'auto',
|
|
58
|
+
minHeight: 0,
|
|
59
|
+
scrollbarWidth: 'thin',
|
|
60
|
+
scrollbarColor: 'var(--grey-2, #d7d8e0) transparent',
|
|
61
|
+
...style,
|
|
62
|
+
}}>
|
|
63
|
+
{children}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function TableCardFooter({ total = 0, page = 1, limit = 100, pages = 1, onChange, style = {} }) {
|
|
69
|
+
const from = total === 0 ? 0 : (page - 1) * limit + 1;
|
|
70
|
+
const to = Math.min(page * limit, total);
|
|
71
|
+
return (
|
|
72
|
+
<div style={{
|
|
73
|
+
flexShrink: 0,
|
|
74
|
+
marginTop: 'auto',
|
|
75
|
+
display: 'flex',
|
|
76
|
+
alignItems: 'center',
|
|
77
|
+
justifyContent: 'space-between',
|
|
78
|
+
padding: '12px 0 0 0',
|
|
79
|
+
borderTop: '1px solid var(--border-light, #ebebf0)',
|
|
80
|
+
fontSize: '.78rem',
|
|
81
|
+
color: 'var(--muted, #9b9daa)',
|
|
82
|
+
boxSizing: 'border-box',
|
|
83
|
+
...style,
|
|
84
|
+
}}>
|
|
85
|
+
<span>
|
|
86
|
+
{total === 0 ? '0 записей' : `${from}–${to} из ${total}`}
|
|
87
|
+
</span>
|
|
88
|
+
<Pagination page={page} pages={pages} onChange={onChange} />
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function CardHdr({ title, icon: Icon, tabs, children, style = {} }) {
|
|
94
|
+
return (
|
|
95
|
+
<div style={{
|
|
96
|
+
flexShrink: 0,
|
|
97
|
+
display: 'flex',
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
justifyContent: 'space-between',
|
|
100
|
+
padding: '0',
|
|
101
|
+
height: 48,
|
|
102
|
+
borderBottom: '1px solid var(--border-light, #ebebf0)',
|
|
103
|
+
...style,
|
|
104
|
+
}}>
|
|
105
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: '.85rem', fontWeight: 600, color: 'var(--primary-text, #0f111c)' }}>
|
|
106
|
+
{Icon && <Icon size={14} />}
|
|
107
|
+
{title}
|
|
108
|
+
{tabs && <span style={{ marginLeft: 12 }}>{tabs}</span>}
|
|
109
|
+
</div>
|
|
110
|
+
{children && <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>{children}</div>}
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function StatCard({ label, value, sub }) {
|
|
116
|
+
return (
|
|
117
|
+
<div style={{ background: 'var(--surface, #fff)', border: '1px solid var(--border-light, #ebebf0)', borderRadius: 'var(--rads, 8px)', padding: '14px 16px', boxShadow: 'var(--shadow, 0px 1px 3px rgba(20,22,41,.10))' }}>
|
|
118
|
+
<div style={{ fontSize: '.62rem', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '.08em', color: 'var(--muted, #9b9daa)', marginBottom: 4 }}>{label}</div>
|
|
119
|
+
<div style={{ fontSize: '1.4rem', fontWeight: 700, color: 'var(--primary-text, #0f111c)', lineHeight: 1.2 }}>{value ?? '—'}</div>
|
|
120
|
+
{sub && <div style={{ fontSize: '.72rem', color: 'var(--muted, #9b9daa)', marginTop: 2 }}>{sub}</div>}
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function StatCardSkeleton() {
|
|
126
|
+
return (
|
|
127
|
+
<div style={{ background: 'var(--surface, #fff)', border: '1px solid var(--border-light, #ebebf0)', borderRadius: 'var(--rads, 8px)', padding: '14px 16px' }}>
|
|
128
|
+
<div className="skeleton skeleton-text" style={{ marginBottom: 10, height: 12, width: '40%', background: 'linear-gradient(90deg, var(--grey-1, #f5f5f8) 25%, var(--border-light, #ebebf0) 50%, var(--grey-1, #f5f5f8) 75%)', backgroundSize: '600px 100%', animation: 'shimmer 1.4s ease infinite', borderRadius: 'var(--radxs, 6px)' }} />
|
|
129
|
+
<div className="skeleton skeleton-text" style={{ height: 28, width: '60%', marginBottom: 6, background: 'linear-gradient(90deg, var(--grey-1, #f5f5f8) 25%, var(--border-light, #ebebf0) 50%, var(--grey-1, #f5f5f8) 75%)', backgroundSize: '600px 100%', animation: 'shimmer 1.4s ease infinite', borderRadius: 'var(--radxs, 6px)' }} />
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
@@ -1,41 +1,52 @@
|
|
|
1
|
-
import Button from './Button';
|
|
2
|
-
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
|
3
|
-
|
|
4
|
-
export function Pagination({ page, pages, total, perPage, onChange }) {
|
|
5
|
-
const totalPages = pages || (total && perPage ? Math.ceil(total / perPage) : 0);
|
|
6
|
-
if (!totalPages || totalPages <= 1) return null;
|
|
7
|
-
|
|
8
|
-
const items = [];
|
|
9
|
-
for (let i = 1; i <= totalPages; i++) {
|
|
10
|
-
if (i === 1 || i === totalPages || (i >= page - 1 && i <= page + 1)) items.push(i);
|
|
11
|
-
else if (items[items.length - 1] !== '...') items.push('...');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const start = perPage ? (page - 1) * perPage + 1 : null;
|
|
15
|
-
const end = perPage ? Math.min(page * perPage, total) : null;
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<div style={{
|
|
19
|
-
display: 'flex',
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
1
|
+
import Button from './Button';
|
|
2
|
+
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
export function Pagination({ page = 1, pages = 1, total, perPage, onChange, style = {} }) {
|
|
5
|
+
const totalPages = pages || (total && perPage ? Math.ceil(total / perPage) : 0);
|
|
6
|
+
if (!totalPages || totalPages <= 1) return null;
|
|
7
|
+
|
|
8
|
+
const items = [];
|
|
9
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
10
|
+
if (i === 1 || i === totalPages || (i >= page - 1 && i <= page + 1)) items.push(i);
|
|
11
|
+
else if (items[items.length - 1] !== '...') items.push('...');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const start = perPage ? (page - 1) * perPage + 1 : null;
|
|
15
|
+
const end = perPage ? Math.min(page * perPage, total) : null;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div style={{
|
|
19
|
+
display: 'flex',
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
gap: 8,
|
|
22
|
+
...style,
|
|
23
|
+
}}>
|
|
24
|
+
{start !== null && (
|
|
25
|
+
<div style={{ fontSize: '.72rem', color: 'var(--muted, #797b8d)', fontFamily: 'var(--mono, ui-monospace, monospace)' }}>
|
|
26
|
+
{start}–{end} of {total}
|
|
27
|
+
</div>
|
|
28
|
+
)}
|
|
29
|
+
<div style={{ display: 'flex', gap: 4, alignItems: 'center', marginLeft: start !== null ? 'auto' : 0 }}>
|
|
30
|
+
<Button
|
|
31
|
+
variant="ghost"
|
|
32
|
+
size="xs"
|
|
33
|
+
icon={<ChevronLeft size={14} />}
|
|
34
|
+
onClick={() => onChange?.(page - 1)}
|
|
35
|
+
disabled={page <= 1}
|
|
36
|
+
/>
|
|
37
|
+
{items.map((item, i) =>
|
|
38
|
+
item === '...'
|
|
39
|
+
? <span key={`e${i}`} style={{ padding: '0 4px', color: 'var(--muted, #797b8d)', fontSize: '.78rem' }}>…</span>
|
|
40
|
+
: <Button key={item} variant={item === page ? 'primary' : 'no-line'} size="xs" onClick={() => onChange?.(item)} style={{ minWidth: 28 }}>{item}</Button>
|
|
41
|
+
)}
|
|
42
|
+
<Button
|
|
43
|
+
variant="ghost"
|
|
44
|
+
size="xs"
|
|
45
|
+
icon={<ChevronRight size={14} />}
|
|
46
|
+
onClick={() => onChange?.(page + 1)}
|
|
47
|
+
disabled={page >= totalPages}
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
package/index.js
CHANGED
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
// cynx-ui — shared component library
|
|
2
|
-
import { default as _Button } from './components/Button.jsx';
|
|
3
|
-
import { default as _Input } from './components/Input.jsx';
|
|
4
|
-
import { default as _Toggle } from './components/Toggle.jsx';
|
|
5
|
-
import { default as _Spinner, Spinner as _SpinnerNamed } from './components/Spinner.jsx';
|
|
6
|
-
import { default as _TabBar } from './components/TabBar.jsx';
|
|
7
|
-
import { default as _ImageUpload } from './components/ImageUpload.jsx';
|
|
8
|
-
import { default as _ChipSelect } from './components/ChipSelect.jsx';
|
|
9
|
-
import { default as _Checkbox } from './components/Checkbox.jsx';
|
|
10
|
-
import { default as _AuthOverlay } from './components/AuthOverlay.jsx';
|
|
11
|
-
import { default as _UptimeBar } from './components/UptimeBar.jsx';
|
|
12
|
-
import { default as _LinearProgress } from './components/LinearProgress.jsx';
|
|
13
|
-
import { default as _StatBarCard } from './components/StatBarCard.jsx';
|
|
14
|
-
import { default as _StatsCard } from './components/StatsCard.jsx';
|
|
15
|
-
import { default as _ActivityCard } from './components/ActivityCard.jsx';
|
|
16
|
-
import { default as _HoverCard } from './components/HoverCard.jsx';
|
|
17
|
-
import { default as _StatsBar } from './components/StatsBar.jsx';
|
|
18
|
-
import { default as _Select } from './components/Select.jsx';
|
|
19
|
-
import { default as _Badge } from './components/Badge.jsx';
|
|
20
|
-
import { default as _PulseDot } from './components/PulseDot.jsx';
|
|
21
|
-
import { default as _CircularProgress } from './components/CircularProgress.jsx';
|
|
22
|
-
import { default as _Skeleton } from './components/Skeleton.jsx';
|
|
23
|
-
import { Modal as _Modal, Confirm as _Confirm } from './components/Modal.jsx';
|
|
24
|
-
import { toast as _toast, useToast as _useToast, Toast as _Toast } from './components/Toast.jsx';
|
|
25
|
-
import { ConfirmRoot as _ConfirmRoot, confirm as _confirm } from './components/Confirm.jsx';
|
|
26
|
-
import { Pagination as _Pagination } from './components/Pagination.jsx';
|
|
27
|
-
import { DatePicker as _DatePicker } from './components/DatePicker.jsx';
|
|
28
|
-
import { TimePicker as _TimePicker } from './components/TimePicker.jsx';
|
|
29
|
-
import { ActionsMenu as _ActionsMenu } from './components/ActionsMenu.jsx';
|
|
30
|
-
import { BrandingCard as _BrandingCard } from './components/BrandingCard.jsx';
|
|
31
|
-
import { Dropzone as _Dropzone } from './components/Dropzone.jsx';
|
|
32
|
-
import { Tabs as _Tabs } from './components/Tabs.jsx';
|
|
33
|
-
import { SkeletonText as _SkeletonText, SkeletonCard as _SkeletonCard, SkeletonRows as _SkeletonRows, SkeletonStats as _SkeletonStats } from './components/Skeleton.jsx';
|
|
34
|
-
import { XTable as _XTable, XThead as _XThead, XTbody as _XTbody, XTr as _XTr, XTh as _XTh, XTd as _XTd, SkeletonTable as _SkeletonTable } from './components/XTable.jsx';
|
|
35
|
-
import { PageShell as _PageShell, TableCard as _TableCard, TableCardFilters as _TableCardFilters, TableCardBody as _TableCardBody, TableCardFooter as _TableCardFooter, CardHdr as _CardHdr, StatCard as _StatCard, StatCardSkeleton as _StatCardSkeleton } from './components/Card.jsx';
|
|
36
|
-
|
|
37
|
-
import { default as _FilePicker } from './components/FilePicker.jsx';
|
|
38
|
-
import { default as _Divider } from './components/Divider.jsx';
|
|
39
|
-
import { default as _InfoBadge } from './components/InfoBadge.jsx';
|
|
40
|
-
|
|
41
|
-
export const Button = _Button;
|
|
42
|
-
export const FilePicker = _FilePicker;
|
|
43
|
-
export const Divider = _Divider;
|
|
44
|
-
export const InfoBadge = _InfoBadge;
|
|
45
|
-
export const Input = _Input;
|
|
46
|
-
export const Toggle = _Toggle;
|
|
47
|
-
export const Spinner = _Spinner || _SpinnerNamed;
|
|
48
|
-
export const TabBar = _TabBar;
|
|
49
|
-
export const ImageUpload = _ImageUpload;
|
|
50
|
-
export const ChipSelect = _ChipSelect;
|
|
51
|
-
export const Checkbox = _Checkbox;
|
|
52
|
-
export const AuthOverlay = _AuthOverlay;
|
|
53
|
-
export const UptimeBar = _UptimeBar;
|
|
54
|
-
export const LinearProgress = _LinearProgress;
|
|
55
|
-
export const StatBarCard = _StatBarCard;
|
|
56
|
-
export const StatsCard = _StatsCard;
|
|
57
|
-
export const ActivityCard = _ActivityCard;
|
|
58
|
-
export const HoverCard = _HoverCard;
|
|
59
|
-
export const StatsBar = _StatsBar;
|
|
60
|
-
export const Select = _Select;
|
|
61
|
-
export const Badge = _Badge;
|
|
62
|
-
export const PulseDot = _PulseDot;
|
|
63
|
-
export const CircularProgress = _CircularProgress;
|
|
64
|
-
export const Skeleton = _Skeleton;
|
|
65
|
-
export const Modal = _Modal;
|
|
66
|
-
export const Confirm = _Confirm;
|
|
67
|
-
export const toast = _toast;
|
|
68
|
-
export const useToast = _useToast;
|
|
69
|
-
export const Toast = _Toast;
|
|
70
|
-
export const ConfirmRoot = _ConfirmRoot;
|
|
71
|
-
export const confirm = _confirm;
|
|
72
|
-
export const Pagination = _Pagination;
|
|
73
|
-
export const DatePicker = _DatePicker;
|
|
74
|
-
export const TimePicker = _TimePicker;
|
|
75
|
-
export const ActionsMenu = _ActionsMenu;
|
|
76
|
-
export const BrandingCard = _BrandingCard;
|
|
77
|
-
export const Dropzone = _Dropzone;
|
|
78
|
-
export const Tabs = _Tabs;
|
|
79
|
-
export const SkeletonText = _SkeletonText;
|
|
80
|
-
export const SkeletonCard = _SkeletonCard;
|
|
81
|
-
export const SkeletonRows = _SkeletonRows;
|
|
82
|
-
export const SkeletonStats = _SkeletonStats;
|
|
83
|
-
export const XTable = _XTable;
|
|
84
|
-
export const XThead = _XThead;
|
|
85
|
-
export const XTbody = _XTbody;
|
|
86
|
-
export const XTr = _XTr;
|
|
87
|
-
export const XTh = _XTh;
|
|
88
|
-
export const XTd = _XTd;
|
|
89
|
-
export const SkeletonTable = _SkeletonTable;
|
|
90
|
-
export const PageShell = _PageShell;
|
|
91
|
-
export const TableCard = _TableCard;
|
|
92
|
-
export const TableCardFilters = _TableCardFilters;
|
|
93
|
-
export const TableCardBody = _TableCardBody;
|
|
94
|
-
export const TableCardFooter = _TableCardFooter;
|
|
95
|
-
export const CardHdr = _CardHdr;
|
|
96
|
-
export const StatCard = _StatCard;
|
|
97
|
-
export const StatCardSkeleton = _StatCardSkeleton;
|
|
1
|
+
// cynx-ui — shared component library
|
|
2
|
+
import { default as _Button } from './components/Button.jsx';
|
|
3
|
+
import { default as _Input } from './components/Input.jsx';
|
|
4
|
+
import { default as _Toggle } from './components/Toggle.jsx';
|
|
5
|
+
import { default as _Spinner, Spinner as _SpinnerNamed } from './components/Spinner.jsx';
|
|
6
|
+
import { default as _TabBar } from './components/TabBar.jsx';
|
|
7
|
+
import { default as _ImageUpload } from './components/ImageUpload.jsx';
|
|
8
|
+
import { default as _ChipSelect } from './components/ChipSelect.jsx';
|
|
9
|
+
import { default as _Checkbox } from './components/Checkbox.jsx';
|
|
10
|
+
import { default as _AuthOverlay } from './components/AuthOverlay.jsx';
|
|
11
|
+
import { default as _UptimeBar } from './components/UptimeBar.jsx';
|
|
12
|
+
import { default as _LinearProgress } from './components/LinearProgress.jsx';
|
|
13
|
+
import { default as _StatBarCard } from './components/StatBarCard.jsx';
|
|
14
|
+
import { default as _StatsCard } from './components/StatsCard.jsx';
|
|
15
|
+
import { default as _ActivityCard } from './components/ActivityCard.jsx';
|
|
16
|
+
import { default as _HoverCard } from './components/HoverCard.jsx';
|
|
17
|
+
import { default as _StatsBar } from './components/StatsBar.jsx';
|
|
18
|
+
import { default as _Select } from './components/Select.jsx';
|
|
19
|
+
import { default as _Badge } from './components/Badge.jsx';
|
|
20
|
+
import { default as _PulseDot } from './components/PulseDot.jsx';
|
|
21
|
+
import { default as _CircularProgress } from './components/CircularProgress.jsx';
|
|
22
|
+
import { default as _Skeleton } from './components/Skeleton.jsx';
|
|
23
|
+
import { Modal as _Modal, Confirm as _Confirm } from './components/Modal.jsx';
|
|
24
|
+
import { toast as _toast, useToast as _useToast, Toast as _Toast } from './components/Toast.jsx';
|
|
25
|
+
import { ConfirmRoot as _ConfirmRoot, confirm as _confirm } from './components/Confirm.jsx';
|
|
26
|
+
import { Pagination as _Pagination } from './components/Pagination.jsx';
|
|
27
|
+
import { DatePicker as _DatePicker } from './components/DatePicker.jsx';
|
|
28
|
+
import { TimePicker as _TimePicker } from './components/TimePicker.jsx';
|
|
29
|
+
import { ActionsMenu as _ActionsMenu } from './components/ActionsMenu.jsx';
|
|
30
|
+
import { BrandingCard as _BrandingCard } from './components/BrandingCard.jsx';
|
|
31
|
+
import { Dropzone as _Dropzone } from './components/Dropzone.jsx';
|
|
32
|
+
import { Tabs as _Tabs } from './components/Tabs.jsx';
|
|
33
|
+
import { SkeletonText as _SkeletonText, SkeletonCard as _SkeletonCard, SkeletonRows as _SkeletonRows, SkeletonStats as _SkeletonStats } from './components/Skeleton.jsx';
|
|
34
|
+
import { XTable as _XTable, XThead as _XThead, XTbody as _XTbody, XTr as _XTr, XTh as _XTh, XTd as _XTd, SkeletonTable as _SkeletonTable } from './components/XTable.jsx';
|
|
35
|
+
import { PageShell as _PageShell, TableCard as _TableCard, TableCardFilters as _TableCardFilters, TableCardBody as _TableCardBody, TableCardFooter as _TableCardFooter, CardHdr as _CardHdr, StatCard as _StatCard, StatCardSkeleton as _StatCardSkeleton } from './components/Card.jsx';
|
|
36
|
+
|
|
37
|
+
import { default as _FilePicker } from './components/FilePicker.jsx';
|
|
38
|
+
import { default as _Divider } from './components/Divider.jsx';
|
|
39
|
+
import { default as _InfoBadge } from './components/InfoBadge.jsx';
|
|
40
|
+
|
|
41
|
+
export const Button = _Button;
|
|
42
|
+
export const FilePicker = _FilePicker;
|
|
43
|
+
export const Divider = _Divider;
|
|
44
|
+
export const InfoBadge = _InfoBadge;
|
|
45
|
+
export const Input = _Input;
|
|
46
|
+
export const Toggle = _Toggle;
|
|
47
|
+
export const Spinner = _Spinner || _SpinnerNamed;
|
|
48
|
+
export const TabBar = _TabBar;
|
|
49
|
+
export const ImageUpload = _ImageUpload;
|
|
50
|
+
export const ChipSelect = _ChipSelect;
|
|
51
|
+
export const Checkbox = _Checkbox;
|
|
52
|
+
export const AuthOverlay = _AuthOverlay;
|
|
53
|
+
export const UptimeBar = _UptimeBar;
|
|
54
|
+
export const LinearProgress = _LinearProgress;
|
|
55
|
+
export const StatBarCard = _StatBarCard;
|
|
56
|
+
export const StatsCard = _StatsCard;
|
|
57
|
+
export const ActivityCard = _ActivityCard;
|
|
58
|
+
export const HoverCard = _HoverCard;
|
|
59
|
+
export const StatsBar = _StatsBar;
|
|
60
|
+
export const Select = _Select;
|
|
61
|
+
export const Badge = _Badge;
|
|
62
|
+
export const PulseDot = _PulseDot;
|
|
63
|
+
export const CircularProgress = _CircularProgress;
|
|
64
|
+
export const Skeleton = _Skeleton;
|
|
65
|
+
export const Modal = _Modal;
|
|
66
|
+
export const Confirm = _Confirm;
|
|
67
|
+
export const toast = _toast;
|
|
68
|
+
export const useToast = _useToast;
|
|
69
|
+
export const Toast = _Toast;
|
|
70
|
+
export const ConfirmRoot = _ConfirmRoot;
|
|
71
|
+
export const confirm = _confirm;
|
|
72
|
+
export const Pagination = _Pagination;
|
|
73
|
+
export const DatePicker = _DatePicker;
|
|
74
|
+
export const TimePicker = _TimePicker;
|
|
75
|
+
export const ActionsMenu = _ActionsMenu;
|
|
76
|
+
export const BrandingCard = _BrandingCard;
|
|
77
|
+
export const Dropzone = _Dropzone;
|
|
78
|
+
export const Tabs = _Tabs;
|
|
79
|
+
export const SkeletonText = _SkeletonText;
|
|
80
|
+
export const SkeletonCard = _SkeletonCard;
|
|
81
|
+
export const SkeletonRows = _SkeletonRows;
|
|
82
|
+
export const SkeletonStats = _SkeletonStats;
|
|
83
|
+
export const XTable = _XTable;
|
|
84
|
+
export const XThead = _XThead;
|
|
85
|
+
export const XTbody = _XTbody;
|
|
86
|
+
export const XTr = _XTr;
|
|
87
|
+
export const XTh = _XTh;
|
|
88
|
+
export const XTd = _XTd;
|
|
89
|
+
export const SkeletonTable = _SkeletonTable;
|
|
90
|
+
export const PageShell = _PageShell;
|
|
91
|
+
export const TableCard = _TableCard;
|
|
92
|
+
export const TableCardFilters = _TableCardFilters;
|
|
93
|
+
export const TableCardBody = _TableCardBody;
|
|
94
|
+
export const TableCardFooter = _TableCardFooter;
|
|
95
|
+
export const CardHdr = _CardHdr;
|
|
96
|
+
export const StatCard = _StatCard;
|
|
97
|
+
export const StatCardSkeleton = _StatCardSkeleton;
|