From d31de41ca381d86d0afa23e376170f4329f04189 Mon Sep 17 00:00:00 2001 From: Bayda77 Date: Mon, 12 Jan 2026 23:34:12 -0600 Subject: [PATCH] changed the code render for the side quests tab --- src/components/CodeBlock.tsx | 40 ++++++ src/components/ProjectCard.tsx | 12 +- src/components/RichTextRenderer.tsx | 36 +++++ src/pages/Projects.tsx | 33 +++-- src/pages/SidequestDetail.tsx | 194 +++++++-------------------- src/styles/components/codeBlock.css | 48 +++++++ src/styles/pages/sidequestDetail.css | 131 ++++++++++++++++++ 7 files changed, 336 insertions(+), 158 deletions(-) create mode 100644 src/components/CodeBlock.tsx create mode 100644 src/components/RichTextRenderer.tsx create mode 100644 src/styles/components/codeBlock.css create mode 100644 src/styles/pages/sidequestDetail.css diff --git a/src/components/CodeBlock.tsx b/src/components/CodeBlock.tsx new file mode 100644 index 0000000..d504e9c --- /dev/null +++ b/src/components/CodeBlock.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'; +import '../styles/components/codeBlock.css'; + +interface CodeBlockProps { + language?: string; + code: string; +} + +const CodeBlock: React.FC = ({ language, code }) => ( +
+
+
+
+
+
+
+ + {language || 'text'} + +
+ + + {code} + +
+); + +export default CodeBlock; diff --git a/src/components/ProjectCard.tsx b/src/components/ProjectCard.tsx index 061d8bb..ec9de09 100644 --- a/src/components/ProjectCard.tsx +++ b/src/components/ProjectCard.tsx @@ -2,6 +2,11 @@ import { motion, Variants } from "framer-motion"; import "../styles/components/cards.css"; import { Link } from "react-router-dom"; +export type DetailSection = + | { type: 'text'; title?: string; content: string } + | { type: 'code'; title?: string; language?: string; code: string } + | { type: 'image'; src: string; alt?: string; caption?: string; title?: string }; + export interface Project { id: number; title: string; @@ -13,12 +18,7 @@ export interface Project { repo?: string; }; hasDetails?: boolean; - detailContent?: { - longDescription: string; - challenges: string; - learnings: string; - codeSnippet?: string; - }; + sections?: DetailSection[]; } interface ProjectCardProps { diff --git a/src/components/RichTextRenderer.tsx b/src/components/RichTextRenderer.tsx new file mode 100644 index 0000000..fbdae71 --- /dev/null +++ b/src/components/RichTextRenderer.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import CodeBlock from './CodeBlock'; + +interface RichTextRendererProps { + content: string; +} + +const RichTextRenderer: React.FC = ({ content }) => { + if (!content) return null; + + const parts = content.split(/```/); + + return ( +
+ {parts.map((part, index) => { + if (index % 2 === 1) { + // Code block + const firstLineBreak = part.indexOf('\n'); + const language = part.slice(0, firstLineBreak).trim(); + const code = part.slice(firstLineBreak + 1).trim(); + + return ; + } + + // Regular text (split by newlines for paragraph handling) + return ( + + {part} + + ); + })} +
+ ); +}; + +export default RichTextRenderer; diff --git a/src/pages/Projects.tsx b/src/pages/Projects.tsx index 9d52237..45748c7 100644 --- a/src/pages/Projects.tsx +++ b/src/pages/Projects.tsx @@ -28,10 +28,17 @@ export const SIDEQUESTS: Project[] = [ repo: "https://github.com/Bayda77/sidequests", // Placeholder link }, hasDetails: true, - detailContent: { - longDescription: "This project started as a deep dive into the world of fragment shaders. I wanted to understand how to create organic-looking textures without relying on image assets. Using Perlin noise and fractional Brownian motion (fBm), I created a dynamic, shifting terrain that reacts to time and mouse input.", - codeSnippet: `\`\`\`glsl -float noise(vec2 st) { + sections: [ + { + type: 'text', + title: 'Overview', + content: "This project started as a deep dive into the world of fragment shaders. I wanted to understand how to create organic-looking textures without relying on image assets. Using Perlin noise and fractional Brownian motion (fBm), I created a dynamic, shifting terrain that reacts to time and mouse input." + }, + { + type: 'code', + language: 'glsl', + title: 'Noise Function', + code: `float noise(vec2 st) { vec2 i = floor(st); vec2 f = fract(st); float a = random(i); @@ -40,11 +47,19 @@ float noise(vec2 st) { float d = random(i + vec2(1.0, 1.0)); vec2 u = f * f * (3.0 - 2.0 * f); return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; -} -\`\`\``, - challenges: "One of the biggest challenges was optimizing the GLSL code to run smoothly on lower-end devices. Mathematical operations in the fragment shader can get expensive quickly.", - learnings: "I gained a much deeper understanding of the graphics pipeline, vector math, and how to think about visuals in terms of mathematical functions rather than pixels." - } +}` + }, + { + type: 'text', + title: 'Challenges', + content: "One of the biggest challenges was optimizing the GLSL code to run smoothly on lower-end devices. Mathematical operations in the fragment shader can get expensive quickly." + }, + { + type: 'text', + title: 'Learnings', + content: "I gained a much deeper understanding of the graphics pipeline, vector math, and how to think about visuals in terms of mathematical functions rather than pixels." + } + ] } ]; diff --git a/src/pages/SidequestDetail.tsx b/src/pages/SidequestDetail.tsx index 7ce98d1..c9b660f 100644 --- a/src/pages/SidequestDetail.tsx +++ b/src/pages/SidequestDetail.tsx @@ -1,84 +1,10 @@ +import { useEffect } from "react"; import { useParams, Link } from "react-router-dom"; import { motion } from "framer-motion"; -import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; -import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'; import { SIDEQUESTS } from "./Projects"; -import { useEffect } from "react"; - -const RichTextRenderer = ({ content }: { content: string }) => { - if (!content) return null; - - const parts = content.split(/```/); - - return ( -
- {parts.map((part, index) => { - if (index % 2 === 1) { - // Code block - const firstLineBreak = part.indexOf('\n'); - const language = part.slice(0, firstLineBreak).trim(); - const code = part.slice(firstLineBreak + 1).trim(); - - return ( -
- {/* Window Header */} -
-
-
-
-
-
- - {language || 'text'} - -
- - - {code} - -
- ); - } - - // Regular text (split by newlines for paragraph handling) - return ( - - {part} - - ); - })} -
- ); -}; +import CodeBlock from "../components/CodeBlock"; +import RichTextRenderer from "../components/RichTextRenderer"; +import "../styles/pages/sidequestDetail.css"; export default function SidequestDetail() { const { id } = useParams<{ id: string }>(); @@ -90,109 +16,91 @@ export default function SidequestDetail() { if (!project) { return ( -
+

Sidequest not found

- Back to Projects + Back to Projects
); } return ( -
+
- + ← Back to Projects -
-

{project.title}

-
+
+

{project.title}

+
{project.techStack.map(tech => ( - + {tech} ))}
-
+
{project.title}
-
-
-

Overview

-
- -
-
+
+ {/* Dynamic Sections Rendering */} + {project.sections?.map((section, index) => { + switch (section.type) { + case 'text': + return ( +
+ {section.title &&

{section.title}

} +
+ +
+
+ ); + case 'code': + return ( +
+ {section.title &&

{section.title}

} + +
+ ); + case 'image': + return ( +
+ {section.title &&

{section.title}

} + {section.alt + {section.caption &&

{section.caption}

} +
+ ); + default: + return null; + } + })} - {project.detailContent?.codeSnippet && ( -
- -
- )} - - {project.detailContent?.challenges && ( -
-

Challenges

-
- -
-
- )} - - {project.detailContent?.learnings && ( -
-

Learnings

-
- -
-
- )} - -
+
{project.links.demo && ( - + Live Demo ↗ )} {project.links.repo && ( - + View Code ↗ )}
-
+
); diff --git a/src/styles/components/codeBlock.css b/src/styles/components/codeBlock.css new file mode 100644 index 0000000..52d9f2d --- /dev/null +++ b/src/styles/components/codeBlock.css @@ -0,0 +1,48 @@ +.code-block-container { + margin: 30px 0; + border-radius: 12px; + overflow: hidden; + border: 1px solid rgba(255, 255, 255, 0.1); + background: #1e1e1e; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); +} + +.code-block-header { + display: flex; + align-items: center; + padding: 12px 16px; + background: rgba(255, 255, 255, 0.05); + border-bottom: 1px solid rgba(255, 255, 255, 0.05); +} + +.window-controls { + display: flex; + gap: 8px; + margin-right: auto; +} + +.control-dot { + width: 12px; + height: 12px; + border-radius: 50%; +} + +.control-dot.red { + background: #ff5f56; +} + +.control-dot.yellow { + background: #ffbd2e; +} + +.control-dot.green { + background: #27c93f; +} + +.language-label { + font-size: 12px; + color: rgba(255, 255, 255, 0.5); + font-family: monospace; + text-transform: uppercase; + margin-top: 2px; +} \ No newline at end of file diff --git a/src/styles/pages/sidequestDetail.css b/src/styles/pages/sidequestDetail.css new file mode 100644 index 0000000..0e00db5 --- /dev/null +++ b/src/styles/pages/sidequestDetail.css @@ -0,0 +1,131 @@ +.sidequest-error-container { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + color: white; +} + +.sidequest-back-link-error { + color: rgba(255, 255, 255, 0.7); + margin-top: 20px; +} + +.sidequest-container { + min-width: 66vw; + display: flex; + justify-content: center; + padding-top: 40px; +} + +.sidequest-content-wrapper { + width: 100%; + max-width: 800px; + padding: 0 20px; +} + +.sidequest-back-link { + display: inline-flex; + align-items: center; + color: rgba(255, 255, 255, 0.6); + text-decoration: none; + margin-bottom: 30px; + transition: color 0.2s ease; +} + +.sidequest-back-link:hover { + color: white; +} + +.sidequest-header { + margin-bottom: 40px; +} + +.sidequest-title { + font-size: 2.5rem; + margin-bottom: 10px; + color: white; +} + +.sidequest-tech-stack { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 20px; +} + +.sidequest-tech-tag { + background: rgba(255, 255, 255, 0.1); + padding: 4px 12px; + border-radius: 15px; + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.9); +} + +.sidequest-hero-image-container { + width: 100%; + height: 400px; + border-radius: 16px; + overflow: hidden; + margin-bottom: 40px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); +} + +.sidequest-hero-image { + width: 100%; + height: 100%; + object-fit: cover; +} + +.sidequest-details-container { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(10px); + border-radius: 16px; + padding: 40px; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.sidequest-section { + margin-bottom: 30px; +} + +.sidequest-section-title { + color: white; + font-size: 1.5rem; + margin-bottom: 15px; +} + +.sidequest-section-content { + color: rgba(255, 255, 255, 0.8); + line-height: 1.7; +} + +.sidequest-section-image { + width: 100%; + border-radius: 12px; +} + +.sidequest-section-caption { + color: rgba(255, 255, 255, 0.5); + font-size: 0.9rem; + margin-top: 10px; + text-align: center; +} + +.sidequest-footer-links { + margin-top: 40px; + padding-top: 20px; + border-top: 1px solid rgba(255, 255, 255, 0.1); + display: flex; + gap: 20px; +} + +.sidequest-footer-link { + color: white; + text-decoration: underline; +} + +.sidequest-footer-spacer { + height: 100px; +} \ No newline at end of file