@streamoid/ui 0.6.16 → 0.6.18
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/README.md +35 -18
- package/dist/docs/AGENTS.md +321 -0
- package/dist/docs/CreditWarningBanner.md +305 -0
- package/dist/docs/InvoiceHistoryMobile.md +222 -0
- package/dist/docs/ScAccess.md +259 -0
- package/dist/docs/ScAppCard.md +244 -0
- package/dist/docs/ScAppCardForCopilot.md +230 -0
- package/dist/docs/ScAppCardV3.md +273 -0
- package/dist/docs/ScAppField.md +308 -0
- package/dist/docs/ScAppListingCard.md +271 -0
- package/dist/docs/ScAppSwitchPanel.md +286 -0
- package/dist/docs/ScAppcardLogos.md +226 -0
- package/dist/docs/ScArtifaxInvite.md +262 -0
- package/dist/docs/ScArtifaxSidebar.md +330 -0
- package/dist/docs/ScAskAgentButton.md +307 -0
- package/dist/docs/ScBadges.md +261 -0
- package/dist/docs/ScBeacon.md +244 -0
- package/dist/docs/ScBillingHistoryHeader.md +210 -0
- package/dist/docs/ScBillingHistoryTableList.md +243 -0
- package/dist/docs/ScBillingLogsTableHeader.md +212 -0
- package/dist/docs/ScBillingLogsTableList.md +251 -0
- package/dist/docs/ScBriefCard.md +255 -0
- package/dist/docs/ScButton.md +251 -0
- package/dist/docs/ScCalendar.md +268 -0
- package/dist/docs/ScCalendarDateComps.md +264 -0
- package/dist/docs/ScCatalogixInvite.md +345 -0
- package/dist/docs/ScCatalogixSidebar.md +337 -0
- package/dist/docs/ScCatalogixStoreHeader.md +246 -0
- package/dist/docs/ScCatalogixStoreTableList.md +316 -0
- package/dist/docs/ScCheckField.md +233 -0
- package/dist/docs/ScCheckbox.md +272 -0
- package/dist/docs/ScCounter.md +235 -0
- package/dist/docs/ScCreditsUsageCard.md +247 -0
- package/dist/docs/ScCreditsUsageCardMobile.md +224 -0
- package/dist/docs/ScDefaultCard.md +269 -0
- package/dist/docs/ScDp.md +245 -0
- package/dist/docs/ScDrawer.md +318 -0
- package/dist/docs/ScFieldButton.md +255 -0
- package/dist/docs/ScFileField.md +268 -0
- package/dist/docs/ScGoogleSignIn.md +250 -0
- package/dist/docs/ScGuide.md +278 -0
- package/dist/docs/ScHDivider.md +213 -0
- package/dist/docs/ScHeader.md +222 -0
- package/dist/docs/ScImageField.md +253 -0
- package/dist/docs/ScInChatList.md +277 -0
- package/dist/docs/ScInChatMessage.md +205 -0
- package/dist/docs/ScInfoPopup.md +248 -0
- package/dist/docs/ScIntialProfileCover.md +233 -0
- package/dist/docs/ScInvoiceHistoryMobile.md +187 -0
- package/dist/docs/ScLogoUnit.md +232 -0
- package/dist/docs/ScMappingCard.md +241 -0
- package/dist/docs/ScMediaApproval.md +301 -0
- package/dist/docs/ScMediaSelect.md +310 -0
- package/dist/docs/ScMenuOptions.md +308 -0
- package/dist/docs/ScMobileBottomAction.md +252 -0
- package/dist/docs/ScMobileTopNav.md +279 -0
- package/dist/docs/ScModal.md +291 -0
- package/dist/docs/ScOnlyField.md +302 -0
- package/dist/docs/ScOnlyIcon.md +213 -0
- package/dist/docs/ScPagination.md +284 -0
- package/dist/docs/ScPairtext.md +287 -0
- package/dist/docs/ScPendingAction.md +238 -0
- package/dist/docs/ScPhtogenixInvite.md +275 -0
- package/dist/docs/ScPlanCard.md +302 -0
- package/dist/docs/ScPlanComparison.md +264 -0
- package/dist/docs/ScPlanDetailsCard.md +246 -0
- package/dist/docs/ScPlanDetailsCardMobile.md +240 -0
- package/dist/docs/ScPopUpMenu.md +224 -0
- package/dist/docs/ScProfile.md +234 -0
- package/dist/docs/ScProfileImageUpdate.md +261 -0
- package/dist/docs/ScProfileOptions.md +245 -0
- package/dist/docs/ScProfilePopup.md +396 -0
- package/dist/docs/ScProfileSettingsComp.md +250 -0
- package/dist/docs/ScProfileV2Mobile.md +216 -0
- package/dist/docs/ScProgressBar.md +267 -0
- package/dist/docs/ScQuickPrompt.md +277 -0
- package/dist/docs/ScRadio.md +228 -0
- package/dist/docs/ScReferralCardMobile.md +226 -0
- package/dist/docs/ScReferralTableHeader.md +260 -0
- package/dist/docs/ScReferralTableList.md +293 -0
- package/dist/docs/ScRole.md +226 -0
- package/dist/docs/ScRoleMobile.md +199 -0
- package/dist/docs/ScSelect.md +270 -0
- package/dist/docs/ScSelection.md +256 -0
- package/dist/docs/ScSelectionList.md +272 -0
- package/dist/docs/ScSelectionPill.md +240 -0
- package/dist/docs/ScSelectionPillGroup.md +302 -0
- package/dist/docs/ScSettingsNav.md +212 -0
- package/dist/docs/ScSettingsTabComp.md +260 -0
- package/dist/docs/ScSideBarLogoUnit.md +340 -0
- package/dist/docs/ScSidebar.md +243 -0
- package/dist/docs/ScSidebarIcons.md +232 -0
- package/dist/docs/ScSidebarMenu.md +283 -0
- package/dist/docs/ScSidebarProfile.md +231 -0
- package/dist/docs/ScSidebarSwitchMenu.md +258 -0
- package/dist/docs/ScSlider.md +194 -0
- package/dist/docs/ScStoreCard.md +252 -0
- package/dist/docs/ScStrLogo.md +253 -0
- package/dist/docs/ScStreamoidWordmark.md +302 -0
- package/dist/docs/ScSubAgent.md +226 -0
- package/dist/docs/ScTabComp.md +308 -0
- package/dist/docs/ScTabField.md +258 -0
- package/dist/docs/ScTabSwitcher.md +307 -0
- package/dist/docs/ScTableHeader.md +261 -0
- package/dist/docs/ScTableList.md +301 -0
- package/dist/docs/ScTableListMobile.md +282 -0
- package/dist/docs/ScTabs.md +268 -0
- package/dist/docs/ScTaxonomyPill.md +263 -0
- package/dist/docs/ScTextArea.md +259 -0
- package/dist/docs/ScTextField.md +324 -0
- package/dist/docs/ScThinkingStepIcon.md +249 -0
- package/dist/docs/ScTodoList.md +288 -0
- package/dist/docs/ScToggleSwitch.md +229 -0
- package/dist/docs/ScUsageHistoryMobile.md +194 -0
- package/dist/docs/ScVDivider.md +215 -0
- package/dist/docs/ScValueMappingL1.md +256 -0
- package/dist/docs/ScVersion.md +251 -0
- package/dist/docs/ScWorkspace.md +233 -0
- package/dist/docs/ScWorkspaceCard.md +234 -0
- package/dist/docs/ScWorkspaceSettingsMobile.md +265 -0
- package/dist/docs/ScWorkspaceSwitchCard.md +314 -0
- package/dist/docs/ScWorkspaceSwitchMobile.md +241 -0
- package/dist/docs/ScWorkspaceSwitchMobileV2.md +278 -0
- package/dist/docs/StreamoidSidebar.md +403 -0
- package/dist/docs/StreamoidWorkspaceSwitcher.md +307 -0
- package/dist/docs/UsageHistoryMobile.md +235 -0
- package/dist/docs/components.json +4849 -0
- package/dist/index.css +43 -37
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/package.json +3 -2
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScWorkspaceSettingsMobile
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: mobile
|
|
5
|
+
status: stable
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [mobile, workspace, settings, team, owner, members, card, role]
|
|
8
|
+
related: [ScWorkspaceSwitchMobile, ScWorkspaceSwitchMobileV2, ScWorkspaceCard, ScTableListMobile]
|
|
9
|
+
do_not_confuse_with: [ScWorkspaceSwitchMobile, ScWorkspaceSwitchMobileV2, ScWorkspaceCard, ScWorkspaceSwitchCard, ScProfileSettingsComp]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ScWorkspaceSettingsMobile
|
|
13
|
+
|
|
14
|
+
**The mobile workspace card with two info rows.** A fixed 326px rounded card: a 48px
|
|
15
|
+
initials tile beside the workspace name with an always-blue role badge on the right, a
|
|
16
|
+
divider, then **two** icon+text rows — the owner email and the team count. Structurally
|
|
17
|
+
`ScWorkspaceSwitchMobile` plus the second row.
|
|
18
|
+
|
|
19
|
+
## TL;DR for agents
|
|
20
|
+
|
|
21
|
+
- **Reach for it when:** a mobile workspace-settings screen needs a workspace summary
|
|
22
|
+
that also shows how many people are in it.
|
|
23
|
+
- **Don't reach for it when:** the card's job is *switching* workspaces
|
|
24
|
+
(→ `ScWorkspaceSwitchMobileV2`, which is what CXO actually ships), or you're on desktop
|
|
25
|
+
(→ `ScWorkspaceCard` / `ScWorkspaceSwitchCard`).
|
|
26
|
+
- **Four things that will bite you:**
|
|
27
|
+
1. **It is `width: 326px`, fixed.** Not `100%`.
|
|
28
|
+
2. **`ownerIcon` and `teamIcon` have no defaults**, but both 48px icon gutters render
|
|
29
|
+
regardless — omit them and you get two blocks of empty space.
|
|
30
|
+
3. **The role badge is always info-blue**, whatever `role` says.
|
|
31
|
+
4. **`currentWs` defaults to `true`**, so in a list every card looks active.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 1. How to use it
|
|
36
|
+
|
|
37
|
+
### Import
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { ScWorkspaceSettingsMobile } from "@streamoid/ui";
|
|
41
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Minimal usage
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { SiconUser, SiconUsers } from "@streamoid/icons";
|
|
48
|
+
|
|
49
|
+
<ScWorkspaceSettingsMobile
|
|
50
|
+
storeName={ws.name}
|
|
51
|
+
initials={ws.initials}
|
|
52
|
+
role={ws.role === "admin" ? "Admin" : "Member"}
|
|
53
|
+
ownerId={ws.ownerEmail}
|
|
54
|
+
ownerIcon={<SiconUser size={24} />}
|
|
55
|
+
teamCount={`${ws.memberCount} Users`}
|
|
56
|
+
teamIcon={<SiconUsers size={24} />}
|
|
57
|
+
currentWs={ws._id === currentId}
|
|
58
|
+
/>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Props
|
|
62
|
+
|
|
63
|
+
| Prop | Type | Default | Notes |
|
|
64
|
+
|---|---|---|---|
|
|
65
|
+
| `storeName` | `string` | `"Stores"` | ⚠️ Demo default. The workspace name — note `storeName`, not `wsName`. 16px/500. It has `overflow: hidden; text-overflow: ellipsis` but **no `white-space: nowrap`**, so a long name wraps instead of ellipsising — see Gotcha 10. |
|
|
66
|
+
| `initials` | `string` | `"WS"` | ⚠️ Demo default. Rendered into a hand-rolled 48px `--radius-xl` tile. No name-derived fallback, no image support. |
|
|
67
|
+
| `role` | `string` | `"Admin"` | ⚠️ Demo default. Free text in a **fixed 80px always-blue** badge. Colour never varies. |
|
|
68
|
+
| `ownerId` | `string` | `"rohan@streamoid.com"` | ⚠️ Demo default — a real-looking Streamoid address. First info row. |
|
|
69
|
+
| `teamCount` | `string` | `"12 Users"` | ⚠️ Demo default. Second info row. You append the word "Users" — the card does no pluralisation. |
|
|
70
|
+
| `currentWs` | `boolean` | `true` | ⚠️ Defaults to **true**. Picks the `current` vs `other` skin. |
|
|
71
|
+
| `ownerIcon` | `JSX.Element` | – | **Slot** for the first info row's icon. No default; the gutter renders anyway. |
|
|
72
|
+
| `teamIcon` | `JSX.Element` | – | **Slot** for the second info row's icon. Same caveat. |
|
|
73
|
+
| `className` | `string` | – | Appended after internal classes. Unguarded concat — see Gotcha 5. |
|
|
74
|
+
| `onClick` | `(e: React.MouseEvent) => void` | – | Attached to the root. No `role`/`tabIndex`/`cursor` come with it. |
|
|
75
|
+
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | – | Spread onto the root `div`. |
|
|
76
|
+
|
|
77
|
+
### What each `currentWs` value renders
|
|
78
|
+
|
|
79
|
+
| `currentWs` | Class | Background | Border |
|
|
80
|
+
|---|---|---|---|
|
|
81
|
+
| `true` | `variant-current` | `--alias-surface-canvas` | 0.5px `--alias-border-subtle` |
|
|
82
|
+
| `false` | `variant-other` | `--alias-surface-base` | 0.5px `--alias-border-subtle` |
|
|
83
|
+
|
|
84
|
+
Both variants keep the border (unlike `ScWorkspaceSwitchMobile`, whose current variant
|
|
85
|
+
has none), so the two skins differ only by background.
|
|
86
|
+
|
|
87
|
+
### Recipes
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
// Make it fluid (the card is 326px by default)
|
|
91
|
+
<ScWorkspaceSettingsMobile storeName={ws.name} className="w-full" />
|
|
92
|
+
|
|
93
|
+
// Both icon slots — the inner wrapper is 24×24, so size 20–24
|
|
94
|
+
import { SiconUser, SiconUsers } from "@streamoid/icons";
|
|
95
|
+
<ScWorkspaceSettingsMobile
|
|
96
|
+
storeName={ws.name}
|
|
97
|
+
initials={ws.initials}
|
|
98
|
+
role="Admin"
|
|
99
|
+
ownerId={ws.ownerEmail}
|
|
100
|
+
ownerIcon={<SiconUser size={24} />}
|
|
101
|
+
teamCount={`${n} ${n === 1 ? "User" : "Users"}`} // pluralise yourself
|
|
102
|
+
teamIcon={<SiconUsers size={24} />}
|
|
103
|
+
currentWs={false}
|
|
104
|
+
className="w-full"
|
|
105
|
+
/>
|
|
106
|
+
|
|
107
|
+
// Tappable — add the semantics yourself
|
|
108
|
+
<ScWorkspaceSettingsMobile
|
|
109
|
+
storeName={ws.name}
|
|
110
|
+
onClick={() => openManageSheet(ws)}
|
|
111
|
+
role="Admin"
|
|
112
|
+
tabIndex={0}
|
|
113
|
+
className="w-full cursor-pointer"
|
|
114
|
+
/>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 2. Where to use it
|
|
120
|
+
|
|
121
|
+
Its intended home is the mobile **workspace settings** screen: the summary card at the
|
|
122
|
+
top of "manage this workspace", or one card per workspace in a settings list where the
|
|
123
|
+
member count matters.
|
|
124
|
+
|
|
125
|
+
CXO's mobile settings screen currently renders `ScWorkspaceSwitchMobileV2` instead
|
|
126
|
+
(`cxo-dashboard/src/app/components/mobile-settings-content.tsx:313`), which shows
|
|
127
|
+
`role · plan · owner` but **not** a team count — so this card's distinguishing feature
|
|
128
|
+
is exactly what that screen is missing.
|
|
129
|
+
|
|
130
|
+
It composes nothing from the DS: the initials tile and the role badge are hand-rolled,
|
|
131
|
+
and both icons are slots you fill.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 3. When to use it
|
|
136
|
+
|
|
137
|
+
### Use it when
|
|
138
|
+
|
|
139
|
+
- The screen is workspace **settings** (not switching) on mobile.
|
|
140
|
+
- The team size is a fact worth showing on the card.
|
|
141
|
+
- You have icons to put in both info rows.
|
|
142
|
+
|
|
143
|
+
### Don't use it — reach for this instead
|
|
144
|
+
|
|
145
|
+
| Situation | Use instead |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Switching workspaces on mobile | `ScWorkspaceSwitchMobileV2` (fluid, images, `plan`, `type` triad) |
|
|
148
|
+
| The V1 switch card with one owner row | `ScWorkspaceSwitchMobile` — but it's `status: legacy` |
|
|
149
|
+
| Desktop workspace card / switcher | `ScWorkspaceCard` / `ScWorkspaceSwitchCard` / `StreamoidWorkspaceSwitcher` |
|
|
150
|
+
| A whole profile-settings scaffold | `ScProfileSettingsComp` |
|
|
151
|
+
| Listing the workspace's members individually | `ScTableListMobile`, one per member |
|
|
152
|
+
| A role chip whose colour varies | `ScRoleMobile` (two skins) or `ScBadges` (any colour) |
|
|
153
|
+
| A workspace avatar on its own, with image support | `ScDp` (`variant="workspace"`) |
|
|
154
|
+
|
|
155
|
+
### Don't confuse with
|
|
156
|
+
|
|
157
|
+
| You may actually want | Not this |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `ScWorkspaceSwitchMobile` — **the same card minus the team row**. Identical props (`storeName`, `initials`, `role`, `ownerId`, `currentWs`, `ownerIcon`) with only `teamCount`/`teamIcon` added here, and a slightly different skin pair | The two are trivially interchangeable at a glance; decide by screen: settings → this, switching → V2 |
|
|
160
|
+
| `ScWorkspaceSwitchMobileV2` — the current mobile workspace row; `wsName`, `type`, `imageUrl`, `plan`, fluid width, composes `ScDp` | Different prop names for the same data |
|
|
161
|
+
| `ScWorkspaceCard` — the desktop workspace tile | Desktop metrics |
|
|
162
|
+
| `ScProfileSettingsComp` — a whole settings screen scaffold, for a person | Not a workspace card |
|
|
163
|
+
|
|
164
|
+
`ScWorkspaceSettingsMobile` / `ScWorkspaceSwitchMobile` / `ScWorkspaceSwitchMobileV2` are
|
|
165
|
+
three near-namesakes for the same object. Ship V2 unless you specifically need the team
|
|
166
|
+
count (this one) or the V1 look.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 4. Why to use it
|
|
171
|
+
|
|
172
|
+
- **The only mobile workspace card that shows team size**, with the icon gutters already
|
|
173
|
+
aligned so both info rows line up under the name.
|
|
174
|
+
- **Truncation is handled** on `ownerId` and `teamCount`
|
|
175
|
+
(`flex: 1 0 0; min-width: 0` + `overflow: hidden; text-overflow: ellipsis;
|
|
176
|
+
white-space: nowrap`), so long emails and big counts never break the card.
|
|
177
|
+
`storeName` gets the same flex treatment but is missing `white-space: nowrap`, so it
|
|
178
|
+
wraps rather than ellipsising (Gotcha 10).
|
|
179
|
+
- **Icon slots keep app-specific iconography out of the DS** — you pass whichever
|
|
180
|
+
`Sicon*` your product uses for "owner" and "team".
|
|
181
|
+
- **Fixed 48px gutters** mean the two rows are optically aligned regardless of icon
|
|
182
|
+
width, which is what hand-rolled versions get wrong.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Gotchas
|
|
187
|
+
|
|
188
|
+
**1. Fixed `width: 326px`.** The root is not fluid; it will not fill a mobile sheet.
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
// WRONG — 326px card inside a full-width settings screen
|
|
192
|
+
<ScWorkspaceSettingsMobile storeName={ws.name} />
|
|
193
|
+
|
|
194
|
+
// RIGHT
|
|
195
|
+
<ScWorkspaceSettingsMobile storeName={ws.name} className="w-full" />
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**2. Both icon slots are empty by default, but their gutters are not.**
|
|
199
|
+
`.iconContainer` is `width: 48px; flex-shrink: 0` and renders unconditionally; the icon
|
|
200
|
+
inside is `{ownerIcon && …}` / `{teamIcon && …}`. Omit them and you get two 48px voids.
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
// WRONG — two rows of text indented by 48px of nothing
|
|
204
|
+
<ScWorkspaceSettingsMobile ownerId={email} teamCount="12 Users" />
|
|
205
|
+
|
|
206
|
+
// RIGHT
|
|
207
|
+
<ScWorkspaceSettingsMobile
|
|
208
|
+
ownerId={email}
|
|
209
|
+
ownerIcon={<SiconUser size={24} />}
|
|
210
|
+
teamCount="12 Users"
|
|
211
|
+
teamIcon={<SiconUsers size={24} />}
|
|
212
|
+
/>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**3. The role badge is always info-blue.** `.roleBadge` hardcodes
|
|
216
|
+
`--alias-fill-info-soft` + `--alias-border-info` + info text, fixed 80px wide. `"Member"`
|
|
217
|
+
looks like `"Admin"`.
|
|
218
|
+
|
|
219
|
+
**4. `currentWs` defaults to `true`.** In a list, forgetting it makes every card look
|
|
220
|
+
like the active workspace.
|
|
221
|
+
|
|
222
|
+
**5. `className` is concatenated unguarded.** Omit it and the root carries a literal
|
|
223
|
+
`undefined` class.
|
|
224
|
+
|
|
225
|
+
**6. `.initialsText` has a wrong fallback.** It uses
|
|
226
|
+
`var(--font-size-font-size-md, 14px)` where `md` is 16px everywhere else, so the initials
|
|
227
|
+
change size depending on whether the tokens stylesheet is loaded.
|
|
228
|
+
|
|
229
|
+
**7. `teamCount` is a string you build.** No number formatting, no pluralisation — pass
|
|
230
|
+
`"1 User"` vs `"12 Users"` yourself.
|
|
231
|
+
|
|
232
|
+
**8. `onClick` brings no semantics.** Plain `div`, no `cursor: pointer` in the CSS. Add
|
|
233
|
+
`role="button"`, `tabIndex={0}` and `onKeyDown` yourself. Note the `role` prop here is
|
|
234
|
+
this component's *badge text*, so if you need the ARIA role, wrap the card.
|
|
235
|
+
|
|
236
|
+
**9. `backdrop-filter: blur(4px)`** on the root creates a containing block, so any
|
|
237
|
+
`position: fixed` descendant anchors to this card rather than the viewport.
|
|
238
|
+
|
|
239
|
+
**10. `storeName` wraps, it does not ellipsise.** `.storeName` sets `overflow: hidden`
|
|
240
|
+
and `text-overflow: ellipsis` but omits `white-space: nowrap`, so a long workspace name
|
|
241
|
+
breaks onto a second line (and then gets clipped) instead of showing "…". The two info
|
|
242
|
+
rows (`ownerId`, `teamCount`) do set `nowrap` and truncate correctly. Cap the name
|
|
243
|
+
yourself if it can be long.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## In the wild
|
|
248
|
+
|
|
249
|
+
_No host render site found — used by the agent runtime / composed internally._
|
|
250
|
+
|
|
251
|
+
To be precise: it is exported from `@streamoid/ui` but no host app renders it, and it is
|
|
252
|
+
not agent-runtime — it is currently unused. Where it belongs is CXO's mobile settings
|
|
253
|
+
screen, which today renders `ScWorkspaceSwitchMobileV2` for the same slot
|
|
254
|
+
(`cxo-dashboard/src/app/components/mobile-settings-content.tsx:313`) and therefore shows
|
|
255
|
+
`role · plan · owner` without a member count.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Related
|
|
260
|
+
|
|
261
|
+
- `ScWorkspaceSwitchMobile` — the same card minus the team row (`status: legacy`).
|
|
262
|
+
- `ScWorkspaceSwitchMobileV2` — the current mobile workspace row; what CXO ships.
|
|
263
|
+
- `ScWorkspaceCard` / `ScWorkspaceSwitchCard` / `StreamoidWorkspaceSwitcher` — desktop.
|
|
264
|
+
- `ScTableListMobile` — a member row, if you're listing the team rather than counting it.
|
|
265
|
+
- `ScDp` — the avatar primitive V2 uses; this card hand-rolls a 48px initials tile.
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScWorkspaceSwitchCard
|
|
3
|
+
also_exports: [NscWorkspaceSwitch]
|
|
4
|
+
package: "@streamoid/ui"
|
|
5
|
+
category: cards
|
|
6
|
+
status: stable
|
|
7
|
+
renders: div
|
|
8
|
+
tags: [workspace, switch-workspace, tenant, current-workspace, role, plan, owner, hover-actions, leave-workspace]
|
|
9
|
+
related: [ScWorkspaceCard, ScWorkspaceSwitchMobileV2, ScDp, StreamoidWorkspaceSwitcher, ScProfilePopup]
|
|
10
|
+
do_not_confuse_with: [ScWorkspaceCard, ScWorkspace, StreamoidWorkspaceSwitcher, ScWorkspaceSwitchMobile, ScWorkspaceSwitchMobileV2]
|
|
11
|
+
used_by: [cxo, photogenix, catalogix, artifax]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# ScWorkspaceSwitchCard
|
|
15
|
+
|
|
16
|
+
**One row in the "switch workspace" list.** A 90px workspace tile, the workspace name,
|
|
17
|
+
and a Role / Plan / Workspace-Owner detail strip — plus up to two **hover-only**
|
|
18
|
+
trailing actions: "Switch Workspace" (other workspaces), a settings icon (admins), or
|
|
19
|
+
a red leave button (non-admins). All four host apps render it; the modal around it is
|
|
20
|
+
hand-rolled in each.
|
|
21
|
+
|
|
22
|
+
## TL;DR for agents
|
|
23
|
+
|
|
24
|
+
- **Reach for it when:** you are building a workspace list where each row shows role,
|
|
25
|
+
plan and owner and can be switched into, configured or left.
|
|
26
|
+
- **Don't reach for it when:** you need the card with a user count and a persistent
|
|
27
|
+
CTA (→ `ScWorkspaceCard`), a mobile row (→ `ScWorkspaceSwitchMobileV2`), or a bare
|
|
28
|
+
workspace identity line (→ `ScProfilePopup`'s workspace block).
|
|
29
|
+
- **Five things that will bite you:**
|
|
30
|
+
1. **Every action is hover-gated.** No hover → no buttons. Touch devices and
|
|
31
|
+
keyboard users can never reach them. That is why the `*Mobile` twins exist.
|
|
32
|
+
2. `role` is a **free string** and drives everything: `role.toLowerCase() === "admin"`
|
|
33
|
+
picks amber text **and** the settings button; anything else (including
|
|
34
|
+
`"owner"`) gets info-blue and the **red leave** button.
|
|
35
|
+
3. Its props do **not** extend `HTMLAttributes` — no `onClick`, no `style`, no
|
|
36
|
+
`data-*`, no `aria-*`. Only the 12 listed props.
|
|
37
|
+
4. ⚠️ `ownerId` defaults to a real person's address, **`"rohan@streamoid.com"`**,
|
|
38
|
+
and `wsName` to `"Workspace name is kepler"`.
|
|
39
|
+
5. `cardOther` sets `cursor: pointer` on the whole card, but the card has **no
|
|
40
|
+
click handler** — only the buttons do. The cursor lies.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 1. How to use it
|
|
45
|
+
|
|
46
|
+
### Import
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import { ScWorkspaceSwitchCard } from "@streamoid/ui";
|
|
50
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Minimal usage
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<ScWorkspaceSwitchCard
|
|
57
|
+
wsName={ws.name}
|
|
58
|
+
role={ws.role}
|
|
59
|
+
plan={ws.plan}
|
|
60
|
+
ownerId={ws.ownerEmail}
|
|
61
|
+
type={ws.isCurrent ? "currentWS" : "otherWS"}
|
|
62
|
+
onSwitch={() => void switchTo(ws)}
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Props
|
|
67
|
+
|
|
68
|
+
| Prop | Type | Default | Notes |
|
|
69
|
+
|---|---|---|---|
|
|
70
|
+
| `wsName` | `string` | `"Workspace name is kepler"` | ⚠️ Real default. Also the source of derived initials. Single line + ellipsis. |
|
|
71
|
+
| `role` | `string` | `"Admin"` | ⚠️ Real default, and a **free string**. Compared case-insensitively to `"admin"`; displayed Title-Cased (`charAt(0).toUpperCase() + rest.toLowerCase()`). |
|
|
72
|
+
| `plan` | `string` | `"Free"` | ⚠️ Real default. Plain secondary text. |
|
|
73
|
+
| `ownerId` | `string` | `"rohan@streamoid.com"` | ⚠️ Real default — a real address. Always pass the actual owner. |
|
|
74
|
+
| `initials` | `string` | derived from `wsName` | First letters of the first two words, uppercased; `"WS"` if that yields nothing. |
|
|
75
|
+
| `imageUrl` | `string` | – | When set, the tile renders the image (`ScDp type="image"`); otherwise initials. |
|
|
76
|
+
| `type` | `"currentWS"` \| `"otherWS"` | `"currentWS"` | ⚠️ Defaults to **current**. Drives surface, border, cursor and whether "Switch Workspace" can appear. |
|
|
77
|
+
| `hover` | `boolean` | – | Controlled override of the internal hover state. `undefined` → the card tracks its own mouse enter/leave. Pass `true` to force the actions visible (Figma parity / tests). |
|
|
78
|
+
| `className` | `string` | – | Appended after the internal classes. |
|
|
79
|
+
| `onSwitch` | `() => void` | – | "Switch Workspace" button. **`otherWS` + hover only.** |
|
|
80
|
+
| `onSettings` | `() => void` | – | Settings icon button. **admin + hover only** (both `type`s). |
|
|
81
|
+
| `onLeave` | `() => void` | – | Red leave button. **non-admin + hover only** (both `type`s). |
|
|
82
|
+
|
|
83
|
+
Nothing else is accepted — `ScWorkspaceSwitchCardProps` is a plain interface, not an
|
|
84
|
+
`HTMLAttributes` extension.
|
|
85
|
+
|
|
86
|
+
### What renders in each state
|
|
87
|
+
|
|
88
|
+
| Region | `currentWS` | `otherWS` |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| Surface | `surface-raised` + `border-default`, `cursor: default` | `surface-base` + `border-subtle`, `cursor: pointer`; hover → `surface-basesubtle` |
|
|
91
|
+
| Tile | `ScDp` forced to **90 × 90**, `radius-xl`, bg `neutralactive` | same, bg `neutralselected` |
|
|
92
|
+
| Details | Role · Plan · Workspace Owner, split by two `ScVDivider`s | identical |
|
|
93
|
+
| "Switch Workspace" | **never** | hover only |
|
|
94
|
+
| Settings icon | hover **and** `role` is admin | hover **and** `role` is admin |
|
|
95
|
+
| Leave (red) | hover **and** `role` is not admin | hover **and** `role` is not admin |
|
|
96
|
+
|
|
97
|
+
Role colour: admin → `text-and-icons-warning` (amber); everything else →
|
|
98
|
+
`text-and-icons-info` (blue).
|
|
99
|
+
|
|
100
|
+
### Recipes
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
// Current + other sections (the shape all four hosts use)
|
|
104
|
+
<>
|
|
105
|
+
<ScWorkspaceSwitchCard
|
|
106
|
+
wsName={current.name}
|
|
107
|
+
initials={current.initials}
|
|
108
|
+
imageUrl={current.imageUrl}
|
|
109
|
+
role={current.role}
|
|
110
|
+
plan={current.plan}
|
|
111
|
+
ownerId={current.ownerEmail}
|
|
112
|
+
type="currentWS"
|
|
113
|
+
onSettings={() => openSettings(current)}
|
|
114
|
+
onLeave={() => confirmLeave(current)}
|
|
115
|
+
/>
|
|
116
|
+
{others.map((ws) => (
|
|
117
|
+
<ScWorkspaceSwitchCard
|
|
118
|
+
key={ws.id}
|
|
119
|
+
wsName={ws.name}
|
|
120
|
+
initials={ws.initials}
|
|
121
|
+
imageUrl={ws.imageUrl}
|
|
122
|
+
role={ws.role}
|
|
123
|
+
plan={ws.plan}
|
|
124
|
+
ownerId={ws.ownerEmail}
|
|
125
|
+
type="otherWS"
|
|
126
|
+
onSwitch={() => void switchTo(ws)}
|
|
127
|
+
onSettings={() => openSettings(ws)}
|
|
128
|
+
onLeave={() => confirmLeave(ws)}
|
|
129
|
+
/>
|
|
130
|
+
))}
|
|
131
|
+
</>
|
|
132
|
+
|
|
133
|
+
// Force the actions visible — screenshots, Figma parity, or a touch fallback
|
|
134
|
+
<ScWorkspaceSwitchCard wsName={ws.name} type="otherWS" hover onSwitch={switchTo} />
|
|
135
|
+
|
|
136
|
+
// Make the whole row keyboard-reachable (the card gives you no semantics)
|
|
137
|
+
<div role="button" tabIndex={0}
|
|
138
|
+
onClick={() => void switchTo(ws)}
|
|
139
|
+
onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); void switchTo(ws); } }}>
|
|
140
|
+
<ScWorkspaceSwitchCard wsName={ws.name} type="otherWS" onSwitch={() => void switchTo(ws)} />
|
|
141
|
+
</div>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 2. Where to use it
|
|
147
|
+
|
|
148
|
+
Stacked in a scrolling list inside a **host-owned** modal or drawer. Every app builds
|
|
149
|
+
that shell itself:
|
|
150
|
+
|
|
151
|
+
| App | Shell |
|
|
152
|
+
|---|---|
|
|
153
|
+
| CXO | `src/app/components/app-workspace-switcher.tsx` (+ `app-organization-switcher.tsx` for orgs) |
|
|
154
|
+
| Catalogix | `app/containers/LeftMenu/WorkspaceListing/index.jsx` |
|
|
155
|
+
| Photogenix | `dashboard/client/src/components/layout/Sidebar.tsx` |
|
|
156
|
+
| Artifax | `packages/shared/src/components/DashboardSidebar.tsx` |
|
|
157
|
+
|
|
158
|
+
The usual trigger is `ScProfilePopup`'s `onSwitchWorkspace`. `StreamoidWorkspaceSwitcher`
|
|
159
|
+
is the DS's own attempt at that modal, but no app uses it (see its README).
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 3. When to use it
|
|
164
|
+
|
|
165
|
+
### Use it when
|
|
166
|
+
|
|
167
|
+
- The row's job is **role + plan + owner at a glance**, with switch/settings/leave as
|
|
168
|
+
secondary hover affordances.
|
|
169
|
+
- You are rendering a current-vs-others list and want the two surfaces to differ
|
|
170
|
+
without writing the token pairs.
|
|
171
|
+
|
|
172
|
+
### Don't use it — reach for this instead
|
|
173
|
+
|
|
174
|
+
| Situation | Use instead |
|
|
175
|
+
|---|---|
|
|
176
|
+
| Workspace card with a **user count** and an always-visible CTA button | `ScWorkspaceCard` |
|
|
177
|
+
| Mobile workspace row (tap, no hover) | `ScWorkspaceSwitchMobileV2` (or `ScWorkspaceSwitchMobile`, `ScWorkspaceSettingsMobile`) |
|
|
178
|
+
| A one-line workspace identity (logo + name + role) | `ScProfilePopup`'s workspace block (`ScWorkspace` itself is not exported) |
|
|
179
|
+
| The whole switch **modal**, prebuilt | `StreamoidWorkspaceSwitcher` — but read its Tailwind caveat first |
|
|
180
|
+
| A generic pick-one option card | `ScDefaultCard` |
|
|
181
|
+
| A store row (Catalogix) | `ScStoreCard` / `ScCatalogixStoreTableList` |
|
|
182
|
+
| Just the workspace tile | `ScDp variant="workspace"` / `ScIntialProfileCover` |
|
|
183
|
+
|
|
184
|
+
### Don't confuse with
|
|
185
|
+
|
|
186
|
+
| You may actually want | Not this |
|
|
187
|
+
|---|---|
|
|
188
|
+
| `ScWorkspaceCard` — `workspaceName`/`role`/`userCount`/`ownerEmail`/`buttonText`, persistent button, no plan, no hover gating | `ScWorkspaceSwitchCard` has `plan`, hover actions, and no user count |
|
|
189
|
+
| `ScWorkspace` — the bare two-line identity row (**not exported**) | this is the full row with actions |
|
|
190
|
+
| `StreamoidWorkspaceSwitcher` — the modal that would contain rows like this | this is one row |
|
|
191
|
+
| `ScWorkspaceSwitchMobileV2` — mobile twin; has a third `type="display"` and a single `onClick` | this is desktop and hover-driven |
|
|
192
|
+
| `NscWorkspaceSwitch` | **`@deprecated` alias of this same component.** Import `ScWorkspaceSwitchCard`. |
|
|
193
|
+
|
|
194
|
+
### Prop-name trap across the family
|
|
195
|
+
|
|
196
|
+
| Component | Name prop | Role prop | Owner prop |
|
|
197
|
+
|---|---|---|---|
|
|
198
|
+
| `ScWorkspaceSwitchCard` | `wsName` | `role` | `ownerId` |
|
|
199
|
+
| `ScWorkspaceCard` | `workspaceName` | `role` | `ownerEmail` |
|
|
200
|
+
| `ScWorkspaceSwitchMobile` | `storeName` | `role` | `ownerId` |
|
|
201
|
+
| `ScWorkspaceSwitchMobileV2` | `wsName` | `role` | `ownerId` |
|
|
202
|
+
| `ScWorkspace` (internal) | `workspaceName` | `userRole` | — |
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 4. Why to use it
|
|
207
|
+
|
|
208
|
+
- **Current vs other is a token pair, not a colour.** `surface-raised`/`border-default`
|
|
209
|
+
against `surface-base`/`border-subtle`, with `surface-basesubtle` on hover — three
|
|
210
|
+
greys that stay distinguishable in light mode, where a hand-picked grey collapses to
|
|
211
|
+
white.
|
|
212
|
+
- **The action matrix is already correct.** Switch only for other workspaces, settings
|
|
213
|
+
only for admins, leave only for non-admins, none of them on the current card's
|
|
214
|
+
switch slot. Getting that wrong ships a "leave" button to the owner of the workspace.
|
|
215
|
+
- **`min-width: 0` + `flex: 1 0 0` in the right three places** so long names and owner
|
|
216
|
+
emails ellipsise instead of pushing the buttons off the card — the most common bug
|
|
217
|
+
when this row is hand-rolled.
|
|
218
|
+
- **Initials derivation for free** (first letters of two words, `"WS"` fallback), so
|
|
219
|
+
you can pass `wsName` alone.
|
|
220
|
+
- **Consistent across four apps** — the same row in CXO, Catalogix, Photogenix and
|
|
221
|
+
Artifax, differing only in the modal around it.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Gotchas
|
|
226
|
+
|
|
227
|
+
**1. All actions are hover-only, and they are plain `<div onClick>`s.** No `role`, no
|
|
228
|
+
`tabIndex`, no keyboard activation. A keyboard-only or touch user cannot switch, open
|
|
229
|
+
settings or leave from this card. Provide your own path (a wrapping `role="button"`,
|
|
230
|
+
or `hover` forced on for touch), or use the `*Mobile` twins.
|
|
231
|
+
|
|
232
|
+
**2. `role` is a free string with real consequences.**
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
// WRONG — "Owner" is not "admin": info-blue text AND the red leave button
|
|
236
|
+
<ScWorkspaceSwitchCard wsName={ws.name} role="Owner" onLeave={leave} />
|
|
237
|
+
|
|
238
|
+
// RIGHT — normalise, then relabel elsewhere if you need to
|
|
239
|
+
<ScWorkspaceSwitchCard wsName={ws.name} role={isAdmin ? "Admin" : "Member"} onSettings={settings} />
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Comparison is `role?.toLowerCase() === "admin"`, so `"ADMIN"` and `"admin"` are fine;
|
|
243
|
+
display is force-Title-Cased, so `"co-admin"` renders as `"Co-admin"` **and** is
|
|
244
|
+
treated as a non-admin.
|
|
245
|
+
|
|
246
|
+
**3. Personal data in the defaults.** `ownerId` defaults to
|
|
247
|
+
`"rohan@streamoid.com"`, `plan` to `"Free"` and `wsName` to
|
|
248
|
+
`"Workspace name is kepler"`. This has already shipped as a real bug: Artifax's
|
|
249
|
+
`packages/shared/src/components/DashboardSidebar.tsx:1032` carries a comment about every row falling back to
|
|
250
|
+
`"Free" + "rohan@streamoid.com"` because the store's `/workspaces` payload has no
|
|
251
|
+
plan. Always pass real values, or `""`.
|
|
252
|
+
|
|
253
|
+
**4. No `onClick` / `style` / `data-*` on the card.** The interface lists 12 props and
|
|
254
|
+
does not extend `HTMLAttributes`. To make the whole row clickable, wrap it (and note
|
|
255
|
+
the inner buttons already `stopPropagation`, so a wrapper handler won't double-fire).
|
|
256
|
+
|
|
257
|
+
**5. The `otherWS` cursor implies a click that does not exist.** `.cardOther` sets
|
|
258
|
+
`cursor: pointer` on the whole card, but only the "Switch Workspace" button is wired.
|
|
259
|
+
Either wrap the card in your own click handler or accept the mismatch.
|
|
260
|
+
|
|
261
|
+
**6. `ScDp`'s `size` is overridden.** `.dp` forces `width/height: 90px !important`, so
|
|
262
|
+
the nested tile is always 90px regardless of anything you would pass. The tile's
|
|
263
|
+
`border-radius` is also overridden inline to `radius-xl`.
|
|
264
|
+
|
|
265
|
+
**7. `hover` is a controlled override, not an event.** Passing `hover={false}` pins
|
|
266
|
+
the actions **hidden** forever, including on real mouse-over. Pass `undefined` (omit
|
|
267
|
+
it) for normal behaviour.
|
|
268
|
+
|
|
269
|
+
**8. Both hover actions can appear at once.** An admin viewing another workspace gets
|
|
270
|
+
"Switch Workspace" **and** the settings icon; a member gets "Switch Workspace" **and**
|
|
271
|
+
the red leave button. Budget the horizontal space — the details strip shrinks to make
|
|
272
|
+
room.
|
|
273
|
+
|
|
274
|
+
**9. Leave is available on the current workspace too.** `isHover && !isAdmin` is not
|
|
275
|
+
gated on `type`, so a member sees the red button on the card they are currently in.
|
|
276
|
+
Confirm destructively (all four hosts open a confirm modal from `onLeave`).
|
|
277
|
+
|
|
278
|
+
**10. `NscWorkspaceSwitch` is a deprecated alias** of this export, kept for old
|
|
279
|
+
imports. Don't use it in new code.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## In the wild
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
// cxo-dashboard src/app/components/app-workspace-switcher.tsx:408
|
|
287
|
+
<ScWorkspaceSwitchCard
|
|
288
|
+
wsName={currentWorkspace.name}
|
|
289
|
+
initials={currentWorkspace.initials}
|
|
290
|
+
imageUrl={currentWorkspace.imageUrl}
|
|
291
|
+
role={currentWorkspace.role}
|
|
292
|
+
plan={currentWorkspace.plan}
|
|
293
|
+
ownerId={currentWorkspace.ownerEmail}
|
|
294
|
+
type="currentWS"
|
|
295
|
+
onSwitch={() => void handleSwitch(currentWorkspace)}
|
|
296
|
+
onSettings={() => { setEditingWs(currentWorkspace); setUpdateModalOpen(true); }}
|
|
297
|
+
onLeave={() => { setLeavingWs(currentWorkspace); setConfirmLeaveOpen(true); }}
|
|
298
|
+
/>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Also: `catalogix/dashboard app/containers/LeftMenu/WorkspaceListing/index.jsx:371`,
|
|
302
|
+
`photogenix_v2 dashboard/client/src/components/layout/Sidebar.tsx:1129`, and
|
|
303
|
+
`artifax packages/shared/src/components/DashboardSidebar.tsx:1134`.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Related
|
|
308
|
+
|
|
309
|
+
- `ScWorkspaceCard` — user count + persistent CTA instead of hover actions.
|
|
310
|
+
- `ScWorkspaceSwitchMobileV2` — the mobile twin (tap, no hover, extra `"display"` type).
|
|
311
|
+
- `StreamoidWorkspaceSwitcher` — the DS's prebuilt modal; unused by hosts, needs Tailwind.
|
|
312
|
+
- `ScProfilePopup` — its `onSwitchWorkspace` is what opens the list.
|
|
313
|
+
- `ScDp` — the tile it composes (forced to 90px here).
|
|
314
|
+
- `ScVDivider` — the two separators in the details strip.
|