feat: updated some sections
This commit is contained in:
+125
-64
@@ -1,10 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { Icon } from "@iconify/react";
|
||||
import Image from "next/image";
|
||||
import { useRef, useState } from "react";
|
||||
import { Card, Typography } from "poyraz-ui/atoms";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
import { useRouter } from "@/i18n/routing";
|
||||
import {
|
||||
Button,
|
||||
ButtonIcon,
|
||||
ButtonLabel,
|
||||
TextEffect,
|
||||
Typography,
|
||||
} from "poyraz-ui/atoms";
|
||||
import { NewsCard } from "poyraz-ui/molecules";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { getResumeHref } from "@/lib/links";
|
||||
|
||||
type HomeHeroProps = {
|
||||
news: {
|
||||
@@ -18,78 +26,131 @@ type HomeHeroProps = {
|
||||
};
|
||||
|
||||
export function HomeHero({ news }: HomeHeroProps) {
|
||||
const [frame, setFrame] = useState<1 | 2>(1);
|
||||
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
const t = useTranslations("Home");
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
if (intervalRef.current) return;
|
||||
|
||||
intervalRef.current = setInterval(() => {
|
||||
setFrame((prev) => (prev === 1 ? 2 : 1));
|
||||
}, 260);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
intervalRef.current = null;
|
||||
}
|
||||
setFrame(1);
|
||||
};
|
||||
const locale = useLocale();
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<section className="grid gap-3 md:h-65 md:grid-cols-2">
|
||||
<div className="grid gap-2 md:grid-rows-3">
|
||||
{news.map((item) => (
|
||||
<div key={item.id}>
|
||||
<NewsCard
|
||||
className="rounded-sm border-border md:h-full"
|
||||
category={item.category}
|
||||
title={item.title}
|
||||
date={item.date}
|
||||
image={item.image}
|
||||
href={item.href}
|
||||
/>
|
||||
<section className="space-y-4">
|
||||
<div className="relative grid min-h-[150px] overflow-hidden border-b border-border py-4 sm:grid-cols-[1fr_180px] sm:py-5">
|
||||
<div className="flex max-w-2xl flex-col justify-center gap-2">
|
||||
<Typography
|
||||
variant="h2"
|
||||
component="h1"
|
||||
className="leading-none tracking-[-0.045em] font-secondary font-semibold text-foreground text-2xl"
|
||||
>
|
||||
Poyraz{" "}
|
||||
<TextEffect
|
||||
effect="hand-drawn"
|
||||
tone="primary"
|
||||
className="tracking-[-0.04em]"
|
||||
>
|
||||
Avsever
|
||||
</TextEffect>
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="small"
|
||||
className="max-w-xl text-xs leading-5 text-muted-foreground sm:text-sm"
|
||||
>
|
||||
{t("heroDescription")}
|
||||
</Typography>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2 pt-1">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
radius="sm"
|
||||
effect="swap"
|
||||
swapTarget="both"
|
||||
onClick={() => router.push("/contact")}
|
||||
>
|
||||
<ButtonLabel>{t("hireMe")}</ButtonLabel>
|
||||
<ButtonIcon>
|
||||
<Icon icon="mdi:arrow-right" width={15} height={15} />
|
||||
</ButtonIcon>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
radius="sm"
|
||||
effect="swap"
|
||||
swapTarget="both"
|
||||
onClick={() => window.open(getResumeHref(locale), "_blank", "noopener,noreferrer")}
|
||||
>
|
||||
<ButtonIcon>
|
||||
<Icon icon="mdi:download" width={15} height={15} />
|
||||
</ButtonIcon>
|
||||
<ButtonLabel>{t("downloadCv")}</ButtonLabel>
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-none absolute right-0 bottom-0 hidden h-full w-44 overflow-hidden sm:block">
|
||||
<Image
|
||||
src="/images/hero1.png"
|
||||
alt="Poyraz Avsever"
|
||||
width={220}
|
||||
height={220}
|
||||
sizes="180px"
|
||||
priority
|
||||
className="absolute right-0 bottom-0 h-auto w-36 object-contain"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute right-0 bottom-0 h-px w-36 bg-border"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card className="grid grid-cols-[112px_1fr] items-stretch gap-2 rounded-sm border-border sm:grid-cols-[168px_1fr] md:h-full">
|
||||
<div className="flex flex-col justify-center gap-1 px-3 py-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<Typography variant="h2" className="leading-tight">
|
||||
Poyraz{" "}
|
||||
<span className="font-secondary text-red-600">Avsever</span>
|
||||
</Typography>
|
||||
</div>
|
||||
<Typography variant="small" className="text-xs leading-relaxed text-muted-foreground sm:text-sm">
|
||||
{t.rich("role", {
|
||||
strong: (chunks) => (
|
||||
<strong className="font-semibold text-foreground">{chunks}</strong>
|
||||
),
|
||||
})}
|
||||
<section className="space-y-3">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<Typography
|
||||
variant="h3"
|
||||
component="h2"
|
||||
className="tracking-[-0.035em]"
|
||||
>
|
||||
{t("readMyPosts")}
|
||||
</Typography>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
radius="sm"
|
||||
effect="swap"
|
||||
swapTarget="both"
|
||||
onClick={() => router.push("/blog")}
|
||||
>
|
||||
<ButtonLabel>{t("allPosts")}</ButtonLabel>
|
||||
<ButtonIcon>
|
||||
<Icon icon="mdi:arrow-right" width={15} height={15} />
|
||||
</ButtonIcon>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="relative h-full overflow-hidden">
|
||||
<div
|
||||
className="relative h-full w-full"
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<Image
|
||||
src={frame === 1 ? "/images/hero1.png" : "/images/hero2.png"}
|
||||
alt="Poyraz Avsever"
|
||||
width={240}
|
||||
height={240}
|
||||
sizes="(max-width: 768px) 80px, 192px"
|
||||
priority
|
||||
className="absolute right-0 bottom-0 h-auto w-20 object-contain md:w-48"
|
||||
/>
|
||||
<div className="relative overflow-hidden py-1">
|
||||
<div className="flex w-max items-stretch gap-3">
|
||||
{news.map((item) => (
|
||||
<NewsCard
|
||||
key={item.id}
|
||||
className="w-72 shrink-0 rounded-sm border-border"
|
||||
category={item.category}
|
||||
title={item.title}
|
||||
date={item.date}
|
||||
image={item.image}
|
||||
href={item.href}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute top-0 right-0 h-full w-24 bg-gradient-to-l from-background via-background/80 to-transparent"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</section>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ export function LanguageSwitcher() {
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
variant="glass"
|
||||
variant="secondary"
|
||||
size="icon-sm"
|
||||
radius="sm"
|
||||
onClick={toggleLanguage}
|
||||
className="min-w-9 cursor-pointer !border-border/80 text-xs font-semibold hover:!border-border focus-visible:!border-border"
|
||||
className="min-w-9 cursor-pointer text-xs font-semibold"
|
||||
aria-label={locale === "tr" ? "Switch to English" : "Türkçe'ye geç"}
|
||||
>
|
||||
{locale === "tr" ? "EN" : "TR"}
|
||||
|
||||
@@ -13,7 +13,7 @@ type ReferenceCardsProps = {
|
||||
export function ReferenceCards({ className, cardClassName, lineClamp }: ReferenceCardsProps) {
|
||||
const locale = useLocale();
|
||||
const hoverClassName =
|
||||
"transition-colors duration-200 group-hover:border-red-600/40 group-hover:bg-muted/30 group-hover:shadow-sm";
|
||||
"transition-colors duration-200 group-hover:border-red-600/40 group-hover:bg-muted/30";
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
@@ -27,7 +27,7 @@ export function ReferenceCards({ className, cardClassName, lineClamp }: Referenc
|
||||
role={getLocalizedValue(item.role, locale)}
|
||||
avatar={item.avatar}
|
||||
rating={item.rating}
|
||||
className={`flex flex-col rounded-sm ${lineClamp ? "[&_p]:line-clamp-3" : ""} ${hoverClassName} ${cardClassName || "w-70 shrink-0"}`}
|
||||
className={`flex flex-col rounded-sm ${lineClamp ? "[&_p]:line-clamp-4" : ""} ${hoverClassName} ${cardClassName || "w-70 shrink-0"}`}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,24 +1,55 @@
|
||||
"use client";
|
||||
|
||||
import { Icon } from "@iconify/react";
|
||||
import { ReferenceCards } from "@/components/reference-cards";
|
||||
import { useRouter } from "@/i18n/routing";
|
||||
import { Button, ButtonIcon, ButtonLabel, Typography } from "poyraz-ui/atoms";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export function ReferencesSection() {
|
||||
const t = useTranslations("Home");
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<section className="space-y-8 pt-0 sm:pt-12">
|
||||
<div className="relative overflow-hidden rounded-sm py-4">
|
||||
<section className="space-y-3 pt-0 sm:pt-8">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<Typography
|
||||
variant="h3"
|
||||
component="h2"
|
||||
className="tracking-[-0.035em]"
|
||||
>
|
||||
{t("reviewsAndReferences")}
|
||||
</Typography>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
radius="sm"
|
||||
effect="swap"
|
||||
swapTarget="both"
|
||||
onClick={() => router.push("/about/references")}
|
||||
>
|
||||
<ButtonLabel>{t("allReferences")}</ButtonLabel>
|
||||
<ButtonIcon>
|
||||
<Icon icon="mdi:arrow-right" width={15} height={15} />
|
||||
</ButtonIcon>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="relative overflow-hidden py-1">
|
||||
{/* We use two sets of cards for seamless infinite marquee effect */}
|
||||
<div className="flex items-start w-max gap-4 animate-marquee pause-on-hover">
|
||||
<div className="flex w-max items-start gap-4 animate-marquee pause-on-hover">
|
||||
<ReferenceCards className="flex items-start gap-4 shrink-0" lineClamp={true} cardClassName="w-80" />
|
||||
<ReferenceCards className="flex items-start gap-4 shrink-0" lineClamp={true} cardClassName="w-80" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute top-0 right-0 h-full w-32 bg-gradient-to-l from-white to-transparent"
|
||||
className="pointer-events-none absolute top-0 right-0 h-full w-32 bg-gradient-to-l from-background to-transparent"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute top-0 left-0 h-full w-32 bg-gradient-to-r from-white to-transparent"
|
||||
className="pointer-events-none absolute top-0 left-0 h-full w-32 bg-gradient-to-r from-background to-transparent"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
+18
-21
@@ -42,9 +42,6 @@ const SearchCommand = dynamic(
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
const glassActionClassName =
|
||||
"!border-border/80 hover:!border-border focus-visible:!border-border data-[state=open]:!border-border";
|
||||
|
||||
const slowShineClassName = "[--poyraz-motion-duration-deliberate:1100ms]";
|
||||
|
||||
function getNavLinkClass(isActive: boolean) {
|
||||
@@ -85,12 +82,12 @@ function ThemeToggle() {
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
variant="glass"
|
||||
variant="secondary"
|
||||
size="icon-sm"
|
||||
radius="sm"
|
||||
effect="shine"
|
||||
aria-label={label}
|
||||
className={`cursor-pointer ${glassActionClassName} ${slowShineClassName}`}
|
||||
className={`cursor-pointer ${slowShineClassName}`}
|
||||
onClick={() => setTheme(nextTheme)}
|
||||
>
|
||||
<Icon
|
||||
@@ -134,12 +131,12 @@ export function SiteNavbar() {
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
asChild
|
||||
variant="glass"
|
||||
variant="secondary"
|
||||
size="icon-sm"
|
||||
radius="sm"
|
||||
effect="shine"
|
||||
aria-label={label}
|
||||
className={`cursor-pointer ${glassActionClassName} ${slowShineClassName}`}
|
||||
className={`cursor-pointer ${slowShineClassName}`}
|
||||
>
|
||||
<a
|
||||
href={href}
|
||||
@@ -150,7 +147,7 @@ export function SiteNavbar() {
|
||||
</a>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" surface="glass" radius="sm" size="sm">
|
||||
<TooltipContent side="bottom" surface="soft" radius="sm" size="sm">
|
||||
{label}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
@@ -161,7 +158,7 @@ export function SiteNavbar() {
|
||||
<TooltipTrigger asChild>
|
||||
<LanguageSwitcher />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" surface="glass" radius="sm" size="sm">
|
||||
<TooltipContent side="bottom" surface="soft" radius="sm" size="sm">
|
||||
{languageLabel}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
@@ -170,7 +167,7 @@ export function SiteNavbar() {
|
||||
<TooltipTrigger asChild>
|
||||
<ThemeToggle />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" surface="glass" radius="sm" size="sm">
|
||||
<TooltipContent side="bottom" surface="soft" radius="sm" size="sm">
|
||||
{locale === "tr" ? "Tema değiştir" : "Toggle theme"}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
@@ -234,11 +231,11 @@ export function SiteNavbar() {
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="glass"
|
||||
variant="secondary"
|
||||
radius="sm"
|
||||
effect="shine"
|
||||
onClick={() => setSearchOpen(true)}
|
||||
className={`h-9 w-44 cursor-pointer justify-between px-3 text-sm sm:w-52 ${glassActionClassName} ${slowShineClassName}`}
|
||||
className={`h-9 w-44 cursor-pointer justify-between px-3 text-sm sm:w-52 ${slowShineClassName}`}
|
||||
aria-label={t("search")}
|
||||
>
|
||||
<ButtonIcon>
|
||||
@@ -252,10 +249,10 @@ export function SiteNavbar() {
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="glass"
|
||||
variant="secondary"
|
||||
radius="sm"
|
||||
effect="shine"
|
||||
className={`h-9 cursor-pointer ${glassActionClassName} ${slowShineClassName}`}
|
||||
className={`h-9 cursor-pointer ${slowShineClassName}`}
|
||||
>
|
||||
<ButtonIcon>
|
||||
<Icon icon="mdi:share-variant" width={16} height={16} />
|
||||
@@ -269,7 +266,7 @@ export function SiteNavbar() {
|
||||
radius="md"
|
||||
itemSize="md"
|
||||
itemRadius="sm"
|
||||
className="w-56 border-border bg-popover"
|
||||
className="w-56 bg-popover"
|
||||
>
|
||||
<DropdownMenuLabel>{t("socialLinks")}</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
@@ -293,11 +290,11 @@ export function SiteNavbar() {
|
||||
<div className="flex items-center gap-2 md:hidden">
|
||||
<Button
|
||||
type="button"
|
||||
variant="glass"
|
||||
variant="secondary"
|
||||
size="icon-sm"
|
||||
radius="sm"
|
||||
effect="shine"
|
||||
className={`cursor-pointer ${glassActionClassName} ${slowShineClassName}`}
|
||||
className={`cursor-pointer ${slowShineClassName}`}
|
||||
aria-label={t("search")}
|
||||
onClick={() => setSearchOpen(true)}
|
||||
>
|
||||
@@ -308,10 +305,10 @@ export function SiteNavbar() {
|
||||
<SheetTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="glass"
|
||||
variant="secondary"
|
||||
radius="sm"
|
||||
effect="shine"
|
||||
className={`h-9 cursor-pointer ${glassActionClassName} ${slowShineClassName}`}
|
||||
className={`h-9 cursor-pointer ${slowShineClassName}`}
|
||||
>
|
||||
<ButtonIcon>
|
||||
<Icon icon="mdi:menu" width={18} height={18} />
|
||||
@@ -325,11 +322,11 @@ export function SiteNavbar() {
|
||||
<SheetClose asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="glass"
|
||||
variant="secondary"
|
||||
radius="sm"
|
||||
effect="shine"
|
||||
onClick={() => setSearchOpen(true)}
|
||||
className={`w-full cursor-pointer justify-between ${glassActionClassName} ${slowShineClassName}`}
|
||||
className={`w-full cursor-pointer justify-between ${slowShineClassName}`}
|
||||
aria-label={t("search")}
|
||||
>
|
||||
<span className="inline-flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user