feat: Project dialog, updated screenshots, migration to bun
This commit is contained in:
126
app/page.js
126
app/page.js
@@ -3,10 +3,13 @@
|
||||
import React, { useState } from "react";
|
||||
import { useTranslations, useLocale } from "next-intl";
|
||||
import { Header } from "@/components/header";
|
||||
import { SiVk, SiTelegram, SiNextdotjs, SiTailwindcss, SiPostgresql, SiSupabase, SiReact, SiDocker, SiLinux, SiGo, SiPython, SiHtml5, SiJavascript, SiPhp, SiMaildotru, SiGmail, SiFacebook, SiTiktok, SiPrisma, SiMapbox } from "react-icons/si";
|
||||
import { SiVk, SiTelegram, SiPostgresql, SiReact, SiGo, SiHtml5, SiMaildotru, SiGmail, SiTiktok } from "react-icons/si";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { TriangleAlert } from "lucide-react";
|
||||
import ProjectDialog from "@/components/projectDialog";
|
||||
import { skillsList } from "@/lib/skillsList";
|
||||
import projectsData from "@/lib/projects.json";
|
||||
|
||||
export default function Main() {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
@@ -42,23 +45,6 @@ export default function Main() {
|
||||
},
|
||||
];
|
||||
|
||||
const skillsRunline = [
|
||||
{ name: "Next.js", icon: <SiNextdotjs /> },
|
||||
{ name: "Tailwind", icon: <SiTailwindcss /> },
|
||||
{ name: "Prisma", icon: <SiPrisma /> },
|
||||
{ name: "Postgres", icon: <SiPostgresql /> },
|
||||
{ name: "Supabase", icon: <SiSupabase /> },
|
||||
{ name: "React", icon: <SiReact /> },
|
||||
{ name: "Docker", icon: <SiDocker /> },
|
||||
{ name: "Linux", icon: <SiLinux /> },
|
||||
{ name: "HTML", icon: <SiHtml5 /> },
|
||||
{ name: "JS", icon: <SiJavascript /> },
|
||||
{ name: "Go", icon: <SiGo /> },
|
||||
{ name: "PHP", icon: <SiPhp /> },
|
||||
{ name: "Python", icon: <SiPython /> },
|
||||
{ name: "Mapbox", icon: <SiMapbox /> },
|
||||
];
|
||||
|
||||
const contacts = [
|
||||
{"icon": <SiTelegram />, "name": t("contact.contacts.0.name"), "username": "@rezcjikov", "url": "https://t.me/rezcjikov/"},
|
||||
{"icon": <SiMaildotru />, "name": t("contact.contacts.1.name"), "username": "rezcjikov@mail.ru", "url": "mailto:rezcjikov@mail.ru"},
|
||||
@@ -69,75 +55,38 @@ export default function Main() {
|
||||
|
||||
const languages = [
|
||||
{
|
||||
flag: "/img/flags/ru.png",
|
||||
flag: "/images/flags/ru.png",
|
||||
name: t("notOnlyCoding.languages.0.name"),
|
||||
level: t("notOnlyCoding.languages.0.level"),
|
||||
text: t("notOnlyCoding.languages.0.text")
|
||||
},
|
||||
{
|
||||
flag: "/img/flags/en.png",
|
||||
flag: "/images/flags/uk.png",
|
||||
name: t("notOnlyCoding.languages.1.name"),
|
||||
level: t("notOnlyCoding.languages.1.level"),
|
||||
text: t("notOnlyCoding.languages.1.text")
|
||||
},
|
||||
{
|
||||
flag: "/img/flags/it.png",
|
||||
flag: "/images/flags/it.png",
|
||||
name: t("notOnlyCoding.languages.2.name"),
|
||||
level: t("notOnlyCoding.languages.2.level"),
|
||||
text: t("notOnlyCoding.languages.2.text")
|
||||
},
|
||||
{
|
||||
flag: "/img/fi.png",
|
||||
flag: "/images/flags/fi.png",
|
||||
name: t("notOnlyCoding.languages.3.name"),
|
||||
level: t("notOnlyCoding.languages.3.level"),
|
||||
text: t("notOnlyCoding.languages.3.text")
|
||||
}
|
||||
];
|
||||
|
||||
const projects = [
|
||||
{
|
||||
screenshot: "/img/screenshots/duid/main.png",
|
||||
screenshotBg: "bg-gray-50",
|
||||
logo: "/img/coat_of_arms.png",
|
||||
logoAlt: t("projects.items.0.logoAlt"),
|
||||
title: t("projects.items.0.title"),
|
||||
url: "https://id.dusiburg.ru/",
|
||||
hostname: "id.dusiburg.ru",
|
||||
description: t("projects.items.0.description"),
|
||||
skills: ["Next.js", "Tailwind", "Postgres", "Supabase"]
|
||||
},
|
||||
{
|
||||
screenshot: "/img/screenshots/map.png",
|
||||
screenshotBg: "bg-zinc-700",
|
||||
logo: "/img/map.png",
|
||||
logoAlt: t("projects.items.1.logoAlt"),
|
||||
title: t("projects.items.1.title"),
|
||||
url: "https://map.dusiburg.ru/",
|
||||
hostname: "map.dusiburg.ru",
|
||||
description: t("projects.items.1.description"),
|
||||
skills: ["Next.js", "Tailwind", "Mapbox", "Postgres", "Supabase"]
|
||||
},
|
||||
{
|
||||
screenshot: "/img/screenshots/vote.png",
|
||||
screenshotBg: "bg-gray-50",
|
||||
logo: "/img/coat_of_arms.png",
|
||||
logoAlt: t("projects.items.2.logoAlt"),
|
||||
title: t("projects.items.2.title"),
|
||||
url: "https://vote.dusiburg.ru/",
|
||||
hostname: "vote.dusiburg.ru",
|
||||
description: t("projects.items.2.description"),
|
||||
skills: ["Next.js", "Tailwind", "Prisma", "Postgres", "Supabase"]
|
||||
},
|
||||
{
|
||||
screenshot: "/img/screenshots/fastlink.png",
|
||||
screenshotBg: "bg-zinc-800",
|
||||
logo: "/img/fastlink.png",
|
||||
logoAlt: t("projects.items.3.logoAlt"),
|
||||
title: t("projects.items.3.title"),
|
||||
description: t("projects.items.3.description"),
|
||||
skills: ["Next.js", "Tailwind", "Go", "Postgres", "Supabase"]
|
||||
}
|
||||
]
|
||||
const projects = projectsData.map(p => ({
|
||||
...p,
|
||||
logoAlt: t(p.logoAlt),
|
||||
title: t(p.title),
|
||||
description: t(p.description),
|
||||
text: t(p.text)
|
||||
}));
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -174,7 +123,7 @@ export default function Main() {
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
style={{ animationPlayState: isHovered ? "paused" : "running" }}
|
||||
>
|
||||
{[...skillsRunline.slice(0, 13), ...skillsRunline.slice(0, 13)].map((skill, index) => (
|
||||
{[...skillsList.slice(0, 13), ...skillsList.slice(0, 13)].map((skill, index) => (
|
||||
<div key={index} className="flex items-center gap-2 rounded-full bg-orange-500 text-white px-3 py-1 transition-all hover:scale-[1.08] cursor-default whitespace-nowrap">
|
||||
<div>{skill.icon}</div>
|
||||
<p>{skill.name}</p>
|
||||
@@ -215,32 +164,23 @@ export default function Main() {
|
||||
<h3>{t("projects.intro")}</h3>
|
||||
<div className="grid grid-cols-1 xl:grid-cols-3 gap-8">
|
||||
{projects.map((project, index) => (
|
||||
<div key={index} className="flex flex-col justify-between gap-4 p-2 rounded-xl bg-black/10 w-full max-w-lg transition-all hover:scale-[1.02] cursor-default">
|
||||
<div className={`w-full p-2 rounded-lg ${project.screenshotBg}`}>
|
||||
<Image className="rounded-md w-full h-auto" src={project.screenshot} width={500} height={50} alt={`${project.title} screenshot`} />
|
||||
</div>
|
||||
<div className="flex flex-col mx-1">
|
||||
<div className="flex gap-2 items-center flex-wrap">
|
||||
<Image src={project.logo} width={24} height={24} className="p-0.5 bg-white rounded-sm" alt={project.logoAlt} />
|
||||
<h3>{project.title}</h3>
|
||||
<ProjectDialog key={index} project={project}>
|
||||
<div key={index} className="flex flex-col justify-between gap-4 p-2 rounded-xl bg-black/10 w-full max-w-lg transition-all hover:scale-[1.02] cursor-default">
|
||||
<div className={`w-full p-2 rounded-lg ${project.screenshotBg}`}>
|
||||
<Image className="rounded-md w-full h-auto" src={project.screenshots[0]} width={500} height={50} alt={`${project.title} screenshot`} />
|
||||
</div>
|
||||
{project.url && project.hostname && (<Link href={project.url} target="_blank" className="text-blue-500 hover:text-blue-600 duration-200">
|
||||
<h4>{project.hostname}</h4>
|
||||
</Link>)}
|
||||
<div className="flex flex-col mx-1">
|
||||
<div className="flex gap-2 items-center flex-wrap">
|
||||
<Image src={project.logo} width={24} height={24} className="p-0.5 bg-white rounded-sm" alt={project.logoAlt} />
|
||||
<h3>{project.title}</h3>
|
||||
</div>
|
||||
{project.url && project.hostname && (<Link href={project.url} target="_blank" className="w-max text-blue-500 hover:text-blue-600 duration-200">
|
||||
<h4>{project.hostname}</h4>
|
||||
</Link>)}
|
||||
</div>
|
||||
<h4 className="mx-1">{project.description}</h4>
|
||||
</div>
|
||||
<h4 className="mx-1">{project.description}</h4>
|
||||
<div className="flex flex-wrap gap-2 items-center">
|
||||
{project.skills.map((skillName, idx) => {
|
||||
const skill = skillsRunline.find(s => s.name === skillName);
|
||||
return skill ? (
|
||||
<div key={idx} className="flex items-center gap-2 rounded-full bg-white px-2 xl:px-3 py-1">
|
||||
{skill.icon}
|
||||
<h6>{skill.name}</h6>
|
||||
</div>
|
||||
) : null;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</ProjectDialog>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
@@ -251,7 +191,7 @@ export default function Main() {
|
||||
<div className="flex flex-col gap-8">
|
||||
{languages.map((language, index) => (
|
||||
<div key={index} className={`flex flex-col xl:flex-row gap-16 items-center p-3 xl:p-6 rounded-2xl transition-all hover:scale-[1.02] ${index % 2 === 1 ? "xl:flex-row-reverse bg-pink-100" : "bg-fuchsia-100"} cursor-default`}>
|
||||
<Image src={language.flag} width={200} height={200} className={`w-36 h-36 rounded-lg ${index % 2 === 1 ? "rotate-2" : "-rotate-2"}`} alt={`Flag #${index}`} />
|
||||
<Image src={language.flag} width={200} height={200} className={`w-36 h-36 rounded-lg ${index % 2 === 1 ? "rotate-2" : "-rotate-2"}`} alt={`Flag #${index+1}`} />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex gap-4 items-center">
|
||||
<h2>{language.name}</h2>
|
||||
@@ -284,7 +224,7 @@ export default function Main() {
|
||||
<div className="flex flex-wrap gap-3 mt-8">
|
||||
<p className="text-white/60 mr-2">{t("contact.remember")}</p>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{skillsRunline.slice(0, 6).map((skill, index) => (
|
||||
{skillsList.slice(0, 6).map((skill, index) => (
|
||||
<div key={index} className="flex items-center gap-2 rounded-full bg-white/20 px-2 xl:px-3 py-1">
|
||||
<div className="text-white">{skill.icon}</div>
|
||||
<h6>{skill.name}</h6>
|
||||
|
||||
Reference in New Issue
Block a user