pinakes-ui: restyle tasks and statistics components with icons
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ib7e4888602163f828f8aaa9bce2bc5e66a6a6964
This commit is contained in:
parent
3595f89fec
commit
445281ea5a
3 changed files with 367 additions and 261 deletions
|
|
@ -1,4 +1,8 @@
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_free_icons::Icon;
|
||||||
|
use dioxus_free_icons::icons::fa_solid_icons::{
|
||||||
|
FaChartBar, FaCircle, FaClock, FaDatabase, FaFolder, FaLink, FaTags,
|
||||||
|
};
|
||||||
|
|
||||||
use super::utils::format_size;
|
use super::utils::format_size;
|
||||||
use crate::client::LibraryStatisticsResponse;
|
use crate::client::LibraryStatisticsResponse;
|
||||||
|
|
@ -10,184 +14,228 @@ pub fn Statistics(
|
||||||
on_refresh: EventHandler<()>,
|
on_refresh: EventHandler<()>,
|
||||||
) -> Element {
|
) -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "card mb-16",
|
div { class: "statistics-page",
|
||||||
div { class: "card-header",
|
div { class: "card",
|
||||||
h3 { class: "card-title", "Library Statistics" }
|
div { class: "card-header",
|
||||||
button {
|
h3 { class: "card-title", "Library Statistics" }
|
||||||
class: "btn btn-sm btn-secondary",
|
|
||||||
onclick: move |_| on_refresh.call(()),
|
|
||||||
"\u{21bb} Refresh"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ref err) = error {
|
|
||||||
div { class: "alert alert-error mb-8",
|
|
||||||
span { "{err}" }
|
|
||||||
button {
|
button {
|
||||||
class: "btn btn-sm btn-secondary ml-8",
|
class: "btn btn-sm btn-secondary",
|
||||||
onclick: move |_| on_refresh.call(()),
|
onclick: move |_| on_refresh.call(()),
|
||||||
"Retry"
|
"\u{21bb} Refresh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
match stats.as_ref() {
|
if let Some(ref err) = error {
|
||||||
Some(s) => {
|
div { class: "alert alert-error mb-8",
|
||||||
let total_size = format_size(s.total_size_bytes);
|
span { "{err}" }
|
||||||
let avg_size = format_size(s.avg_file_size_bytes);
|
button {
|
||||||
rsx! {
|
class: "btn btn-sm btn-secondary ml-8",
|
||||||
// Overview
|
onclick: move |_| on_refresh.call(()),
|
||||||
div { class: "stats-grid",
|
"Retry"
|
||||||
div { class: "stat-card",
|
|
||||||
div { class: "stat-value", "{s.total_media}" }
|
|
||||||
div { class: "stat-label", "Total Media" }
|
|
||||||
}
|
|
||||||
div { class: "stat-card",
|
|
||||||
div { class: "stat-value", "{total_size}" }
|
|
||||||
div { class: "stat-label", "Total Size" }
|
|
||||||
}
|
|
||||||
div { class: "stat-card",
|
|
||||||
div { class: "stat-value", "{avg_size}" }
|
|
||||||
div { class: "stat-label", "Avg File Size" }
|
|
||||||
}
|
|
||||||
div { class: "stat-card",
|
|
||||||
div { class: "stat-value", "{s.total_tags}" }
|
|
||||||
div { class: "stat-label", "Tags" }
|
|
||||||
}
|
|
||||||
div { class: "stat-card",
|
|
||||||
div { class: "stat-value", "{s.total_collections}" }
|
|
||||||
div { class: "stat-label", "Collections" }
|
|
||||||
}
|
|
||||||
div { class: "stat-card",
|
|
||||||
div { class: "stat-value", "{s.total_duplicates}" }
|
|
||||||
div { class: "stat-label", "Duplicate Hashes" }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Media by Type
|
match stats.as_ref() {
|
||||||
|
Some(s) => {
|
||||||
|
let total_size = format_size(s.total_size_bytes);
|
||||||
|
let avg_size = format_size(s.avg_file_size_bytes);
|
||||||
|
rsx! {
|
||||||
|
div { class: "stats-overview",
|
||||||
|
div { class: "stat-card stat-primary",
|
||||||
|
div { class: "stat-icon",
|
||||||
|
Icon { icon: FaFolder, width: 20, height: 20 }
|
||||||
|
}
|
||||||
|
div { class: "stat-content",
|
||||||
|
div { class: "stat-value", "{s.total_media}" }
|
||||||
|
div { class: "stat-label", "Total Media" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "stat-card stat-success",
|
||||||
|
div { class: "stat-icon",
|
||||||
|
Icon { icon: FaDatabase, width: 20, height: 20 }
|
||||||
|
}
|
||||||
|
div { class: "stat-content",
|
||||||
|
div { class: "stat-value", "{total_size}" }
|
||||||
|
div { class: "stat-label", "Total Size" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "stat-card stat-info",
|
||||||
|
div { class: "stat-icon",
|
||||||
|
Icon { icon: FaChartBar, width: 20, height: 20 }
|
||||||
|
}
|
||||||
|
div { class: "stat-content",
|
||||||
|
div { class: "stat-value", "{avg_size}" }
|
||||||
|
div { class: "stat-label", "Average Size" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "stat-card stat-warning",
|
||||||
|
div { class: "stat-icon",
|
||||||
|
Icon { icon: FaTags, width: 20, height: 20 }
|
||||||
|
}
|
||||||
|
div { class: "stat-content",
|
||||||
|
div { class: "stat-value", "{s.total_tags}" }
|
||||||
|
div { class: "stat-label", "Tags" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "stat-card stat-purple",
|
||||||
|
div { class: "stat-icon",
|
||||||
|
Icon { icon: FaCircle, width: 20, height: 20 }
|
||||||
|
}
|
||||||
|
div { class: "stat-content",
|
||||||
|
div { class: "stat-value", "{s.total_collections}" }
|
||||||
|
div { class: "stat-label", "Collections" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "stat-card stat-danger",
|
||||||
|
div { class: "stat-icon",
|
||||||
|
Icon { icon: FaLink, width: 20, height: 20 }
|
||||||
|
}
|
||||||
|
div { class: "stat-content",
|
||||||
|
div { class: "stat-value", "{s.total_duplicates}" }
|
||||||
|
div { class: "stat-label", "Duplicates" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Storage by Type
|
if !s.media_by_type.is_empty() {
|
||||||
|
{
|
||||||
|
let max_count = s.media_by_type.iter().map(|i| i.count).max().unwrap_or(1) as f64;
|
||||||
|
|
||||||
// Top Tags
|
rsx! {
|
||||||
|
div { class: "stats-section",
|
||||||
// Top Collections
|
h4 { class: "section-title",
|
||||||
|
Icon { icon: FaChartBar, width: 16, height: 16, style: "margin-right: 8px; vertical-align: middle;" }
|
||||||
// Date Range
|
"Media by Type"
|
||||||
|
}
|
||||||
|
div { class: "chart-bars",
|
||||||
|
for item in s.media_by_type.iter() {
|
||||||
|
{
|
||||||
|
let percentage = (item.count as f64 / max_count) * 100.0;
|
||||||
|
let name = item.name.clone();
|
||||||
|
let count = item.count;
|
||||||
if !s.media_by_type.is_empty() {
|
rsx! {
|
||||||
div { class: "card mt-16",
|
div { key: "{name}", class: "bar-item",
|
||||||
h4 { class: "card-title", "Media by Type" }
|
div { class: "bar-label", "{name}" }
|
||||||
table { class: "table",
|
div { class: "bar-track",
|
||||||
thead {
|
div {
|
||||||
tr {
|
class: "bar-fill bar-primary",
|
||||||
th { "Type" }
|
style: "width: {percentage}%",
|
||||||
th { "Count" }
|
}
|
||||||
|
}
|
||||||
|
div { class: "bar-value", "{count}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tbody {
|
}
|
||||||
for item in s.media_by_type.iter() {
|
}
|
||||||
tr {
|
}
|
||||||
td { "{item.name}" }
|
|
||||||
td { "{item.count}" }
|
if !s.storage_by_type.is_empty() {
|
||||||
|
{
|
||||||
|
let max_size = s.storage_by_type.iter().map(|i| i.count).max().unwrap_or(1) as f64;
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div { class: "stats-section",
|
||||||
|
h4 { class: "section-title",
|
||||||
|
Icon { icon: FaDatabase, width: 16, height: 16, style: "margin-right: 8px; vertical-align: middle;" }
|
||||||
|
"Storage by Type"
|
||||||
|
}
|
||||||
|
div { class: "chart-bars",
|
||||||
|
for item in s.storage_by_type.iter() {
|
||||||
|
{
|
||||||
|
let percentage = (item.count as f64 / max_size) * 100.0;
|
||||||
|
let name = item.name.clone();
|
||||||
|
let size_str = format_size(item.count);
|
||||||
|
rsx! {
|
||||||
|
div { key: "{name}", class: "bar-item",
|
||||||
|
div { class: "bar-label", "{name}" }
|
||||||
|
div { class: "bar-track",
|
||||||
|
div {
|
||||||
|
class: "bar-fill bar-success",
|
||||||
|
style: "width: {percentage}%",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "bar-value", "{size_str}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !s.storage_by_type.is_empty() {
|
if !s.top_tags.is_empty() {
|
||||||
div { class: "card mt-16",
|
div { class: "stats-section",
|
||||||
h4 { class: "card-title", "Storage by Type" }
|
h4 { class: "section-title",
|
||||||
table { class: "table",
|
Icon { icon: FaTags, width: 16, height: 16, style: "margin-right: 8px; vertical-align: middle;" }
|
||||||
thead {
|
"Top Tags"
|
||||||
tr {
|
|
||||||
th { "Type" }
|
|
||||||
th { "Size" }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tbody {
|
div { class: "tag-list",
|
||||||
for item in s.storage_by_type.iter() {
|
|
||||||
tr {
|
|
||||||
td { "{item.name}" }
|
|
||||||
td { "{format_size(item.count)}" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !s.top_tags.is_empty() {
|
|
||||||
div { class: "card mt-16",
|
|
||||||
h4 { class: "card-title", "Top Tags" }
|
|
||||||
table { class: "table",
|
|
||||||
thead {
|
|
||||||
tr {
|
|
||||||
th { "Tag" }
|
|
||||||
th { "Count" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tbody {
|
|
||||||
for item in s.top_tags.iter() {
|
for item in s.top_tags.iter() {
|
||||||
tr {
|
div { class: "tag-item",
|
||||||
td { "{item.name}" }
|
span { class: "tag-badge", "{item.name}" }
|
||||||
td { "{item.count}" }
|
span { class: "tag-count", "{item.count}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !s.top_collections.is_empty() {
|
if !s.top_collections.is_empty() {
|
||||||
div { class: "card mt-16",
|
div { class: "stats-section",
|
||||||
h4 { class: "card-title", "Top Collections" }
|
h4 { class: "section-title",
|
||||||
table { class: "table",
|
Icon { icon: FaCircle, width: 16, height: 16, style: "margin-right: 8px; vertical-align: middle;" }
|
||||||
thead {
|
"Top Collections"
|
||||||
tr {
|
|
||||||
th { "Collection" }
|
|
||||||
th { "Members" }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tbody {
|
div { class: "collection-list",
|
||||||
for item in s.top_collections.iter() {
|
for item in s.top_collections.iter() {
|
||||||
tr {
|
div { class: "collection-item",
|
||||||
td { "{item.name}" }
|
Icon { icon: FaFolder, width: 16, height: 16, class: "collection-icon" }
|
||||||
td { "{item.count}" }
|
span { class: "collection-name", "{item.name}" }
|
||||||
|
span { class: "collection-count", "{item.count}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
div { class: "card mt-16",
|
div { class: "stats-section",
|
||||||
h4 { class: "card-title", "Date Range" }
|
h4 { class: "section-title",
|
||||||
div { class: "stats-grid",
|
Icon { icon: FaClock, width: 16, height: 16, style: "margin-right: 8px; vertical-align: middle;" }
|
||||||
div { class: "stat-card",
|
"Date Range"
|
||||||
div { class: "stat-value", "{s.oldest_item.as_deref().unwrap_or(\"N/A\")}" }
|
|
||||||
div { class: "stat-label", "Oldest Item" }
|
|
||||||
}
|
}
|
||||||
div { class: "stat-card",
|
div { class: "date-range",
|
||||||
div { class: "stat-value", "{s.newest_item.as_deref().unwrap_or(\"N/A\")}" }
|
div { class: "date-item",
|
||||||
div { class: "stat-label", "Newest Item" }
|
Icon { icon: FaClock, width: 16, height: 16 }
|
||||||
|
div { class: "date-content",
|
||||||
|
div { class: "date-label", "Oldest Item" }
|
||||||
|
div { class: "date-value", "{s.oldest_item.as_deref().unwrap_or(\"N/A\")}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "date-item",
|
||||||
|
Icon { icon: FaClock, width: 16, height: 16 }
|
||||||
|
div { class: "date-content",
|
||||||
|
div { class: "date-label", "Newest Item" }
|
||||||
|
div { class: "date-value", "{s.newest_item.as_deref().unwrap_or(\"N/A\")}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None => rsx! {
|
||||||
|
div { class: "empty-state",
|
||||||
|
div { class: "spinner" }
|
||||||
|
p { "Loading statistics..." }
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
None => rsx! {
|
|
||||||
div { class: "empty-state",
|
|
||||||
p { "Loading statistics..." }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_free_icons::Icon;
|
||||||
|
use dioxus_free_icons::icons::fa_solid_icons::{
|
||||||
|
FaArrowsRotate, FaCalendar, FaCircleCheck, FaClock, FaPause, FaPlay,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::client::ScheduledTaskResponse;
|
use crate::client::ScheduledTaskResponse;
|
||||||
|
|
||||||
|
|
@ -11,80 +15,134 @@ pub fn Tasks(
|
||||||
on_run_now: EventHandler<String>,
|
on_run_now: EventHandler<String>,
|
||||||
) -> Element {
|
) -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "card mb-16",
|
div { class: "tasks-container",
|
||||||
div { class: "card-header",
|
div { class: "card mb-16",
|
||||||
h3 { class: "card-title", "Scheduled Tasks" }
|
div { class: "card-header",
|
||||||
button {
|
h3 { class: "card-title", "Scheduled Tasks" }
|
||||||
class: "btn btn-sm btn-secondary",
|
|
||||||
onclick: move |_| on_refresh.call(()),
|
|
||||||
"\u{21bb} Refresh"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ref err) = error {
|
|
||||||
div { class: "alert alert-error mb-8",
|
|
||||||
span { "{err}" }
|
|
||||||
button {
|
button {
|
||||||
class: "btn btn-sm btn-secondary ml-8",
|
class: "btn btn-sm btn-secondary",
|
||||||
onclick: move |_| on_refresh.call(()),
|
onclick: move |_| on_refresh.call(()),
|
||||||
"Retry"
|
Icon { icon: FaArrowsRotate, width: 14, height: 14 }
|
||||||
|
" Refresh"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if tasks.is_empty() {
|
if let Some(ref err) = error {
|
||||||
div { class: "empty-state",
|
div { class: "alert alert-error mb-8",
|
||||||
p { "No scheduled tasks configured." }
|
span { "{err}" }
|
||||||
}
|
button {
|
||||||
} else {
|
class: "btn btn-sm btn-secondary ml-8",
|
||||||
table { class: "table",
|
onclick: move |_| on_refresh.call(()),
|
||||||
thead {
|
"Retry"
|
||||||
tr {
|
|
||||||
th { "Enabled" }
|
|
||||||
th { "Name" }
|
|
||||||
th { "Schedule" }
|
|
||||||
th { "Last Run" }
|
|
||||||
th { "Next Run" }
|
|
||||||
th { "Status" }
|
|
||||||
th { "Actions" }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tbody {
|
}
|
||||||
|
|
||||||
|
if tasks.is_empty() {
|
||||||
|
div { class: "empty-state",
|
||||||
|
div { class: "empty-icon",
|
||||||
|
Icon { icon: FaCalendar, width: 48, height: 48 }
|
||||||
|
}
|
||||||
|
p { "No scheduled tasks configured." }
|
||||||
|
p { class: "text-muted", "Tasks will appear here once configured on the server." }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
div { class: "tasks-grid",
|
||||||
for task in tasks.iter() {
|
for task in tasks.iter() {
|
||||||
{
|
{
|
||||||
let task_id_toggle = task.id.clone();
|
let task_id_toggle = task.id.clone();
|
||||||
let task_id_run = task.id.clone();
|
let task_id_run = task.id.clone();
|
||||||
let last_run = task.last_run.clone().unwrap_or_else(|| "-".to_string());
|
let last_run = task.last_run.clone().unwrap_or_else(|| "Never".to_string());
|
||||||
let next_run = task.next_run.clone().unwrap_or_else(|| "-".to_string());
|
let next_run = task.next_run.clone().unwrap_or_else(|| "Not scheduled".to_string());
|
||||||
let last_status = task.last_status.clone().unwrap_or_else(|| "-".to_string());
|
let last_status = task.last_status.clone().unwrap_or_else(|| "No runs yet".to_string());
|
||||||
|
let is_enabled = task.enabled;
|
||||||
|
let task_name = task.name.clone();
|
||||||
|
let schedule = task.schedule.clone();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
tr {
|
div {
|
||||||
td {
|
class: if is_enabled { "task-card task-card-enabled" } else { "task-card task-card-disabled" },
|
||||||
if task.enabled {
|
|
||||||
span { class: "badge badge-success", "\u{2713}" }
|
// Header with status and actions
|
||||||
} else {
|
div { class: "task-card-header",
|
||||||
span { class: "badge badge-muted", "\u{2715}" }
|
div { class: "task-header-left",
|
||||||
|
div { class: "task-name", "{task_name}" }
|
||||||
|
div { class: "task-schedule",
|
||||||
|
span { class: "schedule-icon",
|
||||||
|
Icon { icon: FaClock, width: 14, height: 14 }
|
||||||
|
}
|
||||||
|
"{schedule}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "task-status-badge",
|
||||||
|
if is_enabled {
|
||||||
|
span { class: "status-badge status-enabled",
|
||||||
|
span { class: "status-dot" }
|
||||||
|
"Active"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
span { class: "status-badge status-disabled",
|
||||||
|
span { class: "status-dot" }
|
||||||
|
"Disabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
td { "{task.name}" }
|
|
||||||
td { "{task.schedule}" }
|
// Task info grid
|
||||||
td { "{last_run}" }
|
div { class: "task-info-grid",
|
||||||
td { "{next_run}" }
|
div { class: "task-info-item",
|
||||||
td { "{last_status}" }
|
div { class: "task-info-icon",
|
||||||
td {
|
Icon { icon: FaClock, width: 16, height: 16 }
|
||||||
|
}
|
||||||
|
div { class: "task-info-content",
|
||||||
|
div { class: "task-info-label", "Last Run" }
|
||||||
|
div { class: "task-info-value", "{last_run}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "task-info-item",
|
||||||
|
div { class: "task-info-icon",
|
||||||
|
Icon { icon: FaClock, width: 16, height: 16 }
|
||||||
|
}
|
||||||
|
div { class: "task-info-content",
|
||||||
|
div { class: "task-info-label", "Next Run" }
|
||||||
|
div { class: "task-info-value", "{next_run}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "task-info-item",
|
||||||
|
div { class: "task-info-icon",
|
||||||
|
Icon { icon: FaCircleCheck, width: 16, height: 16 }
|
||||||
|
}
|
||||||
|
div { class: "task-info-content",
|
||||||
|
div { class: "task-info-label", "Last Status" }
|
||||||
|
div { class: "task-info-value", "{last_status}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
div { class: "task-card-actions",
|
||||||
button {
|
button {
|
||||||
class: "btn btn-sm btn-secondary mr-8",
|
class: if is_enabled { "btn btn-sm btn-secondary" } else { "btn btn-sm btn-primary" },
|
||||||
onclick: move |_| on_toggle.call(task_id_toggle.clone()),
|
onclick: move |_| on_toggle.call(task_id_toggle.clone()),
|
||||||
if task.enabled {
|
if is_enabled {
|
||||||
"Disable"
|
span {
|
||||||
|
Icon { icon: FaPause, width: 14, height: 14 }
|
||||||
|
" Disable"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
"Enable"
|
span {
|
||||||
|
Icon { icon: FaPlay, width: 14, height: 14 }
|
||||||
|
" Enable"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
class: "btn btn-sm btn-primary",
|
class: "btn btn-sm btn-primary",
|
||||||
onclick: move |_| on_run_now.call(task_id_run.clone()),
|
onclick: move |_| on_run_now.call(task_id_run.clone()),
|
||||||
"Run Now"
|
disabled: !is_enabled,
|
||||||
|
Icon { icon: FaPlay, width: 14, height: 14 }
|
||||||
|
" Run Now"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ body {
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Layout ── */
|
/* Layout */
|
||||||
.app {
|
.app {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|
@ -233,7 +233,7 @@ body {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Table ── */
|
/* Table */
|
||||||
.data-table {
|
.data-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
|
|
@ -282,7 +282,7 @@ body {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Buttons ── */
|
/* Buttons */
|
||||||
.btn {
|
.btn {
|
||||||
padding: 5px 12px;
|
padding: 5px 12px;
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
|
|
@ -349,7 +349,7 @@ body {
|
||||||
}
|
}
|
||||||
.btn-icon:hover { color: var(--text-0); }
|
.btn-icon:hover { color: var(--text-0); }
|
||||||
|
|
||||||
/* ── Cards ── */
|
/* Cards */
|
||||||
.card {
|
.card {
|
||||||
background: var(--bg-2);
|
background: var(--bg-2);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
|
|
@ -369,7 +369,7 @@ body {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Forms ── */
|
/* Forms */
|
||||||
input[type="text"], textarea, select {
|
input[type="text"], textarea, select {
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
|
|
@ -412,7 +412,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Toast ── */
|
/* Toast */
|
||||||
.toast {
|
.toast {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
|
|
@ -437,7 +437,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
to { opacity: 1; transform: translateY(0); }
|
to { opacity: 1; transform: translateY(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Detail ── */
|
/* Detail */
|
||||||
.detail-actions {
|
.detail-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|
@ -482,7 +482,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
color: var(--text-1);
|
color: var(--text-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Stats ── */
|
/* Stats */
|
||||||
.statistics-page {
|
.statistics-page {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
@ -692,7 +692,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
|
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Tasks ── */
|
/* Tasks */
|
||||||
.tasks-grid {
|
.tasks-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
|
||||||
|
|
@ -875,7 +875,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
.type-text { background: rgba(200, 160, 36, 0.1); color: #c4a840; }
|
.type-text { background: rgba(200, 160, 36, 0.1); color: #c4a840; }
|
||||||
.type-other { background: rgba(128, 128, 160, 0.08); color: var(--text-2); }
|
.type-other { background: rgba(128, 128, 160, 0.08); color: var(--text-2); }
|
||||||
|
|
||||||
/* ── Tags ── */
|
/* Tags */
|
||||||
.tag-list { display: flex; flex-wrap: wrap; gap: 4px; }
|
.tag-list { display: flex; flex-wrap: wrap; gap: 4px; }
|
||||||
|
|
||||||
.tag-badge {
|
.tag-badge {
|
||||||
|
|
@ -909,7 +909,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Empty state ── */
|
/* Empty state */
|
||||||
.empty-state {
|
.empty-state {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 48px 16px;
|
padding: 48px 16px;
|
||||||
|
|
@ -936,7 +936,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Settings ── */
|
/* Settings */
|
||||||
.settings-section { margin-bottom: 24px; }
|
.settings-section { margin-bottom: 24px; }
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
|
|
@ -1016,7 +1016,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
.info-label { color: var(--text-1); font-weight: 500; }
|
.info-label { color: var(--text-1); font-weight: 500; }
|
||||||
.info-value { color: var(--text-0); }
|
.info-value { color: var(--text-0); }
|
||||||
|
|
||||||
/* ── Scrollbar ── */
|
/* Scrollbar */
|
||||||
::-webkit-scrollbar { width: 5px; height: 5px; }
|
::-webkit-scrollbar { width: 5px; height: 5px; }
|
||||||
::-webkit-scrollbar-track { background: transparent; }
|
::-webkit-scrollbar-track { background: transparent; }
|
||||||
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; }
|
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; }
|
||||||
|
|
@ -1032,7 +1032,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
scrollbar-color: rgba(255,255,255,0.08) transparent;
|
scrollbar-color: rgba(255,255,255,0.08) transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Import Tabs ── */
|
/* Import Tabs */
|
||||||
.import-tabs {
|
.import-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
|
|
@ -1061,7 +1061,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
border-bottom-color: var(--accent);
|
border-bottom-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Batch Actions ── */
|
/* Batch Actions */
|
||||||
.batch-actions {
|
.batch-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1076,13 +1076,13 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
color: var(--accent-text);
|
color: var(--accent-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Action badges (audit) ── */
|
/* Action badges (audit) */
|
||||||
.action-danger {
|
.action-danger {
|
||||||
background: rgba(228, 88, 88, 0.1);
|
background: rgba(228, 88, 88, 0.1);
|
||||||
color: #d47070;
|
color: #d47070;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Tag hierarchy ── */
|
/* Tag hierarchy */
|
||||||
.tag-group {
|
.tag-group {
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
@ -1095,7 +1095,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Detail field inputs ── */
|
/* Detail field inputs */
|
||||||
.detail-field input[type="text"],
|
.detail-field input[type="text"],
|
||||||
.detail-field textarea,
|
.detail-field textarea,
|
||||||
.detail-field select {
|
.detail-field select {
|
||||||
|
|
@ -1108,7 +1108,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Checkbox ── */
|
/* Checkbox */
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
|
|
@ -1192,7 +1192,7 @@ input[type="number"]:focus {
|
||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Select ── */
|
/* Select */
|
||||||
select {
|
select {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
|
|
@ -1203,7 +1203,7 @@ select {
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Code ── */
|
/* Code */
|
||||||
code {
|
code {
|
||||||
padding: 1px 5px;
|
padding: 1px 5px;
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
|
|
@ -1216,7 +1216,7 @@ code {
|
||||||
ul { list-style: none; padding: 0; }
|
ul { list-style: none; padding: 0; }
|
||||||
ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
|
|
||||||
/* ── Status indicator ── */
|
/* Status indicator */
|
||||||
.status-indicator {
|
.status-indicator {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1262,7 +1262,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Modal ── */
|
/* Modal */
|
||||||
.modal-overlay {
|
.modal-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|
@ -1308,7 +1308,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Saved Searches ── */
|
/* Saved Searches */
|
||||||
.saved-searches-list {
|
.saved-searches-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -1363,7 +1363,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Offline banner ── */
|
/* Offline banner */
|
||||||
.offline-banner {
|
.offline-banner {
|
||||||
background: rgba(228, 88, 88, 0.06);
|
background: rgba(228, 88, 88, 0.06);
|
||||||
border: 1px solid rgba(228, 88, 88, 0.2);
|
border: 1px solid rgba(228, 88, 88, 0.2);
|
||||||
|
|
@ -1382,7 +1382,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Utility ── */
|
/* Utility */
|
||||||
.flex-row { display: flex; align-items: center; gap: 8px; }
|
.flex-row { display: flex; align-items: center; gap: 8px; }
|
||||||
.flex-between { display: flex; justify-content: space-between; align-items: center; }
|
.flex-between { display: flex; justify-content: space-between; align-items: center; }
|
||||||
.mb-16 { margin-bottom: 16px; }
|
.mb-16 { margin-bottom: 16px; }
|
||||||
|
|
@ -1391,7 +1391,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
.text-sm { font-size: 11px; }
|
.text-sm { font-size: 11px; }
|
||||||
.mono { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 12px; }
|
.mono { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 12px; }
|
||||||
|
|
||||||
/* ── Filter bar ── */
|
/* Filter bar */
|
||||||
.filter-bar {
|
.filter-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -1575,7 +1575,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Form label row ── */
|
/* Form label row */
|
||||||
.form-label-row {
|
.form-label-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1587,7 +1587,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Read-only banner ── */
|
/* Read-only banner */
|
||||||
.readonly-banner {
|
.readonly-banner {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1601,7 +1601,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
color: var(--warning);
|
color: var(--warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Config path ── */
|
/* Config path */
|
||||||
.config-path {
|
.config-path {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: var(--text-2);
|
color: var(--text-2);
|
||||||
|
|
@ -1613,7 +1613,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
border: 1px solid var(--border-subtle);
|
border: 1px solid var(--border-subtle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Settings cards ── */
|
/* Settings cards */
|
||||||
.settings-card {
|
.settings-card {
|
||||||
background: var(--bg-2);
|
background: var(--bg-2);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
|
|
@ -1656,7 +1656,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
color: var(--error);
|
color: var(--error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Disabled button ── */
|
/* Disabled button */
|
||||||
.btn:disabled, .btn[disabled] {
|
.btn:disabled, .btn[disabled] {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
|
|
@ -1671,7 +1671,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
cursor: help;
|
cursor: help;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Library Toolbar ── */
|
/* Library Toolbar */
|
||||||
.library-toolbar {
|
.library-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
@ -1694,7 +1694,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── View Toggle ── */
|
/* View Toggle */
|
||||||
.view-toggle {
|
.view-toggle {
|
||||||
display: flex;
|
display: flex;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
|
|
@ -1727,7 +1727,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
color: var(--accent-text);
|
color: var(--accent-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Sort & Page Size Controls ── */
|
/* Sort & Page Size Controls */
|
||||||
.sort-control select,
|
.sort-control select,
|
||||||
.page-size-control select {
|
.page-size-control select {
|
||||||
padding: 4px 24px 4px 8px;
|
padding: 4px 24px 4px 8px;
|
||||||
|
|
@ -1741,7 +1741,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Media Grid ── */
|
/* Media Grid */
|
||||||
.media-grid {
|
.media-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||||
|
|
@ -1768,7 +1768,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
box-shadow: 0 0 0 1px var(--accent);
|
box-shadow: 0 0 0 1px var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Card Checkbox ── */
|
/* Card Checkbox */
|
||||||
.card-checkbox {
|
.card-checkbox {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
|
|
@ -1790,7 +1790,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.5));
|
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Card Thumbnail ── */
|
/* Card Thumbnail */
|
||||||
.card-thumbnail {
|
.card-thumbnail {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
|
|
@ -1827,7 +1827,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Card Info ── */
|
/* Card Info */
|
||||||
.card-info {
|
.card-info {
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
}
|
}
|
||||||
|
|
@ -1854,7 +1854,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Table Thumbnail ── */
|
/* Table Thumbnail */
|
||||||
.table-thumb-cell {
|
.table-thumb-cell {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
padding: 4px 6px !important;
|
padding: 4px 6px !important;
|
||||||
|
|
@ -1889,7 +1889,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Type Filter Row ── */
|
/* Type Filter Row */
|
||||||
.type-filter-row {
|
.type-filter-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1922,7 +1922,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Library Stats Row ── */
|
/* Library Stats Row */
|
||||||
.library-stats {
|
.library-stats {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
@ -1931,7 +1931,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Sortable Table Headers ── */
|
/* Sortable Table Headers */
|
||||||
.sortable-header {
|
.sortable-header {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
@ -1942,7 +1942,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
color: var(--accent-text);
|
color: var(--accent-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Card extra info ── */
|
/* Card extra info */
|
||||||
.card-title,
|
.card-title,
|
||||||
.card-artist {
|
.card-artist {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
|
@ -1952,7 +1952,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Pagination ── */
|
/* Pagination */
|
||||||
.pagination {
|
.pagination {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1975,7 +1975,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Loading indicator ── */
|
/* Loading indicator */
|
||||||
.loading-overlay {
|
.loading-overlay {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -2017,7 +2017,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Toast container (stacked) ── */
|
/* Toast container (stacked) */
|
||||||
.toast-container {
|
.toast-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
|
|
@ -2034,7 +2034,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Nav badge ── */
|
/* Nav badge */
|
||||||
.nav-badge {
|
.nav-badge {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
|
@ -2048,7 +2048,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Detail preview ── */
|
/* Detail preview */
|
||||||
.detail-preview {
|
.detail-preview {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
background: var(--bg-0);
|
background: var(--bg-0);
|
||||||
|
|
@ -2086,7 +2086,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Action badge styles (audit) ── */
|
/* Action badge styles (audit) */
|
||||||
.action-updated {
|
.action-updated {
|
||||||
background: rgba(59, 120, 200, 0.1);
|
background: rgba(59, 120, 200, 0.1);
|
||||||
color: #6ca0d4;
|
color: #6ca0d4;
|
||||||
|
|
@ -2112,7 +2112,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
color: var(--text-2);
|
color: var(--text-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Audit controls ── */
|
/* Audit controls */
|
||||||
.audit-controls {
|
.audit-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -2126,7 +2126,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
background: var(--bg-2);
|
background: var(--bg-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Clickable elements ── */
|
/* Clickable elements */
|
||||||
.clickable {
|
.clickable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--accent-text);
|
color: var(--accent-text);
|
||||||
|
|
@ -2144,7 +2144,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
background: rgba(255,255,255,0.03);
|
background: rgba(255,255,255,0.03);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Progress bar ── */
|
/* Progress bar */
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
|
|
@ -2171,7 +2171,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
100% { transform: translateX(400%); }
|
100% { transform: translateX(400%); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Import status panel ── */
|
/* Import status panel */
|
||||||
.import-status-panel {
|
.import-status-panel {
|
||||||
background: var(--bg-2);
|
background: var(--bg-2);
|
||||||
border: 1px solid var(--accent);
|
border: 1px solid var(--accent);
|
||||||
|
|
@ -2238,7 +2238,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
color: var(--text-2);
|
color: var(--text-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Sidebar import progress ── */
|
/* Sidebar import progress */
|
||||||
.sidebar-import-progress {
|
.sidebar-import-progress {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
background: var(--bg-2);
|
background: var(--bg-2);
|
||||||
|
|
@ -2276,7 +2276,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Tag confirmation ── */
|
/* Tag confirmation */
|
||||||
.tag-confirm-delete {
|
.tag-confirm-delete {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -2305,7 +2305,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Help overlay ── */
|
/* Help overlay */
|
||||||
.help-overlay {
|
.help-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|
@ -2381,14 +2381,14 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
background: rgba(255,255,255,0.06);
|
background: rgba(255,255,255,0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Add media modal (collections) ── */
|
/* Add media modal (collections) */
|
||||||
.modal.wide {
|
.modal.wide {
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
max-height: 70vh;
|
max-height: 70vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Database management ── */
|
/* Database management */
|
||||||
.db-actions {
|
.db-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -2428,7 +2428,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
border: 1px solid rgba(228, 88, 88, 0.25);
|
border: 1px solid rgba(228, 88, 88, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Library select-all banner ── */
|
/* Library select-all banner */
|
||||||
.select-all-banner {
|
.select-all-banner {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -2457,7 +2457,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
color: var(--text-0);
|
color: var(--text-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Media Player ── */
|
/* Media Player */
|
||||||
.media-player {
|
.media-player {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: var(--bg-0);
|
background: var(--bg-0);
|
||||||
|
|
@ -2610,7 +2610,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Image Viewer ── */
|
/* Image Viewer */
|
||||||
.image-viewer-overlay {
|
.image-viewer-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|
@ -2687,7 +2687,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
-webkit-user-drag: none;
|
-webkit-user-drag: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Markdown Viewer ── */
|
/* Markdown Viewer */
|
||||||
.markdown-viewer {
|
.markdown-viewer {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
@ -2861,7 +2861,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Frontmatter Card ── */
|
/* Frontmatter Card */
|
||||||
.frontmatter-card {
|
.frontmatter-card {
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
background: var(--bg-2);
|
background: var(--bg-2);
|
||||||
|
|
@ -2891,7 +2891,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Duplicates ── */
|
/* Duplicates */
|
||||||
.duplicates-view {
|
.duplicates-view {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -3058,7 +3058,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Login ── */
|
/* Login */
|
||||||
.login-container {
|
.login-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -3113,7 +3113,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── User Info (sidebar) ── */
|
/* User Info (sidebar) */
|
||||||
.user-info {
|
.user-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -3156,7 +3156,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
.role-editor { background: rgba(34, 160, 80, 0.1); color: #5cb97a; }
|
.role-editor { background: rgba(34, 160, 80, 0.1); color: #5cb97a; }
|
||||||
.role-viewer { background: rgba(59, 120, 200, 0.1); color: #6ca0d4; }
|
.role-viewer { background: rgba(59, 120, 200, 0.1); color: #6ca0d4; }
|
||||||
|
|
||||||
/* ── Settings fields ── */
|
/* Settings fields */
|
||||||
.settings-field {
|
.settings-field {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
@ -3175,7 +3175,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Detail no preview ── */
|
/* Detail no preview */
|
||||||
.detail-no-preview {
|
.detail-no-preview {
|
||||||
padding: 32px 16px;
|
padding: 32px 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -3185,7 +3185,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Light Theme ── */
|
/* Light Theme */
|
||||||
.theme-light {
|
.theme-light {
|
||||||
--bg-0: #f5f5f7;
|
--bg-0: #f5f5f7;
|
||||||
--bg-1: #eeeef0;
|
--bg-1: #eeeef0;
|
||||||
|
|
@ -3217,7 +3217,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
background: rgba(0, 0, 0, 0.05);
|
background: rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Skeleton Loading States ── */
|
/* Skeleton Loading States */
|
||||||
@keyframes skeleton-pulse {
|
@keyframes skeleton-pulse {
|
||||||
0% { opacity: 0.6; }
|
0% { opacity: 0.6; }
|
||||||
50% { opacity: 0.3; }
|
50% { opacity: 0.3; }
|
||||||
|
|
@ -3307,7 +3307,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Breadcrumb ── */
|
/* Breadcrumb */
|
||||||
.breadcrumb {
|
.breadcrumb {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -3337,7 +3337,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Queue Panel ── */
|
/* Queue Panel */
|
||||||
.queue-panel {
|
.queue-panel {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -4135,7 +4135,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Wikilink Styles (in markdown) ── */
|
/* Wikilink Styles (in markdown) */
|
||||||
.wikilink {
|
.wikilink {
|
||||||
color: var(--accent-text);
|
color: var(--accent-text);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
@ -4160,7 +4160,7 @@ ul li { padding: 3px 0; font-size: 12px; color: var(--text-1); }
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Light theme adjustments for links and graph ── */
|
/* Light theme adjustments for links and graph */
|
||||||
.theme-light .graph-nodes .graph-node text {
|
.theme-light .graph-nodes .graph-node text {
|
||||||
fill: var(--text-0);
|
fill: var(--text-0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue