diff --git a/.gitignore b/.gitignore index ea8c4bf..5454021 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /target +examples/*/target +examples/*/dist +examples/*/Cargo.lock diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c160533 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,31 @@ +# Code of Conduct + +## Our Pledge + +We are committed to providing a friendly, safe, and welcoming environment for all contributors. + +## Our Standards + +**Expected behavior:** + +- Be respectful and inclusive +- Accept constructive criticism gracefully +- Focus on what is best for the community +- Show empathy towards others + +**Unacceptable behavior:** + +- Harassment, trolling, or personal attacks +- Discriminatory language or imagery +- Publishing others' private information +- Other conduct inappropriate in a professional setting + +## Enforcement + +Project maintainers may remove, edit, or reject comments, commits, code, issues, and other contributions that violate this Code of Conduct. + +Instances of unacceptable behavior may be reported by opening an issue or contacting the maintainers directly. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..cd49a29 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,56 @@ +# Contributing + +Thanks for your interest in contributing to `yew-nav-link`! + +## Quick Start + +1. Fork and clone the repo +2. Create a branch from an issue: `git checkout -b 123-feature-name` +3. Make changes following our standards +4. Submit a PR + +## Standards + +This project follows [RustManifest](https://github.com/RAprogramm/RustManifest) guidelines: + +### Code Style + +- Format with `cargo +nightly fmt` +- Max 99 characters per line +- No `mod.rs` files +- Use `::` only in imports + +### Quality + +- No `unwrap()` or `expect()` in library code +- Avoid unnecessary `clone()` +- Prefer `&str` over `String`, `&[T]` over `Vec` + +### Documentation + +- Doc comments (`///`) on all public items +- Include examples in doc comments + +### Commits + +Format: `#issue type: description` + +``` +#42 feat: add custom class support +#15 fix: active state detection +#8 docs: update usage examples +``` + +Types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore` + +## Before PR + +```bash +cargo +nightly fmt +cargo clippy -- -D warnings +cargo test +``` + +## Questions? + +Open an issue or check [RustManifest](https://github.com/RAprogramm/RustManifest) for detailed guidelines. diff --git a/Cargo.toml b/Cargo.toml index fc1944e..9b0d6c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/RAprogramm/yew-nav-link" license = "MIT" keywords = ["yew", "router", "navigation", "wasm", "frontend"] categories = ["gui", "wasm", "web-programming"] +exclude = ["examples/*"] [dependencies] yew = { version = "0.22", features = ["csr"] } diff --git a/README.md b/README.md index 4004444..5228b06 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Navigation link component for [Yew](https://yew.rs) with automatic active state - [Overview](#overview) - [Installation](#installation) - [Requirements](#requirements) +- [Examples](#examples) - [Usage](#usage) - [Component Syntax](#component-syntax) - [Function Syntax](#function-syntax) @@ -55,6 +56,33 @@ yew-nav-link = "0.3"
↑ top
+## Examples + +Full working examples are available in the [examples/](https://github.com/RAprogramm/yew-nav-link/tree/main/examples) directory: + +| Example | Description | +|---------|-------------| +| [basic](https://github.com/RAprogramm/yew-nav-link/tree/main/examples/basic) | Simple navigation with Home, About, Contact pages | +| [bootstrap](https://github.com/RAprogramm/yew-nav-link/tree/main/examples/bootstrap) | Integration with Bootstrap 5 navbar | +| [tailwind](https://github.com/RAprogramm/yew-nav-link/tree/main/examples/tailwind) | Sidebar navigation styled with Tailwind CSS | +| [nested-routes](https://github.com/RAprogramm/yew-nav-link/tree/main/examples/nested-routes) | Multi-level navigation with nested routing | + +### Running Examples + +```bash +# Install prerequisites (once) +rustup target add wasm32-unknown-unknown +cargo install trunk + +# Run example +cd examples/basic +trunk serve +``` + +Open http://127.0.0.1:8080 in your browser. + +
↑ top
+ ## Usage ### Component Syntax diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..bcf892b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,38 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +|---------|--------------------| +| 0.3.x | :white_check_mark: | +| < 0.3 | :x: | + +## Reporting a Vulnerability + +**Do not open a public issue for security vulnerabilities.** + +Instead: + +1. Email: andrey.rozanov.vl@gmail.com +2. Or use [GitHub Security Advisories](https://github.com/RAprogramm/yew-nav-link/security/advisories/new) + +Include: + +- Description of the vulnerability +- Steps to reproduce +- Potential impact +- Suggested fix (if any) + +## Response Timeline + +- **Acknowledgment**: within 48 hours +- **Initial assessment**: within 7 days +- **Fix timeline**: depends on severity + +## Disclosure + +We follow coordinated disclosure. We will work with you to understand and address the issue before any public disclosure. + +## Scope + +This policy applies to the `yew-nav-link` crate. For issues in dependencies, please report to the respective maintainers. diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..65c4590 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,23 @@ +# Examples + +## Quick Start + +```bash +rustup target add wasm32-unknown-unknown +cargo install trunk + +cd basic +trunk serve +# Open http://127.0.0.1:8080 +``` + +## Examples + +| Example | Description | +|---------|-------------| +| [basic](./basic) | Simple navigation with component and function syntax | +| [bootstrap](./bootstrap) | Bootstrap 5 navbar integration | +| [tailwind](./tailwind) | Sidebar with Tailwind CSS styling | +| [nested-routes](./nested-routes) | Multi-level navigation | + +Each example has its own README with details. diff --git a/examples/basic/Cargo.toml b/examples/basic/Cargo.toml new file mode 100644 index 0000000..1b544b2 --- /dev/null +++ b/examples/basic/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "basic-example" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +yew = { version = "0.22", features = ["csr"] } +yew-router = "0.19" +yew-nav-link = { path = "../.." } diff --git a/examples/basic/README.md b/examples/basic/README.md new file mode 100644 index 0000000..6ca7a73 --- /dev/null +++ b/examples/basic/README.md @@ -0,0 +1,55 @@ +# Basic Example + +Simple navigation demo with Home, About, Contact pages. + +## What it demonstrates + +- `NavLink` component syntax +- `nav_link()` function syntax +- Automatic `active` class on current route + +## Run + +```bash +# Prerequisites (once) +rustup target add wasm32-unknown-unknown +cargo install trunk + +# Run +trunk serve +``` + +Open http://127.0.0.1:8080 + +## Project structure + +``` +basic/ +├── Cargo.toml # Dependencies +├── index.html # HTML template with styles +└── src/ + └── main.rs # App code +``` + +## Key code + +```rust +use yew_nav_link::{NavLink, nav_link}; + +// Component syntax + to={Route::Home}>{ "Home" }> + +// Function syntax +{ nav_link(Route::About, "About") } +``` + +## CSS + +NavLink renders `` (or `` when route matches). + +Styles in `index.html`: + +```css +.nav-link { color: #ecf0f1; } +.nav-link.active { background: #3498db; } +``` diff --git a/examples/basic/index.html b/examples/basic/index.html new file mode 100644 index 0000000..05068c4 --- /dev/null +++ b/examples/basic/index.html @@ -0,0 +1,74 @@ + + + + + + yew-nav-link Example + + + + + + diff --git a/examples/basic/src/main.rs b/examples/basic/src/main.rs new file mode 100644 index 0000000..5a21d9f --- /dev/null +++ b/examples/basic/src/main.rs @@ -0,0 +1,124 @@ +//! Basic example demonstrating yew-nav-link usage. +//! +//! Run with: `trunk serve` from the examples/basic directory. + +use yew::prelude::*; +use yew_nav_link::{NavLink, nav_link}; +use yew_router::prelude::*; + +/// Application routes. +#[derive(Clone, PartialEq, Routable)] +enum Route { + #[at("/")] + Home, + #[at("/about")] + About, + #[at("/contact")] + Contact, + #[not_found] + #[at("/404")] + NotFound, +} + +/// Main application component. +#[component] +fn App() -> Html { + html! { + + +
+ render={switch} /> +
+
+ } +} + +/// Navigation bar using NavLink component. +#[component] +fn Navigation() -> Html { + html! { + + } +} + +/// Route switch function. +fn switch(route: Route) -> Html { + match route { + Route::Home => html! { }, + Route::About => html! { }, + Route::Contact => html! { }, + Route::NotFound => html! { }, + } +} + +#[component] +fn HomePage() -> Html { + html! { + <> +

{ "Home" }

+

{ "Welcome to yew-nav-link example!" }

+
+

{ "Click the navigation links above to see the active state change automatically." }

+

{ "The current page link will be highlighted with a blue background." }

+
+ + } +} + +#[component] +fn AboutPage() -> Html { + html! { + <> +

{ "About" }

+

{ "yew-nav-link provides automatic active state detection for navigation links." }

+
+

{ "Features:" }

+
    +
  • { "Automatic 'active' class when route matches" }
  • +
  • { "Type-safe routing with Yew Router" }
  • +
  • { "Works with Bootstrap, Tailwind, and custom CSS" }
  • +
+
+ + } +} + +#[component] +fn ContactPage() -> Html { + html! { + <> +

{ "Contact" }

+

{ "This page was linked using the nav_link() function syntax." }

+
+

{ "Both NavLink component and nav_link function work identically." }

+

{ "Choose the syntax that fits your use case." }

+
+ + } +} + +#[component] +fn NotFoundPage() -> Html { + html! { + <> +

{ "404 - Not Found" }

+

{ "The page you're looking for doesn't exist." }

+ + } +} + +fn main() { + yew::Renderer::::new().render(); +} diff --git a/examples/bootstrap/Cargo.toml b/examples/bootstrap/Cargo.toml new file mode 100644 index 0000000..6569dd6 --- /dev/null +++ b/examples/bootstrap/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "bootstrap-example" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +yew = { version = "0.22", features = ["csr"] } +yew-router = "0.19" +yew-nav-link = { path = "../.." } diff --git a/examples/bootstrap/README.md b/examples/bootstrap/README.md new file mode 100644 index 0000000..9084614 --- /dev/null +++ b/examples/bootstrap/README.md @@ -0,0 +1,51 @@ +# Bootstrap Example + +NavLink integration with Bootstrap 5 navbar. + +## What it demonstrates + +- NavLink works with Bootstrap out of the box +- `nav-link` and `active` classes are Bootstrap-compatible + +## Run + +```bash +# Prerequisites (once) +rustup target add wasm32-unknown-unknown +cargo install trunk + +# Run +trunk serve +``` + +Open http://127.0.0.1:8080 + +## Project structure + +``` +bootstrap/ +├── Cargo.toml +├── index.html # Includes Bootstrap CDN +└── src/ + └── main.rs +``` + +## Key code + +```rust +// Bootstrap navbar structure +
+``` + +## Why it works + +NavLink always adds `nav-link` class, and `active` when route matches - exactly what Bootstrap expects. + +No extra configuration needed. diff --git a/examples/bootstrap/index.html b/examples/bootstrap/index.html new file mode 100644 index 0000000..79fd3f2 --- /dev/null +++ b/examples/bootstrap/index.html @@ -0,0 +1,13 @@ + + + + + + yew-nav-link + Bootstrap + + + + + + + diff --git a/examples/bootstrap/src/main.rs b/examples/bootstrap/src/main.rs new file mode 100644 index 0000000..4b9c82f --- /dev/null +++ b/examples/bootstrap/src/main.rs @@ -0,0 +1,128 @@ +//! Bootstrap integration example for yew-nav-link. +//! +//! Demonstrates how NavLink works seamlessly with Bootstrap's nav components. +//! The `nav-link` and `active` classes are Bootstrap-compatible by default. +//! +//! Run with: `trunk serve` from the examples/bootstrap directory. + +use yew::prelude::*; +use yew_nav_link::NavLink; +use yew_router::prelude::*; + +#[derive(Clone, PartialEq, Routable)] +enum Route { + #[at("/")] + Home, + #[at("/products")] + Products, + #[at("/pricing")] + Pricing, + #[at("/contact")] + Contact, + #[not_found] + #[at("/404")] + NotFound, +} + +#[component] +fn App() -> Html { + html! { + + +
+ render={switch} /> +
+
+ } +} + +/// Bootstrap navbar with NavLink integration. +/// NavLink outputs `nav-link` class by default - perfect for Bootstrap! +#[component] +fn Navbar() -> Html { + html! { +
+ } +} + +fn switch(route: Route) -> Html { + match route { + Route::Home => html! { +
+
+

{ "Welcome" }

+

{ "This example shows yew-nav-link with Bootstrap 5." }

+

+ { "The NavLink component outputs " } + { "nav-link" } + { " and " } + { "active" } + { " classes - Bootstrap-compatible by default!" } +

+
+
+ }, + Route::Products => html! { +
+
+

{ "Products" }

+

{ "Browse our product catalog." }

+
+
+ }, + Route::Pricing => html! { +
+
+

{ "Pricing" }

+

{ "View our pricing plans." }

+
+
+ }, + Route::Contact => html! { +
+
+

{ "Contact" }

+

{ "Get in touch with us." }

+
+
+ }, + Route::NotFound => html! { +
+

{ "404 - Not Found" }

+

{ "The page you're looking for doesn't exist." }

+
+ }, + } +} + +fn main() { + yew::Renderer::::new().render(); +} diff --git a/examples/nested-routes/Cargo.toml b/examples/nested-routes/Cargo.toml new file mode 100644 index 0000000..6c65495 --- /dev/null +++ b/examples/nested-routes/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "nested-routes-example" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +yew = { version = "0.22", features = ["csr"] } +yew-router = "0.19" +yew-nav-link = { path = "../.." } diff --git a/examples/nested-routes/README.md b/examples/nested-routes/README.md new file mode 100644 index 0000000..e4919f6 --- /dev/null +++ b/examples/nested-routes/README.md @@ -0,0 +1,71 @@ +# Nested Routes Example + +Multi-level navigation with main nav and sub-navigation tabs. + +## What it demonstrates + +- Multiple route enums (top-level + nested) +- NavLink at different routing levels +- Main nav stays active while sub-nav changes + +## Run + +```bash +# Prerequisites (once) +rustup target add wasm32-unknown-unknown +cargo install trunk + +# Run +trunk serve +``` + +Open http://127.0.0.1:8080 + +## Project structure + +``` +nested-routes/ +├── Cargo.toml +├── index.html +└── src/ + └── main.rs +``` + +## Key code + +Multiple route enums: + +```rust +// Top-level routes +enum Route { + #[at("/")] + Home, + #[at("/docs/*")] + Docs, +} + +// Nested docs routes +enum DocsRoute { + #[at("/docs")] + Overview, + #[at("/docs/getting-started")] + GettingStarted, +} +``` + +Navigation at each level: + +```rust +// Main nav - uses Route + to={Route::Home}>{ "Home" }> + to={Route::DocsRoot}>{ "Docs" }> + +// Sub nav - uses DocsRoute + to={DocsRoute::Overview}>{ "Overview" }> + to={DocsRoute::GettingStarted}>{ "Getting Started" }> +``` + +## Result + +- Click "Docs" → main nav shows "Docs" active +- Click sub-tabs → "Docs" stays active, sub-tab changes diff --git a/examples/nested-routes/index.html b/examples/nested-routes/index.html new file mode 100644 index 0000000..7a62429 --- /dev/null +++ b/examples/nested-routes/index.html @@ -0,0 +1,102 @@ + + + + + + yew-nav-link - Nested Routes + + + + + + diff --git a/examples/nested-routes/src/main.rs b/examples/nested-routes/src/main.rs new file mode 100644 index 0000000..a7d5497 --- /dev/null +++ b/examples/nested-routes/src/main.rs @@ -0,0 +1,221 @@ +//! Nested routes example for yew-nav-link. +//! +//! Demonstrates using NavLink with nested routing patterns: +//! - Main navigation (top-level routes) +//! - Sub-navigation (nested routes within sections) +//! +//! Run with: `trunk serve` from the examples/nested-routes directory. + +use yew::prelude::*; +use yew_nav_link::NavLink; +use yew_router::prelude::*; + +/// Top-level application routes. +#[derive(Clone, PartialEq, Routable)] +enum Route { + #[at("/")] + Home, + #[at("/docs")] + DocsRoot, + #[at("/docs/*")] + Docs, + #[at("/blog")] + BlogRoot, + #[at("/blog/*")] + Blog, + #[not_found] + #[at("/404")] + NotFound, +} + +/// Documentation section routes. +#[derive(Clone, PartialEq, Routable)] +enum DocsRoute { + #[at("/docs")] + Overview, + #[at("/docs/getting-started")] + GettingStarted, + #[at("/docs/api")] + Api, + #[not_found] + #[at("/docs/404")] + NotFound, +} + +/// Blog section routes. +#[derive(Clone, PartialEq, Routable)] +enum BlogRoute { + #[at("/blog")] + Latest, + #[at("/blog/archive")] + Archive, + #[at("/blog/categories")] + Categories, + #[not_found] + #[at("/blog/404")] + NotFound, +} + +#[component] +fn App() -> Html { + html! { + + + render={switch_main} /> + + } +} + +/// Main navigation bar. +#[component] +fn MainNav() -> Html { + html! { + + } +} + +fn switch_main(route: Route) -> Html { + match route { + Route::Home => html! { }, + Route::DocsRoot | Route::Docs => html! { }, + Route::BlogRoot | Route::Blog => html! { }, + Route::NotFound => html! { }, + } +} + +#[component] +fn HomePage() -> Html { + html! { +
+

{ "Nested Routes Example" }

+

{ "This example demonstrates using NavLink with nested routing patterns." }

+
+ { "Key concepts:" } +
    +
  • { "Main navigation uses top-level Route enum" }
  • +
  • { "Each section has its own nested route enum (DocsRoute, BlogRoute)" }
  • +
  • { "NavLink automatically detects active state at each level" }
  • +
+
+

{ "Click 'Documentation' or 'Blog' to see sub-navigation in action." }

+
+ } +} + +/// Documentation section with sub-navigation. +#[component] +fn DocsSection() -> Html { + html! { + <> + +
+ render={switch_docs} /> +
+ + } +} + +fn switch_docs(route: DocsRoute) -> Html { + match route { + DocsRoute::Overview => html! { + <> +

{ "Documentation Overview" }

+

{ "Welcome to the documentation section." }

+

{ "Notice how the 'Documentation' link in the main nav stays active," }

+

{ "while the sub-navigation tabs change based on the current page." }

+ + }, + DocsRoute::GettingStarted => html! { + <> +

{ "Getting Started" }

+

{ "Installation" }

+

{ "Add yew-nav-link to your Cargo.toml dependencies." }

+

{ "Basic Usage" }

+

{ "Import NavLink and use it in your navigation components." }

+ + }, + DocsRoute::Api => html! { + <> +

{ "API Reference" }

+

{ "NavLink" }

+

{ "The main component for navigation links with active state." }

+

{ "nav_link()" }

+

{ "Helper function for creating text-only navigation links." }

+ + }, + DocsRoute::NotFound => html! { +

{ "Documentation page not found." }

+ }, + } +} + +/// Blog section with sub-navigation. +#[component] +fn BlogSection() -> Html { + html! { + <> + +
+ render={switch_blog} /> +
+ + } +} + +fn switch_blog(route: BlogRoute) -> Html { + match route { + BlogRoute::Latest => html! { + <> +

{ "Latest Posts" }

+

{ "Recent blog entries would appear here." }

+ + }, + BlogRoute::Archive => html! { + <> +

{ "Archive" }

+

{ "Browse posts by date." }

+ + }, + BlogRoute::Categories => html! { + <> +

{ "Categories" }

+

{ "Browse posts by category." }

+ + }, + BlogRoute::NotFound => html! { +

{ "Blog page not found." }

+ }, + } +} + +#[component] +fn NotFoundPage() -> Html { + html! { +
+

{ "404 - Not Found" }

+

{ "The page you're looking for doesn't exist." }

+
+ } +} + +fn main() { + yew::Renderer::::new().render(); +} diff --git a/examples/tailwind/Cargo.toml b/examples/tailwind/Cargo.toml new file mode 100644 index 0000000..a51ffdc --- /dev/null +++ b/examples/tailwind/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "tailwind-example" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +yew = { version = "0.22", features = ["csr"] } +yew-router = "0.19" +yew-nav-link = { path = "../.." } diff --git a/examples/tailwind/README.md b/examples/tailwind/README.md new file mode 100644 index 0000000..bf8f012 --- /dev/null +++ b/examples/tailwind/README.md @@ -0,0 +1,60 @@ +# Tailwind CSS Example + +Dashboard with sidebar navigation styled using Tailwind CSS. + +## What it demonstrates + +- Custom styling for `nav-link` and `active` classes +- Using Tailwind's `@apply` directive + +## Run + +```bash +# Prerequisites (once) +rustup target add wasm32-unknown-unknown +cargo install trunk + +# Run +trunk serve +``` + +Open http://127.0.0.1:8080 + +## Project structure + +``` +tailwind/ +├── Cargo.toml +├── index.html # Tailwind CDN + custom styles +└── src/ + └── main.rs +``` + +## Key code + +Styling in `index.html`: + +```css +.nav-link { + @apply px-4 py-2 rounded-lg text-gray-300 + hover:text-white hover:bg-gray-700 transition-colors; +} + +.nav-link.active { + @apply bg-indigo-600 text-white font-medium; +} +``` + +Usage in Rust: + +```rust + +``` + +## Result + +- Inactive links: gray text, hover effect +- Active link: indigo background, white text, bold diff --git a/examples/tailwind/index.html b/examples/tailwind/index.html new file mode 100644 index 0000000..e451c78 --- /dev/null +++ b/examples/tailwind/index.html @@ -0,0 +1,21 @@ + + + + + + yew-nav-link + Tailwind CSS + + + + + + + diff --git a/examples/tailwind/src/main.rs b/examples/tailwind/src/main.rs new file mode 100644 index 0000000..0e60a71 --- /dev/null +++ b/examples/tailwind/src/main.rs @@ -0,0 +1,108 @@ +//! Tailwind CSS integration example for yew-nav-link. +//! +//! Shows how to style NavLink using Tailwind CSS classes. +//! The `nav-link` and `active` classes can be styled with @apply. +//! +//! Run with: `trunk serve` from the examples/tailwind directory. + +use yew::prelude::*; +use yew_nav_link::NavLink; +use yew_router::prelude::*; + +#[derive(Clone, PartialEq, Routable)] +enum Route { + #[at("/")] + Dashboard, + #[at("/analytics")] + Analytics, + #[at("/settings")] + Settings, + #[not_found] + #[at("/404")] + NotFound, +} + +#[component] +fn App() -> Html { + html! { + +
+ +
+ render={switch} /> +
+
+
+ } +} + +/// Sidebar navigation styled with Tailwind. +#[component] +fn Sidebar() -> Html { + html! { + + } +} + +fn switch(route: Route) -> Html { + match route { + Route::Dashboard => html! { +
+

{ "Dashboard" }

+
+
+
{ "Users" }
+
{ "1,234" }
+
+
+
{ "Revenue" }
+
{ "$12,345" }
+
+
+
{ "Orders" }
+
{ "567" }
+
+
+
+ }, + Route::Analytics => html! { +
+

{ "Analytics" }

+
+

{ "Analytics dashboard content goes here." }

+
+
+ }, + Route::Settings => html! { +
+

{ "Settings" }

+
+

{ "Settings page content goes here." }

+
+
+ }, + Route::NotFound => html! { +
+

{ "404" }

+

{ "Page not found" }

+
+ }, + } +} + +fn main() { + yew::Renderer::::new().render(); +}