Compare commits
2 Commits
2baa5a930a
...
085ce51b0a
Author | SHA1 | Date | |
---|---|---|---|
085ce51b0a | |||
7d3ddc12ed |
@ -12,7 +12,10 @@ categories = ["gui", "wasm", "web-programming"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[dependencies]
|
||||
yew = { version="0.21", features=["csr"] }
|
||||
yew-router = "0.18"
|
||||
web-sys = { version = "0.3", features = ["Document", "HtmlElement", "Window"] }
|
||||
gloo-utils = "0.1"
|
||||
gloo-storage = "0.2"
|
||||
gloo-net = "0.4"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
290
index.scss
290
index.scss
@ -251,4 +251,294 @@ body {
|
||||
background: none !important;
|
||||
color: black !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Kanban Board Styles
|
||||
.kanban-board {
|
||||
background-color: var(--bs-body-bg);
|
||||
min-height: 100vh;
|
||||
padding: 2rem 0;
|
||||
|
||||
.kanban-header {
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
|
||||
h1 {
|
||||
color: var(--bs-body-color);
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.kanban-description {
|
||||
color: var(--bs-navbar-color);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.kanban-columns {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
overflow-x: auto;
|
||||
padding: 1rem 0;
|
||||
min-height: 70vh;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.kanban-column {
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
background-color: var(--bs-feature-bg);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1.5rem;
|
||||
box-shadow: var(--bs-shadow);
|
||||
border: 1px solid var(--bs-card-border);
|
||||
|
||||
.column-header {
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 2px solid var(--bs-card-border);
|
||||
|
||||
.column-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: var(--bs-body-color);
|
||||
margin-bottom: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
.card-count {
|
||||
background-color: var(--bs-navbar-color);
|
||||
color: var(--bs-body-bg);
|
||||
border-radius: 50%;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.column-description {
|
||||
color: var(--bs-navbar-color);
|
||||
font-size: 0.9rem;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.column-cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
min-height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.kanban-card {
|
||||
background-color: var(--bs-card-bg);
|
||||
border: 1px solid var(--bs-card-border);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
box-shadow: var(--bs-shadow);
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--bs-shadow-lg);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
margin-bottom: 0.75rem;
|
||||
|
||||
.card-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: var(--bs-body-color);
|
||||
margin-bottom: 0.5rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.card-description {
|
||||
color: var(--bs-navbar-color);
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
|
||||
.priority-badge {
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
|
||||
&.priority-high {
|
||||
background-color: rgba(220, 53, 69, 0.1);
|
||||
color: #dc3545;
|
||||
border: 1px solid rgba(220, 53, 69, 0.2);
|
||||
}
|
||||
|
||||
&.priority-medium {
|
||||
background-color: rgba(255, 193, 7, 0.1);
|
||||
color: #ffc107;
|
||||
border: 1px solid rgba(255, 193, 7, 0.2);
|
||||
}
|
||||
|
||||
&.priority-low {
|
||||
background-color: rgba(25, 135, 84, 0.1);
|
||||
color: #198754;
|
||||
border: 1px solid rgba(25, 135, 84, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.due-date {
|
||||
background-color: rgba(var(--bs-primary-rgb), 0.1);
|
||||
color: var(--bs-primary);
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
border: 1px solid rgba(var(--bs-primary-rgb), 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.card-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
margin-bottom: 0.75rem;
|
||||
|
||||
.tag {
|
||||
background-color: var(--bs-navbar-color);
|
||||
color: var(--bs-body-bg);
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 1rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.card-assignee {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--bs-navbar-color);
|
||||
font-size: 0.875rem;
|
||||
|
||||
.assignee-avatar {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.card-stats {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid var(--bs-card-border);
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
color: var(--bs-navbar-color);
|
||||
font-size: 0.75rem;
|
||||
|
||||
i {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.checklist-progress {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
.progress-bar {
|
||||
width: 40px;
|
||||
height: 4px;
|
||||
background-color: var(--bs-card-border);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background-color: #198754;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
font-size: 0.7rem;
|
||||
color: var(--bs-navbar-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive kanban adjustments
|
||||
@media (max-width: 992px) {
|
||||
.kanban-board {
|
||||
.kanban-columns {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.kanban-column {
|
||||
min-width: 280px;
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.kanban-board {
|
||||
padding: 1rem 0;
|
||||
|
||||
.kanban-column {
|
||||
min-width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.kanban-card {
|
||||
padding: 0.75rem;
|
||||
|
||||
.card-meta {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.card-stats {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
139
kanban_data.json
Normal file
139
kanban_data.json
Normal file
@ -0,0 +1,139 @@
|
||||
{
|
||||
"title": "Project Management Board",
|
||||
"description": "Track project progress with this kanban board",
|
||||
"columns": [
|
||||
{
|
||||
"id": "todo",
|
||||
"title": "To Do",
|
||||
"description": "Tasks that need to be started",
|
||||
"cards": [
|
||||
{
|
||||
"id": "card-1",
|
||||
"title": "Design User Interface",
|
||||
"description": "Create wireframes and mockups for the new feature",
|
||||
"priority": "high",
|
||||
"assignee": "Alice Johnson",
|
||||
"tags": ["design", "ui/ux"],
|
||||
"dueDate": "2024-01-15",
|
||||
"attachments": 2,
|
||||
"comments": 3,
|
||||
"checklist": {
|
||||
"completed": 1,
|
||||
"total": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "card-2",
|
||||
"title": "Research Market Trends",
|
||||
"description": "Analyze current market trends and competitor analysis",
|
||||
"priority": "medium",
|
||||
"assignee": "Bob Smith",
|
||||
"tags": ["research", "analysis"],
|
||||
"dueDate": "2024-01-20",
|
||||
"attachments": 0,
|
||||
"comments": 1,
|
||||
"checklist": {
|
||||
"completed": 0,
|
||||
"total": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "in-progress",
|
||||
"title": "In Progress",
|
||||
"description": "Tasks currently being worked on",
|
||||
"cards": [
|
||||
{
|
||||
"id": "card-3",
|
||||
"title": "Implement Authentication",
|
||||
"description": "Set up user authentication system with JWT tokens and secure password handling",
|
||||
"priority": "high",
|
||||
"assignee": "Charlie Brown",
|
||||
"tags": ["backend", "security"],
|
||||
"dueDate": "2024-01-12",
|
||||
"attachments": 1,
|
||||
"comments": 5,
|
||||
"checklist": {
|
||||
"completed": 2,
|
||||
"total": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "card-4",
|
||||
"title": "Database Migration",
|
||||
"description": "Migrate existing data to new database schema",
|
||||
"priority": "medium",
|
||||
"assignee": "Diana Prince",
|
||||
"tags": ["database", "migration"],
|
||||
"dueDate": "2024-01-18",
|
||||
"attachments": 3,
|
||||
"comments": 2,
|
||||
"checklist": {
|
||||
"completed": 3,
|
||||
"total": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "review",
|
||||
"title": "Review",
|
||||
"description": "Tasks pending review and approval",
|
||||
"cards": [
|
||||
{
|
||||
"id": "card-5",
|
||||
"title": "API Documentation",
|
||||
"description": "Complete API documentation with examples and usage guidelines",
|
||||
"priority": "low",
|
||||
"assignee": "Eve Wilson",
|
||||
"tags": ["documentation", "api"],
|
||||
"dueDate": "2024-01-10",
|
||||
"attachments": 2,
|
||||
"comments": 4,
|
||||
"checklist": {
|
||||
"completed": 4,
|
||||
"total": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "done",
|
||||
"title": "Done",
|
||||
"description": "Completed tasks",
|
||||
"cards": [
|
||||
{
|
||||
"id": "card-6",
|
||||
"title": "Setup Development Environment",
|
||||
"description": "Configure development tools and environment for the team",
|
||||
"priority": "high",
|
||||
"assignee": "Frank Miller",
|
||||
"tags": ["setup", "devops"],
|
||||
"dueDate": "2024-01-05",
|
||||
"attachments": 1,
|
||||
"comments": 2,
|
||||
"checklist": {
|
||||
"completed": 3,
|
||||
"total": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "card-7",
|
||||
"title": "Initial Project Planning",
|
||||
"description": "Define project scope, timeline, and resource allocation",
|
||||
"priority": "high",
|
||||
"assignee": "Grace Lee",
|
||||
"tags": ["planning", "management"],
|
||||
"dueDate": "2024-01-03",
|
||||
"attachments": 4,
|
||||
"comments": 8,
|
||||
"checklist": {
|
||||
"completed": 5,
|
||||
"total": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
139
public/kanban_data.json
Normal file
139
public/kanban_data.json
Normal file
@ -0,0 +1,139 @@
|
||||
{
|
||||
"title": "Project Management Board",
|
||||
"description": "Track project progress with this kanban board",
|
||||
"columns": [
|
||||
{
|
||||
"id": "todo",
|
||||
"title": "To Do",
|
||||
"description": "Tasks that need to be started",
|
||||
"cards": [
|
||||
{
|
||||
"id": "card-1",
|
||||
"title": "Design User Interface",
|
||||
"description": "Create wireframes and mockups for the new feature",
|
||||
"priority": "high",
|
||||
"assignee": "Alice Johnson",
|
||||
"tags": ["design", "ui/ux"],
|
||||
"dueDate": "2024-01-15",
|
||||
"attachments": 2,
|
||||
"comments": 3,
|
||||
"checklist": {
|
||||
"completed": 1,
|
||||
"total": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "card-2",
|
||||
"title": "Research Market Trends",
|
||||
"description": "Analyze current market trends and competitor analysis",
|
||||
"priority": "medium",
|
||||
"assignee": "Bob Smith",
|
||||
"tags": ["research", "analysis"],
|
||||
"dueDate": "2024-01-20",
|
||||
"attachments": 0,
|
||||
"comments": 1,
|
||||
"checklist": {
|
||||
"completed": 0,
|
||||
"total": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "in-progress",
|
||||
"title": "In Progress",
|
||||
"description": "Tasks currently being worked on",
|
||||
"cards": [
|
||||
{
|
||||
"id": "card-3",
|
||||
"title": "Implement Authentication",
|
||||
"description": "Set up user authentication system with JWT tokens and secure password handling",
|
||||
"priority": "high",
|
||||
"assignee": "Charlie Brown",
|
||||
"tags": ["backend", "security"],
|
||||
"dueDate": "2024-01-12",
|
||||
"attachments": 1,
|
||||
"comments": 5,
|
||||
"checklist": {
|
||||
"completed": 2,
|
||||
"total": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "card-4",
|
||||
"title": "Database Migration",
|
||||
"description": "Migrate existing data to new database schema",
|
||||
"priority": "medium",
|
||||
"assignee": "Diana Prince",
|
||||
"tags": ["database", "migration"],
|
||||
"dueDate": "2024-01-18",
|
||||
"attachments": 3,
|
||||
"comments": 2,
|
||||
"checklist": {
|
||||
"completed": 3,
|
||||
"total": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "review",
|
||||
"title": "Review",
|
||||
"description": "Tasks pending review and approval",
|
||||
"cards": [
|
||||
{
|
||||
"id": "card-5",
|
||||
"title": "API Documentation",
|
||||
"description": "Complete API documentation with examples and usage guidelines",
|
||||
"priority": "low",
|
||||
"assignee": "Eve Wilson",
|
||||
"tags": ["documentation", "api"],
|
||||
"dueDate": "2024-01-10",
|
||||
"attachments": 2,
|
||||
"comments": 4,
|
||||
"checklist": {
|
||||
"completed": 4,
|
||||
"total": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "done",
|
||||
"title": "Done",
|
||||
"description": "Completed tasks",
|
||||
"cards": [
|
||||
{
|
||||
"id": "card-6",
|
||||
"title": "Setup Development Environment",
|
||||
"description": "Configure development tools and environment for the team",
|
||||
"priority": "high",
|
||||
"assignee": "Frank Miller",
|
||||
"tags": ["setup", "devops"],
|
||||
"dueDate": "2024-01-05",
|
||||
"attachments": 1,
|
||||
"comments": 2,
|
||||
"checklist": {
|
||||
"completed": 3,
|
||||
"total": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "card-7",
|
||||
"title": "Initial Project Planning",
|
||||
"description": "Define project scope, timeline, and resource allocation",
|
||||
"priority": "high",
|
||||
"assignee": "Grace Lee",
|
||||
"tags": ["planning", "management"],
|
||||
"dueDate": "2024-01-03",
|
||||
"attachments": 4,
|
||||
"comments": 8,
|
||||
"checklist": {
|
||||
"completed": 5,
|
||||
"total": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
124
src/app.rs
124
src/app.rs
@ -1,7 +1,10 @@
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::*;
|
||||
use gloo_utils::document;
|
||||
use gloo_storage::{LocalStorage, Storage};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::home::HomePage;
|
||||
use crate::kanban::KanbanBoard;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
enum Theme {
|
||||
@ -18,6 +21,25 @@ impl Theme {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Routable, PartialEq)]
|
||||
enum Route {
|
||||
#[at("/")]
|
||||
Home,
|
||||
#[at("/kanban")]
|
||||
Kanban,
|
||||
#[not_found]
|
||||
#[at("/404")]
|
||||
NotFound,
|
||||
}
|
||||
|
||||
fn switch(routes: Route) -> Html {
|
||||
match routes {
|
||||
Route::Home => html! { <HomePage /> },
|
||||
Route::Kanban => html! { <KanbanBoard /> },
|
||||
Route::NotFound => html! { <h1>{ "404 - Page not found" }</h1> },
|
||||
}
|
||||
}
|
||||
|
||||
#[function_component(App)]
|
||||
pub fn app() -> Html {
|
||||
let theme = use_state(|| {
|
||||
@ -41,19 +63,26 @@ pub fn app() -> Html {
|
||||
let navbar_class = if *theme == Theme::Dark { "navbar navbar-expand-lg navbar-dark" } else { "navbar navbar-expand-lg navbar-light" };
|
||||
|
||||
html! {
|
||||
<>
|
||||
<BrowserRouter>
|
||||
<nav class={navbar_class}>
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand fw-bold" href="#">{"🦀 Yew Bootstrap App"}</a>
|
||||
<Link<Route> to={Route::Home} classes="navbar-brand fw-bold">
|
||||
{"🦀 Yew Bootstrap App"}
|
||||
</Link<Route>>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">
|
||||
<Link<Route> to={Route::Home} classes="nav-link">
|
||||
<i class="bi bi-house-fill me-1"></i>{"Home"}
|
||||
</a>
|
||||
</Link<Route>>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<Link<Route> to={Route::Kanban} classes="nav-link">
|
||||
<i class="bi bi-kanban me-1"></i>{"Kanban"}
|
||||
</Link<Route>>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
@ -80,90 +109,7 @@ pub fn app() -> Html {
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="hero-section jumbotron">
|
||||
<div class="container py-5 text-center">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<h1 class="display-4 fw-bold mb-4">{"🚀 Welcome to Yew Bootstrap!"}</h1>
|
||||
<p class="lead fs-5 mb-4">{"Experience the power of Rust and WebAssembly with this modern Yew application featuring Bootstrap 5 integration, responsive design, and seamless dark mode switching."}</p>
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-center">
|
||||
<button class="btn btn-primary btn-lg px-4 me-md-2" type="button">
|
||||
<i class="bi bi-rocket-takeoff me-2"></i>{"Get Started"}
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary btn-lg px-4" type="button">
|
||||
<i class="bi bi-github me-2"></i>{"View Source"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container my-5">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="feature-icon bg-primary bg-gradient text-white rounded-3 mb-3 mx-auto" style="width: 4rem; height: 4rem; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="bi bi-lightning-charge fs-2"></i>
|
||||
</div>
|
||||
<h3 class="card-title">{"⚡ Fast Performance"}</h3>
|
||||
<p class="card-text">{"Built with Rust and WebAssembly for blazing fast performance. Experience near-native speed in your web applications."}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="feature-icon bg-success bg-gradient text-white rounded-3 mb-3 mx-auto" style="width: 4rem; height: 4rem; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="bi bi-shield-check fs-2"></i>
|
||||
</div>
|
||||
<h3 class="card-title">{"🛡️ Type Safety"}</h3>
|
||||
<p class="card-text">{"Rust's powerful type system ensures memory safety and prevents common programming errors at compile time."}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="feature-icon bg-info bg-gradient text-white rounded-3 mb-3 mx-auto" style="width: 4rem; height: 4rem; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="bi bi-phone fs-2"></i>
|
||||
</div>
|
||||
<h3 class="card-title">{"📱 Responsive Design"}</h3>
|
||||
<p class="card-text">{"Fully responsive design that works perfectly on desktop, tablet, and mobile devices with Bootstrap 5."}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-body-secondary py-5">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6">
|
||||
<h2 class="display-6 fw-bold mb-3">{"🎨 Modern UI Components"}</h2>
|
||||
<p class="lead">{"This application showcases modern UI patterns with smooth theme transitions, interactive components, and beautiful typography."}</p>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>{"Dark/Light theme switching"}</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>{"Responsive navigation"}</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>{"Bootstrap 5 integration"}</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>{"Custom CSS properties"}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-lg-6 text-center">
|
||||
<div class="p-4">
|
||||
<i class="bi bi-palette2 display-1 text-primary"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="bg-body-tertiary py-4 mt-5">
|
||||
<div class="container text-center">
|
||||
<p class="mb-0">{"Built with ❤️ using Yew, Rust, and Bootstrap 5"}</p>
|
||||
</div>
|
||||
</footer>
|
||||
</>
|
||||
<Switch<Route> render={switch} />
|
||||
</BrowserRouter>
|
||||
}
|
||||
}
|
||||
|
94
src/home.rs
Normal file
94
src/home.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use yew::prelude::*;
|
||||
|
||||
#[function_component(HomePage)]
|
||||
pub fn home_page() -> Html {
|
||||
html! {
|
||||
<>
|
||||
<div class="hero-section jumbotron">
|
||||
<div class="container py-5 text-center">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<h1 class="display-4 fw-bold mb-4">{"🚀 Welcome to Yew Bootstrap!"}</h1>
|
||||
<p class="lead fs-5 mb-4">{"Experience the power of Rust and WebAssembly with this modern Yew application featuring Bootstrap 5 integration, responsive design, and seamless dark mode switching."}</p>
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-center">
|
||||
<button class="btn btn-primary btn-lg px-4 me-md-2" type="button">
|
||||
<i class="bi bi-rocket-takeoff me-2"></i>{"Get Started"}
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary btn-lg px-4" type="button">
|
||||
<i class="bi bi-github me-2"></i>{"View Source"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container my-5">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="feature-icon bg-primary bg-gradient text-white rounded-3 mb-3 mx-auto" style="width: 4rem; height: 4rem; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="bi bi-lightning-charge fs-2"></i>
|
||||
</div>
|
||||
<h3 class="card-title">{"⚡ Fast Performance"}</h3>
|
||||
<p class="card-text">{"Built with Rust and WebAssembly for blazing fast performance. Experience near-native speed in your web applications."}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="feature-icon bg-success bg-gradient text-white rounded-3 mb-3 mx-auto" style="width: 4rem; height: 4rem; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="bi bi-shield-check fs-2"></i>
|
||||
</div>
|
||||
<h3 class="card-title">{"🛡️ Type Safety"}</h3>
|
||||
<p class="card-text">{"Rust's powerful type system ensures memory safety and prevents common programming errors at compile time."}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="feature-icon bg-info bg-gradient text-white rounded-3 mb-3 mx-auto" style="width: 4rem; height: 4rem; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="bi bi-phone fs-2"></i>
|
||||
</div>
|
||||
<h3 class="card-title">{"📱 Responsive Design"}</h3>
|
||||
<p class="card-text">{"Fully responsive design that works perfectly on desktop, tablet, and mobile devices with Bootstrap 5."}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-body-secondary py-5">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6">
|
||||
<h2 class="display-6 fw-bold mb-3">{"🎨 Modern UI Components"}</h2>
|
||||
<p class="lead">{"This application showcases modern UI patterns with smooth theme transitions, interactive components, and beautiful typography."}</p>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>{"Dark/Light theme switching"}</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>{"Responsive navigation"}</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>{"Bootstrap 5 integration"}</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>{"Custom CSS properties"}</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>{"Kanban board with rich content"}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-lg-6 text-center">
|
||||
<div class="p-4">
|
||||
<i class="bi bi-palette2 display-1 text-primary"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="bg-body-tertiary py-4 mt-5">
|
||||
<div class="container text-center">
|
||||
<p class="mb-0">{"Built with ❤️ using Yew, Rust, and Bootstrap 5"}</p>
|
||||
</div>
|
||||
</footer>
|
||||
</>
|
||||
}
|
||||
}
|
321
src/kanban.rs
Normal file
321
src/kanban.rs
Normal file
@ -0,0 +1,321 @@
|
||||
use yew::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct KanbanData {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub columns: Vec<KanbanColumn>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct KanbanColumn {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub cards: Vec<KanbanCard>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct KanbanCard {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub priority: String,
|
||||
pub assignee: String,
|
||||
pub tags: Vec<String>,
|
||||
#[serde(rename = "dueDate")]
|
||||
pub due_date: String,
|
||||
pub attachments: u32,
|
||||
pub comments: u32,
|
||||
pub checklist: ChecklistInfo,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ChecklistInfo {
|
||||
pub completed: u32,
|
||||
pub total: u32,
|
||||
}
|
||||
|
||||
fn get_sample_data() -> KanbanData {
|
||||
KanbanData {
|
||||
title: "Project Management Board".to_string(),
|
||||
description: "Track project progress with this kanban board".to_string(),
|
||||
columns: vec![
|
||||
KanbanColumn {
|
||||
id: "todo".to_string(),
|
||||
title: "To Do".to_string(),
|
||||
description: "Tasks that need to be started".to_string(),
|
||||
cards: vec![
|
||||
KanbanCard {
|
||||
id: "card-1".to_string(),
|
||||
title: "Design User Interface".to_string(),
|
||||
description: "Create wireframes and mockups for the new feature".to_string(),
|
||||
priority: "high".to_string(),
|
||||
assignee: "Alice Johnson".to_string(),
|
||||
tags: vec!["design".to_string(), "ui/ux".to_string()],
|
||||
due_date: "2024-01-15".to_string(),
|
||||
attachments: 2,
|
||||
comments: 3,
|
||||
checklist: ChecklistInfo { completed: 1, total: 4 },
|
||||
},
|
||||
KanbanCard {
|
||||
id: "card-2".to_string(),
|
||||
title: "Research Market Trends".to_string(),
|
||||
description: "Analyze current market trends and competitor analysis".to_string(),
|
||||
priority: "medium".to_string(),
|
||||
assignee: "Bob Smith".to_string(),
|
||||
tags: vec!["research".to_string(), "analysis".to_string()],
|
||||
due_date: "2024-01-20".to_string(),
|
||||
attachments: 0,
|
||||
comments: 1,
|
||||
checklist: ChecklistInfo { completed: 0, total: 3 },
|
||||
},
|
||||
],
|
||||
},
|
||||
KanbanColumn {
|
||||
id: "in-progress".to_string(),
|
||||
title: "In Progress".to_string(),
|
||||
description: "Tasks currently being worked on".to_string(),
|
||||
cards: vec![
|
||||
KanbanCard {
|
||||
id: "card-3".to_string(),
|
||||
title: "Implement Authentication".to_string(),
|
||||
description: "Set up user authentication system with JWT tokens and secure password handling".to_string(),
|
||||
priority: "high".to_string(),
|
||||
assignee: "Charlie Brown".to_string(),
|
||||
tags: vec!["backend".to_string(), "security".to_string()],
|
||||
due_date: "2024-01-12".to_string(),
|
||||
attachments: 1,
|
||||
comments: 5,
|
||||
checklist: ChecklistInfo { completed: 2, total: 5 },
|
||||
},
|
||||
KanbanCard {
|
||||
id: "card-4".to_string(),
|
||||
title: "Database Migration".to_string(),
|
||||
description: "Migrate existing data to new database schema".to_string(),
|
||||
priority: "medium".to_string(),
|
||||
assignee: "Diana Prince".to_string(),
|
||||
tags: vec!["database".to_string(), "migration".to_string()],
|
||||
due_date: "2024-01-18".to_string(),
|
||||
attachments: 3,
|
||||
comments: 2,
|
||||
checklist: ChecklistInfo { completed: 3, total: 6 },
|
||||
},
|
||||
],
|
||||
},
|
||||
KanbanColumn {
|
||||
id: "review".to_string(),
|
||||
title: "Review".to_string(),
|
||||
description: "Tasks pending review and approval".to_string(),
|
||||
cards: vec![
|
||||
KanbanCard {
|
||||
id: "card-5".to_string(),
|
||||
title: "API Documentation".to_string(),
|
||||
description: "Complete API documentation with examples and usage guidelines".to_string(),
|
||||
priority: "low".to_string(),
|
||||
assignee: "Eve Wilson".to_string(),
|
||||
tags: vec!["documentation".to_string(), "api".to_string()],
|
||||
due_date: "2024-01-10".to_string(),
|
||||
attachments: 2,
|
||||
comments: 4,
|
||||
checklist: ChecklistInfo { completed: 4, total: 4 },
|
||||
},
|
||||
],
|
||||
},
|
||||
KanbanColumn {
|
||||
id: "done".to_string(),
|
||||
title: "Done".to_string(),
|
||||
description: "Completed tasks".to_string(),
|
||||
cards: vec![
|
||||
KanbanCard {
|
||||
id: "card-6".to_string(),
|
||||
title: "Setup Development Environment".to_string(),
|
||||
description: "Configure development tools and environment for the team".to_string(),
|
||||
priority: "high".to_string(),
|
||||
assignee: "Frank Miller".to_string(),
|
||||
tags: vec!["setup".to_string(), "devops".to_string()],
|
||||
due_date: "2024-01-05".to_string(),
|
||||
attachments: 1,
|
||||
comments: 2,
|
||||
checklist: ChecklistInfo { completed: 3, total: 3 },
|
||||
},
|
||||
KanbanCard {
|
||||
id: "card-7".to_string(),
|
||||
title: "Initial Project Planning".to_string(),
|
||||
description: "Define project scope, timeline, and resource allocation".to_string(),
|
||||
priority: "high".to_string(),
|
||||
assignee: "Grace Lee".to_string(),
|
||||
tags: vec!["planning".to_string(), "management".to_string()],
|
||||
due_date: "2024-01-03".to_string(),
|
||||
attachments: 4,
|
||||
comments: 8,
|
||||
checklist: ChecklistInfo { completed: 5, total: 5 },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[function_component(KanbanBoard)]
|
||||
pub fn kanban_board() -> Html {
|
||||
let data = get_sample_data();
|
||||
|
||||
html! {
|
||||
<div class="kanban-board">
|
||||
<div class="container-fluid">
|
||||
<div class="kanban-header">
|
||||
<h1>{&data.title}</h1>
|
||||
<p class="kanban-description">{&data.description}</p>
|
||||
</div>
|
||||
<div class="kanban-columns">
|
||||
{for data.columns.iter().map(|column| {
|
||||
html! {
|
||||
<KanbanColumnComponent column={column.clone()} />
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct KanbanColumnProps {
|
||||
pub column: KanbanColumn,
|
||||
}
|
||||
|
||||
#[function_component(KanbanColumnComponent)]
|
||||
pub fn kanban_column_component(props: &KanbanColumnProps) -> Html {
|
||||
let column = &props.column;
|
||||
|
||||
html! {
|
||||
<div class="kanban-column">
|
||||
<div class="column-header">
|
||||
<div class="column-title">
|
||||
{&column.title}
|
||||
<span class="card-count">{column.cards.len()}</span>
|
||||
</div>
|
||||
<p class="column-description">{&column.description}</p>
|
||||
</div>
|
||||
<div class="column-cards">
|
||||
{for column.cards.iter().map(|card| {
|
||||
html! {
|
||||
<KanbanCardComponent card={card.clone()} />
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct KanbanCardProps {
|
||||
pub card: KanbanCard,
|
||||
}
|
||||
|
||||
#[function_component(KanbanCardComponent)]
|
||||
pub fn kanban_card_component(props: &KanbanCardProps) -> Html {
|
||||
let card = &props.card;
|
||||
|
||||
let priority_class = match card.priority.as_str() {
|
||||
"high" => "priority-high",
|
||||
"medium" => "priority-medium",
|
||||
"low" => "priority-low",
|
||||
_ => "priority-medium",
|
||||
};
|
||||
|
||||
let progress_percentage = if card.checklist.total > 0 {
|
||||
(card.checklist.completed as f32 / card.checklist.total as f32 * 100.0) as u32
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let assignee_initials = card.assignee
|
||||
.split_whitespace()
|
||||
.map(|word| word.chars().next().unwrap_or(' '))
|
||||
.collect::<String>()
|
||||
.to_uppercase();
|
||||
|
||||
html! {
|
||||
<div class="kanban-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">{&card.title}</h3>
|
||||
<p class="card-description">{&card.description}</p>
|
||||
</div>
|
||||
|
||||
<div class="card-meta">
|
||||
<span class={classes!("priority-badge", priority_class)}>
|
||||
{&card.priority}
|
||||
</span>
|
||||
<span class="due-date">
|
||||
<i class="bi bi-calendar-event me-1"></i>
|
||||
{&card.due_date}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{if !card.tags.is_empty() {
|
||||
html! {
|
||||
<div class="card-tags">
|
||||
{for card.tags.iter().map(|tag| {
|
||||
html! {
|
||||
<span class="tag">{tag}</span>
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}}
|
||||
|
||||
<div class="card-assignee">
|
||||
<div class="assignee-avatar">
|
||||
{assignee_initials}
|
||||
</div>
|
||||
<span>{&card.assignee}</span>
|
||||
</div>
|
||||
|
||||
<div class="card-stats">
|
||||
<div class="d-flex gap-3">
|
||||
{if card.attachments > 0 {
|
||||
html! {
|
||||
<div class="stat-item">
|
||||
<i class="bi bi-paperclip"></i>
|
||||
<span>{card.attachments}</span>
|
||||
</div>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}}
|
||||
|
||||
{if card.comments > 0 {
|
||||
html! {
|
||||
<div class="stat-item">
|
||||
<i class="bi bi-chat-dots"></i>
|
||||
<span>{card.comments}</span>
|
||||
</div>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}}
|
||||
</div>
|
||||
|
||||
{if card.checklist.total > 0 {
|
||||
html! {
|
||||
<div class="checklist-progress">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" style={format!("width: {}%", progress_percentage)}></div>
|
||||
</div>
|
||||
<span class="progress-text">
|
||||
{format!("{}/{}", card.checklist.completed, card.checklist.total)}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
mod app;
|
||||
mod home;
|
||||
mod kanban;
|
||||
use app::App;
|
||||
|
||||
fn main() {
|
||||
|
Loading…
Reference in New Issue
Block a user