feat(projects): add OSTIM portals and stack popovers
This commit is contained in:
@@ -3,13 +3,14 @@
|
|||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { useLocale, useTranslations } from "next-intl";
|
import { useLocale, useTranslations } from "next-intl";
|
||||||
import { Button, ButtonIcon, ButtonLabel, Typography } from "poyraz-ui/atoms";
|
import { Button, ButtonIcon, ButtonLabel, Typography } from "poyraz-ui/atoms";
|
||||||
import { ImageCard } from "poyraz-ui/molecules";
|
|
||||||
import { useRouter } from "@/i18n/routing";
|
import { useRouter } from "@/i18n/routing";
|
||||||
import { WEB_APPS } from "@/data/projects";
|
import { WEB_APPS } from "@/data/projects";
|
||||||
import { getLocalizedValue } from "@/lib/locale";
|
import { getLocalizedValue } from "@/lib/locale";
|
||||||
|
import { ProjectCardWithPopover } from "@/components/project-card-with-popover";
|
||||||
|
|
||||||
export function HomeProjectsSection() {
|
export function HomeProjectsSection() {
|
||||||
const t = useTranslations("Home");
|
const t = useTranslations("Home");
|
||||||
|
const tProjects = useTranslations("Projects");
|
||||||
const locale = useLocale();
|
const locale = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const projects = WEB_APPS.slice(0, 5);
|
const projects = WEB_APPS.slice(0, 5);
|
||||||
@@ -43,7 +44,7 @@ export function HomeProjectsSection() {
|
|||||||
<div className="relative overflow-hidden py-1">
|
<div className="relative overflow-hidden py-1">
|
||||||
<div className="flex w-max items-stretch gap-2">
|
<div className="flex w-max items-stretch gap-2">
|
||||||
{projects.map((project) => (
|
{projects.map((project) => (
|
||||||
<ImageCard
|
<ProjectCardWithPopover
|
||||||
key={project.id}
|
key={project.id}
|
||||||
image={project.image}
|
image={project.image}
|
||||||
title={project.title}
|
title={project.title}
|
||||||
@@ -54,6 +55,10 @@ export function HomeProjectsSection() {
|
|||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
href={project.href}
|
href={project.href}
|
||||||
|
technologies={project.technologies}
|
||||||
|
architecture={getLocalizedValue(project.architecture, locale)}
|
||||||
|
technologiesLabel={tProjects("technologies")}
|
||||||
|
architectureLabel={tProjects("architecture")}
|
||||||
className="aspect-square w-56 shrink-0 rounded-sm border-border md:w-[calc((100vw-8rem)/4)] md:max-w-56"
|
className="aspect-square w-56 shrink-0 rounded-sm border-border md:w-[calc((100vw-8rem)/4)] md:max-w-56"
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { Badge, Typography } from "poyraz-ui/atoms";
|
||||||
|
import {
|
||||||
|
ImageCard,
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "poyraz-ui/molecules";
|
||||||
|
|
||||||
|
type ProjectCardWithPopoverProps = {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
image: string;
|
||||||
|
badge?: string;
|
||||||
|
href?: string;
|
||||||
|
technologies: string[];
|
||||||
|
architecture: string;
|
||||||
|
technologiesLabel: string;
|
||||||
|
architectureLabel: string;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ProjectCardWithPopover({
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
image,
|
||||||
|
badge,
|
||||||
|
href,
|
||||||
|
technologies,
|
||||||
|
architecture,
|
||||||
|
technologiesLabel,
|
||||||
|
architectureLabel,
|
||||||
|
className,
|
||||||
|
}: ProjectCardWithPopoverProps) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const closeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
|
|
||||||
|
const cancelClose = () => {
|
||||||
|
if (closeTimer.current) {
|
||||||
|
clearTimeout(closeTimer.current);
|
||||||
|
closeTimer.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const showPopover = () => {
|
||||||
|
cancelClose();
|
||||||
|
setOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const scheduleClose = () => {
|
||||||
|
cancelClose();
|
||||||
|
closeTimer.current = setTimeout(() => setOpen(false), 120);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (closeTimer.current) clearTimeout(closeTimer.current);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const card = (
|
||||||
|
<ImageCard
|
||||||
|
image={image}
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
badge={badge}
|
||||||
|
className={className}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover open={open} onOpenChange={setOpen}>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
{href ? (
|
||||||
|
<a
|
||||||
|
href={href}
|
||||||
|
className="block text-inherit no-underline outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||||
|
onPointerEnter={showPopover}
|
||||||
|
onPointerLeave={scheduleClose}
|
||||||
|
onFocus={showPopover}
|
||||||
|
onBlur={scheduleClose}
|
||||||
|
>
|
||||||
|
{card}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="block border-0 bg-transparent p-0 text-left text-inherit outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||||
|
onPointerEnter={showPopover}
|
||||||
|
onPointerLeave={scheduleClose}
|
||||||
|
onFocus={showPopover}
|
||||||
|
onBlur={scheduleClose}
|
||||||
|
>
|
||||||
|
{card}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</PopoverTrigger>
|
||||||
|
|
||||||
|
<PopoverContent
|
||||||
|
side="top"
|
||||||
|
align="center"
|
||||||
|
sideOffset={10}
|
||||||
|
radius="sm"
|
||||||
|
padding="sm"
|
||||||
|
className="w-80 max-w-[calc(100vw-1rem)]"
|
||||||
|
onPointerEnter={showPopover}
|
||||||
|
onPointerLeave={scheduleClose}
|
||||||
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||||
|
onCloseAutoFocus={(event) => event.preventDefault()}
|
||||||
|
>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<Typography variant="large" className="text-sm leading-tight">
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Typography
|
||||||
|
variant="small"
|
||||||
|
className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground"
|
||||||
|
>
|
||||||
|
{technologiesLabel}
|
||||||
|
</Typography>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{technologies.map((technology) => (
|
||||||
|
<Badge key={technology} size="sm" variant="outline" className="rounded-sm">
|
||||||
|
{technology}
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-1">
|
||||||
|
<Typography
|
||||||
|
variant="small"
|
||||||
|
className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground"
|
||||||
|
>
|
||||||
|
{architectureLabel}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="small" className="text-xs leading-relaxed text-muted-foreground">
|
||||||
|
{architecture}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -9,8 +9,8 @@ import {
|
|||||||
Card,
|
Card,
|
||||||
Typography,
|
Typography,
|
||||||
} from "poyraz-ui/atoms";
|
} from "poyraz-ui/atoms";
|
||||||
import { ImageCard } from "poyraz-ui/molecules";
|
|
||||||
import { StaggerContainer, StaggerItem } from "@/components/motion-wrapper";
|
import { StaggerContainer, StaggerItem } from "@/components/motion-wrapper";
|
||||||
|
import { ProjectCardWithPopover } from "@/components/project-card-with-popover";
|
||||||
import {
|
import {
|
||||||
EXTENSIONS,
|
EXTENSIONS,
|
||||||
FIGMA_TEMPLATES,
|
FIGMA_TEMPLATES,
|
||||||
@@ -64,6 +64,8 @@ type LocalizedProjectItem = {
|
|||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
image: string;
|
image: string;
|
||||||
|
technologies: string[];
|
||||||
|
architecture: string;
|
||||||
badge?: string;
|
badge?: string;
|
||||||
href?: string;
|
href?: string;
|
||||||
};
|
};
|
||||||
@@ -71,9 +73,13 @@ type LocalizedProjectItem = {
|
|||||||
function ProjectSection({
|
function ProjectSection({
|
||||||
title,
|
title,
|
||||||
items,
|
items,
|
||||||
|
technologiesLabel,
|
||||||
|
architectureLabel,
|
||||||
}: {
|
}: {
|
||||||
title: string;
|
title: string;
|
||||||
items: LocalizedProjectItem[];
|
items: LocalizedProjectItem[];
|
||||||
|
technologiesLabel: string;
|
||||||
|
architectureLabel: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<section className="space-y-3">
|
<section className="space-y-3">
|
||||||
@@ -83,12 +89,16 @@ function ProjectSection({
|
|||||||
<StaggerContainer className="grid grid-cols-2 gap-2 lg:grid-cols-4">
|
<StaggerContainer className="grid grid-cols-2 gap-2 lg:grid-cols-4">
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<StaggerItem key={item.id}>
|
<StaggerItem key={item.id}>
|
||||||
<ImageCard
|
<ProjectCardWithPopover
|
||||||
image={item.image}
|
image={item.image}
|
||||||
title={item.title}
|
title={item.title}
|
||||||
description={item.description}
|
description={item.description}
|
||||||
badge={item.badge}
|
badge={item.badge}
|
||||||
href={item.href}
|
href={item.href}
|
||||||
|
technologies={item.technologies}
|
||||||
|
architecture={item.architecture}
|
||||||
|
technologiesLabel={technologiesLabel}
|
||||||
|
architectureLabel={architectureLabel}
|
||||||
className="aspect-square rounded-sm border-border"
|
className="aspect-square rounded-sm border-border"
|
||||||
/>
|
/>
|
||||||
</StaggerItem>
|
</StaggerItem>
|
||||||
@@ -111,6 +121,7 @@ export async function ProjectsContent() {
|
|||||||
return items.map((item) => ({
|
return items.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
description: getLocalizedValue(item.description, locale),
|
description: getLocalizedValue(item.description, locale),
|
||||||
|
architecture: getLocalizedValue(item.architecture, locale),
|
||||||
badge: item.badge ? getLocalizedValue(item.badge, locale) : undefined,
|
badge: item.badge ? getLocalizedValue(item.badge, locale) : undefined,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
@@ -130,10 +141,30 @@ export async function ProjectsContent() {
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<ProjectSection title={t("sections.mobileApps")} items={localizeItems(MOBILE_APPS)} />
|
<ProjectSection
|
||||||
<ProjectSection title={t("sections.webApps")} items={localizeItems(WEB_APPS)} />
|
title={t("sections.webApps")}
|
||||||
<ProjectSection title={t("sections.extensions")} items={localizeItems(EXTENSIONS)} />
|
items={localizeItems(WEB_APPS)}
|
||||||
<ProjectSection title={t("sections.figmaTemplates")} items={localizeItems(FIGMA_TEMPLATES)} />
|
technologiesLabel={t("technologies")}
|
||||||
|
architectureLabel={t("architecture")}
|
||||||
|
/>
|
||||||
|
<ProjectSection
|
||||||
|
title={t("sections.mobileApps")}
|
||||||
|
items={localizeItems(MOBILE_APPS)}
|
||||||
|
technologiesLabel={t("technologies")}
|
||||||
|
architectureLabel={t("architecture")}
|
||||||
|
/>
|
||||||
|
<ProjectSection
|
||||||
|
title={t("sections.extensions")}
|
||||||
|
items={localizeItems(EXTENSIONS)}
|
||||||
|
technologiesLabel={t("technologies")}
|
||||||
|
architectureLabel={t("architecture")}
|
||||||
|
/>
|
||||||
|
<ProjectSection
|
||||||
|
title={t("sections.figmaTemplates")}
|
||||||
|
items={localizeItems(FIGMA_TEMPLATES)}
|
||||||
|
technologiesLabel={t("technologies")}
|
||||||
|
architectureLabel={t("architecture")}
|
||||||
|
/>
|
||||||
|
|
||||||
<section className="space-y-3">
|
<section className="space-y-3">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ export type ProjectItem = {
|
|||||||
en: string;
|
en: string;
|
||||||
};
|
};
|
||||||
image: string;
|
image: string;
|
||||||
|
technologies: string[];
|
||||||
|
architecture: {
|
||||||
|
tr: string;
|
||||||
|
en: string;
|
||||||
|
};
|
||||||
badge?: {
|
badge?: {
|
||||||
tr: string;
|
tr: string;
|
||||||
en: string;
|
en: string;
|
||||||
@@ -19,6 +24,11 @@ export const MOBILE_APPS: ProjectItem[] = [
|
|||||||
title: "Targiz App",
|
title: "Targiz App",
|
||||||
badge: "Agritech",
|
badge: "Agritech",
|
||||||
image: "/projects/targiz.png",
|
image: "/projects/targiz.png",
|
||||||
|
technologies: ["Next.js", "Supabase"],
|
||||||
|
architecture: {
|
||||||
|
tr: "Atomic Design yaklaşımıyla oluşturulmuş, Supabase tabanlı modüler uygulama mimarisi.",
|
||||||
|
en: "A modular, Supabase-backed application architecture built with the Atomic Design approach.",
|
||||||
|
},
|
||||||
href: "https://targiz.com",
|
href: "https://targiz.com",
|
||||||
description: {
|
description: {
|
||||||
tr: "Ottoqua ekibiyle birlikte geliştirdiğimiz, küçük ölçekli üreticilere sahada destek veren yapay zeka destekli tarım uygulaması.",
|
tr: "Ottoqua ekibiyle birlikte geliştirdiğimiz, küçük ölçekli üreticilere sahada destek veren yapay zeka destekli tarım uygulaması.",
|
||||||
@@ -27,7 +37,70 @@ export const MOBILE_APPS: ProjectItem[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const OSTIM_TECHNOLOGIES = [
|
||||||
|
".NET 10",
|
||||||
|
"Angular",
|
||||||
|
"Astro",
|
||||||
|
"Own UI Kit",
|
||||||
|
"OMD UI Kit",
|
||||||
|
"Tailwind CSS",
|
||||||
|
];
|
||||||
|
|
||||||
export const WEB_APPS: ProjectItem[] = [
|
export const WEB_APPS: ProjectItem[] = [
|
||||||
|
{
|
||||||
|
id: "ostim-web-portal",
|
||||||
|
title: "OSTİM Web Portalı",
|
||||||
|
badge: {
|
||||||
|
tr: "Kurumsal Portal",
|
||||||
|
en: "Corporate Portal",
|
||||||
|
},
|
||||||
|
image: "/projects/ostim.png",
|
||||||
|
technologies: OSTIM_TECHNOLOGIES,
|
||||||
|
architecture: {
|
||||||
|
tr: "OSTİM Organize Sanayi Bölgesi ve yedi kümeye ait kurumsal içerikleri, firma ve ürün aramasını, çevrim içi işlemleri ve iletişim akışlarını tek portalda birleştiren çok bölümlü yapı.",
|
||||||
|
en: "A multi-section architecture combining corporate content for OSTİM Organized Industrial Zone and its seven clusters with company and product search, online services, and communication flows in one portal.",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
tr: "OSTİM Organize Sanayi Bölgesi ve yedi kümesi için geliştirdiğimiz kapsamlı kurumsal web portalı.",
|
||||||
|
en: "A comprehensive corporate web portal we developed for OSTİM Organized Industrial Zone and its seven clusters.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ostim-employment",
|
||||||
|
title: "OSTİM İstihdam",
|
||||||
|
badge: {
|
||||||
|
tr: "İstihdam Portalı",
|
||||||
|
en: "Employment Portal",
|
||||||
|
},
|
||||||
|
image: "/projects/ostim-istihdam.png",
|
||||||
|
technologies: OSTIM_TECHNOLOGIES,
|
||||||
|
architecture: {
|
||||||
|
tr: "İŞKUR senkronizasyonu üzerine kurulu; aday, işveren, iş ve staj ilanı akışlarını yapay zekâ destekli eşleştirme katmanıyla buluşturan rol tabanlı portal mimarisi.",
|
||||||
|
en: "A role-based portal architecture built around İŞKUR synchronization, connecting candidate, employer, job, and internship workflows through an AI-assisted matching layer.",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
tr: "İŞKUR ile senkron çalışan, adayları iş ve staj fırsatlarıyla buluşturan istihdam portalı.",
|
||||||
|
en: "An employment portal synchronized with İŞKUR that connects candidates with job and internship opportunities.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ostim-foreign-trade",
|
||||||
|
title: "OSTİM Dış Ticaret",
|
||||||
|
badge: {
|
||||||
|
tr: "Dış Ticaret Portalı",
|
||||||
|
en: "Foreign Trade Portal",
|
||||||
|
},
|
||||||
|
image: "/projects/ostim-dis-ticaret.png",
|
||||||
|
technologies: OSTIM_TECHNOLOGIES,
|
||||||
|
architecture: {
|
||||||
|
tr: "Dış ticaret firmaları, ilanlar ve yabancı dil bilen öğrenciler için ayrı kayıt ve başvuru akışlarını ortak bir eşleştirme ve ilan havuzunda birleştiren çok taraflı portal mimarisi.",
|
||||||
|
en: "A multi-sided portal architecture that brings registration and application flows for foreign-trade companies, listings, and multilingual students into a shared matching and opportunity pool.",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
tr: "Dış ticaret yapan firmaları yabancı dil bilen öğrencilerle buluşturmaya odaklanan portal.",
|
||||||
|
en: "A portal focused on matching foreign-trade companies with students who speak foreign languages.",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "arc-foreign-trade",
|
id: "arc-foreign-trade",
|
||||||
title: "ARC Foreign Trade",
|
title: "ARC Foreign Trade",
|
||||||
@@ -36,6 +109,11 @@ export const WEB_APPS: ProjectItem[] = [
|
|||||||
en: "Freelance",
|
en: "Freelance",
|
||||||
},
|
},
|
||||||
image: "/projects/arc.png",
|
image: "/projects/arc.png",
|
||||||
|
technologies: ["Wix"],
|
||||||
|
architecture: {
|
||||||
|
tr: "Wix üzerinde yönetilebilir içerik ve kurumsal tanıtım sayfalarından oluşan, ihracat odaklı web sitesi yapısı.",
|
||||||
|
en: "An export-focused website architecture built on Wix with manageable content and corporate presentation pages.",
|
||||||
|
},
|
||||||
href: "https://arcforeigntrade.com",
|
href: "https://arcforeigntrade.com",
|
||||||
description: {
|
description: {
|
||||||
tr: "Ankara merkezli ihracat odaklı bir üretici firma için kurumsal web sitesi yenileme projesi.",
|
tr: "Ankara merkezli ihracat odaklı bir üretici firma için kurumsal web sitesi yenileme projesi.",
|
||||||
@@ -50,6 +128,11 @@ export const WEB_APPS: ProjectItem[] = [
|
|||||||
en: "Open Source",
|
en: "Open Source",
|
||||||
},
|
},
|
||||||
image: "/projects/ataturk.png",
|
image: "/projects/ataturk.png",
|
||||||
|
technologies: ["React"],
|
||||||
|
architecture: {
|
||||||
|
tr: "React ile geliştirilen, kronoloji verisini etkileşimli bir zaman çizelgesi arayüzünde sunan istemci taraflı uygulama.",
|
||||||
|
en: "A client-side React application presenting chronology data through an interactive timeline interface.",
|
||||||
|
},
|
||||||
href: "https://ataturk-kronolojisi.org",
|
href: "https://ataturk-kronolojisi.org",
|
||||||
description: {
|
description: {
|
||||||
tr: "Atatürk’ün hayatındaki önemli olayları, konuşmaları ve reformları etkileşimli bir zaman çizelgesiyle sunan web deneyimi.",
|
tr: "Atatürk’ün hayatındaki önemli olayları, konuşmaları ve reformları etkileşimli bir zaman çizelgesiyle sunan web deneyimi.",
|
||||||
@@ -64,6 +147,11 @@ export const WEB_APPS: ProjectItem[] = [
|
|||||||
en: "Open Source",
|
en: "Open Source",
|
||||||
},
|
},
|
||||||
image: "/projects/mockup.png",
|
image: "/projects/mockup.png",
|
||||||
|
technologies: ["Next.js"],
|
||||||
|
architecture: {
|
||||||
|
tr: "Next.js tabanlı, görsel işleme akışını tamamen tarayıcıda çalıştıran istemci öncelikli araç mimarisi.",
|
||||||
|
en: "A client-first Next.js tool architecture that runs its image-processing workflow entirely in the browser.",
|
||||||
|
},
|
||||||
href: "https://mockup-factory-mu.vercel.app/",
|
href: "https://mockup-factory-mu.vercel.app/",
|
||||||
description: {
|
description: {
|
||||||
tr: "Görsellerin cihaz mockup’larına saniyeler içinde dönüştürüldüğü, tamamen tarayıcı üzerinde çalışan açık kaynak araç.",
|
tr: "Görsellerin cihaz mockup’larına saniyeler içinde dönüştürüldüğü, tamamen tarayıcı üzerinde çalışan açık kaynak araç.",
|
||||||
@@ -78,6 +166,11 @@ export const WEB_APPS: ProjectItem[] = [
|
|||||||
en: "Open Source",
|
en: "Open Source",
|
||||||
},
|
},
|
||||||
image: "/projects/ohhike.png",
|
image: "/projects/ohhike.png",
|
||||||
|
technologies: ["React", "Express.js", "Better Auth", "better-sqlite3"],
|
||||||
|
architecture: {
|
||||||
|
tr: "Landing page, uygulama ve API katmanlarını aynı çalışma alanında yöneten; React arayüzü ve Express API'sinden oluşan monorepo.",
|
||||||
|
en: "A monorepo managing the landing page, application, and API in one workspace, with a React interface and Express API.",
|
||||||
|
},
|
||||||
href: "https://www.ohhike.com",
|
href: "https://www.ohhike.com",
|
||||||
description: {
|
description: {
|
||||||
tr: "Spor takımları için açık kaynaklı, yapay zekâ destekli antrenörlük zekâ platformu. OhHike CoachOS; sporcu check-in'lerini, antrenman notlarını, akıllı saat verilerini ve antrenman geçmişini aksiyona geçirilebilir bir takım hafızasına dönüştürür.",
|
tr: "Spor takımları için açık kaynaklı, yapay zekâ destekli antrenörlük zekâ platformu. OhHike CoachOS; sporcu check-in'lerini, antrenman notlarını, akıllı saat verilerini ve antrenman geçmişini aksiyona geçirilebilir bir takım hafızasına dönüştürür.",
|
||||||
@@ -92,6 +185,11 @@ export const WEB_APPS: ProjectItem[] = [
|
|||||||
en: "Open Source",
|
en: "Open Source",
|
||||||
},
|
},
|
||||||
image: "/projects/neta.png",
|
image: "/projects/neta.png",
|
||||||
|
technologies: ["Next.js", "Express.js"],
|
||||||
|
architecture: {
|
||||||
|
tr: "Landing page, uygulama ve API paketlerini birlikte yöneten Next.js ve Express.js tabanlı monorepo mimarisi.",
|
||||||
|
en: "A Next.js and Express.js monorepo architecture managing landing page, application, and API packages together.",
|
||||||
|
},
|
||||||
href: "https://www.takeneta.com",
|
href: "https://www.takeneta.com",
|
||||||
description: {
|
description: {
|
||||||
tr: "Dijital ikinci beyniniz. Bilinçli üretkenlik ve yaşam takibi için hepsi bir arada kişisel işletim sistemi. Yerel öncelikli, yapay zekâ entegrasyonlu ve açık kaynaklı.",
|
tr: "Dijital ikinci beyniniz. Bilinçli üretkenlik ve yaşam takibi için hepsi bir arada kişisel işletim sistemi. Yerel öncelikli, yapay zekâ entegrasyonlu ve açık kaynaklı.",
|
||||||
@@ -109,6 +207,11 @@ export const EXTENSIONS: ProjectItem[] = [
|
|||||||
en: "Cross-Browser",
|
en: "Cross-Browser",
|
||||||
},
|
},
|
||||||
image: "/projects/quick-fill.png",
|
image: "/projects/quick-fill.png",
|
||||||
|
technologies: ["JavaScript"],
|
||||||
|
architecture: {
|
||||||
|
tr: "Tarayıcı eklentisi API'leriyle çalışan, kısayol tanımlarını form alanlarına bağlayan çapraz tarayıcı JavaScript yapısı.",
|
||||||
|
en: "A cross-browser JavaScript extension architecture that connects shortcut definitions to form fields through browser extension APIs.",
|
||||||
|
},
|
||||||
href: "https://github.com/poyrazavsever/shortcut-injector",
|
href: "https://github.com/poyrazavsever/shortcut-injector",
|
||||||
description: {
|
description: {
|
||||||
tr: "Özel klavye kısayollarını kullanarak önceden tanımlanmış kişisel verileri ve bağlantıları web formlarına hızlıca enjekte etmek için geliştirilmiş bir tarayıcı eklentisi.",
|
tr: "Özel klavye kısayollarını kullanarak önceden tanımlanmış kişisel verileri ve bağlantıları web formlarına hızlıca enjekte etmek için geliştirilmiş bir tarayıcı eklentisi.",
|
||||||
@@ -123,6 +226,11 @@ export const EXTENSIONS: ProjectItem[] = [
|
|||||||
en: "Cross-Browser",
|
en: "Cross-Browser",
|
||||||
},
|
},
|
||||||
image: "/projects/sound_sync.png",
|
image: "/projects/sound_sync.png",
|
||||||
|
technologies: ["JavaScript"],
|
||||||
|
architecture: {
|
||||||
|
tr: "Sekmelerin medya durumlarını izleyip oynatma komutlarını ileten olay tabanlı, çapraz tarayıcı eklenti mimarisi.",
|
||||||
|
en: "An event-driven, cross-browser extension architecture that observes media state across tabs and relays playback commands.",
|
||||||
|
},
|
||||||
href: "https://github.com/poyrazavsever/tab-audio-relay",
|
href: "https://github.com/poyrazavsever/tab-audio-relay",
|
||||||
description: {
|
description: {
|
||||||
tr: "Sekmeler arasındaki ses çalma işlemlerini senkronize eden bir tarayıcı eklentisi. Eğitim videonuz durduğunda müziğinizi otomatik olarak oynatır, eğitime devam ettiğinizde ise müziği duraklatır.",
|
tr: "Sekmeler arasındaki ses çalma işlemlerini senkronize eden bir tarayıcı eklentisi. Eğitim videonuz durduğunda müziğinizi otomatik olarak oynatır, eğitime devam ettiğinizde ise müziği duraklatır.",
|
||||||
@@ -137,6 +245,11 @@ export const FIGMA_TEMPLATES: ProjectItem[] = [
|
|||||||
title: "HSD Community Web Site",
|
title: "HSD Community Web Site",
|
||||||
badge: "Figma",
|
badge: "Figma",
|
||||||
image: "/projects/hsd.png",
|
image: "/projects/hsd.png",
|
||||||
|
technologies: ["Figma"],
|
||||||
|
architecture: {
|
||||||
|
tr: "Bileşenler, kontrol paneli, açılış sayfası ve profil ekranlarını doğrudan Figma içinde düzenleyen bileşen tabanlı tasarım dosyası.",
|
||||||
|
en: "A component-based design file organized directly in Figma across components, dashboard, landing page, and profile screens.",
|
||||||
|
},
|
||||||
href: "https://www.figma.com/community/file/1613511833232376739",
|
href: "https://www.figma.com/community/file/1613511833232376739",
|
||||||
description: {
|
description: {
|
||||||
tr: "HSD Community için Web Site tasarımı. Bileşenler, kontrol paneli, açılış sayfası, profil sayfaları.",
|
tr: "HSD Community için Web Site tasarımı. Bileşenler, kontrol paneli, açılış sayfası, profil sayfaları.",
|
||||||
@@ -148,6 +261,11 @@ export const FIGMA_TEMPLATES: ProjectItem[] = [
|
|||||||
title: "Restaurant Menu UI Design",
|
title: "Restaurant Menu UI Design",
|
||||||
badge: "Figma",
|
badge: "Figma",
|
||||||
image: "/projects/menu.png",
|
image: "/projects/menu.png",
|
||||||
|
technologies: ["Figma"],
|
||||||
|
architecture: {
|
||||||
|
tr: "Tekrar kullanılabilir arayüz parçaları ve menü varyasyonlarından oluşan, doğrudan Figma üzerinde hazırlanan tasarım şablonu.",
|
||||||
|
en: "A design template created directly in Figma with reusable interface elements and menu variants.",
|
||||||
|
},
|
||||||
href: "https://www.figma.com/community/file/1613577450975840169/restaurant-menu-ui-design",
|
href: "https://www.figma.com/community/file/1613577450975840169/restaurant-menu-ui-design",
|
||||||
description: {
|
description: {
|
||||||
tr: "Topluluk için Restaurant Menü Arayüz Tasarımı şablonu.",
|
tr: "Topluluk için Restaurant Menü Arayüz Tasarımı şablonu.",
|
||||||
|
|||||||
@@ -64,6 +64,8 @@
|
|||||||
},
|
},
|
||||||
"viewNpmPackages": "View my NPM packages",
|
"viewNpmPackages": "View my NPM packages",
|
||||||
"visitGithub": "Visit my GitHub profile",
|
"visitGithub": "Visit my GitHub profile",
|
||||||
|
"technologies": "Technologies",
|
||||||
|
"architecture": "Architecture",
|
||||||
"emptyNpm": "npm API response is currently empty.",
|
"emptyNpm": "npm API response is currently empty.",
|
||||||
"emptyGithub": "GitHub API response is currently empty."
|
"emptyGithub": "GitHub API response is currently empty."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -64,6 +64,8 @@
|
|||||||
},
|
},
|
||||||
"viewNpmPackages": "NPM paketlerimi gör",
|
"viewNpmPackages": "NPM paketlerimi gör",
|
||||||
"visitGithub": "GitHub hesabına git",
|
"visitGithub": "GitHub hesabına git",
|
||||||
|
"technologies": "Teknolojiler",
|
||||||
|
"architecture": "Mimari",
|
||||||
"emptyNpm": "npm API yanıtı şu anda boş.",
|
"emptyNpm": "npm API yanıtı şu anda boş.",
|
||||||
"emptyGithub": "GitHub API yanıtı şu anda boş."
|
"emptyGithub": "GitHub API yanıtı şu anda boş."
|
||||||
},
|
},
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 774 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 512 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 537 KiB |
Reference in New Issue
Block a user