├── .github └── workflows │ └── main.yml ├── .gitignore ├── Cargo.toml ├── Dioxus.toml ├── LICENSE ├── README.md ├── README.zh-CN.md ├── index.html ├── public ├── CNAME ├── assets │ ├── dioxus.png │ └── tailwind │ │ ├── tailwind.config.js │ │ └── tailwind.min.js ├── favicon.ico └── robots.txt ├── settings.json └── src ├── components ├── content.rs ├── footer.rs └── mod.rs ├── hooks ├── markdown.rs ├── mod.rs └── mode.rs ├── main.rs ├── markdown └── readme.md └── pages ├── _404.rs ├── mod.rs └── starter.rs /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: github pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build-deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: "Dioxus Deploy" 13 | uses: DioxusLabs/deploy-action@v1 14 | with: 15 | toolSource: "mrxiaozhuox/dioxus-cli" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | # System file 13 | .DS_Store 14 | 15 | # Add by dioxus 16 | /dist/ -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-starter" 3 | version = "0.2.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | dioxus = { version = "0.5.6", features = ["web", "router"] } 10 | fermi = "0.4.3" 11 | 12 | js-sys = "0.3.58" 13 | web-sys = { version = "0.3.58", features = ["Storage"] } 14 | dioxus-free-icons = { version = "0.8.6", features = ["font-awesome-brands", "font-awesome-solid" ] } 15 | dioxus-toast = { version = "0.4.0", default-features = false, features = ["web"] } 16 | gloo = "0.8.0" 17 | log = "0.4.6" 18 | wasm-logger = "0.2.0" 19 | anyhow = "1.0.57" 20 | urlencoding = "2.1.0" 21 | pulldown-cmark = "0.9.1" 22 | 23 | # dioxus-sdk = { version = "0.5", features = ["storage"] } 24 | dioxus-sdk = { git = "https://github.com/DioxusLabs/sdk/", features = ["storage"] } 25 | 26 | -------------------------------------------------------------------------------- /Dioxus.toml: -------------------------------------------------------------------------------- 1 | [application] 2 | 3 | # dioxus project name 4 | name = "dioxus-starter" 5 | 6 | # default platfrom 7 | # you can also use `dioxus serve/build --platform XXX` to use other platform 8 | # value: web | desktop 9 | default_platform = "web" 10 | 11 | # Web `build` & `serve` dist path 12 | out_dir = "dist" 13 | 14 | # resource (static) file folder 15 | asset_dir = "public" 16 | 17 | [web.app] 18 | 19 | # HTML title tag content 20 | title = "Dioxus Starter | opinionated dioxus template" 21 | 22 | [web.watcher] 23 | 24 | watch_path = [ 25 | "src", 26 | "public", 27 | "Dioxus.toml", 28 | ] 29 | 30 | index_on_404 = true 31 | 32 | # include `assets` in web platform 33 | [web.resource] 34 | 35 | # CSS style file 36 | style = [] 37 | 38 | # Javascript code file 39 | script = [ 40 | "/assets/tailwind/tailwind.min.js", 41 | "/assets/tailwind/tailwind.config.js", 42 | ] 43 | 44 | [web.resource.dev] 45 | 46 | # Javascript code file 47 | # serve: [dev-server] only 48 | script = [] 49 | 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 YuKun Liu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Dioxus Starter

3 |
4 | 5 |
6 | Online Demo 7 |
8 | 9 |
10 |

11 | English 12 | | 13 | 简体中文 14 |

15 |
16 | 17 | ## Features 18 | 19 | - 🧭 [Dynamic routing](https://dioxuslabs.com/nightly/router/) support 20 | - ☀️ Light / Dark mode support 21 | - 🏡 [Tailwind](https://tailwindcss.com/) framework support 22 | - 📙 Markdown parser support 23 | - 🍿 [Toast](https://github.com/mrxiaozhuox/dioxus-toast) popup support 24 | - 💎 [FA](https://fontawesome.com/) free icon support 25 | 26 | ## Pre-Packed 27 | 28 | ### UI Framework 29 | 30 | - [Tailwind](https://github.com/tailwindlabs/tailwindcss) - A utility-first CSS framework 31 | 32 | ### Dioxus Plugins 33 | 34 | - [Dioxus Router](https://github.com/DioxusLabs/dioxus/tree/master/packages/router) - Dioxus Router is a first-party router for Dioxus 35 | - [Dioxus Fermi](https://github.com/DioxusLabs/dioxus/tree/master/packages/fermi) - Atom-based global state management solution for Dioxus 36 | - [Dioxus Free Icon](https://github.com/nissy-dev/dioxus-free-icons) - Use free svg icons in your Dioxus 37 | - [Dioxus Toast](https://github.com/mrxiaozhuox/dioxus-toast) - Add toast support for your Dioxus 38 | - [Dioxus Local torage](https://github.com/mrxiaozhuox/dioxus-local-storage) - Add Storage Hooks for Dioxus 39 | 40 | ## Try it 41 | 42 | ``` 43 | dx create --template=gh:mrxiaozhuox/dioxus-starter 44 | cd {PROJECT_NAME} 45 | dx serve 46 | ``` 47 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrxiaozhuox/dioxus-starter/57d0d9a7fb3e02b81de87bdb5b60b57e9c2e76df/README.zh-CN.md -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {app_title} 5 | 6 | 7 | 8 | 9 | {style_include} 10 | 11 | 12 | 13 |
14 | 22 | {script_include} 23 | 24 | -------------------------------------------------------------------------------- /public/CNAME: -------------------------------------------------------------------------------- 1 | dioxus-starter.mrxzx.info -------------------------------------------------------------------------------- /public/assets/dioxus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrxiaozhuox/dioxus-starter/57d0d9a7fb3e02b81de87bdb5b60b57e9c2e76df/public/assets/dioxus.png -------------------------------------------------------------------------------- /public/assets/tailwind/tailwind.config.js: -------------------------------------------------------------------------------- 1 | tailwind.config = { 2 | darkMode: "class" 3 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrxiaozhuox/dioxus-starter/57d0d9a7fb3e02b81de87bdb5b60b57e9c2e76df/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / -------------------------------------------------------------------------------- /settings.json: -------------------------------------------------------------------------------- 1 | {"Lua.diagnostics.globals":["library_dir"],"Lua.workspace.library":["../core/"]} -------------------------------------------------------------------------------- /src/components/content.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use pulldown_cmark::Parser; 3 | 4 | #[component] 5 | pub fn Href(to: ReadOnlySignal, children: Element) -> Element { 6 | rsx! { 7 | a { class: "text-cyan-700 dark:text-cyan-100 underline", href: "{to}", target: "_blank", { children } } 8 | } 9 | } 10 | 11 | #[derive(Props, PartialEq, Clone)] 12 | pub struct MarkdownProps { 13 | #[props(default)] 14 | class: ReadOnlySignal, 15 | content: String, 16 | } 17 | 18 | #[component] 19 | pub fn Markdown(props: MarkdownProps) -> Element { 20 | let content = &props.content; 21 | let parser = Parser::new(content); 22 | let mut html_buf = String::new(); 23 | pulldown_cmark::html::push_html(&mut html_buf, parser); 24 | let extra_class = &props.class; 25 | rsx! {div { id: "markdown-body", class: "prose {extra_class}", dangerous_inner_html: "{html_buf}" }} 26 | } 27 | -------------------------------------------------------------------------------- /src/components/footer.rs: -------------------------------------------------------------------------------- 1 | use crate::hooks::mode::{mode, use_mode}; 2 | use dioxus::prelude::*; 3 | use dioxus_free_icons::{ 4 | icons::{fa_brands_icons, fa_solid_icons}, 5 | Icon, 6 | }; 7 | 8 | pub fn Footer() -> Element { 9 | let mut current_mode = use_mode(); 10 | rsx! { 11 | div { class: "mt-6 flex space-x-4 justify-center", 12 | Link { 13 | class: "text-black dark:text-white hover:text-gray-800 dark:hover:text-gray-200", 14 | to: "/", 15 | Icon { height: 26, width: 26, icon: fa_solid_icons::FaHouse } 16 | } 17 | a { 18 | class: "text-black dark:text-white hover:text-gray-800 dark:hover:text-gray-200", 19 | href: "javascript:;", 20 | onclick: move |_| { 21 | let is_dark = !current_mode.read().clone(); 22 | // current_mode.set(dark); 23 | *current_mode.write() = is_dark; 24 | mode(is_dark); 25 | }, 26 | if current_mode.read().clone() { 27 | Icon { 28 | height: 26, 29 | width: 26, 30 | icon: fa_solid_icons::FaSun 31 | } 32 | } else { 33 | Icon { 34 | height: 26, 35 | width: 26, 36 | icon: fa_solid_icons::FaMoon 37 | } 38 | } 39 | } 40 | Link { 41 | class: "text-black dark:text-white hover:text-gray-800 dark:hover:text-gray-200", 42 | to: "/about", 43 | Icon { height: 26, width: 26, icon: fa_solid_icons::FaBook } 44 | } 45 | a { 46 | class: "text-black dark:text-white hover:text-gray-800 dark:hover:text-gray-200", 47 | href: "https://github.com/mrxiaozhuox/dioxus-starter", 48 | Icon { height: 26, width: 26, icon: fa_brands_icons::FaGithub } 49 | } 50 | } 51 | div { class: "mt-10 flex justify-center text-gray-400", 52 | span { 53 | "[ made by " 54 | a { 55 | class: "underline", 56 | href: "https://github.com/mrxiaozhuox/", 57 | target: "_blank", 58 | "@mrxiaozhuox" 59 | } 60 | " ]" 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/components/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod footer; 2 | pub mod content; -------------------------------------------------------------------------------- /src/hooks/markdown.rs: -------------------------------------------------------------------------------- 1 | // use dioxus::prelude::use_hook; 2 | // use pulldown_cmark::{Options, Parser, html}; 3 | // 4 | // pub fn use_markdown() -> UseMarkdown<'_, '_> { 5 | // let options = Options::all(); 6 | // use_hook(|| { 7 | // let parser = Parser::new_ext(str, options); 8 | // UseMarkdown { parser } 9 | // }) 10 | // } 11 | // 12 | // pub struct UseMarkdown<'a, 'b> { 13 | // parser: Parser<'a, 'b> 14 | // } 15 | // 16 | // impl<'a, 'b> UseMarkdown<'a, 'b> { 17 | // pub fn to_html(&mut self) -> String { 18 | // let mut output = String::new(); 19 | // html::push_html(&mut output, &mut self.parser); 20 | // output 21 | // } 22 | // } 23 | -------------------------------------------------------------------------------- /src/hooks/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod mode; 2 | pub mod markdown; -------------------------------------------------------------------------------- /src/hooks/mode.rs: -------------------------------------------------------------------------------- 1 | use dioxus::signals::{Readable, Signal}; 2 | use dioxus_sdk::storage::{use_synced_storage, LocalStorage}; 3 | 4 | pub fn use_mode() -> Signal { 5 | use_synced_storage::("mode".to_string(), || false) 6 | } 7 | 8 | pub fn mode(dark: bool) { 9 | if dark { 10 | let _ = js_sys::eval("document.documentElement.classList.add('dark');"); 11 | } else { 12 | let _ = js_sys::eval("document.documentElement.classList.remove('dark');"); 13 | } 14 | } 15 | 16 | pub fn init_mode_info() { 17 | let _ = js_sys::eval("document.body.classList.add('dark:bg-gray-600');"); 18 | let dark = use_mode(); 19 | if *dark.read() { 20 | let _ = js_sys::eval("document.documentElement.classList.add('dark');"); 21 | } else { 22 | let _ = js_sys::eval("document.documentElement.classList.remove('dark');"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use dioxus::prelude::*; 4 | use dioxus_toast::{ToastFrame, ToastManager}; 5 | 6 | mod components; 7 | mod hooks; 8 | mod pages; 9 | 10 | use hooks::mode::init_mode_info; 11 | use pages::_404::NotFound; 12 | use pages::starter::{About, HelloDioxus, SayHi}; 13 | 14 | #[derive(Routable, Clone, Debug, PartialEq)] 15 | enum Route { 16 | // Main Page 17 | #[route("/")] 18 | HelloDioxus {}, 19 | 20 | // Say Hi Page 21 | #[route("/hi/:name")] 22 | SayHi { name: String }, 23 | 24 | // About Page 25 | #[route("/about")] 26 | About {}, 27 | 28 | // 404 Not Found Page 29 | #[route("/:route")] 30 | NotFound { route: String }, 31 | } 32 | 33 | fn main() { 34 | 35 | wasm_logger::init(wasm_logger::Config::default()); 36 | 37 | dioxus_sdk::storage::set_dir!(); 38 | 39 | log::info!("Dioxus Starter: https://github.com/mrxiaozhuox/dioxus-starter"); 40 | launch(App) 41 | } 42 | 43 | fn App() -> Element { 44 | // init mode information 45 | init_mode_info(); 46 | 47 | let toast = use_context_provider(|| Signal::new(ToastManager::default())); 48 | 49 | rsx! { 50 | // dioxus toast manager init 51 | ToastFrame { manager: toast } 52 | Router:: {} 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/markdown/readme.md: -------------------------------------------------------------------------------- 1 |
2 |

🔮 Dioxus Starter 🔮

3 |
4 | 5 |
6 | dioxus-starter 7 | is a template for quick app development 8 |
9 | 10 | ## Features 11 | - 🧭 [Dynamic routing](https://dioxuslabs.com/nightly/router/) support 12 | - ☀️ Light / Dark mode support 13 | - 🏡 [Tailwind](https://tailwindcss.com/) framework support 14 | - 📙 Markdown parser support 15 | - 🍿 [Toast](https://github.com/mrxiaozhuox/dioxus-toast) popup support 16 | - 💎 [FA](https://fontawesome.com/) free icon support 17 | 18 | > This page display from markdown file. -------------------------------------------------------------------------------- /src/pages/_404.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | use crate::components::footer::Footer; 4 | 5 | #[component] 6 | pub fn NotFound(route: String) -> Element { 7 | rsx! { 8 | section { class: "h-screen bg-cover bg-white dark:bg-gray-600", 9 | div { class: "flex h-full w-full items-center justify-center container mx-auto px-8", 10 | div { class: "max-w-2xl text-center", 11 | h1 { class: "text-3xl sm:text-5xl capitalize tracking-widest dark:text-white lg:text-6xl", 12 | "Page Not Found" 13 | } 14 | Footer {} 15 | } 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/pages/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod _404; 2 | pub mod starter; 3 | 4 | -------------------------------------------------------------------------------- /src/pages/starter.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use dioxus_toast::{ToastInfo, ToastManager}; 3 | use crate::components::{content::Markdown, footer::Footer}; 4 | 5 | #[component] 6 | pub fn HelloDioxus() -> Element { 7 | let mut input_name = use_signal(String::new); 8 | let router = use_navigator(); 9 | let mut toast: Signal = use_context(); 10 | rsx! { 11 | section { class: "h-screen bg-cover bg-white dark:bg-gray-600", 12 | div { class: "flex h-full w-full items-center justify-center container mx-auto px-8", 13 | div { class: "max-w-2xl text-center", 14 | h1 { class: "text-3xl sm:text-5xl capitalize tracking-widest text-gray-600 dark:text-white lg:text-6xl", 15 | "Dioxus Starter" 16 | } 17 | p { class: "mt-6 lg:text-lg text-gray-600 dark:text-white", 18 | "Opinionated Dioxus Starter Template" 19 | } 20 | div { class: "mt-8 flex flex-col space-y-3 sm:-mx-2 sm:flex-row sm:justify-center sm:space-y-0", 21 | input { 22 | r#type: "text", 23 | class: "rounded-md border border-transparent bg-gray-800 dark:bg-white/20 px-4 py-2 text-white placeholder-white backdrop-blur-sm focus:border-blue-400 focus:outline-none focus:ring focus:ring-blue-300 focus:ring-opacity-40 sm:mx-2", 24 | placeholder: "What's your name ?", 25 | oninput: move |e| input_name.set(e.value().clone()), 26 | value: "{input_name}" 27 | } 28 | button { 29 | id: "submit-button", 30 | class: "transform rounded-md bg-blue-700 px-8 py-2 text-sm font-medium capitalize tracking-wide text-white transition-colors duration-200 hover:bg-blue-600 focus:bg-blue-600 focus:outline-none sm:mx-2", 31 | onclick: move |_| { 32 | let name = input_name.read(); 33 | if !name.is_empty() { 34 | router.push(&format!("/hi/{}", name)); 35 | } else { 36 | toast.write().popup(ToastInfo::warning("Empty input box", "Dioxus Toast")); 37 | } 38 | }, 39 | "Go" 40 | } 41 | } 42 | Footer {} 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | #[component] 50 | pub fn SayHi(name: String) -> Element { 51 | let name = urlencoding::decode(&name).expect("UTF-8").to_string(); 52 | rsx! { 53 | section { class: "h-screen bg-cover bg-white dark:bg-gray-600", 54 | div { class: "flex h-full w-full items-center justify-center container mx-auto px-8", 55 | div { class: "max-w-2xl text-center", 56 | h1 { class: "text-3xl sm:text-5xl capitalize tracking-widest dark:text-white lg:text-6xl", 57 | "Hi, "{name}"" 58 | } 59 | Footer {} 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | #[component] 67 | pub fn About() -> Element { 68 | let content = include_str!("../markdown/readme.md"); 69 | rsx! { 70 | div { class: "dark:bg-gray-600", 71 | br {} 72 | div { class: "md:flex md:justify-center", 73 | div { class: "block sm:p-6 md:p-8 rounded-lg shadow-2xl bg-white dark:bg-gray-700", 74 | Markdown { class: "dark:prose-invert", content: content.to_string() } 75 | } 76 | } 77 | Footer {} 78 | } 79 | } 80 | } 81 | --------------------------------------------------------------------------------