first commit
This commit is contained in:
BIN
app/favicon.ico
Normal file
BIN
app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
176
app/globals.css
Normal file
176
app/globals.css
Normal file
@@ -0,0 +1,176 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
|
||||
--font-sans: var(--font-nunito);
|
||||
--font-risha: var(--font-risha);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
}
|
||||
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
--header-height: 2rem;
|
||||
--spacing-section: 4rem;
|
||||
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-padding-top: var(--header-height);
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground font-sans font-bold min-h-screen;
|
||||
}
|
||||
|
||||
main > section:first-child {
|
||||
padding-top: calc(var(--header-height) + 2.25rem);
|
||||
}
|
||||
|
||||
main > section:not(:first-child) {
|
||||
padding-top: 2.25rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-2xl;
|
||||
font-family: var(--font-risha);
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply text-3xl;
|
||||
font-family: var(--font-risha);
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-lg leading-6.5;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply text-lg;
|
||||
}
|
||||
|
||||
h5 {
|
||||
@apply text-base;
|
||||
}
|
||||
|
||||
h6 {
|
||||
@apply text-xs;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-sm;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes marquee {
|
||||
from { transform: translateX(0); }
|
||||
to { transform: translateX(-50%); }
|
||||
}
|
||||
|
||||
@keyframes wave {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-6px); }
|
||||
}
|
||||
|
||||
.animate-marquee {
|
||||
animation: marquee 10s linear infinite;
|
||||
}
|
||||
|
||||
.animate-wave {
|
||||
display: inline-block;
|
||||
animation: wave 1.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@media (width >= 80rem) {
|
||||
:root {
|
||||
--header-height: 7rem;
|
||||
}
|
||||
|
||||
.animate-marquee {
|
||||
animation-duration: 20s;
|
||||
}
|
||||
|
||||
h1 { @apply text-4xl; }
|
||||
h2 { @apply text-3xl; }
|
||||
h3 { @apply text-2xl leading-normal; }
|
||||
h4 { @apply text-xl; }
|
||||
h5 { @apply text-lg; }
|
||||
h6 { @apply text-sm; }
|
||||
p { @apply text-base; }
|
||||
}
|
||||
30
app/layout.js
Normal file
30
app/layout.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import "./globals.css";
|
||||
import { Nunito } from "next/font/google";
|
||||
import Localfont from "next/font/local";
|
||||
import { NextIntlClientProvider } from "next-intl";
|
||||
|
||||
const risha = Localfont({
|
||||
src: "../public/fonts/RishaNeo.ttf",
|
||||
variable: "--font-risha"
|
||||
});
|
||||
|
||||
const nunito = Nunito({
|
||||
variable: "--font-nunito",
|
||||
weight: ["500", "700"],
|
||||
subsets: ["latin", "cyrillic"],
|
||||
});
|
||||
|
||||
export const metadata = {
|
||||
title: "Ivan Rezchikov",
|
||||
description: "Web developer and just a guy who loves coding",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body className={`${risha.variable} ${nunito.variable} antialiased selection:bg-black/10`}>
|
||||
<NextIntlClientProvider>{children}</NextIntlClientProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
299
app/page.js
Normal file
299
app/page.js
Normal file
@@ -0,0 +1,299 @@
|
||||
"use client";
|
||||
|
||||
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 Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { TriangleAlert } from "lucide-react";
|
||||
|
||||
export default function Main() {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const t = useTranslations("main");
|
||||
const locale = useLocale();
|
||||
|
||||
const handleToggleLanguage = () => {
|
||||
const nextLocale = locale === "en" ? "ru" : "en";
|
||||
document.cookie = `locale=${nextLocale}; path=/; max-age=31536000`;
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
const timeline = [
|
||||
{
|
||||
era: t("skills.timeline.0.era"),
|
||||
text: (<h3>{t("skills.timeline.0.text")}</h3>),
|
||||
icon: <SiHtml5 className="w-5 h-5 text-orange-500" />,
|
||||
},
|
||||
{
|
||||
era: t("skills.timeline.1.era"),
|
||||
text: (<h3>{t("skills.timeline.1.text")}</h3>),
|
||||
icon: <SiReact className="w-5 h-5 text-orange-500" />,
|
||||
},
|
||||
{
|
||||
era: t("skills.timeline.2.era"),
|
||||
text: (<h3>{t("skills.timeline.2.text")}</h3>),
|
||||
icon: <SiPostgresql className="w-5 h-5 text-orange-500" />,
|
||||
},
|
||||
{
|
||||
era: t("skills.timeline.3.era"),
|
||||
text: (<h3>{t("skills.timeline.3.text")}</h3>),
|
||||
icon: <SiGo className="w-5 h-5 text-orange-500" />,
|
||||
},
|
||||
];
|
||||
|
||||
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"},
|
||||
{"icon": <SiGmail />, "name": t("contact.contacts.2.name"), "username": "rezcjikov@gmail.com", "url": "mailto:rezcjikov@gmail.com"},
|
||||
{"icon": <SiVk />, "name": t("contact.contacts.3.name"), "username": "@rezcjikov", "url": "https://vk.com/rezcjikov/"},
|
||||
{"icon": <SiTiktok />, "name": t("contact.contacts.4.name"), "username": "@gattowolfe", "url": "https://tiktok.com/@gattowolfe/"},
|
||||
]
|
||||
|
||||
const languages = [
|
||||
{
|
||||
flag: "/img/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",
|
||||
name: t("notOnlyCoding.languages.1.name"),
|
||||
level: t("notOnlyCoding.languages.1.level"),
|
||||
text: t("notOnlyCoding.languages.1.text")
|
||||
},
|
||||
{
|
||||
flag: "/img/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",
|
||||
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"]
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="flex flex-col">
|
||||
<section className="flex flex-col gap-2 px-4 xl:px-8 pb-8 xl:pb-10 bg-blue-300" id="whoami">
|
||||
<h2>{t("whoami.title")}</h2>
|
||||
<h3>{t("whoami.text")}</h3>
|
||||
<h4 className="mt-6 xl:mt-0 xl:absolute xl:right-8 text-blue-200 cursor-pointer select-none" onClick={handleToggleLanguage}>
|
||||
{t("changeLanguage").split("").map((ch, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className="animate-wave"
|
||||
style={{ animationDelay: `${i * 0.06}s` }}
|
||||
>
|
||||
{ch === " " ? "\u00A0" : ch}
|
||||
</span>
|
||||
))}
|
||||
</h4>
|
||||
</section>
|
||||
|
||||
{locale == "it" && (<section className="flex gap-4 items-center px-4 xl:px-8 pb-8 xl:pb-10 bg-red-300">
|
||||
<TriangleAlert />
|
||||
<h3>Cari italiani, mi scuso, ma il sito non è completamente tradotto in italiano. Sarebbe meglio usare la versione in inglese.</h3>
|
||||
</section>)}
|
||||
|
||||
<section className="flex flex-col px-4 xl:px-8 pb-8 xl:pb-10 bg-orange-50" id="skills">
|
||||
<h2 className="text-2xl font-semibold mb-6">{t("skills.title")}</h2>
|
||||
|
||||
<div className="mt-2 mb-8 overflow-hidden">
|
||||
<div
|
||||
className="flex items-center gap-3 animate-marquee"
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
style={{ animationPlayState: isHovered ? "paused" : "running" }}
|
||||
>
|
||||
{[...skillsRunline.slice(0, 13), ...skillsRunline.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>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full flex-col items-start">
|
||||
{timeline.map((element, index) => (
|
||||
<div className="group flex gap-x-4 xl:gap-x-6" key={index}>
|
||||
<div className="relative">
|
||||
<div className="absolute left-1/2 top-0 h-full w-0.5 -translate-x-1/2 bg-orange-500" />
|
||||
<span className="relative z-10 grid h-3 w-3 place-items-center rounded-full bg-orange-400" />
|
||||
</div>
|
||||
<div className="-translate-y-1.5 pb-8 space-y-4">
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
{element.icon}
|
||||
<h2>{element.era}</h2>
|
||||
</div>
|
||||
{element.text}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-8 px-4 xl:px-8 pb-8 xl:pb-10 relative bg-gray-100" id="projects"
|
||||
style={{
|
||||
backgroundImage: `
|
||||
linear-gradient(to right, rgba(21, 93, 252, 0.1) 3px, transparent 1px),
|
||||
linear-gradient(to bottom, rgba(21, 93, 252, 0.1) 3px, transparent 1px)
|
||||
`,
|
||||
backgroundSize: "100px 100px"
|
||||
}}
|
||||
>
|
||||
<h2>{t("projects.title")}</h2>
|
||||
<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>
|
||||
</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>
|
||||
<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>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-6 px-4 xl:px-8 pb-8 xl:pb-10 bg-pink-50">
|
||||
<h2>{t("notOnlyCoding.title")}</h2>
|
||||
<h3>{t("notOnlyCoding.subtitle")}</h3>
|
||||
<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}`} />
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex gap-4 items-center">
|
||||
<h2>{language.name}</h2>
|
||||
<h5 className="w-max px-2.5 py-0.5 rounded-full border-3 border-black">
|
||||
{language.level}
|
||||
</h5>
|
||||
</div>
|
||||
<h3>{language.text}</h3>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<h3>{t("notOnlyCoding.outro")}</h3>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-6 px-4 xl:px-8 py-8 xl:py-12 bg-amber-600 text-white" id="contact">
|
||||
<h2>{t("contact.title")}</h2>
|
||||
<h3 className="max-w-2xl">{t("contact.subtitle")}</h3>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-4">
|
||||
{contacts.map((item, index) => (
|
||||
<Link key={index} href={item.url} target="_blank" className="group flex flex-col gap-0.5 xl:gap-0 xl:flex-row xl:items-center justify-between rounded-xl bg-white/10 backdrop-blur-sm px-4 py-3 hover:bg-white/20 transition-all duration-200 cursor-pointer">
|
||||
<div className="flex gap-2 items-center text-white/80">
|
||||
{item.icon}
|
||||
<h4 className="text-xs! xl:text-lg!">{item.name}</h4>
|
||||
</div>
|
||||
<h4>{item.username}</h4>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<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) => (
|
||||
<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>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user