init
This commit is contained in:
12
.gitignore
vendored
git.filemode.normal_file
12
.gitignore
vendored
git.filemode.normal_file
@@ -0,0 +1,12 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
*.lock
|
||||||
|
|
||||||
|
assets/tailwind.css
|
||||||
|
assets/*.csv
|
||||||
16
Cargo.toml
git.filemode.normal_file
16
Cargo.toml
git.filemode.normal_file
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "vulkan-cts-analyzer"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Kbz-8 <kbz_8.code@proton.me>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
csv = "1.4.0"
|
||||||
|
dioxus = { version = "0.7.2", features = ["router"] }
|
||||||
|
dioxus-primitives = { git = "https://github.com/DioxusLabs/components", version = "0.0.1", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["web"]
|
||||||
|
web = ["dioxus/web"]
|
||||||
|
desktop = ["dioxus/desktop"]
|
||||||
|
mobile = ["dioxus/mobile"]
|
||||||
11
Dioxus.toml
git.filemode.normal_file
11
Dioxus.toml
git.filemode.normal_file
@@ -0,0 +1,11 @@
|
|||||||
|
[application]
|
||||||
|
|
||||||
|
[web.app]
|
||||||
|
title = "Vulkan CTS Report"
|
||||||
|
|
||||||
|
[web.resource]
|
||||||
|
style = []
|
||||||
|
script = []
|
||||||
|
|
||||||
|
[web.resource.dev]
|
||||||
|
script = []
|
||||||
50
README.md
git.filemode.normal_file
50
README.md
git.filemode.normal_file
@@ -0,0 +1,50 @@
|
|||||||
|
# Development
|
||||||
|
|
||||||
|
Your new bare-bones project includes minimal organization with a single `main.rs` file and a few assets.
|
||||||
|
|
||||||
|
```
|
||||||
|
project/
|
||||||
|
├─ assets/ # Any assets that are used by the app should be placed here
|
||||||
|
├─ src/
|
||||||
|
│ ├─ main.rs # main.rs is the entry point to your application and currently contains all components for the app
|
||||||
|
├─ Cargo.toml # The Cargo.toml file defines the dependencies and feature flags for your project
|
||||||
|
```
|
||||||
|
|
||||||
|
### Automatic Tailwind (Dioxus 0.7+)
|
||||||
|
|
||||||
|
As of Dioxus 0.7, there no longer is a need to manually install tailwind. Simply `dx serve` and you're good to go!
|
||||||
|
|
||||||
|
Automatic tailwind is supported by checking for a file called `tailwind.css` in your app's manifest directory (next to Cargo.toml). To customize the file, use the dioxus.toml:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[application]
|
||||||
|
tailwind_input = "my.css"
|
||||||
|
tailwind_output = "assets/out.css" # also customize the location of the out file!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tailwind Manual Install
|
||||||
|
|
||||||
|
To use tailwind plugins or manually customize tailwind, you can can install the Tailwind CLI and use it directly.
|
||||||
|
|
||||||
|
### Tailwind
|
||||||
|
1. Install npm: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm
|
||||||
|
2. Install the Tailwind CSS CLI: https://tailwindcss.com/docs/installation/tailwind-cli
|
||||||
|
3. Run the following command in the root of the project to start the Tailwind CSS compiler:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @tailwindcss/cli -i ./input.css -o ./assets/tailwind.css --watch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Serving Your App
|
||||||
|
|
||||||
|
Run the following command in the root of your project to start developing with the default platform:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dx serve
|
||||||
|
```
|
||||||
|
|
||||||
|
To run for a different platform, use the `--platform platform` flag. E.g.
|
||||||
|
```bash
|
||||||
|
dx serve --platform desktop
|
||||||
|
```
|
||||||
|
|
||||||
83
assets/dx-components-theme.css
git.filemode.normal_file
83
assets/dx-components-theme.css
git.filemode.normal_file
@@ -0,0 +1,83 @@
|
|||||||
|
/* This file contains the global styles for the styled dioxus components. You only
|
||||||
|
* need to import this file once in your project root.
|
||||||
|
*/
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap");
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: var(--secondary-color-4);
|
||||||
|
font-family: Inter, sans-serif;
|
||||||
|
font-optical-sizing: auto;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--dark: initial;
|
||||||
|
--light: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
:root {
|
||||||
|
--dark: ;
|
||||||
|
--light: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* Primary colors */
|
||||||
|
--primary-color: var(--dark, #000) var(--light, #fff);
|
||||||
|
--primary-color-1: var(--dark, #0e0e0e) var(--light, #fbfbfb);
|
||||||
|
--primary-color-2: var(--dark, #0a0a0a) var(--light, #fff);
|
||||||
|
--primary-color-3: var(--dark, #141313) var(--light, #f8f8f8);
|
||||||
|
--primary-color-4: var(--dark, #1a1a1a) var(--light, #f8f8f8);
|
||||||
|
--primary-color-5: var(--dark, #262626) var(--light, #f5f5f5);
|
||||||
|
--primary-color-6: var(--dark, #232323) var(--light, #e5e5e5);
|
||||||
|
--primary-color-7: var(--dark, #3e3e3e) var(--light, #b0b0b0);
|
||||||
|
|
||||||
|
/* Secondary colors */
|
||||||
|
--secondary-color: var(--dark, #fff) var(--light, #000);
|
||||||
|
--secondary-color-1: var(--dark, #fafafa) var(--light, #000);
|
||||||
|
--secondary-color-2: var(--dark, #e6e6e6) var(--light, #0d0d0d);
|
||||||
|
--secondary-color-3: var(--dark, #dcdcdc) var(--light, #2b2b2b);
|
||||||
|
--secondary-color-4: var(--dark, #d4d4d4) var(--light, #111);
|
||||||
|
--secondary-color-5: var(--dark, #a1a1a1) var(--light, #848484);
|
||||||
|
--secondary-color-6: var(--dark, #5d5d5d) var(--light, #d0d0d0);
|
||||||
|
|
||||||
|
/* Highlight colors */
|
||||||
|
--focused-border-color: var(--dark, #2b7fff) var(--light, #2b7fff);
|
||||||
|
--primary-success-color: var(--dark, #02271c) var(--light, #ecfdf5);
|
||||||
|
--secondary-success-color: var(--dark, #b6fae3) var(--light, #10b981);
|
||||||
|
--primary-warning-color: var(--dark, #342203) var(--light, #fffbeb);
|
||||||
|
--secondary-warning-color: var(--dark, #feeac7) var(--light, #f59e0b);
|
||||||
|
--primary-error-color: var(--dark, #a22e2e) var(--light, #dc2626);
|
||||||
|
--secondary-error-color: var(--dark, #9b1c1c) var(--light, #ef4444);
|
||||||
|
--contrast-error-color: var(--dark, var(--secondary-color-3))
|
||||||
|
var(--light, var(--primary-color));
|
||||||
|
--primary-info-color: var(--dark, var(--primary-color-5))
|
||||||
|
var(--light, var(--primary-color));
|
||||||
|
--secondary-info-color: var(--dark, var(--primary-color-7))
|
||||||
|
var(--light, var(--secondary-color-3));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modern browsers with `scrollbar-*` support */
|
||||||
|
@supports (scrollbar-width: auto) {
|
||||||
|
:not(:hover) {
|
||||||
|
scrollbar-color: rgb(0 0 0 / 0%) rgb(0 0 0 / 0%);
|
||||||
|
}
|
||||||
|
|
||||||
|
:hover {
|
||||||
|
scrollbar-color: var(--secondary-color-2) rgb(0 0 0 / 0%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Legacy browsers with `::-webkit-scrollbar-*` support */
|
||||||
|
@supports selector(::-webkit-scrollbar) {
|
||||||
|
:root::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/favicon.ico
git.filemode.normal_file
BIN
assets/favicon.ico
git.filemode.normal_file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
2
src/components/mod.rs
git.filemode.normal_file
2
src/components/mod.rs
git.filemode.normal_file
@@ -0,0 +1,2 @@
|
|||||||
|
// AUTOGENERTED Components module
|
||||||
|
pub mod skeleton;
|
||||||
9
src/components/skeleton/component.rs
git.filemode.normal_file
9
src/components/skeleton/component.rs
git.filemode.normal_file
@@ -0,0 +1,9 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Skeleton(#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>) -> Element {
|
||||||
|
rsx! {
|
||||||
|
document::Link { rel: "stylesheet", href: asset!("./style.css") }
|
||||||
|
div { class: "skeleton", ..attributes }
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/components/skeleton/mod.rs
git.filemode.normal_file
2
src/components/skeleton/mod.rs
git.filemode.normal_file
@@ -0,0 +1,2 @@
|
|||||||
|
mod component;
|
||||||
|
pub use component::*;
|
||||||
16
src/components/skeleton/style.css
git.filemode.normal_file
16
src/components/skeleton/style.css
git.filemode.normal_file
@@ -0,0 +1,16 @@
|
|||||||
|
.skeleton {
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
animation: skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
background-color: var(--primary-color-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes skeleton-pulse {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
61.8% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
232
src/landing.rs
git.filemode.normal_file
232
src/landing.rs
git.filemode.normal_file
@@ -0,0 +1,232 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
use csv::StringRecord;
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy, PartialEq, Eq)]
|
||||||
|
struct GlobalStats {
|
||||||
|
count: usize,
|
||||||
|
passed: usize,
|
||||||
|
failed: usize,
|
||||||
|
skip: usize,
|
||||||
|
flake: usize,
|
||||||
|
crash: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn percentage(count: usize, total: usize) -> f32 {
|
||||||
|
(count as f32 * 100.0) / total as f32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Landing() -> Element {
|
||||||
|
let result = use_context::<Vec<StringRecord>>();
|
||||||
|
|
||||||
|
let global_stats = result.iter().fold(GlobalStats::default(), |acc, record| {
|
||||||
|
let mut new_acc = acc;
|
||||||
|
match &record[1] {
|
||||||
|
"Pass" => new_acc.passed += 1,
|
||||||
|
"Skip" => new_acc.skip += 1,
|
||||||
|
"Fail" => new_acc.failed += 1,
|
||||||
|
"Flake" => new_acc.flake += 1,
|
||||||
|
"Crash" => new_acc.crash += 1,
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
new_acc.count = new_acc.passed + new_acc.failed + new_acc.skip + new_acc.flake + new_acc.crash;
|
||||||
|
new_acc
|
||||||
|
});
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "flex flex-col space-y-4 rounded-3xl p-4 w-full h-fit shadow-xl shadow-slate-950",
|
||||||
|
style: "background: linear-gradient(145deg, #020617 0, #02081f 60%, #020617 100%);",
|
||||||
|
div { class: "border-1 border-slate-400 bg-slate-400/15 text-slate-400 w-fit rounded-3xl p-1 flex flex-row space-x-1 items-center",
|
||||||
|
div { class: "bg-[#22c55e] rounded-full size-3" }
|
||||||
|
p { class: "text-xs",
|
||||||
|
"Count: {global_stats.count} tests"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4",
|
||||||
|
StatCard {
|
||||||
|
name: "PASSED".to_string(),
|
||||||
|
color: "#22c55e".to_string(),
|
||||||
|
count: global_stats.passed,
|
||||||
|
stat: percentage(global_stats.passed, global_stats.count),
|
||||||
|
}
|
||||||
|
StatCard {
|
||||||
|
name: "FAILED".to_string(),
|
||||||
|
color: "#ff6467".to_string(),
|
||||||
|
count: global_stats.failed,
|
||||||
|
stat: percentage(global_stats.failed, global_stats.count),
|
||||||
|
}
|
||||||
|
StatCard {
|
||||||
|
name: "SKIPPED".to_string(),
|
||||||
|
color: "#ffdf20".to_string(),
|
||||||
|
count: global_stats.skip,
|
||||||
|
stat: percentage(global_stats.skip, global_stats.count),
|
||||||
|
}
|
||||||
|
StatCard {
|
||||||
|
name: "FLAKE".to_string(),
|
||||||
|
color: "#38bdf8".to_string(),
|
||||||
|
count: global_stats.flake,
|
||||||
|
stat: percentage(global_stats.flake, global_stats.count),
|
||||||
|
}
|
||||||
|
StatCard {
|
||||||
|
name: "CRASH".to_string(),
|
||||||
|
color: "#e7000b".to_string(),
|
||||||
|
count: global_stats.crash,
|
||||||
|
stat: percentage(global_stats.crash, global_stats.count),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div { class: "mx-auto size-[200px]",
|
||||||
|
StatsPieChart { stats: global_stats }
|
||||||
|
}
|
||||||
|
div { class: "mt-12 w-full bg-gray-900 overflow-hidden border-1 border-slate-700 rounded-lg",
|
||||||
|
table { class: "w-full border-collapse border-spacing-0",
|
||||||
|
tr {
|
||||||
|
class: "border-b-1 border-slate-700",
|
||||||
|
style: "background: radial-gradient(circle at top, rgba(56, 189, 248, 0.1), rgba(15, 23, 42, 1));",
|
||||||
|
th { class: "text-left uppercase bold whitespace-nowrap py-2 px-3",
|
||||||
|
"Test name",
|
||||||
|
}
|
||||||
|
th { class: "text-left uppercase bold whitespace-nowrap py-2 px-3",
|
||||||
|
"Status",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for test in result[0..100].iter() {
|
||||||
|
tr { class: "text-sm hover:bg-[#38bef7]/5",
|
||||||
|
td { class: "py-2 px-3",
|
||||||
|
"{&test[0]}"
|
||||||
|
}
|
||||||
|
td { class: "py-2 px-3",
|
||||||
|
"{&test[1]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn StatCard(
|
||||||
|
name: String,
|
||||||
|
color: String,
|
||||||
|
count: usize,
|
||||||
|
stat: f32,
|
||||||
|
) -> Element {
|
||||||
|
rsx! {
|
||||||
|
div { class: "rounded-2xl p-4 border-1 border-slate-800 shadow-xl shadow-[#02081f] w-full h-fit bg-[#090f21] flex flex-col space-y-2",
|
||||||
|
div { class: "flex flex-row space-x-2 flex items-center",
|
||||||
|
div {
|
||||||
|
class: "rounded-full size-4",
|
||||||
|
style: format!("background-color: {color};"),
|
||||||
|
}
|
||||||
|
h3 { class: "text-sm text-gray-300",
|
||||||
|
"{name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
class: "text-2xl font-bold",
|
||||||
|
style: format!("color: {color};"),
|
||||||
|
"{count}",
|
||||||
|
}
|
||||||
|
p { class: "text-xs text-gray-400",
|
||||||
|
"{stat:.1}% of total"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Segment {
|
||||||
|
percentage: f32,
|
||||||
|
start: f32,
|
||||||
|
end: f32,
|
||||||
|
color: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn StatsPieChart(stats: GlobalStats) -> Element {
|
||||||
|
let total = stats.count as f32;
|
||||||
|
|
||||||
|
if total == 0.0 {
|
||||||
|
return rsx!{};
|
||||||
|
}
|
||||||
|
|
||||||
|
let passed = stats.passed as f32 / total;
|
||||||
|
let failed = stats.failed as f32 / total;
|
||||||
|
let skip = stats.skip as f32 / total;
|
||||||
|
let flake = stats.flake as f32 / total;
|
||||||
|
let crash = stats.crash as f32 / total;
|
||||||
|
|
||||||
|
let colors = (
|
||||||
|
"#22c55e", // passed
|
||||||
|
"#ff6467", // failed
|
||||||
|
"#ffdf20", // skipped
|
||||||
|
"#38bdf8", // flake
|
||||||
|
"#e7000b", // crash
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut segments: Vec<Segment> = Vec::new();
|
||||||
|
let mut cumulative = 0.0_f32;
|
||||||
|
|
||||||
|
for (pct, color) in [
|
||||||
|
(passed, colors.0),
|
||||||
|
(failed, colors.1),
|
||||||
|
(skip, colors.2),
|
||||||
|
(flake, colors.3),
|
||||||
|
(crash, colors.4),
|
||||||
|
] {
|
||||||
|
if pct > 0.0 {
|
||||||
|
segments.push(Segment {
|
||||||
|
percentage: pct * 100.0,
|
||||||
|
start: cumulative,
|
||||||
|
end: cumulative + pct,
|
||||||
|
color: color.to_string(),
|
||||||
|
});
|
||||||
|
cumulative += pct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let radius: f32 = 80.0;
|
||||||
|
let cx: f32 = 100.0;
|
||||||
|
let cy: f32 = 100.0;
|
||||||
|
|
||||||
|
let paths = segments
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, seg)| {
|
||||||
|
let start_angle = seg.start * 2.0 * PI;
|
||||||
|
let end_angle = seg.end * 2.0 * PI;
|
||||||
|
|
||||||
|
let x1 = cx + radius * start_angle.cos();
|
||||||
|
let y1 = cy + radius * start_angle.sin();
|
||||||
|
let x2 = cx + radius * end_angle.cos();
|
||||||
|
let y2 = cy + radius * end_angle.sin();
|
||||||
|
|
||||||
|
let large_arc_flag = if (end_angle - start_angle) > PI { 1 } else { 0 };
|
||||||
|
|
||||||
|
let d = format!(
|
||||||
|
"M {cx} {cy} L {x1} {y1} A {radius} {radius} 0 {large_arc_flag} 1 {x2} {y2} Z"
|
||||||
|
);
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
path {
|
||||||
|
key: "{idx}",
|
||||||
|
d: "{d}",
|
||||||
|
fill: "{seg.color}",
|
||||||
|
opacity: "0.9",
|
||||||
|
stroke: "rgba(255, 255, 255, 0.1)",
|
||||||
|
"stroke-width": "1",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
svg {
|
||||||
|
class: "max-w-[200px] h-auto",
|
||||||
|
view_box: "0 0 200 200",
|
||||||
|
{paths}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/loader.rs
git.filemode.normal_file
64
src/loader.rs
git.filemode.normal_file
@@ -0,0 +1,64 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
/// Default placeholder for loading state
|
||||||
|
#[component]
|
||||||
|
pub fn LoadingPlaceholder(message: String) -> Element {
|
||||||
|
rsx! {
|
||||||
|
div { class: "rounded-radius h-[50vh] w-1/2 bg-foreground/20 animate-pulse text-foreground flex justify-center items-center place-self-center mt-14 mx-auto",
|
||||||
|
h3 { class: "h3", {message} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
struct SuspenseContextPlaceholder {
|
||||||
|
element: Option<Element>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait to create a suspense with a default loading placeholder
|
||||||
|
pub trait Loader<T: 'static> {
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
message: impl ToString,
|
||||||
|
) -> Result<MappedSignal<T, Signal<Option<T>> /* wtf Dioxus ??? */>, RenderError>;
|
||||||
|
fn load_with(
|
||||||
|
&self,
|
||||||
|
element: Element,
|
||||||
|
) -> Result<MappedSignal<T, Signal<Option<T>>>, RenderError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Loader<T> for Resource<T> {
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
message: impl ToString,
|
||||||
|
) -> Result<MappedSignal<T, Signal<Option<T>>>, RenderError> {
|
||||||
|
let mut context = use_context::<Signal<SuspenseContextPlaceholder>>();
|
||||||
|
context.write().element = Some(rsx! {
|
||||||
|
LoadingPlaceholder { message: message.to_string() }
|
||||||
|
});
|
||||||
|
self.suspend()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_with(
|
||||||
|
&self,
|
||||||
|
element: Element,
|
||||||
|
) -> Result<MappedSignal<T, Signal<Option<T>>>, RenderError> {
|
||||||
|
let mut context = use_context::<Signal<SuspenseContextPlaceholder>>();
|
||||||
|
context.write().element = Some(element);
|
||||||
|
self.suspend()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Suspense(children: Element) -> Element {
|
||||||
|
let context = use_context_provider(|| Signal::new(SuspenseContextPlaceholder::default()));
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
SuspenseBoundary {
|
||||||
|
fallback: move |_| {
|
||||||
|
context.read().clone().element.unwrap_or_else(|| rsx! { "Loading..." })
|
||||||
|
},
|
||||||
|
{children}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/main.rs
git.filemode.normal_file
38
src/main.rs
git.filemode.normal_file
@@ -0,0 +1,38 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
use csv::{ReaderBuilder, StringRecord};
|
||||||
|
|
||||||
|
mod landing;
|
||||||
|
mod navbar;
|
||||||
|
mod routes;
|
||||||
|
mod loader;
|
||||||
|
|
||||||
|
use crate::routes::Route;
|
||||||
|
|
||||||
|
const FAVICON: Asset = asset!("/assets/favicon.ico");
|
||||||
|
const TAILWIND_CSS: Asset = asset!("/assets/tailwind.css");
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dioxus::launch(App);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn App() -> Element {
|
||||||
|
// TODO: get results from request
|
||||||
|
let result_data = include_str!("../assets/results.csv");
|
||||||
|
let mut reader = ReaderBuilder::new().from_reader(result_data.as_bytes());
|
||||||
|
|
||||||
|
let records = reader.into_records().collect::<Result<Vec<StringRecord>, csv::Error>>()?;
|
||||||
|
|
||||||
|
let result = use_context_provider(|| records);
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
document::Link { rel: "icon", href: FAVICON }
|
||||||
|
document::Link { rel: "stylesheet", href: TAILWIND_CSS }
|
||||||
|
div {
|
||||||
|
class: "text-white min-h-screen",
|
||||||
|
style: "background: radial-gradient(circle at top, #1e293b 0, #020617 45%, #000 100%);",
|
||||||
|
Router::<Route> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/navbar.rs
git.filemode.normal_file
54
src/navbar.rs
git.filemode.normal_file
@@ -0,0 +1,54 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
use crate::routes::Route;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Navbar() -> Element {
|
||||||
|
rsx! {
|
||||||
|
div { class: "w-screen mb-12 py-2 px-6 flex flex-row justify-between",
|
||||||
|
Link { class: "flex flex-row h-16 text-4xl md:text-5xl select-none cursor-pointer",
|
||||||
|
to: Route::Landing {},
|
||||||
|
VulkanVSvg {}
|
||||||
|
p { class: "hidden md:block mt-auto font-bold -ml-3.5 text-[#9d1b1f]",
|
||||||
|
"ulkan"
|
||||||
|
}
|
||||||
|
p { class: "mt-auto ml-2 font-bold text-gray-300",
|
||||||
|
"CTS Report"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main { class: "mx-auto container mb-24",
|
||||||
|
Outlet::<Route> {}
|
||||||
|
}
|
||||||
|
footer { class: "w-screen flex flex-row justify-between px-6 text-sm text-gray-400",
|
||||||
|
"Made by kbz_8 with Dioxus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn VulkanVSvg() -> Element {
|
||||||
|
rsx! {
|
||||||
|
svg {
|
||||||
|
view_box: "0 0 192 192",
|
||||||
|
g {
|
||||||
|
transform: "translate(0.0, 192.0) scale(0.1, -0.1)",
|
||||||
|
fill: "#9d1b1f",
|
||||||
|
stroke: "none",
|
||||||
|
path {
|
||||||
|
d: "M320 1703 c1 -10 18 -70 38 -133 35 -106 40 -115 63 -114 41 2 311 33 315 36 1 2 -8 35 -21 73 -14 39 -29 89 -35 113 l-11 42 -174 0 c-160 0 -175 -1 -175 -17z",
|
||||||
|
}
|
||||||
|
path {
|
||||||
|
d: "M1336 1678 c-38 -104 -77 -240 -73 -251 3 -7 31 -21 63 -31 33 -10 97 -34 143 -52 46 -19 88 -33 93 -32 8 3 138 380 138 401 0 4 -78 7 -174 7 l-174 0 -16 -42z",
|
||||||
|
}
|
||||||
|
path {
|
||||||
|
d: "M550 1369 c-235 -26 -412 -107 -509 -232 l-41 -54 0 -91 c0 -89 1 -92 39 -149 50 -75 117 -142 206 -205 124 -87 339 -197 350 -178 3 6 -35 50 -84 98 -160 157 -189 276 -96 402 35 47 116 105 183 130 285 108 789 43 1208 -155 107 -50 114 -52 113 -32 0 14 -26 44 -74 86 -218 191 -465 307 -765 361 -134 24 -401 34 -530 19z",
|
||||||
|
}
|
||||||
|
path {
|
||||||
|
d: "M739 1025 c-75 -15 -166 -51 -172 -68 -4 -13 221 -717 242 -755 12 -22 14 -23 192 -20 98 1 184 5 189 8 9 6 81 213 205 589 31 95 53 177 48 182 -10 10 -294 67 -308 62 -10 -3 -83 -220 -106 -312 -9 -38 -12 -42 -25 -29 -8 8 -39 91 -68 184 l-53 169 -39 2 c-21 1 -69 -4 -105 -12z",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/routes.rs
git.filemode.normal_file
26
src/routes.rs
git.filemode.normal_file
@@ -0,0 +1,26 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
landing::Landing,
|
||||||
|
navbar::Navbar,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Routable, PartialEq)]
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub enum Route {
|
||||||
|
#[layout(Navbar)]
|
||||||
|
#[route("/")]
|
||||||
|
Landing {},
|
||||||
|
|
||||||
|
#[route("/:..route")]
|
||||||
|
PageNotFound {
|
||||||
|
route: Vec<String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn PageNotFound(route: Vec<String>) -> Element {
|
||||||
|
rsx! {
|
||||||
|
"test"
|
||||||
|
}
|
||||||
|
}
|
||||||
20
tailwind.css
git.filemode.normal_file
20
tailwind.css
git.filemode.normal_file
@@ -0,0 +1,20 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
@layer "base" {
|
||||||
|
.skeleton {
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
animation: skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
background-color: #262626;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes skeleton-pulse {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
61.8% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user