-
- saveFooter('about_text', v)} />
+
+ {footer.about_text}
- {/* آیکونهای شبکههای اجتماعی: گویهای شیشهای شناور */}
-
+ {/* Social icons */}
+
{footer.socials.map(({ label, href, icon }) => {
const Icon = SOCIAL_ICONS[icon] ?? InstagramIcon;
return (
@@ -54,100 +58,234 @@ export function Footer() {
key={label}
href={href}
aria-label={label}
- className="group flex h-11 w-11 items-center justify-center rounded-full border border-white/15 bg-white/[0.04] text-ivory/70 backdrop-blur-xl shadow-[inset_0_1px_1px_rgba(255,255,255,0.15),0_4px_12px_rgba(0,0,0,0.3)] transition-all duration-300 ease-lux hover:-translate-y-1 hover:border-copper/70 hover:bg-copper/10 hover:text-copper hover:shadow-[0_0_20px_rgba(197,143,92,0.4)] active:scale-95"
+ className="group flex h-10 w-10 items-center justify-center rounded-full border border-white/15 bg-white/[0.04] text-ivory/70 backdrop-blur-xl shadow-[inset_0_1px_1px_rgba(255,255,255,0.15),0_4px_12px_rgba(0,0,0,0.3)] transition-all duration-300 ease-lux hover:border-copper/70 hover:bg-copper/10 hover:text-copper active:scale-95"
>
-
+
);
})}
-
-
- saveFooter('pages_heading', v)} />
-
-
- {nav.map((item) => (
-
- -
-
- saveNav(item.id, { label: v })}
- />
-
+ {/* Collapsible Link Groups */}
+
+ {/* Pages Accordion */}
+
+
+
+
+ {nav.map((item) => (
+ -
+
+ {item.label}
+
+
+ ))}
+
+
+
+
+ {/* Services Accordion */}
+
+
+
+
+ {services.map((service) => (
+ -
+ {service.title}
+
+ ))}
+
+
+
+
+ {/* Contact Accordion */}
+
+
+
+
+ -
+
+ {brand.address}
-
- ))}
-
-
-
-
- saveFooter('services_heading', v)} />
-
-
- {services.map((service) => (
- -
- {service.title}
+ {/* Bottom Copyright & Meta for Mobile */}
+
+
+
{footer.copyright}
+
{footer.tagline}
+
+
+
+ {/* Desktop View: Multi-Column Layout */}
+
+
+
+
+

+
+
+
+ saveFooter('about_text', v)} />
+
+ {/* آیکونهای شبکههای اجتماعی */}
+
+ {footer.socials.map(({ label, href, icon }) => {
+ const Icon = SOCIAL_ICONS[icon] ?? InstagramIcon;
+ return (
+
+
+
+ );
+ })}
+
+
+
+
+
+ saveFooter('pages_heading', v)} />
+
+
+ {nav.map((item) => (
+
+ -
+
+ saveNav(item.id, { label: v })}
+ />
+
+
+
+ ))}
+
+
+
+
+
+
+ saveFooter('services_heading', v)} />
+
+
+ {services.map((service) => (
+ -
+ {service.title}
+
+ ))}
+
+
+
+
-
-
- saveFooter('contact_heading', v)} />
-
-
+ {/* خط پایانی به همراه دکمه کپسولی بازگشت به بالا */}
+
+
+ saveFooter('copyright', v)} />
+
+
+
+
+
+ saveFooter('tagline', v)} />
+
- {/* خط پایانی به همراه دکمه کپسولی بازگشت به بالا */}
-
-
- saveFooter('copyright', v)} />
-
-
-
-
-
- saveFooter('tagline', v)} />
-
-
);
diff --git a/frontend/src/components/ProjectCard.tsx b/frontend/src/components/ProjectCard.tsx
index 4d6b1fe..8738a40 100644
--- a/frontend/src/components/ProjectCard.tsx
+++ b/frontend/src/components/ProjectCard.tsx
@@ -52,7 +52,7 @@ export function ProjectCard({ project, imageUrl, detailHref }: ProjectCardProps)

@@ -60,25 +60,25 @@ export function ProjectCard({ project, imageUrl, detailHref }: ProjectCardProps)
{/* نشانگر وضعیت کپسولی شیشهای */}
{statusText}
-
+
-
+
{title}
- {location &&
{location}
}
+ {location &&
{location}
}
{area && (
<>
-
-
+
+
{/* واحد زیربنا در محتوای انگلیسی داخل خود مقدار است — فقط در فارسی اضافه میشود */}
{lang === 'fa' ? `${area} ${t('sqm')}` : area}
@@ -88,7 +88,7 @@ export function ProjectCard({ project, imageUrl, detailHref }: ProjectCardProps)
{/* پایهٔ کارت: یک دکمه واحد */}
-
+
{t('viewProject')}
diff --git a/frontend/src/components/home/Articles.tsx b/frontend/src/components/home/Articles.tsx
index 636ddde..4b5efdf 100644
--- a/frontend/src/components/home/Articles.tsx
+++ b/frontend/src/components/home/Articles.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import { Link } from 'react-router-dom';
import { ArrowLeftIcon } from 'lucide-react';
import { Reveal } from '../Reveal';
import { ButtonLink } from '../Button';
@@ -8,6 +9,7 @@ import { useLang } from '../../i18n/lang';
import { useFieldSaver } from '../../admin/AdminContext';
import { InlineEdit } from '../admin/InlineEdit';
import { AddItemButton, EditableItem } from '../../admin/Editable';
+import { formatJalali } from '../../utils/date';
export function Articles() {
const { articles } = useSite();
@@ -17,6 +19,9 @@ export function Articles() {
// پیشنویسها فقط در صفحه وبلاگ (برای ادمین) دیده میشوند، نه در خانه
const published = articles.filter((a) => a.status !== 'draft');
+ const topArticles = published.slice(0, 3);
+ const spotlight = topArticles[0];
+ const compactList = topArticles.slice(1, 3);
const saveHeading = (field: 'label' | 'title' | 'lead' | 'cta_label', value: string) =>
save('section-headings', heading.id, { [field]: value }, (d) => {
@@ -25,24 +30,97 @@ export function Articles() {
});
return (
-
-
+
+
saveHeading('label', v)} />
-
+
saveHeading('title', v)} />
-
+
saveHeading('lead', v)} />
-
+
-
- {published.slice(0, 3).map((article, i) =>
-
+ {/* Mobile View: Magazine Editorial layout (1 Featured Spotlight + Compact Rows) */}
+
+ {/* First Article (Spotlight) */}
+ {spotlight && (
+
+
+
+
+
+ {spotlight.category}
+ •
+ {formatJalali(spotlight.date)}
+
+
+ {spotlight.title}
+
+
+ {spotlight.excerpt}
+
+
+
+
+ )}
+
+ {/* Remaining Articles (Compact List Rows) */}
+ {compactList.length > 0 && (
+
+ {compactList.map((article) => (
+
+
+
+
+ {formatJalali(article.date)}
+
+ {article.title}
+
+
+
+
+ ))}
+
+ )}
+
+ {/* Bottom Button ("همه مقالات") */}
+ {heading.cta_label && heading.cta_href && (
+
+
saveHeading('cta_label', v)} />
+
+ )}
+
+
+ {/* Desktop View: 3-Column Grid */}
+
+ {topArticles.map((article, i) =>
+
@@ -64,6 +142,6 @@ export function Articles() {
- );
-
-}
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/components/home/FeaturedProjects.tsx b/frontend/src/components/home/FeaturedProjects.tsx
index 297de99..99b1c9d 100644
--- a/frontend/src/components/home/FeaturedProjects.tsx
+++ b/frontend/src/components/home/FeaturedProjects.tsx
@@ -22,18 +22,18 @@ export function FeaturedProjects() {
.sort((a, b) => FEATURED_TITLES.indexOf(a.title) - FEATURED_TITLES.indexOf(b.title))
return (
-
-
+
+
-
+
{list.map((project, i) => {
const imageUrl = project.image || undefined;
@@ -44,7 +44,7 @@ export function FeaturedProjects() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: i * 0.1, ease: [0.23, 1, 0.32, 1] }}
- className="h-full"
+ className="h-full w-[82vw] max-w-[320px] shrink-0 snap-center md:w-auto md:max-w-none md:shrink"
>
-
+
-
+
+
-
saveHeading('title', v)} />
-
+
saveHeading('lead', v)} />
-
+
-
+
{services.map((service, i) => (
-
-
-
+
+
+
+
+
{service.title}
- {service.desc}
+
+ {service.desc}
+
diff --git a/frontend/src/components/home/Stats.tsx b/frontend/src/components/home/Stats.tsx
index 926c2b5..671ddd4 100644
--- a/frontend/src/components/home/Stats.tsx
+++ b/frontend/src/components/home/Stats.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { useSite } from '../../api';
import { useLang, formatNumber } from '../../i18n/lang';
import { useFieldSaver } from '../../admin/AdminContext';
@@ -71,12 +71,12 @@ export function Stats({ tone = 'black' }: { tone?: 'black' | 'gray' } = {}) {
const save = useFieldSaver();
return (
-
-
+
+
{stats.map((stat) =>
-
-
+
+
x.id === stat.id);
if (s) s.suffix = v;
})}
- className="ltr:ml-1 rtl:mr-1 text-2xl"
+ className="ltr:ml-1 rtl:mr-1 text-lg md:text-2xl"
/>
-
+
save('stats', stat.id, { label: v }, (d) => {
diff --git a/frontend/src/components/home/Team.tsx b/frontend/src/components/home/Team.tsx
index b63dd71..f1148e5 100644
--- a/frontend/src/components/home/Team.tsx
+++ b/frontend/src/components/home/Team.tsx
@@ -1,4 +1,3 @@
-import React from 'react'
import { Reveal } from '../Reveal'
import { SectionHeading } from '../SectionHeading'
import { useSite } from '../../api'
@@ -9,8 +8,8 @@ export function Team({ tone = 'gray' }: { tone?: 'black' | 'gray' } = {}) {
const { team } = useSite()
const { t } = useLang()
return (
-
-
+
+
-
+
{team.map((member, i) => (
-
+
{/* اضافه شدن rounded-2xl برای گرد شدن گوشهها */}
-
+
{member.name}
{member.role}
diff --git a/frontend/src/components/home/Testimonials.tsx b/frontend/src/components/home/Testimonials.tsx
index c1da059..0fc4415 100644
--- a/frontend/src/components/home/Testimonials.tsx
+++ b/frontend/src/components/home/Testimonials.tsx
@@ -1,5 +1,5 @@
import React, { useState } from 'react';
-import { AnimatePresence, motion } from 'framer-motion';
+import { AnimatePresence, motion, PanInfo } from 'framer-motion';
import { ChevronLeftIcon, ChevronRightIcon, QuoteIcon } from 'lucide-react';
import { SectionHeading } from '../SectionHeading';
import { useSite } from '../../api';
@@ -17,39 +17,57 @@ export function Testimonials() {
setIndex((prev) => (prev + dir + testimonials.length) % testimonials.length);
};
+ const handleDragEnd = (_: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => {
+ if (info.offset.x > 50) {
+ go(1); // سوایپ به راست
+ } else if (info.offset.x < -50) {
+ go(-1); // سوایپ به چپ
+ }
+ };
+
return (
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+ «{current.quote}»
+
+
+
+
+
+
-
- «{current.quote}»
-
-
-
-
-
-
+
@@ -63,8 +81,8 @@ export function Testimonials() {
onClick={() => setIndex(i)}
className={`h-2 rounded-full transition-all duration-300 ease-lux ${
i === index
- ? 'w-8 bg-copper shadow-[0_0_12px_rgba(197,143,92,0.6)]'
- : 'w-2.5 bg-ivory/20 hover:bg-ivory/40'
+ ? 'w-7 bg-copper shadow-[0_0_12px_rgba(197,143,92,0.6)] md:w-8'
+ : 'w-2 bg-ivory/20 hover:bg-ivory/40 md:w-2.5'
}`}
/>
))}
@@ -74,9 +92,9 @@ export function Testimonials() {
type="button"
onClick={() => go(-1)}
aria-label={t('nextTestimonial')}
- className="group flex h-12 w-12 items-center justify-center rounded-full border border-copper/35 bg-char/80 text-ivory/80 backdrop-blur-md shadow-[0_4px_20px_rgba(0,0,0,0.35)] transition-all duration-300 ease-lux hover:scale-110 hover:border-copper hover:bg-copper hover:text-char hover:shadow-[0_0_25px_rgba(197,143,92,0.45)] active:scale-95"
+ className="group flex h-10 w-10 items-center justify-center rounded-full border border-copper/35 bg-char/80 text-ivory/80 shadow-[0_4px_20px_rgba(0,0,0,0.35)] backdrop-blur-md transition-all duration-300 ease-lux hover:scale-110 hover:border-copper hover:bg-copper hover:text-char hover:shadow-[0_0_25px_rgba(197,143,92,0.45)] active:scale-95 md:h-12 md:w-12"
>
-
+
diff --git a/frontend/src/components/home/Timeline.tsx b/frontend/src/components/home/Timeline.tsx
index cb6c02c..1f6470e 100644
--- a/frontend/src/components/home/Timeline.tsx
+++ b/frontend/src/components/home/Timeline.tsx
@@ -39,7 +39,7 @@ function Item({ item, index, featured = false, onLi }: { item: Milestone; index:
transition={{ duration: 0.55, ease }}
>
-
+
{item.year}
@@ -85,10 +85,10 @@ export function Timeline({ tone = 'gray' }: { tone?: 'black' | 'gray' } = {}) {
}, [])
return (
-
-
+
)
diff --git a/frontend/src/components/home/WhyUs.tsx b/frontend/src/components/home/WhyUs.tsx
index f8ae052..b5e3983 100644
--- a/frontend/src/components/home/WhyUs.tsx
+++ b/frontend/src/components/home/WhyUs.tsx
@@ -1,8 +1,7 @@
-import React from 'react';
import { Reveal } from '../Reveal';
import { SectionHeading } from '../SectionHeading';
import { useSectionHeading, useSite } from '../../api';
-import { AddItemButton, EditableItem, SingletonPill } from '../../admin/Editable';
+import { AddItemButton, EditableItem } from '../../admin/Editable';
import { InlineEdit } from '../admin/InlineEdit';
import { useFieldSaver } from '../../admin/AdminContext';
import { useLang, formatNumber } from '../../i18n/lang';
@@ -19,9 +18,15 @@ export function WhyUs({ tone = 'black' }: { tone?: 'black' | 'gray' } = {}) {
if (it) Object.assign(it, changes);
});
+ const formatIndex = (index: number) => {
+ return lang === 'fa'
+ ? `۰${formatNumber(index + 1, lang)}`
+ : String(index + 1).padStart(2, '0');
+ };
+
return (
-
-
+
+
-
- {why_us.map((item, i) =>
-
-
-
-
{lang === 'fa' ? `۰${formatNumber(i + 1, lang)}` : formatNumber(i + 1, lang).padStart(2, '0')}
-
- saveItem(item.id, { title: v })}
- />
-
-
- saveItem(item.id, { desc: v })}
- />
-
-
-
-
- )}
+ {/* Mobile 2-Column Luxury Micro-Card Grid */}
+
+
+ {why_us.map((item, i) => (
+
+
+
+ {/* Top Row: Index Badge */}
+
+
+ {`0${i + 1}`}
+
+
+
+ {/* Title */}
+
+ saveItem(item.id, { title: v })}
+ />
+
+
+ {/* Description */}
+
+ saveItem(item.id, { desc: v })}
+ />
+
+
+
+
+ ))}
+
+
-
-
+
+ {/* Desktop Grid Layout */}
+
+
+ {why_us.map((item, i) => (
+
+
+
+
{formatIndex(i)}
+
+ saveItem(item.id, { title: v })}
+ />
+
+
+ saveItem(item.id, { desc: v })}
+ />
+
+
+
+
+ ))}
+
+
- );
-
+
+ );
}