From d76b561e9aa9ca0068115cf5cc0a62036ff77ba6 Mon Sep 17 00:00:00 2001 From: "S. Yakupov" Date: Sun, 16 Jul 2023 17:42:47 +0300 Subject: [PATCH] feat: start implementing new Leptos-based generation (#38) --- .github/workflows/build.yml | 21 +- Cargo.toml | 7 +- dist/index.html | 9 + dist/ng_hello_world/index.html | 15 ++ examples/ng_hello_world.rs | 17 ++ scripts/examples.sh | 1 + src/lib.rs | 1 + src/ng.rs | 57 ++++++ src/ng/align.rs | 27 +++ src/ng/color.rs | 310 +++++++++++++++++++++++++++++ src/ng/label.rs | 41 ++++ src/ng/slide.rs | 50 +++++ src/ng/slideshow.rs | 36 ++++ src/{widgets/mod.rs => widgets.rs} | 0 14 files changed, 585 insertions(+), 7 deletions(-) create mode 100644 dist/ng_hello_world/index.html create mode 100644 examples/ng_hello_world.rs create mode 100644 src/ng.rs create mode 100644 src/ng/align.rs create mode 100644 src/ng/color.rs create mode 100644 src/ng/label.rs create mode 100644 src/ng/slide.rs create mode 100644 src/ng/slideshow.rs rename src/{widgets/mod.rs => widgets.rs} (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8bb7f5c..e1083d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,10 @@ on: push: branches: [master] +permissions: + id-token: write + pages: write + env: CARGO_TERM_COLOR: always @@ -38,11 +42,16 @@ jobs: - name: Build examples run: ./scripts/examples.sh - - name: Publish examples + - name: Setup GitHub Pages + if: github.event_name == 'push' + uses: actions/configure-pages@v3 + + - name: Upload Pages artifact if: github.event_name == 'push' - uses: peaceiris/actions-gh-pages@v3 + uses: actions/upload-pages-artifact@v2 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: dist - cname: lerni.noviga.com - force_orphan: true + path: dist + + - name: Deploy to GitHub Pages + if: github.event_name == 'push' + uses: actions/deploy-pages@v2 diff --git a/Cargo.toml b/Cargo.toml index 511ba7b..941916d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lerni" -version = "0.0.1" +version = "0.0.2" edition = "2021" license = "MIT" description = "Lerni content framework" @@ -12,6 +12,7 @@ derive_more = "0.99.17" getrandom = { version = "0.2.8", features = ["js"] } gloo-events = "0.1.2" gloo-utils = "0.1.6" +leptos = { version = "0.4.3", features = ["csr"] } rand = { version = "0.8.5", default-features = false, features = ["getrandom"] } yew = { version = "0.20.0", features = ["csr"] } wasm-bindgen = "0.2.84" @@ -41,6 +42,10 @@ crate-type = ["cdylib"] name = "hello_world" crate-type = ["cdylib"] +[[example]] +name = "ng_hello_world" +crate-type = ["cdylib"] + [[example]] name = "pointer" crate-type = ["cdylib"] diff --git a/dist/index.html b/dist/index.html index 48cccea..cdab66b 100644 --- a/dist/index.html +++ b/dist/index.html @@ -43,6 +43,15 @@

Lerni Examples

(source) + +

New Generation (Leptos-based) Lerni Examples

+

⚠️ Work in progress!

+ diff --git a/dist/ng_hello_world/index.html b/dist/ng_hello_world/index.html new file mode 100644 index 0000000..219e284 --- /dev/null +++ b/dist/ng_hello_world/index.html @@ -0,0 +1,15 @@ + + + + + + Lerni "Rows & Columns" Example + + + + + + + + + diff --git a/examples/ng_hello_world.rs b/examples/ng_hello_world.rs new file mode 100644 index 0000000..0d591bc --- /dev/null +++ b/examples/ng_hello_world.rs @@ -0,0 +1,17 @@ +use leptos::*; +use lerni::ng::*; + +#[component] +pub fn HelloWorld(cx: Scope) -> impl IntoView { + view! { cx, + + + + + } +} + +#[wasm_bindgen(start)] +pub fn main() { + lerni::ng::start(HelloWorld); +} diff --git a/scripts/examples.sh b/scripts/examples.sh index efa0e91..7c6437c 100755 --- a/scripts/examples.sh +++ b/scripts/examples.sh @@ -5,6 +5,7 @@ blur \ buttons \ grid \ hello_world \ +ng_hello_world \ pointer \ rows_cols \ svg \ diff --git a/src/lib.rs b/src/lib.rs index ca7c757..256761a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![warn(missing_docs)] +pub mod ng; pub mod properties; pub mod utils; pub mod widgets; diff --git a/src/ng.rs b/src/ng.rs new file mode 100644 index 0000000..7ae11c9 --- /dev/null +++ b/src/ng.rs @@ -0,0 +1,57 @@ +//! New generation Lerni based on Leptos. + +pub use wasm_bindgen::prelude::wasm_bindgen; + +mod align; +pub use align::{Align, VAlign}; + +mod color; +pub use color::Color; + +mod label; +pub use label::Label; + +mod slide; +pub use slide::Slide; + +mod slideshow; +pub use slideshow::SlideShow; + +use leptos::{IntoView, Scope}; + +/// Additional information provided to all slides. +#[derive(Clone, Copy, Default, Debug, PartialEq)] +pub struct Metadata { + /// Visibility flag. + pub visible: bool, + /// Teacher mode flag. + pub teacher_mode: bool, + /// Pointer on/off flag. + pub pointer: bool, +} + +/// Frame within which the widget will be rendered. +#[derive(Clone, Default, Debug, PartialEq)] +pub struct Frame { + /// X-coordinate (in pixels) of the to left corner. + pub x: i32, + /// Y-coordinate (in pixels) of the to left corner. + pub y: i32, + /// Width (in pixels). + pub width: i32, + /// Height (in pixels). + pub height: i32, + /// Screen X to SVG X transform factor. + pub fx: f32, + /// Screen Y to SVG Y transform factor. + pub fy: f32, +} + +/// The main entry point. +pub fn start(f: F) +where + F: FnOnce(Scope) -> N + 'static, + N: IntoView, +{ + leptos::mount_to_body(f); +} diff --git a/src/ng/align.rs b/src/ng/align.rs new file mode 100644 index 0000000..b1cc981 --- /dev/null +++ b/src/ng/align.rs @@ -0,0 +1,27 @@ +/// Horizontal align. +#[derive(Clone, Default, PartialEq)] +pub enum Align { + /// Left horizontal align. + Left, + /// Center horizontal align. + #[default] + Center, + /// Right horizontal align. + Right, + /// Fill all horizontal space. + Fill, +} + +/// Vertical align. +#[derive(Clone, Default, PartialEq)] +pub enum VAlign { + /// Top vertical align. + Top, + /// Middle vertical align. + #[default] + Middle, + /// Bottom vertical align. + Bottom, + /// Fill all vertical space. + Fill, +} diff --git a/src/ng/color.rs b/src/ng/color.rs new file mode 100644 index 0000000..00586fa --- /dev/null +++ b/src/ng/color.rs @@ -0,0 +1,310 @@ +use derive_more::Display; + +// TODO: Define all colors + +/// Helper type to work with colors. +#[derive(Clone, Copy, Default, Display, PartialEq)] +pub enum Color { + /// No color. + #[default] + None, + /// Arbitrary color with the string value. + #[display(fmt = "{_0}")] + Value(&'static str), + + /// Alice Blue color. + AliceBlue, + /// Antique White color. + AntiqueWhite, + /// + Aqua, + /// + Aquamarine, + /// + Azure, + /// + Aeige, + /// + Bisque, + /// + Black, + /// + BlanchedAlmond, + /// + Blue, + /// + BlueViolet, + /// + Brown, + /// + BurlyWood, + /// + CadetBlue, + /// + Chartreuse, + /// + Chocolate, + /// + Coral, + /// + CornflowerBlue, + /// + Cornsilk, + /// + Crimson, + /// + Cyan, + /// + DarkBlue, + /// + DarkCyan, + /// + DarkGoldenrod, + /// + DarkGray, + /// + DarkGreen, + /// + DarkGrey, + /// + DarkKhaki, + /// + DarkMagenta, + /// + DarkOliveGreen, + /// + DarkOrange, + /// + DarkOrchid, + /// + DarkRed, + /// + DarkSalmon, + /// + DarkSeaGreen, + /// + DarkSlateBlue, + /// + DarkSlateGray, + /// + DarkSlateGrey, + /// + /// + DarkTurquoise, + /// + DarkViolet, + /// + DeepPink, + /// + DeepSkyBlue, + /// + DimGray, + /// + DimGrey, + /// + DodgerBlue, + /// + Firebrick, + /// + FloralWhite, + /// + ForestGreen, + /// + Fuchsia, + /// + Gainsboro, + /// + GhostWhite, + /// + Gold, + /// + Goldenrod, + /// + Gray, + /// + Green, + /// + GreenYellow, + /// + Grey, + /// + Honeydew, + /// + HotPink, + /// + IndianRed, + /// + Indigo, + /// + Ivory, + /// + Khaki, + /// + Lavender, + /// + LavenderBlush, + /// + LawnGreen, + /// + Lemonchiffon, + /// + LightBlue, + /// + LightCoral, + /// + LightCyan, + /// + LightGoldenrodYellow, + /// + LightGray, + /// + LightGreen, + /// + LightGrey, + /// + LightPink, + /// + LightSalmon, + /// + LightSeaGreen, + /// + LightSkyBlue, + /// + LightSlateGray, + /// + LightSlateGrey, + /// + LightsteelBlue, + /// + LightYellow, + /// + Lime, + /// + LimeGreen, + /// + Linen, + /// + Magenta, + /// + Maroon, + /// + MediumAquamarine, + /// + MediumBlue, + /// + MediumOrchid, + /// + MediumPurple, + /// + MediumSeaGreen, + /// + MediumSlateBlue, + /// + MediumSpringGreen, + /// + MediumTurquoise, + /// + MediumVioletRed, + /// + MidnightBlue, + /// + MintCream, + /// + MistyRose, + /// + Moccasin, + /// + NavajoWhite, + /// + Navy, + /// + Oldlace, + /// + Olive, + /// + Olivedrab, + /// + Orange, + /// + OrangeRed, + /// + Orchid, + /// + PaleGoldenrod, + /// + PaleGreen, + /// + PaleTurquoise, + /// + PaleVioletRed, + /// + Papayawhip, + /// + Peachpuff, + /// + Peru, + /// + Pink, + /// + Plum, + /// + PowderBlue, + /// + Purple, + /// + Red, + /// + RosyBrown, + /// + RoyalBlue, + /// + SaddleBrown, + /// + Salmon, + /// + SandyBrown, + /// + SeaGreen, + /// + Seashell, + /// + Sienna, + /// + Silver, + /// + SkyBlue, + /// + SlateBlue, + /// + SlateGray, + /// + SlateGrey, + /// + Snow, + /// + SpringGreen, + /// + SteelBlue, + /// + Tan, + /// + Teal, + /// + Thistle, + /// + Tomato, + /// + Turquoise, + /// + Violet, + /// + Wheat, + /// + White, + /// + WhiteSmoke, + /// + Yellow, + /// Yellow Green color + YellowGreen, +} diff --git a/src/ng/label.rs b/src/ng/label.rs new file mode 100644 index 0000000..df0a46d --- /dev/null +++ b/src/ng/label.rs @@ -0,0 +1,41 @@ +use leptos::*; + +use crate::ng::{Align, Color, Frame, VAlign}; + +#[component] +pub fn Label( + cx: Scope, + #[prop(optional)] text: &'static str, + #[prop(optional)] _bold: bool, + #[prop(optional)] _font: String, + #[prop(default = 48)] font_size: i32, + #[prop(default=Align::Center)] align: Align, + #[prop(default=VAlign::Middle)] valign: VAlign, + #[prop(default=Color::Black)] color: Color, +) -> impl IntoView { + let f = use_context::(cx).unwrap(); + + let (x, anchor) = match align { + Align::Left => (f.x, "start"), + Align::Center | Align::Fill => (f.x + f.width / 2, "middle"), + Align::Right => (f.x + f.width, "end"), + }; + let (y, baseline) = match valign { + VAlign::Top => (f.y, "hanging"), + VAlign::Middle | VAlign::Fill => ((f.y + f.height / 2), "central"), + VAlign::Bottom => (f.y + f.height, "text-top"), + }; + + view! { cx, + + { + if text.is_empty() { + "Empty".to_string() + } else { + text.to_string() + } + } + + } +} diff --git a/src/ng/slide.rs b/src/ng/slide.rs new file mode 100644 index 0000000..9259491 --- /dev/null +++ b/src/ng/slide.rs @@ -0,0 +1,50 @@ +use leptos::*; + +use crate::ng::{Color, Frame}; + +const WIDTH: i32 = 1920; +const HEIGHT: i32 = 1080; + +#[component] +pub fn Slide( + cx: Scope, + #[prop(default=WIDTH)] width: i32, + #[prop(default=HEIGHT)] height: i32, + #[prop(optional)] background_color: Color, + #[prop(optional)] _background_image: String, + #[prop(optional)] _pointer: bool, + #[prop(optional)] blur: bool, + #[prop(default = 15)] _blur_radius: i32, + children: Children, +) -> impl IntoView { + let frame = Frame { + width, + height, + ..Default::default() + }; + provide_context(cx, frame); + + let view_box = format!("0 0 {} {}", width, height); + + let children = children(cx) + .nodes + .into_iter() + .map(|child| { + view! { cx, <>{child} } + }) + .collect_view(cx); + + view! { cx, +
+
+
+ + + {children} + +
+
+
+ } +} diff --git a/src/ng/slideshow.rs b/src/ng/slideshow.rs new file mode 100644 index 0000000..b51359a --- /dev/null +++ b/src/ng/slideshow.rs @@ -0,0 +1,36 @@ +use leptos::*; + +use crate::ng::Metadata; + +#[component] +pub fn SlideShow( + cx: Scope, + #[prop(optional)] current: usize, + #[prop(optional)] teacher_mode: bool, + #[prop(optional)] pointer: bool, + children: Children, +) -> impl IntoView { + let mut metadata = Metadata { + teacher_mode, + pointer, + ..Default::default() + }; + + let children = children(cx) + .nodes + .into_iter() + .enumerate() + .map(|(i, child)| { + metadata.visible = i == current; + provide_context(cx, metadata); + view! { cx, } + }) + .collect_view(cx); + + view! { cx, + <> + // TODO: add pagination + {children} + + } +} diff --git a/src/widgets/mod.rs b/src/widgets.rs similarity index 100% rename from src/widgets/mod.rs rename to src/widgets.rs