feat(qbz-slint): three-section header with responsive tabs
The header is now three equal sections — navigation tabs (left), the search field (center, so it lands at the window center), and the user element (right) — fixing the tabs stretching to full width under the search field. - Nav tabs regain Lucide icons (compass, library, hard-drive, cassette-tape) and use a 12px label. - The user element uses a hamburger icon instead of the QBZ logo, which aliased badly as a scaled PNG. - Responsive: below 1140px the tabs drop their icons; below 960px the search field narrows to 70%. cc
This commit is contained in:
5 files changed
+155
-84
No files matched your search
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect width="20" height="16" x="2" y="4" rx="2" />
|
||||
<circle cx="8" cy="10" r="2" />
|
||||
<path d="M8 12h8" />
|
||||
<circle cx="16" cy="10" r="2" />
|
||||
<path d="m6 20 .7-2.9A1.4 1.4 0 0 1 8.1 16h7.8a1.4 1.4 0 0 1 1.4 1l.7 3" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 407 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 327 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10 16h.01" />
|
||||
<path d="M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" />
|
||||
<path d="M21.946 12.013H2.054" />
|
||||
<path d="M6 16h.01" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 435 B |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect width="8" height="18" x="3" y="3" rx="1" />
|
||||
<path d="M7 3v18" />
|
||||
<path d="M20.4 18.9c.2.5-.1 1.1-.6 1.3l-1.9.7c-.5.2-1.1-.1-1.3-.6L11.1 5.1c-.2-.5.1-1.1.6-1.3l1.9-.7c.5-.2 1.1.1 1.3.6Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 385 B |
@@ -1,5 +1,9 @@
|
||||
// Top header bar — primary navigation tabs, a window-centered search
|
||||
// field, and the user element with its dropdown menu.
|
||||
// Top header bar — three equal sections: navigation tabs (left), the
|
||||
// search field (center, so it lands at the window center), and the user
|
||||
// element with its dropdown menu (right).
|
||||
//
|
||||
// Responsive: below the first breakpoint the tabs drop their icons;
|
||||
// below the second the search field narrows to 70%.
|
||||
|
||||
import { Theme } from "../foundation/semantic-colors.slint";
|
||||
import { Spacing } from "../foundation/spacing.slint";
|
||||
@@ -10,22 +14,34 @@ import { SessionState } from "../state.slint";
|
||||
import { QbzIcon } from "../primitives/QbzIcon.slint";
|
||||
|
||||
component NavTab inherits Rectangle {
|
||||
in property <image> icon;
|
||||
in property <string> label;
|
||||
in property <bool> active: false;
|
||||
in property <bool> show-icon: true;
|
||||
callback clicked();
|
||||
|
||||
height: 32px;
|
||||
height: 30px;
|
||||
border-radius: Radius.sm;
|
||||
background: root.active ? Theme.surface-elevated
|
||||
: ta.has-hover ? Theme.surface-hover : transparent;
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: Spacing.md;
|
||||
padding-right: Spacing.md;
|
||||
padding-left: root.show-icon ? 9px : 11px;
|
||||
padding-right: 11px;
|
||||
spacing: 6px;
|
||||
if root.show-icon: VerticalLayout {
|
||||
alignment: center;
|
||||
QbzIcon {
|
||||
source: root.icon;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
tint: root.active ? Theme.text-primary : Theme.text-secondary;
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: root.label;
|
||||
color: root.active ? Theme.text-primary : Theme.text-secondary;
|
||||
font-size: Typography.body;
|
||||
font-size: 12px;
|
||||
font-weight: root.active ? Typography.semibold : Typography.regular;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
@@ -84,92 +100,125 @@ export component HeaderBar inherits Rectangle {
|
||||
height: Layout.header-height;
|
||||
background: Theme.surface-card;
|
||||
|
||||
// --- Nav tabs (left) -------------------------------------------------
|
||||
VerticalLayout {
|
||||
x: Spacing.md;
|
||||
height: parent.height;
|
||||
alignment: center;
|
||||
HorizontalLayout {
|
||||
spacing: Spacing.xs;
|
||||
NavTab { label: "Discover"; active: true; }
|
||||
NavTab { label: "Library"; }
|
||||
NavTab { label: "Local Library"; }
|
||||
NavTab { label: "My QBZ"; }
|
||||
}
|
||||
}
|
||||
// Responsive breakpoints.
|
||||
property <bool> show-tab-icons: root.width >= 1140px;
|
||||
property <length> search-width: root.width < 960px ? 224px : 320px;
|
||||
|
||||
// --- Search field, centered to the header width ----------------------
|
||||
Rectangle {
|
||||
width: 320px;
|
||||
height: 32px;
|
||||
x: (parent.width - self.width) / 2;
|
||||
y: (parent.height - self.height) / 2;
|
||||
border-radius: 6px;
|
||||
border-width: 1px;
|
||||
border-color: Theme.border-subtle;
|
||||
background: Theme.surface-elevated;
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
spacing: 7px;
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
QbzIcon {
|
||||
source: @image-url("../assets/icons/search.svg");
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
tint: Theme.text-muted;
|
||||
HorizontalLayout {
|
||||
// --- Tabs (left third) -------------------------------------------
|
||||
VerticalLayout {
|
||||
horizontal-stretch: 1;
|
||||
alignment: center;
|
||||
HorizontalLayout {
|
||||
padding-left: Spacing.md;
|
||||
spacing: Spacing.xs;
|
||||
alignment: start;
|
||||
NavTab {
|
||||
icon: @image-url("../assets/icons/compass.svg");
|
||||
label: "Discover";
|
||||
active: true;
|
||||
show-icon: root.show-tab-icons;
|
||||
}
|
||||
NavTab {
|
||||
icon: @image-url("../assets/icons/library-big.svg");
|
||||
label: "Library";
|
||||
show-icon: root.show-tab-icons;
|
||||
}
|
||||
NavTab {
|
||||
icon: @image-url("../assets/icons/hard-drive.svg");
|
||||
label: "Local Library";
|
||||
show-icon: root.show-tab-icons;
|
||||
}
|
||||
NavTab {
|
||||
icon: @image-url("../assets/icons/cassette-tape.svg");
|
||||
label: "My QBZ";
|
||||
show-icon: root.show-tab-icons;
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: @tr("Search");
|
||||
color: Theme.text-muted;
|
||||
font-size: 13px;
|
||||
vertical-alignment: center;
|
||||
horizontal-stretch: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- User element + dropdown (right) ---------------------------------
|
||||
user-area := TouchArea {
|
||||
width: user-row.preferred-width + 16px;
|
||||
height: 36px;
|
||||
x: parent.width - self.width - Spacing.md;
|
||||
y: (parent.height - self.height) / 2;
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
menu.show();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: Radius.sm;
|
||||
background: user-area.has-hover ? Theme.surface-hover : transparent;
|
||||
}
|
||||
user-row := HorizontalLayout {
|
||||
x: 8px;
|
||||
height: parent.height;
|
||||
spacing: 8px;
|
||||
VerticalLayout {
|
||||
// --- Search (center third) ---------------------------------------
|
||||
VerticalLayout {
|
||||
horizontal-stretch: 1;
|
||||
alignment: center;
|
||||
HorizontalLayout {
|
||||
alignment: center;
|
||||
Text {
|
||||
text: SessionState.user-name == ""
|
||||
? @tr("Guest")
|
||||
: SessionState.user-name;
|
||||
color: Theme.text-primary;
|
||||
font-size: Typography.body;
|
||||
Rectangle {
|
||||
width: root.search-width;
|
||||
height: 32px;
|
||||
border-radius: 6px;
|
||||
border-width: 1px;
|
||||
border-color: Theme.border-subtle;
|
||||
background: Theme.surface-elevated;
|
||||
HorizontalLayout {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
spacing: 7px;
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
QbzIcon {
|
||||
source: @image-url("../assets/icons/search.svg");
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
tint: Theme.text-muted;
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: @tr("Search");
|
||||
color: Theme.text-muted;
|
||||
font-size: 13px;
|
||||
vertical-alignment: center;
|
||||
horizontal-stretch: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
Image {
|
||||
source: @image-url("../assets/qbz-logo.png");
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
image-fit: contain;
|
||||
}
|
||||
|
||||
// --- User element (right third) ----------------------------------
|
||||
VerticalLayout {
|
||||
horizontal-stretch: 1;
|
||||
alignment: center;
|
||||
HorizontalLayout {
|
||||
padding-right: Spacing.md;
|
||||
alignment: end;
|
||||
user-area := TouchArea {
|
||||
width: user-row.preferred-width + 16px;
|
||||
height: 36px;
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
menu.show();
|
||||
}
|
||||
Rectangle {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: Radius.sm;
|
||||
background: user-area.has-hover ? Theme.surface-hover : transparent;
|
||||
}
|
||||
user-row := HorizontalLayout {
|
||||
x: 8px;
|
||||
height: parent.height;
|
||||
spacing: 9px;
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
Text {
|
||||
text: SessionState.user-name == ""
|
||||
? @tr("Guest")
|
||||
: SessionState.user-name;
|
||||
color: Theme.text-primary;
|
||||
font-size: Typography.body;
|
||||
}
|
||||
}
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
QbzIcon {
|
||||
source: @image-url("../assets/icons/menu.svg");
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
tint: Theme.text-secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user