KToolbar: slim public interface, drop Keen dep, refresh examples#1236
KToolbar: slim public interface, drop Keen dep, refresh examples#1236nucleogenesis wants to merge 14 commits into
Conversation
AlexVelezLl
left a comment
There was a problem hiding this comment.
Looks really solid! I've left some comments/questions, but nothing blocking!
| /> | ||
| </slot> | ||
| <!-- @slot Navigation icon area (typically a KIconButton). No content renders if the slot is empty. --> | ||
| <slot name="icon" /> |
There was a problem hiding this comment.
Now that we are here, could we replace the name of this prop? Perhaps we can pair this change with the actions slot too, and have something like left-actions/right-actions or leading-actions/trailing-actions? (I think I prefer the latter)
| @@ -119,89 +74,31 @@ | |||
| type: String, | |||
| default: '', | |||
| }, | |||
There was a problem hiding this comment.
I think we may also want to remove this prop? I don't see it being used anywhere. And we can just use the brand slot
There was a problem hiding this comment.
It'd be great if we could have the toolbar title already with truncation by default. We could change the title slot to be
<slot>
<div
v-if="title"
class="k-toolbar-title"
>
<KTextTruncator
v-if="title"
:text="title"
/>
</div>
</slotAnd we would need to set a min-width: 0 to the .k-toolbar-left class, and change .k-toolbar-title to only contain min-width: 0 (and no other style would be needed).
This would fix the need for a couple of PRs that have been around title truncation on KToolbar, where we have had to use deep styles to fix it.
There was a problem hiding this comment.
I wonder if an #extension slot would be useful for Kolibri and Studio? Just like vuetify. Both Kolibri and Studio use this concept of "extension", which is just another div below the navbar to show subnav elements. Currently, in Kolibri, we set the toolbar background to transparent, and a wrapper div is the one in charge of setting the color and background, but it would make sense to me if it were part of the toolbar component itself. And I don't think it would be too difficult, as it is just one slot. What do you think? @nucleogenesis @MisRob
There was a problem hiding this comment.
Currently, in Kolibri, we set the toolbar background to transparent, and a wrapper div is the one in charge of setting the color and background, but it would make sense to me if it were part of the toolbar component itself.
I think I don't follow, is there an example I could look at? The main purpose of the extension slot has something to do with colors, or is it more general space for placing sub-toolbar under the main toolbar?
There was a problem hiding this comment.
Ah, apologies @MisRob 😅. Yes, this happens, for example, with the AppBar component in Kolibri, where the main Kolibri toolbar (the entire yellow rectangle) isn't really rendered by KToolbar, but it is a wrapper div that sets the background color and shadows:
While the KToolbar component is just this div:

Appbar sets the toolbar to be transparent and without shadows, so that the parent div that also embraces that other div below the KToolbar component can have the same background. Code here. But IMO, the entire yellow rectangle is the toolbar, and KToolbar should also support this layout instead of doing these workarounds, just like Vuetify does, for example.
Benefits of doing this may include ensuring consistency across toolbars, better maintainability, because if we ever decide to change the shadows attributes for toolbars, we would only need to do it on KToolbar, and wouldn't have to recall that the main Kolibri toolbar isn't using the KToolbar shadow specs. And now we also need to do the same on Studio. And in general, having a better concept of "toolbar".
There was a problem hiding this comment.
Ah okay, thank you. Yes your suggestion makes much sense :)
We will just need to be careful around not enforcing <nav> markup, because e.g. in the case of main navigation, there will be two <nav>, each aria-labelled differently. So KToolbar would ideally not have opinions and let <nav>(s) be provided via slots. But I think that would need to apply in any case, due to many contexts we use KToolbar for?
There was a problem hiding this comment.
Yes, I agree, navs should be provided via slot. I think nav enforcement is perhaps the difference between a toolbar and an appbar?
| T6 (AC16). Visual test harness for KToolbar covering the five examples | ||
| landed in T4. Structure follows PR #1153's KToolbarVisualTest.vue, with |
There was a problem hiding this comment.
Not pretty sure what is T6, AC16 and T4 😅 . Do we need this comment?
| <!-- | ||
| Ported WHOLESALE from PR #1153 (examples/KToolbar/NavigationAndActions.vue | ||
| in that PR's diff). No changes — this example only exercises the | ||
| `#navigation` and `#actions` slots, both of which are retained in the | ||
| slimmed-down public interface. Demonstrates AC14: the slots are still the | ||
| primary extension point now that props for layout/styling are gone. | ||
| --> |
There was a problem hiding this comment.
I think it'd be great if we keep an example of using the appBar color, as it's the most common example used across the ecosystem.
Per PR learningequality#1236 review (AlexVelezLl r3130768684): preserve an appBar color example since it's the most common toolbar color across the Kolibri ecosystem. Splits the docs page "Overriding colors" section into two h3s — "Brand color" (AppBarColor.vue, $themeTokens.appBar) first since it's the common case, and "Inverted palette" (Inverted.vue, $themeTokens.appBarDark) for fullscreen modals / immersive bars. Renames the Inverted visual-test entry from "custom colors via :style" to "appBarDark via :style" so the two color-override rows name the token they demonstrate symmetrically.
…ctions Per PR learningequality#1236 review (AlexVelezLl r3130177502): pair the rename of the #icon slot with the #actions slot for symmetric leading/trailing-actions naming. Breaking change. - #icon → #leading-actions - #actions → #trailing-actions - .k-toolbar-nav-icon CSS class → .k-toolbar-leading-actions (matches Kolibri consumers' /deep/ selectors which need an accompanying migration anyway) #navigation and #brand slots are unchanged. Examples (Inverted, AppBarColor, NavigationAndActions) updated to the new slot names.
Per PR learningequality#1236 review (AlexVelezLl r3130658714): wrap the default title slot content in KTextTruncator so consumers no longer need /deep/ .k-toolbar-title workarounds for truncating long titles. Follows Alex's suggested implementation. - Default title slot content uses KTextTruncator (globally registered via KThemePlugin, no import needed). - .k-toolbar-left gets min-width: 0 so the left flex container can shrink below its intrinsic content size, enabling the title to truncate when space runs short. - .k-toolbar-title swaps overflow: hidden / white-space: nowrap (no longer needed — KTextTruncator handles truncation itself) for min-width: 0 plus line-height: 1. The line-height: 1 is needed because KTextTruncator's truncate class applies overflow: hidden to its inline-block span, which by CSS spec shifts that inline-block's baseline from the text baseline to the bottom margin edge. Inside .k-toolbar-title the resulting baseline-shifted inline-block ends up visually offset from the icon flex siblings; collapsing the line-box leading to 1em removes the gap that the offset lives in. Verified visually across short, long-wide, long-narrow, and brand-color toolbars in the playground; descenders fit comfortably within the 56px-tall .k-toolbar. Not a breaking change for consumers passing title="..." (same visible text, gains ellipsis on overflow). Consumers overriding the default slot are unaffected.
afa62da to
66f14c0
Compare
Relocate lib/KToolbar.vue to lib/KToolbar/index.vue ahead of cleanup work in the component. No behavior change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
KToolbar was the only consumer and no longer renders a progress bar (the `loading` + `progressPosition` props were removed). Nothing else imports this file. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ported from PR learningequality#1153 (commit 2188ef5). Exercises #brand, #navigation, #actions slots and the `raised` prop — all retained in the slimmed-down KToolbar public interface.
Replaces the old LightTheme.vue / DarkTheme.vue with two semantic examples: - Default.vue: bare toolbar using the component's default theme-token colors ($themeTokens.surface / $themeTokens.text) - Inverted.vue: canonical demo of overriding the defaults via native :style, replacing the removed textColor/backgroundColor props (full- screen modal / immersive bar palette) Also adds inline review comments to the three MisRob-authored examples ported in the previous commit, tying each to the PR learningequality#1153 discussions that motivated its inclusion. The theme-language rename follows the feedback in PR learningequality#1153 r2600351212 / r2627216880. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a Percy visual test harness covering the five KToolbar examples: Default, Inverted, NotRaised, NavigationAndActions, Brand. - lib/KToolbar/__tests__/visual.spec.js — boilerplate matching other components (KLogo, KBreadcrumbs, etc.) - lib/KToolbar/__tests__/components/KToolbarVisualTest.vue — harness structure ported from PR learningequality#1153 with the example list updated to match the slimmer set landed in T4 (5 examples vs. her 7). - jest.conf/visual.load-test-components.js — register the new harness alongside KBreadcrumbs / KButton. Co-Authored-By: MisRob <robosovam@gmail.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Updates the docs page to reference the five new example filenames (Default, Inverted, NavigationAndActions, Brand, NotRaised) and drops the "Light theme" / "Dark theme" section headings flagged as misleading in PR learningequality#1153. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per PR learningequality#1236 review (AlexVelezLl r3130768684): preserve an appBar color example since it's the most common toolbar color across the Kolibri ecosystem. Splits the docs page "Overriding colors" section into two h3s — "Brand color" (AppBarColor.vue, $themeTokens.appBar) first since it's the common case, and "Inverted palette" (Inverted.vue, $themeTokens.appBarDark) for fullscreen modals / immersive bars. Renames the Inverted visual-test entry from "custom colors via :style" to "appBarDark via :style" so the two color-override rows name the token they demonstrate symmetrically.
…ctions Per PR learningequality#1236 review (AlexVelezLl r3130177502): pair the rename of the #icon slot with the #actions slot for symmetric leading/trailing-actions naming. Breaking change. - #icon → #leading-actions - #actions → #trailing-actions - .k-toolbar-nav-icon CSS class → .k-toolbar-leading-actions (matches Kolibri consumers' /deep/ selectors which need an accompanying migration anyway) #navigation and #brand slots are unchanged. Examples (Inverted, AppBarColor, NavigationAndActions) updated to the new slot names.
Per PR learningequality#1236 review (AlexVelezLl r3130658714): wrap the default title slot content in KTextTruncator so consumers no longer need /deep/ .k-toolbar-title workarounds for truncating long titles. Follows Alex's suggested implementation. - Default title slot content uses KTextTruncator (globally registered via KThemePlugin, no import needed). - .k-toolbar-left gets min-width: 0 so the left flex container can shrink below its intrinsic content size, enabling the title to truncate when space runs short. - .k-toolbar-title swaps overflow: hidden / white-space: nowrap (no longer needed — KTextTruncator handles truncation itself) for min-width: 0 plus line-height: 1. The line-height: 1 is needed because KTextTruncator's truncate class applies overflow: hidden to its inline-block span, which by CSS spec shifts that inline-block's baseline from the text baseline to the bottom margin edge. Inside .k-toolbar-title the resulting baseline-shifted inline-block ends up visually offset from the icon flex siblings; collapsing the line-box leading to 1em removes the gap that the offset lives in. Verified visually across short, long-wide, long-narrow, and brand-color toolbars in the playground; descenders fit comfortably within the 56px-tall .k-toolbar. Not a breaking change for consumers passing title="..." (same visible text, gains ellipsis on overflow). Consumers overriding the default slot are unaffected.
66f14c0 to
a0c8f7c
Compare
Per PR learningequality#1236 review (AlexVelezLl r3130750618): add a Vuetify-style #extension slot that renders below the main toolbar row but inside the same visual surface (shares background and shadow). Intended for tabs, sub-navigation, and breadcrumbs that conceptually belong to the toolbar rather than the page below it. Structural change: the existing flex row that was `.k-toolbar` is now wrapped in a `.k-toolbar-main` div, with `.k-toolbar-extension` rendered as a sibling below when the slot has content. The outer `.k-toolbar` keeps only the surface-level rules (position, font, is-raised shadow); row layout (flex, height, padding) moved onto `.k-toolbar-main`. Existing consumers without an `#extension` slot render visually identically — purely additive, not a breaking change. `.k-toolbar-extension` defaults to flex + align-items: center + min-height: 3rem (matching Vuetify's 48px default) + padding: 0 16px to mirror the main row's horizontal padding. Consumers wanting edge-to-edge content (e.g. tab strips) can use negative margins on their slot content. Adds an Extension.vue example demoing the typical Kolibri AppBar layout (appBar background + leading menu icon + sub-nav router links in the extension), registers it in the visual test harness and the docs page.
Per PR learningequality#1236 review (AlexVelezLl r3130750618): add a Vuetify-style #extension slot that renders below the main toolbar row but inside the same visual surface (shares background and shadow). Intended for tabs, sub-navigation, and breadcrumbs that conceptually belong to the toolbar rather than the page below it. Structural change: the existing flex row that was `.k-toolbar` is now wrapped in a `.k-toolbar-main` div, with `.k-toolbar-extension` rendered as a sibling below when the slot has content. The outer `.k-toolbar` keeps only the surface-level rules (position, font, is-raised shadow); row layout (flex, height, padding) moved onto `.k-toolbar-main`. Existing consumers without an `#extension` slot render visually identically — purely additive, not a breaking change. `.k-toolbar-extension` defaults to flex + align-items: center + min-height: 3rem (matching Vuetify's 48px default) + padding: 0 16px to mirror the main row's horizontal padding. Consumers wanting edge-to-edge content (e.g. tab strips) can use negative margins on their slot content. Adds an Extension.vue example demoing the typical Kolibri AppBar layout (appBar background + leading menu icon + sub-nav router links in the extension), registers it in the visual test harness and the docs page.
3b0c673 to
b3ccfd9
Compare
|
@AlexVelezLl @MisRob I have applied the #extension slot and addressed other feedback given, adding the brand example and tweaking the styles on the docs in a slightly opinionated way (open to feedback, mostly just colors of things on the toolbar examples). One place that I've come to as I do regression testing/fixing on Kolibri is that the KToolbar currently has opinionated paddings and margins that require Shall I slim that stuff down too while I'm at it? Basically, the slots will just be unpadded empty boxes for you to put your stuff in and pad/margin yourself to your heart's content. This was Claude's assessment of the styles and their opinionated-ness and I agree with the assessment except on one point.
The min-height on the extensions is said to be default Material height but I'm dubious of using it here. I'll be updating learningequality/kolibri#14618 with screenshots confirming that the updates work well there. Also just noting that I realize the #extensions slot is a bit extending the scope here, but I'm also happy to take this PR as a chance to put some real polish on KToolbar if y'all think it'd be a worthwhile endeavour. |
|
Thanks @nucleogenesis.
Yes I think that'd be best. Thanks for raising it. We were just discussing it in another context. Generally I think that design system components shouldn't be opinionated in terms of using space around them (such as outer margins), as well as handling spacing within slots.
Yes, thank you & I am happy to let you two decide what's the appropriate scope for this PR, depending on your bandwidth for this work and release schedule. Already lots of good work here :) |
Removes the CSS rules that imposed Material-Design-style spacing on
KToolbar's internal slot wrappers — the same opinions that consumers
were previously forced to fight via /deep/ overrides. Slot composition
is still functional (flex layout, truncation chain stays intact); the
spacing decisions move to consumer slot content.
Removed rules:
- .k-toolbar-left { margin-left: 16px }
- .k-toolbar-leading-actions { margin-right: 8px; margin-left: -16px }
(existed only to counteract the dropped left margin)
- .k-toolbar-nav { display: flex; align-items: baseline;
margin-right: 8px; margin-left: 16px }
- .k-toolbar-right { display: inline-block }
- .k-toolbar-main { align-content: center }
(no-op for single-line flex)
Kept (functional):
- .k-toolbar-main flex/center/space-between/height/padding
- .k-toolbar-extension flex/center/min-height/padding
- .k-toolbar-left flex/center/min-width:0 (truncation chain)
- .k-toolbar-brand min-width: inherit (truncation chain)
- .k-toolbar-title min-width: 0; line-height: 1 (KTextTruncator alignment)
Visual impact on consumers using KToolbar today: the leading icon /
brand area / title / nav / trailing actions sit ~16-24px further left
than before (no longer pushed inward by the dropped margins). Native
KToolbar consumers in KDS' own examples render fine; the
NavigationAndActions example needed a small slot-local margin tweak on
its KRouterLinks (margin-right: 16px → margin: 0 8px) so the nav links
have breathing room from the title.
Downstream consumers (e.g. Kolibri's AppBar / ImmersiveToolbar /
LearningActivityBar) that were using /deep/ .k-toolbar-* selectors to
override these defaults can now drop those overrides outright — KDS
no longer has the opinions to fight.
Percy Visual Test ResultsPercy Dashboard: View Detailed Report Environment:
Instructions for Reviewers:
|
AlexVelezLl
left a comment
There was a problem hiding this comment.
Code changes look good to me! Just one little question, and not approving just yet as I'm not sure if you plan to make further changes, but everything looks good to me at this point!
| .k-toolbar-extension { | ||
| display: flex; | ||
| align-items: center; | ||
| min-height: 3rem; |
There was a problem hiding this comment.
Is this a value we should enforce from KDS?
There was a problem hiding this comment.
nope 😅 will push some updates today
Description
Slims
KToolbar's public interface, drops the last direct Keen dependency (UiProgressLinear), renames the icon/actions slots to#leading-actions/#trailing-actions, bakes title truncation into the default title slot, adds a Vuetify-style#extensionslot for sub-toolbar content, and refreshes the example set with semantic names aligned to the new interface. Implements the PR #1153 cleanup with the breaking changes that PR deferred, plus thebrandprop removal, slot rename, built-in truncation, and#extensionslot addition requested in this round of review (Alex r3130185513 / r3130177502 / r3130658714 / r3130750618).Issue addressed
Addresses #1183
Before/after screenshots
/ktoolbardocs page on the Netlify deploy preview — covers all seven examples (Default, Brand color, Inverted palette, Navigation and actions, Brand, Not raised, Extension) plus the updated Props and Slots tables (Props now lists onlytitleandraised; Slots listsleading-actions,brand,default,navigation,trailing-actions,extension):Title truncation demo — captured from the local playground at five widths to verify behavior across the truncation envelope (short title untouched, long title in wide containers, long title in narrow containers, narrow + brand-color combination):
Changelog
Description: Slims
KToolbar's public interface and drops its last direct Keen dependency. Removes the propstype,textColor,navIcon,removeNavIcon,progressPosition,loading, andbrand; removes thenav-icon-clickevent; renames the#iconslot to#leading-actionsand the#actionsslot to#trailing-actions; removes the default#iconslot fallback. Renames the internal.k-toolbar-nav-iconCSS class to.k-toolbar-leading-actionsto match the slot. Deletes the now-unusedlib/keen/UiProgressLinear.vue. Default bg/text now come from$themeTokens.surface/$themeTokens.textand are overridable via native:style.raisedis the only styling prop that remains.Products impact: removed API
Addresses: Complete KToolbar public interface, make it fully themeable, and cleanup obsolete Keen code #1183
Components:
KToolbarBreaking: yes
Impacts a11y: no
Guidance: Migrate per the mapping below:
type="default"→ remove (now implicit)type="colored"→:style="{ backgroundColor: <theme token> }"type="clear"→ remove (use:style="{ backgroundColor: 'transparent' }"if needed;:raised="false"drops the shadow)textColor="black|white|…"→:style="{ color: <value> }"navIcon="…"/removeNavIcon→ pass your ownKIconButton(or similar) inside the#leading-actionsslot; omit slot content to hide the leading-actions area entirely@nav-icon-click→ attach@clickto the element you put inside the#leading-actionsslotprogressPosition/loading→ use a separateKLinearLoaderabove or below the toolbarbrand="…"prop →<template #brand>…</template>slot<template #icon>…</template>→<template #leading-actions>…</template><template #actions>…</template>→<template #trailing-actions>…</template>/deep/ .k-toolbar-nav-icon→ update the selector to.k-toolbar-leading-actions(Kolibri'sImmersiveToolbar.vueandLearningActivityBar.vueboth do this and need coordinated updates in the companion branch)type="default" :raised="false"is gone; nothing in the Kolibri codebase depended on it. If you need it, add it yourself via:style.lib/keen/UiProgressLinear.vueis removed; no LE consumer imports it directly, but any downstream code that does will need to drop the reference.Description: The default title slot now wraps the
titleprop inKTextTruncator, so long titles ellipsis-truncate automatically when space runs short..k-toolbar-leftand.k-toolbar-titlegotmin-width: 0to let the flex chain shrink, and.k-toolbar-titleisline-height: 1to keep the truncated text vertically centered with the leading/trailing icons.Products impact: behavior change
Addresses: Complete KToolbar public interface, make it fully themeable, and cleanup obsolete Keen code #1183
Components:
KToolbarBreaking: no
Impacts a11y: no
Guidance: Consumers passing
title="…"see the same visible text and gain ellipsis-on-overflow for free. Consumers overriding the default slot are unaffected. Anyone using/deep/ .k-toolbar-title { … }workarounds for title truncation can drop those overrides.Description: Adds a Vuetify-style
#extensionslot toKToolbarthat renders below the main row but inside the same visual surface (shares background and shadow). Intended for tabs, sub-navigation, and breadcrumbs that conceptually belong to the toolbar rather than the page below it. Internally restructures the template so the existing flex row lives inside a new.k-toolbar-maindiv; the outer.k-toolbarkeeps only surface-level rules (position, font,is-raisedshadow). The.k-toolbar-extensiondefaults todisplay: flex; align-items: center; min-height: 3rem; padding: 0 16px(matching Vuetify's 48px extension default and mirroring the main row's horizontal padding).Products impact: new API
Addresses: Complete KToolbar public interface, make it fully themeable, and cleanup obsolete Keen code #1183
Components:
KToolbarBreaking: no
Impacts a11y: no
Guidance: Purely additive — existing consumers without an
#extensionslot render visually identically. Consumers (notably Kolibri'sAppBar) that currently wrapKToolbarin a parent div to provide a colored sub-nav strip below can move that strip into the#extensionslot, set the toolbar's:stylecolor directly, and drop the wrapper div. Edge-to-edge content (e.g. tab strips with bottom borders) can use negative horizontal margins on the slot content to override the default 16px padding.Description: Rewrites the
KToolbardocumentation page and example set. Old "Light theme" / "Dark theme" examples replaced by seven semantic examples (Default,AppBarColor,Inverted,NavigationAndActions,Brand,NotRaised,Extension). The "Overriding colors" docs section is split into a "Brand color" demo (most common Kolibri pattern,$themeTokens.appBar) and an "Inverted palette" demo (immersive bars,$themeTokens.appBarDark). Adds a Percy visual test harness covering all examples.Products impact: documentation
Addresses: Complete KToolbar public interface, make it fully themeable, and cleanup obsolete Keen code #1183
Components:
KToolbarBreaking: no
Impacts a11y: no
Guidance: -
Steps to test
/ktoolbarpage.$themeTokens.appBar), Inverted palette, Navigation and actions, Brand, Not raised, Extension (sub-toolbar).Extensionexample renders the sub-nav row directly below the main toolbar row inside the same yellow surface (shared background + shadow).KToolbarvisual snapshot.CHANGELOG.mdon merge).Testing checklist
KToolbarPercy visual test harness covers the example statesdocs/pages/ktoolbar.vueupdated to wire the new example filenames and drop "Light theme" / "Dark theme" languageReviewer guidance
Specific areas worth a second look:
Default colors +
:styleoverride behavior —lib/KToolbar/index.vue:78-79.toolbarStylesreturns$themeTokens.surface/$themeTokens.text. The override path relies on Vue 2 merging a consumer's:styleonto the root element with consumer values winning on key conflicts. Worth a visual confirmation on the deploy preview: the Inverted and Brand color examples should fully replace the defaults, not blend with them.Slot rename and CSS class follow-through —
lib/KToolbar/index.vue:14, 46, 115. Slots#icon/#actionsrenamed to#leading-actions/#trailing-actions(Alex r3130177502). Internal CSS class.k-toolbar-nav-iconrenamed to.k-toolbar-leading-actionsto keep slot/class naming consistent. The Kolibri companion branch needs paired updates because it uses/deep/selectors against the old class name inImmersiveToolbar.vueandLearningActivityBar.vue.brandprop removal —lib/KToolbar/index.vue:17-23. Verified no LE consumer passesbrand=(Kolibri companion grep). The slot was always the right surface for this; the prop fallback was vestigial.#leading-actionsslot visibility change —lib/KToolbar/index.vue:9-15. Now driven entirely by slot presence (v-if="$slots['leading-actions']"); the defaultUiIconButtonfallback is gone. Audit across LE showed no consumer relied on the fallback, but flag anything we missed.Built-in title truncation +
line-height: 1—lib/KToolbar/index.vue:31, 111, 135-136. Default title slot wrapstitleinKTextTruncator(Alex r3130658714)..k-toolbar-leftand.k-toolbar-titlegetmin-width: 0so the flex chain can shrink;.k-toolbar-titleisline-height: 1to compensate forKTextTruncator'soverflow: hiddenshifting its inline-block baseline to the bottom margin edge (CSS spec behavior). Without the line-height tweak the title sits visually higher than the icon flex siblings. Verified across short / long-wide / long-narrow / brand-color cases on the playground.#extensionslot + template restructure —lib/KToolbar/index.vue:8, 51-57, 101-126. The existing flex row is now wrapped in a new.k-toolbar-maindiv; the outer.k-toolbarkeeps only surface-level rules (position, font,is-raisedshadow)..k-toolbar-extensionis rendered as a sibling below when the slot has content. Visually identical for consumers that don't use#extension(the extra wrapper div is layout-neutral). Worth eyeballing the deploy preview'sExtensionexample to confirm the sub-nav row sits flush below the main row inside the same surface (shared background + shadow), with no visible seam between them.Removed "flat with bottom border" combination —
lib/KToolbar/index.vuescss.raised=falsenow emits no shadow AND no border (previouslytype="default" + raised=falseproduced a bottom border). Kolibri'sAppBarpairsraised=falsewithtype="clear"specifically to avoid that border, so it's safe there — but the companion Kolibri PR will need to visually confirm.Commit authorship — one commit (
Add KToolbar examples for brand, navigation/actions, and not-raised) is authored by MisRob since those three example files port verbatim from PR Make KToolbar themeable, fix textColor validator check error in Kolibri, and remove obsolete Keen code #1153. Everything else is new work here.Comments
A Kolibri companion branch (
kds-ktoolbar-companion-fixes) is waiting in the adjacent worktree for the downstream migrations enumerated in the Guidance section. The migration scope grew during this review round — it now also covers the slot rename (#icon/#actions→#leading-actions/#trailing-actions) and the matching/deep/ .k-toolbar-nav-iconselector updates inImmersiveToolbar.vueandLearningActivityBar.vue, in addition to the original consumer migrations (AppBar,ImmersiveToolbar,LearningActivityBar,ContentModal). Will open as a linked PR once this one is ready for review.#extensionslot — Kolibri-side migration scopeA subagent audit of the Kolibri companion worktree turned up:
AppBar.vueis the only consumer with the wrapper-div + transparent-KToolbar+ sub-nav-below pattern.ImmersiveToolbar,LearningActivityBar, andContentModalare standalone and don't have sub-nav stacked below.AppBar.vuedual-renders itsNavbar— once insideKToolbar's#navigationslot (when it fits) and once in a siblingsubpage-navdiv below (when it overflows). The@update-overflow-countevent fromNavbardrives the responsive switch. Migrating to#extensioncan't preserve the dual-render shape as-is; the overflow logic needs a redesign in the Kolibri PR (likely: render unconditionally in#extensionand use CSS media queries to swap visibility, or push overflow detection intoKToolbaritself). Doesn't block this PR — the slot is purely additive — but flagging it as the work that follows.AppBarPage'sappBarHeightDOM measurement still works after the migration;ScrollingHeader's hard-codedtranslateY(-200px)could break if extension content makes the toolbar tall (already commented in-source as "200px is arbitrary");/deep/ .sub-nav .itemsmargin reset will need to relocate into theNavbarcomponent or use a slot-scoped selector.AI usage
Used Claude Code to aggregate relevant comments and gather understanding, draft and review commits, and compose this PR body. Verified changes locally throughout, including a playground-driven visual sweep of the title-truncation alignment fix.