first project version mrDecor

This commit is contained in:
alirez.br
2026-05-11 15:30:57 +03:30
commit 8724072983
302 changed files with 25401 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
'use client'
import React from 'react'
import Link from 'next/link'
import Image from 'next/image'
import { Instagram, MessageCircle, Linkedin } from 'lucide-react'
import { useContent } from '@/components/layout/content-provider'
export default function Footer5() {
const content = useContent()
const { footer } = content.navigation
const logoAlt = footer.logoAlt
const logoUrl = content.images.logo
return (
<footer className="m-1 rounded-3xl border border-border dark:border-primary/20 bg-card">
<div className="mx-auto max-w-5xl px-5 py-8">
<div className="flex flex-wrap items-center justify-between gap-4 border-b pb-6">
<Link
href="/"
aria-label="go home"
className="flex items-center cursor-pointer">
<Image
src={logoUrl}
alt={logoAlt}
width={150}
height={50}
className="mx-auto h-10 w-auto object-contain object-center md:h-12"
/>
</Link>
<div className="flex items-center gap-3">
<span className="text-sm text-muted-foreground" dir="rtl">{footer.socialLabel}</span>
<Link
href="#"
target="_blank"
rel="noopener noreferrer"
aria-label="Instagram"
className="text-muted-foreground transition-colors hover:text-primary dark:hover:text-primary">
<Instagram className="size-5" />
</Link>
<Link
href="#"
target="_blank"
rel="noopener noreferrer"
aria-label="Telegram"
className="text-muted-foreground transition-colors hover:text-primary dark:hover:text-primary">
<MessageCircle className="size-5" />
</Link>
<Link
href="#"
target="_blank"
rel="noopener noreferrer"
aria-label="LinkedIn"
className="text-muted-foreground transition-colors hover:text-primary dark:hover:text-primary">
<Linkedin className="size-5" />
</Link>
</div>
</div>
<div className="mt-6 flex flex-wrap items-center justify-center gap-6">
{footer.links.map((link, index) => (
<Link
key={index}
href={link.href}
className="text-sm text-muted-foreground hover:text-primary transition-colors duration-150">
{link.name}
</Link>
))}
</div>
<div className="mt-6 flex flex-col items-center justify-center gap-2 text-center sm:flex-row sm:gap-4">
{footer.phoneNumber && footer.phoneHref && (
<a
href={footer.phoneHref}
className="text-sm text-muted-foreground hover:text-primary transition-colors duration-150"
dir="ltr">
{footer.phoneLabel && <span className="ms-1">{footer.phoneLabel}</span>}
{footer.phoneNumber}
</a>
)}
<p className="text-sm text-muted-foreground">
{footer.copyright}
</p>
</div>
</div>
</footer>
)
}
+446
View File
@@ -0,0 +1,446 @@
'use client'
import Link from 'next/link'
import Image from 'next/image'
import { usePathname } from 'next/navigation'
import { BadgeCheck, BriefcaseBusiness, Gauge, Info, Menu, PhoneCall, ShieldCheck, Sparkles, Store, X } from 'lucide-react'
import { Button } from '@/components/ui/button'
import React from 'react'
import { cn } from '@/lib/utils'
import { useScroll } from 'motion/react'
import { useContent } from '@/components/layout/content-provider'
import { AnimatePresence, motion } from 'framer-motion'
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from '@/components/ui/navigation-menu'
function isRouteActive(pathname: string, href: string): boolean {
if (href === '/') return pathname === '/'
return pathname === href || pathname.startsWith(`${href}/`)
}
const HOME_HREF = '/'
export const HeroHeaderTailark = () => {
const [menuState, setMenuState] = React.useState(false)
const [scrolled, setScrolled] = React.useState(false)
const pathname = usePathname() ?? ''
const content = useContent()
const { header } = content.navigation
const { images } = content
const menuItems = header.menuItems
const productItems = header.productItems
const wordmark = header.wordmark ?? content.meta.siteName
const homeItem = menuItems.find((i) => i.href === HOME_HREF)
const trailItems = menuItems.filter((i) => i.href !== HOME_HREF)
const productMenuItems = productItems.map((item, index) => ({
...item,
icon: [Sparkles, Gauge, ShieldCheck][index] ?? BadgeCheck,
}))
const solutionMenuItems = [
{
name: 'درباره ما',
href: '/about',
description: 'آشنایی با چشم انداز، تجربه و مسیر توسعه مستر دکور',
icon: Info,
},
{
name: 'تماس با ما',
href: '/contact',
description: 'ارتباط مستقیم با تیم برای دریافت پاسخ سریع',
icon: PhoneCall,
},
{
name: 'مشاوره و قیمت',
href: '/consultation',
description: 'بررسی دقیق نیاز شما و پیشنهاد مسیر اجرایی مناسب',
icon: BriefcaseBusiness,
},
]
const { scrollYProgress } = useScroll()
React.useEffect(() => {
const unsubscribe = scrollYProgress.on('change', (latest) => {
setScrolled(latest > 0.05)
})
return () => unsubscribe()
}, [scrollYProgress])
return (
<header className="pt-[env(safe-area-inset-top)]">
<nav
data-state={menuState && 'active'}
className={cn(
'fixed z-[100] w-full border-b transition-[background-color,box-shadow] duration-200',
scrolled
? 'border-border/80 bg-background/90 shadow-sm shadow-black/5 backdrop-blur-xl'
: 'border-transparent bg-background/70 backdrop-blur-md'
)}>
<div className="mx-auto max-w-7xl px-4 sm:px-6">
<div className="relative flex min-h-[3.5rem] flex-wrap items-center justify-between gap-3 py-2.5 lg:min-h-0 lg:flex-nowrap lg:py-3">
<div className="flex w-full min-w-0 flex-1 items-center gap-2 lg:w-auto lg:flex-initial">
<button
type="button"
onClick={() => setMenuState(!menuState)}
aria-label={menuState ? 'بستن منو' : 'باز کردن منو'}
className="relative z-20 -m-1.5 flex size-10 shrink-0 items-center justify-center rounded-full border border-transparent hover:bg-accent/60 lg:hidden">
<AnimatePresence mode="wait">
{menuState ? (
<motion.span
key="close"
initial={{ rotate: -90, opacity: 0 }}
animate={{ rotate: 0, opacity: 1 }}
exit={{ rotate: 90, opacity: 0 }}
transition={{ duration: 0.2 }}
className="inline-flex">
<X className="size-5" />
</motion.span>
) : (
<motion.span
key="menu"
initial={{ rotate: 90, opacity: 0 }}
animate={{ rotate: 0, opacity: 1 }}
exit={{ rotate: -90, opacity: 0 }}
transition={{ duration: 0.2 }}
className="inline-flex">
<Menu className="size-5" />
</motion.span>
)}
</AnimatePresence>
</button>
<Link
href="/"
className="flex min-w-0 shrink items-center gap-2.5 rounded-xl py-1 pe-1 ps-0 transition-opacity hover:opacity-90"
aria-label={wordmark}>
<Image
src={images.logo}
alt={header.logoAlt}
width={180}
height={60}
className="mx-auto h-9 w-auto object-contain object-center sm:h-10"
priority
/>
<span className="hidden truncate text-start text-base font-semibold tracking-tight text-foreground sm:inline md:text-lg">
{wordmark}
</span>
</Link>
</div>
<div className="order-last hidden w-full justify-center lg:order-none lg:flex lg:w-auto lg:flex-1 lg:justify-center">
<NavigationMenu
dir="rtl"
className="mx-auto"
>
<NavigationMenuList className="gap-3">
{homeItem ? (
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
isRouteActive(pathname, homeItem.href)
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground'
)}
>
<Link href={homeItem.href}>{homeItem.name}</Link>
</NavigationMenuLink>
</NavigationMenuItem>
) : null}
<NavigationMenuItem >
<NavigationMenuTrigger
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
pathname.startsWith('/product')
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground',
)}
>
{header.productsLabel}
</NavigationMenuTrigger>
<NavigationMenuContent className="p-3" dir="rtl">
<div className="grid gap-3 lg:grid-cols-3 w-[75rem] max-w-[calc(100vw-2rem)]">
<div className="space-y-2 lg:col-span-2">
<div className="px-2">
<p className="text-caption font-medium text-muted-foreground">محصولات</p>
</div>
<ul className="grid gap-1 sm:grid-cols-2">
{productMenuItems.map((product) => {
const Icon = product.icon
return (
<li key={`${product.name}-${product.href}`}>
<NavigationMenuLink asChild>
<Link
href={product.href}
className="flex items-start gap-3 rounded-xl border border-transparent px-3 py-3 text-start transition-colors hover:border-border/80 hover:bg-accent/60"
>
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-muted">
<Icon className="h-4 w-4 text-muted-foreground" />
</span>
<span className="space-y-0.5">
<span className="block text-body-sm font-medium text-foreground">{product.name}</span>
<span className="block text-caption leading-snug text-muted-foreground">{product.description}</span>
</span>
</Link>
</NavigationMenuLink>
</li>
)
})}
</ul>
</div>
<Link
href="/product"
className="group relative hidden overflow-hidden rounded-2xl border border-border bg-card lg:block"
>
<Image
src="/assets/main-pic/product/sampleghaleb.png"
alt="نمای کلی محصولات"
width={600}
height={760}
className="h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.02]"
/>
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-background/90 to-transparent p-4">
<p className="text-body-sm font-medium text-foreground">اکوسیستم یکپارچه محصولات</p>
<p className="mt-1 text-caption text-muted-foreground">برای مشاهده جزئیات کامل همه محصولات کلیک کنید</p>
</div>
<span className="absolute start-3 top-3 inline-flex items-center rounded-full bg-background/90 px-2 py-1 text-caption font-medium text-foreground">
<Store className="me-1 h-3.5 w-3.5" />
{productMenuItems.length} محصول
</span>
</Link>
</div>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
isRouteActive(pathname, '/after-sales')
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground'
)}
>
<Link href="/after-sales">خدمات پس از فروش</Link>
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
isRouteActive(pathname, '/warranty')
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground'
)}
>
<Link href="/warranty">گارانتی</Link>
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink
asChild
className={cn(
'inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
isRouteActive(pathname, '/faq')
? 'bg-foreground/5 text-foreground'
: 'text-muted-foreground hover:bg-foreground/5 hover:text-foreground'
)}
>
<Link href="/faq">سوالات متداول</Link>
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem >
<NavigationMenuTrigger className="inline-flex h-8 w-max items-center justify-center rounded-md px-4 py-1 text-body-sm font-medium text-muted-foreground transition-[color,box-shadow] hover:bg-foreground/5 hover:text-foreground focus-visible:ring-[3px] focus-visible:outline-1">
پیوند ها
</NavigationMenuTrigger>
<NavigationMenuContent className="p-3" dir="rtl">
<div className="grid gap-3 lg:grid-cols-3 w-[75rem] max-w-[calc(100vw-2rem)]">
<div className="space-y-2 lg:col-span-2">
<div className="px-2">
<p className="text-caption font-medium text-muted-foreground">منوی اصلی</p>
</div>
<ul className="grid gap-1 sm:grid-cols-2">
{solutionMenuItems.map((item) => {
const Icon = item.icon
const active = isRouteActive(pathname, item.href)
return (
<li key={item.href}>
<NavigationMenuLink asChild>
<Link
href={item.href}
className={cn(
'flex items-start gap-3 rounded-xl border border-transparent px-3 py-3 text-start transition-colors hover:border-border/80 hover:bg-accent/60',
active && 'border-border/80 bg-accent/60'
)}
>
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-muted">
<Icon className="h-4 w-4 text-muted-foreground" />
</span>
<span className="space-y-0.5">
<span className="block text-body-sm font-medium text-foreground">{item.name}</span>
<span className="block text-caption leading-snug text-muted-foreground">{item.description}</span>
</span>
</Link>
</NavigationMenuLink>
</li>
)
})}
</ul>
</div>
<Link
href="/consultation"
className="group relative hidden overflow-hidden rounded-2xl border border-border bg-card lg:block"
>
<Image
src="/assets/main-pic/feature/feature1.webp"
alt="راهکارهای مشاوره و پیاده سازی"
width={600}
height={760}
className="h-full max-h-[22rem] w-full object-cover transition-transform duration-300 group-hover:scale-[1.02]"
/>
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-background/90 to-transparent p-4">
<p className="text-body-sm font-medium text-foreground">همراهی تا استقرار نهایی</p>
<p className="mt-1 text-caption text-muted-foreground">از مشاوره اولیه تا اجرای عملیاتی کنار شما هستیم</p>
</div>
</Link>
</div>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</div>
<div className="flex shrink-0 items-center gap-2 sm:gap-3">
<Button asChild size="sm" variant="primary" className="hidden sm:inline-flex">
<Link href="/consultation">{header.demoButton}</Link>
</Button>
</div>
</div>
<div className="lg:hidden">
<AnimatePresence>
{menuState && (
<>
<motion.div
aria-hidden
onClick={() => setMenuState(false)}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
className="fixed inset-0 z-[99] bg-background/50 backdrop-blur-[2px]"
/>
<motion.div
initial={{ opacity: 0, y: -8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -8 }}
transition={{ duration: 0.22, ease: [0.32, 0.72, 0, 1] }}
className="relative z-[100] -mx-1 mb-3 overflow-hidden rounded-2xl border border-border/60 bg-card/95 shadow-lg shadow-black/10 backdrop-blur-xl">
<nav className="max-h-[min(70vh,28rem)] overflow-y-auto overscroll-contain px-3 py-3" aria-label="منوی موبایل">
{homeItem ? (
<>
<p className="text-caption mb-2 px-2 font-medium uppercase tracking-wider text-muted-foreground">
منو
</p>
<ul className="space-y-1">
<li>
<Link
href={homeItem.href}
onClick={() => setMenuState(false)}
className={cn(
'flex items-center rounded-xl px-3 py-2.5 text-body-sm transition-colors',
isRouteActive(pathname, homeItem.href)
? 'bg-primary/12 font-medium text-foreground'
: 'text-muted-foreground hover:bg-accent/50 hover:text-foreground'
)}>
{homeItem.name}
</Link>
</li>
</ul>
<div className="my-3 border-t border-border/60" />
</>
) : null}
<p className="text-caption mb-2 px-2 font-medium uppercase tracking-wider text-muted-foreground">
{header.productsLabel}
</p>
<ul className="grid gap-2 sm:grid-cols-2">
{productMenuItems.map((product) => {
const Icon = product.icon
return (
<li key={`${product.name}-${product.href}`}>
<Link
href={product.href}
onClick={() => setMenuState(false)}
className="flex items-start gap-3 rounded-xl border border-border/60 bg-card/40 px-3 py-3 transition-colors hover:bg-muted/40">
<span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-muted">
<Icon className="h-4 w-4 text-muted-foreground" />
</span>
<span className="space-y-0.5">
<span className="block text-body-sm font-medium text-foreground">{product.name}</span>
<span className="block text-caption leading-snug text-muted-foreground">{product.description}</span>
</span>
</Link>
</li>
)})}
</ul>
{trailItems.length > 0 ? (
<>
<div className="my-3 border-t border-border/60" />
<ul className="space-y-1">
{trailItems.map((item, index) => {
const active = isRouteActive(pathname, item.href)
return (
<li key={index}>
<Link
href={item.href}
onClick={() => setMenuState(false)}
className={cn(
'flex items-center rounded-xl px-3 py-2.5 text-body-sm transition-colors',
active
? 'bg-primary/12 font-medium text-foreground'
: 'text-muted-foreground hover:bg-accent/50 hover:text-foreground'
)}>
{item.name}
</Link>
</li>
)
})}
</ul>
</>
) : null}
<div className="mt-4 flex flex-col gap-2 border-t border-border/60 pt-3 sm:flex-row sm:items-center sm:justify-between">
<Button asChild variant="primary" className="w-full sm:w-auto">
<Link href="/consultation" onClick={() => setMenuState(false)}>
{header.demoButton}
</Link>
</Button>
</div>
</nav>
</motion.div>
</>
)}
</AnimatePresence>
</div>
</div>
</nav>
</header>
)
}
+107
View File
@@ -0,0 +1,107 @@
'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { Logo } from '@/components/navigation/logo'
import { Menu, X } from 'lucide-react'
import { Button } from '@/components/ui/button'
import React from 'react'
import { cn } from '@/lib/utils'
const menuItems = [
{ name: 'صفحه اصلی', href: '/' },
{ name: 'محصولات', href: '/product' },
{ name: 'تماس با ما', href: '/contact' },
]
function isLinkActive(pathname: string, href: string): boolean {
if (href === '/') return pathname === '/'
return pathname === href || pathname.startsWith(href + '/')
}
export const HeroHeader = () => {
const pathname = usePathname()
const [menuState, setMenuState] = React.useState(false)
const [isScrolled, setIsScrolled] = React.useState(false)
React.useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 50)
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [])
return (
<header>
<nav
data-state={menuState && 'active'}
className="fixed z-50 w-full px-2">
<div className={cn('mx-auto mt-2 max-w-6xl px-2 transition-all duration-300 lg:px-2 bg-background/30 backdrop-blur-md rounded-md border border-border/10', isScrolled && 'bg-background/20 max-w-4xl shadow-lg lg:px-5')}>
<div className="relative flex flex-wrap items-center justify-between gap-2 lg:gap-0">
<div className="flex w-full justify-start gap-2 lg:w-auto">
<button
onClick={() => setMenuState(!menuState)}
aria-label={menuState == true ? 'بستن منو' : 'باز کردن منو'}
className="relative z-20 -m-2.5 -mr-4 block cursor-pointer p-2.5 lg:hidden">
<Menu className="in-data-[state=active]:rotate-180 in-data-[state=active]:scale-0 in-data-[state=active]:opacity-0 m-auto size-4 duration-200" />
<X className="in-data-[state=active]:rotate-0 in-data-[state=active]:scale-100 in-data-[state=active]:opacity-100 absolute inset-0 m-auto size-4 -rotate-180 scale-0 opacity-0 duration-200" />
</button>
<Logo />
</div>
<div className="absolute inset-0 m-auto hidden size-fit lg:flex items-center">
<ul className="flex gap-2 text-sm">
{menuItems.map((item, index) => {
const active = isLinkActive(pathname ?? '', item.href)
return (
<li key={index}>
<Link
href={item.href}
className={cn(
'text-muted-foreground hover:text-foreground hover:bg-accent/20 transition-all duration-300 relative group p-2 px-4 rounded-md',
active && 'text-foreground bg-accent/40'
)}>
<span className="relative z-10">{item.name}</span>
</Link>
</li>
)
})}
</ul>
</div>
<div className="in-data-[state=active]:block lg:in-data-[state=active]:flex mb-3 hidden w-full flex-wrap items-center justify-end space-y-8 md:flex-nowrap lg:m-0 lg:flex lg:w-fit lg:gap-6 lg:space-y-0 lg:border-transparent lg:bg-transparent lg:p-0 lg:shadow-none dark:shadow-none dark:lg:bg-transparent">
<div className="lg:hidden w-full">
<ul className="text-base flex flex-col items-stretch">
{menuItems.map((item, index) => {
const active = isLinkActive(pathname ?? '', item.href)
return (
<li key={index}>
<Link
href={item.href}
onClick={() => setMenuState(false)}
className={cn(
'text-muted-foreground block w-full hover:text-foreground hover:bg-accent/20 transition-all duration-300 relative group p-2 px-4 rounded-md',
active && 'text-foreground bg-accent/40'
)}>
<span className="relative z-10">{item.name}</span>
</Link>
</li>
)
})}
</ul>
</div>
</div>
<div className={`flex justify-end max-md:absolute top-0.5 left-8 in-data-[state=active]:block`} />
</div>
</div>
</nav>
</header>
)
}
+36
View File
@@ -0,0 +1,36 @@
import { cn } from '@/lib/utils'
export const LogoTailark = ({ className, uniColor }: { className?: string; uniColor?: boolean }) => {
return (
<svg
viewBox="0 0 78 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={cn('text-foreground h-5 w-auto', className)}>
<path
d="M3 0H5V18H3V0ZM13 0H15V18H13V0ZM18 3V5H0V3H18ZM0 15V13H18V15H0Z"
fill={uniColor ? 'currentColor' : 'url(#logo-gradient)'}
/>
<path
d="M27.06 7.054V12.239C27.06 12.5903 27.1393 12.8453 27.298 13.004C27.468 13.1513 27.7513 13.225 28.148 13.225H29.338V14.84H27.808C26.9353 14.84 26.2667 14.636 25.802 14.228C25.3373 13.82 25.105 13.157 25.105 12.239V7.054H24V5.473H25.105V3.144H27.06V5.473H29.338V7.054H27.06ZM30.4782 10.114C30.4782 9.17333 30.6709 8.34033 31.0562 7.615C31.4529 6.88967 31.9855 6.32867 32.6542 5.932C33.3342 5.524 34.0822 5.32 34.8982 5.32C35.6349 5.32 36.2752 5.46733 36.8192 5.762C37.3745 6.04533 37.8165 6.40233 38.1452 6.833V5.473H40.1002V14.84H38.1452V13.446C37.8165 13.888 37.3689 14.2563 36.8022 14.551C36.2355 14.8457 35.5895 14.993 34.8642 14.993C34.0595 14.993 33.3229 14.789 32.6542 14.381C31.9855 13.9617 31.4529 13.3837 31.0562 12.647C30.6709 11.899 30.4782 11.0547 30.4782 10.114ZM38.1452 10.148C38.1452 9.502 38.0092 8.941 37.7372 8.465C37.4765 7.989 37.1309 7.62633 36.7002 7.377C36.2695 7.12767 35.8049 7.003 35.3062 7.003C34.8075 7.003 34.3429 7.12767 33.9122 7.377C33.4815 7.615 33.1302 7.972 32.8582 8.448C32.5975 8.91267 32.4672 9.468 32.4672 10.114C32.4672 10.76 32.5975 11.3267 32.8582 11.814C33.1302 12.3013 33.4815 12.6753 33.9122 12.936C34.3542 13.1853 34.8189 13.31 35.3062 13.31C35.8049 13.31 36.2695 13.1853 36.7002 12.936C37.1309 12.6867 37.4765 12.324 37.7372 11.848C38.0092 11.3607 38.1452 10.794 38.1452 10.148ZM43.6317 4.232C43.2803 4.232 42.9857 4.113 42.7477 3.875C42.5097 3.637 42.3907 3.34233 42.3907 2.991C42.3907 2.63967 42.5097 2.345 42.7477 2.107C42.9857 1.869 43.2803 1.75 43.6317 1.75C43.9717 1.75 44.2607 1.869 44.4987 2.107C44.7367 2.345 44.8557 2.63967 44.8557 2.991C44.8557 3.34233 44.7367 3.637 44.4987 3.875C44.2607 4.113 43.9717 4.232 43.6317 4.232ZM44.5837 5.473V14.84H42.6457V5.473H44.5837ZM49.0661 2.26V14.84H47.1281V2.26H49.0661ZM50.9645 10.114C50.9645 9.17333 51.1572 8.34033 51.5425 7.615C51.9392 6.88967 52.4719 6.32867 53.1405 5.932C53.8205 5.524 54.5685 5.32 55.3845 5.32C56.1212 5.32 56.7615 5.46733 57.3055 5.762C57.8609 6.04533 58.3029 6.40233 58.6315 6.833V5.473H60.5865V14.84H58.6315V13.446C58.3029 13.888 57.8552 14.2563 57.2885 14.551C56.7219 14.8457 56.0759 14.993 55.3505 14.993C54.5459 14.993 53.8092 14.789 53.1405 14.381C52.4719 13.9617 51.9392 13.3837 51.5425 12.647C51.1572 11.899 50.9645 11.0547 50.9645 10.114ZM58.6315 10.148C58.6315 9.502 58.4955 8.941 58.2235 8.465C57.9629 7.989 57.6172 7.62633 57.1865 7.377C56.7559 7.12767 56.2912 7.003 55.7925 7.003C55.2939 7.003 54.8292 7.12767 54.3985 7.377C53.9679 7.615 53.6165 7.972 53.3445 8.448C53.0839 8.91267 52.9535 9.468 52.9535 10.114C52.9535 10.76 53.0839 11.3267 53.3445 11.814C53.6165 12.3013 53.9679 12.6753 54.3985 12.936C54.8405 13.1853 55.3052 13.31 55.7925 13.31C56.2912 13.31 56.7559 13.1853 57.1865 12.936C57.6172 12.6867 57.9629 12.324 58.2235 11.848C58.4955 11.3607 58.6315 10.794 58.6315 10.148ZM65.07 6.833C65.3533 6.357 65.7273 5.98867 66.192 5.728C66.668 5.456 67.229 5.32 67.875 5.32V7.326H67.382C66.6227 7.326 66.0447 7.51867 65.648 7.904C65.2627 8.28933 65.07 8.958 65.07 9.91V14.84H63.132V5.473H65.07V6.833ZM73.3624 10.165L77.6804 14.84H75.0624L71.5944 10.811V14.84H69.6564V2.26H71.5944V9.57L74.9944 5.473H77.6804L73.3624 10.165Z"
fill="currentColor"
/>
<defs>
<linearGradient
id="logo-gradient"
x1="10"
y1="0"
x2="10"
y2="20"
gradientUnits="userSpaceOnUse">
<stop stopColor="#9B99FE" />
<stop
offset="1"
stopColor="#2BC8B7"
/>
</linearGradient>
</defs>
</svg>
)
}
+66
View File
@@ -0,0 +1,66 @@
import { cn } from "@/lib/utils";
import Image from "next/image";
import Link from "next/link";
import { Separator } from "./ui/separator";
export const Logo = ({
className,
uniColor,
hasCaption
}: {
className?: string;
uniColor?: boolean;
hasCaption?: boolean;
}) => {
const _logoText = <span className="font-bold text-xl leading-tight">مستر دکور</span>
return (
<Link href="/" className={cn('flex items-center justify-center', hasCaption ? 'flex-col text-center' : 'gap-2', className)}>
<LogoIcon uniColor={uniColor} />
{hasCaption ?
<span className="flex flex-col items-center">
{_logoText}
<span className="text-xs text-muted-foreground font-normal leading-tight">
زیرساخت دیجیتال بازار طلا
</span>
<Separator className="mt-2 max-w-10" />
</span>
: _logoText}
</Link>
);
};
export const LogoIcon = ({
className,
uniColor,
}: {
className?: string;
uniColor?: boolean;
}) => {
return (
<Image
src="/assets/montazeranLogo.png"
alt="Logo"
width={50}
height={50}
className={cn("mx-auto h-10 w-auto object-contain object-center md:h-12 dark:invert", className)}
/>
);
};
export const LogoStroke = ({ className }: { className?: string }) => {
return (
<svg
className={cn("size-7 w-7", className)}
viewBox="0 0 71 25"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M61.25 1.625L70.75 1.5625C70.75 4.77083 70.25 7.79167 69.25 10.625C68.2917 13.4583 66.8958 15.9583 65.0625 18.125C63.2708 20.25 61.125 21.9375 58.625 23.1875C56.1667 24.3958 53.4583 25 50.5 25C46.875 25 43.6667 24.2708 40.875 22.8125C38.125 21.3542 35.125 19.2083 31.875 16.375C29.75 14.4167 27.7917 12.8958 26 11.8125C24.2083 10.7292 22.2708 10.1875 20.1875 10.1875C18.0625 10.1875 16.25 10.7083 14.75 11.75C13.25 12.75 12.0833 14.1875 11.25 16.0625C10.4583 17.9375 10.0625 20.1875 10.0625 22.8125L0 22.9375C0 19.6875 0.479167 16.6667 1.4375 13.875C2.4375 11.0833 3.83333 8.64583 5.625 6.5625C7.41667 4.47917 9.54167 2.875 12 1.75C14.5 0.583333 17.2292 0 20.1875 0C23.8542 0 27.1042 0.770833 29.9375 2.3125C32.8125 3.85417 35.7708 5.97917 38.8125 8.6875C41.1042 10.7708 43.1042 12.3333 44.8125 13.375C46.5625 14.375 48.4583 14.875 50.5 14.875C52.6667 14.875 54.5417 14.3125 56.125 13.1875C57.75 12.0625 59 10.5 59.875 8.5C60.7917 6.5 61.25 4.20833 61.25 1.625Z"
fill="none"
strokeWidth={0.5}
stroke="currentColor"
/>
</svg>
);
};
+41
View File
@@ -0,0 +1,41 @@
'use client'
import { Moon, Sun } from 'lucide-react'
import { useTheme } from 'next-themes'
import { useEffect, useState } from 'react'
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
export function ThemeToggle() {
const { theme, setTheme } = useTheme()
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
}, [])
if (!mounted) {
return (
<Button
variant="ghost"
size="icon"
aria-label="Toggle theme"
>
<Sun className="size-4" />
</Button>
)
}
return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
aria-label="Toggle theme"
>
<Sun className="size-4 rotate-0 scale-100 transition-all duration-300 dark:-rotate-90 dark:scale-0" />
<Moon className="absolute size-4 rotate-90 scale-0 transition-all duration-300 dark:rotate-0 dark:scale-100" />
</Button>
)
}