Zadanie domowe nr 2: 05.11 JS
Formularz kontaktowy wraz z walidacją inputów na różnych poziomach
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple HTML Webside</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!--skip link dla dostepnosci-->
<a href="#main-content">return to the main page</a>
<!-- nawigacja strony -->
<header>
<h1>Bądz bezpieczny w sieci</h1>
<nav aria-label="Glowna nawigacja">
<!--lista punktowana, przypadkowa-->
<ul class="menu">
<li><a href="/" aria-current="page">Home page</a></li>
<li><a href="/about_us">About us</a></li>
<li><a href="/services">Our services</a>
<!--menu rozwijajace sie-->
<ul>
<li><a href="/services/web">Web Development</a></li>
<li><a href="/services/apps">Mobile Apps</a></li>
<li><a href="/services/consulting">Consulting</a></li>
</ul>
</li>
<!--zamykam menu rozwijajace sie-->
<li><a href="portfolio">Portfolio</a></li>
<li><a href="contact">Contact us</a>
<ul>
<li><a href="mailto:[email protected]">Send a mss</a></li>
<li><a
href="mailto:[email protected]?subject=Zapytanie%20ofertowe&body=Dzień%20dobry,%0D%0AChciałbym%20otrzymać%20ofertę...">Send
a question</a></li>
</ul>
</li>
</ul>
</header>
<!--tworze sciezke ciasteczkowa czyli Breadcrumbs - pasek pokazujący użytkownikowi, gdzie aktualnie się znajduje w strukturze strony i pozwalający łatwo wrócić do poprzednich poziomów
<nav aria-label="Navigation path" class="breadcrumbs">
<ol>
<li><a href="/">Home page</a></li>
<li><a href="/services">Our services</a></li>
<li><a href="/services/web">Web Development</a></li>
<li aria-current="page">Frontend Development</li>
</ol>
</nav> -->
<!--Główna treść-->
<div class="content-wrapper"></div>
<main id="main-content">
<h2>Frontend Development</h2>
<p>Lorem ipsum dolor sit amet. Vel nisi autem ut eveniet esse sed repellat odit vel galisum iure non nihil illum aut
consectetur quidem. Qui fugiat consequuntur ea temporibus omnis eum galisum illum. Qui ipsum veniam est impedit
dolorem et omnis facere rem laborum beatae est nemo eligendi rem voluptatibus ipsa.</p>
<section id="about_us" class="about_section">
<h2>About us</h2>
<p>Lorem ipsum dolor sit amet. Vel nisi autem ut eveniet esse sed repellat odit vel galisum iure non nihil illum
aut consectetur quidem. Qui fugiat consequuntur ea temporibus omnis eum galisum illum. Qui ipsum veniam est
impedit dolorem et omnis facere rem laborum beatae est nemo eligendi rem voluptatibus ipsa.</p>
<li>
<!-- Miniaturka otwierająca zdjęcie w pełnej rozdzielczości -->
<a href="https://picsum.photos/id/1012/1200/800" target="_blank">
<img src="https://picsum.photos/id/1012/450/250" alt="team-photo" title="view full size"
style="border-radius:10px; transition: transform 0.3s ease;">
</a>
</li>
</section>
<!-- Sekcja kontaktowa -->
<section id="contact-form-section" aria-labelledby="contact-form-title">
<h2 id="contact-form-title">Formularz kontaktowy</h2>
<p>Hej! Nie bój się do mnie napisać </p>
<!-- Formularz -->
<form id="contactForm" novalidate>
<!-- Imię -->
<div class="form-group">
<label for="firstName">Imię *</label>
<input type="text" id="firstName" name="firstName" required minlength="2" maxlength="20" required
placeholder="Jan">
<small class="error-message"></small>
</div>
<!-- Nazwisko -->
<div class="form-group">
<label for="lastName">Nazwisko *</label>
<input type="text" id="lastName" name="lastName" required minlength="2" maxlength="30" required
placeholder="Kowalski">
<small class="error-message"></small>
</div>
<!-- Adres e-mail -->
<div class="form-group">
<label for="email">Adres e-mail *</label>
<input type="email" id="email" name="email" minlength="5" maxlength="30" required
placeholder="[email protected]">
<small class="error-message"></small>
</div>
<!-- Wiadomość -->
<div class="form-group">
<label for="message">Wiadomość</label>
<textarea id="message" name="message" rows="4" maxlength="150" placeholder="Treść wiadomości"></textarea>
</div>
<!-- Checkbox - zgoda -->
<div class="form-group checkbox">
<input type="checkbox" id="newsletter" name="newsletter"
title="To pole nie jest obowiązkowe. Zaznacz tylko jeśli chcesz być na bieżąco">
<label for="newsletter">Zgadzam się na otrzymywanie newslettera</label>
</div>
<!-- Przycisk wysyłania -->
<button type="submit" class="submit-btn">Wyślij wiadomość</button>
<!-- Komunikat sukcesu -->
<p id="formSuccess" class="success-message" aria-live="polite"></p>
</form>
</section>
</main>
<!--Nawigacja boczna-->
<aside>
<nav aria-label="Side Navigation">
<h3>Bezpieczne linki</h3>
<ul>
<li>
<a href="https://haveibeenpwned.com/">Sprawdz czy już nie shakowano Twojego maila</a>
</li>
<li>
<a href="https://nmap.org/">Przeanalizuj bezpieczeństwo swojej sieci</a>
</li>
</ul>
<ul>
<li>
<section id="video-security" class="fade-in">
<h3>Bezpieczeństwo online – i już wiesz, jak ...</32>
<div class="video-gallery">
<div class="video-item">
<iframe src="https://www.youtube.com/embed/Wj__ECFxm2o" title="Bezpieczeństwo haseł"
allowfullscreen></iframe>
<p>Jak zabezpieczyć swoje hasło</p>
</div>
<div class="video-item">
<iframe src="https://www.youtube.com/embed/op5mnWLZod8" title="Publiczne Wi-Fi"
allowfullscreen></iframe>
<p>Jak bezpiecznie korzystać z publicznego Wi-Fi</p>
</div>
<div class="video-item">
<iframe src="https://www.youtube.com/embed/CbTtTJNQS50" title="Ataki phishingowe"
allowfullscreen></iframe>
<p>Jak rozpoznać atak phishingowy</p>
</div>
</section>
</li>
</ul>
</ul>
</nav>
</aside>
</div>
<!--Nawigacja stopki-->
<footer>
<nav aria-label="Footer navigation">
<h2>Links</h2>
<ul>
<li><a href="/privacy_policy">Privacy Policy</a></li>
<li><a href="/terms_conditions">Terms and Conditions</a></li>
</ul>
</nav>
<!-- Sekcja z muzyką -->
<section aria-label="Muzyka">
<h3>🎧 enjoy your time listening to music</h3>
<p>Turn on the music and enjoy surfing our website!</p>
<audio controls>
<source src="https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3" type="audio/mpeg">
Twoja przeglądarka nie obsługuje elementu audio.
</audio>
</section>
<p>Copyright 2025 - Moja strona</p>
</footer>
<script>
// Funkcja pomocnicza do czyszczenia i formatowania tekstu
function formatName(input) {
// Usuń spacje z początku i końca
let cleaned = input.trim();
// Jeśli jest coś wpisane – zmień pierwszą literę na dużą, resztę na małe
if (cleaned.length > 0) {
cleaned = cleaned.charAt(0).toUpperCase() + cleaned.slice(1).toLowerCase();
}
return cleaned;
}
document.getElementById('contactForm').addEventListener('submit', function (e) {
e.preventDefault(); // zatrzymujemy domyślną wysyłkę formularza
// Pobranie elementów formularza
const firstName = document.getElementById('firstName');
const lastName = document.getElementById('lastName');
const email = document.getElementById('email');
const message = document.getElementById('message');
const newsletter = document.getElementById('newsletter');
const successMsg = document.getElementById('formSuccess');
let valid = true;
// Czyszczenie poprzednich błędów
document.querySelectorAll('.error-message').forEach(el => el.textContent = '');
// Formatowanie imienia i nazwiska (usuń spacje, duża litera na początku)
firstName.value = formatName(firstName.value);
lastName.value = formatName(lastName.value);
// --- Walidacja imienia ---
if (firstName.value.length < 2) {
firstName.nextElementSibling.textContent = 'Na prawdę tak masz na imię? (min. 2 znaki)';
valid = false;
}
else if (firstName.value.length > 20) {
firstName.nextElementSibling.textContent = "Wyczerpałeś limit dostępnych znaków (max. 20 znaków)";
valid = false;
}
// --- Walidacja nazwiska ---
if (lastName.value.length < 2) {
lastName.nextElementSibling.textContent = 'Czy to na pewno jest Twoje nazwisko? (min. 2 znaki)';
valid = false;
}
else if (lastName.value.length > 30) {
lastName.nextElementSibling.textContent = "Wyczerpałeś limit dostępnych znaków (max. 30 znaków)";
valid = false;
}
// --- Walidacja e-maila ---
// Sprawdzamy czy e-mail zawiera znak "@"
if (!email.value.includes('@')) {
email.nextElementSibling.textContent = 'Nie zapomnij o znaku "@"';
valid = false;
}
else if (email.value.length < 5) {
email.nextElementSibling.textContent = 'Adres e-mail jest za krótki.';
valid = false;
}
else if (email.value.length > 50) {
email.nextElementSibling.textContent = "Adres e-mail jest za długi.";
valid = false;
}
if (message.value.length > 150) {
message.nextElementSibling.textContent = "Każde słowo jest na wagę złota. Postaraj się streścić do 150 znaków";
valid = false;
}
// --- Jeśli wszystko jest OK ---
if (valid) {
successMsg.textContent = '✅ Dzięki za wysłanie wiadomości.';
successMsg.style.color = 'green';
// Symulacja wysyłki — a w przysłości można tutaj wysłać dane do bazy danych
console.log({
firstName: firstName.value,
lastName: lastName.value,
email: email.value,
message: message.value,
newsletter: newsletter.checked
});
// Sukces! Resetujemy formularz po 2 sekundach
setTimeout(() => this.reset(), 2000);
} else {
// Błąd - czyścimy komunikat sukcesu
successMsg.textContent = '';
}
});
</script>
</body>
</html>/* Reset styli, bo każda przeglądarka ma swój styl */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* przypisanie konkretnego stylu dla parametru, klasy lub kontenera*/
html {
font-size: 16px;
scroll-behavior: smooth;
}
ul,
ol,
.about_section {
list-style: none;
}
h1,
h2,
h3,
h4 {
font-family: "Playfair Display", serif;
}
body {
font-family: "Poppins", "Segoe UI", sans-serif;
color: #333;
background: linear-gradient(135deg, #fafafa 0%, #fff5f8 40%, #fefefe 100%);
background-attachment: fixed;
line-height: 1.6;
}
header,
main,
section,
aside,
footer {
background-color: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(4px);
border-radius: 16px;
box-shadow: 0 0 20px rgba(190, 170, 170, 0.15);
margin: 1rem auto;
max-width: 1000px;
padding: 1.5rem;
transition: box-shadow 0.3s ease;
}
header {
background: linear-gradient(135deg, #fff8f9 0%, #fefefe 60%);
border: 1px solid rgba(255, 228, 232, 0.5);
text-align: center;
}
header h1 {
text-transform: uppercase;
letter-spacing: 1px;
font-size: 32px;
margin-bottom: 0, 5rem;
color: #a67c52;
}
.menu {
list-style: none;
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 2rem;
}
.menu a {
color: #c0a36e;
text-decoration: none;
font-weight: 500;
position: relative;
transform: color 0, 3s ease;
}
.menu a::after {
content: "";
position: absolute;
width: 0;
height: 2px;
left: 0;
bottom: -4px;
background-color: #d4af37;
transition: width 0.3s ease;
}
.menu a:hover {
color: #d4af37;
}
.menu a:hover::after {
width: 100%;
}
.breadcrumbs {
background: rgba(255, 255, 255, 0.5);
border-left: 4px solid #d4af37;
font-size: 0.9rem;
padding: 0.5rem 1rem;
color: #777;
}
.breadcrumbs a {
color: #aea06a;
}
.breadcrumbs a:hover {
color: #000;
}
main h2,
.about_section h2 {
color: #a67c52;
border-bottom: 2px solid #d4af37;
padding-bottom: 0.3rem;
display: inline-block;
margin-bottom: 0.8rem;
}
.about_section {
background: rgba(255, 255, 255, 0.6);
}
.about_section img {
width: 100%;
max-width: 500px;
border-radius: 12px;
border: 2px solid #f5e6cc;
box-shadow: 0 0 20px rgba(218, 185, 155, 0.2);
transition: transform 0.3s ease;
}
.about_section p {
max-width: 500px;
margin-bottom: 1rem;
}
.about-section img:hover {
transform: scale(1.03);
}
/* Sekcja formularza kontaktowego */
#contact-form-section {
max-width: 500px;
margin: 2rem auto;
padding: 1.5rem;
border: 1px solid #ccc;
border-radius: 12px;
background-color: #fafafa;
}
#contact-form-section h2 {
text-align: center;
color: #bdbb9e;
}
.form-group {
margin-bottom: 1rem;
display: flex;
flex-direction: column;
}
.form-group label {
font-weight: 500;
margin-bottom: 0.3rem;
}
.form-group input,
.form-group textarea {
padding: 0.6rem;
border: 1px solid #aaa;
border-radius: 6px;
font-size: 1rem;
}
.form-group.checkbox {
flex-direction: row;
align-items: center;
}
.form-group.checkbox label {
margin-left: 0.5rem;
font-weight: normal;
}
button,
.submit-btn {
background: linear-gradient(135deg, #f8e7cf, #e6c78f);
border: none;
color: #5c4a28;
font-weight: 600;
padding: 0.6rem 1.2rem;
border-radius: 8px;
cursor: pointer;
transition: all 0.4s ease;
width: 100%;
position: relative;
overflow: hidden;
z-index: 0;
}
button:hover,
.submit-btn:hover {
background: linear-gradient(135deg, #e6c78f, #f8e7cf);
color: white;
box-shadow: 0 0 15px 4px rgba(212, 175, 55, 0.6); /* złoty blask */
transform: translateY(-2px); /* lekko unosi przycisk */
}
button::before,
.submit-btn::before {
content: "";
position: absolute;
top: 0;
left: -75%;
width: 50%;
height: 100%;
background: linear-gradient(120deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0));
transform: skewX(-25deg);
transition: all 0.7s ease;
z-index: 1;
}
button:hover::before,
.submit-btn:hover::before {
left: 125%;
}
button:active,
.submit-btn:active {
transform: scale(0.97);
box-shadow: 0 0 5px rgba(212, 175, 55, 0.4);
}
.error-message {
color: red;
font-size: 0.85rem;
height: 1rem;
}
/* komunikat sukcesu po wysłaniu*/
.success-message {
text-align: center;
color: green;
margin-top: 1rem;
font-weight: bold;
}
/* === GALERIA WIDEO W JEDNEJ LINII === */
.video-gallery {
display: flex;
justify-content: center;
align-items: flex-start;
gap: 1.5rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.video-item {
flex: 1 1 220px;
max-width: 300px;
text-align: center;
cursor: pointer;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.video-item iframe {
width: 100%;
height: 200px;
border-radius: 12px;
border: none;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.video-item:hover {
transform: scale(1.03);
box-shadow: 0 0 15px rgba(212, 175, 55, 0.4); /* złoty efekt hover */
}
/* Responsywność dla mniejszych ekranów */
@media (max-width: 768px) {
.video-item iframe {
height: 180px;
}
}
footer {
background: linear-gradient(145deg, #fffaf7, #fff);
color: #7a6b55;
text-align: center;
border-top: 2px solid #d4af37;
}
footer a {
color: #b48b5b;
text-decoration: none;
}
footer a:hover {
color: #d4af37;
text-decoration: underline;
}
/* RESPONSYWNOŚĆ */
@media (max-width: 768px) {
.content-wrapper {
flex-direction: column;
align-items: center;
}
main, aside {
width: 100%;
max-width: 600px;
}
}
Bądz bezpieczny w sieci
Frontend Development
Lorem ipsum dolor sit amet. Vel nisi autem ut eveniet esse sed repellat odit vel galisum iure non nihil illum aut consectetur quidem. Qui fugiat consequuntur ea temporibus omnis eum galisum illum. Qui ipsum veniam est impedit dolorem et omnis facere rem laborum beatae est nemo eligendi rem voluptatibus ipsa.
About us
Lorem ipsum dolor sit amet. Vel nisi autem ut eveniet esse sed repellat odit vel galisum iure non nihil illum aut consectetur quidem. Qui fugiat consequuntur ea temporibus omnis eum galisum illum. Qui ipsum veniam est impedit dolorem et omnis facere rem laborum beatae est nemo eligendi rem voluptatibus ipsa.
Formularz kontaktowy
Hej! Nie bój się do mnie napisać