Files
shadcn-slint/ui/pages/home.slint
2026-01-30 12:56:00 +08:00

520 lines
18 KiB
Plaintext

import { Theme, SpacingSystem, Typography } from "../theme/theme.slint";
import { Card } from "../components/card.slint";
import { Badge } from "../components/badge.slint";
import { Button } from "../components/button.slint";
import { Switch } from "../components/switch.slint";
import { Label, LabelSize, LabelColor } from "../components/label.slint";
import { Progress } from "../components/progress.slint";
export component HomePage {
callback refresh-profile();
callback toggle-tun-mode(bool);
callback toggle-system-proxy(bool);
callback open-port-settings();
in property <string> profile-name: "NanoCloud";
in property <string> profile-node: "免费-日本1-Ver.7";
in property <float> profile-usage: 1.26;
in property <float> profile-total: 100;
in property <string> profile-expiry: "2025-11-11";
in property <string> profile-updated: "2025-10-12 10:05";
in property <string> location-ip: "47.238.198.100";
in property <string> location-region: "日本 · 东京";
in property <bool> tun-mode-enabled: false;
in property <bool> system-proxy-enabled: false;
in property <int> proxy-port: 7890;
VerticalLayout {
padding: SpacingSystem.spacing.s4;
spacing: SpacingSystem.spacing.s4;
// Header
Text {
text: "Home";
color: Theme.colors.foreground;
font-size: Typography.sizes.xl;
font-weight: Typography.weights.bold;
}
ScrollView {
VerticalLayout {
spacing: SpacingSystem.spacing.s3;
// Profile Card
ProfileCard {
profile-name: root.profile-name;
profile-node: root.profile-node;
usage: root.profile-usage;
total: root.profile-total;
expiry: root.profile-expiry;
updated: root.profile-updated;
refresh => {
root.refresh-profile();
}
}
// Location Card
LocationCard {
ip: root.location-ip;
region: root.location-region;
}
// Settings Card
gsCard {
tun-enabled: root.tun-mode-enabled;
proxy-enabled: root.system-proxy-enabled;
port: root.proxy-port;
tun-toggled(enabled) => {
root.toggle-tun-mode(enabled);
}
proxy-toggled(enabled) => {
root.toggle-system-proxy(enabled);
}
port-clicked => {
root.open-port-settings();
}
}
}
}
}
}
component ProfileCard {
in property <string> profile-name: "";
in property <string> profile-node: "";
in property <float> usage: 0;
in property <float> total: 100;
in property <string> expiry: "";
in property <string> updated: "";
callback refresh();
Card {
VerticalLayout {
spacing: SpacingSystem.spacing.s4;
// Header
HorizontalLayout {
spacing: SpacingSystem.spacing.s3;
padding-bottom: SpacingSystem.ss4;
// Icon
Rectangle {
width: 48px;
height: 48px;
border-radius: 12px;
background: Theme.colors.primary.transparentize(0.9);
Text {
text: "☁";
color: Theme.colors.primary;
font-size: 24px;
horizontal-alignment: center;
vertical-alignment: center;
}
}
// Info
VerticalLayout {
spacing: SpacingSystem.spacing.s1;
HorizontalLayout {
spacing: SpacingSystem.spacing.s2;
Text {
text: root.profile-name;
color: Theme.colors.foreground;
font-size: Typography.sizes.lg;
font-weight: Typography.weights.bold;
vertical-alignment: center;
}
}
HorizontalLayout {
spacing: SpacingSystem.spacing.s2;
Text {
text: "🌐";
font-size: Typography.sizes.xs;
vertical-alignment: center;
}
Text {
text: root.profile-node;
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
font-weight: Typography.weights.medium;
vertical-alignment: center;
}
Badge {
text: "Vmess";
variant: "outline";
}
Badge {
text: "UDP";
variant: "outline";
}
}
}
Rectan horizontal-stretch: 1;
}
// Refresh button
Button {
width: 32px;
height: 32px;
variant: "ghost";
text: "↻";
clicked => {
root.refresh();
}
}
}
// Separator
Rectangle {
height: 1px;
background: Theme.colors.border.transparentize(0.6);
}
// Stats
HorizontalLayout {
spacing: SpacingSystem.spacing.s6;
VerticalLayout {
spacing: SpacingSystem.spacing.s1;
HorizontalLayout {
spacing: SpacingSystem.spacing.s1;
Text {
text: "☁";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
vertical-alignment: center;
}
Text {
text: "已使用 / 总量";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
font-weight: Typography.weights.semibold;
vertical-alignment: center;
}
}
Text {
text: root.usage + "GB / " + root.total + "GB";
color: Theme.colors.foreground;
font-size: Typography.sizes.sm;
font-weight: Typography.weights.medium;
}
}
VerticalLayout {
spacing: SpacingSystem.spacing.s1;
HorizontalLayout {
spacing: SpacingSystem.spacing.s1;
Text {
text: "✓";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
vertical-aliter;
}
Text {
text: "到期时间";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
font-weight: Typography.weights.semibold;
vertical-alignment: center;
}
}
Text {
text: root.expiry;
color: Theme.colors.foreground;
font-size: Typography.sizes.sm;
font-weight: Typography.weights.medium;
}
}
VerticalLayout {
spacing: SpacingSystem.spacing.s1;
HorizontalLayout {
spacing: SpacingSystem.spacing.s1;
Text {
text: "✓";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
vertical-: center;
n
Text {
text: "更新时间";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
font-weight: Typography.weights.semibold;
vertical-alignment: center;
}
}
Text {
text: root.updated;
color: Theme.colors.foreground;
font-size: Typography.sizes.sm;
font-weight: Typography.weights.medium;
}
}
}
}
}
}
component LocationCard {
in property <string> ip: "";
in property <string> region: "";
Card {
VerticalLayout {
spacing: SpacingSystem.spacing.s4;
// IP and Location
HorizontalLayout {
spacing: SpacingSystem.spacing.s6;
VerticalLayout {
spacing: SpacingSystem.spacing.s1;
HorizontalLayout {
spacing: SpacingSystem.spacing.s1;
Text {
text: "🌐";
font-size: Typography.sizes.xs;
vertical-alignment: center;
}
Text {
text: "IP";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
font-weight: Typography.weights.semibold;
vertical-alignment: center;
}
}
Text {
text: root.ip;
color: Theme.colors.foreground;
font-size: Typography.sizes.sm;
font-weight: Typography.weights.medium;
}
}
VerticalLayout {
: SpacingSystem.spacing.s1;
HorizontalLayout {
spacing: SpacingSystem.spacing.s1;
Text {
text: "🌐";
font-size: Typography.sizes.xs;
vertical-alignment: center;
}
Text {
text: "所属地址";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
font-weight: Typography.weights.semibold;
vertical-alignment: center;
}
}
Text {
text: root.region;
color: Theme.colors.foreground;
font-size: Typography.sizes.sm;
font-weight: Typography.weights.medium;
}
}
}
// Latency
VerticalLayout {
spacing: SpacingSystem.spacing.s2;
HorizontalLayout {
spacing: SpacingSystem.spacing.s1;
Text {
text: "✓";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
vertical-alignment: center;
}
Text {
text: "延迟";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.xs;
font-weight: Typography.weights.semibold;
vertical-alignment: center;
}
}
GridLayout {
spacing: SpacingSystem.spacing.s2;
Row {
LatencyItem { service: "Github"; latency: "122ms"; }
LatencyItem { service: "Google"; latency: "45ms"; }
LatencyItem { service: "Youtube"; latency: "67ms"; }
LatencyItem { service: "Twitter"; latency: "89ms"; }
}
Row {
LatencyItem { serviceetflix"; latency: "34ms"; }
LatencyItem { service: "Steam"; latency: "156ms"; }
LatencyItem { service: "Spotify"; latency: "78ms"; }
LatencyItem { service: "Discord"; latency: "92ms"; }
}
}
}
}
}
}
component LatencyItem {
in property <string> service: "";
in property <string> latency: "";
HorizontalLayout {
spacing: SpacingSystem.spacing.s1;
Text {
text: root.service;
color: Theme.colors.muted-foreg;
font-size: Typography.sizes.xs;
font-weight: Typography.weights.medium;
vertical-alignment: center;
}
Text {
text: root.latency;
color: Theme.colors.foreground;
font-size: Typography.sizes.xs;
font-weight: Typography.weights.semibold;
vertical-alignment: center;
}
}
}
component SettingsCard {
in property <bool> tun-enabled: false;
in property <bool> proxy-enabled: false;
in property <int> port: 7890;
callback tun-toggled(bool);
callback proxy-toggled(bool);
callback port-clicked();
Card {
VerticalLayout {
spacing: 0;
// TUN Mode
SettingItem {
label: "Tun 模式";
Switch {
checked: root.tun-enabled;
toggled(checked) => {
root.tun-toggled(checked);
}
}
}
Rectangle {
height: 1px;
background: Theme.colors.border.transparentize(0.6);
}
// System Proxy
SettingItem {
label: "系统代理";
Switch {
checked: root.proxy-enabled;
toggled(checked) => {
root.proxy-toggled(checked);
}
}
}
Rectangle {
height: 1px;
background: Theme.colors.border.transparentize(0.6);
}
// Proxy Port
SettingItem {
label: "代理端口";
But text: root.port;
variant: "link";
clicked => {
root.port-clicked();
}
}
}
}
}
}
component SettingItem {
in property <string> label: "";
height: 40px;
HorizontalLayout {
padding-left: 0;
padding-right: 0;
spacing: SpacingSystem.spacing.s3;
alignment: space-between;
HorizontalLayout {
spacing: SpacingSystem.spacing.s2;
Text {
text: "✓";
color: Theme.colors.muted-foreground;
font-size: Typography.sizes.sm;
vertical-alignment: center;
}
Text {
text: root.label;
color: Theme.colors.foreground;
font-size: Typography.sizes.sm;
vertical-alignment: center;
}
}
@children
}
}