feat(qbz-qt): phase 5.5 — visual polish pass audited against the Slint sources
Screen-by-screen audit with before/after screenshots: rounded surface-main content panel with 8px bezel (the Slack-style frame), real splash card, QbzPrimaryButton/QbzCheckbox/QbzTextLink replicas, accent arc spinner replacing BusyIndicator, custom thin auto-hide scrollbars (Home + Library grid/list), carousel edge fades, toolbar pill offset, QbzSlider/SeekBar metrics, alpha-format re-audit of all 8-digit hex literals. Pure look — zero functionality changes. km
No files matched your search
@@ -48,6 +48,8 @@ fn main() {
|
||||
"qml/LibraryView.qml",
|
||||
"qml/QbzTheme.qml",
|
||||
"qml/QbzIcon.qml",
|
||||
"qml/QbzScrollBar.qml",
|
||||
"qml/QbzSpinner.qml",
|
||||
],
|
||||
qrc_files: &qrc_refs,
|
||||
..Default::default()
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
// App shell — the QML port of crates/qbz-ui/ui/shell/AppShell.slint's
|
||||
// chrome: HeaderBar (top, 42px) / { Sidebar | content | queue column } /
|
||||
// NowPlayingBarSmall (bottom). The recovery affordance and logout live in
|
||||
// the header (offline badge flyout + app menu), like the Slint shell.
|
||||
// chrome: HeaderBar (top, 42px) / { Sidebar | content frame | queue
|
||||
// column } / NowPlayingBarSmall (bottom).
|
||||
//
|
||||
// The window chrome is surface-card throughout; the content area is a
|
||||
// ROUNDED surface-main panel inset 8px left/right/bottom (0 top — it
|
||||
// butts the header), the "Slack-style bezel on all four corners" of
|
||||
// AppShell.slint:358-390. The recovery affordance and logout live in the
|
||||
// header (offline badge flyout + app menu), like the Slint shell.
|
||||
//
|
||||
// POC-NOTE: the artwork-derived ambient background (AppearanceState
|
||||
// "Ambient"/"Blurred art" modes) is not implemented — the Slint default
|
||||
// is Off, which is what this static dark treatment matches.
|
||||
|
||||
import QtQuick
|
||||
import com.blitzfc.qbz
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: theme.surfaceMain
|
||||
// The window chrome is surface-card (header / sidebar / queue column /
|
||||
// NPB all paint it too); the content panel contrasts in surface-main.
|
||||
color: theme.surfaceCard
|
||||
|
||||
QbzTheme { id: theme }
|
||||
|
||||
@@ -58,14 +69,20 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// Content frame — the view area between sidebar and queue column.
|
||||
// Content frame — the rounded, inset surface-main panel (Radius.md,
|
||||
// 8px gaps left/right/bottom, flush to the header).
|
||||
Rectangle {
|
||||
id: contentFrame
|
||||
anchors.left: sidebar.right
|
||||
anchors.right: queueColumn.left
|
||||
anchors.top: header.bottom
|
||||
anchors.bottom: npb.top
|
||||
anchors.leftMargin: 8
|
||||
anchors.rightMargin: 8
|
||||
anchors.bottomMargin: 8
|
||||
radius: theme.radiusMd
|
||||
color: theme.surfaceMain
|
||||
border.width: 0
|
||||
clip: true
|
||||
|
||||
Loader {
|
||||
|
||||
@@ -370,16 +370,47 @@ Rectangle {
|
||||
onPageLeft: rail.contentX = Math.min(0, rail.contentX - step)
|
||||
onPageRight: rail.contentX = Math.min(maxScroll, rail.contentX + step)
|
||||
}
|
||||
ListView {
|
||||
id: rail
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 246
|
||||
orientation: ListView.Horizontal
|
||||
spacing: 32
|
||||
clip: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
model: sectionData.items
|
||||
delegate: AlbumCard { card: modelData }
|
||||
ListView {
|
||||
id: rail
|
||||
anchors.fill: parent
|
||||
orientation: ListView.Horizontal
|
||||
spacing: 32
|
||||
clip: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
model: sectionData.items
|
||||
delegate: AlbumCard { card: modelData }
|
||||
}
|
||||
// Cider-style edge fades (Carousel.slint): content dissolves
|
||||
// into the page background at the scrolled edges.
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: 56
|
||||
opacity: rail.contentX > 1 ? 1.0 : 0.0
|
||||
Behavior on opacity { NumberAnimation { duration: 150 } }
|
||||
gradient: Gradient {
|
||||
orientation: Gradient.Horizontal
|
||||
GradientStop { position: 0.0; color: theme.surfaceMain }
|
||||
GradientStop { position: 1.0; color: "transparent" }
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: 56
|
||||
opacity: rail.contentX < maxScroll - 1 ? 1.0 : 0.0
|
||||
Behavior on opacity { NumberAnimation { duration: 150 } }
|
||||
gradient: Gradient {
|
||||
orientation: Gradient.Horizontal
|
||||
GradientStop { position: 0.0; color: "transparent" }
|
||||
GradientStop { position: 1.0; color: theme.surfaceMain }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -688,7 +719,9 @@ Rectangle {
|
||||
height: 56
|
||||
|
||||
Row {
|
||||
x: 32
|
||||
// Slint left-controls: x 32 + NavButtons (now a 0px
|
||||
// placeholder) + 16px spacing -> the pill starts at 48.
|
||||
x: 48
|
||||
y: 25 - height / 2
|
||||
height: tabPill.height
|
||||
spacing: 16
|
||||
@@ -805,10 +838,13 @@ Rectangle {
|
||||
}
|
||||
|
||||
// --- Scrollable sections -----------------------------------------
|
||||
Item {
|
||||
width: parent.width
|
||||
height: parent.height - 57
|
||||
Flickable {
|
||||
id: homeFlick
|
||||
width: parent.width
|
||||
height: parent.height - 57
|
||||
height: parent.height
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: homeContent.implicitHeight
|
||||
@@ -988,5 +1024,14 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Thin auto-hiding scrollbar in the right gutter (ListScrollbar).
|
||||
QbzScrollBar {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 4
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
target: homeFlick
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -949,10 +949,10 @@ Rectangle {
|
||||
height: parent.height - 57
|
||||
clip: true
|
||||
|
||||
// Loading.
|
||||
BusyIndicator {
|
||||
// Loading (LoadingSpinner.slint: accent arc, 1s spin).
|
||||
QbzSpinner {
|
||||
anchors.centerIn: parent
|
||||
running: QbzBridge.libraryLoading
|
||||
size: 36
|
||||
visible: QbzBridge.libraryLoading
|
||||
}
|
||||
|
||||
@@ -1049,6 +1049,24 @@ Rectangle {
|
||||
item: modelData
|
||||
}
|
||||
}
|
||||
|
||||
// Thin auto-hiding scrollbars (ListScrollbar replica).
|
||||
QbzScrollBar {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 4
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
target: grid
|
||||
visible: grid.visible && grid.contentHeight > grid.height
|
||||
}
|
||||
QbzScrollBar {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 4
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
target: list
|
||||
visible: list.visible && list.contentHeight > list.height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,15 +92,16 @@ Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
radius: 4
|
||||
color: root.tosAccepted ? theme.accent : "transparent"
|
||||
border.color: root.tosAccepted ? theme.accent : theme.textMuted
|
||||
border.width: 1
|
||||
border.color: theme.textMuted
|
||||
border.width: root.tosAccepted ? 0 : 1.5
|
||||
|
||||
Text {
|
||||
QbzIcon {
|
||||
anchors.centerIn: parent
|
||||
visible: root.tosAccepted
|
||||
text: "✓"
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: 13
|
||||
name: "check"
|
||||
width: 12
|
||||
height: 12
|
||||
tintName: "primary"
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
@@ -135,18 +136,19 @@ Rectangle {
|
||||
Rectangle {
|
||||
id: signInButton
|
||||
width: parent.width
|
||||
height: 44
|
||||
height: 48
|
||||
radius: theme.radiusSm
|
||||
property bool canSignIn: root.tosAccepted && QbzBridge.loginPhase === 0
|
||||
color: canSignIn ? (signInArea.containsMouse ? "#5a95f5" : theme.accent)
|
||||
: theme.surfaceElevated
|
||||
opacity: canSignIn ? 1.0 : 0.5
|
||||
color: signInArea.containsMouse && canSignIn ? theme.accentHover : theme.accent
|
||||
Behavior on color { ColorAnimation { duration: 150 } }
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: QbzBridge.tr("Sign in with your browser")
|
||||
color: signInButton.canSignIn ? theme.textPrimary : theme.textMuted
|
||||
font.pixelSize: theme.fontBody
|
||||
font.weight: theme.weightMedium
|
||||
color: theme.accentText
|
||||
font.pixelSize: theme.fontButton
|
||||
font.weight: theme.weightSemibold
|
||||
}
|
||||
MouseArea {
|
||||
id: signInArea
|
||||
@@ -185,13 +187,26 @@ Rectangle {
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
Item { width: 1; height: 4 }
|
||||
Text {
|
||||
Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: QbzBridge.tr("Cancel")
|
||||
color: theme.accent
|
||||
font.pixelSize: theme.fontBody
|
||||
width: cancelText.implicitWidth
|
||||
height: cancelText.implicitHeight + 3
|
||||
Text {
|
||||
id: cancelText
|
||||
text: QbzBridge.tr("Cancel")
|
||||
color: cancelArea.containsMouse ? theme.accent : theme.textMuted
|
||||
font.pixelSize: theme.fontLink
|
||||
}
|
||||
Rectangle {
|
||||
y: cancelText.implicitHeight + 1
|
||||
width: cancelText.implicitWidth
|
||||
height: 1
|
||||
color: cancelArea.containsMouse ? theme.accent : theme.textMuted
|
||||
}
|
||||
MouseArea {
|
||||
id: cancelArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: QbzBridge.cancelLogin()
|
||||
}
|
||||
@@ -335,13 +350,26 @@ Rectangle {
|
||||
// Always visible (#553): without a previous session this
|
||||
// opens the GUEST profile (user 0) — Local Library only,
|
||||
// adopted by the account on the first real login.
|
||||
Text {
|
||||
Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: QbzBridge.tr("Start offline (no access to Qobuz™ services)")
|
||||
color: theme.accent
|
||||
font.pixelSize: theme.fontBody
|
||||
width: offlineText.implicitWidth
|
||||
height: offlineText.implicitHeight + 3
|
||||
Text {
|
||||
id: offlineText
|
||||
text: QbzBridge.tr("Start offline (no access to Qobuz™ services)")
|
||||
color: offlineArea.containsMouse ? theme.accent : theme.textMuted
|
||||
font.pixelSize: theme.fontLink
|
||||
}
|
||||
Rectangle {
|
||||
y: offlineText.implicitHeight + 1
|
||||
width: offlineText.implicitWidth
|
||||
height: 1
|
||||
color: offlineArea.containsMouse ? theme.accent : theme.textMuted
|
||||
}
|
||||
MouseArea {
|
||||
id: offlineArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: QbzBridge.startOffline()
|
||||
}
|
||||
|
||||
@@ -38,25 +38,56 @@ ApplicationWindow {
|
||||
: (QbzBridge.screen === "shell" ? "AppShell.qml" : "")
|
||||
}
|
||||
|
||||
// Splash: shown until the silent session restore resolves.
|
||||
// Splash (SplashScreen.slint): the same 720px dark card as the login
|
||||
// screen while the silent session restore resolves.
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "#0f0f0f"
|
||||
visible: QbzBridge.screen === "splash"
|
||||
|
||||
Column {
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
spacing: 16
|
||||
Image {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
source: "assets/qbz-logo.png"
|
||||
width: 120
|
||||
height: 120
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
BusyIndicator {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
running: true
|
||||
width: 720
|
||||
height: splashColumn.height + 104
|
||||
radius: 16
|
||||
color: "#1a1a1a"
|
||||
|
||||
Column {
|
||||
id: splashColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 52
|
||||
spacing: 0
|
||||
Image {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
source: "assets/qbz-logo.png"
|
||||
width: 140
|
||||
height: 140
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
Item { width: 1; height: 8 }
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "QBZ"
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 29
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: 8
|
||||
}
|
||||
Item { width: 1; height: 2 }
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "QOBUZ™ PLAYER"
|
||||
color: "#888888"
|
||||
font.pixelSize: 15
|
||||
font.letterSpacing: 4
|
||||
}
|
||||
Item { width: 1; height: 32 }
|
||||
QbzSpinner {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
size: 32
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,14 +108,14 @@ Rectangle {
|
||||
id: seekTrack
|
||||
width: parent.width
|
||||
height: 3
|
||||
radius: 1.5
|
||||
radius: 2
|
||||
color: theme.surfaceElevated
|
||||
|
||||
// Buffered / cache line.
|
||||
Rectangle {
|
||||
width: parent.width * Math.min(Math.max(QbzBridge.npCacheProgress, 0), 1)
|
||||
height: parent.height
|
||||
radius: 1.5
|
||||
radius: 2
|
||||
color: theme.textMuted
|
||||
opacity: 0.35
|
||||
}
|
||||
@@ -123,7 +123,7 @@ Rectangle {
|
||||
Rectangle {
|
||||
width: parent.width * Math.min(Math.max(QbzBridge.npProgress, 0), 1)
|
||||
height: parent.height
|
||||
radius: 1.5
|
||||
radius: 2
|
||||
color: theme.accent
|
||||
}
|
||||
// Hover thumb.
|
||||
@@ -421,20 +421,20 @@ Rectangle {
|
||||
Rectangle {
|
||||
id: volTrack
|
||||
width: parent.width
|
||||
height: 3
|
||||
radius: 1.5
|
||||
height: 4
|
||||
radius: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: theme.surfaceElevated
|
||||
Rectangle {
|
||||
width: parent.width * QbzBridge.npVolume
|
||||
height: parent.height
|
||||
radius: 1.5
|
||||
radius: 2
|
||||
color: theme.accent
|
||||
}
|
||||
Rectangle {
|
||||
width: 12
|
||||
height: 12
|
||||
radius: 6
|
||||
width: 16
|
||||
height: 16
|
||||
radius: 8
|
||||
color: theme.textPrimary
|
||||
x: parent.width * QbzBridge.npVolume - width / 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Custom vertical scrollbar — replica of primitives/ListScrollbar.slint.
|
||||
// 14px gutter (not over the rows), 6px #ffffff12 track, 8px thumb
|
||||
// (#ffffff44, widens to 10px / #ffffff77 on hover|drag), 48px min thumb,
|
||||
// auto-hide 900ms after the last scroll. Attach as a sibling anchored to
|
||||
// the right of a Flickable/GridView/ListView and set `target`.
|
||||
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
required property Flickable target
|
||||
|
||||
width: 14
|
||||
visible: maxScroll > 0
|
||||
|
||||
readonly property real maxScroll: Math.max(0, target.contentHeight - target.height)
|
||||
readonly property real thumbH: target.contentHeight > 0
|
||||
? Math.max(48, target.height / target.contentHeight * height)
|
||||
: height
|
||||
readonly property real travel: Math.max(0, height - thumbH)
|
||||
// Shown while scrolling, hovering, or dragging (auto-hide).
|
||||
property bool scrollActive: false
|
||||
readonly property bool shown: scrollActive || barArea.containsMouse || barArea.pressed
|
||||
|
||||
Connections {
|
||||
target: root.target
|
||||
function onContentYChanged() {
|
||||
root.scrollActive = true
|
||||
hideTimer.restart()
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id: hideTimer
|
||||
interval: 900
|
||||
onTriggered: root.scrollActive = false
|
||||
}
|
||||
|
||||
// Track.
|
||||
Rectangle {
|
||||
width: 6
|
||||
x: Math.round((parent.width - width) / 2)
|
||||
height: parent.height
|
||||
radius: 3
|
||||
color: "#12ffffff"
|
||||
opacity: root.shown ? 1.0 : 0.0
|
||||
Behavior on opacity { NumberAnimation { duration: 160 } }
|
||||
}
|
||||
// Thumb.
|
||||
Rectangle {
|
||||
width: barArea.containsMouse || barArea.pressed ? 10 : 8
|
||||
x: Math.round((parent.width - width) / 2)
|
||||
height: root.thumbH
|
||||
y: root.maxScroll > 0 ? (root.target.contentY / root.maxScroll) * root.travel : 0
|
||||
radius: 5
|
||||
color: barArea.containsMouse || barArea.pressed ? "#77ffffff" : "#44ffffff"
|
||||
opacity: root.shown ? 1.0 : 0.0
|
||||
Behavior on width { NumberAnimation { duration: 100 } }
|
||||
Behavior on opacity { NumberAnimation { duration: 160 } }
|
||||
}
|
||||
// Drag / click-to-position over the whole gutter.
|
||||
MouseArea {
|
||||
id: barArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: position(mouseY)
|
||||
onPositionChanged: if (pressed) position(mouseY)
|
||||
function position(my) {
|
||||
if (root.travel <= 0) return
|
||||
var frac = Math.min(1, Math.max(0, (my - root.thumbH / 2) / root.travel))
|
||||
root.target.contentY = frac * root.maxScroll
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Loading spinner — replica of primitives/LoadingSpinner.slint: the
|
||||
// Lucide loader-circle arc in accent, rotating 360deg/1000ms linear.
|
||||
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int size: 32
|
||||
property bool spinning: true
|
||||
|
||||
width: size
|
||||
height: size
|
||||
|
||||
QbzIcon {
|
||||
name: "loader-circle"
|
||||
width: root.size
|
||||
height: root.size
|
||||
tintName: "accent"
|
||||
RotationAnimation on rotation {
|
||||
running: root.spinning && root.visible
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 1000
|
||||
loops: Animation.Infinite
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4285f4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 215 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4285f4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>
|
||||
|
After Width: | Height: | Size: 222 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 215 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>
|
||||
|
After Width: | Height: | Size: 222 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#888888" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 215 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#888888" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>
|
||||
|
After Width: | Height: | Size: 222 B |
@@ -0,0 +1,3 @@
|
||||
<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="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 215 B |
@@ -0,0 +1 @@
|
||||
<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="M21 12a9 9 0 1 1-6.219-8.56"/></svg>
|
||||
|
After Width: | Height: | Size: 222 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#cccccc" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 215 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#cccccc" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>
|
||||
|
After Width: | Height: | Size: 222 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 215 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>
|
||||
|
After Width: | Height: | Size: 222 B |