import { ScrollView } from "std-widgets.slint";
import { CheckState, AppState } from "../globals.slint";
import { StyledButton } from "misc.slint";
// Floating action button for check status
component CheckFab inherits Rectangle {
callback clicked();
width: 48px;
height: 48px;
border-radius: 24px;
background: CheckState.check-status == "critical" ? #fa5252 :
CheckState.check-status == "warning" ? #fd7e14 : #40c057;
drop-shadow-blur: 8px;
drop-shadow-color: #00000030;
drop-shadow-offset-y: 2px;
animate background { duration: 200ms; }
touch := TouchArea {
mouse-cursor: pointer;
clicked => { root.clicked(); }
}
VerticalLayout {
alignment: center;
HorizontalLayout {
alignment: center;
if CheckState.check-status == "critical" : Text {
text: CheckState.critical-count > 9 ? "9+" : CheckState.critical-count;
font-size: 18px;
font-weight: 700;
color: #ffffff;
horizontal-alignment: center;
vertical-alignment: center;
}
if CheckState.check-status == "warning" : Text {
text: CheckState.warning-count > 9 ? "9+" : CheckState.warning-count;
font-size: 18px;
font-weight: 700;
color: #ffffff;
horizontal-alignment: center;
vertical-alignment: center;
}
if CheckState.check-status == "ok" : Text {
text: "\u{2713}";
font-size: 22px;
font-weight: 700;
color: #ffffff;
horizontal-alignment: center;
vertical-alignment: center;
}
}
}
}
// Issue row in the side panel
component IssueRow inherits Rectangle {
in property <string> message;
in property <bool> is-critical: false;
min-height: 40px;
background: is-critical ? #fff5f5 : #fff9db;
border-radius: 4px;
border-width: 1px;
border-color: is-critical ? #ffc9c9 : #ffec99;
HorizontalLayout {
padding: 8px;
spacing: 8px;
Rectangle {
width: 4px;
background: is-critical ? #fa5252 : #fd7e14;
border-radius: 2px;
}
Text {
text: message;
font-size: 13px;
color: #495057;
wrap: word-wrap;
vertical-alignment: center;
}
}
}
// Side panel showing check results
component CheckPanel inherits Rectangle {
width: 360px;
background: #ffffff;
border-width: 1px;
border-color: #dee2e6;
border-radius: 8px;
drop-shadow-blur: 8px;
drop-shadow-color: #00000020;
drop-shadow-offset-x: -2px;
VerticalLayout {
padding: 16px;
spacing: 12px;
// Header
HorizontalLayout {
spacing: 8px;
Text {
text: "Manifest Check";
font-size: 16px;
font-weight: 600;
color: #212529;
vertical-alignment: center;
}
Rectangle { horizontal-stretch: 1; }
// Re-check button
StyledButton {
text: "Re-check";
min-width: 80px;
clicked => { CheckState.request-check(); }
}
// Close button
Rectangle {
width: 28px;
height: 28px;
border-radius: 14px;
background: close-touch.has-hover ? #f1f3f5 : transparent;
close-touch := TouchArea {
mouse-cursor: pointer;
clicked => { CheckState.panel-visible = false; }
}
Text {
text: "\u{2715}";
font-size: 16px;
color: #868e96;
horizontal-alignment: center;
vertical-alignment: center;
}
}
}
// Summary
HorizontalLayout {
spacing: 16px;
if CheckState.critical-count > 0 : HorizontalLayout {
spacing: 4px;
Rectangle {
width: 10px;
height: 10px;
border-radius: 5px;
background: #fa5252;
y: (parent.height - self.height) / 2;
}
Text {
text: CheckState.critical-count + " critical";
font-size: 13px;
font-weight: 500;
color: #fa5252;
vertical-alignment: center;
}
}
if CheckState.warning-count > 0 : HorizontalLayout {
spacing: 4px;
Rectangle {
width: 10px;
height: 10px;
border-radius: 5px;
background: #fd7e14;
y: (parent.height - self.height) / 2;
}
Text {
text: CheckState.warning-count + " warning" + (CheckState.warning-count > 1 ? "s" : "");
font-size: 13px;
font-weight: 500;
color: #fd7e14;
vertical-alignment: center;
}
}
if CheckState.critical-count == 0 && CheckState.warning-count == 0 : Text {
text: "No issues found";
font-size: 13px;
font-weight: 500;
color: #40c057;
vertical-alignment: center;
}
}
// Divider
Rectangle {
height: 1px;
background: #dee2e6;
}
// Scrollable issue list
ScrollView {
vertical-stretch: 1;
VerticalLayout {
spacing: 6px;
alignment: start;
// Critical errors first
for error in CheckState.critical-errors : IssueRow {
message: error;
is-critical: true;
}
// Then warnings
for warning in CheckState.warnings : IssueRow {
message: warning;
is-critical: false;
}
}
}
}
}
// Main exported widget combining FAB + Panel
export component CheckWidget inherits Rectangle {
// Overlay to close panel when clicking outside
if CheckState.panel-visible : Rectangle {
x: 0px;
y: 0px;
width: root.width;
height: root.height;
TouchArea {
clicked => { CheckState.panel-visible = false; }
}
}
// Side panel (anchored to right edge)
if CheckState.panel-visible : CheckPanel {
x: root.width - self.width;
y: 0px;
height: root.height;
}
// Floating action button (bottom-right, above panel if open)
if AppState.manifest-is-open && CheckState.check-status != "none" : CheckFab {
x: CheckState.panel-visible ? root.width - 360px - self.width - 16px : root.width - self.width - 24px;
y: root.height - self.height - 24px;
animate x { duration: 200ms; easing: ease-out; }
clicked => {
CheckState.panel-visible = !CheckState.panel-visible;
}
}
}