Finished general styling for contact form

This commit is contained in:
Franklin 2023-04-28 18:09:55 -04:00
parent f3ca2ce3d8
commit ecb56ed9a9
10 changed files with 256 additions and 5 deletions

1
Cargo.lock generated
View File

@ -103,6 +103,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-logger",
"web-sys",
"yew",
"yew-router",
"yew-utils",

View File

@ -16,6 +16,7 @@ yew-utils = { path = "../../libs/yew-utils" }
wasm-logger = "0.2"
wasm-bindgen = "0.2.84"
wasm-bindgen-futures = "0.4.34"
web-sys = "0.3.61"
stdweb = "0.4.20"
js-sys = "0.3"

View File

@ -0,0 +1,71 @@
.contact-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100vw;
margin-left: calc(-1 * clamp(35px, 10%, 10vw));
margin-right: calc(-1 * clamp(35px, 10%, 10vw));
background-color: #4C40F7;
padding-top: 40px;
padding-bottom: 20px;
}
.contact-title {
font-family: Poppins;
font-size: 14px;
font-weight: 400;
text-align: center;
color: white
}
.contact-subtitle {
margin-top: 20px;
font-family: Poppins;
font-size: 28px;
font-weight: 600;
text-align: center;
letter-spacing: 1px;
color: white
}
.contact-textfield-container {
margin-top: 30px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 20px;
width: 500px;
}
.contact-form-button {
margin-top: 25px;
display: flex;
justify-content: center;
align-items: center;
background-color: #00113B;
color: white;
font-size: 14px;
width: 150px;
height: 50px;
border-radius: 4px;
}
.contact-form-button {
cursor: pointer;
user-select: none;
}
@media only screen and (min-width: 1000px) {
.contact-container {
margin-left: calc(-1 * clamp(35px, 25%, 10vw));
margin-right: calc(-1 * clamp(35px, 25%, 10vw))
}
}

View File

@ -0,0 +1,54 @@
.textfield-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: start;
gap: 4px;
width: 100%;
}
.textfield {
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
height: 50px;
background-color: white;
border: solid 0.5px #d8d8d8;
width: 100%;
text-indent: 10px;
font-family: Poppins;
font-weight: 200;
font-size: 14px;
line-height: 32px;
color: #ABAFC7;
}
.textarea {
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
height: 150px;
background-color: white;
border: solid 0.5px #d8d8d8;
width: 100%;
padding: 10px;
font-family: Poppins;
font-weight: 200;
font-size: 13px;
line-height: 20px;
color: #ABAFC7;
}
::placeholder {
color: #ABAFC7;
font-family: Poppins;
font-size: 13px;
}

View File

@ -15,6 +15,8 @@
<link data-trunk type="text/css" href="css/language-picker.css" rel="css" />
<link data-trunk type="text/css" href="css/about.css" rel="css" />
<link data-trunk type="text/css" href="css/components/textfield.css" rel="css" />
<link href="https://fonts.googleapis.com/css?family=Poppins" rel="stylesheet">
<script src="https://kit.fontawesome.com/fcdfdfe1ad.js" crossorigin="anonymous"></script>

View File

@ -56,4 +56,10 @@ footer:
+62 (0) 000 0000 00
copyright-text: © 2023 Blanco Lorenzo - All rights reserved
contact:
title: Contact Us
subtitle: Leave us a message
contact.form-name-label: Name
contact.form-email-label: Email
contact.form-message-label: Start typing...
contact.form-button-label: Send

View File

@ -2,3 +2,4 @@ pub mod footer;
pub mod language_picker;
pub mod nav_bar;
pub mod service_card;
pub mod textfield;

View File

@ -0,0 +1,86 @@
// COMPONENTFORLIB
use wasm_bindgen::{JsCast, UnwrapThrowExt};
use web_sys::{HtmlInputElement, HtmlTextAreaElement};
use yew::prelude::*;
/// This component is a text
#[function_component(TextField)]
pub fn textfield(props: &TextFieldProps) -> Html {
let on_input_changed = {
let handle = props.value.clone();
let fieldtype = props.fieldtype.clone();
let onchange = props.onchange.clone();
Callback::from(move |e: InputEvent| match fieldtype {
TextFieldType::Input => {
let value = get_value_from_input_event(e);
match onchange.clone() {
Some(onchange) => {
onchange.emit(value.clone());
}
None => {}
};
handle.set(value);
}
TextFieldType::TextArea => {
let value = get_value_from_textarea_event(e);
match onchange.clone() {
Some(onchange) => {
onchange.emit(value.clone());
}
None => {}
};
handle.set(value);
}
})
};
html! {
<div class={"textfield-container"}>
{
if props.fieldtype == TextFieldType::Input {
html! { <input class={"textfield"} oninput={on_input_changed} value={(*props.value).clone()} placeholder={props.label.clone()}/> }
} else {
html! { <textarea class={"textarea"} oninput={on_input_changed} value={(*props.value).clone()} placeholder={props.label.clone()}/> }
}
}
</div>
}
}
#[derive(Properties, PartialEq, Clone)]
pub struct TextFieldProps {
pub label: String,
pub value: UseStateHandle<String>,
#[prop_or_default]
pub fieldtype: TextFieldType,
#[prop_or_default]
pub required: bool,
pub onchange: Option<Callback<String>>,
}
#[derive(PartialEq, Clone, Default)]
pub enum TextFieldType {
TextArea,
#[default]
Input,
}
pub fn get_value_from_input_event(e: InputEvent) -> String {
let event: Event = e.dyn_into().unwrap_throw();
let event_target = event.target().unwrap_throw();
let target: HtmlInputElement = event_target.dyn_into().unwrap_throw();
target.value()
}
pub fn get_value_from_textarea_event(e: InputEvent) -> String {
let event: Event = e.dyn_into().unwrap_throw();
let event_target = event.target().unwrap_throw();
let target: HtmlTextAreaElement = event_target.dyn_into().unwrap_throw();
target.value()
}
pub fn get_files_from_input_event(e: InputEvent) -> Option<web_sys::FileList> {
let event: Event = e.dyn_into().unwrap_throw();
let event_target = event.target().unwrap_throw();
let target: HtmlInputElement = event_target.dyn_into().unwrap_throw();
target.files()
}

View File

@ -1,6 +1,35 @@
use rust_i18n::t;
use yew::prelude::*;
#[function_component(CallToActionPage)]
pub fn call_to_action_page() -> Html {
html! {}
use crate::components::{language_picker::Language, textfield::{TextField, TextFieldType}};
#[derive(Properties, PartialEq)]
pub struct CallToActionPageProps {
pub language: Language
}
#[function_component(CallToActionPage)]
pub fn call_to_action_page(props: &CallToActionPageProps) -> Html {
let language = props.language.clone();
let name_handle = use_state(|| String::new());
let email_handle = use_state(|| String::new());
let message_handle = use_state(|| String::new());
html! {
<div class={"contact-container"}>
<div class={"contact-title"}>
{t!("contact.title", locale = language.locale())}
</div>
<div class={"contact-subtitle"}>
{t!("contact.subtitle", locale = language.locale())}
</div>
<div class={"contact-textfield-container"}>
<TextField label={t!("contact.form-name-label", locale = language.locale())} value={name_handle} />
<TextField label={t!("contact.form-email-label", locale = language.locale())} value={email_handle} />
<TextField label={t!("contact.form-message-label", locale = language.locale())} value={message_handle} fieldtype={TextFieldType::TextArea} />
</div>
<div class={"contact-form-button"}>
{t!("contact.form-button-label", locale = language.locale())}
</div>
</div>
}
}

View File

@ -36,7 +36,7 @@ pub fn main_page() -> Html {
<StartPage language={(*language).clone()}/>
<ServicesPage language={(*language).clone()}/>
<AboutPage language={(*language).clone()}/>
<CallToActionPage/>
<CallToActionPage language={(*language).clone()}/>
</div>
<PageFooter language={(*language).clone()}/>
</>