diff --git a/backend/.prettierignore b/backend/.prettierignore new file mode 100644 index 0000000..1b8ac88 --- /dev/null +++ b/backend/.prettierignore @@ -0,0 +1,3 @@ +# Ignore artifacts: +build +coverage diff --git a/backend/.prettierrc b/backend/.prettierrc new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/backend/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/backend/package-lock.json b/backend/package-lock.json index cb04950..8c99059 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -19,6 +19,7 @@ }, "devDependencies": { "@types/node": "^22.13.4", + "prettier": "3.5.1", "ts-node": "^10.9.2", "typescript": "^5.7.3" } @@ -758,6 +759,22 @@ "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", "license": "MIT" }, + "node_modules/prettier": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", + "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/process-warning": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", diff --git a/backend/package.json b/backend/package.json index fbb889d..671e0b5 100644 --- a/backend/package.json +++ b/backend/package.json @@ -22,6 +22,7 @@ }, "devDependencies": { "@types/node": "^22.13.4", + "prettier": "3.5.1", "ts-node": "^10.9.2", "typescript": "^5.7.3" } diff --git a/backend/server.ts b/backend/server.ts index 03bb2e9..220d0e3 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -1,15 +1,17 @@ import Fastify from "fastify"; import cors from "@fastify/cors"; -import multipart from '@fastify/multipart'; +import multipart from "@fastify/multipart"; import { libreConvert } from "./src/routes/libreconvert.route"; +import { colorConvert } from "./src/routes/colorconvert.route"; const app = Fastify({ logger: true }); app.register(cors, { origin: "*" }); app.register(multipart); app.register(libreConvert); +app.register(colorConvert); const PORT = process.env.PORT || 4000; app.listen({ port: Number(PORT), host: "0.0.0.0" }, () => { - console.log(`🚀Fastify is live on http://localhost:${PORT}`); -}); \ No newline at end of file + console.log(`🚀Fastify is live on http://localhost:${PORT}`); +}); diff --git a/backend/src/routes/colorconvert.route.ts b/backend/src/routes/colorconvert.route.ts new file mode 100644 index 0000000..402e642 --- /dev/null +++ b/backend/src/routes/colorconvert.route.ts @@ -0,0 +1,29 @@ +import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; + +interface RequestBody { + red: string; + green: string; + blue: string; +} + +export async function colorConvert(app: FastifyInstance) { + app.post( + "/api/color-convert", + async ( + request: FastifyRequest<{ Body: RequestBody }>, + reply: FastifyReply, + ) => { + try { + const data = request.body; + if (!data) { + return reply.status(400).send({ error: "No RGB declared!" }); + } + const hex = (`#${(+data.red).toString(16).padStart(2, "0")}${(+data.green).toString(16).padStart(2, "0")}${(+data.blue).toString(16).padStart(2, "0")}`).toUpperCase(); + reply.header("Content-Type", "application/json").send({ hex: hex }); + } catch (error) { + console.error("Convert error:", error); + reply.status(500).send({ error: "Error while converting!" }); + } + }, + ); +} diff --git a/backend/src/routes/libreconvert.route.ts b/backend/src/routes/libreconvert.route.ts index ac4c8af..d28705e 100644 --- a/backend/src/routes/libreconvert.route.ts +++ b/backend/src/routes/libreconvert.route.ts @@ -5,26 +5,29 @@ import { promisify } from "util"; const libreConvertAsync = promisify(libre.convert); export async function libreConvert(app: FastifyInstance) { - app.post("/api/libre-convert", async (request: FastifyRequest, reply: FastifyReply) => { - try { - const data = await request.file(); - if (!data) { - return reply.status(400).send({ error: "No file uploaded!" }); - } + app.post( + "/api/libre-convert", + async (request: FastifyRequest, reply: FastifyReply) => { + try { + const data = await request.file(); + if (!data) { + return reply.status(400).send({ error: "No file uploaded!" }); + } - const ext = ".pdf"; - const format = ext.substring(1); - const fileBuffer = await data.toBuffer(); + const ext = ".pdf"; + const format = ext.substring(1); + const fileBuffer = await data.toBuffer(); - const pdfBuffer = await libreConvertAsync(fileBuffer, ext, undefined); + const pdfBuffer = await libreConvertAsync(fileBuffer, ext, undefined); - reply + reply .header("Content-Type", "application/" + format) .header("Content-Disposition", "attachment; filename=converted" + ext) .send(pdfBuffer); - } catch (error) { - console.error("Convert error:", error); - reply.status(500).send({ error: "Error while converting!" }); - } - }); + } catch (error) { + console.error("Convert error:", error); + reply.status(500).send({ error: "Error while converting!" }); + } + }, + ); } diff --git a/frontend/src/app/rgb-to-hex/layout.tsx b/frontend/src/app/rgb-to-hex/layout.tsx new file mode 100644 index 0000000..04c7606 --- /dev/null +++ b/frontend/src/app/rgb-to-hex/layout.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import type { Metadata } from "next"; +import { toolLinks } from "@/constants"; + +export const metadata: Metadata = { + title: toolLinks[2].title, + description: "Converter for rgb to hex color format!", +}; + +export default function RootLayout({ + children, + }: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/frontend/src/app/rgb-to-hex/page.tsx b/frontend/src/app/rgb-to-hex/page.tsx new file mode 100644 index 0000000..cdef0e4 --- /dev/null +++ b/frontend/src/app/rgb-to-hex/page.tsx @@ -0,0 +1,133 @@ +"use client"; + +import React, { useState } from "react"; +import Navbar from "../../components/Navbar"; +import Footer from "../../components/Footer"; +import Button from "../../components/Button"; + +export default function RgbToHex() { + + const [loading, setLoading] = useState(false); + const [hex, setHex] = useState(""); + + const convertToHex = async () => { + + setLoading(true); + + const red = (document.getElementById("red") as HTMLInputElement).value; + const green = (document.getElementById("green") as HTMLInputElement).value; + const blue = (document.getElementById("blue") as HTMLInputElement).value; + + try { + const response = await fetch( + process.env.backend_url + "/api/color-convert", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ red: red, green: green, blue: blue }), + }, + ); + if (!response.ok) { + return new Error(`Error: ${response.statusText}`); + } + const hex: string = await response.text(); + setHex(hex); + + } catch (error) { + console.error("Error while converting:", error); + alert("Error while converting"); + } finally { + setLoading(false); + } + }; + + const clearInAndOutput = () => { + setHex(""); + const red = document.getElementById("red") as HTMLInputElement; + const green = document.getElementById("green") as HTMLInputElement; + const blue = document.getElementById("blue") as HTMLInputElement; + red.value = ""; + green.value = ""; + blue.value = ""; + }; + + const checkInput = (event: React.ChangeEvent) => { + const color = (document.getElementById(event.target.id) as HTMLInputElement); + const colorValue = +color.value; + + if (colorValue < 0 || colorValue > 255 ) { + alert("Invalid input. Please enter a number between 0 and 255."); + } + if (colorValue < 0) { + color.value = "0"; + } else if (colorValue > 255) { + color.value = "255"; + } + } + + return ( +
+ +
+

rgb-to-hex

+
+ + + + + + +
+
+
+
+ {hex} +
+
+
+ ); +} \ No newline at end of file