@scalio-cloud/ui 0.18.0 → 0.18.1

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/CHANGELOG.md CHANGED
@@ -1,16 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.18.1
4
+ Page actions after Markus' feedback (2026-10-31, UISPEC section 2 "Page actions"). 0.18.0 was released before these
5
+ changes were merged; apps use 0.18.1.
6
+ - The slot is shown only when a page has actions and pushes the menu down; no reserved room, no separator line.
7
+ - 0.25rem above the buttons, 0.875rem from the last button to the next section heading (half the usual gap).
8
+ - Only Übersicht (first item of a first section without heading) is pinned; further items of that section stay in
9
+ the menu (Pulse: Geräte).
10
+ - Buttons in the slot: same height (2.25rem), one line, long labels end with "…". Labels without "Neu" (README).
11
+ - **Visible change:** only in apps that set `pageActions`. No token changes.
12
+
3
13
  ## 0.18.0
4
- Page actions in the sidebar (Markus 2026-10-31, reference Scalio Kontor; scalio-docs ADR 0042 Nachtrag).
14
+ Page actions in the sidebar, first version (Markus 2026-10-31, reference Scalio Kontor; scalio-docs ADR 0042 Nachtrag).
5
15
  - New `react/actions.js`: `PageActions` puts a page's actions (Neu …, Import, Zurück) into a fixed slot in the
6
- sidebar right below Übersicht from 768px; on phones they stay in the page header. `ActionSlot` for apps with their
7
- own sidebar, `useDesktop()` (768px, same as the sidebar).
8
- - `Sidebar` gets `pageActions`: Übersicht (first section without heading) is pinned on top, then the slot, then the
9
- other sections. The slot keeps room for two buttons when empty, so the menu never moves. Not in the phone drawer.
10
- - CSS (`nav.css`): `.scalio-sidebar-pinned`, `.scalio-action-slot`, `.scalio-side-actions` (buttons stacked, full
11
- width). `shell.css`: an empty `.scalio-page-actions` is hidden.
12
- - `react-dom` is an optional peer dependency (for the portal; every app has it).
13
- - **Visible change:** none until an app sets `pageActions` and wraps its actions in `PageActions`. No token changes.
16
+ sidebar right below Übersicht from 768px; on phones they stay in the page header. `ActionSlot`, `useDesktop()`.
17
+ - `Sidebar` gets `pageActions`: Übersicht pinned on top, then the slot (room for two buttons, line below), then the
18
+ sections. `shell.css`: an empty `.scalio-page-actions` is hidden. `react-dom` is an optional peer dependency.
19
+ - **Visible change:** none until an app sets `pageActions`. No token changes.
14
20
 
15
21
  ## 0.17.0
16
22
  Scalio Pulse is built (scalio-docs ADR 0043, P1 started 2026-10-31).
package/README.md CHANGED
@@ -130,16 +130,17 @@ on top. An app with two work areas (Nexus Identity and HR) puts `<WorkspaceSwitc
130
130
  into the sidebar's `top`.
131
131
 
132
132
  **Page actions in the sidebar** (from 0.18.0, UISPEC section 2): `<Sidebar pageActions ... />` keeps Übersicht (the
133
- first section without a heading) on top and adds a fixed slot right below it. A page wraps its actions in
134
- `<PageActions>`; from 768px they move into the slot, on phones they stay in the page header. The slot keeps room for
135
- two buttons even when a page has none, so the menu never moves.
133
+ first item of a first section without heading) on top and adds a slot right below it. A page wraps its actions in
134
+ `<PageActions>`; from 768px they move into the slot, on phones they stay in the page header. The slot takes no
135
+ room on pages without actions; with actions it pushes the menu down.
136
136
 
137
137
  ```jsx
138
- <PageHeader title="Kontakte" actions={<PageActions><Button onClick={add}><Plus /> Neuer Kontakt</Button></PageActions>} />
138
+ <PageHeader title="Kontakte" actions={<PageActions><Button onClick={add}><Plus /> Kontakt</Button></PageActions>} />
139
139
  <PageHeader title={doc.number} actions={<PageActions><Button variant="outline" asChild><Link to="/invoices"><ArrowLeft /> Zurück</Link></Button></PageActions>} />
140
140
  ```
141
141
 
142
142
  Only actions that start something or lead away go there (Neu …, Import, Scannen, Zurück), at most two per page.
143
+ Labels without "Neu"/"New": the + icon says it ("+ Kontakt", not "+ Neuer Kontakt").
143
144
  Filters, search, tabs and Speichern stay on the page. Apps with their own sidebar place `<ActionSlot />` themselves.
144
145
 
145
146
  ## Settings page (React)
package/nav.css CHANGED
@@ -17,16 +17,23 @@
17
17
  .scalio-sidebar-top { padding: 0.75rem 0.75rem 0; }
18
18
  .scalio-sidebar-scroll { flex: 1 1 auto; overflow-y: auto; padding: 0.5rem 0 0.75rem; }
19
19
  .scalio-nav-section + .scalio-nav-section { margin-top: 0.25rem; }
20
- /* Page actions (react/actions.js): Übersicht stays on top, then a fixed slot for the page's actions. The slot
21
- keeps room for two buttons even when empty, so the menu below never moves. */
20
+ /* Page actions (react/actions.js): Übersicht stays on top, then the slot for the page's actions. The slot takes no
21
+ room when a page has no actions; with actions it shows them and pushes the menu down. No separator line. */
22
22
  .scalio-sidebar-pinned { flex-shrink: 0; padding-top: 0.5rem; }
23
- .scalio-action-slot {
24
- flex-shrink: 0; box-sizing: border-box; min-height: 6.25rem; margin: 0 0.75rem; padding: 0.5rem 0 0.75rem;
25
- border-bottom: 1px solid hsl(var(--border));
26
- }
23
+ .scalio-action-slot { flex-shrink: 0; margin: 0 0.75rem; }
27
24
  .scalio-sidebar-scroll.has-action-slot { padding-top: 0; }
28
- .scalio-side-actions, .scalio-side-actions > div { display: flex; flex-direction: column; align-items: stretch; gap: 0.5rem; }
29
- .scalio-side-actions > :not(div), .scalio-side-actions > div > * { width: 100%; justify-content: center; }
25
+ .scalio-side-actions, .scalio-side-actions > div { display: flex; flex-direction: column; align-items: stretch; gap: 0.375rem; }
26
+ .scalio-side-actions { padding-top: 0.25rem; }
27
+ /* Below the buttons: half the usual space before the next heading (0.875rem instead of 1.75rem), a little room
28
+ before a plain menu item. */
29
+ .scalio-action-slot:has(.scalio-side-actions:not(:empty)) + .scalio-sidebar-scroll > .scalio-nav-section:first-child > .scalio-nav-heading { padding-top: 0.875rem; }
30
+ .scalio-action-slot:has(.scalio-side-actions:not(:empty)) + .scalio-sidebar-scroll > .scalio-nav-section:first-child:not(:has(> .scalio-nav-heading)) { padding-top: 0.375rem; }
31
+ .scalio-side-actions:empty { display: none; }
32
+ /* Same height for every button (2.25rem), one line; a long label is cut with "…". */
33
+ .scalio-side-actions > :not(div), .scalio-side-actions > div > * {
34
+ box-sizing: border-box; width: 100%; height: 2.25rem; min-height: 0; margin: 0; justify-content: center;
35
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
36
+ }
30
37
  .scalio-side-actions input[type="file"], .scalio-side-actions [hidden] { display: none; }
31
38
  .scalio-nav-heading {
32
39
  padding: 1.25rem 1.25rem 0.5rem; font-size: 11px; font-weight: 700; text-transform: uppercase;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalio-cloud/ui",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "Scalio Control Room design tokens, Tailwind preset, self-hosted fonts, the shared app header, sign-in layout, sidebar and page blocks",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "private": false,
package/react/actions.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // Page actions in the sidebar (UISPEC section 2, "Seitenaktionen", from 0.18.0). Buttons such as "Neu ...",
3
- // "Import" or "Zurück" sit in a fixed slot right below Übersicht, close to the navigation, instead of far
4
- // right in the page header. The slot keeps its height when a page has no actions, so the menu never moves.
3
+ // "Import" or "Zurück" sit right below Übersicht, close to the navigation, instead of far right in the page
4
+ // header. The slot takes no room when a page has no actions; with actions it pushes the menu down.
5
5
  // Phones have no sidebar: there the actions stay in the page header.
6
6
  //
7
7
  // The app turns the slot on with <Sidebar pageActions />; a page wraps its actions in <PageActions>.
package/react/nav.js CHANGED
@@ -102,8 +102,8 @@ function SearchButton({ search, lang, labels, testIdPrefix, onNavigate }) {
102
102
 
103
103
  // Sidebar. variant "desktop" shows from 768px, "drawer" is the same content inside NavDrawer.
104
104
  // link: the router's NavLink (gets to, end, className(fn), onClick); without it plain <a> + activePath.
105
- // pageActions: a fixed slot for the page's actions (react/actions.js) right below Übersicht, desktop only.
106
- // Übersicht (the first section when it has no heading) then stays on top and does not scroll.
105
+ // pageActions: a slot for the page's actions (react/actions.js) right below Übersicht, desktop only.
106
+ // Übersicht (first item of the first section when it has no heading) then stays on top and does not scroll.
107
107
  function Sidebar(props) {
108
108
  const {
109
109
  nav, link, activePath, top, search, primaryAction, footer, version, commit, lang, labels,
@@ -113,8 +113,10 @@ function Sidebar(props) {
113
113
  const L = labelsFor(lang, labels);
114
114
  const sections = visibleSections(nav);
115
115
  const slot = !!pageActions && variant !== "drawer";
116
- const pinned = slot && sections.length && !sections[0].label ? sections[0] : null;
117
- const rest = pinned ? sections.slice(1) : sections;
116
+ // Only Übersicht (first item of a first section without heading) is pinned; the rest of that section scrolls.
117
+ const first = sections[0];
118
+ const pinned = slot && first && !first.label ? Object.assign({}, first, { items: first.items.slice(0, 1) }) : null;
119
+ const rest = !pinned ? sections : first.items.length > 1 ? [Object.assign({}, first, { items: first.items.slice(1) })].concat(sections.slice(1)) : sections.slice(1);
118
120
  const section = (sec, i) =>
119
121
  h(
120
122
  "div",