模块1完成,支持新旧导出数据
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -1241,6 +1241,15 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dioxus-free-icons"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d356e0f9edad0930bc1cc76744360c0ecca020cb943acaadf42cb774f28284"
|
||||||
|
dependencies = [
|
||||||
|
"dioxus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-fullstack"
|
name = "dioxus-fullstack"
|
||||||
version = "0.7.5"
|
version = "0.7.5"
|
||||||
@@ -1740,6 +1749,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
|
"dioxus-free-icons",
|
||||||
"futures",
|
"futures",
|
||||||
"polars",
|
"polars",
|
||||||
"rfd",
|
"rfd",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ dioxus = { version = "0.7.1", features = ["router"] }
|
|||||||
futures = "0.3.32"
|
futures = "0.3.32"
|
||||||
polars = { version="0.53.0", features = ["lazy", "csv"] }
|
polars = { version="0.53.0", features = ["lazy", "csv"] }
|
||||||
rfd = { version = "0.17.2" }
|
rfd = { version = "0.17.2" }
|
||||||
|
dioxus-free-icons = {version = "0.10.0", features=["font-awesome-solid"]}
|
||||||
[features]
|
[features]
|
||||||
default = ["desktop"]
|
default = ["desktop"]
|
||||||
web = ["dioxus/web"]
|
web = ["dioxus/web"]
|
||||||
|
|||||||
@@ -188,12 +188,35 @@
|
|||||||
.mb-4 {
|
.mb-4 {
|
||||||
margin-bottom: calc(var(--spacing) * 4);
|
margin-bottom: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
|
.ml-3 {
|
||||||
|
margin-left: calc(var(--spacing) * 3);
|
||||||
|
}
|
||||||
|
.table {
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
.border-collapse {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
.transform {
|
.transform {
|
||||||
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
||||||
}
|
}
|
||||||
|
.resize {
|
||||||
|
resize: both;
|
||||||
|
}
|
||||||
|
.border {
|
||||||
|
border-style: var(--tw-border-style);
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
.pt-0 {
|
.pt-0 {
|
||||||
padding-top: calc(var(--spacing) * 0);
|
padding-top: calc(var(--spacing) * 0);
|
||||||
}
|
}
|
||||||
|
.underline {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
|
.outline {
|
||||||
|
outline-style: var(--tw-outline-style);
|
||||||
|
outline-width: 1px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@property --tw-rotate-x {
|
@property --tw-rotate-x {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
@@ -215,6 +238,16 @@
|
|||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
}
|
}
|
||||||
|
@property --tw-border-style {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
initial-value: solid;
|
||||||
|
}
|
||||||
|
@property --tw-outline-style {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
initial-value: solid;
|
||||||
|
}
|
||||||
@layer properties {
|
@layer properties {
|
||||||
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
||||||
*, ::before, ::after, ::backdrop {
|
*, ::before, ::after, ::backdrop {
|
||||||
@@ -223,6 +256,8 @@
|
|||||||
--tw-rotate-z: initial;
|
--tw-rotate-z: initial;
|
||||||
--tw-skew-x: initial;
|
--tw-skew-x: initial;
|
||||||
--tw-skew-y: initial;
|
--tw-skew-y: initial;
|
||||||
|
--tw-border-style: solid;
|
||||||
|
--tw-outline-style: solid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{fs::File, future::Future};
|
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_free_icons::{icons::fa_solid_icons, Icon};
|
||||||
use polars::prelude::*;
|
use polars::prelude::*;
|
||||||
|
use std::{fs::File, future::Future};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct FilterRateThresholdState {
|
pub struct FilterRateThresholdState {
|
||||||
@@ -16,9 +16,77 @@ pub struct ThresholdItem {
|
|||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_threshold_items() -> Vec<ThresholdItem> {
|
||||||
|
vec![
|
||||||
|
ThresholdItem {
|
||||||
|
id: 0,
|
||||||
|
label: "0".to_string(),
|
||||||
|
value: "20".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 1,
|
||||||
|
label: "300".to_string(),
|
||||||
|
value: "1161.2".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 2,
|
||||||
|
label: "800".to_string(),
|
||||||
|
value: "3217.337".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 3,
|
||||||
|
label: "1300".to_string(),
|
||||||
|
value: "3849.787".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 4,
|
||||||
|
label: "1800".to_string(),
|
||||||
|
value: "4146.974".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 5,
|
||||||
|
label: "2300".to_string(),
|
||||||
|
value: "4392.644".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 6,
|
||||||
|
label: "2800".to_string(),
|
||||||
|
value: "4712.814".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 7,
|
||||||
|
label: "3300".to_string(),
|
||||||
|
value: "4951.606".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 8,
|
||||||
|
label: "4300".to_string(),
|
||||||
|
value: "5301.445".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 9,
|
||||||
|
label: "5300".to_string(),
|
||||||
|
value: "5652.705".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 10,
|
||||||
|
label: "7800".to_string(),
|
||||||
|
value: "6334.89".to_string(),
|
||||||
|
},
|
||||||
|
ThresholdItem {
|
||||||
|
id: 11,
|
||||||
|
label: "10300".to_string(),
|
||||||
|
value: "6951.119".to_string(),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn FilterRateThreshold() -> Element {
|
pub fn FilterRateThreshold() -> Element {
|
||||||
let mut state = use_context::<FilterRateThresholdState>();
|
let items = use_signal(default_threshold_items);
|
||||||
|
let next_id = use_signal(|| 12usize);
|
||||||
|
let mut import_dropdown_open = use_signal(|| false);
|
||||||
|
let mut state = use_context_provider(|| FilterRateThresholdState { items, next_id });
|
||||||
let navigator = use_navigator();
|
let navigator = use_navigator();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
@@ -68,18 +136,8 @@ pub fn FilterRateThreshold() -> Element {
|
|||||||
button {
|
button {
|
||||||
class: "button is-light",
|
class: "button is-light",
|
||||||
onclick: move |_| {
|
onclick: move |_| {
|
||||||
// let id = (state.next_id)();
|
*state.items.write() = default_threshold_items();
|
||||||
// state
|
state.next_id.set(12);
|
||||||
// .items
|
|
||||||
// .write()
|
|
||||||
// .push(ThresholdItem {
|
|
||||||
// id,
|
|
||||||
// label: String::new(),
|
|
||||||
// value: String::new(),
|
|
||||||
// });
|
|
||||||
// state.next_id.with_mut(|next_id| *next_id += 1);
|
|
||||||
state.items.write().clear();
|
|
||||||
state.next_id.with_mut(|n| *n = 0);
|
|
||||||
},
|
},
|
||||||
"重置"
|
"重置"
|
||||||
}
|
}
|
||||||
@@ -89,25 +147,73 @@ pub fn FilterRateThreshold() -> Element {
|
|||||||
|
|
||||||
div { class: "box",
|
div { class: "box",
|
||||||
h2 { class: "title is-6 mb-4", "数据导入" }
|
h2 { class: "title is-6 mb-4", "数据导入" }
|
||||||
|
div { class: if import_dropdown_open() { "dropdown is-active" } else { "dropdown" },
|
||||||
div { class: "buttons",
|
div { class: "dropdown-trigger",
|
||||||
button {
|
button {
|
||||||
class: "button is-primary",
|
class: "button is-primary",
|
||||||
onclick: move |_| {
|
style: "height: 2.5em; justify-content: space-between; align-items: center;",
|
||||||
load_csv_data(state.items);
|
"aria-haspopup": "true",
|
||||||
},
|
"aria-controls": "dropdown-menu",
|
||||||
span { class: "icon",
|
"aria-expanded": if import_dropdown_open() { "true" } else { "false" },
|
||||||
i { class: "fas fa-file-import" }
|
onclick: move |_| {
|
||||||
|
import_dropdown_open.set(!import_dropdown_open());
|
||||||
|
},
|
||||||
|
span { "导入CSV" }
|
||||||
|
span { class: "icon is-small",
|
||||||
|
Icon {
|
||||||
|
width: 18,
|
||||||
|
height: 18,
|
||||||
|
fill: "black",
|
||||||
|
icon: fa_solid_icons::FaAngleDown,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
span { "导入 CSV" }
|
}
|
||||||
|
div { class: "buttons",
|
||||||
|
div {
|
||||||
|
class: "dropdown-menu height: 2.5em;",
|
||||||
|
"id": "dropdown-menu",
|
||||||
|
"role": "menu",
|
||||||
|
div { class: "dropdown-content",
|
||||||
|
button {
|
||||||
|
class: "dropdown-item button is-white",
|
||||||
|
onclick: move |_| {
|
||||||
|
import_dropdown_open.set(false);
|
||||||
|
load_csv_data_old(state.items);
|
||||||
|
},
|
||||||
|
"导入旧格式"
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
class: "dropdown-item button is-white",
|
||||||
|
onclick: move |_| {
|
||||||
|
import_dropdown_open.set(false);
|
||||||
|
load_csv_data_new(state.items);
|
||||||
|
},
|
||||||
|
"导入新格式"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
|
||||||
class: "button is-light",
|
|
||||||
onclick: move |_| navigator.go_back(),
|
|
||||||
"返回"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
button {
|
||||||
|
class: "button is-light ml-3",
|
||||||
|
style: "height: 2.5em;",
|
||||||
|
onclick: move |_| navigator.go_back(),
|
||||||
|
"返回"
|
||||||
|
}
|
||||||
|
// div { class: "buttons",
|
||||||
|
// button {
|
||||||
|
// class: "button is-primary",
|
||||||
|
// onclick: move |_| {
|
||||||
|
// load_csv_data(state.items);
|
||||||
|
// },
|
||||||
|
// span { class: "icon",
|
||||||
|
// i { class: "fas fa-file-import" }
|
||||||
|
// }
|
||||||
|
// span { "导入 CSV" }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,7 +289,11 @@ struct SmoothRateConfig {
|
|||||||
|
|
||||||
impl Default for SmoothRateConfig {
|
impl Default for SmoothRateConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
SmoothRateConfig { ths: Vec::new(), rates: Vec::new(), file_path: Vec::new() }
|
SmoothRateConfig {
|
||||||
|
ths: Vec::new(),
|
||||||
|
rates: Vec::new(),
|
||||||
|
file_path: Vec::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,10 +332,12 @@ impl SmoothRateConfig {
|
|||||||
if rates.len() + 1 != ths.len() {
|
if rates.len() + 1 != ths.len() {
|
||||||
return SmoothRateConfig::default();
|
return SmoothRateConfig::default();
|
||||||
}
|
}
|
||||||
println!("ths: {:?}", ths);
|
|
||||||
println!("rates: {:?}", rates);
|
|
||||||
|
|
||||||
SmoothRateConfig { ths, rates, file_path: files }
|
SmoothRateConfig {
|
||||||
|
ths,
|
||||||
|
rates,
|
||||||
|
file_path: files,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analysis_all_files(&self) -> anyhow::Result<()> {
|
pub fn analysis_all_files(&self) -> anyhow::Result<()> {
|
||||||
@@ -250,6 +362,27 @@ impl SmoothRateConfig {
|
|||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn analysis_all_files_old(&self) -> anyhow::Result<()> {
|
||||||
|
if self.file_path.is_empty() {
|
||||||
|
return anyhow::Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut failed = vec![];
|
||||||
|
for file in &self.file_path {
|
||||||
|
match self.analysis_file_once_old(file) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(error) => failed.push((file.clone(), error.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !failed.is_empty() {
|
||||||
|
for (file, error) in failed {
|
||||||
|
println!("{file} -> {error}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
anyhow::Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn analysis_file_once(&self, file: &str) -> anyhow::Result<()> {
|
fn analysis_file_once(&self, file: &str) -> anyhow::Result<()> {
|
||||||
let df = LazyCsvReader::new(file.into())
|
let df = LazyCsvReader::new(file.into())
|
||||||
.with_has_header(true)
|
.with_has_header(true)
|
||||||
@@ -272,13 +405,35 @@ impl SmoothRateConfig {
|
|||||||
.include_header(true)
|
.include_header(true)
|
||||||
.finish(&mut df.clone())?;
|
.finish(&mut df.clone())?;
|
||||||
|
|
||||||
debug!("analysis finished");
|
anyhow::Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn analysis_file_once_old(&self, file: &str) -> anyhow::Result<()> {
|
||||||
|
let df = LazyCsvReader::new(file.into())
|
||||||
|
.with_has_header(false)
|
||||||
|
.finish()?
|
||||||
|
.with_columns(
|
||||||
|
(2..=85)
|
||||||
|
.map(|i| {
|
||||||
|
let name = format!("column_{}", i);
|
||||||
|
SmoothRateConfig::analysis_col_once(&name, &self.ths, &self.rates)
|
||||||
|
.cast(DataType::Float32)
|
||||||
|
.alias(&name)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
.collect()?;
|
||||||
|
let output = format!("{file}_processed.csv");
|
||||||
|
let mut output_file = File::create(output)?;
|
||||||
|
CsvWriter::new(&mut output_file)
|
||||||
|
.include_header(false)
|
||||||
|
.finish(&mut df.clone())?;
|
||||||
|
|
||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analysis_col_once(name: &str, thresholds: &[f32], rates: &[f32]) -> Expr {
|
fn analysis_col_once(name: &str, thresholds: &[f32], rates: &[f32]) -> Expr {
|
||||||
let mut expr: Expr =
|
let mut expr: Expr = col(name).cast(DataType::Float64) * lit(rates[rates.len() - 1] as f64);
|
||||||
col(name).cast(DataType::Float64) * lit(rates[rates.len() - 1] as f64);
|
|
||||||
|
|
||||||
for i in (0..rates.len()).rev() {
|
for i in (0..rates.len()).rev() {
|
||||||
let t0 = thresholds[i] as f64;
|
let t0 = thresholds[i] as f64;
|
||||||
@@ -295,13 +450,41 @@ impl SmoothRateConfig {
|
|||||||
.otherwise(expr);
|
.otherwise(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
when(col(name).cast(DataType::Float64).lt(lit(thresholds[0] as f64)))
|
when(
|
||||||
.then(lit(0.0))
|
col(name)
|
||||||
.otherwise(expr)
|
.cast(DataType::Float64)
|
||||||
|
.lt(lit(thresholds[0] as f64)),
|
||||||
|
)
|
||||||
|
.then(lit(0.0))
|
||||||
|
.otherwise(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_csv_data(items: Signal<Vec<ThresholdItem>>) {
|
fn load_csv_data_old(items: Signal<Vec<ThresholdItem>>) {
|
||||||
|
let current_items = items.read().clone();
|
||||||
|
|
||||||
|
let task = rfd::AsyncFileDialog::new()
|
||||||
|
.add_filter("CSV", &["csv"])
|
||||||
|
.pick_files();
|
||||||
|
execute(async move {
|
||||||
|
let file_handles = task.await;
|
||||||
|
|
||||||
|
if let Some(files) = file_handles {
|
||||||
|
let file_path_vec = files
|
||||||
|
.iter()
|
||||||
|
.map(|file| file.path().to_string_lossy().to_string())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let config = SmoothRateConfig::new(current_items, file_path_vec);
|
||||||
|
|
||||||
|
if let Err(error) = config.analysis_all_files_old() {
|
||||||
|
eprintln!("批量处理失败: {error}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_csv_data_new(items: Signal<Vec<ThresholdItem>>) {
|
||||||
let current_items = items.read().clone();
|
let current_items = items.read().clone();
|
||||||
|
|
||||||
let task = rfd::AsyncFileDialog::new()
|
let task = rfd::AsyncFileDialog::new()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use dioxus::prelude::*;
|
|
||||||
use crate::guide_router::Route;
|
use crate::guide_router::Route;
|
||||||
|
use dioxus::prelude::*;
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MainPage() -> Element {
|
pub fn MainPage() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
@@ -85,17 +85,6 @@ pub fn MainPage() -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 底部说明区
|
|
||||||
section { class: "section pt-0",
|
|
||||||
div { class: "container",
|
|
||||||
div { class: "notification is-light",
|
|
||||||
p { class: "has-text-grey",
|
|
||||||
"建议从“阈值配置”或“数据导入”开始。主页仅作为导航入口,具体路由逻辑可在外层统一处理。"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use crate::components::{main_page::MainPage,
|
use crate::components::{filters_rate_threshold::FilterRateThreshold, main_page::MainPage};
|
||||||
filters_rate_threshold::FilterRateThreshold,
|
|
||||||
};
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[derive(Routable, Clone, PartialEq)]
|
#[derive(Routable, Clone, PartialEq)]
|
||||||
|
|||||||
45
src/main.rs
45
src/main.rs
@@ -1,48 +1,35 @@
|
|||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod guide_router;
|
pub mod guide_router;
|
||||||
|
use dioxus::desktop::{use_window, Config};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
const FAVICON: Asset = asset!("/assets/favicon.ico");
|
const FAVICON: Asset = asset!("/assets/favicon.ico");
|
||||||
const MAIN_CSS: Asset = asset!("/assets/bulma.css");
|
const MAIN_CSS: Asset = asset!("/assets/bulma.css");
|
||||||
const HEADER_SVG: Asset = asset!("/assets/header.svg");
|
const HEADER_SVG: Asset = asset!("/assets/header.svg");
|
||||||
|
|
||||||
|
|
||||||
use crate::components::filters_rate_threshold::FilterRateThresholdState;
|
|
||||||
use crate::guide_router::Route;
|
use crate::guide_router::Route;
|
||||||
fn main() {
|
fn main() {
|
||||||
dioxus::launch(App);
|
LaunchBuilder::new()
|
||||||
|
.with_cfg(Config::new().with_menu(None))
|
||||||
|
.launch(App);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn App() -> Element {
|
fn App() -> Element {
|
||||||
let items = use_signal(Vec::new);
|
let window = use_window();
|
||||||
let next_id = use_signal(|| 0usize);
|
|
||||||
use_context_provider(|| FilterRateThresholdState { items, next_id });
|
use_effect(move || {
|
||||||
|
window.window.set_always_on_top(false);
|
||||||
|
});
|
||||||
rsx! {
|
rsx! {
|
||||||
document::Link { rel: "icon", href: FAVICON }
|
document::Link { rel: "icon", href: FAVICON }
|
||||||
document::Link { rel: "stylesheet", href: MAIN_CSS }
|
document::Link { rel: "stylesheet", href: MAIN_CSS }
|
||||||
// // Hero {}
|
div {
|
||||||
// FilterRateThreshold {}
|
width: "100%",
|
||||||
Router::<Route> {}
|
min_height: "100vh",
|
||||||
}
|
oncontextmenu: move |event| {
|
||||||
|
event.prevent_default();
|
||||||
}
|
},
|
||||||
|
Router::<Route> {}
|
||||||
#[component]
|
|
||||||
pub fn Hero() -> Element {
|
|
||||||
rsx! {
|
|
||||||
div { id: "hero",
|
|
||||||
img { src: HEADER_SVG, id: "header" }
|
|
||||||
div { id: "links",
|
|
||||||
a { href: "https://dioxuslabs.com/learn/0.7/", "📚 Learn Dioxus" }
|
|
||||||
a { href: "https://dioxuslabs.com/awesome", "🚀 Awesome Dioxus" }
|
|
||||||
a { href: "https://github.com/dioxus-community/", "📡 Community Libraries" }
|
|
||||||
a { href: "https://github.com/DioxusLabs/sdk", "⚙️ Dioxus Development Kit" }
|
|
||||||
a { href: "https://marketplace.visualstudio.com/items?itemName=DioxusLabs.dioxus",
|
|
||||||
"💫 VSCode Extension"
|
|
||||||
}
|
|
||||||
a { href: "https://discord.gg/XgGxMSkvUM", "👋 Community Discord" }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user