diff --git a/package.json b/package.json index 2d80190..8b804ba 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "next-themes": "^0.4.4", "react": "^19.0.0", "react-dom": "^19.0.0", + "simple-icons": "^14.2.0", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7" }, diff --git a/public/icons/GitHub.svg b/public/icons/GitHub.svg new file mode 100644 index 0000000..538ec5b --- /dev/null +++ b/public/icons/GitHub.svg @@ -0,0 +1 @@ +GitHub \ No newline at end of file diff --git a/public/locales/en-US.json b/public/locales/en-US.json index 7c14a2c..f054fe9 100644 --- a/public/locales/en-US.json +++ b/public/locales/en-US.json @@ -46,7 +46,10 @@ }, "ESLint": { "Description": "ESLint is a code linting tool for JavaScript. It is used to identify and report problematic patterns found in JavaScript code. It is highly configurable and can be customized to meet the specific needs of your project." - }, + }, + "GitHub": { + "Description": "GitHub is a web-based platform for version control using Git. It allows developers to collaborate on projects, track changes, and manage code repositories. It provides a wide range of features, such as issue tracking, pull requests, code review, and project management." + }, "HTML5": { "Description": "HTML5 is a markup language used for structuring and presenting content on the World Wide Web. It is the fifth and final major version of HTML, recommended by the World Wide Web Consortium (W3C)." }, @@ -95,6 +98,8 @@ }, "Projects": { "Title": "Projects", + "ViewSource": "View on GitHub", + "ViewDeploy": "View Deploy", "N-D-B": { "Description": "N-D-B is a Discord bot developed using DiscordJS and Necord an library for NestJS. It is a multipurpose bot that has several features, such as moderation, music, and fun commands. The bot is designed to be easy to use and has a simple and intuitive interface. It is constantly being updated with new features and improvements." } diff --git a/public/locales/pt-BR.json b/public/locales/pt-BR.json index e63f47e..10a43ef 100644 --- a/public/locales/pt-BR.json +++ b/public/locales/pt-BR.json @@ -47,6 +47,9 @@ "ESLint": { "Description": "ESLint é uma ferramenta de linting de código para JavaScript. Ele é usado para identificar e relatar padrões problemáticos encontrados no código JavaScript. Ele é altamente configurável e pode ser personalizado para atender às necessidades específicas do seu projeto." }, + "GitHub": { + "Description": "GitHub é uma plataforma baseada na web para controle de versão usando Git. Ele permite que os desenvolvedores colaborem em projetos, rastreiem alterações e gerenciem repositórios de código. Ele oferece uma ampla gama de recursos, como rastreamento de problemas, solicitações de pull, revisão de código e gerenciamento de projetos." + }, "HTML5": { "Description": "HTML5 é uma linguagem de marcação usada para estruturar e apresentar conteúdo na World Wide Web. É a quinta e última grande versão do HTML que é uma recomendação do World Wide Web Consortium (W3C)." }, @@ -95,6 +98,8 @@ }, "Projects": { "Title": "Projetos", + "ViewSource": "Ver no GitHub", + "ViewDeploy": "Ver Deploy", "N-D-B": { "Description": "N-D-B é um bot do Discord desenvolvido usando DiscordJS e Necord uma biblioteca para o NestJS. É um bot multipropósito que possui várias funcionalidades, como moderação, música e comandos divertidos. O bot é projetado para ser fácil de usar e possui uma interface simples e intuitiva. Ele está sendo constantemente atualizado com novos recursos e melhorias." } diff --git a/src/@types/index.d.ts b/src/@types/index.d.ts index 2b0455a..3c02a66 100644 --- a/src/@types/index.d.ts +++ b/src/@types/index.d.ts @@ -41,6 +41,8 @@ export type ProjectCategories = ""; export type Project = { name: string; description: string; + github: string; + deploy: string; techs: Techs[]; categories: ProjectCategories[]; }; diff --git a/src/app/api/images/[project]/route.ts b/src/app/api/images/[project]/route.ts new file mode 100644 index 0000000..811a7fe --- /dev/null +++ b/src/app/api/images/[project]/route.ts @@ -0,0 +1,37 @@ +import fs from "node:fs"; +import path from "node:path"; +import { NextResponse } from "next/server"; + +export async function GET( + request: Request, + { params }: { params: { project: string } } +) { + const { project } = await params; + + if (!project) { + return NextResponse.json( + { error: "Project name is required" }, + { status: 400 } + ); + } + + const imagesPath = path.join(process.cwd(), "public", "images", project); + + try { + const files = fs.readdirSync(imagesPath); + const images = files + .filter((file) => /\.(png|jpg|jpeg|gif|svg)$/i.test(file)) + .map((file, index) => ({ + id: index, + src: `/images/${project}/${file}`, + alt: `${project} ${file}`, + })); + + return NextResponse.json(images); + } catch (error) { + return NextResponse.json( + { error: "Unable to fetch images" }, + { status: 500 } + ); + } +} diff --git a/src/components/projects/full-card.tsx b/src/components/projects/full-card.tsx index d5c5e4d..bb7bb32 100644 --- a/src/components/projects/full-card.tsx +++ b/src/components/projects/full-card.tsx @@ -1,3 +1,71 @@ -export function ProjectsFullCard() { - return
; +"use client"; + +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, +} from "../ui/dialog"; +import { DialogTitle } from "@radix-ui/react-dialog"; +import type { Dispatch, SetStateAction } from "react"; +import { ProjectCarousel } from "./project-carousel"; +import { Project } from "@/@types"; +import { Icon } from "../icon"; +import { LucideUpload } from "lucide-react"; +import { Button, Separator } from "../ui"; +import { useTranslations } from "next-intl"; +import Link from "next/link"; + +interface ProjectsFullCardProps { + openState: [boolean, Dispatch>]; + info: Project; +} + +export function ProjectsFullCard({ + openState, + info, +}: Readonly) { + const [isOpen, setIsOpen] = openState; + const t = useTranslations("Projects"); + + return ( + setIsOpen((prev) => !prev)}> + + + + + {info.name} + + + + + {t(info.description)} + +
+ + +
+ + +
+ {info.techs.map((tech) => ( + + ))} +
+
+
+ ); } diff --git a/src/components/projects/index.ts b/src/components/projects/index.ts index aa704b2..9435075 100644 --- a/src/components/projects/index.ts +++ b/src/components/projects/index.ts @@ -1,4 +1,5 @@ import { ProjectsFullCard } from "./full-card"; +import { ProjectCarousel } from "./project-carousel"; import { ProjectsSection } from "./projects"; import { ProjectsSmallCard } from "./small-card"; @@ -6,4 +7,5 @@ export const Projects = { Section: ProjectsSection, SmallCard: ProjectsSmallCard, FullCard: ProjectsFullCard, + Carousel: ProjectCarousel, }; diff --git a/src/components/projects/project-carousel.tsx b/src/components/projects/project-carousel.tsx new file mode 100644 index 0000000..9a0d3cb --- /dev/null +++ b/src/components/projects/project-carousel.tsx @@ -0,0 +1,80 @@ +"use client"; + +import { Card, CardContent } from "@/components/ui/card"; +import { + Carousel, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from "@/components/ui/carousel"; +import { useEffect, useState } from "react"; + +interface ProjectCarouselProps { + name: string; +} + +export function ProjectCarousel({ name }: ProjectCarouselProps) { + const [pictures, setPictures] = useState<{ id: number, src: string; alt: string }[]>([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchPictures = async () => { + try { + const response = await fetch(`/api/images/${name}`); + if (response.ok) { + const data = await response.json(); + setPictures(data); + } else { + console.error("Failed to fetch images"); + } + } catch (error) { + console.error("Error fetching images:", error); + } finally { + setLoading(false); + } + }; + + fetchPictures(); + }, [name]); + + if(loading) { + return ( + + + +
+ + +
+
+
+
+
+
+ + +
+ ); + } + + return ( + + + {pictures.map((picture) => ( + +
+ + + {picture.alt} + + +
+
+ ))} +
+ + +
+ ) +} \ No newline at end of file diff --git a/src/components/projects/projects.tsx b/src/components/projects/projects.tsx index 28f924f..abab262 100644 --- a/src/components/projects/projects.tsx +++ b/src/components/projects/projects.tsx @@ -12,7 +12,7 @@ export function ProjectsSection() {
{projects.map((project) => ( - + ))}
diff --git a/src/components/projects/small-card.tsx b/src/components/projects/small-card.tsx index 6ed13e6..c7e3be5 100644 --- a/src/components/projects/small-card.tsx +++ b/src/components/projects/small-card.tsx @@ -1,3 +1,5 @@ +"use client" + import { Card, CardContent, @@ -8,32 +10,38 @@ import { } from "@/components/ui/card"; import { Icon } from "../icon"; import { Separator } from "../ui"; -import { Techs } from "@/@types"; +import { Project } from "@/@types"; +import { ProjectsFullCard } from "./full-card"; +import { useState } from "react"; +import { useTranslations } from "next-intl"; interface ProjectsSmallCardProps { - name: string; - description: string; - techs: Techs[]; + info: Project } -export function ProjectsSmallCard(props: Readonly) { - const uniqueTechs = Array.from(new Set(props.techs)); +export function ProjectsSmallCard({ info }: Readonly) { + const uniqueTechs = Array.from(new Set(info.techs)); + const openState = useState(false); + const t = useTranslations("Projects"); return ( - - - {`${props.name} - - {props.name} - - - {props.description.split(".")[0]+"."} - - - {uniqueTechs.map((tech) => ( - - ))} - - + <> + openState[1](true)}> + + {`${info.name} + + {info.name} + + + {t(info.description).split(".")[0]+"."} + + + {uniqueTechs.map((tech) => ( + + ))} + + + + ); } diff --git a/src/constants/projects.ts b/src/constants/projects.ts index 8d8ebd4..b440664 100644 --- a/src/constants/projects.ts +++ b/src/constants/projects.ts @@ -5,6 +5,9 @@ export const projects: Project[] = [ name: "N-D-B", description: "N-D-B.Description", categories: [], + github: "https://github.com/N-D-B-Project/N-D-B", + deploy: + "https://discord.com/oauth2/authorize?client_id=708822043420000366&permissions=8&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fapi%2Fauth%2Fredirect&scope=bot%20applications.commands", techs: [ "NodeJS", "TypeScript", diff --git a/src/constants/skills.ts b/src/constants/skills.ts index 44246e3..ba9eb66 100644 --- a/src/constants/skills.ts +++ b/src/constants/skills.ts @@ -37,6 +37,12 @@ export const skills: SkillData[] = [ categories: ["Tools"], url: "https://eslint.org/", }, + { + name: "GitHub", + description: "GitHub.Description", + categories: ["Tools"], + url: "https://github.com/NedcloarBR", + }, { name: "HTML5", description: "HTML5.Description", diff --git a/yarn.lock b/yarn.lock index 25e0a60..6541710 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2397,6 +2397,7 @@ __metadata: postcss: "npm:^8.4.49" react: "npm:^19.0.0" react-dom: "npm:^19.0.0" + simple-icons: "npm:^14.2.0" tailwind-merge: "npm:^2.6.0" tailwindcss: "npm:^3.4.17" tailwindcss-animate: "npm:^1.0.7" @@ -2830,6 +2831,13 @@ __metadata: languageName: node linkType: hard +"simple-icons@npm:^14.2.0": + version: 14.2.0 + resolution: "simple-icons@npm:14.2.0" + checksum: 10c0/47b3656ecdd33f0b58d516bd2d67f06c6bd9b39ffa5cea26cbdfb6799af2ce6c07d0b525920e25dd5d9bdf491904fb35ac8a20f1cfe20cfbef82b7b10bbc935c + languageName: node + linkType: hard + "simple-swizzle@npm:^0.2.2": version: 0.2.2 resolution: "simple-swizzle@npm:0.2.2"