feat: refine system specs screen layout
Build And Push Container / build-and-push (push) Successful in 56s
Build And Push Container / build-and-push (push) Successful in 56s
This commit is contained in:
@@ -177,7 +177,7 @@ fn run_display_session(state: &AppState, screen: &mut AooScreen) -> Result<()> {
|
||||
if send_due {
|
||||
if active_frame.image_name == SYSTEM_FRAME_NAME {
|
||||
let panel_name = SYSTEM_FRAME_NAME.to_string();
|
||||
let rgb_img = render_system_panel();
|
||||
let rgb_img = render_system_panel(&snapshot.specs_mode);
|
||||
prepare_screen_for_frame(screen, &active_frame);
|
||||
screen
|
||||
.send_image(&rgb_img)
|
||||
@@ -660,6 +660,7 @@ mod tests {
|
||||
custom_panel: true,
|
||||
switch_time: 7,
|
||||
specs_enabled: false,
|
||||
specs_mode: "cards".into(),
|
||||
memes_enabled: false,
|
||||
gifs_enabled: true,
|
||||
active_images: vec![manifest_name.into()],
|
||||
@@ -702,6 +703,7 @@ mod tests {
|
||||
custom_panel: true,
|
||||
switch_time: 7,
|
||||
specs_enabled: false,
|
||||
specs_mode: "cards".into(),
|
||||
memes_enabled: false,
|
||||
gifs_enabled: false,
|
||||
active_images: vec![manifest_name.into()],
|
||||
|
||||
@@ -32,6 +32,7 @@ pub(crate) async fn ensure_layout(state: &AppState) -> Result<()> {
|
||||
"language": 1,
|
||||
"switchTime": "10",
|
||||
"nativeSpecs": false,
|
||||
"nativeSpecsMode": "cards",
|
||||
"nativeMemes": true,
|
||||
"nativeGifs": true,
|
||||
"operationMode": 0,
|
||||
@@ -93,6 +94,7 @@ pub(crate) async fn build_state_response(state: &AppState) -> Result<StateRespon
|
||||
.unwrap_or("10")
|
||||
.to_string();
|
||||
let specs_enabled = current_specs_enabled(&monitor);
|
||||
let specs_mode = current_specs_mode(&monitor);
|
||||
let memes_enabled = current_memes_enabled(&monitor);
|
||||
let gifs_enabled = current_gifs_enabled(&monitor);
|
||||
|
||||
@@ -103,6 +105,7 @@ pub(crate) async fn build_state_response(state: &AppState) -> Result<StateRespon
|
||||
custom_panel,
|
||||
switch_time,
|
||||
specs_enabled,
|
||||
specs_mode,
|
||||
memes_enabled,
|
||||
gifs_enabled,
|
||||
},
|
||||
@@ -162,6 +165,16 @@ pub(crate) fn current_memes_enabled(monitor: &Value) -> bool {
|
||||
.unwrap_or_else(|| !current_active_images(monitor).is_empty())
|
||||
}
|
||||
|
||||
pub(crate) fn current_specs_mode(monitor: &Value) -> String {
|
||||
monitor
|
||||
.get("setup")
|
||||
.and_then(Value::as_object)
|
||||
.and_then(|setup| setup.get("nativeSpecsMode"))
|
||||
.and_then(Value::as_str)
|
||||
.map(normalize_specs_mode)
|
||||
.unwrap_or_else(|| "cards".into())
|
||||
}
|
||||
|
||||
pub(crate) fn current_gifs_enabled(monitor: &Value) -> bool {
|
||||
monitor
|
||||
.get("setup")
|
||||
@@ -176,6 +189,7 @@ pub(crate) fn rotation_snapshot(monitor: &Value) -> RotationSnapshot {
|
||||
custom_panel: current_custom_panel_enabled(monitor),
|
||||
switch_time: current_switch_time(monitor),
|
||||
specs_enabled: current_specs_enabled(monitor),
|
||||
specs_mode: current_specs_mode(monitor),
|
||||
memes_enabled: current_memes_enabled(monitor),
|
||||
gifs_enabled: current_gifs_enabled(monitor),
|
||||
active_images: current_active_images(monitor),
|
||||
@@ -186,6 +200,7 @@ pub(crate) fn set_custom_panels(
|
||||
monitor: &mut Value,
|
||||
switch_time: u32,
|
||||
specs_enabled: bool,
|
||||
specs_mode: &str,
|
||||
memes_enabled: bool,
|
||||
gifs_enabled: bool,
|
||||
images: &[String],
|
||||
@@ -201,6 +216,10 @@ pub(crate) fn set_custom_panels(
|
||||
setup.insert("customPanel".into(), Value::Bool(enabled));
|
||||
setup.insert("switchTime".into(), Value::String(switch_time.to_string()));
|
||||
setup.insert("nativeSpecs".into(), Value::Bool(specs_enabled));
|
||||
setup.insert(
|
||||
"nativeSpecsMode".into(),
|
||||
Value::String(normalize_specs_mode(specs_mode)),
|
||||
);
|
||||
setup.insert("nativeMemes".into(), Value::Bool(memes_enabled));
|
||||
setup.insert("nativeGifs".into(), Value::Bool(gifs_enabled));
|
||||
}
|
||||
@@ -218,6 +237,13 @@ pub(crate) fn set_custom_panels(
|
||||
);
|
||||
}
|
||||
|
||||
fn normalize_specs_mode(value: &str) -> String {
|
||||
match value {
|
||||
"meters" => "meters".into(),
|
||||
_ => "cards".into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn load_monitor_json_sync(path: &PathBuf) -> Result<Value> {
|
||||
let raw = std::fs::read_to_string(path)
|
||||
.with_context(|| format!("Failed to read {}", path.display()))?;
|
||||
|
||||
@@ -18,8 +18,8 @@ use crate::{
|
||||
},
|
||||
monitor::{
|
||||
build_state_response, current_active_images, current_gifs_enabled, current_memes_enabled,
|
||||
current_specs_enabled, current_switch_time, load_monitor_json, save_monitor_json,
|
||||
set_custom_panels,
|
||||
current_specs_enabled, current_specs_mode, current_switch_time, load_monitor_json,
|
||||
save_monitor_json, set_custom_panels,
|
||||
},
|
||||
types::{ActivateRequest, AppState, DeleteRequest, ErrorResponse},
|
||||
ui::index_response,
|
||||
@@ -103,6 +103,17 @@ async fn api_activate(
|
||||
) -> Response {
|
||||
let switch_time = payload.switch_time.unwrap_or(10).clamp(1, 600);
|
||||
let specs_enabled = payload.specs_enabled.unwrap_or(false);
|
||||
let specs_mode = payload
|
||||
.specs_mode
|
||||
.as_deref()
|
||||
.map(|value| {
|
||||
if value == "meters" {
|
||||
"meters".to_string()
|
||||
} else {
|
||||
"cards".to_string()
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| "cards".to_string());
|
||||
let available = match list_images(&state).await {
|
||||
Ok(items) => items,
|
||||
Err(err) => return error_response(StatusCode::INTERNAL_SERVER_ERROR, err.to_string()),
|
||||
@@ -140,6 +151,7 @@ async fn api_activate(
|
||||
&mut monitor,
|
||||
switch_time,
|
||||
specs_enabled,
|
||||
&specs_mode,
|
||||
memes_enabled,
|
||||
gifs_enabled,
|
||||
&valid,
|
||||
@@ -153,6 +165,7 @@ async fn api_activate(
|
||||
"ok": true,
|
||||
"switchTime": switch_time,
|
||||
"specsEnabled": specs_enabled,
|
||||
"specsMode": specs_mode,
|
||||
"memesEnabled": memes_enabled,
|
||||
"gifsEnabled": gifs_enabled,
|
||||
"activeImages": valid,
|
||||
@@ -167,11 +180,13 @@ async fn api_disable(State(state): State<Arc<AppState>>) -> Response {
|
||||
};
|
||||
let switch_time = current_switch_time(&monitor);
|
||||
let active_images = current_active_images(&monitor);
|
||||
let specs_mode = current_specs_mode(&monitor);
|
||||
|
||||
set_custom_panels(
|
||||
&mut monitor,
|
||||
switch_time,
|
||||
false,
|
||||
&specs_mode,
|
||||
false,
|
||||
false,
|
||||
&active_images,
|
||||
@@ -209,6 +224,7 @@ async fn api_delete(
|
||||
let mut active_images = current_active_images(&monitor);
|
||||
let switch_time = current_switch_time(&monitor);
|
||||
let specs_enabled = current_specs_enabled(&monitor);
|
||||
let specs_mode = current_specs_mode(&monitor);
|
||||
let memes_enabled = current_memes_enabled(&monitor);
|
||||
let gifs_enabled = current_gifs_enabled(&monitor);
|
||||
let before = active_images.len();
|
||||
@@ -218,6 +234,7 @@ async fn api_delete(
|
||||
&mut monitor,
|
||||
switch_time,
|
||||
specs_enabled,
|
||||
&specs_mode,
|
||||
memes_enabled,
|
||||
gifs_enabled,
|
||||
&active_images,
|
||||
|
||||
@@ -14,6 +14,13 @@ use crate::types::SystemView;
|
||||
pub(crate) const DISPLAY_WIDTH: u32 = 960;
|
||||
pub(crate) const DISPLAY_HEIGHT: u32 = 376;
|
||||
|
||||
pub(crate) fn normalize_specs_mode(mode: &str) -> &'static str {
|
||||
match mode {
|
||||
"meters" => "meters",
|
||||
_ => "cards",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn collect_system_view() -> SystemView {
|
||||
fn mount_usage(disks: &Disks, mount_point: &str) -> (String, String, String) {
|
||||
disks
|
||||
@@ -140,7 +147,14 @@ fn format_bytes(bytes: u64) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn render_system_panel() -> RgbImage {
|
||||
pub(crate) fn render_system_panel(mode: &str) -> RgbImage {
|
||||
match normalize_specs_mode(mode) {
|
||||
"meters" => render_system_panel_meters(),
|
||||
_ => render_system_panel_cards(),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_system_panel_cards() -> RgbImage {
|
||||
let system = collect_system_view();
|
||||
let mut canvas = RgbImage::from_pixel(DISPLAY_WIDTH, DISPLAY_HEIGHT, Rgb([10, 14, 18]));
|
||||
let host_name = System::host_name().unwrap_or_else(|| "Unraid".into());
|
||||
@@ -229,7 +243,10 @@ pub(crate) fn render_system_panel() -> RgbImage {
|
||||
236,
|
||||
"System",
|
||||
system.uptime.clone(),
|
||||
format!("{} CPU / {} proc", system.cpu_count, system.process_count),
|
||||
format!(
|
||||
"{} cores | {} procs",
|
||||
system.cpu_count, system.process_count
|
||||
),
|
||||
Rgb([216, 253, 114]),
|
||||
),
|
||||
];
|
||||
@@ -241,6 +258,109 @@ pub(crate) fn render_system_panel() -> RgbImage {
|
||||
canvas
|
||||
}
|
||||
|
||||
fn render_system_panel_meters() -> RgbImage {
|
||||
let system = collect_system_view();
|
||||
let mut canvas = RgbImage::from_pixel(DISPLAY_WIDTH, DISPLAY_HEIGHT, Rgb([9, 13, 17]));
|
||||
let host_name = System::host_name().unwrap_or_else(|| "Unraid".into());
|
||||
let timestamp = Local::now().format("%d.%m.%Y %H:%M:%S").to_string();
|
||||
|
||||
draw_filled_rect_mut(
|
||||
&mut canvas,
|
||||
Rect::at(0, 0).of_size(DISPLAY_WIDTH, 72),
|
||||
Rgb([15, 23, 30]),
|
||||
);
|
||||
draw_text_line(
|
||||
&mut canvas,
|
||||
Rgb([216, 253, 114]),
|
||||
26,
|
||||
18,
|
||||
32.0,
|
||||
"AOOSTAR System Monitor",
|
||||
);
|
||||
draw_text_line(
|
||||
&mut canvas,
|
||||
Rgb([146, 163, 181]),
|
||||
28,
|
||||
48,
|
||||
18.0,
|
||||
&format!("{host_name} | {timestamp}"),
|
||||
);
|
||||
|
||||
draw_meter_row(
|
||||
&mut canvas,
|
||||
26,
|
||||
102,
|
||||
"CPU",
|
||||
&format!("{}%", system.cpu_usage_percent),
|
||||
parse_metric_percent(&system.cpu_usage_percent),
|
||||
Rgb([110, 231, 183]),
|
||||
&format!(
|
||||
"Load {} / {} / {} {} cores {} procs",
|
||||
system.load_avg_one,
|
||||
system.load_avg_five,
|
||||
system.load_avg_fifteen,
|
||||
system.cpu_count,
|
||||
system.process_count
|
||||
),
|
||||
);
|
||||
draw_meter_row(
|
||||
&mut canvas,
|
||||
26,
|
||||
170,
|
||||
"RAM",
|
||||
&format!("{}%", system.mem_usage_percent),
|
||||
parse_metric_percent(&system.mem_usage_percent),
|
||||
Rgb([120, 189, 247]),
|
||||
&format!("{} / {}", system.mem_used, system.mem_total),
|
||||
);
|
||||
draw_meter_row(
|
||||
&mut canvas,
|
||||
26,
|
||||
238,
|
||||
"GPU",
|
||||
system.temperature_gpu.as_deref().unwrap_or("-"),
|
||||
normalize_temperature_bar(system.temperature_gpu.as_deref()),
|
||||
Rgb([241, 132, 121]),
|
||||
&format!(
|
||||
"Temp meter CPU {} Cache {}% User {}%",
|
||||
system.temperature_cpu.as_deref().unwrap_or("-"),
|
||||
system.cache_usage_percent,
|
||||
system.user_usage_percent
|
||||
),
|
||||
);
|
||||
|
||||
draw_filled_rect_mut(
|
||||
&mut canvas,
|
||||
Rect::at(26, 308).of_size(908, 42),
|
||||
Rgb([12, 18, 24]),
|
||||
);
|
||||
draw_hollow_rect_mut(
|
||||
&mut canvas,
|
||||
Rect::at(26, 308).of_size(908, 42),
|
||||
Rgb([31, 44, 58]),
|
||||
);
|
||||
draw_text_line(
|
||||
&mut canvas,
|
||||
Rgb([146, 163, 181]),
|
||||
42,
|
||||
321,
|
||||
18.0,
|
||||
&format!(
|
||||
"Swap {}% {} / {} Cache {} / {} User {} / {} Uptime {}",
|
||||
system.swap_usage_percent,
|
||||
system.swap_used,
|
||||
system.swap_total,
|
||||
system.cache_used,
|
||||
system.cache_total,
|
||||
system.user_used,
|
||||
system.user_total,
|
||||
system.uptime
|
||||
),
|
||||
);
|
||||
|
||||
canvas
|
||||
}
|
||||
|
||||
pub(crate) fn overlay_system_specs(canvas: &mut RgbImage) {
|
||||
let system = collect_system_view();
|
||||
let host_name = System::host_name().unwrap_or_else(|| "Unraid".into());
|
||||
@@ -309,6 +429,69 @@ pub(crate) fn overlay_system_specs(canvas: &mut RgbImage) {
|
||||
);
|
||||
}
|
||||
|
||||
fn draw_meter_row(
|
||||
canvas: &mut RgbImage,
|
||||
x: i32,
|
||||
y: i32,
|
||||
label: &str,
|
||||
value: &str,
|
||||
percent: f32,
|
||||
accent: Rgb<u8>,
|
||||
meta: &str,
|
||||
) {
|
||||
draw_text_line(canvas, accent, x, y, 19.0, label);
|
||||
draw_text_line(canvas, Rgb([237, 242, 247]), x + 112, y, 19.0, value);
|
||||
draw_meter_bar(canvas, x, y + 28, 840, 20, percent, accent);
|
||||
draw_text_line(canvas, Rgb([146, 163, 181]), x, y + 56, 17.0, meta);
|
||||
}
|
||||
|
||||
fn draw_meter_bar(
|
||||
canvas: &mut RgbImage,
|
||||
x: i32,
|
||||
y: i32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
percent: f32,
|
||||
accent: Rgb<u8>,
|
||||
) {
|
||||
draw_filled_rect_mut(
|
||||
canvas,
|
||||
Rect::at(x, y).of_size(width, height),
|
||||
Rgb([19, 27, 35]),
|
||||
);
|
||||
draw_hollow_rect_mut(
|
||||
canvas,
|
||||
Rect::at(x, y).of_size(width, height),
|
||||
Rgb([36, 50, 67]),
|
||||
);
|
||||
let fill_width =
|
||||
((width.saturating_sub(2)) as f32 * (percent.clamp(0.0, 100.0) / 100.0)).round() as u32;
|
||||
if fill_width > 0 {
|
||||
draw_filled_rect_mut(
|
||||
canvas,
|
||||
Rect::at(x + 1, y + 1).of_size(fill_width, height.saturating_sub(2)),
|
||||
accent,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_metric_percent(value: &str) -> f32 {
|
||||
value.parse::<f32>().unwrap_or(0.0)
|
||||
}
|
||||
|
||||
fn normalize_temperature_bar(value: Option<&str>) -> f32 {
|
||||
let Some(raw) = value else {
|
||||
return 0.0;
|
||||
};
|
||||
let numeric = raw
|
||||
.replace(" °C", "")
|
||||
.replace('C', "")
|
||||
.trim()
|
||||
.parse::<f32>()
|
||||
.unwrap_or(0.0);
|
||||
(numeric / 100.0 * 100.0).clamp(0.0, 100.0)
|
||||
}
|
||||
|
||||
fn draw_metric_card(
|
||||
canvas: &mut RgbImage,
|
||||
x: i32,
|
||||
|
||||
@@ -47,6 +47,7 @@ pub(crate) struct RotationSnapshot {
|
||||
pub(crate) custom_panel: bool,
|
||||
pub(crate) switch_time: u32,
|
||||
pub(crate) specs_enabled: bool,
|
||||
pub(crate) specs_mode: String,
|
||||
pub(crate) memes_enabled: bool,
|
||||
pub(crate) gifs_enabled: bool,
|
||||
pub(crate) active_images: Vec<String>,
|
||||
@@ -107,6 +108,7 @@ pub(crate) struct SetupView {
|
||||
pub(crate) custom_panel: bool,
|
||||
pub(crate) switch_time: String,
|
||||
pub(crate) specs_enabled: bool,
|
||||
pub(crate) specs_mode: String,
|
||||
pub(crate) memes_enabled: bool,
|
||||
pub(crate) gifs_enabled: bool,
|
||||
}
|
||||
@@ -173,6 +175,7 @@ pub(crate) struct ActivateRequest {
|
||||
pub(crate) images: Vec<String>,
|
||||
pub(crate) switch_time: Option<u32>,
|
||||
pub(crate) specs_enabled: Option<bool>,
|
||||
pub(crate) specs_mode: Option<String>,
|
||||
pub(crate) memes_enabled: Option<bool>,
|
||||
pub(crate) gifs_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
--surface: #10161d;
|
||||
--surface-2: #141b24;
|
||||
--surface-3: #0c1117;
|
||||
--surface-4: #172230;
|
||||
--line: #223042;
|
||||
--line-soft: #182333;
|
||||
--text: #eef3f8;
|
||||
@@ -37,6 +38,7 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
--faint: #667789;
|
||||
--accent: #6ee7b7;
|
||||
--accent-2: #b9f66a;
|
||||
--accent-3: #7ec8ff;
|
||||
--warn: #f6c65b;
|
||||
--danger: #f18479;
|
||||
--shadow: 0 18px 60px rgba(0, 0, 0, .28);
|
||||
@@ -130,6 +132,8 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid rgba(34, 48, 66, .72);
|
||||
}
|
||||
h2 {
|
||||
margin: 0;
|
||||
@@ -192,6 +196,15 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
flex-wrap: wrap;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.select-wrap select {
|
||||
min-height: 42px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--line);
|
||||
background: var(--surface-3);
|
||||
color: var(--text);
|
||||
padding: 10px 12px;
|
||||
font: inherit;
|
||||
}
|
||||
.toggle-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -221,6 +234,16 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
display: grid;
|
||||
align-content: space-between;
|
||||
background: rgba(16, 22, 30, .86);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.status::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0 auto 0 0;
|
||||
width: 3px;
|
||||
background: linear-gradient(180deg, var(--accent), var(--accent-3));
|
||||
opacity: .9;
|
||||
}
|
||||
.status span, .metric-label {
|
||||
color: var(--muted);
|
||||
@@ -244,6 +267,7 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
.metric-card {
|
||||
min-height: 104px;
|
||||
border-left: 3px solid var(--accent);
|
||||
background: linear-gradient(180deg, rgba(17, 24, 32, .98), rgba(12, 17, 24, .98));
|
||||
}
|
||||
.metric-card:nth-child(2) { border-left-color: #78bdf7; }
|
||||
.metric-card:nth-child(3) { border-left-color: var(--warn); }
|
||||
@@ -376,13 +400,31 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
}
|
||||
.nyan-wrap {
|
||||
position: fixed;
|
||||
right: 14px;
|
||||
bottom: 10px;
|
||||
width: 132px;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
width: 184px;
|
||||
pointer-events: none;
|
||||
z-index: 30;
|
||||
opacity: .42;
|
||||
filter: drop-shadow(0 8px 14px rgba(0, 0, 0, .26));
|
||||
opacity: .92;
|
||||
padding: 10px 12px 8px;
|
||||
border: 1px solid rgba(126, 200, 255, .22);
|
||||
border-radius: 8px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(15, 22, 30, .88), rgba(10, 15, 22, .72));
|
||||
box-shadow:
|
||||
0 16px 36px rgba(0, 0, 0, .28),
|
||||
inset 0 0 0 1px rgba(110, 231, 183, .08);
|
||||
filter: drop-shadow(0 10px 18px rgba(0, 0, 0, .22));
|
||||
}
|
||||
.nyan-wrap::before {
|
||||
content: "UI mascot";
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
color: var(--muted);
|
||||
font-size: .68rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.nyan-wrap img {
|
||||
display: block;
|
||||
@@ -406,7 +448,8 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
.gallery { grid-template-columns: 1fr; }
|
||||
.order-item { grid-template-columns: 28px minmax(0, 1fr); }
|
||||
.order-item .mini { grid-column: 2; }
|
||||
.nyan-wrap { width: 96px; opacity: .32; }
|
||||
.nyan-wrap { width: 128px; right: 10px; bottom: 10px; opacity: .78; padding: 8px; }
|
||||
.nyan-wrap::before { margin-bottom: 4px; font-size: .62rem; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -452,12 +495,21 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
<button id="disable" class="danger" type="button">Disable</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<label class="toggle-pill"><input id="specsEnabled" type="checkbox"> System Specs</label>
|
||||
<label class="toggle-pill"><input id="memesEnabled" type="checkbox"> Memes</label>
|
||||
<label class="toggle-pill"><input id="gifsEnabled" type="checkbox"> GIFs</label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<label class="toggle-pill"><input id="specsEnabled" type="checkbox"> System Specs</label>
|
||||
<label class="toggle-pill"><input id="memesEnabled" type="checkbox"> Memes</label>
|
||||
<label class="toggle-pill"><input id="gifsEnabled" type="checkbox"> GIFs</label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<label class="select-wrap">
|
||||
<span>Screen Layout</span>
|
||||
<select id="specsMode">
|
||||
<option value="cards">Cards</option>
|
||||
<option value="meters">Meters</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="status-grid">
|
||||
@@ -521,7 +573,7 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
const state = {
|
||||
images: [],
|
||||
activeImages: [],
|
||||
setup: { switch_time: "10", custom_panel: false, specs_enabled: false, memes_enabled: false, gifs_enabled: true },
|
||||
setup: { switch_time: "10", custom_panel: false, specs_enabled: false, specs_mode: "cards", memes_enabled: false, gifs_enabled: true },
|
||||
display: {},
|
||||
system: {},
|
||||
activeTab: "screen-control",
|
||||
@@ -534,6 +586,7 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
tabPanels: Array.from(document.querySelectorAll("[data-tab-panel]")),
|
||||
switchTime: document.getElementById("switchTime"),
|
||||
specsEnabled: document.getElementById("specsEnabled"),
|
||||
specsMode: document.getElementById("specsMode"),
|
||||
memesEnabled: document.getElementById("memesEnabled"),
|
||||
gifsEnabled: document.getElementById("gifsEnabled"),
|
||||
customPanelValue: document.getElementById("customPanelValue"),
|
||||
@@ -677,6 +730,7 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
...data.setup,
|
||||
switch_time: el.switchTime.value || data.setup.switch_time || "10",
|
||||
specs_enabled: el.specsEnabled.checked,
|
||||
specs_mode: el.specsMode.value || data.setup.specs_mode || "cards",
|
||||
memes_enabled: el.memesEnabled.checked,
|
||||
gifs_enabled: el.gifsEnabled.checked,
|
||||
}
|
||||
@@ -686,6 +740,7 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
if (!preserveDraft) {
|
||||
el.switchTime.value = data.setup.switch_time || "10";
|
||||
el.specsEnabled.checked = !!data.setup.specs_enabled;
|
||||
el.specsMode.value = data.setup.specs_mode || "cards";
|
||||
el.memesEnabled.checked = !!data.setup.memes_enabled;
|
||||
el.gifsEnabled.checked = data.setup.gifs_enabled !== false;
|
||||
}
|
||||
@@ -712,8 +767,8 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
el.diskMetaValue.textContent = `${state.system.cache_used || "-"} / ${state.system.cache_total || "-"} | ${state.system.user_used || "-"} / ${state.system.user_total || "-"}`;
|
||||
el.swapUsageValue.textContent = `${state.system.swap_usage_percent || "-"} %`;
|
||||
el.swapMetaValue.textContent = `${state.system.swap_used || "-"} / ${state.system.swap_total || "-"}`;
|
||||
el.loadValue.textContent = `${state.system.cpu_count || "-"} CPU / ${state.system.process_count || "-"} proc`;
|
||||
el.uptimeValue.textContent = `Uptime ${state.system.uptime || "-"}`;
|
||||
el.loadValue.textContent = `${state.system.load_avg_one || "-"} / ${state.system.load_avg_five || "-"} / ${state.system.load_avg_fifteen || "-"}`;
|
||||
el.uptimeValue.textContent = `${state.system.cpu_count || "-"} cores • ${state.system.process_count || "-"} procs • Uptime ${state.system.uptime || "-"}`;
|
||||
el.tempCpuValue.textContent = `CPU ${state.system.temperature_cpu || "-"}`;
|
||||
el.tempGpuValue.textContent = `GPU ${state.system.temperature_gpu || "-"}`;
|
||||
el.displayStatusMirror.textContent = el.displayStatusValue.textContent;
|
||||
@@ -745,6 +800,7 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
images: state.activeImages,
|
||||
switch_time: Number.parseInt(el.switchTime.value || "10", 10),
|
||||
specs_enabled: el.specsEnabled.checked,
|
||||
specs_mode: el.specsMode.value,
|
||||
memes_enabled: el.memesEnabled.checked,
|
||||
gifs_enabled: el.gifsEnabled.checked,
|
||||
}),
|
||||
@@ -869,6 +925,7 @@ const INDEX_HTML: &str = r##"<!DOCTYPE html>
|
||||
});
|
||||
el.switchTime.addEventListener("change", markDirty);
|
||||
el.specsEnabled.addEventListener("change", markDirty);
|
||||
el.specsMode.addEventListener("change", markDirty);
|
||||
el.memesEnabled.addEventListener("change", markDirty);
|
||||
el.gifsEnabled.addEventListener("change", markDirty);
|
||||
el.tabButtons.forEach((button) => {
|
||||
|
||||
Reference in New Issue
Block a user