-
This commit is contained in:
@@ -1,170 +1,209 @@
|
||||
import { Theme, SpacingSystem, Typography } from "../theme/theme.slint";
|
||||
import { Tabs, TabItem, TabContent } from "../components/tabs.slint";
|
||||
// Logs Page - Display Mihomo and App logs with tabs
|
||||
import { Theme, Typography, SpacingSystem } from "../theme/theme.slint";
|
||||
import { Empty } from "../components/empty.slint";
|
||||
import { LogEntry } from "../types.slint";
|
||||
|
||||
export struct LogEntry {
|
||||
time: string,
|
||||
level: string, // "debug", "info", "warn", "error"
|
||||
message: string,
|
||||
}
|
||||
export component LogsPage inherits Rectangle {
|
||||
in property <[LogEntry]> mihomo-logs;
|
||||
in property <[LogEntry]> app-logs;
|
||||
in-out property <string> active-tab: "mihomo";
|
||||
|
||||
callback load-logs(string /* type: mihomo/app */);
|
||||
|
||||
background: Theme.colors.background;
|
||||
|
||||
export component LogsPage {
|
||||
in property <[LogEntry]> mihomo-logs: [];
|
||||
in property <[LogEntry]> app-logs: [];
|
||||
in-out property <int> current-tab: 0;
|
||||
|
||||
callback tab-changed(int);
|
||||
|
||||
VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
spacing: SpacingSystem.spacing.s4;
|
||||
|
||||
// Header with Tabs
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s3;
|
||||
alignment: space-between;
|
||||
|
||||
Text {
|
||||
text: "Logs";
|
||||
color: Theme.colors.foreground;
|
||||
font-size: Typography.sizes.xl;
|
||||
font-weight: Typography.weights.bold;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
horizontal-stretch: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Tabs
|
||||
Tabs {
|
||||
tabs: [
|
||||
{ title: "Mihomo Logs" },
|
||||
{ title: "App Logs" },
|
||||
];
|
||||
current-index: root.current-tab;
|
||||
|
||||
tab-changed(index) => {
|
||||
root.current-tab = index;
|
||||
root.tab-changed(index);
|
||||
}
|
||||
|
||||
// Mihomo Logs
|
||||
TabContent {
|
||||
index: 0;
|
||||
current-index: root.current-tab;
|
||||
|
||||
LogView {
|
||||
logs: root.mihomo-logs;
|
||||
}
|
||||
}
|
||||
|
||||
// App Logs
|
||||
TabContent {
|
||||
index: 1;
|
||||
current-index: root.current-tab;
|
||||
|
||||
LogView {
|
||||
logs: root.app-logs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fixed header with tabs
|
||||
Rectangle {
|
||||
height: 48px;
|
||||
background: Theme.colors.background;
|
||||
|
||||
component LogView {
|
||||
in property <[LogEntry]> logs: [];
|
||||
|
||||
Rectangle {
|
||||
background: Theme.colors.background;
|
||||
border-radius: SpacingSystem.radius.md;
|
||||
border-width: 1px;
|
||||
border-color: Theme.colors.border;
|
||||
|
||||
ScrollView {
|
||||
VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s2;
|
||||
spacing: 0;
|
||||
|
||||
for log[index] in root.logs: LogRow {
|
||||
log-entry: log;
|
||||
odd: Math.mod(index, 2) == 1;
|
||||
HorizontalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
spacing: SpacingSystem.spacing.s4;
|
||||
alignment: space-between;
|
||||
|
||||
Text {
|
||||
text: "Logs";
|
||||
font-size: Typography.sizes.xl;
|
||||
font-weight: Typography.weights.bold;
|
||||
color: Theme.colors.foreground;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
|
||||
// Tabs
|
||||
HorizontalLayout {
|
||||
spacing: SpacingSystem.spacing.s1;
|
||||
|
||||
Rectangle {
|
||||
width: 120px;
|
||||
height: 32px;
|
||||
background: active-tab == "mihomo" ? Theme.colors.primary : Theme.colors.muted;
|
||||
border-radius: SpacingSystem.radius.md;
|
||||
|
||||
TouchArea {
|
||||
clicked => {
|
||||
active-tab = "mihomo";
|
||||
root.load-logs("mihomo");
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Mihomo Logs";
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
color: active-tab == "mihomo" ? Theme.colors.primary-foreground : Theme.colors.muted-foreground;
|
||||
horizontal-alignment: center;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 100px;
|
||||
height: 32px;
|
||||
background: active-tab == "app" ? Theme.colors.primary : Theme.colors.muted;
|
||||
border-radius: SpacingSystem.radius.md;
|
||||
|
||||
TouchArea {
|
||||
clicked => {
|
||||
active-tab = "app";
|
||||
root.load-logs("app");
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "App Logs";
|
||||
font-size: Typography.sizes.sm;
|
||||
font-weight: Typography.weights.medium;
|
||||
color: active-tab == "app" ? Theme.colors.primary-foreground : Theme.colors.muted-foreground;
|
||||
horizontal-alignment: center;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scrollable log content
|
||||
Flickable {
|
||||
viewport-height: log-content.preferred-height + SpacingSystem.spacing.s4 * 2;
|
||||
|
||||
log-content := VerticalLayout {
|
||||
padding: SpacingSystem.spacing.s4;
|
||||
spacing: 0px;
|
||||
|
||||
// Mihomo logs
|
||||
if active-tab == "mihomo": VerticalLayout {
|
||||
spacing: 0px;
|
||||
|
||||
if mihomo-logs.length == 0: Empty {
|
||||
height: 300px;
|
||||
icon: "📝";
|
||||
title: "No Logs";
|
||||
description: "Mihomo logs will appear here";
|
||||
}
|
||||
|
||||
for log[index] in mihomo-logs: Rectangle {
|
||||
height: 24px;
|
||||
background: mod(index, 2) == 0 ? Theme.colors.muted : transparent;
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: SpacingSystem.spacing.s2;
|
||||
padding-right: SpacingSystem.spacing.s2;
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
// Time
|
||||
Text {
|
||||
text: log.time;
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-family: "monospace";
|
||||
vertical-alignment: center;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
// Level
|
||||
Text {
|
||||
text: log.level;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.bold;
|
||||
color: log.level == "error" ? #ef4444 :
|
||||
log.level == "warn" ? #f59e0b :
|
||||
log.level == "info" ? #3b82f6 : Theme.colors.muted-foreground;
|
||||
font-family: "monospace";
|
||||
vertical-alignment: center;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
// Message
|
||||
Text {
|
||||
text: log.message;
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.foreground;
|
||||
font-family: "monospace";
|
||||
vertical-alignment: center;
|
||||
overflow: elide;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// App logs
|
||||
if active-tab == "app": VerticalLayout {
|
||||
spacing: 0px;
|
||||
|
||||
if app-logs.length == 0: Empty {
|
||||
height: 300px;
|
||||
icon: "📝";
|
||||
title: "No Logs";
|
||||
description: "App logs will appear here";
|
||||
}
|
||||
|
||||
for log[index] in app-logs: Rectangle {
|
||||
height: 24px;
|
||||
background: mod(index, 2) == 0 ? Theme.colors.muted : transparent;
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: SpacingSystem.spacing.s2;
|
||||
padding-right: SpacingSystem.spacing.s2;
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
// Time
|
||||
Text {
|
||||
text: log.time;
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-family: "monospace";
|
||||
vertical-alignment: center;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
// Level
|
||||
Text {
|
||||
text: log.level;
|
||||
font-size: Typography.sizes.xs;
|
||||
font-weight: Typography.weights.bold;
|
||||
color: log.level == "error" ? #ef4444 :
|
||||
log.level == "warn" ? #f59e0b :
|
||||
log.level == "info" ? #3b82f6 : Theme.colors.muted-foreground;
|
||||
font-family: "monospace";
|
||||
vertical-alignment: center;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
// Message
|
||||
Text {
|
||||
text: log.message;
|
||||
font-size: Typography.sizes.xs;
|
||||
color: Theme.colors.foreground;
|
||||
font-family: "monospace";
|
||||
vertical-alignment: center;
|
||||
overflow: elide;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component LogRow {
|
||||
in property <LogEntry> log-entry;
|
||||
in property ool> odd: false;
|
||||
|
||||
private property <bool> hovered: false;
|
||||
|
||||
private property <color> level-color: log-entry.level == "error" ? #ef4444 :
|
||||
log-entry.level == "warn" ? #eab308 :
|
||||
log-entry.level == "info" ? #3b82f6 :
|
||||
log-entry.level == "debug" ? #6b7280 :
|
||||
Theme.colors.muted-foreground;
|
||||
|
||||
height: 24px;
|
||||
|
||||
states [
|
||||
hovered when root.hovered: {
|
||||
container.background: Theme.colors.muted.transparentize(0.5);
|
||||
}
|
||||
odd when root.odd && !root.hovered: {
|
||||
container.background: Theme.colors.muted.transparentize(0.8);
|
||||
}
|
||||
]
|
||||
|
||||
container := Rectangle {
|
||||
background: transparent;
|
||||
border-radius: SpacingSystem.radius.sm;
|
||||
|
||||
animate background { duration: 150ms; }
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: SpacingSystem.spacing.s2;
|
||||
padding-right: SpacingSystem.spacing.s2;
|
||||
spacing: SpacingSystem.spacing.s2;
|
||||
|
||||
// Time
|
||||
Text {
|
||||
text: root.log-entry.time;
|
||||
color: Theme.colors.muted-foreground;
|
||||
font-size: 11px;
|
||||
font-family: "monospace";
|
||||
vertical-alignment: center;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
// Level
|
||||
Text {
|
||||
text: root.log-entry.level;
|
||||
color: root.level-color;
|
||||
font-size: 11px;
|
||||
font-family: "monospace";
|
||||
font-weight: Typography.weights.bold;
|
||||
vertical-alignment: center;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
// Message
|
||||
Text {
|
||||
text: root.log-entry.message;
|
||||
color: Theme.colors.foreground;
|
||||
font-size: 11px;
|
||||
font-family: "ospace";
|
||||
vertical-alignment: center;
|
||||
overflow: elide;
|
||||
}
|
||||
}
|
||||
|
||||
touch := TouchArea {
|
||||
moved => {
|
||||
root.hovered = self.has-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user