Ajout du composant Scroll et début de la page About

This commit is contained in:
Feror 2025-03-12 09:07:17 +01:00
parent b96ed99cc4
commit efb2184245
7 changed files with 109 additions and 14 deletions

20
front/ScrollComponent.ts Normal file
View file

@ -0,0 +1,20 @@
import { newLine } from ".";
interface ScrollComponentProps {
text: string;
width: number;
height: number;
scrollPosition: number;
}
const ScrollComponent = ({ text, width, height, scrollPosition }: ScrollComponentProps) => {
const lines = text.split(newLine);
const totalLines = lines.length;
const startLine = scrollPosition;
const endLine = Math.min(startLine + height, totalLines);
const visibleLines = lines.slice(startLine, endLine);
return visibleLines.join(newLine);
};
export default ScrollComponent;

View file

@ -1,9 +1,57 @@
import { newLine } from "..";
import ScrollComponent from "../ScrollComponent";
interface AboutProps { interface AboutProps {
width: number; width: number;
height: number; height: number;
scrollPosition: number;
} }
const About = ({ width, height }: AboutProps) => { const age = new Date().getFullYear() - 2004 - (new Date().getMonth() > 10 ? 0 : 1);
return "About";
const About = ({ width, height, scrollPosition }: AboutProps) => {
const content =
` Hi there! My name is Jokin Suares, and I'm a software engineer.${newLine}` +
` I'm passionate about technology and I love to learn new things.${newLine}` +
` ${newLine}` +
` Welcome to my ssh portfolio! Here you can navigate through my projects and contact me.${newLine}` +
` You might be wondering how this works, right?${newLine}` +
` Or maybe you're just curious about why anyone would build a portfolio like this.${newLine}` +
` Well, the answer is simple: I love the terminal!${newLine}` +
` I spend most of my day in the terminal, so why not have my portfolio there too?${newLine}` +
` I hope you enjoy it so far!${newLine}` +
` By the way, you can scroll down to read more about me.${newLine}` +
` To do so, use the arrow keys on your keyboard.${newLine}` +
` ${newLine}` +
` Some background first: ${newLine}` +
` I'm a ${age} years old French 🇫🇷 software engineer ${newLine}` +
` I'm always looking for new challenges and opportunities to learn and grow.${newLine}` +
` At first, I started with backend development, and that was my main focus.${newLine}` +
` But I quickly diversified my skills and started working on many other things.${newLine}` +
` ${newLine}` +
` Here are some of the technologies I've worked with:${newLine}` +
` - Typescript (Bun, React, React Native, Angular, Svelte, ...)${newLine}` +
` - Python (Django, Flask, FastAPI, ...)${newLine}` +
` - Java ${newLine}` +
` - Docker${newLine}` +
` - Kubernetes${newLine}` +
` - Git${newLine}` +
` - Linux${newLine}` +
` - Ansible${newLine}` +
` - Jenkins${newLine}` +
` - Gitlab CI${newLine}` +
` - Travis CI${newLine}` +
` - Circle CI${newLine}` +
` - ...${newLine}` +
` ${newLine}` +
` I am also very passionate about open-source and self-hosting.${newLine}` +
` This portfolio is hosted on my own hardware, and I'm very proud of that.${newLine}`;
return ScrollComponent({
width,
height,
scrollPosition,
text: content,
});
}; };
export default About; export default About;

View file

@ -14,7 +14,7 @@ const Contact = ({ width, height }: ContactProps) => {
` GitHub: ${link("Feror-BotMaker", "https://github.com/Feror-BotMaker")}${newLine}` + ` GitHub: ${link("Feror-BotMaker", "https://github.com/Feror-BotMaker")}${newLine}` +
` Discord: ${link("Feror", "https://discordapp.com/users/323206956640763916")}${newLine}` + ` Discord: ${link("Feror", "https://discordapp.com/users/323206956640763916")}${newLine}` +
` LinkedIn: ${link("Jokin Suares", "https://www.linkedin.com/in/jokin-suares/")}${newLine}` + ` LinkedIn: ${link("Jokin Suares", "https://www.linkedin.com/in/jokin-suares/")}${newLine}` +
` ssh: $ ssh contact@jokinsuares.fr${newLine}` ` ssh: ${link("$ ssh contact@jokinsuares.fr", "ssh:contact@jokinsuares.fr")}${newLine}`
); );
}; };
export default Contact; export default Contact;

View file

@ -1,9 +1,10 @@
interface ProjectsProps { interface ProjectsProps {
width: number; width: number;
height: number; height: number;
scrollPosition: number;
} }
const Projects = ({ width, height }: ProjectsProps) => { const Projects = ({ width, height, scrollPosition }: ProjectsProps) => {
return "Projects"; return `Projects ${scrollPosition}`;
}; };
export default Projects; export default Projects;

View file

@ -6,14 +6,15 @@ interface TabRouterProps {
width: number; width: number;
height: number; height: number;
selectedTab: "About" | "Projects" | "Contact"; selectedTab: "About" | "Projects" | "Contact";
scrollPosition: number;
} }
const TabRouter = ({ width, height, selectedTab }: TabRouterProps) => { const TabRouter = ({ width, height, selectedTab, scrollPosition }: TabRouterProps) => {
switch (selectedTab) { switch (selectedTab) {
case "About": case "About":
return About({ width, height }); return About({ width, height, scrollPosition });
case "Projects": case "Projects":
return Projects({ width, height }); return Projects({ width, height, scrollPosition });
case "Contact": case "Contact":
return Contact({ width, height }); return Contact({ width, height });
} }

View file

@ -6,24 +6,30 @@ interface FrontProps {
columns: number; columns: number;
rows: number; rows: number;
selectedTab: "About" | "Projects" | "Contact"; selectedTab: "About" | "Projects" | "Contact";
scrollPosition: number;
} }
const minimumWidth = 90;
const minimumHeight = 20;
const terminalTooSmall = (width: number, height: number) => { const terminalTooSmall = (width: number, height: number) => {
return ( return (
`Oh no! Your terminal window is too small!${newLine}` + `\x1b[31mOh no!\x1b[0m Your terminal window is too small!${newLine}` +
`Minimum size required: 60x20` + `Minimum size required: ${minimumWidth}x${minimumHeight}${newLine}` +
`Current size: ${width}x${height}` `Current size: ${width >= minimumWidth ? width : `\x1b[31m${width}\x1b[0m`}x${
height >= minimumHeight ? height : `\x1b[31m${height}\x1b[0m`
}${newLine}`
); );
}; };
const Front = ({ columns, rows, selectedTab }: FrontProps) => { const Front = ({ columns, rows, selectedTab, scrollPosition }: FrontProps) => {
if (columns < 60 || rows < 20) { if (columns < minimumWidth || rows < minimumHeight) {
return terminalTooSmall(columns, rows); return terminalTooSmall(columns, rows);
} }
return ( return (
`${Header({ width: columns, height: 3 })}${newLine}` + `${Header({ width: columns, height: 3 })}${newLine}` +
`${Categories({ width: columns, height: 3, selectedTab })}${newLine}` + `${Categories({ width: columns, height: 3, selectedTab })}${newLine}` +
`${TabRouter({ width: columns, height: 3, selectedTab })}` `${TabRouter({ width: columns, height: rows - 6, selectedTab, scrollPosition })}`
); );
}; };

View file

@ -52,6 +52,7 @@ const server = new Server(
columns: number; columns: number;
rows: number; rows: number;
selectedTab: "About" | "Projects" | "Contact"; selectedTab: "About" | "Projects" | "Contact";
scrollPosition: number;
stream: ServerChannel | null; stream: ServerChannel | null;
contactFormData: { contactFormData: {
name: string; name: string;
@ -63,6 +64,7 @@ const server = new Server(
columns: 80, columns: 80,
rows: 24, rows: 24,
selectedTab: "About", selectedTab: "About",
scrollPosition: 0,
stream: null, stream: null,
contactFormData: { contactFormData: {
name: "", name: "",
@ -114,6 +116,7 @@ const server = new Server(
stream.on("data", (data: Buffer) => { stream.on("data", (data: Buffer) => {
const cmd = data.toString(); const cmd = data.toString();
const cmdAsInt = data.readInt8(); const cmdAsInt = data.readInt8();
const cmdAsBase64 = data.toBase64();
if ( if (
cmdAsInt == inputCodes.int8.ctrlC || cmdAsInt == inputCodes.int8.ctrlC ||
@ -232,14 +235,30 @@ const server = new Server(
switch (cmdAsInt) { switch (cmdAsInt) {
case inputCodes.int8.a: case inputCodes.int8.a:
userWindow.selectedTab = "About"; userWindow.selectedTab = "About";
userWindow.scrollPosition = 0;
render(); render();
break; break;
case inputCodes.int8.p: case inputCodes.int8.p:
userWindow.selectedTab = "Projects"; userWindow.selectedTab = "Projects";
userWindow.scrollPosition = 0;
render(); render();
break; break;
case inputCodes.int8.c: case inputCodes.int8.c:
userWindow.selectedTab = "Contact"; userWindow.selectedTab = "Contact";
userWindow.scrollPosition = 0;
render();
break;
}
switch (cmdAsBase64) {
case inputCodes.base64.arrows.up:
userWindow.scrollPosition -= 1;
if (userWindow.scrollPosition < 0) {
userWindow.scrollPosition = 0;
}
render();
break;
case inputCodes.base64.arrows.down:
userWindow.scrollPosition += 1;
render(); render();
break; break;
} }