Compare commits

...

2 Commits

14 changed files with 476 additions and 5 deletions

42
Cargo.lock generated
View File

@ -1051,6 +1051,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f"
dependencies = [
"futures-channel",
"gloo-events",
"js-sys",
"wasm-bindgen",
@ -2026,6 +2027,12 @@ dependencies = [
"thiserror 1.0.69",
]
[[package]]
name = "route-recognizer"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746"
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@ -2540,6 +2547,12 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "utf8parse"
version = "0.2.2"
@ -2599,6 +2612,7 @@ dependencies = [
"wasm-bindgen-futures",
"web-sys",
"yew",
"yew-router",
]
[[package]]
@ -2900,3 +2914,31 @@ dependencies = [
"rustversion",
"syn 2.0.100",
]
[[package]]
name = "yew-router"
version = "0.18.0"
source = "git+https://github.com/yewstack/yew/#b0d065626175f009cde687980f3724de8dc27240"
dependencies = [
"gloo",
"js-sys",
"route-recognizer",
"serde",
"serde_urlencoded",
"tracing",
"urlencoding",
"wasm-bindgen",
"web-sys",
"yew",
"yew-router-macro",
]
[[package]]
name = "yew-router-macro"
version = "0.18.0"
source = "git+https://github.com/yewstack/yew/#b0d065626175f009cde687980f3724de8dc27240"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]

View File

@ -66,6 +66,7 @@ wasm-bindgen = { version = "0.2.100" }
wasm-bindgen-futures = { version = "0.4.50" }
web-sys = { version = "0.3.77" }
yew = { git = "https://github.com/yewstack/yew/", features = ["csr"] }
yew-router = { git = "https://github.com/yewstack/yew/" }
# cairo-rs = { version = "0.18" }
# gio = { version = "0.18" }

View File

@ -14,4 +14,5 @@ wasm-bindgen = { workspace = true }
wasm-bindgen-futures = { workspace = true }
web-sys = { workspace = true }
yew = { workspace = true }
yew-router = { workspace = true }

View File

@ -1,11 +1,145 @@
:root {
--spacing-s: 4px;
--spacing-m: 8px;
--spacing-l: 16px;
--grey-1: hsl(0, 0%, 95%);
--grey-2: hsl(0, 0%, 85%);
--grey-3: hsl(0, 0%, 60%);
--grey-4: hsl(0, 0%, 35%);
--grey-5: hsl(0, 0%, 25%);
--blue-1: hsl(240, 75%, 90%);
--blue-2: hsl(240, 75%, 75%);
--blue-3: hsl(240, 75%, 50%);
--blue-4: hsl(240, 75%, 35%);
--blue-5: hsl(240, 75%, 25%);
--purple-1: hsl(270, 75%, 90%);
--purple-2: hsl(270, 75%, 75%);
--purple-3: hsl(270, 75%, 50%);
--purple-4: hsl(270, 75%, 35%);
--purple-5: hsl(270, 75%, 25%);
--red-1: hsl(0, 75%, 90%);
--red-2: hsl(0, 75%, 75%);
--red-3: hsl(0, 75%, 50%);
--red-4: hsl(0, 75%, 35%);
--red-5: hsl(0, 75%, 25%);
--shadow-shallow: 2px 2px 1px;
--border-light: 1px solid var(--grey-3);
--border-activated: 2px solid var(--blue-3);
--radius-s: 4px;
--radius-m: 8px;
--radius-l: 16px;
--background-color: var(--grey-2);
--text-normal: var(--grey-5);
--text-light: var(--grey-3);
--text-inverse: var(--grey-1);
--button-background-dark: var(--blue-4);
--highlight-background: var(--grey-1);
}
.swatch {
margin: var(--spacing-m);
border: var(--border-light);
border-radius: var(--radius-s);
width: 50px;
height: 50px;
}
.swatch__grey-1 {
background-color: var(--grey-1);
}
.swatch__grey-2 {
background-color: var(--grey-2);
}
.swatch__grey-3 {
background-color: var(--grey-3);
}
.swatch__grey-4 {
background-color: var(--grey-4);
}
.swatch__grey-5 {
background-color: var(--grey-5);
}
.swatch__blue-1 {
background-color: var(--blue-1);
}
.swatch__blue-2 {
background-color: var(--blue-2);
}
.swatch__blue-3 {
background-color: var(--blue-3);
}
.swatch__blue-4 {
background-color: var(--blue-4);
}
.swatch__blue-5 {
background-color: var(--blue-5);
}
.swatch__purple-1 {
background-color: var(--purple-1);
}
.swatch__purple-2 {
background-color: var(--purple-2);
}
.swatch__purple-3 {
background-color: var(--purple-3);
}
.swatch__purple-4 {
background-color: var(--purple-4);
}
.swatch__purple-5 {
background-color: var(--purple-5);
}
.swatch__red-1 {
background-color: var(--red-1);
}
.swatch__red-2 {
background-color: var(--red-2);
}
.swatch__red-3 {
background-color: var(--red-3);
}
.swatch__red-4 {
background-color: var(--red-4);
}
.swatch__red-5 {
background-color: var(--red-5);
}
body {
background-color: hsl(0, 0%, 95%);
background-color: var(--background-color);
color: var(--text-normal);
font-family: Ariel, sans-serif;
}
@ -13,10 +147,11 @@ body {
display: flex;
flex-direction: column;
align-items: space-between;
border: 1px solid black;
border: var(--border-light);
box-shadow: var(--shadow-shallow);
border-radius: var(--spacing-s);
border-radius: var(--radius-m);
padding: var(--spacing-m);
background-color: var(--highlight-background);
}
.card > h1 {
@ -34,3 +169,49 @@ body {
align-items: center;
height: 100vh;
}
.label {
padding: var(--spacing-m);
padding-left: var(--spacing-l);
padding-right: var(--spacing-l);
border: var(--border-light);
border-radius: var(--radius-l);
background: var(--highlight-background);
}
.label__placeholder {
color: var(--text-light);
}
.label__edit-button {
margin-left: var(--spacing-l);
padding: var(--spacing-s);
padding-left: var(--spacing-m);
padding-right: var(--spacing-m);
border-radius: var(--radius-l);
background-color: var(--button-background-dark);
color: var(--text-inverse);
}
.row {
margin: var(--spacing-m);
display: flex;
}
.row > * {
margin: var(--spacing-s);
}
.text-entry {
padding: var(--spacing-m);
padding-left: var(--spacing-l);
padding-right: var(--spacing-l);
border: var(--border-light);
border-radius: var(--radius-l);
background-color: var(--highlight-background);
}
.text-entry__placeholder {
color: var(--text-light);
}

View File

@ -0,0 +1,18 @@
use yew::{function_component, html, AttrValue, Html, Properties};
#[derive(Properties, PartialEq)]
pub struct CardProps {
#[prop_or(AttrValue::from(""))]
pub title: AttrValue,
pub children: Html,
}
#[function_component]
pub fn Card(CardProps { title, children }: &CardProps) -> Html {
html! {
<div class="card">
<h1>{title.clone()}</h1>
{children.clone()}
</div>
}
}

View File

@ -0,0 +1,30 @@
use yew::{function_component, html, AttrValue, Html, Properties};
#[derive(Properties, PartialEq)]
pub struct LabelProps {
#[prop_or(AttrValue::from(""))]
pub text: AttrValue,
#[prop_or(AttrValue::from("placeholder"))]
pub placeholder: AttrValue,
#[prop_or(false)]
pub editable: bool,
}
#[function_component]
pub fn Label(LabelProps { text, placeholder, editable }: &LabelProps) -> Html {
let body_text = if text.is_empty() {
html! { <span class="label__placeholder">{placeholder.clone()}</span> }
} else {
html! { text.clone() }
};
let edit_button = if *editable {
html! { <span class="label__edit-button">{"edit"}</span> }
} else { html! { } };
html! {
<div class="label">
{body_text}{edit_button}
</div>
}
}

View File

@ -0,0 +1,14 @@
mod card;
pub use card::Card;
mod label;
pub use label::Label;
mod row;
pub use row::Row;
mod swatch;
pub use swatch::Swatch;
mod text_entry;
pub use text_entry::TextEntry;

View File

@ -0,0 +1,15 @@
use yew::{function_component, html, Html, Properties};
#[derive(Properties, PartialEq)]
pub struct RowProps {
pub children: Html
}
#[function_component]
pub fn Row(RowProps { children }: &RowProps) -> Html {
html! {
<div class="row">
{children.clone()}
</div>
}
}

View File

@ -0,0 +1,14 @@
use yew::{function_component, html, AttrValue, Html, Properties};
#[derive(Properties, PartialEq)]
pub struct SwatchProps {
pub color: AttrValue,
}
#[function_component]
pub fn Swatch(SwatchProps { color }: &SwatchProps) -> Html {
let class_name = format!("swatch swatch__{}", color);
html! {
<div class={class_name} />
}
}

View File

@ -0,0 +1,33 @@
use wasm_bindgen::JsCast;
use web_sys::HtmlInputElement;
use yew::{function_component, html, use_node_ref, use_state, AttrValue, Callback, Event, Html, Properties};
#[derive(Properties, PartialEq)]
pub struct TextEntryProps {
#[prop_or(AttrValue::from(""))]
pub value: AttrValue,
#[prop_or(AttrValue::from("placeholder"))]
pub placeholder: AttrValue,
#[prop_or(None)]
pub on_changed: Option<Callback<String>>,
}
#[function_component]
pub fn TextEntry(TextEntryProps { value, placeholder, on_changed }: &TextEntryProps) -> Html {
let on_changed_ = {
let on_changed = on_changed.clone();
Callback::from(move |event: Event| {
let input = event.target().and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
if let Some(input) = input {
if let Some(ref on_changed) = on_changed {
on_changed.emit(input.value());
}
}
})
};
html! {
<input class="text-entry" type="text" placeholder={placeholder} onchange={on_changed_} value={value} />
}
}

View File

@ -3,13 +3,26 @@ use std::rc::Rc;
use gloo_console::log;
use visions_types::{AuthResponse, SessionId, UserOverview};
use yew::prelude::*;
use yew_router::prelude::*;
mod client;
use client::*;
mod components;
mod views;
use views::Design;
use views::Login;
#[derive(Clone, Routable, PartialEq)]
enum Route {
#[at("/")]
Home,
#[at("/design")]
Design,
}
struct AuthInfo {
session_id: Option<SessionId>,
}
@ -120,6 +133,22 @@ fn App() -> Html {
}
}
fn main() {
yew::Renderer::<App>::new().render();
fn switch(routes: Route) -> Html {
match routes {
Route::Home => html! { <App /> },
Route::Design => html! { <Design /> },
}
}
#[function_component]
fn AppWrapper() -> Html {
html! {
<BrowserRouter>
<Switch<Route> render={switch} />
</BrowserRouter>
}
}
fn main() {
yew::Renderer::<AppWrapper>::new().render();
}

View File

@ -0,0 +1,63 @@
use yew::{function_component, html, Html, Properties};
use crate::components::*;
#[derive(Properties, PartialEq)]
pub struct DesignProps { }
#[function_component]
pub fn Design(DesignProps { }: &DesignProps) -> Html {
html! {
<div>
<Row>
<Swatch color="grey-1" />
<Swatch color="grey-2" />
<Swatch color="grey-3" />
<Swatch color="grey-4" />
<Swatch color="grey-5" />
</Row>
<Row>
<Swatch color="blue-1" />
<Swatch color="blue-2" />
<Swatch color="blue-3" />
<Swatch color="blue-4" />
<Swatch color="blue-5" />
</Row>
<Row>
<Swatch color="purple-1" />
<Swatch color="purple-2" />
<Swatch color="purple-3" />
<Swatch color="purple-4" />
<Swatch color="purple-5" />
</Row>
<Row>
<Swatch color="red-1" />
<Swatch color="red-2" />
<Swatch color="red-3" />
<Swatch color="red-4" />
<Swatch color="red-5" />
</Row>
<Row>
<Label placeholder="username" />
<Label placeholder="username" editable=true />
<Label text="normal label" placeholder="empty" />
<Label text="editable label" placeholder="empty" editable=true />
</Row>
<Row>
<TextEntry placeholder="username" />
<TextEntry value="vakarian" placeholder="username" />
</Row>
<Row>
<Card title="Card Title">
<p>{"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."}</p>
</Card>
</Row>
</div>
}
}

View File

@ -2,6 +2,8 @@ use wasm_bindgen::JsCast;
use web_sys::HtmlInputElement;
use yew::{function_component, html, use_state, Callback, Event, Html, Properties};
use crate::components::TextEntry;
#[derive(Properties, PartialEq)]
pub struct LoginProps {
pub on_login: Callback<(String, String)>,
@ -19,6 +21,17 @@ pub fn Login(LoginProps { on_login }: &LoginProps) -> Html {
Callback::from(move |_| on_login.emit((username.to_string(), password.to_string())))
};
let on_username_changed = {
let username = username.clone();
Callback::from(move |text: String| username.set(text))
};
let on_password_changed = {
let username = username.clone();
Callback::from(move |text: String| username.set(text))
};
/*
let on_username_changed = {
let username = username.clone();
Callback::from(move |event: Event| {
@ -42,7 +55,9 @@ pub fn Login(LoginProps { on_login }: &LoginProps) -> Html {
}
})
};
*/
/*
html! {
<div class="login-form">
<div class="card">
@ -53,6 +68,17 @@ pub fn Login(LoginProps { on_login }: &LoginProps) -> Html {
</div>
</div>
}
*/
html! {
<div class="login-form">
<div class="card">
<h1>{"Welcome to Visions VTT"}</h1>
<TextEntry placeholder="username" on_changed={on_username_changed} />
<TextEntry placeholder="password" on_changed={on_password_changed} />
<button onclick={on_click}>{"Login"}</button>
</div>
</div>
}
}

View File

@ -1,2 +1,6 @@
mod design;
pub use design::Design;
mod login;
pub use login::Login;