@streamoid/ui 0.6.17 → 0.6.19
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 +325 -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 +210 -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/ScWorkspaceAccountMenu.md +115 -0
- package/dist/docs/ScWorkspaceCard.md +234 -0
- package/dist/docs/ScWorkspaceSettingsMobile.md +265 -0
- package/dist/docs/ScWorkspaceSwitchCard.md +312 -0
- package/dist/docs/ScWorkspaceSwitchMobile.md +241 -0
- package/dist/docs/ScWorkspaceSwitchMobileV2.md +278 -0
- package/dist/docs/StreamoidSidebar.md +413 -0
- package/dist/docs/StreamoidWorkspaceSwitcher.md +307 -0
- package/dist/docs/UsageHistoryMobile.md +235 -0
- package/dist/docs/components.json +4931 -0
- package/dist/index.css +361 -36
- package/dist/index.d.mts +213 -88
- package/dist/index.d.ts +213 -88
- package/dist/index.js +2486 -1629
- package/dist/index.mjs +2487 -1620
- package/package.json +5 -3
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScArtifaxInvite
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: cards
|
|
5
|
+
status: stable
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [invite, app-access, artifax, toggle, permissions, user-management, settings, onboarding, row]
|
|
8
|
+
related: [ScPhtogenixInvite, ScCatalogixInvite, ScAppCard, ScToggleSwitch, ScAccess]
|
|
9
|
+
do_not_confuse_with: [ScPhtogenixInvite, ScCatalogixInvite, ScAppCard, ScAppListingCard, ScAppCardV3, ScAppCardForCopilot, ScAccess]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ScArtifaxInvite
|
|
13
|
+
|
|
14
|
+
**One "does this user get Artifax?" row for the invite / edit-user modal.** An
|
|
15
|
+
`ScAppCard` (icon + app name + description) on the left, an `ScToggleSwitch` on the
|
|
16
|
+
right, a hairline divider underneath. Nothing else — no store scoping, no roles.
|
|
17
|
+
|
|
18
|
+
## TL;DR for agents
|
|
19
|
+
|
|
20
|
+
- **Reach for it when:** you are building the per-app access list in an invite or
|
|
21
|
+
edit-user flow and need the **Artifax** row (or any app whose access is a plain
|
|
22
|
+
on/off with no sub-scope).
|
|
23
|
+
- **Don't reach for it when:** the app needs sub-scoping under the toggle
|
|
24
|
+
(→ `ScCatalogixInvite`, which adds the store-access panel), it's the Photogenix
|
|
25
|
+
row (→ `ScPhtogenixInvite`, **different prop names**), or you just want to
|
|
26
|
+
display an app without a toggle (→ `ScAppCard`).
|
|
27
|
+
- **Four things that will bite you:**
|
|
28
|
+
1. ⚠️ It defaults to **ON**: `active` defaults to `"true"`. Pass `enabled`
|
|
29
|
+
explicitly, always.
|
|
30
|
+
2. ⚠️ Every string defaults to Artifax placeholder copy — `appName="Artifax"`,
|
|
31
|
+
`appDescription="Info about artifax"`. That description is Figma filler, not
|
|
32
|
+
product copy.
|
|
33
|
+
3. `active` is the string `"true"`/`"false"` (a Figma variant), `enabled` is the
|
|
34
|
+
boolean. `enabled` wins when defined. Use `enabled`.
|
|
35
|
+
4. It's fully controlled: `onToggle(next)` fires, the component does not change
|
|
36
|
+
its own state.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 1. How to use it
|
|
41
|
+
|
|
42
|
+
### Import
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { ScArtifaxInvite } from "@streamoid/ui";
|
|
46
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Minimal usage
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
<ScArtifaxInvite
|
|
53
|
+
enabled={artifaxOn}
|
|
54
|
+
onToggle={setArtifaxOn}
|
|
55
|
+
appDescription="Design brief and asset workflows"
|
|
56
|
+
/>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Props
|
|
60
|
+
|
|
61
|
+
| Prop | Type | Default | Notes |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| `enabled` | `boolean` | – | The real on/off. Overrides `active` whenever it is not `undefined`. **Use this one.** |
|
|
64
|
+
| `active` | `"true"` \| `"false"` | `"true"` | ⚠️ Figma-variant leftover, a *string*. Only consulted when `enabled` is `undefined` — so the row renders **ON** by default. |
|
|
65
|
+
| `onToggle` | `(active: boolean) => void` | – | Fires with the **next** value. No-op if omitted: the toggle then looks live but never changes. |
|
|
66
|
+
| `appName` | `string` | `"Artifax"` | ⚠️ Real default. Passed to `ScAppCard`. |
|
|
67
|
+
| `appDescription` | `string` | `"Info about artifax"` | ⚠️ Real default, and it is placeholder copy. Always set it. |
|
|
68
|
+
| `appIcon` | `JSX.Element` | `<SiconArtifacts />` | ⚠️ Has a default. Correct for Artifax; wrong if you reuse this row for another app. |
|
|
69
|
+
| `className` | `string` | – | Appended after internal classes. |
|
|
70
|
+
| `...props` | `Omit<HTMLAttributes<HTMLDivElement>, "onToggle">` | – | Spread onto the root `<div>` — `onClick`, `style`, `data-*` all work here (unlike `ScPhtogenixInvite`). |
|
|
71
|
+
|
|
72
|
+
### Recipes
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
// The standard app-access list: one controlled row per app
|
|
76
|
+
const [access, setAccess] = useState({ artifax: false, photogenix: false });
|
|
77
|
+
|
|
78
|
+
<ScArtifaxInvite
|
|
79
|
+
enabled={access.artifax}
|
|
80
|
+
onToggle={(next) => setAccess((a) => ({ ...a, artifax: next }))}
|
|
81
|
+
appDescription="Design brief and asset workflows"
|
|
82
|
+
/>
|
|
83
|
+
<ScPhtogenixInvite
|
|
84
|
+
enabled={access.photogenix}
|
|
85
|
+
onToggle={(next) => setAccess((a) => ({ ...a, photogenix: next }))}
|
|
86
|
+
scAppCardappDescription="AI product photography" // note the prop names
|
|
87
|
+
scAppCardappIcon={<SiconPhotogenix size={24} />}
|
|
88
|
+
/>
|
|
89
|
+
|
|
90
|
+
// Reusing the row for a different app (it is app-agnostic apart from its defaults)
|
|
91
|
+
<ScArtifaxInvite
|
|
92
|
+
appName="Tactix"
|
|
93
|
+
appDescription="Merch planning and allocation"
|
|
94
|
+
appIcon={<SiconArtifacts size={24} />}
|
|
95
|
+
enabled={tactixOn}
|
|
96
|
+
onToggle={setTactixOn}
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
// Mark the last row so you can drop the divider from your side
|
|
100
|
+
<ScArtifaxInvite
|
|
101
|
+
enabled={artifaxOn}
|
|
102
|
+
onToggle={setArtifaxOn}
|
|
103
|
+
className={styles.lastRow} // .lastRow { border-bottom-width: 0 }
|
|
104
|
+
/>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 2. Where to use it
|
|
110
|
+
|
|
111
|
+
- **The invite-user modal's "App access" section** — a stacked list of app rows,
|
|
112
|
+
one per product, inside `ScModal`/`ScDrawer`.
|
|
113
|
+
- **The edit-user / manage-access drawer** — same list, pre-populated.
|
|
114
|
+
- **First-run onboarding** ("which products do you want enabled?").
|
|
115
|
+
|
|
116
|
+
It composes `ScAppCard` (flexed to fill) + `ScToggleSwitch` (`flex-shrink: 0`) and
|
|
117
|
+
draws its own bottom divider, so a vertical stack of these rows needs no
|
|
118
|
+
`ScHDivider` between them.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 3. When to use it
|
|
123
|
+
|
|
124
|
+
### Use it when
|
|
125
|
+
|
|
126
|
+
- Access to the app is a **single boolean** with no sub-resource to pick.
|
|
127
|
+
- You want the row to match the Catalogix/Photogenix rows beside it — same
|
|
128
|
+
padding (`--spacing-3xl`), same divider, same toggle geometry.
|
|
129
|
+
|
|
130
|
+
### Don't use it — reach for this instead
|
|
131
|
+
|
|
132
|
+
| Situation | Use instead |
|
|
133
|
+
|---|---|
|
|
134
|
+
| The app's access needs a nested resource picker (stores, projects) | `ScCatalogixInvite` |
|
|
135
|
+
| The Photogenix row | `ScPhtogenixInvite` — same layout, **prefixed** prop names |
|
|
136
|
+
| App icon + name + description with **no** toggle | `ScAppCard` |
|
|
137
|
+
| A read-only "which apps does this user have" indicator (icons only) | `ScAccess` |
|
|
138
|
+
| A marketing/launcher card for an app | `ScAppListingCard` / `ScAppCardV3` |
|
|
139
|
+
| The app card inside the copilot/agent surface | `ScAppCardForCopilot` |
|
|
140
|
+
| Just the switch, in your own row | `ScToggleSwitch` |
|
|
141
|
+
| A labelled boolean inside a normal form | `ScCheckField` / `ScCheckbox` |
|
|
142
|
+
| Switching the *current* app | `ScAppSwitchPanel` |
|
|
143
|
+
|
|
144
|
+
### Don't confuse with
|
|
145
|
+
|
|
146
|
+
| You may actually want | Not this |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `ScCatalogixInvite` — same header row **plus** a store-access panel that appears when enabled; defaults to **OFF** | `ScArtifaxInvite` is header-only and defaults to **ON** |
|
|
149
|
+
| `ScPhtogenixInvite` — identical markup, but props are `scAppCardappName` / `scAppCardappDescription` / `scAppCardappIcon`, and it **drops** `...props` | `ScArtifaxInvite` uses clean `appName`/`appDescription`/`appIcon` and forwards DOM props |
|
|
150
|
+
| `ScAppCard` — the inner icon/name/description block, no toggle, no divider | This row wraps one |
|
|
151
|
+
| `ScAccess` — up to three app icons in a row, read-only, no labels | Not an editable access control |
|
|
152
|
+
|
|
153
|
+
The trio is **not** app-locked: nothing but the default strings and the default
|
|
154
|
+
icon ties `ScArtifaxInvite` to Artifax. Pick the one whose *shape* you need
|
|
155
|
+
(plain row vs. row + sub-scope), then override the copy.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 4. Why to use it
|
|
160
|
+
|
|
161
|
+
- **The row is the design.** 16px padding, 8px gap, a 0.5px
|
|
162
|
+
`--alias-border-divider` bottom hairline, `ScAppCard` flexed to `1` and the
|
|
163
|
+
toggle pinned at `flex-shrink: 0` — that's the whole spec, and getting the
|
|
164
|
+
divider/flex pair wrong is exactly how these lists end up ragged.
|
|
165
|
+
- **The toggle is the shared one.** `ScToggleSwitch` renders the two exact Figma
|
|
166
|
+
SVG states (on: base fill + inverse knob; off: neutral fill + divider stroke),
|
|
167
|
+
token-coloured, so it matches every other switch in the product across themes.
|
|
168
|
+
- **`enabled`/`onToggle` is a plain controlled-boolean contract**, which is what
|
|
169
|
+
an invite form wants: one piece of state per app, submitted together.
|
|
170
|
+
- **One place to change.** `@streamoid/settings` currently hand-rolls this row
|
|
171
|
+
three times over (with its own local `ToggleSwitch`); adopting these components
|
|
172
|
+
is how that duplication goes away.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Gotchas
|
|
177
|
+
|
|
178
|
+
**1. It renders ON unless you say otherwise.** `active = "true"` is the default and
|
|
179
|
+
`enabled` is `undefined` until you pass it.
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
// WRONG — an invite form that starts with Artifax already granted
|
|
183
|
+
<ScArtifaxInvite onToggle={setArtifaxOn} />
|
|
184
|
+
|
|
185
|
+
// RIGHT
|
|
186
|
+
<ScArtifaxInvite enabled={artifaxOn} onToggle={setArtifaxOn} />
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Note the inconsistency across the trio: `ScArtifaxInvite` and `ScPhtogenixInvite`
|
|
190
|
+
default to `"true"`, `ScCatalogixInvite` defaults to `"false"`.
|
|
191
|
+
|
|
192
|
+
**2. `active` is a string, not a boolean.** `active={true}` is a type error and
|
|
193
|
+
`active="false"` reads as off — but any `enabled` you pass overrides it. Treat
|
|
194
|
+
`active` as legacy and never mix the two.
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
// WRONG — mixed sources of truth; `enabled` silently wins
|
|
198
|
+
<ScArtifaxInvite active="false" enabled={artifaxOn} onToggle={setArtifaxOn} />
|
|
199
|
+
|
|
200
|
+
// RIGHT
|
|
201
|
+
<ScArtifaxInvite enabled={artifaxOn} onToggle={setArtifaxOn} />
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**3. `appDescription` defaults to `"Info about artifax"`.** That is Figma filler
|
|
205
|
+
that will ship to users. Same for the `ScAppCard` fallbacks underneath it.
|
|
206
|
+
|
|
207
|
+
**4. It is stateless.** Omit `onToggle` and the switch is a dead pixel — clicking
|
|
208
|
+
does nothing, because `checked` is recomputed from your props on every render.
|
|
209
|
+
|
|
210
|
+
**5. You cannot disable the toggle.** `ScToggleSwitch` supports `disabled`, but
|
|
211
|
+
this row never forwards it and exposes no such prop. For a read-only row, render
|
|
212
|
+
`ScAppCard` + your own indicator, or gate the whole section.
|
|
213
|
+
|
|
214
|
+
**6. Only the switch is clickable.** The root `<div>` gets no handler, `role` or
|
|
215
|
+
keyboard affordance of its own (you can spread your own `onClick` via `...props`,
|
|
216
|
+
but nothing focusable appears); the switch itself is a `div` with `onClick` (not a
|
|
217
|
+
real `<input type="checkbox">`), so there is **no keyboard or screen-reader
|
|
218
|
+
support**. If access control has to be operable by keyboard, wrap or replace it —
|
|
219
|
+
`ScCheckField` gives you real semantics.
|
|
220
|
+
|
|
221
|
+
**7. `styles["active-true"]` doesn't exist.** The stylesheet only defines
|
|
222
|
+
`.active-false` (which merely thickens the divider from 0.5px to 1px), so in the
|
|
223
|
+
ON state the variant class resolves to `undefined` and lands in the class
|
|
224
|
+
attribute as the literal string `"undefined"` — along with `className` when you
|
|
225
|
+
omit it. Don't write selectors or snapshot assertions against the class list.
|
|
226
|
+
|
|
227
|
+
**8. Rows carry their own bottom divider.** Stacking these gives you the
|
|
228
|
+
separators for free, but the last row also draws one. Strip it with `className`.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## In the wild
|
|
233
|
+
|
|
234
|
+
_No host render site found — used by the agent runtime / composed internally._
|
|
235
|
+
|
|
236
|
+
The surface it models is real but hand-rolled in the shared settings package,
|
|
237
|
+
which reimplements this row (and its own local `ToggleSwitch`) instead of
|
|
238
|
+
importing it:
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
// @streamoid/settings packages/settings/src/invite-update-modal.tsx:617
|
|
242
|
+
<ToggleSwitch // local component, not ScToggleSwitch
|
|
243
|
+
active={artifaxOn}
|
|
244
|
+
onClick={() => { setArtifaxOn(!artifaxOn); markChanged(); }}
|
|
245
|
+
/>
|
|
246
|
+
// …wrapped in hand-written markup that duplicates ScAppCard, including the
|
|
247
|
+
// literal strings "Artifax" and "Info about artifax" (lines ~596-620).
|
|
248
|
+
// The local ToggleSwitch is defined at invite-update-modal.tsx:84.
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
That modal (rendered by CXO settings → Teams → invite/edit user) is where this
|
|
252
|
+
component belongs.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Related
|
|
257
|
+
|
|
258
|
+
- `ScPhtogenixInvite` — the Photogenix twin; watch the `scAppCard*` prop prefix.
|
|
259
|
+
- `ScCatalogixInvite` — the same row plus a store-access panel when enabled.
|
|
260
|
+
- `ScAppCard` — the icon/name/description block inside it.
|
|
261
|
+
- `ScToggleSwitch` — the switch on the right, if you need it standalone.
|
|
262
|
+
- `ScAccess` — read-only app-access icon row.
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScArtifaxSidebar
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: sidebar
|
|
5
|
+
status: stable
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [sidebar, artifax, nav, shell, rail, collapsible-sections, accordion, collapse]
|
|
8
|
+
related: [StreamoidSidebar, ScSideBarLogoUnit, ScAppSwitchPanel, ScSidebarMenu, ScAskAgentButton, CreditWarningBanner]
|
|
9
|
+
do_not_confuse_with: [StreamoidSidebar, ScCatalogixSidebar, ScArtifaxInvite, ScSidebar]
|
|
10
|
+
used_by: [artifax]
|
|
11
|
+
required_props: [expanded, onToggle, sections]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# ScArtifaxSidebar
|
|
15
|
+
|
|
16
|
+
**The Artifax app shell's sidebar — the one shell with collapsible, labelled nav
|
|
17
|
+
sections.** Same silhouette as `StreamoidSidebar` (256px rounded card / 56px rail,
|
|
18
|
+
logo slot, credit banner, gradient assistant CTA, profile + inline collapse toggle),
|
|
19
|
+
but the nav is an accordion of uppercase-labelled sections, and it has **no
|
|
20
|
+
`switchPanel` slot** — the app switcher is the host's job.
|
|
21
|
+
|
|
22
|
+
## TL;DR for agents
|
|
23
|
+
|
|
24
|
+
- **Reach for it when:** you are working on the Artifax (or Tactix) shell, or you
|
|
25
|
+
need a sidebar whose sections the user can collapse.
|
|
26
|
+
- **Don't reach for it when:** you are in CXO / Photogenix / Catalogix
|
|
27
|
+
(→ `StreamoidSidebar`), or you need the built-in app-switch overlay
|
|
28
|
+
(`StreamoidSidebar`'s `switchPanel` — this component has none).
|
|
29
|
+
- **Four things that will bite you:**
|
|
30
|
+
1. Uncontrolled open-state is captured **once, at mount**. Sections that arrive
|
|
31
|
+
later (async nav) render **closed**.
|
|
32
|
+
2. Passing `openSections={{}}` switches it to controlled mode with **everything
|
|
33
|
+
closed** — `isControlled = !!openSections`, and `{}` is truthy.
|
|
34
|
+
3. A missing `iconMap` entry renders a **dashed-circle placeholder**, not nothing.
|
|
35
|
+
4. `.footerToggle > *` forces your toggle icon to **24×24 via CSS** — the `size`
|
|
36
|
+
prop on your `Sicon*` is overridden.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 1. How to use it
|
|
41
|
+
|
|
42
|
+
### Import
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import {
|
|
46
|
+
ScArtifaxSidebar,
|
|
47
|
+
type ArtifaxSection,
|
|
48
|
+
type ArtifaxSidebarIconMap,
|
|
49
|
+
type ArtifaxSidebarAssistantCta,
|
|
50
|
+
} from "@streamoid/ui";
|
|
51
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Minimal usage
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
<ScArtifaxSidebar
|
|
58
|
+
expanded={!collapsed}
|
|
59
|
+
onToggle={() => setCollapsed((v) => !v)}
|
|
60
|
+
sections={[
|
|
61
|
+
{ id: "work", label: "Workspace", items: [{ id: "projects", label: "Projects", iconKey: "folder" }] },
|
|
62
|
+
]}
|
|
63
|
+
iconMap={{ folder: <SiconFolder /> }}
|
|
64
|
+
activeItemId="projects"
|
|
65
|
+
onItemSelect={(item) => navigate(`/${item.id}`)}
|
|
66
|
+
/>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Props
|
|
70
|
+
|
|
71
|
+
| Prop | Type | Default | Notes |
|
|
72
|
+
|---|---|---|---|
|
|
73
|
+
| `expanded` | `boolean` | — | **Required.** `true` → 256px card inside a 16px padded wrapper; `false` → 56px rail with a right border. Separate render branches. |
|
|
74
|
+
| `onToggle` | `() => void` | — | **Required.** Fired by the footer toggle. |
|
|
75
|
+
| `sections` | `ArtifaxSection[]` | — | **Required.** `{ id, label?, collapsible?, defaultOpen?, items }[]`. A `ScHDivider` is drawn before every section except the first. |
|
|
76
|
+
| `iconMap` | `ArtifaxSidebarIconMap` | – | `Record<iconKey, ReactNode \| ({item, active, expanded}) => ReactNode>`. ⚠️ Missing key → dashed-circle placeholder icon. |
|
|
77
|
+
| `activeItemId` | `string` | – | Matching row gets `state="active"`; `active` is also passed to your icon renderer. |
|
|
78
|
+
| `onItemSelect` | `(item: ArtifaxMenuItem, sectionId: string) => void` | – | Fired on row click. |
|
|
79
|
+
| `expandedLogo` | `ReactNode` | – | Slot. Omit → **no logo at all** (there is no built-in default). |
|
|
80
|
+
| `collapsedLogo` | `ReactNode` | – | Slot, in a fixed 48×48 box. |
|
|
81
|
+
| `creditWarning` | `ArtifaxSidebarCreditWarning \| null` | – | `{ availableCredits, remainingPct, level?, onBuyCredits }`. `level` defaults to **`"danger"`** here. Renders `CreditWarningBanner`. |
|
|
82
|
+
| `assistantCta` | `ArtifaxSidebarAssistantCta \| null` | – | Alias of `AssistantCta`. Renders `ScAskAgentSlot` — the gradient "Ask CXO" pill / collapsed square. |
|
|
83
|
+
| `profile` | `ArtifaxSidebarProfile` | – | `{ name, subtitle?, avatar?, onClick? }`. Omit and an `aria-hidden` spacer keeps the toggle right-aligned. |
|
|
84
|
+
| `toggleIcon` | `ReactNode \| ((expanded: boolean) => ReactNode)` | `<SiconCollapse />` | ⚠️ **Has a real default** (unlike `StreamoidSidebar`). It does **not** rotate when collapsed — do that yourself. |
|
|
85
|
+
| `openSections` | `Record<string, boolean>` | – | Presence switches to **controlled** accordion mode. |
|
|
86
|
+
| `onSectionToggle` | `(sectionId: string, open: boolean) => void` | – | Fires in **both** modes (uncontrolled too). |
|
|
87
|
+
| `className` | `string` | – | On the outer wrapper — Artifax uses it to scope per-app CSS. |
|
|
88
|
+
| `style` | `CSSProperties` | – | On the outer wrapper. |
|
|
89
|
+
|
|
90
|
+
### Types
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
interface ArtifaxMenuItem { id: string; label: string; iconKey: string }
|
|
94
|
+
interface ArtifaxSection {
|
|
95
|
+
id: string;
|
|
96
|
+
label?: string; // no label → no header, section is always open
|
|
97
|
+
collapsible?: boolean; // false → header renders but is disabled, always open
|
|
98
|
+
defaultOpen?: boolean; // read ONCE, at mount. Defaults to true.
|
|
99
|
+
items: ArtifaxMenuItem[];
|
|
100
|
+
}
|
|
101
|
+
interface ArtifaxSidebarCreditWarning { availableCredits: number; remainingPct: number; level?: "warning" | "danger"; onBuyCredits: () => void }
|
|
102
|
+
type ArtifaxSidebarAssistantCta = AssistantCta; // { label, icon?, active?, ariaLabel?, onClick }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### What renders in each rail
|
|
106
|
+
|
|
107
|
+
| Region | expanded | collapsed |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| Container | 256px, 16px radius, 1px `border-subtle` overlay, inside a 16px padded wrapper | 56px wide, `border-right` only, no wrapper padding |
|
|
110
|
+
| Logo | `expandedLogo`, 8px padding, full width | `collapsedLogo` in a 48×48 centred box |
|
|
111
|
+
| Section header | uppercase 10px/1px-tracked label + `SiconUp`/`SiconDown` chevron | **not rendered** |
|
|
112
|
+
| Items | `ScSidebarMenu variant="expanded"` with `text` | `variant="collapsed"`, `text` omitted |
|
|
113
|
+
| Collapsibility | honoured | **ignored** — all items always render |
|
|
114
|
+
| Credit banner | `CreditWarningBanner expanded` | `CreditWarningBanner expanded={false}` (40×40 square) |
|
|
115
|
+
| Assistant CTA | `ScAskAgentSlot` pill | `ScAskAgentSlot collapsed` square |
|
|
116
|
+
| Footer | profile (flex-1, hover bg) + toggle, `aria-label="Collapse sidebar"` | avatar above toggle, `aria-label="Expand sidebar"` |
|
|
117
|
+
|
|
118
|
+
### Recipes
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
// Controlled accordion — persist which sections are open
|
|
122
|
+
const [openSections, setOpenSections] = useState<Record<string, boolean>>({ work: true, recent: false });
|
|
123
|
+
|
|
124
|
+
<ScArtifaxSidebar
|
|
125
|
+
expanded={!collapsed}
|
|
126
|
+
onToggle={() => setCollapsed((v) => !v)}
|
|
127
|
+
sections={sections}
|
|
128
|
+
openSections={openSections}
|
|
129
|
+
onSectionToggle={(id, open) => setOpenSections((p) => ({ ...p, [id]: open }))}
|
|
130
|
+
iconMap={iconMap}
|
|
131
|
+
/>
|
|
132
|
+
|
|
133
|
+
// Icon renderer that tracks the active row
|
|
134
|
+
<ScArtifaxSidebar
|
|
135
|
+
/* … */
|
|
136
|
+
iconMap={{
|
|
137
|
+
folder: ({ active }) => (
|
|
138
|
+
<SiconFolder color={active ? "var(--alias-text---icons-primary)" : "var(--alias-text---icons-tertiary)"} />
|
|
139
|
+
),
|
|
140
|
+
}}
|
|
141
|
+
/>
|
|
142
|
+
|
|
143
|
+
// Gradient assistant CTA + low credits, plus a collapsed-aware toggle glyph
|
|
144
|
+
<ScArtifaxSidebar
|
|
145
|
+
/* … */
|
|
146
|
+
assistantCta={{ label: "Ask CXO", icon: <SiconBolt className="h-5 w-5" />, active: assistantOpen, onClick: toggleAssistant }}
|
|
147
|
+
creditWarning={{ availableCredits: 120, remainingPct: 4, onBuyCredits: goBilling }}
|
|
148
|
+
toggleIcon={(expanded) => <SiconCollapse className={expanded ? "" : "rotate-180"} />}
|
|
149
|
+
/>
|
|
150
|
+
|
|
151
|
+
// The app switcher — this component has no slot for it, so portal your own
|
|
152
|
+
<>
|
|
153
|
+
<ScArtifaxSidebar expandedLogo={<div ref={anchorRef}><ScSideBarLogoUnit wordmark={wm} onClick={() => setOpen(v => !v)} /></div>} … />
|
|
154
|
+
{open ? createPortal(<Flyout anchorRef={anchorRef}><ScAppSwitchPanel apps={apps} /></Flyout>, document.body) : null}
|
|
155
|
+
</>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 2. Where to use it
|
|
161
|
+
|
|
162
|
+
- **The Artifax dashboard shell** — `packages/shared/src/components/DashboardSidebar.tsx`,
|
|
163
|
+
shared by the Artifax and Tactix front-ends. That file is the reference wiring for
|
|
164
|
+
everything this component deliberately leaves out (app switcher, profile menu,
|
|
165
|
+
workspace modal).
|
|
166
|
+
- It composes internally: `ScSidebarMenu`, `ScHDivider`, `CreditWarningBanner`,
|
|
167
|
+
`ScAskAgentSlot`, and `SiconCollapse`/`SiconUp`/`SiconDown`.
|
|
168
|
+
- You supply into its slots: `ScSideBarLogoUnit` (both logo slots), `ScDp`
|
|
169
|
+
(`profile.avatar`).
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 3. When to use it
|
|
174
|
+
|
|
175
|
+
### Use it when
|
|
176
|
+
|
|
177
|
+
- You are in the Artifax/Tactix shell.
|
|
178
|
+
- The nav has **several labelled groups** the user should be able to collapse —
|
|
179
|
+
`StreamoidSidebar` has section labels but no accordion.
|
|
180
|
+
- You want the credit banner and assistant CTA wired by prop rather than by slot.
|
|
181
|
+
|
|
182
|
+
### Don't use it — reach for this instead
|
|
183
|
+
|
|
184
|
+
| Situation | Use instead |
|
|
185
|
+
|---|---|
|
|
186
|
+
| CXO / Photogenix / Catalogix sidebar | `StreamoidSidebar` |
|
|
187
|
+
| You need the built-in app-switch overlay + backdrop | `StreamoidSidebar` (`switchPanel` / `switchPanelOpen`) |
|
|
188
|
+
| You want a free-form nav body instead of `sections` | `StreamoidSidebar` (`showBody` + `bodyContent`) |
|
|
189
|
+
| One nav row | `ScSidebarMenu` |
|
|
190
|
+
| The product-switch list | `ScAppSwitchPanel` (portal it yourself here) |
|
|
191
|
+
| Artifax's invite/onboarding card | `ScArtifaxInvite` — unrelated component |
|
|
192
|
+
|
|
193
|
+
### Don't confuse with
|
|
194
|
+
|
|
195
|
+
| You may actually want | Not this |
|
|
196
|
+
|---|---|
|
|
197
|
+
| `StreamoidSidebar` — the shared shell; different prop names (`config`, `topItems`, `switchPanel`, `versionText`) | `ScArtifaxSidebar` is a **sibling**, not a wrapper |
|
|
198
|
+
| `ScCatalogixSidebar` — *is* a wrapper of `StreamoidSidebar` | This one is standalone |
|
|
199
|
+
| `ScArtifaxInvite` — the Artifax invite card | Nothing to do with navigation |
|
|
200
|
+
| `ScSidebar` — legacy shell | Superseded |
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 4. Why to use it
|
|
205
|
+
|
|
206
|
+
- **The accordion is already correct in both modes.** Controlled and uncontrolled,
|
|
207
|
+
`collapsible: false` headers that render but don't toggle, label-less sections that
|
|
208
|
+
are permanently open — three branches you'd otherwise re-derive.
|
|
209
|
+
- **Both rails are real designs, not a CSS `width` change.** The collapsed rail
|
|
210
|
+
drops labels and section headers, centres everything, and stacks avatar-over-toggle;
|
|
211
|
+
the expanded one puts the toggle inline in the profile row.
|
|
212
|
+
- **CSS-module scoped, token-only.** `--alias-surface-base`, `--alias-border-subtle`,
|
|
213
|
+
`--alias-fill-neutral-neutral` hovers, `--alias-text-and-icons-*` — light mode is free.
|
|
214
|
+
- **Real `<button>`s throughout.** Section headers, profile, toggle and the assistant
|
|
215
|
+
CTA are all native `<button type="button">`s — unlike `StreamoidSidebar`, whose
|
|
216
|
+
profile row and toggle are `div`s with `onClick`. (`aria-label` is set on the
|
|
217
|
+
footer toggle — `"Collapse sidebar"` / `"Expand sidebar"` — and on the collapsed
|
|
218
|
+
profile button; the section header and the expanded profile are labelled by their
|
|
219
|
+
own text.)
|
|
220
|
+
- **One assistant CTA implementation.** `assistantCta` renders the shared
|
|
221
|
+
`SC-AskAgentButton`, so the Artifax pill and the CXO/Catalogix pill cannot drift.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Gotchas
|
|
226
|
+
|
|
227
|
+
**1. Uncontrolled open-state is frozen at mount.** The internal map is built in a
|
|
228
|
+
`useState` initialiser from `defaultOpen ?? true`. A section added later has no key,
|
|
229
|
+
`!!internalOpen[id]` is `false`, and it renders **closed** — the classic
|
|
230
|
+
"sections load from the API and are all collapsed" bug.
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
// WRONG — sections arrive after mount, all render closed
|
|
234
|
+
<ScArtifaxSidebar sections={sectionsFromApi} … />
|
|
235
|
+
|
|
236
|
+
// RIGHT — either don't mount until loaded…
|
|
237
|
+
{sectionsFromApi.length ? <ScArtifaxSidebar sections={sectionsFromApi} … /> : <Skeleton />}
|
|
238
|
+
// …or drive it controlled
|
|
239
|
+
<ScArtifaxSidebar sections={sectionsFromApi} openSections={open} onSectionToggle={set} … />
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**2. `openSections={{}}` means "controlled, all closed".** The mode switch is
|
|
243
|
+
`isControlled = !!openSections`, and `{}` is truthy. Never pass an empty object as a
|
|
244
|
+
placeholder.
|
|
245
|
+
|
|
246
|
+
**3. A missing `iconMap` key renders a dashed circle.** `resolveIcon` falls back to
|
|
247
|
+
`ArtifaxPlaceholderIcon` (a 20px box with a 10px dashed-border `::before`). It looks
|
|
248
|
+
like a deliberate design, so typo'd `iconKey`s survive review.
|
|
249
|
+
|
|
250
|
+
**4. CSS overrides your toggle icon's size.** `.footerToggle > * { width: 1.5rem; height: 1.5rem }`
|
|
251
|
+
wins over an svg's `width`/`height` attributes. `<SiconCollapse size={16} />` still
|
|
252
|
+
renders 24px. Use a wrapper with an inline style if you truly need another size.
|
|
253
|
+
|
|
254
|
+
**5. `toggleIcon` doesn't rotate itself.** The default is a bare `<SiconCollapse />`
|
|
255
|
+
in both states. Artifax passes `(expanded) => <SiconCollapse className={expanded ? "" : "rotate-180"} />`.
|
|
256
|
+
|
|
257
|
+
**6. The scroll body clips popovers.** `.body` is `overflow-y: auto; overflow-x: hidden`.
|
|
258
|
+
Anything you open from the logo slot, a nav row or the profile row must be portalled
|
|
259
|
+
to `document.body` — which is exactly why the Artifax host renders `SwitchFlyout` and
|
|
260
|
+
`ProfileMenu` as portals.
|
|
261
|
+
|
|
262
|
+
**7. There is no app-switcher slot.** No `switchPanel`, no `switchPanelOpen`, no
|
|
263
|
+
backdrop. Clicking `ScSideBarLogoUnit` in the logo slot only calls your handler; you
|
|
264
|
+
own the panel, its position and its outside-click.
|
|
265
|
+
|
|
266
|
+
**8. Collapsed ignores `collapsible` / `label` / `defaultOpen` entirely.** Every
|
|
267
|
+
item of every section renders. A section the user collapsed reappears when they
|
|
268
|
+
collapse the rail.
|
|
269
|
+
|
|
270
|
+
**9. `creditWarning.onCollapsedClick` doesn't exist here.** The collapsed 40×40
|
|
271
|
+
square falls back to `onBuyCredits`, so collapsing the rail turns the banner into a
|
|
272
|
+
"go to billing" button. (`StreamoidSidebar` + `CreditWarningBanner` directly *do*
|
|
273
|
+
support `onCollapsedClick`.) The banner also dismisses itself permanently on ✕ with
|
|
274
|
+
no callback — see `CreditWarningBanner`'s own README.
|
|
275
|
+
|
|
276
|
+
**10. Hardcoded English.** `"Collapse sidebar"` / `"Expand sidebar"` aria-labels, and
|
|
277
|
+
section labels are force-uppercased via `text-transform` (so `label` should be
|
|
278
|
+
written in sentence case, not shouted).
|
|
279
|
+
|
|
280
|
+
**11. No logo default.** Omit `expandedLogo`/`collapsedLogo` and the slot simply
|
|
281
|
+
isn't rendered — no fallback wordmark.
|
|
282
|
+
|
|
283
|
+
**12. Widths are hardcoded** — `16rem` expanded, `3.5rem` collapsed, 48×48 collapsed
|
|
284
|
+
logo box, 32×32 avatar. Not overridable by props.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## In the wild
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
// artifax packages/shared/src/components/DashboardSidebar.tsx:641
|
|
292
|
+
<ScArtifaxSidebar
|
|
293
|
+
className={nav.rootClassName}
|
|
294
|
+
expanded={!collapsed}
|
|
295
|
+
onToggle={() => setCollapsed((v) => !v)}
|
|
296
|
+
sections={nav.sections}
|
|
297
|
+
iconMap={nav.iconMap}
|
|
298
|
+
activeItemId={activeItemId}
|
|
299
|
+
onItemSelect={handleItemSelect}
|
|
300
|
+
expandedLogo={
|
|
301
|
+
<div ref={expandedSwitchRef} className="flex w-full flex-col">
|
|
302
|
+
<ScSideBarLogoUnit state="expanded" wordmark={nav.wordmark} onClick={() => setAppListOpen((v) => !v)} switchAriaLabel="Switch product" />
|
|
303
|
+
</div>
|
|
304
|
+
}
|
|
305
|
+
collapsedLogo={
|
|
306
|
+
<div ref={collapsedLogoRef} className="flex w-full flex-col items-center">
|
|
307
|
+
<ScSideBarLogoUnit state="collapsed" wordmark={nav.mark} onClick={() => setAppListOpen((v) => !v)} switchAriaLabel="Switch product" />
|
|
308
|
+
</div>
|
|
309
|
+
}
|
|
310
|
+
creditWarning={creditWarning}
|
|
311
|
+
assistantCta={
|
|
312
|
+
onToggleAssistant
|
|
313
|
+
? { label: ASK_CXO_LABEL, icon: <SiconBolt className="h-5 w-5" />, active: assistantOpen, onClick: onToggleAssistant }
|
|
314
|
+
: undefined
|
|
315
|
+
}
|
|
316
|
+
profile={{ name: userName, subtitle: workspaceName, avatar: <ScDp type="initial" variant="profile" initial={userInitial} size={32} />, onClick: () => setProfileMenuOpen((v) => !v) }}
|
|
317
|
+
toggleIcon={(expanded) => <SiconCollapse className={expanded ? "" : "rotate-180"} />}
|
|
318
|
+
/>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Related
|
|
324
|
+
|
|
325
|
+
- `StreamoidSidebar` — the shell every other desktop app uses; has `switchPanel`, `bodyContent`, `versionText`.
|
|
326
|
+
- `ScSideBarLogoUnit` — what goes in the two logo slots.
|
|
327
|
+
- `ScAppSwitchPanel` — the product-switch list you must portal yourself here.
|
|
328
|
+
- `ScAskAgentButton` / `ScAskAgentSlot` — what `assistantCta` renders.
|
|
329
|
+
- `CreditWarningBanner` — what `creditWarning` renders (read its gotchas: self-dismiss, raw `remainingPct`).
|
|
330
|
+
- `ScSidebarMenu` — the nav row rendered per item.
|