fix: UI/UX regressions - header glassmorphic, dark mode icons, testimonials i18n, image remotePatterns

This commit is contained in:
parsa aghaei 2026-06-29 09:57:51 +03:30
parent 7dc79b3151
commit 79c229a93c
10 changed files with 126 additions and 67 deletions

View File

@ -14,6 +14,18 @@ const nextConfig = {
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: 'backend.parsaaghayi.ir',
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: 'parsaaghayi.ir',
port: '',
pathname: '/**',
},
],
},
async rewrites() {

View File

@ -82,7 +82,7 @@ export default function Contact({ dict }: ContactProps) {
whileTap={{ scale: 0.98 }}
disabled={isSubmitting}
type="submit"
className="relative w-full md:w-auto flex items-center justify-center gap-2 px-8 py-4 rounded-2xl bg-primary text-primary-foreground font-bold transition-all duration-300 disabled:opacity-70 disabled:cursor-not-allowed"
className="relative w-full md:w-auto flex items-center justify-center gap-2 px-8 py-4 rounded-2xl bg-primary text-primary-foreground font-bold whitespace-nowrap transition-all duration-300 disabled:opacity-70 disabled:cursor-not-allowed"
>
{isSubmitting ? (
<div className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />

View File

@ -54,14 +54,14 @@ export default async function Footer() {
<a
key={index}
href="#"
className="p-2 rounded-full glass-panel transition-all duration-300 hover:scale-110 hover:text-primary"
className="p-2 rounded-full glass-panel transition-all duration-300 hover:scale-110 hover:text-primary group"
>
<Image
src={social.src}
width={24}
height={24}
alt={social.alt}
className="w-6 h-6"
className="w-6 h-6 dark:brightness-0 dark:invert group-hover:dark:brightness-0 group-hover:dark:invert-[.7]"
/>
</a>
))}

View File

@ -41,10 +41,10 @@ export default function Header() {
return (
<header
className={`fixed top-0 left-0 z-50 flex h-20 w-full items-center justify-between px-6 py-4 transition-all duration-300 xl:px-12 ${
className={`fixed top-0 left-0 z-50 flex h-20 w-full items-center justify-between px-6 py-4 transition-all duration-300 xl:px-12 backdrop-blur-md bg-white/70 dark:bg-zinc-950/70 ${
scrolled
? "backdrop-blur-md bg-white/70 dark:bg-zinc-950/70 border-b border-zinc-200/50 dark:border-zinc-800/50 shadow-sm"
: "bg-transparent"
? "border-b border-zinc-200/50 dark:border-zinc-800/50 shadow-sm"
: ""
}`}
id="header"
>

View File

@ -57,14 +57,14 @@ export default function Hero({ dict }: HeroProps) {
viewport={{ once: true }}
whileHover={{ scale: 1.2, rotate: 5 }}
whileTap={{ scale: 0.9 }}
className="p-2 rounded-full glass-panel hover:text-primary transition-colors"
className="p-2 rounded-full glass-panel hover:text-primary transition-colors group"
>
<Image
src={src}
width={24}
height={24}
alt={alt}
className="w-6 h-6"
className="w-6 h-6 dark:brightness-0 dark:invert group-hover:dark:brightness-0 group-hover:dark:invert-[.7]"
/>
</motion.a>
))}
@ -128,7 +128,7 @@ export default function Hero({ dict }: HeroProps) {
>
<a
href="#contact"
className="group relative inline-flex items-center justify-center whitespace-nowrap px-4 sm:px-8 py-3 font-bold text-white transition-all duration-200 bg-primary rounded-full hover:brightness-110 hover:scale-105 active:scale-95"
className="group relative inline-flex items-center justify-center whitespace-nowrap px-6 sm:px-8 py-3 font-bold text-white transition-all duration-200 bg-primary rounded-full hover:brightness-110 hover:scale-105 active:scale-95"
>
<span className="relative z-10">{dict.website.homePage.top.cta}</span>
<div className="absolute inset-0 rounded-full bg-primary blur-lg opacity-50 group-hover:opacity-100 transition-opacity"></div>

View File

@ -56,7 +56,7 @@ export default function Services({ dict }: ServicesProps) {
<img
src={service!.imageSrc}
alt={service!.altText}
className="w-12 h-12 object-contain transition-transform duration-300 group-hover:scale-110"
className="w-12 h-12 object-contain transition-transform duration-300 group-hover:scale-110 dark:brightness-0 dark:invert"
/>
)}
</div>

View File

@ -1,70 +1,34 @@
"use client";
import { Testimonial } from "@/app/types/types";
import React, { useState, useRef, useEffect } from "react";
import { motion } from "framer-motion";
import { Quote, ChevronLeft, ChevronRight } from "lucide-react";
import Image from "next/image";
import { getCookie } from "cookies-next";
interface TestimonialData {
name: string;
position: string;
image: string;
quote: string;
}
interface TestimonialsDict {
title: string;
description: string;
data: TestimonialData[];
}
interface TestimonialsProps {
dict: {
website: {
homePage: {
testimonials: {
title: string;
description: string;
};
testimonials: TestimonialsDict;
};
};
};
}
const testimonials: Testimonial[] = [
{
name: "Sarah Johnson",
position: "Founder & CEO of Innovate Solutions",
image: "/images/user-1.svg",
quote:
'The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.',
},
{
name: "Michael Lee",
position: "Chief Executive Officer at Tech Innovators",
image: "/images/user-1.svg",
quote:
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
},
{
name: "Emma Davis",
position: "CEO & Lead Strategist at Visionary Ventures",
image: "/images/user-1.svg",
quote:
"It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
},
{
name: "John Doe",
position: "COO at Startup Labs",
image: "/images/user-1.svg",
quote:
"All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet.",
},
{
name: "Jane Smith",
position: "Founder at Health Innovations",
image: "/images/user-1.svg",
quote:
"It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.",
},
{
name: "Alex Chen",
position: "CTO at CloudBase Technologies",
image: "/images/user-1.svg",
quote:
"Working with this developer was an absolute pleasure. The attention to detail, code quality, and timely delivery exceeded our expectations. I highly recommend their services for any complex web development project.",
},
];
export default function Testimonials({ dict }: TestimonialsProps) {
const [currentIndex, setCurrentIndex] = useState(0);
const scrollRef = useRef<HTMLDivElement>(null);
@ -77,7 +41,8 @@ export default function Testimonials({ dict }: TestimonialsProps) {
}, []);
const isRTL = locale === "fa";
const maxIndex = Math.max(0, testimonials.length - 3);
const tData = dict.website.homePage.testimonials.data || [];
const maxIndex = Math.max(0, tData.length - 3);
const scrollTo = (index: number) => {
const idx = Math.max(0, Math.min(index, maxIndex));
@ -120,7 +85,7 @@ export default function Testimonials({ dict }: TestimonialsProps) {
className="flex gap-8 overflow-x-auto snap-x snap-mandatory scrollbar-none pb-4"
style={{ scrollbarWidth: "none", msOverflowStyle: "none" }}
>
{testimonials.map((testimonial, index) => (
{tData.map((testimonial, index) => (
<div
key={index}
className="min-w-[100%] md:min-w-[calc(50%-1rem)] lg:min-w-[calc(33.333%-1.1rem)] snap-start flex-shrink-0"
@ -131,14 +96,14 @@ export default function Testimonials({ dict }: TestimonialsProps) {
transition={{ duration: 0.5, delay: index * 0.1 }}
viewport={{ once: true }}
whileHover={{ y: -10 }}
className="relative p-6 md:p-8 rounded-3xl glass-panel flex flex-col h-full"
className="relative p-6 md:p-8 rounded-3xl glass-panel flex flex-col h-full overflow-visible"
>
<div className="absolute -top-6 -start-6 w-12 h-12 bg-primary rounded-full flex items-center justify-center text-white shadow-lg">
<Quote className="w-6 h-6" />
</div>
<div className="flex-grow pt-2">
<p className="text-muted-foreground leading-relaxed mb-8 italic text-sm md:text-base">
<p className="text-muted-foreground leading-relaxed mb-8 italic text-sm md:text-base break-words">
"{testimonial.quote}"
</p>
</div>
@ -169,7 +134,7 @@ export default function Testimonials({ dict }: TestimonialsProps) {
))}
</div>
{testimonials.length > 3 && (
{tData.length > 3 && (
<>
<button
onClick={isRTL ? handleNext : handlePrev}

View File

@ -19,7 +19,45 @@
},
"testimonials": {
"title": "testimonials",
"description": "The Testimonials section features feedback from clients and collaborators, highlighting the quality of my services and commitment to client satisfaction. These authentic reviews reflect my professionalism and the positive impact of my work, giving potential clients confidence in choosing me for their web development needs."
"description": "The Testimonials section features feedback from clients and collaborators, highlighting the quality of my services and commitment to client satisfaction. These authentic reviews reflect my professionalism and the positive impact of my work, giving potential clients confidence in choosing me for their web development needs.",
"data": [
{
"name": "Sarah Johnson",
"position": "Founder & CEO of Innovate Solutions",
"image": "/images/user-1.svg",
"quote": "The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from \"de Finibus Bonorum et Malorum\" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham."
},
{
"name": "Michael Lee",
"position": "Chief Executive Officer at Tech Innovators",
"image": "/images/user-1.svg",
"quote": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged."
},
{
"name": "Emma Davis",
"position": "CEO & Lead Strategist at Visionary Ventures",
"image": "/images/user-1.svg",
"quote": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English."
},
{
"name": "John Doe",
"position": "COO at Startup Labs",
"image": "/images/user-1.svg",
"quote": "All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet."
},
{
"name": "Jane Smith",
"position": "Founder at Health Innovations",
"image": "/images/user-1.svg",
"quote": "It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable."
},
{
"name": "Alex Chen",
"position": "CTO at CloudBase Technologies",
"image": "/images/user-1.svg",
"quote": "Working with this developer was an absolute pleasure. The attention to detail, code quality, and timely delivery exceeded our expectations."
}
]
},
"contact": {
"slogan": "Lets Design Together",

View File

@ -19,7 +19,45 @@
},
"testimonials": {
"title": "نظرات",
"description": "بخش نظرات شامل بازخوردهای مشتریان و همکاران است که کیفیت خدمات و تعهد من به رضایت مشتری را برجسته می‌کند. این بررسی‌های واقعی، حرفه‌ای‌گری و تأثیر مثبت کارهای من را نشان می‌دهد و به مشتریان احتمالی اطمینان می‌دهد."
"description": "بخش نظرات شامل بازخوردهای مشتریان و همکاران است که کیفیت خدمات و تعهد من به رضایت مشتری را برجسته می‌کند. این بررسی‌های واقعی، حرفه‌ای‌گری و تأثیر مثبت کارهای من را نشان می‌دهد و به مشتریان احتمالی اطمینان می‌دهد.",
"data": [
{
"name": "سارا جانسون",
"position": "بنیانگذار و مدیرعامل راهکارهای نوآورانه",
"image": "/images/user-1.svg",
"quote": "بخش استاندارد لورم ایپسوم که از سال ۱۵۰۰ مورد استفاده قرار گرفته در زیر برای علاقه‌مندان بازتولید شده است. بخش‌های ۱.۱۰.۳۲ و ۱.۱۰.۳۳ از کتاب \"درباره حدود خیر و شر\" سیسرو نیز به شکل اصلی خود بازتولید شده است."
},
{
"name": "مایکل لی",
"position": "مدیر اجرایی در نوآوران فناوری",
"image": "/images/user-1.svg",
"quote": "لورم ایپسوم صرفاً متن ساختگی صنعت چاپ و نشر است. لورم ایپسوم از سال ۱۵۰۰ به عنوان متن استاندارد صنعت استفاده شده است، زمانی که یک چاپگر ناشناس یک کاسه از حروف را برداشت و آنها را به هم ریخت تا یک نمونه کتاب بسازد."
},
{
"name": "اما دیویس",
"position": "مدیرعامل و استراتژیست ارشد در ونچرهای چشم‌انداز",
"image": "/images/user-1.svg",
"quote": "این یک واقعیت ثابت شده است که خواننده با خواندن محتوای قابل خواندن یک صفحه هنگام بررسی طرح آن حواسش پرت می‌شود. نکته استفاده از لورم ایپسوم این است که توزیع حروف کم و بیش نرمال دارد."
},
{
"name": "جان دو",
"position": "مدیر عملیات در استارتاپ لبز",
"image": "/images/user-1.svg",
"quote": "همه مولدهای لورم ایپسوم در اینترنت تمایل به تکرار قطعات از پیش تعریف شده دارند، که این را به اولین مولد واقعی در اینترنت تبدیل می‌کند."
},
{
"name": "جین اسمیت",
"position": "بنیانگذار در نوآوری‌های سلامت",
"image": "/images/user-1.svg",
"quote": "این از فرهنگ لغت بیش از ۲۰۰ کلمه لاتین استفاده می‌کند که با تعداد کمی از ساختارهای جمله نمونه ترکیب شده است تا لورم ایپسومی منطقی تولید کند."
},
{
"name": "الکس چن",
"position": "مدیر فناوری در فناوری‌های کلودبیس",
"image": "/images/user-1.svg",
"quote": "کار با این توسعه‌دهنده یک لذت مطلق بود. توجه به جزئیات، کیفیت کد و تحویل به موقع فراتر از انتظارات ما بود."
}
]
},
"contact": {
"slogan": "بیایید با هم طراحی کنیم",

View File

@ -140,6 +140,12 @@ export type Dictionary = {
testimonials: {
title: string;
description: string;
data: Array<{
name: string;
position: string;
image: string;
quote: string;
}>;
};
contact: {
slogan: string;