@xeplr/ui-account 1.0.0 → 1.0.2

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 (40) hide show
  1. package/package.json +25 -5
  2. package/src/AccessContext.jsx +86 -4
  3. package/src/ProtectedRoute.jsx +4 -1
  4. package/src/activeScope.js +71 -0
  5. package/src/adminApi.js +0 -29
  6. package/src/api.js +321 -22
  7. package/src/authRoutes.jsx +125 -0
  8. package/src/designs/AccountMenu.jsx +71 -0
  9. package/src/designs/ActivateSample.jsx +8 -16
  10. package/src/designs/ChangePasswordSample.jsx +3 -3
  11. package/src/designs/ForgotPasswordSample.jsx +3 -3
  12. package/src/designs/LoginSample.jsx +3 -2
  13. package/src/designs/NavDrawer.jsx +194 -0
  14. package/src/designs/NavFloatingSettings.jsx +25 -0
  15. package/src/designs/NavTopSample.jsx +34 -0
  16. package/src/designs/NotificationsBell.jsx +31 -0
  17. package/src/designs/ProfileSample.jsx +3 -3
  18. package/src/designs/RegisterSample.jsx +3 -3
  19. package/src/designs/ResetPasswordSample.jsx +7 -9
  20. package/src/designs/admin.css +13 -3
  21. package/src/designs/auth.css +6 -60
  22. package/src/designs/index.js +5 -2
  23. package/src/designs/nav.css +439 -0
  24. package/src/index.js +24 -8
  25. package/src/mt.js +31 -0
  26. package/src/pages.jsx +95 -38
  27. package/src/returnTo.js +24 -0
  28. package/src/useActivateController.js +19 -4
  29. package/src/useChangePasswordController.js +8 -2
  30. package/src/useForgotPasswordController.js +3 -0
  31. package/src/useLoginController.js +8 -1
  32. package/src/useNavController.js +224 -0
  33. package/src/useProfileController.js +6 -1
  34. package/src/useRegisterController.js +5 -1
  35. package/src/useResetPasswordController.js +12 -1
  36. package/src/validateDesign.js +20 -2
  37. package/src/designs/TenantPickerSample.jsx +0 -39
  38. package/src/designs/TenantSample.jsx +0 -182
  39. package/src/useTenantController.js +0 -146
  40. package/src/useTenantPickerController.js +0 -97
@@ -1,16 +1,16 @@
1
1
  import './auth.css';
2
2
 
3
+ // error/success feedback fires as a snackbar (see useChangePasswordController.js)
4
+ // — this design doesn't render it inline.
3
5
  export default function ChangePasswordSample({
4
6
  currentPassword, setCurrentPassword,
5
7
  newPassword, setNewPassword,
6
8
  confirmPassword, setConfirmPassword,
7
- error, success, loading, handleSubmit
9
+ loading, handleSubmit
8
10
  }) {
9
11
  return (
10
12
  <div className="xeplr-auth-container">
11
13
  <h1>Change Password</h1>
12
- {error && <div className="xeplr-auth-alert xeplr-auth-alert-error">{error}</div>}
13
- {success && <div className="xeplr-auth-alert xeplr-auth-alert-success">{success}</div>}
14
14
  <form onSubmit={handleSubmit}>
15
15
  <div className="xeplr-auth-form-group">
16
16
  <label htmlFor="xeplr-current-password">Current Password</label>
@@ -1,12 +1,12 @@
1
1
  import { Link } from 'react-router-dom';
2
2
  import './auth.css';
3
3
 
4
- export default function ForgotPasswordSample({ email, setEmail, error, success, loading, handleSubmit }) {
4
+ // error/success feedback fires as a snackbar (see useForgotPasswordController.js)
5
+ // — this design doesn't render it inline.
6
+ export default function ForgotPasswordSample({ email, setEmail, loading, handleSubmit }) {
5
7
  return (
6
8
  <div className="xeplr-auth-container">
7
9
  <h1>Forgot Password</h1>
8
- {error && <div className="xeplr-auth-alert xeplr-auth-alert-error">{error}</div>}
9
- {success && <div className="xeplr-auth-alert xeplr-auth-alert-success">{success}</div>}
10
10
  <form onSubmit={handleSubmit}>
11
11
  <div className="xeplr-auth-form-group">
12
12
  <label htmlFor="xeplr-email">Email</label>
@@ -1,11 +1,12 @@
1
1
  import { Link } from 'react-router-dom';
2
2
  import './auth.css';
3
3
 
4
- export default function LoginSample({ email, setEmail, password, setPassword, error, loading, handleSubmit }) {
4
+ // error/success feedback fires as a snackbar (see useLoginController.js) —
5
+ // this design doesn't render it inline.
6
+ export default function LoginSample({ email, setEmail, password, setPassword, loading, handleSubmit }) {
5
7
  return (
6
8
  <div className="xeplr-auth-container">
7
9
  <h1>Login</h1>
8
- {error && <div className="xeplr-auth-alert xeplr-auth-alert-error">{error}</div>}
9
10
  <form onSubmit={handleSubmit}>
10
11
  <div className="xeplr-auth-form-group">
11
12
  <label htmlFor="xeplr-email">Email</label>
@@ -0,0 +1,194 @@
1
+ import { memo, useState, useMemo } from 'react';
2
+ import AccountMenu from './AccountMenu.jsx';
3
+ import NotificationsBell from './NotificationsBell.jsx';
4
+
5
+ // The ENTIRE nav when drawerItems is non-empty — NavPage renders this instead
6
+ // of (never alongside) the top bar, see pages.jsx. A pure overlay: `position:
7
+ // fixed` (nav.css), pinned to (0,0), full height — it never pushes or resizes
8
+ // anything else on the page, completely decoupled from the app's own content.
9
+ // Two states: icon-only (collapsed, `drawerOpen=false`) and
10
+ // icon+label+groups+search+promo (expanded). Toggled by clicking its own
11
+ // logo. Settings + notifications live in its footer (bottom-pinned) instead
12
+ // of a top bar, since there isn't one — same accountItems/notifications the
13
+ // top bar would have gotten, just rendered here instead.
14
+ //
15
+ // Items are bucketed by their optional `group` — ungrouped items render first
16
+ // (no header), grouped ones under a section header, groups in first-seen order.
17
+ function bucketItems(items) {
18
+ var ungrouped = [];
19
+ var groupOrder = [];
20
+ var groups = {};
21
+ items.forEach(function(item) {
22
+ if (!item.group) {
23
+ ungrouped.push(item);
24
+ return;
25
+ }
26
+ if (!groups[item.group]) {
27
+ groups[item.group] = [];
28
+ groupOrder.push(item.group);
29
+ }
30
+ groups[item.group].push(item);
31
+ });
32
+ return { ungrouped: ungrouped, groupOrder: groupOrder, groups: groups };
33
+ }
34
+
35
+ function NavDrawer({
36
+ drawerOpen, toggleDrawer, drawerItems, expandedLogo, logo, drawerPromo,
37
+ user, accountItems, notifications, accountOpen, toggleAccount, closeAccount, accountRef, logout,
38
+ hideFooterIcons,
39
+ drawerWidth, drawerResizing, startDrawerResize, resetDrawerWidth, nudgeDrawerWidth, drawerWidthBounds
40
+ }) {
41
+ var [query, setQuery] = useState('');
42
+
43
+ var bounds = drawerWidthBounds || { min: 180, max: 480, step: 16 };
44
+
45
+ // Arrow keys resize, Home/End jump to the stops — the handle is focusable,
46
+ // so everything the drag does has to be reachable from the keyboard too.
47
+ function onResizeKeyDown(e) {
48
+ if (e.key === 'ArrowLeft') { e.preventDefault(); nudgeDrawerWidth(-bounds.step); }
49
+ else if (e.key === 'ArrowRight') { e.preventDefault(); nudgeDrawerWidth(bounds.step); }
50
+ else if (e.key === 'Home') { e.preventDefault(); nudgeDrawerWidth(-Infinity); }
51
+ else if (e.key === 'End') { e.preventDefault(); nudgeDrawerWidth(Infinity); }
52
+ else if (e.key === 'Enter') { e.preventDefault(); resetDrawerWidth(); }
53
+ }
54
+
55
+ var visibleItems = useMemo(function() {
56
+ if (!drawerOpen || !query.trim()) return drawerItems;
57
+ var q = query.trim().toLowerCase();
58
+ return drawerItems.filter(function(item) { return item.name.toLowerCase().indexOf(q) !== -1; });
59
+ }, [drawerItems, query, drawerOpen]);
60
+
61
+ var buckets = useMemo(function() { return bucketItems(visibleItems); }, [visibleItems]);
62
+
63
+ function renderItem(item) {
64
+ // A COUNT THAT HAS TO BE SEEN FROM WHEREVER YOU ARE.
65
+ //
66
+ // Optional `item.badge` — a number or a short string. It renders as a pill
67
+ // beside the label when the drawer is expanded and as a dot on the icon
68
+ // when it is collapsed, because the collapsed rail is the state most
69
+ // people leave it in and a badge only visible when expanded is a badge
70
+ // that does not do its job.
71
+ //
72
+ // 0, null and undefined all render NOTHING. A pill reading "0" is noise
73
+ // that trains people to stop looking at the pill.
74
+ var badge = item.badge === 0 || item.badge == null || item.badge === '' ? null : item.badge;
75
+ return (
76
+ <button
77
+ key={item.name}
78
+ type="button"
79
+ className={'xeplr-nav-drawer-link' + (badge ? ' xeplr-nav-drawer-link-badged' : '')}
80
+ onClick={item.clickHandler}
81
+ // The count belongs in the tooltip too — the collapsed dot says
82
+ // "something", and the hover has to say how many.
83
+ title={badge ? item.name + ' (' + badge + ')' : item.name}
84
+ >
85
+ {item.icon && (
86
+ <span className="xeplr-nav-drawer-icon">
87
+ {item.icon}
88
+ {badge && !drawerOpen && <span className="xeplr-nav-drawer-dot" aria-hidden="true" />}
89
+ </span>
90
+ )}
91
+ {drawerOpen && <span className="xeplr-nav-drawer-label">{item.name}</span>}
92
+ {drawerOpen && badge && <span className="xeplr-nav-drawer-badge">{badge}</span>}
93
+ </button>
94
+ );
95
+ }
96
+
97
+ return (
98
+ <aside
99
+ className={
100
+ 'xeplr-nav-drawer'
101
+ + (drawerOpen ? ' xeplr-nav-drawer-expanded' : ' xeplr-nav-drawer-collapsed')
102
+ + (drawerResizing ? ' xeplr-nav-drawer-resizing' : '')
103
+ }
104
+ /* Inline width ONLY when expanded — collapsed is the fixed icon rail and
105
+ nav.css keeps owning that number. Inline because it changes per
106
+ pointermove; a stylesheet cannot express a live drag. */
107
+ style={drawerOpen && drawerWidth ? { width: drawerWidth + 'px' } : undefined}
108
+ >
109
+ <button
110
+ type="button"
111
+ className="xeplr-nav-drawer-toggle"
112
+ onClick={toggleDrawer}
113
+ aria-label={drawerOpen ? 'Collapse menu' : 'Expand menu'}
114
+ aria-expanded={drawerOpen}
115
+ >
116
+ {/* ONE MARK AT A TIME.
117
+ expandedLogo is a stacked icon+wordmark lockup — it CONTAINS this
118
+ icon — so rendering both put the same mark on screen twice, one
119
+ above the other. Collapsed, the icon is the brand and the thing you
120
+ click to expand; open, the lockup is the brand and this is only the
121
+ collapse control, which the chevron says better than a second copy
122
+ of the logo. */}
123
+ {drawerOpen && expandedLogo
124
+ ? <span className="xeplr-nav-drawer-collapse" aria-hidden="true">«</span>
125
+ : (logo && <img src={logo} alt="" className="xeplr-nav-drawer-logo" />)}
126
+ </button>
127
+ {/* Own row below the toggle, not squeezed inline beside it — a stacked
128
+ lockup needs real height to stay legible, not the icon's 22px. */}
129
+ {drawerOpen && expandedLogo && (
130
+ <img src={expandedLogo} alt="" className="xeplr-nav-drawer-expanded-logo" />
131
+ )}
132
+
133
+ {drawerOpen && (
134
+ <input
135
+ type="search"
136
+ className="xeplr-nav-drawer-search"
137
+ placeholder="Search"
138
+ value={query}
139
+ onChange={function(e) { setQuery(e.target.value); }}
140
+ />
141
+ )}
142
+
143
+ <nav className="xeplr-nav-drawer-links">
144
+ {buckets.ungrouped.map(renderItem)}
145
+ {buckets.groupOrder.map(function(groupName) {
146
+ return (
147
+ <div key={groupName} className="xeplr-nav-drawer-group">
148
+ {drawerOpen && <div className="xeplr-nav-drawer-group-label">{groupName}</div>}
149
+ {buckets.groups[groupName].map(renderItem)}
150
+ </div>
151
+ );
152
+ })}
153
+ {visibleItems.length === 0 && drawerOpen && <div className="xeplr-nav-drawer-empty">No matches</div>}
154
+ </nav>
155
+
156
+ {drawerOpen && drawerPromo && <div className="xeplr-nav-drawer-promo">{drawerPromo}</div>}
157
+
158
+ {!hideFooterIcons && (
159
+ <div className="xeplr-nav-drawer-footer">
160
+ <NotificationsBell notifications={notifications} label={drawerOpen ? 'Notifications' : undefined} />
161
+ <AccountMenu
162
+ placement="top" triggerLabel={drawerOpen ? 'Settings' : undefined}
163
+ user={user} accountItems={accountItems}
164
+ accountOpen={accountOpen} toggleAccount={toggleAccount} closeAccount={closeAccount}
165
+ accountRef={accountRef} logout={logout}
166
+ />
167
+ </div>
168
+ )}
169
+
170
+ {/* LAST child and absolutely positioned, so it sits over the drawer's
171
+ right border at any height without taking part in the column layout
172
+ above it. Only when expanded: there is nothing to widen on a 60px
173
+ icon rail, and a resize handle there would just fight the toggle. */}
174
+ {drawerOpen && (
175
+ <div
176
+ className="xeplr-nav-drawer-resize"
177
+ role="separator"
178
+ aria-orientation="vertical"
179
+ aria-label="Resize menu"
180
+ aria-valuenow={drawerWidth}
181
+ aria-valuemin={bounds.min}
182
+ aria-valuemax={bounds.max}
183
+ tabIndex={0}
184
+ onPointerDown={startDrawerResize}
185
+ onDoubleClick={resetDrawerWidth}
186
+ onKeyDown={onResizeKeyDown}
187
+ title="Drag to resize — double-click to reset"
188
+ />
189
+ )}
190
+ </aside>
191
+ );
192
+ }
193
+
194
+ export default memo(NavDrawer);
@@ -0,0 +1,25 @@
1
+ import { memo } from 'react';
2
+ import AccountMenu from './AccountMenu.jsx';
3
+ import NotificationsBell from './NotificationsBell.jsx';
4
+ import './nav.css';
5
+
6
+ // A minimal top-right overlay — just the notifications bell + account/settings
7
+ // trigger, no logo/middle slot/header bar around them. Opt-in via NavPage's
8
+ // `floatingSettings` prop, for layouts (e.g. an icon drawer) that want these
9
+ // two floating over the page instead of pinned to the drawer's own footer.
10
+ function NavFloatingSettings({
11
+ user, accountItems, notifications, accountOpen, toggleAccount, closeAccount, accountRef, logout
12
+ }) {
13
+ return (
14
+ <div className="xeplr-nav-floating">
15
+ <NotificationsBell notifications={notifications} />
16
+ <AccountMenu
17
+ user={user} accountItems={accountItems}
18
+ accountOpen={accountOpen} toggleAccount={toggleAccount} closeAccount={closeAccount}
19
+ accountRef={accountRef} logout={logout}
20
+ />
21
+ </div>
22
+ );
23
+ }
24
+
25
+ export default memo(NavFloatingSettings);
@@ -0,0 +1,34 @@
1
+ import { memo } from 'react';
2
+ import AccountMenu from './AccountMenu.jsx';
3
+ import NotificationsBell from './NotificationsBell.jsx';
4
+ import './nav.css';
5
+
6
+ // The (default, swappable via NavPage's `design` prop) top bar: 10% / 80% / 10%
7
+ // columns. Only ever rendered when there's NO drawer — NavPage renders the
8
+ // drawer instead of this, never both (see pages.jsx). Left holds the small
9
+ // `logo`, middle is `navMiddle` (a fully exposed slot, e.g. an app's
10
+ // company/workspace picker), right is always the settings trigger plus the
11
+ // notifications bell when `notifications` is set.
12
+ function NavTopSample({
13
+ logo, navMiddle,
14
+ user, accountItems, notifications, accountOpen, toggleAccount, closeAccount, accountRef, logout
15
+ }) {
16
+ return (
17
+ <header className="xeplr-nav xeplr-nav-top">
18
+ <div className="xeplr-nav-left">
19
+ {logo && <img src={logo} alt="" className="xeplr-nav-logo" />}
20
+ </div>
21
+ <div className="xeplr-nav-middle">{navMiddle}</div>
22
+ <div className="xeplr-nav-right">
23
+ <NotificationsBell notifications={notifications} />
24
+ <AccountMenu
25
+ user={user} accountItems={accountItems}
26
+ accountOpen={accountOpen} toggleAccount={toggleAccount} closeAccount={closeAccount}
27
+ accountRef={accountRef} logout={logout}
28
+ />
29
+ </div>
30
+ </header>
31
+ );
32
+ }
33
+
34
+ export default memo(NavTopSample);
@@ -0,0 +1,31 @@
1
+ import { memo } from 'react';
2
+
3
+ // Its own control, separate from AccountMenu on purpose — memoized independently
4
+ // so a notification count changing doesn't re-render the account dropdown (and
5
+ // vice versa). `notifications` is optional; omit it to hide the bell entirely.
6
+ // Wire a real feed later (open a popover, etc.) without touching the other parts.
7
+ // `label` is optional text shown next to the icon — the drawer passes
8
+ // "Notifications" when expanded (matching how its other items show a label),
9
+ // omits it when collapsed; the top bar never passes it (icon-only, no room).
10
+ function NotificationsBell({ notifications, label }) {
11
+ if (!notifications) return null;
12
+ var count = notifications.count;
13
+
14
+ return (
15
+ <button
16
+ type="button"
17
+ className={'xeplr-nav-bell' + (label ? ' xeplr-nav-bell-labeled' : '')}
18
+ onClick={notifications.onClick}
19
+ aria-label={count > 0 ? count + ' unread notifications' : 'Notifications'}
20
+ >
21
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
22
+ <path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" />
23
+ <path d="M10.3 21a1.94 1.94 0 0 0 3.4 0" />
24
+ </svg>
25
+ {count > 0 && <span className="xeplr-nav-badge">{count > 9 ? '9+' : count}</span>}
26
+ {label && <span className="xeplr-nav-bell-label">{label}</span>}
27
+ </button>
28
+ );
29
+ }
30
+
31
+ export default memo(NotificationsBell);
@@ -1,7 +1,9 @@
1
1
  import './auth.css';
2
2
 
3
+ // error/success feedback fires as a snackbar (see useProfileController.js) —
4
+ // this design doesn't render it inline.
3
5
  export default function ProfileSample({
4
- form, error, success, loading, fetching, handleChange, handleSubmit
6
+ form, loading, fetching, handleChange, handleSubmit
5
7
  }) {
6
8
  if (fetching) {
7
9
  return (
@@ -14,8 +16,6 @@ export default function ProfileSample({
14
16
  return (
15
17
  <div className="xeplr-auth-container">
16
18
  <h1>Profile</h1>
17
- {error && <div className="xeplr-auth-alert xeplr-auth-alert-error">{error}</div>}
18
- {success && <div className="xeplr-auth-alert xeplr-auth-alert-success">{success}</div>}
19
19
  <form onSubmit={handleSubmit}>
20
20
  <div className="xeplr-auth-form-group">
21
21
  <label htmlFor="xeplr-profile-name">Name</label>
@@ -1,12 +1,12 @@
1
1
  import { Link } from 'react-router-dom';
2
2
  import './auth.css';
3
3
 
4
- export default function RegisterSample({ form, error, success, loading, handleChange, handleSubmit }) {
4
+ // error/success feedback fires as a snackbar (see useRegisterController.js) —
5
+ // this design doesn't render it inline.
6
+ export default function RegisterSample({ form, loading, handleChange, handleSubmit }) {
5
7
  return (
6
8
  <div className="xeplr-auth-container">
7
9
  <h1>Register</h1>
8
- {error && <div className="xeplr-auth-alert xeplr-auth-alert-error">{error}</div>}
9
- {success && <div className="xeplr-auth-alert xeplr-auth-alert-success">{success}</div>}
10
10
  <form onSubmit={handleSubmit}>
11
11
  <div className="xeplr-auth-form-group">
12
12
  <label htmlFor="xeplr-name">Name</label>
@@ -1,11 +1,13 @@
1
1
  import { Link } from 'react-router-dom';
2
2
  import './auth.css';
3
3
 
4
- export default function ResetPasswordSample({ token, password, setPassword, error, success, loading, handleSubmit }) {
4
+ // error/success feedback fires as a snackbar (see useResetPasswordController.js,
5
+ // including the "invalid link" case) — this design doesn't render it inline,
6
+ // it just switches which block is visible.
7
+ export default function ResetPasswordSample({ token, password, setPassword, success, loading, handleSubmit }) {
5
8
  if (!token && !success) {
6
9
  return (
7
10
  <div className="xeplr-auth-container">
8
- <div className="xeplr-auth-alert xeplr-auth-alert-error">Invalid reset link</div>
9
11
  <div className="xeplr-auth-links">
10
12
  <p><Link to="/auth/forgot-password">Request a new reset link</Link></p>
11
13
  </div>
@@ -16,14 +18,10 @@ export default function ResetPasswordSample({ token, password, setPassword, erro
16
18
  return (
17
19
  <div className="xeplr-auth-container">
18
20
  <h1>Reset Password</h1>
19
- {error && <div className="xeplr-auth-alert xeplr-auth-alert-error">{error}</div>}
20
21
  {success && (
21
- <>
22
- <div className="xeplr-auth-alert xeplr-auth-alert-success">{success}</div>
23
- <div className="xeplr-auth-links">
24
- <p><Link to="/auth/login">Go to Login</Link></p>
25
- </div>
26
- </>
22
+ <div className="xeplr-auth-links">
23
+ <p><Link to="/auth/login">Go to Login</Link></p>
24
+ </div>
27
25
  )}
28
26
  {!success && (
29
27
  <form onSubmit={handleSubmit}>
@@ -3,8 +3,14 @@
3
3
  /* ─── xeplr Admin Matrix ─── */
4
4
 
5
5
  .xeplr-admin-container {
6
- max-width: 1200px;
7
- margin: 20px auto;
6
+ /* Fill the available height of whatever container the host app uses
7
+ (e.g. the architects app's `.content` area) so the table area scrolls
8
+ internally instead of leaving empty whitespace below. */
9
+ width: 100%;
10
+ height: 100%;
11
+ min-height: 0;
12
+ display: flex;
13
+ flex-direction: column;
8
14
  padding: 20px;
9
15
  border: 1px solid var(--xeplr-border-primary);
10
16
  border-radius: 8px;
@@ -165,7 +171,11 @@
165
171
  /* ─── Matrix Table ─── */
166
172
 
167
173
  .xeplr-admin-matrix-wrapper {
168
- overflow-x: auto;
174
+ /* Fills remaining height inside the flex column container so the table
175
+ scrolls internally and the header/tabs/toolbar stay pinned at top. */
176
+ flex: 1;
177
+ min-height: 0;
178
+ overflow: auto;
169
179
  border: 1px solid var(--xeplr-border-primary);
170
180
  border-radius: 6px;
171
181
  }
@@ -82,22 +82,16 @@
82
82
  text-decoration: underline;
83
83
  }
84
84
 
85
+ /* In-progress status text (e.g. "Activating your account...") — error/success
86
+ feedback fires as a snackbar instead (see the use*Controller.js hooks), so
87
+ there's no -error/-success modifier here anymore. */
85
88
  .xeplr-auth-alert {
86
89
  padding: 10px 15px;
87
90
  border-radius: 4px;
88
91
  margin-bottom: 15px;
89
- }
90
-
91
- .xeplr-auth-alert-error {
92
- background: var(--xeplr-danger-bg);
93
- color: var(--xeplr-danger);
94
- border: 1px solid var(--xeplr-danger-border);
95
- }
96
-
97
- .xeplr-auth-alert-success {
98
- background: var(--xeplr-success-bg);
99
- color: var(--xeplr-success);
100
- border: 1px solid var(--xeplr-success-border);
92
+ background: var(--xeplr-info-bg);
93
+ color: var(--xeplr-info);
94
+ border: 1px solid var(--xeplr-info-border);
101
95
  }
102
96
 
103
97
  .xeplr-auth-not-activated {
@@ -110,51 +104,3 @@
110
104
  color: var(--xeplr-warning);
111
105
  margin: 20px 0;
112
106
  }
113
-
114
- /* Tenant Picker */
115
- .xeplr-tenant-picker {
116
- display: flex;
117
- flex-direction: column;
118
- gap: 10px;
119
- margin-top: 16px;
120
- }
121
-
122
- .xeplr-tenant-option {
123
- display: flex;
124
- flex-direction: column;
125
- align-items: flex-start;
126
- gap: 4px;
127
- padding: 16px;
128
- border: 1px solid var(--xeplr-border-primary, #333);
129
- border-radius: 8px;
130
- background: var(--xeplr-bg-secondary, #222);
131
- cursor: pointer;
132
- transition: all 0.15s;
133
- text-align: left;
134
- width: 100%;
135
- }
136
-
137
- .xeplr-tenant-option:hover {
138
- border-color: var(--xeplr-accent, #646cff);
139
- background: var(--xeplr-bg-active, #1a1a2a);
140
- }
141
-
142
- .xeplr-tenant-name {
143
- font-size: 16px;
144
- font-weight: 600;
145
- color: var(--xeplr-text-primary, #e0e0e0);
146
- }
147
-
148
- .xeplr-tenant-code {
149
- font-size: 12px;
150
- font-family: monospace;
151
- color: var(--xeplr-tag-text, #9999cc);
152
- background: var(--xeplr-tag-bg, #2a2a3a);
153
- padding: 2px 6px;
154
- border-radius: 3px;
155
- }
156
-
157
- .xeplr-tenant-desc {
158
- font-size: 13px;
159
- color: var(--xeplr-text-muted, #777);
160
- }
@@ -9,5 +9,8 @@ export { default as ProfileSample } from './ProfileSample.jsx';
9
9
  export { default as UserRolesMatrixSample } from './UserRolesMatrixSample.jsx';
10
10
  export { default as AccessMatrixSample } from './AccessMatrixSample.jsx';
11
11
  export { default as MasterSettingsSample } from './MasterSettingsSample.jsx';
12
- export { default as TenantSample } from './TenantSample.jsx';
13
- export { default as TenantPickerSample } from './TenantPickerSample.jsx';
12
+ export { default as NavTopSample } from './NavTopSample.jsx';
13
+ export { default as AccountMenu } from './AccountMenu.jsx';
14
+ export { default as NavDrawer } from './NavDrawer.jsx';
15
+ export { default as NavFloatingSettings } from './NavFloatingSettings.jsx';
16
+ export { default as NotificationsBell } from './NotificationsBell.jsx';