feat(ZEE-29): implement design system, dark mode, and JSON content management

- Add comprehensive design system with CSS variables, animations, and utility classes
- Implement dark mode with ThemeProvider (system preference + manual toggle)
- Create JSON-based content management system in src/content/
- Update all pages to use structured JSON content
- Add ThemeProvider component with theme toggle button
- Update Header with glass effect and animated mobile menu
- Update Footer with dark mode support
- Update documentation (README.md, CLAUDE.md, knowledge.md, proto/README.md)
- Sync with Linear (ZEE-29 completed)
This commit is contained in:
Do Siki
2026-01-24 02:30:27 +01:00
parent db464d1c48
commit d1213f9b3f
27 changed files with 3294 additions and 450 deletions
+7 -4
View File
@@ -1,12 +1,15 @@
import { siteConfig } from '@/config/site'
import { content } from '@/content'
import type { Metadata } from 'next'
const { contact: pageContent } = content.pages
export const metadata: Metadata = {
title: `Kapcsolat | ${siteConfig.general.name}`,
description: 'Vegye fel velünk a kapcsolatot! Segítünk minden IT kérdésében. Email, telefon és online űrlap is rendelkezésére áll.',
title: `${pageContent.meta.title} | ${siteConfig.general.name}`,
description: pageContent.meta.description,
openGraph: {
title: `Kapcsolat | ${siteConfig.general.name}`,
description: 'Vegye fel velünk a kapcsolatot! Segítünk minden IT kérdésében.',
title: `${pageContent.meta.title} | ${siteConfig.general.name}`,
description: pageContent.meta.description,
url: `${siteConfig.general.url}/kapcsolat`,
},
}
+42 -53
View File
@@ -1,8 +1,11 @@
'use client'
import { siteConfig } from '@/config/site'
import { content } from '@/content'
import { useState } from 'react'
const { contact: pageContent } = content.pages
export default function ContactPage() {
const [formData, setFormData] = useState({
name: '',
@@ -20,27 +23,27 @@ export default function ContactPage() {
const newErrors: Record<string, string> = {}
if (!formData.name.trim()) {
newErrors.name = 'A név megadása kötelező'
newErrors.name = pageContent.form.fields.name.error
}
if (!formData.email.trim()) {
newErrors.email = 'Az email cím megadása kötelező'
newErrors.email = pageContent.form.fields.email.errorRequired
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.email = 'Érvénytelen email cím formátum'
newErrors.email = pageContent.form.fields.email.errorInvalid
}
if (!formData.subject.trim()) {
newErrors.subject = 'A tárgy megadása kötelező'
newErrors.subject = pageContent.form.fields.subject.error
}
if (!formData.message.trim()) {
newErrors.message = 'Az üzenet megadása kötelező'
newErrors.message = pageContent.form.fields.message.errorRequired
} else if (formData.message.trim().length < 10) {
newErrors.message = 'Az üzenet legalább 10 karakter hosszú legyen'
newErrors.message = pageContent.form.fields.message.errorMinLength
}
if (!formData.gdprConsent) {
newErrors.gdprConsent = 'Az adatkezelési tájékoztató elfogadása kötelező'
newErrors.gdprConsent = pageContent.form.fields.gdpr.error
}
setErrors(newErrors)
@@ -93,7 +96,6 @@ export default function ContactPage() {
[name]: type === 'checkbox' ? (e.target as HTMLInputElement).checked : value
}))
// Clear error when user starts typing
if (errors[name]) {
setErrors(prev => ({ ...prev, [name]: '' }))
}
@@ -105,10 +107,10 @@ export default function ContactPage() {
<section className="bg-gradient-to-r from-blue-50 to-indigo-50 py-16">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 mb-6">
Kapcsolat
{pageContent.hero.title}
</h1>
<p className="text-xl text-gray-600 leading-relaxed">
Vegye fel velünk a kapcsolatot! Szívesen segítünk minden IT kérdésében.
{pageContent.hero.subtitle}
</p>
</div>
</section>
@@ -119,13 +121,13 @@ export default function ContactPage() {
<div>
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
Küldjön üzenetet
{pageContent.form.title}
</h2>
{submitStatus === 'success' && (
<div className="mb-6 p-4 bg-green-50 border border-green-200 rounded-md">
<p className="text-green-800">
Köszönjük üzenetét! Hamarosan felvesszük Önnel a kapcsolatot.
{pageContent.form.successMessage}
</p>
</div>
)}
@@ -133,7 +135,7 @@ export default function ContactPage() {
{submitStatus === 'error' && (
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-md">
<p className="text-red-800">
Hiba történt az üzenet küldése során. Kérjük, próbálja újra vagy írjon közvetlenül a {siteConfig.contact.email} címre.
{pageContent.form.errorMessage.replace('{email}', siteConfig.contact.email)}
</p>
</div>
)}
@@ -141,7 +143,7 @@ export default function ContactPage() {
<form onSubmit={handleSubmit} className="space-y-6">
<div>
<label htmlFor="name" className="block text-sm font-medium text-gray-700 mb-1">
Név *
{pageContent.form.fields.name.label} *
</label>
<input
type="text"
@@ -152,14 +154,14 @@ export default function ContactPage() {
className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.name ? 'border-red-300' : 'border-gray-300'
}`}
placeholder="Az Ön neve"
placeholder={pageContent.form.fields.name.placeholder}
/>
{errors.name && <p className="mt-1 text-sm text-red-600">{errors.name}</p>}
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-1">
Email cím *
{pageContent.form.fields.email.label} *
</label>
<input
type="email"
@@ -170,14 +172,14 @@ export default function ContactPage() {
className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.email ? 'border-red-300' : 'border-gray-300'
}`}
placeholder="pelda@email.hu"
placeholder={pageContent.form.fields.email.placeholder}
/>
{errors.email && <p className="mt-1 text-sm text-red-600">{errors.email}</p>}
</div>
<div>
<label htmlFor="subject" className="block text-sm font-medium text-gray-700 mb-1">
Tárgy *
{pageContent.form.fields.subject.label} *
</label>
<input
type="text"
@@ -188,14 +190,14 @@ export default function ContactPage() {
className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.subject ? 'border-red-300' : 'border-gray-300'
}`}
placeholder="Miben segíthetünk?"
placeholder={pageContent.form.fields.subject.placeholder}
/>
{errors.subject && <p className="mt-1 text-sm text-red-600">{errors.subject}</p>}
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium text-gray-700 mb-1">
Üzenet *
{pageContent.form.fields.message.label} *
</label>
<textarea
id="message"
@@ -206,7 +208,7 @@ export default function ContactPage() {
className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.message ? 'border-red-300' : 'border-gray-300'
}`}
placeholder="Írja le részletesen kérését vagy kérdését..."
placeholder={pageContent.form.fields.message.placeholder}
/>
{errors.message && <p className="mt-1 text-sm text-red-600">{errors.message}</p>}
</div>
@@ -220,9 +222,10 @@ export default function ContactPage() {
onChange={handleInputChange}
className="mt-1 h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
/>
<span className="text-sm text-gray-700">
Elfogadom az <a href="/adatkezelesi-tajekoztato" className="text-blue-600 hover:text-blue-700 underline">adatkezelési tájékoztatót</a> és hozzájárulok személyes adataim kezeléséhez a kapcsolatfelvétel céljából. *
</span>
<span
className="text-sm text-gray-700"
dangerouslySetInnerHTML={{ __html: pageContent.form.fields.gdpr.label + ' *' }}
/>
</label>
{errors.gdprConsent && <p className="mt-1 text-sm text-red-600">{errors.gdprConsent}</p>}
</div>
@@ -232,7 +235,7 @@ export default function ContactPage() {
disabled={isSubmitting}
className="w-full bg-blue-600 hover:bg-blue-700 disabled:bg-blue-400 text-white font-medium py-3 px-4 rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
>
{isSubmitting ? 'Küldés...' : 'Üzenet küldése'}
{isSubmitting ? pageContent.form.submittingButton : pageContent.form.submitButton}
</button>
</form>
</div>
@@ -242,7 +245,7 @@ export default function ContactPage() {
<div className="space-y-8">
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
Elérhetőségek
{pageContent.info.title}
</h2>
<div className="space-y-6">
@@ -251,7 +254,7 @@ export default function ContactPage() {
<span className="text-lg"></span>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-1">Email</h3>
<h3 className="font-semibold text-gray-900 mb-1">{pageContent.info.email.title}</h3>
<a
href={`mailto:${siteConfig.contact.email}`}
className="text-blue-600 hover:text-blue-700"
@@ -259,7 +262,7 @@ export default function ContactPage() {
{siteConfig.contact.email}
</a>
<p className="text-sm text-gray-600 mt-1">
24 órán belül válaszolunk
{pageContent.info.email.responseTime}
</p>
</div>
</div>
@@ -269,7 +272,7 @@ export default function ContactPage() {
<span className="text-lg">🏢</span>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-1">Cég</h3>
<h3 className="font-semibold text-gray-900 mb-1">{pageContent.info.company.title}</h3>
<p className="text-gray-700">{siteConfig.general.name}</p>
<p className="text-sm text-gray-600">{siteConfig.contact.address}</p>
</div>
@@ -280,17 +283,17 @@ export default function ContactPage() {
<span className="text-lg">🌐</span>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-1">Webmail hozzáférés</h3>
<h3 className="font-semibold text-gray-900 mb-1">{pageContent.info.webmail.title}</h3>
<a
href={siteConfig.hero.cta.primary.href}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:text-blue-700"
>
Webmail belépés
{pageContent.info.webmail.linkText}
</a>
<p className="text-sm text-gray-600 mt-1">
Ügyfeleink számára
{pageContent.info.webmail.subtitle}
</p>
</div>
</div>
@@ -300,30 +303,16 @@ export default function ContactPage() {
{/* FAQ */}
<div className="bg-gray-50 rounded-xl p-8">
<h2 className="text-xl font-bold text-gray-900 mb-6">
Gyakori kérdések
{pageContent.faq.title}
</h2>
<div className="space-y-4">
<div>
<h3 className="font-semibold text-gray-900 mb-2">Milyen gyorsan válaszolnak?</h3>
<p className="text-gray-600 text-sm">
Email üzenetekre 24 órán belül, sürgős esetekben telefonon is elérhetők vagyunk.
</p>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-2">Van ingyenes konzultáció?</h3>
<p className="text-gray-600 text-sm">
Igen! Az első konzultáció mindig ingyenes, hogy megismerjük az Ön igényeit.
</p>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-2">Milyen fizetési módokat fogadnak el?</h3>
<p className="text-gray-600 text-sm">
Banki átutalás, PayPal és kártyás fizetés is lehetséges.
</p>
</div>
{pageContent.faq.items.map((item, index) => (
<div key={index}>
<h3 className="font-semibold text-gray-900 mb-2">{item.question}</h3>
<p className="text-gray-600 text-sm">{item.answer}</p>
</div>
))}
</div>
</div>
</div>