diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..7bbf351 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,54 @@ +name: Templates CI + +on: + push: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + + +# workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: -D warnings + +jobs: + check: + if: github.event.pull_request.draft == false + name: Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: cargo-bins/cargo-binstall@v1.10.13 + - run: cargo binstall dioxus-cli@0.6.0-alpha.5 + - run: sudo apt update + - run: sudo apt install expect libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev + + # Test bare bones + - name: Create Bare-Bones + run: dx new --template . --subtemplate Bare-Bones --yes --option default_platform=web barebones-all + + - name: Test Bare-Bones + working-directory: ./barebones-all + run: cargo check + + # Test Jumpstart + - name: Create Jumpstart + run: dx new --template . --subtemplate Jumpstart --yes --option default_platform=web jumpstart-all + + - name: Test Jumpstart + working-directory: ./jumpstart-all + run: cargo check + + # Test Workspace + - name: Create Workspace + run: dx new --template . --subtemplate Workspace --yes workspace-all + + - name: Test Workspace + working-directory: ./workspace-all + run: cargo check + \ No newline at end of file diff --git a/.gitignore b/Bare-Bones/.gitignore similarity index 100% rename from .gitignore rename to Bare-Bones/.gitignore diff --git a/Bare-Bones/Cargo.toml b/Bare-Bones/Cargo.toml new file mode 100644 index 0000000..a6acfb1 --- /dev/null +++ b/Bare-Bones/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "{{project-name}}" +version = "0.1.0" +authors = ["{{authors}}"] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus = { {{ dioxus_dep_src }}, features = {{dioxus_dep_features}} } +dioxus-logger = "0.5" + +[features] +default = ["{{default_platform}}"] +{%- for feature in features %} +{{ feature }} +{%- endfor %} \ No newline at end of file diff --git a/Dioxus.toml b/Bare-Bones/Dioxus.toml similarity index 68% rename from Dioxus.toml rename to Bare-Bones/Dioxus.toml index ddc5a6c..6be7283 100644 --- a/Dioxus.toml +++ b/Bare-Bones/Dioxus.toml @@ -3,15 +3,11 @@ # App (Project) Name name = "{{project-name}}" -# Dioxus App Default Platform -# web, desktop, fullstack -default_platform = "desktop" - -# `build` & `serve` dist path +# `build` dist path out_dir = "dist" -# assets file folder -asset_dir = "assets" +# resource (assets) file folder +asset_dir = "none" [web.app] @@ -30,11 +26,7 @@ watch_path = ["src", "assets"] [web.resource] # CSS style file -{% if styling == "Tailwind" %} -style = ["/tailwind.css"] -{% else %} style = [] -{% endif %} # Javascript code file script = [] diff --git a/Bare-Bones/README.md b/Bare-Bones/README.md new file mode 100644 index 0000000..055cdb9 --- /dev/null +++ b/Bare-Bones/README.md @@ -0,0 +1,34 @@ +# Development + +Your new bare-bones project includes minimal organization with a single `main.rs` file and a few assets. + +{% if is_tailwind -%} +### 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 +3. Run the following command in the root of the project to start the Tailwind CSS compiler: + +```bash +npx tailwindcss -i ./input.css -o ./assets/tailwind.css --watch +``` +{%- endif %} + +### 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 +``` + +{% if is_mobile -%} +To serve on mobile, you need to explicitly set your target device, `android` or `ios`: +```bash +dx serve --platform android +``` +{%- endif %} \ No newline at end of file diff --git a/Bare-Bones/assets/favicon.ico b/Bare-Bones/assets/favicon.ico new file mode 100644 index 0000000..eed0c09 Binary files /dev/null and b/Bare-Bones/assets/favicon.ico differ diff --git a/assets/header.svg b/Bare-Bones/assets/header.svg similarity index 100% rename from assets/header.svg rename to Bare-Bones/assets/header.svg diff --git a/Bare-Bones/assets/main.css b/Bare-Bones/assets/main.css new file mode 100644 index 0000000..a0a5583 --- /dev/null +++ b/Bare-Bones/assets/main.css @@ -0,0 +1,111 @@ +/* App-wide styling */ +body { + background-color: #0f1116; + color: #ffffff; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + margin: 20px; +} + +#hero { + margin: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +#links { + width: 400px; + text-align: left; + font-size: x-large; + color: white; + display: flex; + flex-direction: column; +} + +#links a { + color: white; + text-decoration: none; + margin-top: 20px; + margin: 10px 0px; + border: white 1px solid; + border-radius: 5px; + padding: 10px; +} + +#links a:hover { + background-color: #1f1f1f; + cursor: pointer; +} + +#header { + max-width: 1200px; +} + +{% if is_router -%} +/* Navbar */ +#navbar { + display: flex; + flex-direction: row; + } + +#navbar a { + color: #ffffff; + margin-right: 20px; + text-decoration: none; + transition: color 0.2s ease; +} + +#navbar a:hover { + cursor: pointer; + color: #91a4d2; +} + +/* Blog page */ +#blog { + margin-top: 50px; + } + +#blog a { + color: #ffffff; + margin-top: 50px; +} +{%- endif %} + +{% if is_fullstack -%} +/* Echo */ +#echo { + width: 360px; + margin-left: auto; + margin-right: auto; + margin-top: 50px; + background-color: #1e222d; + padding: 20px; + border-radius: 10px; +} + +#echo>h4 { + margin: 0px 0px 15px 0px; +} + + +#echo>input { + border: none; + border-bottom: 1px white solid; + background-color: transparent; + color: #ffffff; + transition: border-bottom-color 0.2s ease; + outline: none; + display: block; + padding: 0px 0px 5px 0px; + width: 100%; +} + +#echo>input:focus { + border-bottom-color: #6d85c6; +} + +#echo>p { + margin: 20px 0px 0px auto; +} +{%- endif %} \ No newline at end of file diff --git a/Bare-Bones/cargo-generate.toml b/Bare-Bones/cargo-generate.toml new file mode 100644 index 0000000..fb3ea05 --- /dev/null +++ b/Bare-Bones/cargo-generate.toml @@ -0,0 +1,14 @@ +[template] + +[hooks] +pre = ["init.rhai", "../common.rhai"] +post = ["conditional-files.rhai"] + +[placeholders] +is_web = { prompt = "Do you want to build for Dioxus Web?", default = true, type = "bool" } +is_desktop = { prompt = "Do you want to build for Dioxus Desktop?", default = true, type = "bool" } +is_mobile = { prompt = "Do you want to build for Dioxus Mobile?", default = true, type = "bool" } + +is_fullstack = { prompt = "Do you want to use Dioxus Fullstack?", default = true, type = "bool" } +is_router = { prompt = "Do you want to use the Dioxus Router?", default = true, type = "bool" } +is_tailwind = { prompt = "Do you want to use Tailwind CSS?", default = false, type = "bool" } diff --git a/Bare-Bones/conditional-files.rhai b/Bare-Bones/conditional-files.rhai new file mode 100644 index 0000000..24ca1cf --- /dev/null +++ b/Bare-Bones/conditional-files.rhai @@ -0,0 +1,9 @@ +// This file handles conditional files for this specific sub-template. + +const IS_TAILWIND_VAR = "is_tailwind"; + +let is_tailwind = variable::get(IS_TAILWIND_VAR); +if !is_tailwind { + file::delete("tailwind.config.js"); + file::delete("input.css"); +} \ No newline at end of file diff --git a/Bare-Bones/init.rhai b/Bare-Bones/init.rhai new file mode 100644 index 0000000..1718b90 --- /dev/null +++ b/Bare-Bones/init.rhai @@ -0,0 +1,3 @@ +// Tell the common init script that this template needs the default platform. +variable::set("needs_default_platform", true); +// variable::set("needs_tailwind_prompt", true); \ No newline at end of file diff --git a/input.css b/Bare-Bones/input.css similarity index 100% rename from input.css rename to Bare-Bones/input.css diff --git a/Bare-Bones/src/main.rs b/Bare-Bones/src/main.rs new file mode 100644 index 0000000..bf24192 --- /dev/null +++ b/Bare-Bones/src/main.rs @@ -0,0 +1,160 @@ +use dioxus::prelude::*; +use dioxus_logger::tracing::Level; + +{% if is_router %} +#[derive(Debug, Clone, Routable, PartialEq)] +#[rustfmt::skip] +enum Route { + #[layout(Navbar)] + #[route("/")] + Home {}, + #[route("/blog/:id")] + Blog { id: i32 }, +} +{% endif %} + +const FAVICON: Asset = asset!("/assets/favicon.ico"); +const MAIN_CSS: Asset = asset!("/assets/main.css"); +const HEADER_SVG: Asset = asset!("/assets/header.svg"); +{% if is_tailwind -%} +const TAILWIND_CSS: Asset = asset!("/assets/tailwind.css"); +{%- endif %} + +fn main() { + dioxus_logger::init(Level::INFO).expect("failed to init logger"); + dioxus::launch(App); +} + +#[component] +fn App() -> Element { + // Build cool things ✌️ + + rsx! { + // Global app resources + document::Link { rel: "icon", href: FAVICON } + document::Link { rel: "stylesheet", href: MAIN_CSS } + {% if is_tailwind -%} + document::Link { rel: "stylesheet", href: TAILWIND_CSS } + {%- endif %} + + {% if is_router -%} + Router:: {} + {%- else -%} + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + {%- endif %} + } +} + +#[component] +pub fn Hero() -> Element { + rsx! { + div { + id: "hero", + img { src: HEADER_SVG, id: "header" } + div { id: "links", + a { target: "_blank", href: "https://dioxuslabs.com/learn/0.6/", "📚 Learn Dioxus" } + a { target: "_blank", href: "https://dioxuslabs.com/awesome", "🚀 Awesome Dioxus" } + a { target: "_blank", href: "https://github.com/dioxus-community/", "📡 Community Libraries" } + a { target: "_blank", href: "https://github.com/DioxusLabs/sdk", "⚙️ Dioxus Development Kit" } + a { target: "_blank", href: "https://marketplace.visualstudio.com/items?itemName=DioxusLabs.dioxus", "💫 VSCode Extension" } + a { target: "_blank", href: "https://discord.gg/XgGxMSkvUM", "👋 Community Discord" } + } + } + } +} + +{% if is_router -%} +/// Home page +#[component] +fn Home() -> Element { + rsx! { + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + } +} + +/// Blog page +#[component] +pub fn Blog(id: i32) -> Element { + rsx! { + div { + id: "blog", + + // Content + h1 { "This is blog #{id}!" } + p { "In blog #{id}, we show how the Dioxus router works and how URL paramaters can be passed as props to our route components." } + + // Navigation links + Link { + to: Route::Blog { id: id - 1 }, + "Previous" + } + span { " <---> " } + Link { + to: Route::Blog { id: id + 1 }, + "Next" + } + } + } +} + +/// Shared navbar component. +#[component] +fn Navbar() -> Element { + rsx! { + div { + id: "navbar", + Link { + to: Route::Home {}, + "Home" + } + Link { + to: Route::Blog { id: 1 }, + "Blog" + } + } + + Outlet:: {} + } +} +{%- endif %} + +{% if is_fullstack -%} +/// Echo component that demonstrates fullstack server functions. +#[component] +fn Echo() -> Element { + let mut response = use_signal(|| String::new()); + + rsx! { + div { + id: "echo", + h4 { "ServerFn Echo" } + input { + placeholder: "Type here to echo...", + oninput: move |event| async move { + let data = echo_server(event.value()).await.unwrap(); + response.set(data); + }, + } + + if !response().is_empty() { + p { + "Server echoed: " + i { "{response}" } + } + } + } + } +} + +/// Echo the user input on the server. +#[server(EchoServer)] +async fn echo_server(input: String) -> Result { + Ok(input) +} +{%- endif %} \ No newline at end of file diff --git a/tailwind.config.js b/Bare-Bones/tailwind.config.js similarity index 100% rename from tailwind.config.js rename to Bare-Bones/tailwind.config.js diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index a528a01..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "{{project-name}}" -version = "0.1.0" -authors = ["{{authors}}"] -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -dioxus = { version = "0.6.0-alpha.5", features = [{% if router %}"router",{% endif %}{% if fullstack %}"fullstack",{% endif %}] } - - -[features] -web = ["dioxus/web"] -desktop = ["dioxus/desktop"] -mobile = ["dioxus/mobile"] -server = ["dioxus/server"] diff --git a/Jumpstart/.gitignore b/Jumpstart/.gitignore new file mode 100644 index 0000000..5f0b8d2 --- /dev/null +++ b/Jumpstart/.gitignore @@ -0,0 +1,12 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +/dist/ +/static/ +/.dioxus/ + +# this file will generate by tailwind: +/assets/tailwind.css + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/Jumpstart/Cargo.toml b/Jumpstart/Cargo.toml new file mode 100644 index 0000000..a6acfb1 --- /dev/null +++ b/Jumpstart/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "{{project-name}}" +version = "0.1.0" +authors = ["{{authors}}"] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus = { {{ dioxus_dep_src }}, features = {{dioxus_dep_features}} } +dioxus-logger = "0.5" + +[features] +default = ["{{default_platform}}"] +{%- for feature in features %} +{{ feature }} +{%- endfor %} \ No newline at end of file diff --git a/Jumpstart/Dioxus.toml b/Jumpstart/Dioxus.toml new file mode 100644 index 0000000..6be7283 --- /dev/null +++ b/Jumpstart/Dioxus.toml @@ -0,0 +1,38 @@ +[application] + +# App (Project) Name +name = "{{project-name}}" + +# `build` dist path +out_dir = "dist" + +# resource (assets) file folder +asset_dir = "none" + +[web.app] + +# HTML title tag content +title = "{{project-name}}" + +[web.watcher] + +# when watcher trigger, regenerate the `index.html` +reload_html = true + +# which files or dirs will be watcher monitoring +watch_path = ["src", "assets"] + +# include `assets` in web platform +[web.resource] + +# CSS style file +style = [] + +# Javascript code file +script = [] + +[web.resource.dev] + +# Javascript code file +# serve: [dev-server] only +script = [] diff --git a/Jumpstart/README.md b/Jumpstart/README.md new file mode 100644 index 0000000..6ce9a3a --- /dev/null +++ b/Jumpstart/README.md @@ -0,0 +1,35 @@ +# Development + +Your new jumpstart project includes basic organization with an organized `assets` folder and a `components` folder. +If you chose to develop with the router feature, you will also have a `views` folder. + +{% if is_tailwind -%} +### 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 +3. Run the following command in the root of the project to start the Tailwind CSS compiler: + +```bash +npx tailwindcss -i ./input.css -o ./assets/styling/tailwind.css --watch +``` +{%- endif %} + +### 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 +``` + +{% if is_mobile -%} +To serve on mobile, you need to explicitly set your target device, `android` or `ios`: +```bash +dx serve --platform android +``` +{%- endif %} \ No newline at end of file diff --git a/Jumpstart/assets/favicon.ico b/Jumpstart/assets/favicon.ico new file mode 100644 index 0000000..eed0c09 Binary files /dev/null and b/Jumpstart/assets/favicon.ico differ diff --git a/Jumpstart/assets/header.svg b/Jumpstart/assets/header.svg new file mode 100644 index 0000000..59c96f2 --- /dev/null +++ b/Jumpstart/assets/header.svg @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/Jumpstart/assets/styling/blog.css b/Jumpstart/assets/styling/blog.css new file mode 100644 index 0000000..f27f060 --- /dev/null +++ b/Jumpstart/assets/styling/blog.css @@ -0,0 +1,8 @@ +#blog { + margin-top: 50px; +} + +#blog a { + color: #ffffff; + margin-top: 50px; +} \ No newline at end of file diff --git a/Jumpstart/assets/styling/echo.css b/Jumpstart/assets/styling/echo.css new file mode 100644 index 0000000..67d9b2b --- /dev/null +++ b/Jumpstart/assets/styling/echo.css @@ -0,0 +1,34 @@ +#echo { + width: 360px; + margin-left: auto; + margin-right: auto; + margin-top: 50px; + background-color: #1e222d; + padding: 20px; + border-radius: 10px; +} + +#echo>h4 { + margin: 0px 0px 15px 0px; +} + + +#echo>input { + border: none; + border-bottom: 1px white solid; + background-color: transparent; + color: #ffffff; + transition: border-bottom-color 0.2s ease; + outline: none; + display: block; + padding: 0px 0px 5px 0px; + width: 100%; +} + +#echo>input:focus { + border-bottom-color: #6d85c6; +} + +#echo>p { + margin: 20px 0px 0px auto; +} \ No newline at end of file diff --git a/assets/main.css b/Jumpstart/assets/styling/main.css similarity index 85% rename from assets/main.css rename to Jumpstart/assets/styling/main.css index affbeb0..e13b92d 100644 --- a/assets/main.css +++ b/Jumpstart/assets/styling/main.css @@ -1,14 +1,16 @@ body { - background-color: #111216; + background-color: #0f1116; + color: #ffffff; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + margin: 20px; } -#main { +#hero { margin: 0; display: flex; flex-direction: column; justify-content: center; align-items: center; - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif } #links { @@ -24,7 +26,7 @@ body { color: white; text-decoration: none; margin-top: 20px; - margin: 10px; + margin: 10px 0px; border: white 1px solid; border-radius: 5px; padding: 10px; @@ -37,4 +39,4 @@ body { #header { max-width: 1200px; -} +} \ No newline at end of file diff --git a/Jumpstart/assets/styling/navbar.css b/Jumpstart/assets/styling/navbar.css new file mode 100644 index 0000000..7372c63 --- /dev/null +++ b/Jumpstart/assets/styling/navbar.css @@ -0,0 +1,16 @@ +#navbar { + display: flex; + flex-direction: row; +} + +#navbar a { + color: #ffffff; + margin-right: 20px; + text-decoration: none; + transition: color 0.2s ease; +} + +#navbar a:hover { + cursor: pointer; + color: #91a4d2; +} \ No newline at end of file diff --git a/Jumpstart/cargo-generate.toml b/Jumpstart/cargo-generate.toml new file mode 100644 index 0000000..bed6512 --- /dev/null +++ b/Jumpstart/cargo-generate.toml @@ -0,0 +1,14 @@ +[template] + +[hooks] +pre = ["init.rhai", "../common.rhai"] +post = ["conditional-files.rhai"] + +[placeholders] +is_web = { prompt = "Do you want to build for Dioxus Web?", default = true, type = "bool" } +is_desktop = { prompt = "Do you want to build for Dioxus Desktop?", default = true, type = "bool" } +is_mobile = { prompt = "Do you want to build for Dioxus Mobile?", default = true, type = "bool" } + +is_fullstack = { prompt = "Do you want to use Dioxus Fullstack?", default = true, type = "bool" } +is_router = { prompt = "Do you want to use the Dioxus Router?", default = true, type = "bool" } +is_tailwind = { prompt = "Do you want to use Tailwind CSS?", default = false, type = "bool" } \ No newline at end of file diff --git a/Jumpstart/conditional-files.rhai b/Jumpstart/conditional-files.rhai new file mode 100644 index 0000000..d0599d2 --- /dev/null +++ b/Jumpstart/conditional-files.rhai @@ -0,0 +1,25 @@ +// This file handles conditional files for this specific sub-template. + +const IS_TAILWIND_VAR = "is_tailwind"; +const IS_ROUTER_VAR = "is_router"; +const IS_FULLSTACK_VAR = "is_fullstack"; + +let is_tailwind = variable::get(IS_TAILWIND_VAR); +if !is_tailwind { + file::delete("tailwind.config.js"); + file::delete("input.css"); +} + +let is_router = variable::get(IS_ROUTER_VAR); +if !is_router { + file::delete("src/views"); + file::delete("src/components/navbar.rs"); + file::delete("assets/styling/navbar.css"); + file::delete("assets/styling/blog.css"); +} + +let is_fullstack = variable::get(IS_FULLSTACK_VAR); +if !is_fullstack { + file::delete("src/components/echo.rs"); + file::delete("assets/styling/echo.css"); +} \ No newline at end of file diff --git a/Jumpstart/init.rhai b/Jumpstart/init.rhai new file mode 100644 index 0000000..c4ffadb --- /dev/null +++ b/Jumpstart/init.rhai @@ -0,0 +1,2 @@ +// Tell the common init script that this template needs the default platform. +variable::set("needs_default_platform", true); \ No newline at end of file diff --git a/Jumpstart/input.css b/Jumpstart/input.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/Jumpstart/input.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/Jumpstart/src/components/echo.rs b/Jumpstart/src/components/echo.rs new file mode 100644 index 0000000..edeb567 --- /dev/null +++ b/Jumpstart/src/components/echo.rs @@ -0,0 +1,37 @@ +use dioxus::prelude::*; + +const ECHO_CSS: Asset = asset!("/assets/styling/echo.css"); + +/// Echo component that demonstrates fullstack server functions. +#[component] +pub fn Echo() -> Element { + let mut response = use_signal(|| String::new()); + + rsx! { + document::Link { rel: "stylesheet", href: ECHO_CSS } + div { + id: "echo", + h4 { "ServerFn Echo" } + input { + placeholder: "Type here to echo...", + oninput: move |event| async move { + let data = echo_server(event.value()).await.unwrap(); + response.set(data); + }, + } + + if !response().is_empty() { + p { + "Server echoed: " + i { "{response}" } + } + } + } + } +} + +/// Echo the user input on the server. +#[server(EchoServer)] +async fn echo_server(input: String) -> Result { + Ok(input) +} \ No newline at end of file diff --git a/Jumpstart/src/components/hero.rs b/Jumpstart/src/components/hero.rs new file mode 100644 index 0000000..69553f3 --- /dev/null +++ b/Jumpstart/src/components/hero.rs @@ -0,0 +1,21 @@ +use dioxus::prelude::*; + +const HEADER_SVG: Asset = asset!("/assets/header.svg"); + +#[component] +pub fn Hero() -> Element { + rsx! { + div { + id: "hero", + img { src: HEADER_SVG, id: "header" } + div { id: "links", + a { target: "_blank", href: "https://dioxuslabs.com/learn/0.6/", "📚 Learn Dioxus" } + a { target: "_blank", href: "https://dioxuslabs.com/awesome", "🚀 Awesome Dioxus" } + a { target: "_blank", href: "https://github.com/dioxus-community/", "📡 Community Libraries" } + a { target: "_blank", href: "https://github.com/DioxusLabs/sdk", "⚙️ Dioxus Development Kit" } + a { target: "_blank", href: "https://marketplace.visualstudio.com/items?itemName=DioxusLabs.dioxus", "💫 VSCode Extension" } + a { target: "_blank", href: "https://discord.gg/XgGxMSkvUM", "👋 Community Discord" } + } + } + } +} diff --git a/Jumpstart/src/components/mod.rs b/Jumpstart/src/components/mod.rs new file mode 100644 index 0000000..da3d10c --- /dev/null +++ b/Jumpstart/src/components/mod.rs @@ -0,0 +1,12 @@ +mod hero; +pub use hero::Hero; + +{% if is_router -%} +mod navbar; +pub use navbar::Navbar; +{%- endif %} + +{% if is_fullstack -%} +mod echo; +pub use echo::Echo; +{%- endif %} diff --git a/Jumpstart/src/components/navbar.rs b/Jumpstart/src/components/navbar.rs new file mode 100644 index 0000000..16bcf73 --- /dev/null +++ b/Jumpstart/src/components/navbar.rs @@ -0,0 +1,25 @@ +use crate::Route; +use dioxus::prelude::*; + +const NAVBAR_CSS: Asset = asset!("/assets/styling/navbar.css"); + +#[component] +pub fn Navbar() -> Element { + rsx! { + document::Link { rel: "stylesheet", href: NAVBAR_CSS } + + div { + id: "navbar", + Link { + to: Route::Home {}, + "Home" + } + Link { + to: Route::Blog { id: 1 }, + "Blog" + } + } + + Outlet:: {} + } +} diff --git a/Jumpstart/src/main.rs b/Jumpstart/src/main.rs new file mode 100644 index 0000000..e68e86b --- /dev/null +++ b/Jumpstart/src/main.rs @@ -0,0 +1,64 @@ +use dioxus::prelude::*; +use dioxus_logger::tracing::Level; + +{% if is_router -%} +use components::Navbar; +{%- else -%} +{% if is_fullstack -%} +use components::{Hero, Echo}; +{%- else -%} +use components::Hero; +{%- endif %} +{%- endif %} +{% if is_router -%} +use views::{Blog, Home}; +{%- endif %} + +mod components; +{% if is_router -%} +mod views; + +#[derive(Debug, Clone, Routable, PartialEq)] +#[rustfmt::skip] +enum Route { + #[layout(Navbar)] + #[route("/")] + Home {}, + #[route("/blog/:id")] + Blog { id: i32 }, +} +{%- endif %} + +const FAVICON: Asset = asset!("/assets/favicon.ico"); +const MAIN_CSS: Asset = asset!("/assets/styling/main.css"); +{% if is_tailwind -%} +const TAILWIND_CSS: Asset = asset!("/assets/tailwind.css"); +{%- endif %} + +fn main() { + dioxus_logger::init(Level::INFO).expect("failed to init logger"); + dioxus::launch(App); +} + +#[component] +fn App() -> Element { + // Build cool things ✌️ + + rsx! { + // Global app resources + document::Link { rel: "icon", href: FAVICON } + document::Link { rel: "stylesheet", href: MAIN_CSS } + {% if is_tailwind -%} + document::Link { rel: "stylesheet", href: TAILWIND_CSS } + {%- endif %} + + {% if is_router -%} + Router:: {} + {%- else -%} + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + {%- endif %} + } +} diff --git a/Jumpstart/src/views/blog.rs b/Jumpstart/src/views/blog.rs new file mode 100644 index 0000000..c268013 --- /dev/null +++ b/Jumpstart/src/views/blog.rs @@ -0,0 +1,30 @@ +use crate::Route; +use dioxus::prelude::*; + +const BLOG_CSS: Asset = asset!("/assets/styling/blog.css"); + +#[component] +pub fn Blog(id: i32) -> Element { + rsx! { + document::Link { rel: "stylesheet", href: BLOG_CSS} + + div { + id: "blog", + + // Content + h1 { "This is blog #{id}!" } + p { "In blog #{id}, we show how the Dioxus router works and how URL paramaters can be passed as props to our route components." } + + // Navigation links + Link { + to: Route::Blog { id: id - 1 }, + "Previous" + } + span { " <---> " } + Link { + to: Route::Blog { id: id + 1 }, + "Next" + } + } + } +} diff --git a/Jumpstart/src/views/home.rs b/Jumpstart/src/views/home.rs new file mode 100644 index 0000000..dbf6c5c --- /dev/null +++ b/Jumpstart/src/views/home.rs @@ -0,0 +1,16 @@ +use dioxus::prelude::*; +{% if is_fullstack -%} +use crate::components::{Hero, Echo}; +{%- else -%} +use crate::components::Hero; +{%- endif %} + +#[component] +pub fn Home() -> Element { + rsx! { + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + } +} diff --git a/Jumpstart/src/views/mod.rs b/Jumpstart/src/views/mod.rs new file mode 100644 index 0000000..6e40d5b --- /dev/null +++ b/Jumpstart/src/views/mod.rs @@ -0,0 +1,5 @@ +mod home; +pub use home::Home; + +mod blog; +pub use blog::Blog; \ No newline at end of file diff --git a/Jumpstart/tailwind.config.js b/Jumpstart/tailwind.config.js new file mode 100644 index 0000000..2a69d58 --- /dev/null +++ b/Jumpstart/tailwind.config.js @@ -0,0 +1,9 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + mode: "all", + content: ["./src/**/*.{rs,html,css}", "./dist/**/*.html"], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/README.md b/README.md index 5ea3a32..0c33653 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,23 @@ -# Development -{% if styling == "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 -3. Run the following command in the root of the project to start the tailwind CSS compiler: - -```bash -npx tailwindcss -i ./input.css -o ./assets/tailwind.css --watch -``` -{% endif %} -Run the following command in the root of the project to start the Dioxus dev server: - -```bash -dx serve --hot-reload --platform desktop -``` \ No newline at end of file +# Overview + +**This repo is not intended to be `git cloned`**. + +This repo is used by `dx new` when starting new projects. The CLI relies on [cargo-generate](https://crates.io/crates/cargo-generate) to create and use these templates. + +### Organization + +This repository is organized into three sub-templates: +- `Bare-Bones` - A single file bare-bones Dioxus project. +- `Jumpstart` - A more structured jumpstart with a starting file structure. +- `Workspace` - A full workspace with a crate for shared functionality and every platform. + +All templates support every platform, router, and fullstack. + +### Local Development +To run and test the templates without `dx`, you can run `cargo generate --path myPathToTemplates` + +The templates have a few different scripts: +- `init.rhai` runs first and sets variables that tell the `init-common.rhai` script what this template needs. +- `init-common.rhai` is a common script for all the templates which asks for a variety of information from the user. +- `vars.rhai` is a script that can set additional variables based on the already-ran scripts. For example, generating a new string to insert into the template based on previous variables. +- `conditional-files.rhai` runs last and deletes files and folders based on the variables set by `init-common.rhai`. \ No newline at end of file diff --git a/Workspace/.gitignore b/Workspace/.gitignore new file mode 100644 index 0000000..5f0b8d2 --- /dev/null +++ b/Workspace/.gitignore @@ -0,0 +1,12 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +/dist/ +/static/ +/.dioxus/ + +# this file will generate by tailwind: +/assets/tailwind.css + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/Workspace/Cargo.toml b/Workspace/Cargo.toml new file mode 100644 index 0000000..6eed1a7 --- /dev/null +++ b/Workspace/Cargo.toml @@ -0,0 +1,18 @@ +[workspace] +resolver = "2" +members = [ + "ui", + {%- for member in workspace_members %} + "{{- member -}}", + {%- endfor %} +] + +[workspace.dependencies] +dioxus = { {{ dioxus_dep_src }} } +dioxus-logger = "0.5" + +# workspace +ui = { path = "ui" } +{% if is_fullstack -%} +server = { path = "server" } +{%- endif %} \ No newline at end of file diff --git a/Workspace/README.md b/Workspace/README.md new file mode 100644 index 0000000..5bec655 --- /dev/null +++ b/Workspace/README.md @@ -0,0 +1,25 @@ +# Development + +Depending on your selected options, your new workspace project contains a workspace member for each platform. +If you chose to develop with the router feature, each platform crate will have a `views` folder for your platform-specific views. +You are provided with a `ui` crate for shared UI and if you chose to use fullstack, you will have a `server` crate for your shared server functions. + +### Serving Your App + +Navigate to the platform crate of your choice: +```bash +cd web +``` + +and serve: + +```bash +dx serve +``` + +{% if is_mobile -%} +Mobile platforms are shared in a single crate. To serve mobile, you need to explicitly set your target device, `android` or `ios`: +```bash +dx serve --platform android +``` +{%- endif %} \ No newline at end of file diff --git a/Workspace/cargo-generate.toml b/Workspace/cargo-generate.toml new file mode 100644 index 0000000..37c291d --- /dev/null +++ b/Workspace/cargo-generate.toml @@ -0,0 +1,13 @@ +[template] + +[hooks] +pre = ["init.rhai", "../common.rhai", "vars.rhai"] +post = ["conditional-files.rhai"] + +[placeholders] +is_web = { prompt = "Do you want to build for Dioxus Web?", default = true, type = "bool" } +is_desktop = { prompt = "Do you want to build for Dioxus Desktop?", default = true, type = "bool" } +is_mobile = { prompt = "Do you want to build for Dioxus Mobile?", default = true, type = "bool" } + +is_fullstack = { prompt = "Do you want to use Dioxus Fullstack?", default = true, type = "bool" } +is_router = { prompt = "Do you want to use the Dioxus Router?", default = true, type = "bool" } \ No newline at end of file diff --git a/Workspace/conditional-files.rhai b/Workspace/conditional-files.rhai new file mode 100644 index 0000000..4a82c76 --- /dev/null +++ b/Workspace/conditional-files.rhai @@ -0,0 +1,45 @@ +// This file handles conditional files for this specific sub-template. + +const IS_WEB_VAR = "is_web"; +const IS_DESKTOP_VAR = "is_desktop"; +const IS_MOBILE_VAR = "is_mobile"; +const IS_FULLSTACK_VAR = "is_fullstack"; +const IS_ROUTER_VAR = "is_router"; + +let is_web = variable::get(IS_WEB_VAR); +if !is_web { + file::delete("web"); +} + +let is_desktop = variable::get(IS_DESKTOP_VAR); +if !is_desktop { + file::delete("desktop"); +} + +let is_mobile = variable::get(IS_MOBILE_VAR); +if !is_mobile { + file::delete("mobile"); +} + +let is_fullstack = variable::get(IS_FULLSTACK_VAR); +if !is_fullstack { + file::delete("server"); + file::delete("ui/src/echo.rs"); + file::delete("ui/assets/styling/echo.css"); +} + +let is_router = variable::get(IS_ROUTER_VAR); +if !is_router { + file::delete("web/src/views"); + file::delete("web/assets/blog.css"); + + file::delete("desktop/src/views"); + file::delete("desktop/assets/blog.css"); + + file::delete("mobile/src/views"); + file::delete("mobile/assets/blog.css"); + + file::delete("ui/src/navbar.rs"); + file::delete("ui/assets/styling/navbar.css"); + file::delete("ui/assets/styling/blog.css"); +} \ No newline at end of file diff --git a/Workspace/desktop/Cargo.toml b/Workspace/desktop/Cargo.toml new file mode 100644 index 0000000..5376abe --- /dev/null +++ b/Workspace/desktop/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "desktop" +version = "0.1.0" +edition = "2021" + +[dependencies] +dioxus = { workspace = true, features = [{{- router_feature -}}] } +dioxus-logger = { workspace = true } +ui = { workspace = true } + +[features] +default = ["desktop"] +desktop = ["dioxus/desktop"] +{% if is_fullstack -%} +server = ["dioxus/server"] +{%- endif %} \ No newline at end of file diff --git a/Workspace/desktop/assets/blog.css b/Workspace/desktop/assets/blog.css new file mode 100644 index 0000000..f27f060 --- /dev/null +++ b/Workspace/desktop/assets/blog.css @@ -0,0 +1,8 @@ +#blog { + margin-top: 50px; +} + +#blog a { + color: #ffffff; + margin-top: 50px; +} \ No newline at end of file diff --git a/Workspace/desktop/assets/main.css b/Workspace/desktop/assets/main.css new file mode 100644 index 0000000..ef6e674 --- /dev/null +++ b/Workspace/desktop/assets/main.css @@ -0,0 +1,6 @@ +body { + background-color: #0f1116; + color: #ffffff; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + margin: 20px; +} \ No newline at end of file diff --git a/Workspace/desktop/src/main.rs b/Workspace/desktop/src/main.rs new file mode 100644 index 0000000..f4c810a --- /dev/null +++ b/Workspace/desktop/src/main.rs @@ -0,0 +1,77 @@ +use dioxus::prelude::*; +use dioxus_logger::tracing::Level; + +{% if is_router -%} +use ui::Navbar; +{%- else -%} +{% if is_fullstack -%} +use ui::{Hero, Echo}; +{%- else -%} +use ui::Hero; +{%- endif %} +{%- endif %} +{% if is_router -%} +use views::{Blog, Home}; +{%- endif %} + +{% if is_router %} +mod views; + +#[derive(Debug, Clone, Routable, PartialEq)] +#[rustfmt::skip] +enum Route { + #[layout(DesktopNavbar)] + #[route("/")] + Home {}, + #[route("/blog/:id")] + Blog { id: i32 }, +} +{% endif %} + +const MAIN_CSS: Asset = asset!("/assets/main.css"); + +fn main() { + dioxus_logger::init(Level::INFO).expect("failed to init logger"); + dioxus::launch(App); +} + +#[component] +fn App() -> Element { + // Build cool things ✌️ + + rsx! { + // Global app resources + document::Link { rel: "stylesheet", href: MAIN_CSS } + + {% if is_router -%} + Router:: {} + {%- else -%} + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + {%- endif %} + } +} + +{% if is_router -%} +/// A desktop-specific Router around the shared `Navbar` component +/// which allows us to use the desktop-specific `Route` enum. +#[component] +fn DesktopNavbar() -> Element { + rsx! { + Navbar { + Link { + to: Route::Home {}, + "Home" + } + Link { + to: Route::Blog { id: 1 }, + "Blog" + } + } + + Outlet:: {} + } +} +{%- endif %} \ No newline at end of file diff --git a/Workspace/desktop/src/views/blog.rs b/Workspace/desktop/src/views/blog.rs new file mode 100644 index 0000000..4245084 --- /dev/null +++ b/Workspace/desktop/src/views/blog.rs @@ -0,0 +1,30 @@ +use crate::Route; +use dioxus::prelude::*; + +const BLOG_CSS: Asset = asset!("/assets/blog.css"); + +#[component] +pub fn Blog(id: i32) -> Element { + rsx! { + document::Link { rel: "stylesheet", href: BLOG_CSS} + + div { + id: "blog", + + // Content + h1 { "This is blog #{id}!" } + p { "In blog #{id}, we show how the Dioxus router works and how URL paramaters can be passed as props to our route components." } + + // Navigation links + Link { + to: Route::Blog { id: id - 1 }, + "Previous" + } + span { " <---> " } + Link { + to: Route::Blog { id: id + 1 }, + "Next" + } + } + } +} diff --git a/Workspace/desktop/src/views/home.rs b/Workspace/desktop/src/views/home.rs new file mode 100644 index 0000000..d0411ec --- /dev/null +++ b/Workspace/desktop/src/views/home.rs @@ -0,0 +1,16 @@ +use dioxus::prelude::*; +{% if is_fullstack -%} +use ui::{Hero, Echo}; +{%- else -%} +use ui::Hero; +{%- endif %} + +#[component] +pub fn Home() -> Element { + rsx! { + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + } +} diff --git a/Workspace/desktop/src/views/mod.rs b/Workspace/desktop/src/views/mod.rs new file mode 100644 index 0000000..6e40d5b --- /dev/null +++ b/Workspace/desktop/src/views/mod.rs @@ -0,0 +1,5 @@ +mod home; +pub use home::Home; + +mod blog; +pub use blog::Blog; \ No newline at end of file diff --git a/Workspace/init.rhai b/Workspace/init.rhai new file mode 100644 index 0000000..6bfdc02 --- /dev/null +++ b/Workspace/init.rhai @@ -0,0 +1,2 @@ +// Tell the common init script that this template doesn't need the default platform. +variable::set("needs_default_platform", false); \ No newline at end of file diff --git a/Workspace/mobile/Cargo.toml b/Workspace/mobile/Cargo.toml new file mode 100644 index 0000000..a6cb68f --- /dev/null +++ b/Workspace/mobile/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "mobile" +version = "0.1.0" +edition = "2021" + +[dependencies] +dioxus = { workspace = true, features = [{{- router_feature -}}] } +dioxus-logger = { workspace = true } +ui = { workspace = true } + +[features] +default = ["mobile"] +mobile = ["dioxus/mobile"] +{% if is_fullstack -%} +server = ["dioxus/server"] +{%- endif %} \ No newline at end of file diff --git a/Workspace/mobile/assets/blog.css b/Workspace/mobile/assets/blog.css new file mode 100644 index 0000000..f27f060 --- /dev/null +++ b/Workspace/mobile/assets/blog.css @@ -0,0 +1,8 @@ +#blog { + margin-top: 50px; +} + +#blog a { + color: #ffffff; + margin-top: 50px; +} \ No newline at end of file diff --git a/Workspace/mobile/assets/main.css b/Workspace/mobile/assets/main.css new file mode 100644 index 0000000..ef6e674 --- /dev/null +++ b/Workspace/mobile/assets/main.css @@ -0,0 +1,6 @@ +body { + background-color: #0f1116; + color: #ffffff; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + margin: 20px; +} \ No newline at end of file diff --git a/Workspace/mobile/src/main.rs b/Workspace/mobile/src/main.rs new file mode 100644 index 0000000..004f990 --- /dev/null +++ b/Workspace/mobile/src/main.rs @@ -0,0 +1,77 @@ +use dioxus::prelude::*; +use dioxus_logger::tracing::Level; + +{% if is_router -%} +use ui::Navbar; +{%- else -%} +{% if is_fullstack -%} +use ui::{Hero, Echo}; +{%- else -%} +use ui::Hero; +{%- endif %} +{%- endif %} +{% if is_router -%} +use views::{Blog, Home}; +{%- endif %} + +{% if is_router %} +mod views; + +#[derive(Debug, Clone, Routable, PartialEq)] +#[rustfmt::skip] +enum Route { + #[layout(MobileNavbar)] + #[route("/")] + Home {}, + #[route("/blog/:id")] + Blog { id: i32 }, +} +{% endif %} + +const MAIN_CSS: Asset = asset!("/assets/main.css"); + +fn main() { + dioxus_logger::init(Level::INFO).expect("failed to init logger"); + dioxus::launch(App); +} + +#[component] +fn App() -> Element { + // Build cool things ✌️ + + rsx! { + // Global app resources + document::Link { rel: "stylesheet", href: MAIN_CSS } + + {% if is_router -%} + Router:: {} + {%- else -%} + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + {%- endif %} + } +} + +{% if is_router -%} +/// A mobile-specific Router around the shared `Navbar` component +/// which allows us to use the mobile-specific `Route` enum. +#[component] +fn MobileNavbar() -> Element { + rsx! { + Navbar { + Link { + to: Route::Home {}, + "Home" + } + Link { + to: Route::Blog { id: 1 }, + "Blog" + } + } + + Outlet:: {} + } +} +{%- endif %} \ No newline at end of file diff --git a/Workspace/mobile/src/views/blog.rs b/Workspace/mobile/src/views/blog.rs new file mode 100644 index 0000000..4245084 --- /dev/null +++ b/Workspace/mobile/src/views/blog.rs @@ -0,0 +1,30 @@ +use crate::Route; +use dioxus::prelude::*; + +const BLOG_CSS: Asset = asset!("/assets/blog.css"); + +#[component] +pub fn Blog(id: i32) -> Element { + rsx! { + document::Link { rel: "stylesheet", href: BLOG_CSS} + + div { + id: "blog", + + // Content + h1 { "This is blog #{id}!" } + p { "In blog #{id}, we show how the Dioxus router works and how URL paramaters can be passed as props to our route components." } + + // Navigation links + Link { + to: Route::Blog { id: id - 1 }, + "Previous" + } + span { " <---> " } + Link { + to: Route::Blog { id: id + 1 }, + "Next" + } + } + } +} diff --git a/Workspace/mobile/src/views/home.rs b/Workspace/mobile/src/views/home.rs new file mode 100644 index 0000000..d0411ec --- /dev/null +++ b/Workspace/mobile/src/views/home.rs @@ -0,0 +1,16 @@ +use dioxus::prelude::*; +{% if is_fullstack -%} +use ui::{Hero, Echo}; +{%- else -%} +use ui::Hero; +{%- endif %} + +#[component] +pub fn Home() -> Element { + rsx! { + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + } +} diff --git a/Workspace/mobile/src/views/mod.rs b/Workspace/mobile/src/views/mod.rs new file mode 100644 index 0000000..6e40d5b --- /dev/null +++ b/Workspace/mobile/src/views/mod.rs @@ -0,0 +1,5 @@ +mod home; +pub use home::Home; + +mod blog; +pub use blog::Blog; \ No newline at end of file diff --git a/Workspace/server/Cargo.toml b/Workspace/server/Cargo.toml new file mode 100644 index 0000000..442bf6c --- /dev/null +++ b/Workspace/server/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "server" +version = "0.1.0" +edition = "2021" + +[dependencies] +dioxus = { workspace = true, features = ["fullstack"] } +dioxus-logger = { workspace = true } \ No newline at end of file diff --git a/Workspace/server/src/lib.rs b/Workspace/server/src/lib.rs new file mode 100644 index 0000000..3962b16 --- /dev/null +++ b/Workspace/server/src/lib.rs @@ -0,0 +1,8 @@ +//! This crate contains all shared fullstack server functions. +use dioxus::prelude::*; + +/// Echo the user input on the server. +#[server(Echo)] +pub async fn echo(input: String) -> Result { + Ok(input) +} \ No newline at end of file diff --git a/Workspace/ui/Cargo.toml b/Workspace/ui/Cargo.toml new file mode 100644 index 0000000..deef1ba --- /dev/null +++ b/Workspace/ui/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ui" +version = "0.1.0" +edition = "2021" + +[dependencies] +dioxus = { workspace = true } +dioxus-logger = { workspace = true } +{% if is_fullstack -%} +server = { workspace = true } +{%- endif %} \ No newline at end of file diff --git a/Workspace/ui/assets/header.svg b/Workspace/ui/assets/header.svg new file mode 100644 index 0000000..59c96f2 --- /dev/null +++ b/Workspace/ui/assets/header.svg @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/Workspace/ui/assets/styling/echo.css b/Workspace/ui/assets/styling/echo.css new file mode 100644 index 0000000..67d9b2b --- /dev/null +++ b/Workspace/ui/assets/styling/echo.css @@ -0,0 +1,34 @@ +#echo { + width: 360px; + margin-left: auto; + margin-right: auto; + margin-top: 50px; + background-color: #1e222d; + padding: 20px; + border-radius: 10px; +} + +#echo>h4 { + margin: 0px 0px 15px 0px; +} + + +#echo>input { + border: none; + border-bottom: 1px white solid; + background-color: transparent; + color: #ffffff; + transition: border-bottom-color 0.2s ease; + outline: none; + display: block; + padding: 0px 0px 5px 0px; + width: 100%; +} + +#echo>input:focus { + border-bottom-color: #6d85c6; +} + +#echo>p { + margin: 20px 0px 0px auto; +} \ No newline at end of file diff --git a/Workspace/ui/assets/styling/hero.css b/Workspace/ui/assets/styling/hero.css new file mode 100644 index 0000000..79db803 --- /dev/null +++ b/Workspace/ui/assets/styling/hero.css @@ -0,0 +1,35 @@ +#hero { + margin: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +#links { + width: 400px; + text-align: left; + font-size: x-large; + color: white; + display: flex; + flex-direction: column; +} + +#links a { + color: white; + text-decoration: none; + margin-top: 20px; + margin: 10px 0px; + border: white 1px solid; + border-radius: 5px; + padding: 10px; +} + +#links a:hover { + background-color: #1f1f1f; + cursor: pointer; +} + +#header { + max-width: 1200px; +} \ No newline at end of file diff --git a/Workspace/ui/assets/styling/navbar.css b/Workspace/ui/assets/styling/navbar.css new file mode 100644 index 0000000..7372c63 --- /dev/null +++ b/Workspace/ui/assets/styling/navbar.css @@ -0,0 +1,16 @@ +#navbar { + display: flex; + flex-direction: row; +} + +#navbar a { + color: #ffffff; + margin-right: 20px; + text-decoration: none; + transition: color 0.2s ease; +} + +#navbar a:hover { + cursor: pointer; + color: #91a4d2; +} \ No newline at end of file diff --git a/Workspace/ui/src/echo.rs b/Workspace/ui/src/echo.rs new file mode 100644 index 0000000..caefa44 --- /dev/null +++ b/Workspace/ui/src/echo.rs @@ -0,0 +1,31 @@ +use dioxus::prelude::*; + +const ECHO_CSS: Asset = asset!("/assets/styling/echo.css"); + +/// Echo component that demonstrates fullstack server functions. +#[component] +pub fn Echo() -> Element { + let mut response = use_signal(|| String::new()); + + rsx! { + document::Link { rel: "stylesheet", href: ECHO_CSS } + div { + id: "echo", + h4 { "ServerFn Echo" } + input { + placeholder: "Type here to echo...", + oninput: move |event| async move { + let data = server::echo(event.value()).await.unwrap(); + response.set(data); + }, + } + + if !response().is_empty() { + p { + "Server echoed: " + i { "{response}" } + } + } + } + } +} \ No newline at end of file diff --git a/Workspace/ui/src/hero.rs b/Workspace/ui/src/hero.rs new file mode 100644 index 0000000..5352609 --- /dev/null +++ b/Workspace/ui/src/hero.rs @@ -0,0 +1,24 @@ +use dioxus::prelude::*; + +const HERO_CSS: Asset = asset!("/assets/styling/hero.css"); +const HEADER_SVG: Asset = asset!("/assets/header.svg"); + +#[component] +pub fn Hero() -> Element { + rsx! { + document::Link { rel: "stylesheet", href: HERO_CSS } + + div { + id: "hero", + img { src: HEADER_SVG, id: "header" } + div { id: "links", + a { target: "_blank", href: "https://dioxuslabs.com/learn/0.6/", "📚 Learn Dioxus" } + a { target: "_blank", href: "https://dioxuslabs.com/awesome", "🚀 Awesome Dioxus" } + a { target: "_blank", href: "https://github.com/dioxus-community/", "📡 Community Libraries" } + a { target: "_blank", href: "https://github.com/DioxusLabs/sdk", "⚙️ Dioxus Development Kit" } + a { target: "_blank", href: "https://marketplace.visualstudio.com/items?itemName=DioxusLabs.dioxus", "💫 VSCode Extension" } + a { target: "_blank", href: "https://discord.gg/XgGxMSkvUM", "👋 Community Discord" } + } + } + } +} diff --git a/Workspace/ui/src/lib.rs b/Workspace/ui/src/lib.rs new file mode 100644 index 0000000..c1ab744 --- /dev/null +++ b/Workspace/ui/src/lib.rs @@ -0,0 +1,14 @@ +//! This crate contains all shared UI for the workspace. + +mod hero; +pub use hero::Hero; + +{% if is_router -%} +mod navbar; +pub use navbar::Navbar; +{%- endif %} + +{% if is_fullstack -%} +mod echo; +pub use echo::Echo; +{%- endif %} diff --git a/Workspace/ui/src/navbar.rs b/Workspace/ui/src/navbar.rs new file mode 100644 index 0000000..c169782 --- /dev/null +++ b/Workspace/ui/src/navbar.rs @@ -0,0 +1,15 @@ +use dioxus::prelude::*; + +const NAVBAR_CSS: Asset = asset!("/assets/styling/navbar.css"); + +#[component] +pub fn Navbar(children: Element) -> Element { + rsx! { + document::Link { rel: "stylesheet", href: NAVBAR_CSS } + + div { + id: "navbar", + {children} + } + } +} diff --git a/Workspace/vars.rhai b/Workspace/vars.rhai new file mode 100644 index 0000000..16544b1 --- /dev/null +++ b/Workspace/vars.rhai @@ -0,0 +1,37 @@ +// This file sets variables based on the results of the shared-init script. + +const WORKSPACE_MEMBERS_VAR = "workspace_members"; +const ROUTER_FEATURE_VAR = "router_feature"; + +const IS_WEB_VAR = "is_web"; +const IS_DESKTOP_VAR = "is_desktop"; +const IS_MOBILE_VAR = "is_mobile"; +const IS_FULLSTACK = "is_fullstack"; +const IS_ROUTER = "is_router"; + +let workspace_members = []; + +if variable::get(IS_WEB_VAR) { + workspace_members += "web" +} + +if variable::get(IS_DESKTOP_VAR) { + workspace_members += "desktop" +} + +if variable::get(IS_WEB_VAR) { + workspace_members += "mobile" +} + +if variable::get(IS_FULLSTACK) { + workspace_members += "server" +} + +variable::set(WORKSPACE_MEMBERS_VAR, workspace_members); + +// Router feature +if variable::get(IS_ROUTER) { + variable::set(ROUTER_FEATURE_VAR, "\"router\""); +} else { + variable::set(ROUTER_FEATURE_VAR, ""); +} \ No newline at end of file diff --git a/Workspace/web/Cargo.toml b/Workspace/web/Cargo.toml new file mode 100644 index 0000000..7de3063 --- /dev/null +++ b/Workspace/web/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "web" +version = "0.1.0" +edition = "2021" + +[dependencies] +dioxus = { workspace = true, features = [{{- router_feature -}}] } +dioxus-logger = { workspace = true } +ui = { workspace = true } + +[features] +default = ["web"] +web = ["dioxus/web"] +{% if is_fullstack -%} +server = ["dioxus/server"] +{%- endif %} \ No newline at end of file diff --git a/Workspace/web/assets/blog.css b/Workspace/web/assets/blog.css new file mode 100644 index 0000000..f27f060 --- /dev/null +++ b/Workspace/web/assets/blog.css @@ -0,0 +1,8 @@ +#blog { + margin-top: 50px; +} + +#blog a { + color: #ffffff; + margin-top: 50px; +} \ No newline at end of file diff --git a/Workspace/web/assets/favicon.ico b/Workspace/web/assets/favicon.ico new file mode 100644 index 0000000..eed0c09 Binary files /dev/null and b/Workspace/web/assets/favicon.ico differ diff --git a/Workspace/web/assets/main.css b/Workspace/web/assets/main.css new file mode 100644 index 0000000..ef6e674 --- /dev/null +++ b/Workspace/web/assets/main.css @@ -0,0 +1,6 @@ +body { + background-color: #0f1116; + color: #ffffff; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + margin: 20px; +} \ No newline at end of file diff --git a/Workspace/web/src/main.rs b/Workspace/web/src/main.rs new file mode 100644 index 0000000..691dd3d --- /dev/null +++ b/Workspace/web/src/main.rs @@ -0,0 +1,79 @@ +use dioxus::prelude::*; +use dioxus_logger::tracing::Level; + +{% if is_router -%} +use ui::Navbar; +{%- else -%} +{% if is_fullstack -%} +use ui::{Hero, Echo}; +{%- else -%} +use ui::Hero; +{%- endif %} +{%- endif %} +{% if is_router -%} +use views::{Blog, Home}; +{%- endif %} + +{% if is_router %} +mod views; + +#[derive(Debug, Clone, Routable, PartialEq)] +#[rustfmt::skip] +enum Route { + #[layout(WebNavbar)] + #[route("/")] + Home {}, + #[route("/blog/:id")] + Blog { id: i32 }, +} +{% endif %} + +const FAVICON: Asset = asset!("/assets/favicon.ico"); +const MAIN_CSS: Asset = asset!("/assets/main.css"); + +fn main() { + dioxus_logger::init(Level::INFO).expect("failed to init logger"); + dioxus::launch(App); +} + +#[component] +fn App() -> Element { + // Build cool things ✌️ + + rsx! { + // Global app resources + document::Link { rel: "icon", href: FAVICON } + document::Link { rel: "stylesheet", href: MAIN_CSS } + + {% if is_router -%} + Router:: {} + {%- else -%} + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + {%- endif %} + } +} + +{% if is_router -%} +/// A web-specific Router around the shared `Navbar` component +/// which allows us to use the web-specific `Route` enum. +#[component] +fn WebNavbar() -> Element { + rsx! { + Navbar { + Link { + to: Route::Home {}, + "Home" + } + Link { + to: Route::Blog { id: 1 }, + "Blog" + } + } + + Outlet:: {} + } +} +{%- endif %} \ No newline at end of file diff --git a/Workspace/web/src/views/blog.rs b/Workspace/web/src/views/blog.rs new file mode 100644 index 0000000..4245084 --- /dev/null +++ b/Workspace/web/src/views/blog.rs @@ -0,0 +1,30 @@ +use crate::Route; +use dioxus::prelude::*; + +const BLOG_CSS: Asset = asset!("/assets/blog.css"); + +#[component] +pub fn Blog(id: i32) -> Element { + rsx! { + document::Link { rel: "stylesheet", href: BLOG_CSS} + + div { + id: "blog", + + // Content + h1 { "This is blog #{id}!" } + p { "In blog #{id}, we show how the Dioxus router works and how URL paramaters can be passed as props to our route components." } + + // Navigation links + Link { + to: Route::Blog { id: id - 1 }, + "Previous" + } + span { " <---> " } + Link { + to: Route::Blog { id: id + 1 }, + "Next" + } + } + } +} diff --git a/Workspace/web/src/views/home.rs b/Workspace/web/src/views/home.rs new file mode 100644 index 0000000..d0411ec --- /dev/null +++ b/Workspace/web/src/views/home.rs @@ -0,0 +1,16 @@ +use dioxus::prelude::*; +{% if is_fullstack -%} +use ui::{Hero, Echo}; +{%- else -%} +use ui::Hero; +{%- endif %} + +#[component] +pub fn Home() -> Element { + rsx! { + Hero {} + {% if is_fullstack -%} + Echo {} + {%- endif %} + } +} diff --git a/Workspace/web/src/views/mod.rs b/Workspace/web/src/views/mod.rs new file mode 100644 index 0000000..6e40d5b --- /dev/null +++ b/Workspace/web/src/views/mod.rs @@ -0,0 +1,5 @@ +mod home; +pub use home::Home; + +mod blog; +pub use blog::Blog; \ No newline at end of file diff --git a/cargo-generate.toml b/cargo-generate.toml index f0b4d7b..532ff33 100644 --- a/cargo-generate.toml +++ b/cargo-generate.toml @@ -1,12 +1,2 @@ [template] - -[placeholders] -styling = { prompt = "How do you want to create CSS?", choices = [ - "Tailwind", - "Vanilla", -], default = "Vanilla", type = "string" } -router = { prompt = "Should the application use the Dioxus router?", type = "bool", default = true } -fullstack = { prompt = "Should the application enable fullstack?", type = "bool", default = true } - -[conditional.'styling == "Vanilla"'] -ignore = ["tailwind.config.js", "input.css"] +sub_templates = ["Bare-Bones", "Jumpstart", "Workspace"] \ No newline at end of file diff --git a/common.rhai b/common.rhai new file mode 100644 index 0000000..8e1488c --- /dev/null +++ b/common.rhai @@ -0,0 +1,97 @@ +// Dioxus version. This only needs changed to update all templates. +// You can change this in development to be `path = "abc/"` or `git = "xyz"` for local development. +const DIOXUS_DEP_SRC_VAR = "dioxus_dep_src"; +variable::set(DIOXUS_DEP_SRC_VAR, "version = \"0.6.0-alpha.5\""); + +// These are variables that are used in liquid +const NEEDS_DEFAULT_PLATFORM_VAR = "needs_default_platform"; +// const NEEDS_TAILWIND_PROMPT_VAR = "needs_tailwind_prompt"; + +const DIOXUS_DEP_FEAT_VAR = "dioxus_dep_features"; +const DEFAULT_PLATFORM_VAR = "default_platform"; + +const IS_WEB_VAR = "is_web"; +const IS_DESKTOP_VAR = "is_desktop"; +const IS_MOBILE_VAR = "is_mobile"; + +const IS_ROUTER_VAR = "is_router"; +const IS_FULLSTACK_VAR = "is_fullstack"; +// const IS_TAILWIND_VAR = "is_tailwind"; + +const FEATURES_VAR = "features"; + +// Figure out what platforms +let features = []; +let platforms = []; + +// Web +let is_web = variable::get(IS_WEB_VAR); +if is_web { + platforms += "Web"; + features += "web = [\"dioxus/web\"]"; +} + +// Desktop +let is_desktop = variable::get(IS_DESKTOP_VAR); +if is_desktop { + platforms += "Desktop"; + features += "desktop = [\"dioxus/desktop\"]"; +} + +// Mobile +let is_mobile = variable::get(IS_MOBILE_VAR); +if is_mobile { + // Mobile can't currently be a default platform. + features += "mobile = [\"dioxus/mobile\"]"; +} + +// Do we need a default platform? +if variable::get(NEEDS_DEFAULT_PLATFORM_VAR) { + let is_default_platform_set = variable::is_set(DEFAULT_PLATFORM_VAR); + + // If set, check if valid, otherwise abort. + // If not set, figure out if we need it. + if is_default_platform_set { + let value = variable::get(DEFAULT_PLATFORM_VAR); + + // Lowercase the platforms so they match the expected defined variable. + let lowercased_platforms = []; + for platform in platforms { + lowercased_platforms += platform.to_lower(); + } + + // Check if provided definition is a valid choice. + let is_valid = lowercased_platforms.some(|v| v == value); + if !is_valid { + abort("The `default_platform` variable is not valid based on the selected platforms."); + } + } else { + // Make sure the user chose at least one platform. + if platforms.len() == 0 { + if is_mobile { + variable::set(DEFAULT_PLATFORM_VAR, "mobile"); + } else { + abort("You must choose at least one platform to build for."); + } + } else { + let default_platform = variable::prompt("Which platform do you want DX to serve by default?", platforms[0], platforms); + variable::set(DEFAULT_PLATFORM_VAR, default_platform.to_lower()); + } + } +} + + +let is_router = variable::get(IS_ROUTER_VAR); +let is_fullstack = variable::get(IS_FULLSTACK_VAR); +switch [is_router, is_fullstack] { + [true, true] => variable::set(DIOXUS_DEP_FEAT_VAR, "[\"router\", \"fullstack\"]"), + [true, false] => variable::set(DIOXUS_DEP_FEAT_VAR, "[\"router\"]"), + [false, true] => variable::set(DIOXUS_DEP_FEAT_VAR, "[\"fullstack\"]"), + _ => variable::set(DIOXUS_DEP_FEAT_VAR, "[]") +} + +// Set features +variable::set(FEATURES_VAR, features); + +// Rhai has weird returns. This ensures that the above statement isn't returned instead. +return; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 13c9ab4..0000000 --- a/src/main.rs +++ /dev/null @@ -1,68 +0,0 @@ - -use dioxus::prelude::*; -{% if router %} -#[derive(Clone, Routable, Debug, PartialEq)] -enum Route { - #[route("/")] - Home {}, - #[route("/blog/:id")] - Blog { id: i32 }, -} -{% endif %} - -fn main() { - dioxus::launch(app); -} - -{% if router %} -fn app() -> Element { - rsx! { - Router:: {} - } -} - -#[component] -fn Blog(id: i32) -> Element { - rsx! { - Link { to: Route::Home {}, "Go to counter" } - "Blog post {id}" - } -} - -#[component] -fn Home() -> Element { - let mut count = use_signal(|| 0); - - rsx! { - Link { - to: Route::Blog { - id: count() - }, - "Go to blog" - } - div { - h1 { "High-Five counter: {count}" } - button { onclick: move |_| count += 1, "Up high!" } - button { onclick: move |_| count -= 1, "Down low!" } - } - } -} -{% else %} -fn app() -> Element { - // Build cool things ✌️ - rsx! { - link { rel: "stylesheet", href: asset!("/assets/main.css") } - img { id: "header", src: asset!("/assets/header.svg") } - div { id: "links", - a { href: "https://dioxuslabs.com/learn/0.6/", "📚 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" } - } - } -} -{% endif %}