style changes

This commit is contained in:
2025-10-03 01:48:36 +02:00
parent d0227e4539
commit f5cf8bbaa7
12 changed files with 85 additions and 180 deletions

View File

@@ -1,6 +1,7 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<link rel="stylesheet" href="reset.css">
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />

View File

@@ -11,6 +11,7 @@
"@types/react-router": "^5.1.20", "@types/react-router": "^5.1.20",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-icons": "^5.5.0",
"react-router-dom": "^7.8.1" "react-router-dom": "^7.8.1"
}, },
"devDependencies": { "devDependencies": {
@@ -2922,6 +2923,15 @@
"react": "^19.1.1" "react": "^19.1.1"
} }
}, },
"node_modules/react-icons": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
"license": "MIT",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.17.0", "version": "0.17.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",

View File

@@ -13,6 +13,7 @@
"@types/react-router": "^5.1.20", "@types/react-router": "^5.1.20",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-icons": "^5.5.0",
"react-router-dom": "^7.8.1" "react-router-dom": "^7.8.1"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,99 +0,0 @@
/*TODO: Implement the contact form functionality*/
{% load static %}
<div class="contact-me">
<div class="opening">
<i class="fa-solid fa-arrow-pointer" aria-hidden="true"></i>
</div>
<div class="content">
<form method="post" id="contactme-form">
{% csrf_token %}
{{ contactme_form }}
<input type="submit" value="Submit">
</form>
</div>
<div class="cover"></div>
<div class="triangle"></div>
</div>
<script src="{% static 'home/js/global/contact-me.js' %}"></script>
contact-me.js:
$(document).ready(function () {
$("#contactme-form").submit(function (event) {
event.preventDefault(); // Prevent normal form submission
$.ajax({
url: "/submit-contactme/", // URL of the Django view
type: "POST",
data: $(this).serialize(), // Serialize form data
success: function (response) {
if (response.success) {
close_contact();
$("#contactme-form .success-form-alert").fadeIn();
$("#contactme-form")[0].reset(); // Clear the form
alert("Zpráva odeslaná!")
}
},
error: function (response) {
alert("Zpráva nebyla odeslaná, zkontrolujte si připojení k internetu nebo naskytl u nás problém :(")
}
});
});
$("#contactme-form .success-form .close").click(function () {
$("#contactme-form .success-form-alert").fadeOut();
});
var opened_contact = false;
$(document).on("click", ".contact-me .opening", function () {
console.log("toggle mail");
const opening = $(".contact-me .opening");
// Check if we're opening or closing
if (opened_contact === false) {
// Toggle rotation
opening.toggleClass('rotate-opening');
// Wait for the rotation to finish
setTimeout(function() {
$(".contact-me .content").addClass('content-moveup-index');
}, 500);
setTimeout(function() {
$(".contact-me .content")[0].offsetHeight;
$(".contact-me .content").addClass('content-moveup');
}, 1000); // Small delay to trigger transition
opened_contact = true;
} else {
close_contact();
}
});
function close_contact(){
$(".contact-me .content").removeClass('content-moveup');
setTimeout(function() {
$(".contact-me .content").toggleClass('content-moveup-index');
$(".contact-me .opening").toggleClass('rotate-opening');
}, 700);
opened_contact = false;
}
});

View File

@@ -1,82 +1,64 @@
import React, { useState } from "react" import React, { useState, useRef } from "react"
import styles from "./contact-me.module.css" import styles from "./contact-me.module.css"
import { LuMousePointerClick } from "react-icons/lu";
interface ContactFormResponse {
success: boolean
[key: string]: any
}
export default function ContactMeForm() { export default function ContactMeForm() {
const [opened, setOpened] = useState(false) const [opened, setOpened] = useState(false)
const [formData, setFormData] = useState({ message: "", email: "" }) const [contentMoveUp, setContentMoveUp] = useState(false)
const [loading, setLoading] = useState(false) const [openingBehind, setOpeningBehind] = useState(false)
const [success, setSuccess] = useState(false) const [success, setSuccess] = useState(false)
const [error, setError] = useState<string | null>(null) const openingRef = useRef<HTMLDivElement>(null)
function handleSubmit() {
// form submission logic here
}
const toggleOpen = () => { const toggleOpen = () => {
setOpened((prev) => !prev) if (!opened) {
} setOpened(true)
setOpeningBehind(false)
const handleChange = ( setContentMoveUp(false)
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> // Wait for the rotate-opening animation to finish before moving content up
) => { // The actual moveUp will be handled in onTransitionEnd
const { name, value } = e.target } else {
setFormData((prev) => ({ ...prev, [name]: value })) setContentMoveUp(false)
} setOpeningBehind(false)
setTimeout(() => setOpened(false), 1000) // match transition duration
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setLoading(true)
setError(null)
try {
const response = await fetch("/submit-contactme/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": getCSRFToken(),
},
body: JSON.stringify(formData),
})
const data: ContactFormResponse = await response.json()
if (data.success) {
setSuccess(true)
setFormData({ message: "", email: "" })
} else {
setError("Zpráva nebyla odeslaná.")
}
} catch (err) {
setError("Chyba připojení nebo serveru.")
} finally {
setLoading(false)
} }
} }
// Utility to read CSRF token from cookies (Django) const handleTransitionEnd = (e: React.TransitionEvent<HTMLDivElement>) => {
const getCSRFToken = (): string => { if (opened && e.propertyName === "transform") {
const match = document.cookie.match(/csrftoken=([^;]+)/) setContentMoveUp(true)
return match ? match[1] : "" // Move the opening behind after the animation
setTimeout(() => setOpeningBehind(true), 10)
}
if (!opened && e.propertyName === "transform") {
setOpeningBehind(false)
}
} }
return ( return (
<div className={styles["contact-me"]}> <div className={styles["contact-me"]}>
<div <div
ref={openingRef}
className={ className={
opened [
? `${styles.opening} ${styles["rotate-opening"] || ""}` styles.opening,
: styles.opening opened ? styles["rotate-opening"] : "",
openingBehind ? styles["opening-behind"] : ""
].filter(Boolean).join(" ")
} }
onClick={toggleOpen} onClick={toggleOpen}
onTransitionEnd={handleTransitionEnd}
> >
<i className="fa-solid fa-arrow-pointer" aria-hidden="true"></i> <LuMousePointerClick/>
</div> </div>
<div <div
className={ className={
opened contentMoveUp
? `${styles.content} ${styles["content-moveup"] || ""}` ? `${styles.content} ${styles["content-moveup"]}`
: styles.content : styles.content
} }
> >
@@ -85,27 +67,15 @@ export default function ContactMeForm() {
type="email" type="email"
name="email" name="email"
placeholder="Váš email" placeholder="Váš email"
value={formData.email}
onChange={handleChange}
required required
/> />
<textarea <textarea
name="message" name="message"
placeholder="Vaše zpráva" placeholder="Vaše zpráva"
value={formData.message}
onChange={handleChange}
required required
/> />
<input type="submit" value={loading ? "Odesílám..." : "Odeslat"} /> <input type="submit"/>
</form> </form>
{success && (
<div className={styles.successFormAlert}>
<span>Zpráva odeslaná!</span>
<button onClick={() => setSuccess(false)}>×</button>
</div>
)}
{error && <div className={styles.errorFormAlert}>{error}</div>}
</div> </div>
<div className={styles.cover}></div> <div className={styles.cover}></div>

View File

@@ -35,6 +35,11 @@
transform: rotateX(180deg); transform: rotateX(180deg);
} }
.opening svg{
margin: auto;
font-size: 3em;
margin-top: -0.5em;
}
.contact-me .content { .contact-me .content {
@@ -89,7 +94,7 @@
} }
.opening-behind { z-index: 0 !important; }
.contact-me .cover { .contact-me .cover {
position: absolute; position: absolute;

View File

@@ -1,5 +1,6 @@
import React, { useState } from "react" import React, { useState } from "react"
import styles from "./HomeNav.module.css" import styles from "./HomeNav.module.css"
import { FaBars } from "react-icons/fa";
export default function HomeNav() { export default function HomeNav() {
const [navOpen, setNavOpen] = useState(false) const [navOpen, setNavOpen] = useState(false)
@@ -8,11 +9,7 @@ export default function HomeNav() {
return ( return (
<nav className={styles.nav}> <nav className={styles.nav}>
<i <FaBars className={styles.toggle} onClick={toggleNav} />
id="toggle-nav"
className={`fa-solid fa-bars ${styles.toggle}`}
onClick={toggleNav}
></i>
<ul className={`${styles.navList} ${navOpen ? styles.open : ""}`}> <ul className={`${styles.navList} ${navOpen ? styles.open : ""}`}>
<li id="nav-logo" className={styles.logo}> <li id="nav-logo" className={styles.logo}>

View File

@@ -20,6 +20,7 @@
height: 100%; height: 100%;
width: 100%; width: 100%;
background-color: #c2a67d; background-color: #c2a67d;
color: #5e5747;
border-radius: 1em; border-radius: 1em;
@@ -29,6 +30,13 @@
z-index: 3; z-index: 3;
} }
.portfolio div span svg{
font-size: 5em;
cursor: pointer;
animation: shake 0.4s ease-in-out infinite;
}
@keyframes shake { @keyframes shake {
0% { transform: translateX(0); } 0% { transform: translateX(0); }
@@ -55,9 +63,9 @@
width: fit-content; width: fit-content;
position: absolute; position: absolute;
z-index: 0; z-index: 0;
top: -4.7em; top: -3.7em;
left: 0; left: 0;
padding: 0 3em; padding: 1em 3em;
padding-bottom: 0; padding-bottom: 0;
background-color: #cdc19c; background-color: #cdc19c;
color: #5e5747; color: #5e5747;

View File

@@ -1,5 +1,6 @@
import React, { useState } from "react" import React, { useState } from "react"
import styles from "./Portfolio.module.css" import styles from "./Portfolio.module.css"
import { LuMousePointerClick } from "react-icons/lu";
interface PortfolioItem { interface PortfolioItem {
href: string href: string
@@ -46,7 +47,7 @@ export default function Portfolio() {
} }
onClick={toggleDoor} onClick={toggleDoor}
> >
<i className="fa-solid fa-arrow-pointer">fix missing font awesome</i> <LuMousePointerClick/>
</span> </span>
{portfolioItems.map((item, index) => ( {portfolioItems.map((item, index) => (

View File

@@ -10,10 +10,12 @@ export default function HomeLayout(){
<> <>
{/* Example usage of imported components, adjust as needed */} {/* Example usage of imported components, adjust as needed */}
<HomeNav /> <HomeNav />
<Home /> <Home /> {/*page*/}
<ContactMeForm />
<Portfolio />
<Drone /> <Drone />
<Portfolio />
<div style={{ margin: "6em auto", marginTop: "15em", maxWidth: "80vw" }}>
<ContactMeForm />
</div>
<Footer /> <Footer />
</> </>
) )

View File

@@ -4,6 +4,15 @@
@import url('https://fonts.googleapis.com/css2?family=Exo:ital,wght@0,100..900;1,100..900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Exo:ital,wght@0,100..900;1,100..900&display=swap');
:root{
--c-background: #031D44; /*background*/
--c-background-light: #04395E; /*background-highlight*/
--c-boxes: #24719f;; /*boxes*/
--c-lines: #87a9da; /*lines*/
--c-text: #CAF0F8; /*text*/
--c-other: #70A288; /*other*/
}
html{ html{
scroll-behavior: smooth; scroll-behavior: smooth;
} }