From 5efd806e439e87e0084de26b9f9f3012614209dd Mon Sep 17 00:00:00 2001
From: "smx.pusha" <139338836+smxpusha@users.noreply.github.com>
Date: Thu, 20 Aug 2026 11:02:44 +0200
Subject: [PATCH] ENH - refine notes header and compose controls
---
frontend/src/ui/controls.css | 17 +++++++++++
frontend/src/ui/controls/SkyFab.test.ts | 29 +++++++++++++++++++
frontend/src/ui/controls/SkyFab.vue | 3 +-
.../views/apps/NotesApp.menu.contract.test.ts | 23 ++++++++++++---
frontend/src/views/apps/NotesApp.vue | 15 ++++++++--
5 files changed, 80 insertions(+), 7 deletions(-)
diff --git a/frontend/src/ui/controls.css b/frontend/src/ui/controls.css
index 26e0b55..af8e65b 100644
--- a/frontend/src/ui/controls.css
+++ b/frontend/src/ui/controls.css
@@ -2733,6 +2733,9 @@ label.sky-list-item__row {
.sky-fab--icon-only {
width: var(--sky-touch-target, 44px);
+ height: var(--sky-touch-target, 44px);
+ flex: none;
+ align-self: center;
padding: 0;
}
@@ -2741,6 +2744,16 @@ label.sky-list-item__row {
color: var(--sky-text, #000000);
}
+.sky-glass.sky-fab--glass {
+ border: 1px solid var(--sky-hairline, rgba(0, 0, 0, 0.2));
+ background: var(--sky-glass, rgba(255, 255, 255, 0.75));
+ color: var(--sky-text, #000000);
+ box-shadow: var(--sky-shadow-glass);
+}
+
+.sky-fab--glass .sky-fab__accent-layer,
+.sky-fab--glass .sky-fab__dark-accent-layer,
+.sky-fab--glass .sky-fab__surface-layer,
.sky-fab--neutral .sky-fab__accent-layer,
.sky-fab--neutral .sky-fab__dark-accent-layer,
.sky-fab--neutral .sky-fab__surface-layer {
@@ -2755,6 +2768,10 @@ label.sky-list-item__row {
background: var(--sky-glass-solid, rgba(247, 247, 248, 0.96));
}
+.sky-glass.sky-fab--glass:active:not(:disabled) {
+ background: var(--sky-glass, rgba(255, 255, 255, 0.75));
+}
+
.sky-fab--disabled {
cursor: default;
opacity: 0.42;
diff --git a/frontend/src/ui/controls/SkyFab.test.ts b/frontend/src/ui/controls/SkyFab.test.ts
index cc6bf7d..02e47ea 100644
--- a/frontend/src/ui/controls/SkyFab.test.ts
+++ b/frontend/src/ui/controls/SkyFab.test.ts
@@ -73,4 +73,33 @@ describe('SkyFab', () => {
/\.sky-glass\.sky-fab--neutral\s*\{[^}]*background:\s*var\(--sky-glass-solid/s,
)
})
+
+ it('offers a translucent glass variant for adjacent floating controls', async () => {
+ const html = await renderToString(
+ createSSRApp({
+ render: () => h(SkyFab, { ariaLabel: 'Create', variant: 'glass' }),
+ }),
+ )
+
+ expect(html).toContain('sky-fab--glass')
+
+ const controls = readFileSync(
+ fileURLToPath(new URL('../controls.css', import.meta.url)),
+ 'utf8',
+ )
+ expect(controls).toMatch(
+ /\.sky-glass\.sky-fab--glass\s*\{[^}]*border:\s*1px solid var\(--sky-hairline[^}]*background:\s*var\(--sky-glass[^}]*box-shadow:\s*var\(--sky-shadow-glass\)/s,
+ )
+ })
+
+ it('keeps icon-only fabs perfectly square inside stretching toolbars', () => {
+ const controls = readFileSync(
+ fileURLToPath(new URL('../controls.css', import.meta.url)),
+ 'utf8',
+ )
+
+ expect(controls).toMatch(
+ /\.sky-fab--icon-only\s*\{[^}]*width:\s*var\(--sky-touch-target, 44px\);[^}]*height:\s*var\(--sky-touch-target, 44px\);[^}]*flex:\s*none;[^}]*align-self:\s*center;/s,
+ )
+ })
})
diff --git a/frontend/src/ui/controls/SkyFab.vue b/frontend/src/ui/controls/SkyFab.vue
index 131b901..530cce7 100644
--- a/frontend/src/ui/controls/SkyFab.vue
+++ b/frontend/src/ui/controls/SkyFab.vue
@@ -14,7 +14,7 @@ const props = withDefaults(
text?: string
textPosition?: 'after' | 'before'
type?: 'button' | 'reset' | 'submit'
- variant?: 'neutral' | 'primary'
+ variant?: 'glass' | 'neutral' | 'primary'
}>(),
{
ariaLabel: '',
@@ -72,6 +72,7 @@ function handleClick(event: MouseEvent): void {
class="sky-fab"
:class="{
'sky-fab--disabled': disabled,
+ 'sky-fab--glass': variant === 'glass',
'sky-fab--icon-only': !hasText,
'sky-fab--neutral': variant === 'neutral',
'sky-fab--with-text': hasText,
diff --git a/frontend/src/views/apps/NotesApp.menu.contract.test.ts b/frontend/src/views/apps/NotesApp.menu.contract.test.ts
index 381d47e..04f62ef 100644
--- a/frontend/src/views/apps/NotesApp.menu.contract.test.ts
+++ b/frontend/src/views/apps/NotesApp.menu.contract.test.ts
@@ -10,10 +10,11 @@ const menuSource = source.slice(
source.indexOf('') + ''.length,
)
-const listStart = source.search(
- / {
it('places the Sky searchbar and create action together at the bottom', () => {
@@ -27,7 +28,7 @@ describe('NotesApp list controls', () => {
expect(composerSource).toContain(' {
})
})
+describe('NotesApp headers', () => {
+ it('keeps list and editor headers at the shared app height', () => {
+ expect(source).toContain('class="notes-list-navbar"')
+ expect(source).toContain(
+ '.notes-list-navbar.sky-navbar--large.sky-navbar--no-navigation',
+ )
+ expect(source).toContain(
+ 'padding-top: calc(var(--sky-navbar-safe-area-top) + var(--sky-space-3))',
+ )
+ expect(source).toContain('class="notes-editor-page !pb-0"')
+ expect(source).not.toContain('notes-editor-page !pt-[44px]')
+ })
+})
+
describe('NotesApp more menu', () => {
it('uses the shared Feather-style action sheet', () => {
expect(menuSource).toContain(
diff --git a/frontend/src/views/apps/NotesApp.vue b/frontend/src/views/apps/NotesApp.vue
index 9767ccc..f822edf 100644
--- a/frontend/src/views/apps/NotesApp.vue
+++ b/frontend/src/views/apps/NotesApp.vue
@@ -206,6 +206,7 @@ function shareNote(): void {
:aria-label="phone.t('Apps.notes.name')"
>
@@ -305,7 +306,7 @@ function shareNote(): void {
-
+