- اتصال کامل فرانت به API: همه محتوای سایت (پروژهها، مقالات، خدمات، برند و...) از بکاند خوانده میشود (SiteProvider + useSite) - فرم تماس و خبرنامه متصل به بکاند و تستشده در مرورگر - ساختار مونوریپو: frontend/ + backend/ - Dockerfile برای هر دو بخش + docker-compose (PostgreSQL + FastAPI + nginx) - nginx با پروکسی /api — بدون نیاز به CORS در حالت داکر - README کامل فارسی
93 lines
2.4 KiB
TypeScript
93 lines
2.4 KiB
TypeScript
import React from 'react'
|
|
import { Link } from 'react-router-dom'
|
|
|
|
type Variant = 'copper' | 'outline' | 'dark' | 'dark-ivory'
|
|
|
|
type BaseProps = {
|
|
children: React.ReactNode
|
|
variant?: Variant
|
|
className?: string
|
|
}
|
|
|
|
const STYLES: Record<Variant, { base: string; fill: string; text: string }> = {
|
|
copper: {
|
|
base: 'bg-copper text-char',
|
|
fill: 'bg-char',
|
|
text: 'group-hover:text-ivory',
|
|
},
|
|
outline: {
|
|
base: 'border border-ivory/30 text-ivory',
|
|
fill: 'bg-copper',
|
|
text: 'group-hover:text-char',
|
|
},
|
|
dark: {
|
|
base: 'bg-char text-ivory',
|
|
fill: 'bg-copper',
|
|
text: 'group-hover:text-char',
|
|
},
|
|
'dark-ivory': {
|
|
base: 'bg-char text-ivory',
|
|
fill: 'bg-ivory',
|
|
text: 'group-hover:text-char',
|
|
},
|
|
}
|
|
|
|
function Inner({ children, variant = 'copper' }: { children: React.ReactNode; variant?: Variant }) {
|
|
const style = STYLES[variant]
|
|
return (
|
|
<>
|
|
<span
|
|
aria-hidden="true"
|
|
className={`absolute inset-0 translate-y-full transition-transform duration-[600ms] ease-lux group-hover:translate-y-0 ${style.fill}`}
|
|
/>
|
|
<span
|
|
className={`relative z-10 flex items-center justify-center gap-3 transition-colors duration-[600ms] ease-lux ${style.text}`}
|
|
>
|
|
{children}
|
|
</span>
|
|
</>
|
|
)
|
|
}
|
|
|
|
const SHELL =
|
|
'group relative inline-flex items-center justify-center overflow-hidden px-8 py-4 text-sm font-bold focus:outline-none focus-visible:ring-2 focus-visible:ring-copper focus-visible:ring-offset-2 focus-visible:ring-offset-ink'
|
|
|
|
export function ButtonLink({
|
|
to,
|
|
children,
|
|
variant = 'copper',
|
|
className = '',
|
|
}: BaseProps & { to: string }) {
|
|
return (
|
|
<Link to={to} className={`${SHELL} ${STYLES[variant].base} ${className}`}>
|
|
<Inner variant={variant}>{children}</Inner>
|
|
</Link>
|
|
)
|
|
}
|
|
|
|
export function ButtonAnchor({
|
|
href,
|
|
children,
|
|
variant = 'copper',
|
|
className = '',
|
|
...rest
|
|
}: BaseProps & { href: string } & React.AnchorHTMLAttributes<HTMLAnchorElement>) {
|
|
return (
|
|
<a href={href} className={`${SHELL} ${STYLES[variant].base} ${className}`} {...rest}>
|
|
<Inner variant={variant}>{children}</Inner>
|
|
</a>
|
|
)
|
|
}
|
|
|
|
export function Button({
|
|
children,
|
|
variant = 'copper',
|
|
className = '',
|
|
...rest
|
|
}: BaseProps & React.ButtonHTMLAttributes<HTMLButtonElement>) {
|
|
return (
|
|
<button className={`${SHELL} ${STYLES[variant].base} ${className}`} {...rest}>
|
|
<Inner variant={variant}>{children}</Inner>
|
|
</button>
|
|
)
|
|
} |