import { Theme } from "theme.slint"; import { Sparkline } from "widgets.slint"; // One filesystem row for the disk-usage panel. export struct DiskInfo { path: string, detail: string, // "available/total" percent: float, // used fraction 0.0..1.0 } export struct ProcessInfo { mem: string, cpu: string, name: string, } // --- StatRow --------------------------------------------------------------- // A single label / percentage / progress-bar row used for CPU / memory / swap. component StatRow inherits Rectangle { in property label; in property percent; // 0.0 .. 1.0 in property detail; in property bar-color: Theme.accent; height: 30px; border-radius: Theme.radius-sm; background: Theme.bg-panel-alt.with-alpha(0.38); HorizontalLayout { height: parent.height; padding-left: 6px; padding-right: 6px; spacing: 7px; Text { width: 32px; height: parent.height; text: label; color: Theme.text-secondary; font-size: Theme.fs-xs; vertical-alignment: center; overflow: elide; } Rectangle { y: (parent.height - self.height) / 2; height: 20px; horizontal-stretch: 1; background: Theme.bg-root.with-alpha(0.56); border-radius: Theme.radius-sm; border-width: 1px; border-color: Theme.border-subtle.with-alpha(0.58); clip: true; Rectangle { x: 0; height: parent.height; width: parent.width * clamp(percent, 0.0, 1.0); background: bar-color.with-alpha(0.52); border-radius: Theme.radius-sm; animate width { duration: 500ms; easing: ease-out; } } HorizontalLayout { height: parent.height; padding-left: 7px; padding-right: 7px; Text { height: parent.height; text: Math.round(percent * 100) + "%"; color: Theme.text-primary; font-size: Theme.fs-xs; font-weight: 600; vertical-alignment: center; } Rectangle { horizontal-stretch: 1; } Text { height: parent.height; text: detail; color: Theme.text-primary; font-size: Theme.fs-xs; horizontal-alignment: right; vertical-alignment: center; overflow: elide; } } } } } component ProcessTable inherits VerticalLayout { in property <[ProcessInfo]> processes; vertical-stretch: 0; spacing: 1px; HorizontalLayout { height: 18px; padding-left: 6px; padding-right: 6px; spacing: 4px; Text { width: 42px; text: @tr("Memory"); color: Theme.text-muted; font-size: Theme.fs-xs; vertical-alignment: center; } Text { width: 32px; text: "CPU"; color: Theme.text-muted; font-size: Theme.fs-xs; vertical-alignment: center; } Text { text: @tr("Program"); color: Theme.text-muted; font-size: Theme.fs-xs; vertical-alignment: center; horizontal-stretch: 1; } } for p in root.processes : Rectangle { height: 18px; border-radius: 2px; background: row-ta.has-hover ? Theme.bg-hover.with-alpha(0.78) : Theme.bg-panel-alt.with-alpha(0.22); row-ta := TouchArea {} HorizontalLayout { height: parent.height; padding-left: 6px; padding-right: 6px; spacing: 4px; Text { width: 42px; text: p.mem; color: Theme.text-secondary; font-size: Theme.fs-xs; vertical-alignment: center; overflow: elide; } Text { width: 32px; text: p.cpu; color: Theme.text-secondary; font-size: Theme.fs-xs; vertical-alignment: center; overflow: elide; } Text { text: p.name; color: Theme.text-primary; font-size: Theme.fs-xs; vertical-alignment: center; horizontal-stretch: 1; overflow: elide; } } } } // --- NetGraph -------------------------------------------------------------- // One network throughput graph: a header row (↑ tx / ↓ rx, plus an optional // NIC selector dropdown) over an auto-scaled sparkline. component NetGraph inherits VerticalLayout { in property up-text; in property down-text; in property <[float]> history; in property show-selector: false; in property <[string]> ifaces; in property selected; callback iface-selected(string); // Stay at preferred height; without this the inherited VerticalLayout grabs // a stretch share of the sidebar and balloons the sparkline into blank space. vertical-stretch: 0; spacing: 3px; HorizontalLayout { height: 18px; spacing: 3px; Text { // ↑ upload (green) width: 12px; height: parent.height; text: "\u{E5D8}"; font-family: "Material Icons"; color: Theme.success; font-size: Theme.fs-xs; horizontal-alignment: center; vertical-alignment: center; } Text { height: parent.height; text: root.up-text; color: Theme.text-secondary; font-size: Theme.fs-xs; vertical-alignment: center; } Text { // ↓ download (blue) width: 12px; height: parent.height; text: "\u{E5DB}"; font-family: "Material Icons"; color: Theme.accent; font-size: Theme.fs-xs; horizontal-alignment: center; vertical-alignment: center; } Text { height: parent.height; text: root.down-text; color: Theme.text-secondary; font-size: Theme.fs-xs; vertical-alignment: center; } Rectangle { horizontal-stretch: 1; } // spacer pushes selector to the right if root.show-selector : Rectangle { width: 64px; height: 18px; border-radius: 3px; background: sel-ta.has-hover ? Theme.bg-hover : Theme.bg-elevated; HorizontalLayout { height: parent.height; padding-left: 5px; padding-right: 4px; spacing: 2px; Text { height: parent.height; text: root.selected; color: Theme.text-primary; font-size: Theme.fs-xs; vertical-alignment: center; horizontal-stretch: 1; overflow: elide; } Text { height: parent.height; text: "\u{E5CF}"; font-family: "Material Icons"; color: Theme.text-muted; font-size: 8px; vertical-alignment: center; } } sel-ta := TouchArea { mouse-cursor: pointer; clicked => { popup.show(); } } popup := PopupWindow { x: 0; y: parent.height + 2px; width: 96px; Rectangle { background: Theme.bg-panel; border-radius: 4px; border-width: 1px; border-color: Theme.border-strong; drop-shadow-blur: 10px; drop-shadow-color: #00000050; VerticalLayout { padding: 4px; spacing: 1px; for iface in root.ifaces : Rectangle { height: 22px; border-radius: 3px; background: row-ta.has-hover ? Theme.bg-hover : transparent; row-ta := TouchArea { mouse-cursor: pointer; clicked => { root.iface-selected(iface); } } Text { x: 6px; text: iface; color: Theme.text-primary; font-size: Theme.fs-xs; vertical-alignment: center; height: parent.height; } } } } } } } Sparkline { height: 48px; values: root.history; line-color: Theme.accent; } } // --- Sidebar --------------------------------------------------------------- // Left-hand panel showing local machine health, mimicking FinalShell's // @tr("Status") column but kept minimal for the v0.1 baseline. export component Sidebar inherits Rectangle { in property app-background-active: false; in property ui-opacity: 0.72; in property connection-state: @tr("Not connected"); in property conn-state; // 0 gray / 1 green / 2 yellow in property resource-title: @tr("Local resources"); in property cpu-percent; in property mem-percent; in property swap-percent; in property cpu-detail; in property mem-detail; in property swap-detail; in property net-top-up; in property net-top-down; in property <[float]> net-top-history; in property <[string]> net-ifaces; in property net-selected; in property net-show-selector; in property <[DiskInfo]> disks; in property <[ProcessInfo]> processes; callback select-net-iface(string); width: 220px; background: root.app-background-active ? Theme.bg-panel.with-alpha(root.ui-opacity) : Theme.bg-panel; border-width: 0; VerticalLayout { padding: 10px; spacing: 10px; // Status header VerticalLayout { spacing: 3px; Text { text: @tr("Running status"); color: Theme.text-primary; font-size: Theme.fs-md; font-weight: 600; vertical-alignment: center; } Rectangle { height: 24px; border-radius: Theme.radius-sm; background: root.conn-state == 1 ? Theme.success.with-alpha(0.16) : root.conn-state == 2 ? Theme.warning.with-alpha(0.16) : Theme.bg-root; Text { x: 8px; width: parent.width - 16px; height: parent.height; text: connection-state; color: root.conn-state == 1 ? Theme.success : root.conn-state == 2 ? Theme.warning : Theme.text-secondary; font-size: Theme.fs-sm; vertical-alignment: center; overflow: elide; } } } Rectangle { height: 1px; background: Theme.border-subtle; } // System stats — local machine on the welcome tab, the remote server // when a connected session tab is active. Text { text: root.resource-title; color: Theme.text-secondary; font-size: Theme.fs-sm; } VerticalLayout { spacing: 6px; StatRow { label: "CPU"; percent: root.cpu-percent; detail: root.cpu-detail; bar-color: Theme.accent; } StatRow { label: @tr("Memory"); percent: root.mem-percent; detail: root.mem-detail; bar-color: Theme.success; } StatRow { label: @tr("Swap"); percent: root.swap-percent; detail: root.swap-detail; bar-color: Theme.warning; } } Rectangle { height: 1px; background: Theme.border-subtle; } ProcessTable { processes: root.processes; } if root.net-top-up != "" || root.net-top-down != "" || root.net-show-selector : Rectangle { height: 1px; background: Theme.border-subtle; } // Network — follows the active live session tab. if root.net-top-up != "" || root.net-top-down != "" || root.net-show-selector : VerticalLayout { vertical-stretch: 0; spacing: 6px; NetGraph { up-text: root.net-top-up; down-text: root.net-top-down; history: root.net-top-history; show-selector: root.net-show-selector; ifaces: root.net-ifaces; selected: root.net-selected; iface-selected(i) => { root.select-net-iface(i); } } } Rectangle { height: 1px; background: Theme.border-subtle; } // Disk-usage panel (active tab's filesystems; local on the welcome tab). disk-section := VerticalLayout { vertical-stretch: 1; spacing: 3px; HorizontalLayout { padding-left: 6px; padding-right: 6px; Text { text: @tr("Path"); color: Theme.text-muted; font-size: Theme.fs-xs; horizontal-stretch: 1; } Text { text: @tr("Free/Total"); color: Theme.text-muted; font-size: Theme.fs-xs; } } disk-flick := Flickable { vertical-stretch: 1; viewport-width: self.width; // Grow only when the list overflows; otherwise match the visible // height so `alignment: start` keeps rows pinned to the top. viewport-height: max(self.height, disk-col.preferred-height); disk-col := VerticalLayout { alignment: start; spacing: 1px; for d[i] in root.disks : Rectangle { height: 20px; border-radius: 2px; clip: true; // Usage fill: green-ish normally, amber/red when full. Rectangle { x: 0; y: 0; height: parent.height; width: parent.width * clamp(d.percent, 0.0, 1.0); background: d.percent > 0.9 ? Theme.danger.with-alpha(0.32) : d.percent > 0.75 ? Theme.warning.with-alpha(0.30) : Theme.accent.with-alpha(0.22); } HorizontalLayout { height: parent.height; padding-left: 6px; padding-right: 6px; spacing: 4px; Text { height: parent.height; text: d.path; color: Theme.text-secondary; font-size: Theme.fs-xs; vertical-alignment: center; horizontal-stretch: 1; overflow: elide; } Text { height: parent.height; text: d.detail; color: Theme.text-muted; font-size: Theme.fs-xs; vertical-alignment: center; horizontal-alignment: right; } } } } } } Text { text: "meatshell v0.2.7"; color: Theme.text-muted; font-size: Theme.fs-xs; horizontal-alignment: center; } } }