First commit

This commit is contained in:
2025-05-16 14:02:21 +02:00
parent 64fbc970ff
commit c741dc73bb
36 changed files with 8249 additions and 0 deletions
+67
View File
@@ -0,0 +1,67 @@
import { Link } from 'react-router-dom';
export interface BlogPostProps {
id: string;
slug: string;
title: string;
excerpt: string;
image: string;
category: string;
date: string;
author: string;
commentCount: number;
readTime: string;
featured?: boolean;
tags: string[];
content: string;
}
interface BlogCardProps {
post: BlogPostProps;
}
export const BlogCard: React.FC<BlogCardProps> = ({ post }) => {
return (
<div className={`card ${post.featured ? 'featured-card' : ''}`}>
<div className="position-relative">
<img src={post.image} className={`card-img-top ${post.featured ? 'featured-img' : ''}`} alt={post.title} />
<div className="category-badge">{post.category}</div>
{post.featured && (
<div className="featured-badge">
<i className="fas fa-star"></i>
<span>Featured</span>
</div>
)}
</div>
<div className="card-body">
<h2 className="card-title">
<Link to={`/blog/${post.slug}`}>{post.title}</Link>
</h2>
<div className="d-flex meta-items mb-3">
<div className="meta-item">
<i className="fas fa-calendar-alt meta-icon"></i>
<span>{post.date}</span>
</div>
<div className="meta-item">
<i className="fas fa-user meta-icon"></i>
<span>{post.author}</span>
</div>
<div className="meta-item">
<i className="fas fa-comments meta-icon"></i>
<span>{post.commentCount} Comments</span>
</div>
</div>
<p className="card-text">
{post.excerpt}
</p>
<Link to={`/blog/${post.slug}`} className="read-more">Continue Reading</Link>
<div className="mt-3">
{post.tags.map((tag, index) => (
<span key={index} className="post-tag">{tag}</span>
))}
</div>
</div>
</div>
);
}
+199
View File
@@ -0,0 +1,199 @@
import { useState, type FormEvent } from 'react';
export const ContactForm = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
subject: '',
projectType: '',
message: '',
budget: ''
});
const [isSubmitting, setIsSubmitting] = useState(false);
const [showSuccess, setShowSuccess] = useState(false);
const [showError, setShowError] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
// Simulate form submission
setTimeout(() => {
setIsSubmitting(false);
setShowSuccess(true);
setFormData({
name: '',
email: '',
subject: '',
projectType: '',
message: '',
budget: ''
});
// Hide success message after 5 seconds
setTimeout(() => {
setShowSuccess(false);
}, 5000);
}, 1500);
};
return (
<div className="card h-100">
<div className="card-header bg-transparent">
<h2 className="mb-0 py-2">Send a Message to the Forge</h2>
</div>
<div className="card-body p-4">
{/* Success message */}
{showSuccess && (
<div className="alert alert-success" role="alert">
<i className="fas fa-check-circle me-2"></i> Your message has been successfully sent. I'll get back to you soon!
</div>
)}
{/* Error message */}
{showError && (
<div className="alert alert-danger" role="alert">
<i className="fas fa-exclamation-circle me-2"></i> There was an error sending your message. Please try again later.
</div>
)}
{/* Contact Form */}
<form id="contact-form" className="needs-validation" noValidate onSubmit={handleSubmit}>
<div className="row mb-3">
<div className="col-md-6 mb-3 mb-md-0">
<label htmlFor="name" className="form-label">Your Name</label>
<input
type="text"
className="form-control"
id="name"
name="name"
placeholder="Enter your name"
required
value={formData.name}
onChange={handleChange}
/>
<div className="invalid-feedback">
Please provide your name.
</div>
</div>
<div className="col-md-6">
<label htmlFor="email" className="form-label">Your Email</label>
<input
type="email"
className="form-control"
id="email"
name="email"
placeholder="Enter your email"
required
value={formData.email}
onChange={handleChange}
/>
<div className="invalid-feedback">
Please provide a valid email address.
</div>
</div>
</div>
<div className="mb-3">
<label htmlFor="subject" className="form-label">Subject</label>
<input
type="text"
className="form-control"
id="subject"
name="subject"
placeholder="What's this regarding?"
required
value={formData.subject}
onChange={handleChange}
/>
<div className="invalid-feedback">
Please provide a subject for your message.
</div>
</div>
<div className="mb-3">
<label htmlFor="projectType" className="form-label">Project Type</label>
<select
className="form-select"
id="projectType"
name="projectType"
required
value={formData.projectType}
onChange={handleChange}
>
<option value="" selected disabled>Select a project type</option>
<option value="embedded">Embedded Systems</option>
<option value="web">Web Development</option>
<option value="ml">Machine Learning</option>
<option value="iot">IoT Solution</option>
<option value="consulting">Technical Consulting</option>
<option value="other">Other</option>
</select>
<div className="invalid-feedback">
Please select a project type.
</div>
</div>
<div className="mb-3">
<label htmlFor="message" className="form-label">Your Message</label>
<textarea
className="form-control"
id="message"
name="message"
rows={5}
placeholder="Tell me about your project, requirements, or questions..."
required
value={formData.message}
onChange={handleChange}
></textarea>
<div className="invalid-feedback">
Please provide a message.
</div>
</div>
<div className="mb-4">
<label htmlFor="budget" className="form-label">Budget Range (Optional)</label>
<select
className="form-select"
id="budget"
name="budget"
value={formData.budget}
onChange={handleChange}
>
<option value="" selected disabled>Select your budget range</option>
<option value="small">$1,000 - $5,000</option>
<option value="medium">$5,000 - $15,000</option>
<option value="large">$15,000 - $30,000</option>
<option value="enterprise">$30,000+</option>
<option value="undecided">Not sure yet</option>
</select>
</div>
<div className="text-center">
<button
type="submit"
className="btn btn-primary position-relative"
id="submit-button"
disabled={isSubmitting}
>
{isSubmitting ? (
<>
<span className="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
Sending...
</>
) : (
<>
<i className="fas fa-paper-plane me-2"></i> Send Message
</>
)}
</button>
</div>
</form>
</div>
</div>
);
}
+19
View File
@@ -0,0 +1,19 @@
export const Footer = () => {
const currentYear = new Date().getFullYear()
return (
<footer className="footer">
<div className="container">
<div className="social-links">
<a href="#" className="social-icon"><i className="fab fa-github"></i></a>
<a href="#" className="social-icon"><i className="fab fa-linkedin"></i></a>
<a href="#" className="social-icon"><i className="fab fa-twitter"></i></a>
<a href="#" className="social-icon"><i className="fab fa-discord"></i></a>
<a href="#" className="social-icon"><i className="fas fa-envelope"></i></a>
<a href="#" className="social-icon"><i className="fab fa-hackerrank"></i></a>
</div>
<p className="copyright">&copy; {currentYear} SecCodeSmith. All rights forged in digital fire.</p>
</div>
</footer>
)
}
+91
View File
@@ -0,0 +1,91 @@
import { useState, useEffect } from 'react'
import { NavLink, useLocation } from 'react-router-dom'
export const Header = () => {
const location = useLocation()
const [isNavCollapsed, setIsNavCollapsed] = useState(true)
// Close the mobile menu when changing routes
useEffect(() => {
setIsNavCollapsed(true)
}, [location])
return (
<nav className="navbar navbar-expand-lg fixed-top">
<div className="container">
<NavLink className="navbar-brand" to="/">
<div className="logo-icon">
<i className="fas fa-hammer"></i>
<i
className="fas fa-dragon"
style={{
fontSize: '1.2rem',
position: 'absolute',
top: 0,
right: '-12px',
color: 'var(--accent-dragon)'
}}
></i>
</div>
<div className="logo-text">SecCodeSmith</div>
</NavLink>
<button
className="navbar-toggler"
type="button"
onClick={() => setIsNavCollapsed(!isNavCollapsed)}
aria-controls="navbarNav"
aria-expanded={!isNavCollapsed}
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className={`${isNavCollapsed ? 'collapse' : ''} navbar-collapse justify-content-end`} id="navbarNav">
<ul className="navbar-nav">
<li className="nav-item">
<NavLink
className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`}
to="/"
>
Home
</NavLink>
</li>
<li className="nav-item">
<NavLink
className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`}
to="/blog"
>
Blog
</NavLink>
</li>
<li className="nav-item">
<NavLink
className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`}
to="/about"
>
About
</NavLink>
</li>
<li className="nav-item">
<NavLink
className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`}
to="/projects"
>
Projects
</NavLink>
</li>
<li className="nav-item">
<NavLink
className={({ isActive }) => `nav-link ${isActive ? 'active' : ''}`}
to="/contact"
>
Contact
</NavLink>
</li>
</ul>
</div>
</div>
</nav>
)
}
+15
View File
@@ -0,0 +1,15 @@
import { Outlet } from 'react-router-dom'
import { Header } from './Header'
import { Footer } from './Footer'
export const Layout = () => {
return (
<>
<Header />
<main>
<Outlet />
</main>
<Footer />
</>
)
}
+23
View File
@@ -0,0 +1,23 @@
interface PageHeaderProps {
title: string;
subtitle?: string;
}
export const PageHeader: React.FC<PageHeaderProps> = ({ title, subtitle }) => {
return (
<section className="page-header text-center">
<div className="container position-relative">
<h1 className="page-title">{title}</h1>
{subtitle && <p className="page-subtitle mt-4">{subtitle}</p>}
{/* Binary background effect */}
<div className="binary-bg">
<div className="binary-line" style={{ top: '20%', left: '10%' }}>01001100 01101111 01110010 01100101 01101101</div>
<div className="binary-line" style={{ bottom: '30%', right: '15%' }}>01001001 01110000 01110011 01110101 01101101</div>
<div className="binary-line" style={{ top: '50%', left: '80%' }}>01000100 01101111 01101100 01101111 01110010</div>
<div className="binary-line" style={{ bottom: '10%', left: '40%' }}>01010011 01101001 01110100 00100000 01000001 01101101 01100101 01110100</div>
</div>
</div>
</section>
)
}
+90
View File
@@ -0,0 +1,90 @@
import { useState } from 'react'
export interface ProjectTech {
name: string;
icon: string;
}
export interface ProjectProps {
id: string;
title: string;
description: string;
image: string;
category: string[];
featured?: boolean;
technologies: ProjectTech[];
links: {
github?: string;
demo?: string;
};
}
interface ProjectCardProps {
project: ProjectProps;
onOpenDetails: (id: string) => void;
}
export const ProjectCard: React.FC<ProjectCardProps> = ({ project, onOpenDetails }) => {
const [, setHovered] = useState(false);
return (
<div
className={`card h-100 ${project.featured ? 'featured-card' : ''}`}
data-category={project.category.join(',')}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
<div className="position-relative">
<img src={project.image} className="card-img-top" alt={project.title} />
<div className="category-badge">{project.category[0]}</div>
{project.featured && (
<div className="featured-badge">
<i className="fas fa-star"></i>
<span>Featured</span>
</div>
)}
</div>
<div className="card-body d-flex flex-column">
<h3 className="card-title">{project.title}</h3>
<p className="card-text">
{project.description}
</p>
<div>
<h4 className="tech-title">// TECHNOLOGIES_USED</h4>
<div className="tech-stack">
{project.technologies.map((tech, index) => (
<span className="tech-item" key={index}>
<i className={tech.icon}></i>
<span>{tech.name}</span>
</span>
))}
</div>
</div>
<div className="mt-auto d-flex gap-2 flex-wrap project-links">
<button
className="btn btn-outline-secondary"
onClick={() => onOpenDetails(project.id)}
>
<i className="fas fa-info-circle me-2"></i>
Project Details
</button>
{project.links.github && (
<a href={project.links.github} className="btn btn-outline-secondary">
<i className="fab fa-github me-2"></i>
View Code
</a>
)}
{project.links.demo && (
<a href={project.links.demo} className="btn btn-outline-secondary">
<i className="fas fa-external-link-alt me-2"></i>
Live Demo
</a>
)}
</div>
</div>
</div>
)
}
+56
View File
@@ -0,0 +1,56 @@
import type { ProjectProps } from './ProjectCard';
interface ProjectModalProps {
project: ProjectProps | null;
onClose: () => void;
}
export const ProjectModal: React.FC<ProjectModalProps> = ({ project, onClose }) => {
if (!project) return null;
return (
<div className="modal fade show" style={{ display: 'block' }} tabIndex={-1}>
<div className="modal-dialog modal-xl modal-dialog-scrollable">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">{project.title}</h5>
<button type="button" className="btn-close" onClick={onClose}></button>
</div>
<div className="modal-body">
<div className="mb-4">
<img src={project.image} className="img-fluid rounded mb-3" alt={project.title} />
</div>
<p>{project.description}</p>
<h4 className="mt-4 mb-3">Technologies Used</h4>
<div className="mb-4">
{project.technologies.map((tech, index) => (
<span className="tech-chip" key={index}>
<i className={`${tech.icon} tech-chip-icon`}></i>
<span className="tech-chip-name">{tech.name}</span>
</span>
))}
</div>
</div>
<div className="modal-footer">
{project.links.github && (
<a href={project.links.github} className="btn btn-outline-secondary">
<i className="fab fa-github me-2"></i>Source Code
</a>
)}
{project.links.demo && (
<a href={project.links.demo} className="btn btn-outline-secondary">
<i className="fas fa-external-link-alt me-2"></i>Live Demo
</a>
)}
<button type="button" className="btn btn-secondary" onClick={onClose}>Close</button>
</div>
</div>
</div>
<div className="modal-backdrop fade show"></div>
</div>
);
}
+773
View File
@@ -0,0 +1,773 @@
/* About Page Styles */
.profile-image {
width: 100%;
aspect-ratio: 1/1;
border-radius: 8px;
overflow: hidden;
border: 3px solid rgba(255, 100, 0, 0.3);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
position: relative;
}
.profile-image::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, rgba(255, 100, 0, 0.2), transparent);
z-index: 1;
}
.profile-image img {
width: 100%;
height: 100%;
object-fit: cover;
filter: contrast(1.1) brightness(0.9);
}
.intro-text {
font-size: 1.1rem;
line-height: 1.8;
color: var(--text-ash);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.intro-text p {
margin-bottom: 1.25rem;
}
.intro-text strong {
color: var(--text-light);
}
.intro-text .accent {
color: var(--accent-fire);
}
.connect-link {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 20px;
background-color: rgba(255, 255, 255, 0.05);
border-radius: 4px;
text-decoration: none;
color: var(--text-light);
transition: all 0.3s ease;
border: 1px solid var(--card-border);
margin-right: 0.5rem;
margin-bottom: 0.5rem;
}
.connect-link:hover {
background-color: rgba(255, 100, 0, 0.1);
transform: translateY(-3px);
border-color: var(--accent-fire);
color: var(--text-light);
}
.connect-icon {
color: var(--accent-fire);
}
/* Value cards */
.value-card {
background-color: var(--card-bg);
border-radius: 8px;
padding: 1.875rem;
border: 1px solid var(--card-border);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
text-align: center;
height: 100%;
}
.value-card:hover {
transform: translateY(-5px);
border-color: rgba(255, 100, 0, 0.3);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
}
.value-icon {
font-size: 2.5rem;
color: var(--accent-fire);
margin-bottom: 1.25rem;
}
.value-title {
font-size: 1.3rem;
margin-bottom: 1rem;
position: relative;
display: inline-block;
color: var(--text-light);
}
.value-title::after {
content: "";
position: absolute;
width: 40px;
height: 2px;
background: var(--accent-fire);
bottom: -5px;
left: 50%;
transform: translateX(-50%);
}
.value-text {
color: var(--text-ash);
line-height: 1.6;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
/* Skills card */
.skill-card {
background-color: var(--card-bg);
border-radius: 8px;
padding: 1.875rem;
border: 1px solid var(--card-border);
transition: all 0.3s ease;
position: relative;
height: 100%;
}
.skill-card:hover {
transform: translateY(-10px);
border-color: rgba(255, 100, 0, 0.3);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
}
.skill-card::before {
content: "";
position: absolute;
width: 100%;
height: 5px;
top: 0;
left: 0;
background: linear-gradient(to right, var(--accent-dragon), var(--accent-fire));
border-radius: 8px 8px 0 0;
}
.skill-header {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 1.25rem;
padding-bottom: 0.625rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.skill-icon {
font-size: 2rem;
color: var(--accent-fire);
}
.skill-title {
font-size: 1.3rem;
margin-bottom: 0;
color: var(--text-light);
}
.skill-check {
color: var(--accent-fire);
margin-right: 0.625rem;
}
/* Timeline */
.timeline {
position: relative;
padding: 0;
margin-top: 3rem;
list-style: none;
}
.timeline:before {
content: "";
position: absolute;
width: 3px;
height: 100%;
background: linear-gradient(to bottom, var(--accent-fire), var(--accent-dragon), rgba(255, 100, 0, 0.2));
left: 50%;
transform: translateX(-50%);
z-index: 1;
}
.timeline-item {
position: relative;
margin-bottom: 3rem;
width: 100%;
}
.timeline-item:nth-child(odd) .timeline-content {
margin-left: auto;
padding-left: 3rem;
border-radius: 8px;
}
.timeline-item:nth-child(even) .timeline-content {
margin-right: auto;
padding-right: 3rem;
border-radius: 8px;
}
.timeline-dot {
width: 16px;
height: 16px;
background-color: var(--accent-fire);
border-radius: 50%;
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
box-shadow: var(--glow-effect);
z-index: 2;
}
.timeline-date {
display: inline-block;
font-size: 0.9rem;
background-color: rgba(255, 100, 0, 0.1);
color: var(--accent-fire);
padding: 5px 10px;
border-radius: 4px;
margin-bottom: 1rem;
font-weight: 600;
letter-spacing: 1px;
}
.timeline-title {
font-size: 1.3rem;
margin-bottom: 0.625rem;
color: var(--text-light);
}
.timeline-text {
color: var(--text-ash);
line-height: 1.6;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.timeline-content {
background-color: var(--card-bg);
border-radius: 8px;
padding: 1.5rem;
border: 1px solid var(--card-border);
position: relative;
transition: all 0.3s ease;
width: 45%;
}
.timeline-content:hover {
transform: translateY(-5px);
border-color: rgba(255, 100, 0, 0.3);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
}
/* Testimonials */
.testimonial {
background-color: var(--card-bg);
border-radius: 8px;
padding: 1.875rem;
margin-bottom: 1.875rem;
border: 1px solid var(--card-border);
transition: all 0.3s ease;
position: relative;
}
.testimonial:hover {
transform: translateY(-5px);
border-color: rgba(255, 100, 0, 0.3);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
}
.testimonial-content {
padding-left: 1.25rem;
border-left: 3px solid var(--accent-fire);
font-style: italic;
color: var(--text-ash);
margin-bottom: 1.25rem;
line-height: 1.7;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.author-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
overflow: hidden;
}
.author-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.author-name {
font-weight: 600;
font-size: 1.1rem;
color: var(--text-light);
margin-bottom: 0;
}
.author-title {
color: var(--text-ash);
font-size: 0.9rem;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
/* Blog post specific styles */
.post-container {
max-width: 1200px;
margin: 0 auto;
padding: 120px 20px 60px;
display: grid;
grid-template-columns: 1fr 300px;
gap: 40px;
}
.post-main {
background-color: var(--card-bg);
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--card-border);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.post-header {
position: relative;
}
.post-featured-image {
height: 400px;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
position: relative;
}
.post-featured-image::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100px;
background: linear-gradient(to top, var(--card-bg), transparent);
}
.post-info {
padding: 30px 40px;
}
.post-content {
padding: 0 40px 40px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.8;
color: #e0e0e0;
}
.share-section {
margin-top: 40px;
padding-top: 20px;
border-top: 1px solid var(--card-border);
}
.share-title {
font-size: 1.2rem;
margin-bottom: 15px;
}
.share-buttons {
display: flex;
gap: 15px;
}
.share-button {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.05);
display: flex;
align-items: center;
justify-content: center;
color: var(--text-ash);
transition: all 0.3s ease;
}
.share-button:hover {
background-color: var(--accent-fire);
color: var(--text-light);
transform: translateY(-3px);
}
.author-section {
margin-top: 40px;
padding: 30px;
background-color: rgba(255, 255, 255, 0.02);
border-radius: 8px;
display: flex;
gap: 20px;
align-items: center;
}
.toc-list {
list-style: none;
}
.toc-item {
margin-bottom: 12px;
padding-left: 15px;
position: relative;
}
.toc-item::before {
content: "";
position: absolute;
left: 0;
top: 10px;
width: 5px;
height: 5px;
border-radius: 50%;
background-color: var(--accent-fire);
}
.toc-link {
color: var(--text-ash);
text-decoration: none;
transition: all 0.3s ease;
font-size: 0.9rem;
line-height: 1.5;
display: block;
}
.toc-link:hover {
color: var(--accent-fire);
transform: translateX(5px);
}
.toc-subitem {
margin-top: 8px;
padding-left: 15px;
}
.related-posts-list {
list-style: none;
}
.related-post-item {
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.related-post-item:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.related-post-link {
display: flex;
align-items: center;
gap: 10px;
text-decoration: none;
color: var(--text-ash);
transition: color 0.3s ease;
}
.related-post-link:hover {
color: var(--accent-fire);
}
.related-post-thumb {
width: 60px;
height: 60px;
border-radius: 4px;
background-size: cover;
background-position: center;
flex-shrink: 0;
}
.related-post-info {
flex-grow: 1;
}
.related-post-title {
font-size: 0.9rem;
line-height: 1.4;
margin-bottom: 5px;
}
.related-post-date {
font-size: 0.8rem;
color: rgba(255, 255, 255, 0.5);
}
/* Social grid for contact page */
.social-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 15px;
margin-top: 1.5rem;
}
.social-item {
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;
}
.social-item:hover {
background-color: rgba(255, 100, 0, 0.1);
transform: translateY(-5px);
}
.social-icon-lg {
font-size: 1.8rem;
color: var(--accent-fire);
}
.social-name {
color: var(--text-ash);
font-size: 0.9rem;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
/* 404 page styles */
.error-container {
position: relative;
z-index: 2;
padding-top: 150px;
padding-bottom: 100px;
}
.error-code {
font-size: 8rem;
font-weight: 700;
background: linear-gradient(to right, var(--accent-fire), var(--text-light));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
margin-bottom: 1rem;
text-shadow: var(--glow-effect);
position: relative;
}
.error-title {
font-size: 2rem;
margin-bottom: 1.5rem;
color: var(--text-light);
}
.error-text {
font-size: 1.1rem;
color: var(--text-ash);
margin-bottom: 2rem;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.broken-sword {
font-size: 5rem;
color: var(--accent-fire);
margin-bottom: 2rem;
position: relative;
z-index: 1;
}
.broken-sword::after {
content: "";
position: absolute;
width: 40px;
height: 4px;
background: var(--accent-fire);
transform: rotate(-45deg);
top: 60%;
left: 45%;
box-shadow: var(--glow-effect);
}
.home-button {
background: linear-gradient(45deg, var(--accent-dragon), var(--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;
color: var(--text-light);
text-decoration: none;
border-radius: 4px;
display: inline-flex;
align-items: center;
gap: 10px;
}
.home-button:hover {
transform: translateY(-3px);
box-shadow: 0 7px 25px rgba(139, 0, 0, 0.5);
color: var(--text-light);
}
.home-button::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;
}
.home-button:hover::before {
left: 100%;
}
.error-code-container {
position: relative;
display: inline-block;
}
.error-code-container::before,
.error-code-container::after {
content: "<";
position: absolute;
color: var(--accent-fire);
opacity: 0.6;
font-size: 6rem;
font-family: 'Fira Code', monospace;
}
.error-code-container::before {
left: -4rem;
}
.error-code-container::after {
content: "/>";
right: -6rem;
}
/* Media Queries */
@media (max-width: 992px) {
.timeline:before {
left: 2rem;
}
.timeline-item:nth-child(odd) .timeline-content,
.timeline-item:nth-child(even) .timeline-content {
width: calc(100% - 3rem);
margin-left: 3rem;
padding-left: 1.5rem;
padding-right: 1.5rem;
}
.timeline-dot {
left: 2rem;
}
.post-container {
grid-template-columns: 1fr;
}
.post-sidebar {
position: static;
order: -1;
}
.post-featured-image {
height: 300px;
}
.post-title {
font-size: 2rem;
}
.post-info, .post-content {
padding: 20px;
}
}
@media (max-width: 768px) {
.intro-text {
margin-top: 2rem;
}
.testimonial-author {
flex-direction: column;
align-items: center;
text-align: center;
}
.author-info {
margin-top: 1rem;
text-align: center;
}
.error-code {
font-size: 6rem;
}
.error-title {
font-size: 1.8rem;
}
.broken-sword {
font-size: 4rem;
}
.error-code-container::before,
.error-code-container::after {
font-size: 4rem;
}
.error-code-container::before {
left: -3rem;
}
.error-code-container::after {
right: -4.5rem;
}
}
@media (max-width: 576px) {
.error-code {
font-size: 4rem;
}
.error-title {
font-size: 1.5rem;
}
.broken-sword {
font-size: 3rem;
}
.error-code-container::before,
.error-code-container::after {
font-size: 3rem;
}
.error-code-container::before {
left: -2rem;
}
.error-code-container::after {
right: -3rem;
}
}