From cd684dbaf7c1e6464b26e1735a4b78345ed7698f Mon Sep 17 00:00:00 2001 From: seccodesmith Date: Tue, 27 May 2025 13:41:26 +0200 Subject: [PATCH] feat: implement styling for Contact page and form components --- src/assets/styles/Contact.module.scss | 270 ++++++++++++++++++++++++++ src/assets/styles/FormControl.scss | 95 +++++++++ src/assets/styles/card.scss | 35 ++++ src/components/ContactForm.tsx | 10 +- src/components/styles.css | 135 ------------- src/pages/Contact.tsx | 48 ++--- 6 files changed, 430 insertions(+), 163 deletions(-) create mode 100644 src/assets/styles/FormControl.scss create mode 100644 src/assets/styles/card.scss diff --git a/src/assets/styles/Contact.module.scss b/src/assets/styles/Contact.module.scss index e69de29..c5695e9 100644 --- a/src/assets/styles/Contact.module.scss +++ b/src/assets/styles/Contact.module.scss @@ -0,0 +1,270 @@ +@use './variables' as *; +@use './card.scss' as card; + +@include card.card; + +/* Card styling */ +.contactCard { + position: relative; + border-left: 3px solid $accent-fire; + padding-left: 1.5rem; +} + +.contactIcon { + width: 50px; + height: 50px; + border-radius: 50%; + background-color: rgba(255, 100, 0, 0.1); + display: flex; + align-items: center; + justify-content: center; + color: $accent-fire; + font-size: 1.5rem; + margin-bottom: 1rem; +} + +.contactTitle { + font-size: 1.3rem; + color: $text-light; + margin-bottom: 1rem; +} + +.contactContent { + color: $text-ash; + line-height: 1.6; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +.contactLink { + color: $accent-fire; + text-decoration: none; + transition: all 0.3s ease; +} + +.contactLink:hover { + text-decoration: underline; + color: $accent-ember; +} + +/* Button styling */ +.btnPrimary { + background: linear-gradient(45deg, $accent-dragon, $accent-fire); + border: none; + padding: 0.75rem 2rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; + box-shadow: 0 4px 15px rgba(139, 0, 0, 0.3); + transition: all 0.3s ease; + position: relative; + overflow: hidden; +} + +.btnPrimary:hover { + transform: translateY(-3px); + box-shadow: 0 7px 25px rgba(139, 0, 0, 0.5); + background-color: $accent-fire; + background-image: none; +} + +.btnPrimary:focus { + box-shadow: 0 0 0 0.25rem rgba(255, 100, 0, 0.4); +} + +.btnPrimary::before { + content: ""; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); + transition: 0.6s; +} + +.btnPrimary:hover::before { + left: 100%; +} + +.btnPrimary:disabled { + background: linear-gradient(45deg, rgba(139, 0, 0, 0.5), rgba(255, 100, 0, 0.5)); + transform: none; +} + +/* Social links styling */ +.socialGrid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); + gap: 15px; + margin-top: 1.5rem; +} + +.socialItem { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 10px; + padding: 15px; + border-radius: 8px; + background-color: rgba(255, 255, 255, 0.05); + transition: all 0.3s ease; + text-decoration: none; +} + +.socialItem:hover { + background-color: rgba(255, 100, 0, 0.1); + transform: translateY(-5px); +} + +.socialIconLg { + font-size: 1.8rem; + color: $accent-fire; +} + +.socialName { + color: $text-ash; + font-size: 0.9rem; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +/* Map styling */ +.mapContainer { + position: relative; + overflow: hidden; + border-radius: 8px; + border: 1px solid $card-border; + margin-bottom: 2rem; +} + +.mapContainer::before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 5px; + background: linear-gradient(to right, $accent-dragon, $accent-fire); + z-index: 1; +} + +.mapFrame { + width: 100%; + height: 400px; + border: none; + background-color: $card-bg; + filter: grayscale(90%) invert(92%) hue-rotate(180deg); +} + +/* Accordion styling */ +.accordionButton { + background-color: $card-bg !important; + color: $text-light !important; + border-color: $card-border !important; + box-shadow: none !important; + padding: 1rem 1.25rem; + font-family: 'Cinzel', serif; +} + +.accordionButton:not(.collapsed) { + color: $accent-fire !important; +} + +.accordionButton:focus { + border-color: $accent-fire !important; + box-shadow: 0 0 0 0.25rem rgba(255, 100, 0, 0.25) !important; +} + +.accordionButton::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ff6400'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e") !important; +} + +.accordionItem { + background-color: transparent; + border: none; + margin-bottom: 1rem; +} + +.accordionBody { + background-color: $card-bg; + border: 1px solid $card-border; + border-top: none; + color: $text-ash; + padding: 1.25rem; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + border-bottom-left-radius: 0.375rem; + border-bottom-right-radius: 0.375rem; +} + +/* Binary background effect */ +.binaryLine { + position: absolute; + font-family: 'Fira Code', monospace; + color: $accent-fire; + font-size: 0.8rem; + opacity: 0.15; + pointer-events: none; +} + +/* Ember effect */ +.emberParticle { + position: absolute; + width: 3px; + height: 3px; + background-color: $accent-fire; + border-radius: 50%; + opacity: 0.6; + pointer-events: none; + z-index: 2; + box-shadow: 0 0 5px $accent-fire; + animation: float 3s linear infinite; +} + +@keyframes float { + 0% { + transform: translateY(0) rotate(0deg); + opacity: 0.6; + } + + 100% { + transform: translateY(-100px) rotate(360deg); + opacity: 0; + } +} + +/* Table styling */ +.table { + color: $text-ash; + margin-bottom: 0; +} + +.table td { + padding: 0.5rem 0.25rem; + border-color: rgba(255, 255, 255, 0.05); + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +@media (max-width: 768px) { + .schedule-container { + overflow-x: auto; + } + + .social-grid { + grid-template-columns: repeat(3, 1fr); + } + + .map-frame { + height: 300px; + } +} + +@media (max-width: 576px) { + .social-grid { + grid-template-columns: repeat(2, 1fr); + gap: 10px; + } + + .form-floating>label { + padding: 0.75rem 0.75rem; + } +} \ No newline at end of file diff --git a/src/assets/styles/FormControl.scss b/src/assets/styles/FormControl.scss new file mode 100644 index 0000000..4595d48 --- /dev/null +++ b/src/assets/styles/FormControl.scss @@ -0,0 +1,95 @@ +@use './variables.scss' as *; + +/* Form styling */ +.form-control { + background-color: rgba(255, 255, 255, 0.05); + border: 1px solid var(--card-border); + color: var(--text-light); + padding: 0.75rem 0.9375rem; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +.form-control:focus { + background-color: rgba(255, 255, 255, 0.08); + border-color: var(--accent-fire); + box-shadow: 0 0 0 0.25rem rgba(255, 100, 0, 0.25); + color: var(--text-light); +} + +.form-control::placeholder { + color: rgba(255, 255, 255, 0.3); +} + +textarea.form-control { + min-height: 120px; +} + +.form-label { + color: var(--text-ash); + font-weight: 600; + margin-bottom: 0.5rem; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +.form-text { + color: rgba(255, 255, 255, 0.5); +} + +.form-select { + background-color: rgba(255, 255, 255, 0.05); + border: 1px solid var(--card-border); + color: var(--text-light); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23ff6400' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +.form-select:focus { + background-color: rgba(255, 255, 255, 0.08); + border-color: var(--accent-fire); + box-shadow: 0 0 0 0.25rem rgba(255, 100, 0, 0.25); + color: var(--text-light); +} + +.form-select option { + background-color: var(--card-bg); + color: var(--text-light); +} + +/* Alert styling */ +.alert-success { + background-color: rgba(25, 135, 84, 0.1); + border-color: rgba(25, 135, 84, 0.3); + color: #75b798; +} + +.alert-danger { + background-color: rgba(220, 53, 69, 0.1); + border-color: rgba(220, 53, 69, 0.3); + color: #ea868f; +} + +/* Form validation styling */ +.was-validated .form-control:invalid, +.form-control.is-invalid { + border-color: #dc3545; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.was-validated .form-control:valid, +.form-control.is-valid { + border-color: #198754; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.invalid-feedback { + color: #dc3545; + font-size: 0.875em; + margin-top: 0.25rem; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} \ No newline at end of file diff --git a/src/assets/styles/card.scss b/src/assets/styles/card.scss new file mode 100644 index 0000000..999ad18 --- /dev/null +++ b/src/assets/styles/card.scss @@ -0,0 +1,35 @@ +@use './variables.scss' as *; + +/* Card styling */ +@mixin card { + .card { + background-color: $card-bg; + border: 1px solid $card-border; + border-radius: 8px; + transition: all 0.3s ease; + overflow: hidden; + } + + .card:hover { + transform: translateY(-7px); + border-color: rgba(255, 100, 0, 0.3); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4); + } + + .card::before { + content: ""; + position: absolute; + width: 100%; + height: 5px; + top: 0; + left: 0; + background: linear-gradient(to right, $accent-dragon, $accent-fire); + z-index: 1; + } + + @media (max-width: 576px) { + .card-body { + padding: 1.25rem; + } + } +} \ No newline at end of file diff --git a/src/components/ContactForm.tsx b/src/components/ContactForm.tsx index 792eb1c..0209f3e 100644 --- a/src/components/ContactForm.tsx +++ b/src/components/ContactForm.tsx @@ -1,4 +1,6 @@ import { useState, type FormEvent } from 'react'; +import '@styles/FormControl.scss' +import styles from '@styles/Contact.module.scss' export const ContactForm = () => { const [formData, setFormData] = useState({ @@ -47,11 +49,11 @@ export const ContactForm = () => { }; return ( -
-
+
+

Send a Message to the Forge

-
+
{/* Success message */} {showSuccess && (
@@ -176,7 +178,7 @@ export const ContactForm = () => {
-
+