Finished general styling for contact form
This commit is contained in:
parent
f3ca2ce3d8
commit
ecb56ed9a9
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -103,6 +103,7 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"wasm-logger",
|
"wasm-logger",
|
||||||
|
"web-sys",
|
||||||
"yew",
|
"yew",
|
||||||
"yew-router",
|
"yew-router",
|
||||||
"yew-utils",
|
"yew-utils",
|
||||||
|
@ -16,6 +16,7 @@ yew-utils = { path = "../../libs/yew-utils" }
|
|||||||
wasm-logger = "0.2"
|
wasm-logger = "0.2"
|
||||||
wasm-bindgen = "0.2.84"
|
wasm-bindgen = "0.2.84"
|
||||||
wasm-bindgen-futures = "0.4.34"
|
wasm-bindgen-futures = "0.4.34"
|
||||||
|
web-sys = "0.3.61"
|
||||||
stdweb = "0.4.20"
|
stdweb = "0.4.20"
|
||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
|
|
||||||
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
54
css/components/textfield.css
Normal file
54
css/components/textfield.css
Normal 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;
|
||||||
|
}
|
@ -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/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/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">
|
<link href="https://fonts.googleapis.com/css?family=Poppins" rel="stylesheet">
|
||||||
<script src="https://kit.fontawesome.com/fcdfdfe1ad.js" crossorigin="anonymous"></script>
|
<script src="https://kit.fontawesome.com/fcdfdfe1ad.js" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
@ -56,4 +56,10 @@ footer:
|
|||||||
|
|
||||||
+62 (0) 000 0000 00
|
+62 (0) 000 0000 00
|
||||||
copyright-text: © 2023 Blanco Lorenzo - All rights reserved
|
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
|
@ -2,3 +2,4 @@ pub mod footer;
|
|||||||
pub mod language_picker;
|
pub mod language_picker;
|
||||||
pub mod nav_bar;
|
pub mod nav_bar;
|
||||||
pub mod service_card;
|
pub mod service_card;
|
||||||
|
pub mod textfield;
|
86
src/components/textfield.rs
Normal file
86
src/components/textfield.rs
Normal 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()
|
||||||
|
}
|
@ -1,6 +1,35 @@
|
|||||||
|
use rust_i18n::t;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
#[function_component(CallToActionPage)]
|
use crate::components::{language_picker::Language, textfield::{TextField, TextFieldType}};
|
||||||
pub fn call_to_action_page() -> Html {
|
|
||||||
html! {}
|
#[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>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ pub fn main_page() -> Html {
|
|||||||
<StartPage language={(*language).clone()}/>
|
<StartPage language={(*language).clone()}/>
|
||||||
<ServicesPage language={(*language).clone()}/>
|
<ServicesPage language={(*language).clone()}/>
|
||||||
<AboutPage language={(*language).clone()}/>
|
<AboutPage language={(*language).clone()}/>
|
||||||
<CallToActionPage/>
|
<CallToActionPage language={(*language).clone()}/>
|
||||||
</div>
|
</div>
|
||||||
<PageFooter language={(*language).clone()}/>
|
<PageFooter language={(*language).clone()}/>
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user