first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 22:12:36 +03:00
commit e881f38e4e
278 changed files with 24095 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
interface AboutSectionProps {
isAuthenticated: boolean;
}
export default function AboutSection({ isAuthenticated }: AboutSectionProps) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
// Initialize WOW.js after mount
if (typeof window !== "undefined" && window.WOW) {
new window.WOW().init();
}
}, []);
return (
<section className="about-section" suppressHydrationWarning>
<div className="right-shape">
<img src="/assets/img/core-img/shape.png" alt="" />
</div>
<div className="divider"></div>
<div className="container">
<div className="row g-5 align-items-center">
<div className="col-12 col-lg-6">
<div className="about-content ps-md-4">
<div className="section-heading">
<span className="sub-title">About Us</span>
<h2 className="mb-4">We Are About to Witness Something Great</h2>
<p className="mb-5">
Empower your business with our cutting-edge IT services and unmatched support, tailored for transformative growth and harness innovation.
</p>
<ul className="about-list ps-0 d-flex flex-column gap-3 list-unstyled mb-5">
<li className="d-flex align-items-center gap-2">
<div className="icon"><i className="ti ti-arrow-right"></i></div>
<h5 className="mb-0">Complete authentication system with email verification</h5>
</li>
<li className="d-flex align-items-center gap-2">
<div className="icon"><i className="ti ti-arrow-right"></i></div>
<h5 className="mb-0">Social login with Google and GitHub integration</h5>
</li>
<li className="d-flex align-items-center gap-2">
<div className="icon"><i className="ti ti-arrow-right"></i></div>
<h5 className="mb-0">Secure JWT token management and refresh</h5>
</li>
</ul>
<Link className="btn btn-primary" href={isAuthenticated ? "/dashboard" : "/auth/register"}>
{isAuthenticated ? "View Dashboard" : "Get Started"} <i className="ti ti-arrow-up-right"></i>
</Link>
</div>
</div>
</div>
<div className="col-12 col-lg-6">
<div
className={mounted ? "about-video-content wow fadeInUp" : "about-video-content"}
data-wow-duration="1000ms"
data-wow-delay="500ms"
suppressHydrationWarning
>
<img src="/assets/img/bg-img/25.jpg" alt="" />
<div className="play-video-btn video-btn" data-video="https://youtu.be/4GUFkrHvZdE">
<div className="icon"><i className="ti ti-player-play-filled"></i></div>
</div>
</div>
<div
className={mounted ? "about-images d-flex px-5 mt-5 wow fadeInUp" : "about-images d-flex px-5 mt-5"}
data-wow-duration="1000ms"
data-wow-delay="800ms"
suppressHydrationWarning
>
<div>
<img className="w-100" src="/assets/img/bg-img/26.jpg" alt="" />
</div>
<div>
<svg className="rotatingImage" xmlns="http://www.w3.org/2000/svg" width={70} height={70} viewBox="0 0 70 70" fill="none">
<path d="M35 0L46.1369 23.8631L70 35L46.1369 46.1369L35 70L23.8631 46.1369L0 35L23.8631 23.8631L35 0Z" fill="#222222" />
</svg>
</div>
</div>
</div>
</div>
</div>
<div className="divider"></div>
</section>
);
}
// Extend Window interface
declare global {
interface Window {
WOW: any;
}
}

429
components/BlogSection.tsx Normal file
View File

@@ -0,0 +1,429 @@
"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
import { PostType, Categorie, PaginatedResponse } from "@/Type/post";
import { getBlogPosts, getBlogCategories, extractPageNumber } from "@/lib/blogApi";
export default function BlogSection() {
const [mounted, setMounted] = useState(false);
const [posts, setPosts] = useState<PostType[]>([]);
const [recentPosts, setRecentPosts] = useState<PostType[]>([]);
const [categories, setCategories] = useState<Categorie[]>([]);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [nextPage, setNextPage] = useState<string | null>(null);
const [prevPage, setPrevPage] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
setMounted(true);
// Initialize WOW.js after mount
if (typeof window !== "undefined" && window.WOW) {
new window.WOW().init();
}
}, []);
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
setError(null);
try {
// Fetch posts, recent posts (from different page) and categories in parallel
const [postsData, recentPostsData, categoriesData] = await Promise.all([
getBlogPosts(currentPage),
getBlogPosts(currentPage === 1 ? 2 : 1), // Get from different page
getBlogCategories()
]);
setPosts(postsData.results);
setNextPage(postsData.next);
setPrevPage(postsData.previous);
// Calculate total pages (assuming 10 items per page, adjust if needed)
const itemsPerPage = postsData.results.length || 10;
setTotalPages(Math.ceil(postsData.count / itemsPerPage));
// Set recent posts (exclude current page posts)
const currentPostSlugs = new Set(postsData.results.map(p => p.slug));
const filteredRecentPosts = recentPostsData.results
.filter(post => !currentPostSlugs.has(post.slug))
.slice(0, 3);
// If we don't have enough recent posts, try to get more from page 3
if (filteredRecentPosts.length < 3 && currentPage !== 3) {
try {
const additionalPostsData = await getBlogPosts(3);
const additionalFiltered = additionalPostsData.results
.filter(post => !currentPostSlugs.has(post.slug))
.slice(0, 3 - filteredRecentPosts.length);
setRecentPosts([...filteredRecentPosts, ...additionalFiltered]);
} catch {
setRecentPosts(filteredRecentPosts);
}
} else {
setRecentPosts(filteredRecentPosts);
}
setCategories(categoriesData);
} catch (err) {
console.error("Error fetching blog data:", err);
setError("Blog yazıları yüklenirken bir hata oluştu.");
} finally {
setIsLoading(false);
}
};
fetchData();
}, [currentPage]);
const handlePageChange = (page: number) => {
if (page >= 1 && page <= totalPages) {
setCurrentPage(page);
window.scrollTo({ top: 0, behavior: "smooth" });
}
};
const formatDate = (dateString: string) => {
const date = new Date(dateString);
return date.toLocaleDateString("tr-TR", {
year: "numeric",
month: "long",
day: "numeric"
});
};
const getPageNumbers = () => {
const pages: (number | string)[] = [];
const maxVisible = 5;
if (totalPages <= maxVisible) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
if (currentPage <= 3) {
for (let i = 1; i <= 4; i++) {
pages.push(i);
}
pages.push("...");
pages.push(totalPages);
} else if (currentPage >= totalPages - 2) {
pages.push(1);
pages.push("...");
for (let i = totalPages - 3; i <= totalPages; i++) {
pages.push(i);
}
} else {
pages.push(1);
pages.push("...");
for (let i = currentPage - 1; i <= currentPage + 1; i++) {
pages.push(i);
}
pages.push("...");
pages.push(totalPages);
}
}
return pages;
};
// Get unique tags from all posts
const allTags = Array.from(
new Set(
posts.flatMap(post => post.tags.map(tag => tag.tag))
)
);
// Get category count from API data
const getCategoryCount = (category: Categorie): number => {
if (category.posts && category.posts.length > 0) {
return category.posts.length;
}
return 0;
};
// Flatten categories to show both parent and child categories
const flattenCategories = (categories: Categorie[]): Categorie[] => {
const result: Categorie[] = [];
categories.forEach(category => {
if (category.is_active) {
// Add parent category
result.push(category);
// Add child categories if they exist
if (category.child && category.child.length > 0) {
category.child.forEach(child => {
if (child.is_active) {
result.push(child);
}
});
}
}
});
return result;
};
return (
<div className="blog-section" suppressHydrationWarning>
{/* Divider */}
<div className="divider"></div>
<div className="container">
<div className="row g-5 g-md-4 g-xl-5">
<div className="col-12 col-md-7 col-lg-8">
{/* Blog List Wrapper */}
<div className="blog-list-wrapper pe-lg-3">
{isLoading ? (
<div className="text-center py-5">
<p>Yükleniyor...</p>
</div>
) : error ? (
<div className="text-center py-5">
<p className="text-danger">{error}</p>
</div>
) : posts.length === 0 ? (
<div className="text-center py-5">
<p>Henüz blog yazısı bulunmamaktadır.</p>
</div>
) : (
<>
{posts.map((post, index) => (
<div
key={post.slug}
className={`blog-card-two ${mounted ? 'wow fadeInUp' : ''}`}
data-wow-duration="1000ms"
data-wow-delay={`${(index + 1) * 200}ms`}
suppressHydrationWarning
>
{/* Post Image */}
{post.image && (
<div className="post-img">
<img src={post.image} alt={post.title} />
</div>
)}
{/* Post Body */}
<div className="post-body">
<div className="blog-meta flex-wrap d-flex align-items-center gap-4 mb-3">
<a href="#">
<svg width="20" height="20">
<use xlinkHref="#icon-user-profile"></use>
</svg>
By Admin
</a>
<a href="#">
<svg width="18" height="18">
<use xlinkHref="#icon-message-box"></use>
</svg>
{formatDate(post.created_at)}
</a>
{post.categories.length > 0 && (
<a href="#">
<svg width="18" height="18">
<use xlinkHref="#icon-calendar"></use>
</svg>
{post.categories[0].title}
</a>
)}
</div>
<Link className="post-title" href={`/blog/${post.slug}`}>
{post.title}
</Link>
<p className="mt-3 mb-5">
{post.content.length > 200
? `${post.content.substring(0, 200)}...`
: post.content}
</p>
<Link className="btn btn-primary" href={`/blog/${post.slug}`}>
Read More <i className="ti ti-arrow-up-right"></i>
</Link>
</div>
</div>
))}
{/* Pagination */}
{totalPages > 1 && (
<ul className="softora-pagination list-unstyled justify-content-start">
{prevPage && (
<li>
<a
className="magnet-link"
href="#"
onClick={(e) => {
e.preventDefault();
handlePageChange(currentPage - 1);
}}
>
<i className="ti ti-chevron-left"></i>
</a>
</li>
)}
{getPageNumbers().map((page, index) => {
const isActive = typeof page === "number" && currentPage === page;
return (
<li key={index} className={isActive ? "active" : ""}>
{page === "..." ? (
<span className="magnet-link">{page}</span>
) : (
<a
className="magnet-link"
href="#"
onClick={(e) => {
e.preventDefault();
handlePageChange(page as number);
}}
>
{page}
</a>
)}
</li>
);
})}
{nextPage && (
<li>
<a
className="magnet-link"
href="#"
onClick={(e) => {
e.preventDefault();
handlePageChange(currentPage + 1);
}}
>
<i className="ti ti-chevron-right"></i>
</a>
</li>
)}
</ul>
)}
</>
)}
</div>
</div>
<div className="col-12 col-md-5 col-lg-4">
<div className="d-flex flex-column gap-5">
{/* Widget */}
<div className="blog-widget">
<div className="h4 fw-bold mb-4">Search Here</div>
{/* Form */}
<form action="#" method="get">
<input type="search" placeholder="Search here..." className="form-control" />
<button type="submit">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"
fill="none">
<g clipPath="url(#clip0_1_17841)">
<path
d="M2.5 8.33333C2.5 9.09938 2.65088 9.85792 2.94404 10.5657C3.23719 11.2734 3.66687 11.9164 4.20854 12.4581C4.75022 12.9998 5.39328 13.4295 6.10101 13.7226C6.80875 14.0158 7.56729 14.1667 8.33333 14.1667C9.09938 14.1667 9.85792 14.0158 10.5657 13.7226C11.2734 13.4295 11.9164 12.9998 12.4581 12.4581C12.9998 11.9164 13.4295 11.2734 13.7226 10.5657C14.0158 9.85792 14.1667 9.09938 14.1667 8.33333C14.1667 7.56729 14.0158 6.80875 13.7226 6.10101C13.4295 5.39328 12.9998 4.75022 12.4581 4.20854C11.9164 3.66687 11.2734 3.23719 10.5657 2.94404C9.85792 2.65088 9.09938 2.5 8.33333 2.5C7.56729 2.5 6.80875 2.65088 6.10101 2.94404C5.39328 3.23719 4.75022 3.66687 4.20854 4.20854C3.66687 4.75022 3.23719 5.39328 2.94404 6.10101C2.65088 6.80875 2.5 7.56729 2.5 8.33333Z"
stroke="white" strokeLinecap="round" strokeLinejoin="round" />
<path d="M17.5 17.5L12.5 12.5" stroke="white" strokeLinecap="round"
strokeLinejoin="round" />
</g>
<defs>
<clipPath id="clip0_1_17841">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
</button>
</form>
</div>
{/* Widget - Categories */}
<div className="blog-widget">
<div className="h4 fw-bold mb-4">Categories</div>
<ul className="blog-list style-two">
{categories.map((category) => {
if (!category.is_active) return null;
return (
<li key={category.slug}>
<Link href={`/blog/category/${category.slug}`}>
{category.title}
<span>{getCategoryCount(category)}</span>
</Link>
{/* Child Categories */}
{category.child && category.child.length > 0 && (
<ul className="blog-list style-two ms-3 mt-2 mb-0" style={{ listStyle: 'none', paddingLeft: '1.5rem', borderLeft: '2px solid rgba(31, 30, 33, 0.2)' }}>
{category.child
.filter(child => child.is_active)
.map((child) => (
<li key={child.slug} style={{ marginTop: '0.5rem' }}>
<Link href={`/blog/category/${child.slug}`} style={{ fontSize: '0.95em', color: '#666' }}>
{child.title}
<span>{getCategoryCount(child)}</span>
</Link>
</li>
))}
</ul>
)}
</li>
);
})}
</ul>
</div>
{/* Widget - Recent Posts */}
<div className="blog-widget">
<div className="h4 fw-bold mb-4">Recent Posts</div>
<div className="d-flex flex-column gap-4">
{recentPosts.length > 0 ? (
recentPosts.map((post) => (
<div key={post.slug} className="widget-blog-post">
{post.thumb && (
<div className="blog-thumbnail">
<img src={post.thumb} alt={post.title} />
</div>
)}
<div className="blog-content">
<p className="mb-1 text-primary">{formatDate(post.created_at)}</p>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</div>
</div>
))
) : (
<p className="text-muted">Henüz yazı bulunmamaktadır.</p>
)}
</div>
</div>
{/* Widget - Tags */}
{allTags.length > 0 && (
<div className="blog-widget">
<div className="h4 fw-bold mb-4">Tags</div>
<ul className="tag-list list-unstyled">
{allTags.slice(0, 8).map((tag, index) => (
<li key={index}>
<a href={`/blog/tag/${tag.toLowerCase().replace(/\s+/g, '-')}`}>
{tag}
</a>
</li>
))}
</ul>
</div>
)}
</div>
</div>
</div>
</div>
{/* Divider */}
<div className="divider"></div>
</div>
);
}
// Extend Window interface
declare global {
interface Window {
WOW: any;
}
}

72
components/CTABottom.tsx Normal file
View File

@@ -0,0 +1,72 @@
"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
interface CTABottomProps {
userEmail?: string | null;
isAuthenticated: boolean;
}
export default function CTABottom({ userEmail, isAuthenticated }: CTABottomProps) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
// Initialize WOW.js after mount
if (typeof window !== "undefined" && window.WOW) {
new window.WOW().init();
}
}, []);
return (
<div className="cta-wrapper bg-img" style={{backgroundImage: 'url("/assets/img/core-img/grid.jpg")'}} suppressHydrationWarning>
<div className="divider"></div>
<div className="container">
<div className="row g-4 g-xl-5 align-items-center">
<div className="col-12 col-lg-6 col-xl-7">
<h2
className={`mb-0 ${mounted ? 'wow fadeInUp' : ''}`}
data-wow-duration="1000ms"
data-wow-delay="400ms"
suppressHydrationWarning
>
{isAuthenticated ? `Welcome back, ${userEmail}!` : "Start Building Your Business Now"}
</h2>
</div>
<div className="col-12 col-lg-6 col-xl-5">
<p
className={mounted ? 'wow fadeInUp' : ''}
data-wow-duration="1000ms"
data-wow-delay="600ms"
suppressHydrationWarning
>
{isAuthenticated
? "Access your dashboard to manage your profile and explore all features."
: "Create your account today and experience the power of our authentication system."}
</p>
<Link
href={isAuthenticated ? "/dashboard" : "/auth/register"}
className={`btn btn-primary btn-hover-border ${mounted ? 'wow fadeInUp' : ''}`}
data-wow-duration="1000ms"
data-wow-delay="800ms"
suppressHydrationWarning
>
{isAuthenticated ? "Go to Dashboard" : "Get Started"} <i className="ti ti-arrow-up-right"></i>
</Link>
</div>
</div>
</div>
<div className="divider"></div>
</div>
);
}
// Extend Window interface
declare global {
interface Window {
WOW: any;
}
}

135
components/CTASection.tsx Normal file
View File

@@ -0,0 +1,135 @@
"use client";
import { useEffect, useState, useRef } from "react";
export default function CTASection() {
const [mounted, setMounted] = useState(false);
const ctaRef = useRef<HTMLDivElement>(null);
useEffect(() => {
setMounted(true);
// Initialize Jarallax manually after mount
const initJarallax = () => {
if (ctaRef.current && typeof window !== 'undefined' && (window as any).jarallax) {
(window as any).jarallax(ctaRef.current, {
speed: 0.6
});
}
};
// Delay to ensure jarallax library is loaded
setTimeout(initJarallax, 200);
return () => {
// Cleanup jarallax on unmount
if (ctaRef.current && typeof window !== 'undefined' && (window as any).jarallax) {
(window as any).jarallax(ctaRef.current, 'destroy');
}
};
}, []);
if (!mounted) {
// Server-side render: simple div without jarallax
return (
<div
className="cta-wrap"
style={{backgroundImage: 'url("/assets/img/bg-img/20.jpg")', backgroundSize: 'cover', backgroundPosition: 'center'}}
>
<div className="divider"></div>
<div className="container">
<div className="row justify-content-end">
<div className="col-12 col-sm-11 col-md-10 col-lg-7 col-xl-6 col-xxl-5">
<div className="cta-card">
<div className="total-clients-wrap">
<div className="total-number">
<h3>200+</h3>
<p className="mb-0">Satisfied Customers</p>
</div>
<div className="clients-images">
<img src="/assets/img/bg-img/21.png" alt="" />
<img src="/assets/img/bg-img/22.png" alt="" />
<img src="/assets/img/bg-img/23.png" alt="" />
<img src="/assets/img/bg-img/24.png" alt="" />
</div>
</div>
<div className="cta-stats">
<div>
<h2>100+</h2>
<p className="mb-0">Global Clients</p>
</div>
<div>
<h2>150+</h2>
<p className="mb-0">Team Members</p>
</div>
<div>
<h2>15+</h2>
<p className="mb-0">Business Experience</p>
</div>
<div>
<h2>300+</h2>
<p className="mb-0">Projects Complete</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="divider"></div>
</div>
);
}
// Client-side render: with jarallax
return (
<div
ref={ctaRef}
className="cta-wrap jarallax"
data-jarallax=""
data-speed="0.6"
style={{backgroundImage: 'url("/assets/img/bg-img/20.jpg")'}}
>
<div className="divider"></div>
<div className="container">
<div className="row justify-content-end">
<div className="col-12 col-sm-11 col-md-10 col-lg-7 col-xl-6 col-xxl-5">
<div className="cta-card">
<div className="total-clients-wrap">
<div className="total-number">
<h3>200+</h3>
<p className="mb-0">Satisfied Customers</p>
</div>
<div className="clients-images">
<img src="/assets/img/bg-img/21.png" alt="" />
<img src="/assets/img/bg-img/22.png" alt="" />
<img src="/assets/img/bg-img/23.png" alt="" />
<img src="/assets/img/bg-img/24.png" alt="" />
</div>
</div>
<div className="cta-stats">
<div>
<h2>100+</h2>
<p className="mb-0">Global Clients</p>
</div>
<div>
<h2>150+</h2>
<p className="mb-0">Team Members</p>
</div>
<div>
<h2>15+</h2>
<p className="mb-0">Business Experience</p>
</div>
<div>
<h2>300+</h2>
<p className="mb-0">Projects Complete</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="divider"></div>
</div>
);
}

View File

@@ -0,0 +1,49 @@
"use client";
import { useState, useEffect } from "react";
import Link from "next/link";
export default function CookieAlert() {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
// Check if cookie exists
const cookieExists = document.cookie
.split("; ")
.find((row) => row.startsWith("acceptCookies="));
if (!cookieExists) {
setIsVisible(true);
}
}, []);
const acceptCookies = () => {
// Set cookie for 365 days
const date = new Date();
date.setTime(date.getTime() + 365 * 24 * 60 * 60 * 1000);
document.cookie = `acceptCookies=true; expires=${date.toUTCString()}; path=/`;
setIsVisible(false);
};
if (!isVisible) return null;
return (
<div className="cookiealert shadow-lg show">
<p className="mb-4">
We use cookies for the best experience on our website.{" "}
<Link href="#" target="_blank">
Cookies Policy.
</Link>
</p>
<button
className="btn btn-primary btn-sm acceptcookies"
type="button"
aria-label="Close"
onClick={acceptCookies}
>
Accept
</button>
</div>
);
}

176
components/Header.tsx Normal file
View File

@@ -0,0 +1,176 @@
"use client";
import Link from "next/link";
import { useSession, signOut } from "next-auth/react";
import { useState, useEffect } from "react";
export default function Header() {
const { data: session } = useSession();
const [isSticky, setIsSticky] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
// Track open state for dropdowns by their ID or Label
const [openDropdowns, setOpenDropdowns] = useState<Record<string, boolean>>({});
useEffect(() => {
const handleScroll = () => {
if (window.scrollY > 10) {
setIsSticky(true);
} else {
setIsSticky(false);
}
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
const toggleMobileMenu = () => {
setIsMobileMenuOpen(!isMobileMenuOpen);
};
const toggleDropdown = (key: string, e?: React.MouseEvent) => {
if (e) {
e.preventDefault();
e.stopPropagation();
}
setOpenDropdowns((prev) => ({
...prev,
[key]: !prev[key],
}));
};
return (
<header
className={`header-area style-two ${isSticky ? "sticky-on" : ""} ${isMobileMenuOpen ? "mobile-menu-open" : ""}`}
>
<div className="header-top">
<div className="container h-100 d-flex align-items-center justify-content-between">
{/* Left Side */}
<div className="left-side d-flex align-items-center gap-4 gap-lg-5">
<div className="d-flex align-items-center gap-2 text-white">
<i className="ti ti-mail-filled"></i>
<span className="d-none d-lg-block">info@example.com</span>
</div>
<div className="d-flex align-items-center gap-2 text-white">
<i className="ti ti-map-pin-filled"></i>
<span className="d-none d-lg-block">629 Elgin St.Celina,2202</span>
</div>
<div className="d-flex align-items-center gap-2 text-white">
<i className="ti ti-phone"></i>
<span className="d-none d-lg-block">(888).123.456.7894</span>
</div>
</div>
{/* Right Side */}
<div className="right-side">
<div className="social-nav d-flex align-items-center gap-3">
<a href="#"><i className="ti ti-brand-facebook"></i></a>
<a href="#"><i className="ti ti-brand-x"></i></a>
<a href="#"><i className="ti ti-brand-linkedin"></i></a>
<a href="#"><i className="ti ti-brand-instagram"></i></a>
</div>
</div>
</div>
</div>
<nav className="navbar navbar-expand-lg">
<div className="container">
{/* Navbar Brand */}
<Link className="navbar-brand" href="/">
<img src="/assets/img/core-img/logo.png" alt="" />
</Link>
{/* Navbar Toggler */}
<button
className="navbar-toggler"
type="button"
onClick={toggleMobileMenu}
aria-label="Toggle navigation"
>
<i className="ti ti-category"></i>
</button>
{/* Navbar Nav */}
<div className={`collapse navbar-collapse justify-content-between ${isMobileMenuOpen ? "show" : ""}`} id="softoraNav">
<ul className="navbar-nav navbar-nav-scroll">
<li className="softora-dd">
<Link href="/">Home</Link>
</li>
{/* Features Dropdown Example based on Template */}
<li className="softora-dd">
<a href="#" onClick={(e) => toggleDropdown('features', e)}>
Features <i className="ti ti-caret-down-filled"></i>
</a>
{/* Mobile Toggler */}
<div className="dropdown-toggler d-lg-none" onClick={(e) => toggleDropdown('features', e)}>
<i className="ti ti-caret-down-filled"></i>
</div>
<ul
className={`softora-dd-menu ${openDropdowns['features'] ? 'menu-open' : ''}`}
>
<li><Link href="#services">Services</Link></li>
<li><Link href="/auth/register">Register</Link></li>
<li><Link href="/auth/login">Login</Link></li>
<li><Link href="/auth/forgot-password">Reset Password</Link></li>
</ul>
</li>
<li className="softora-dd">
<a href="#" onClick={(e) => toggleDropdown('utils', e)}>
Yardımcılar <i className="ti ti-caret-down-filled"></i>
</a>
{/* Mobile Toggler */}
<div className="dropdown-toggler d-lg-none" onClick={(e) => toggleDropdown('utils', e)}>
<i className="ti ti-caret-down-filled"></i>
</div>
<ul
className={`softora-dd-menu ${openDropdowns['utils'] ? 'menu-open' : ''}`}
>
<li><Link href="/assistants/converters/jsontotype">Json To Type</Link></li>
<li><Link href="/auth/login">Login</Link></li>
<li><Link href="/auth/forgot-password">Reset Password</Link></li>
</ul>
</li>
{session ? (
<>
<li className="softora-dd">
<Link href="/dashboard">Dashboard</Link>
</li>
<li className="softora-dd">
<Link href="/profile">Profile</Link>
</li>
</>
) : null}
</ul>
<div className="d-flex align-items-center mt-4 mt-lg-0">
{/* Search Button */}
<div className="header-search-btn" id="searchButton">
<button className="btn">
<i className="ti ti-search"></i>
</button>
</div>
{/* Button */}
{session ? (
<button
onClick={() => signOut({ callbackUrl: "/auth/login" })}
className="btn btn-primary"
>
Logout <i className="ti ti-logout"></i>
</button>
) : (
<Link href="/auth/register" className="btn btn-primary">
Get Started <i className="ti ti-arrow-up-right"></i>
</Link>
)}
</div>
</div>
</div>
</nav>
</header>
);
}

View File

@@ -0,0 +1,71 @@
"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
interface HeroSectionProps {
isAuthenticated: boolean;
}
export default function HeroSection({ isAuthenticated }: HeroSectionProps) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
// Initialize WOW.js after mount
if (typeof window !== "undefined" && window.WOW) {
new window.WOW().init();
}
}, []);
return (
<section className="hero-section" style={{backgroundImage: 'url("/assets/img/core-img/grid3.png")'}} suppressHydrationWarning>
<div className="divider"></div>
<div className="container">
<div className="hero-content">
<div className="row g-5">
<div className="col-12 col-md-6">
<h2
className={`mb-0 text-white ${mounted ? 'wow fadeInUp' : ''}`}
data-wow-duration="1000ms"
data-wow-delay="400ms"
suppressHydrationWarning
>
Best IT <span>Solution</span> Agency For Your Business
</h2>
</div>
<div className="col-12 col-md-6 col-xl-5 offset-xl-1 col-xxl-4 offset-xxl-1">
<p
className={`text-white ${mounted ? 'wow fadeInUp' : ''}`}
data-wow-duration="1000ms"
data-wow-delay="600ms"
suppressHydrationWarning
>
At Solvexa, we are dedicated transforming your digital aspirations into reality. With a passion for innovation and a commitment to excellence.
</p>
<Link
className={`btn border-2 btn-outline-light ${mounted ? 'wow fadeInUp' : ''}`}
data-wow-duration="1000ms"
data-wow-delay="800ms"
href={isAuthenticated ? "/dashboard" : "/auth/register"}
suppressHydrationWarning
>
{isAuthenticated ? "Go to Dashboard" : "Get Started"} <i className="ti ti-arrow-up-right"></i>
</Link>
</div>
</div>
</div>
</div>
<div className="divider"></div>
</section>
);
}
// Extend Window interface
declare global {
interface Window {
WOW: any;
}
}

View File

@@ -0,0 +1,75 @@
"use client";
import { useEffect, useState } from "react";
export default function PreloaderAndSearch() {
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
// Preloader'ı kapat
const timer = setTimeout(() => {
setIsLoaded(true);
}, 500);
// Search button click handler
const searchButton = document.getElementById('searchButton');
const searchClose = document.getElementById('searchClose');
const searchOverlay = document.getElementById('searchOverlay');
const searchPopup = document.querySelector('.search-form-popup');
const openSearch = () => {
searchOverlay?.classList.add('active');
searchPopup?.classList.add('active');
document.body.style.overflow = 'hidden';
};
const closeSearch = () => {
searchOverlay?.classList.remove('active');
searchPopup?.classList.remove('active');
document.body.style.overflow = '';
};
searchButton?.addEventListener('click', openSearch);
searchClose?.addEventListener('click', closeSearch);
searchOverlay?.addEventListener('click', closeSearch);
// Cleanup
return () => {
clearTimeout(timer);
searchButton?.removeEventListener('click', openSearch);
searchClose?.removeEventListener('click', closeSearch);
searchOverlay?.removeEventListener('click', closeSearch);
};
}, []);
return (
<>
{/* Preloader */}
{!isLoaded && (
<div className="preloader" id="preloader">
<div className="spinner-grow" role="status">
<span className="visually-hidden">Loading...</span>
</div>
</div>
)}
{/* Search Form Overlay */}
<div className="search-bg-overlay" id="searchOverlay"></div>
{/* Search Form Popup */}
<div className="search-form-popup">
<h2 className="mb-4">How can I help you, Today?</h2>
<button type="button" className="close-btn" id="searchClose" aria-label="Close">
<i className="ti ti-x"></i>
</button>
<form className="search-form">
<input type="search" className="form-control" placeholder="Search..." />
<button type="submit" className="btn btn-primary">
<i className="ti ti-search"></i> Search
</button>
</form>
</div>
</>
);
}