@1889ca/ui 0.3.3 → 0.4.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/package.json +1 -1
- package/src/components/StatusBar.css +118 -0
- package/src/components/StatusBar.jsx +78 -0
- package/src/index.js +2 -0
- package/src/styles/primitives.css +5 -5
package/package.json
CHANGED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/** Contract: contracts/packages-ui-components/rules.md */
|
|
2
|
+
|
|
3
|
+
.ui-statusbar {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: space-between;
|
|
7
|
+
padding: 0 1rem;
|
|
8
|
+
height: 28px;
|
|
9
|
+
border-top: 1px solid var(--ui-border);
|
|
10
|
+
background: rgba(8, 8, 12, 0.75);
|
|
11
|
+
backdrop-filter: blur(var(--ui-glass-blur-heavy));
|
|
12
|
+
box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.03);
|
|
13
|
+
position: fixed;
|
|
14
|
+
bottom: 0;
|
|
15
|
+
left: 0;
|
|
16
|
+
right: 0;
|
|
17
|
+
z-index: 10;
|
|
18
|
+
font-size: 0.72rem;
|
|
19
|
+
color: var(--ui-text-muted);
|
|
20
|
+
gap: 0.5rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.ui-statusbar-left,
|
|
24
|
+
.ui-statusbar-right,
|
|
25
|
+
.ui-statusbar-center {
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
gap: 0.6rem;
|
|
29
|
+
min-width: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.ui-statusbar-left { justify-content: flex-start; }
|
|
33
|
+
.ui-statusbar-center { justify-content: center; flex: 1; }
|
|
34
|
+
.ui-statusbar-right { justify-content: flex-end; }
|
|
35
|
+
|
|
36
|
+
/* Chunks — shared label style */
|
|
37
|
+
|
|
38
|
+
.ui-sb-label {
|
|
39
|
+
color: var(--ui-text-subtle);
|
|
40
|
+
margin-right: 0.3rem;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Text */
|
|
44
|
+
|
|
45
|
+
.ui-sb-text {
|
|
46
|
+
white-space: nowrap;
|
|
47
|
+
font-variant-numeric: tabular-nums;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.ui-sb-text--muted {
|
|
51
|
+
color: var(--ui-text-subtle);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Spinner */
|
|
55
|
+
|
|
56
|
+
.ui-sb-spinner {
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
gap: 0.35rem;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.ui-sb-spinner-icon {
|
|
63
|
+
animation: ui-sb-spin 0.8s linear infinite;
|
|
64
|
+
color: var(--ui-accent);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@keyframes ui-sb-spin {
|
|
68
|
+
to { transform: rotate(360deg); }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Progress */
|
|
72
|
+
|
|
73
|
+
.ui-sb-progress {
|
|
74
|
+
display: inline-flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
gap: 0.4rem;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.ui-sb-progress-track {
|
|
80
|
+
height: 4px;
|
|
81
|
+
background: var(--ui-surface-raised);
|
|
82
|
+
border-radius: 2px;
|
|
83
|
+
overflow: hidden;
|
|
84
|
+
display: inline-block;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.ui-sb-progress-fill {
|
|
88
|
+
display: block;
|
|
89
|
+
height: 100%;
|
|
90
|
+
background: var(--ui-accent);
|
|
91
|
+
border-radius: 2px;
|
|
92
|
+
transition: width 0.3s var(--ui-ease);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Badge */
|
|
96
|
+
|
|
97
|
+
.ui-sb-badge {
|
|
98
|
+
display: inline-flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: 0.3rem;
|
|
101
|
+
white-space: nowrap;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.ui-sb-badge-dot {
|
|
105
|
+
width: 6px;
|
|
106
|
+
height: 6px;
|
|
107
|
+
border-radius: 50%;
|
|
108
|
+
flex-shrink: 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Separator */
|
|
112
|
+
|
|
113
|
+
.ui-sb-sep {
|
|
114
|
+
width: 1px;
|
|
115
|
+
height: 14px;
|
|
116
|
+
background: var(--ui-border);
|
|
117
|
+
flex-shrink: 0;
|
|
118
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** Contract: contracts/packages-ui-components/rules.md */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fixed footer status bar with composable data chunks.
|
|
5
|
+
* Mirrors PageHeader as a bottom counterpart with glass blur.
|
|
6
|
+
*
|
|
7
|
+
* @param {ReactNode} left - Left-aligned chunks
|
|
8
|
+
* @param {ReactNode} right - Right-aligned chunks
|
|
9
|
+
* @param {ReactNode} center - Center-aligned chunks (optional)
|
|
10
|
+
* @param {string} className - Additional class names
|
|
11
|
+
*/
|
|
12
|
+
export default function StatusBar({ left, right, center, className }) {
|
|
13
|
+
return (
|
|
14
|
+
<footer className={`ui-statusbar${className ? ` ${className}` : ''}`}>
|
|
15
|
+
<div className="ui-statusbar-left">{left}</div>
|
|
16
|
+
{center && <div className="ui-statusbar-center">{center}</div>}
|
|
17
|
+
<div className="ui-statusbar-right">{right}</div>
|
|
18
|
+
</footer>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Text chunk — label with optional muted prefix */
|
|
23
|
+
function Text({ label, value, muted }) {
|
|
24
|
+
return (
|
|
25
|
+
<span className={`ui-sb-text${muted ? ' ui-sb-text--muted' : ''}`}>
|
|
26
|
+
{label && <span className="ui-sb-label">{label}</span>}
|
|
27
|
+
{value}
|
|
28
|
+
</span>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Spinner chunk — small rotating indicator with optional label */
|
|
33
|
+
function Spinner({ label, size = 14 }) {
|
|
34
|
+
return (
|
|
35
|
+
<span className="ui-sb-spinner">
|
|
36
|
+
<svg className="ui-sb-spinner-icon" width={size} height={size} viewBox="0 0 16 16" fill="none">
|
|
37
|
+
<circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="2" opacity="0.25" />
|
|
38
|
+
<path d="M14 8a6 6 0 0 0-6-6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
|
|
39
|
+
</svg>
|
|
40
|
+
{label && <span className="ui-sb-label">{label}</span>}
|
|
41
|
+
</span>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Progress chunk — thin inline progress bar */
|
|
46
|
+
function Progress({ value, max = 100, label, width = 80 }) {
|
|
47
|
+
const pct = Math.min(100, Math.max(0, (value / max) * 100));
|
|
48
|
+
return (
|
|
49
|
+
<span className="ui-sb-progress">
|
|
50
|
+
{label && <span className="ui-sb-label">{label}</span>}
|
|
51
|
+
<span className="ui-sb-progress-track" style={{ width }}>
|
|
52
|
+
<span className="ui-sb-progress-fill" style={{ width: `${pct}%` }} />
|
|
53
|
+
</span>
|
|
54
|
+
<span className="ui-sb-text ui-sb-text--muted">{Math.round(pct)}%</span>
|
|
55
|
+
</span>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Badge chunk — colored indicator dot with label */
|
|
60
|
+
function Badge({ label, color = 'var(--ui-success)' }) {
|
|
61
|
+
return (
|
|
62
|
+
<span className="ui-sb-badge">
|
|
63
|
+
<span className="ui-sb-badge-dot" style={{ background: color }} />
|
|
64
|
+
{label}
|
|
65
|
+
</span>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Separator — vertical divider between chunks */
|
|
70
|
+
function Separator() {
|
|
71
|
+
return <span className="ui-sb-sep" />;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
StatusBar.Text = Text;
|
|
75
|
+
StatusBar.Spinner = Spinner;
|
|
76
|
+
StatusBar.Progress = Progress;
|
|
77
|
+
StatusBar.Badge = Badge;
|
|
78
|
+
StatusBar.Separator = Separator;
|
package/src/index.js
CHANGED
|
@@ -19,6 +19,7 @@ import './components/SlidePanel.css';
|
|
|
19
19
|
import './components/LoginCard.css';
|
|
20
20
|
import './components/PasskeyLoginPage.css';
|
|
21
21
|
import './components/UserMenu.css';
|
|
22
|
+
import './components/StatusBar.css';
|
|
22
23
|
|
|
23
24
|
/* Components */
|
|
24
25
|
export { default as ContextMenu } from './components/ContextMenu.jsx';
|
|
@@ -36,6 +37,7 @@ export { default as SlidePanel } from './components/SlidePanel.jsx';
|
|
|
36
37
|
export { default as LoginCard } from './components/LoginCard.jsx';
|
|
37
38
|
export { default as PasskeyLoginPage } from './components/PasskeyLoginPage.jsx';
|
|
38
39
|
export { default as UserMenu } from './components/UserMenu.jsx';
|
|
40
|
+
export { default as StatusBar } from './components/StatusBar.jsx';
|
|
39
41
|
|
|
40
42
|
/* Auth */
|
|
41
43
|
export { AuthProvider, useAuth } from './auth/AuthProvider.jsx';
|
|
@@ -124,11 +124,11 @@
|
|
|
124
124
|
position: fixed;
|
|
125
125
|
inset: 0;
|
|
126
126
|
background:
|
|
127
|
-
radial-gradient(ellipse 80% 60% at 15% 10%, rgba(124, 108, 240, 0.
|
|
128
|
-
radial-gradient(ellipse 60% 50% at 85% 20%, rgba(56, 189, 248, 0.
|
|
129
|
-
radial-gradient(ellipse 50% 60% at 40% 90%, rgba(168, 85, 247, 0.
|
|
130
|
-
radial-gradient(ellipse 70% 40% at 75% 75%, rgba(34, 211, 153, 0.
|
|
131
|
-
radial-gradient(ellipse 40% 30% at 50% 50%, rgba(244, 114, 182, 0.
|
|
127
|
+
radial-gradient(ellipse 80% 60% at 15% 10%, rgba(124, 108, 240, 0.084), transparent),
|
|
128
|
+
radial-gradient(ellipse 60% 50% at 85% 20%, rgba(56, 189, 248, 0.056), transparent),
|
|
129
|
+
radial-gradient(ellipse 50% 60% at 40% 90%, rgba(168, 85, 247, 0.07), transparent),
|
|
130
|
+
radial-gradient(ellipse 70% 40% at 75% 75%, rgba(34, 211, 153, 0.042), transparent),
|
|
131
|
+
radial-gradient(ellipse 40% 30% at 50% 50%, rgba(244, 114, 182, 0.028), transparent);
|
|
132
132
|
pointer-events: none;
|
|
133
133
|
z-index: 0;
|
|
134
134
|
}
|