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-futures",
|
||||
"wasm-logger",
|
||||
"web-sys",
|
||||
"yew",
|
||||
"yew-router",
|
||||
"yew-utils",
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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/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>
|
||||
|
||||
|
@ -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
|
@ -2,3 +2,4 @@ pub mod footer;
|
||||
pub mod language_picker;
|
||||
pub mod nav_bar;
|
||||
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::*;
|
||||
|
||||
#[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>
|
||||
}
|
||||
}
|
||||
|
@ -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()}/>
|
||||
</>
|
||||
|
Loading…
Reference in New Issue
Block a user