feat. add real work experience section and update types
This commit is contained in:
23
src/App.tsx
23
src/App.tsx
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||||
import UmamiAnalytics from "@danielgtmn/umami-react";
|
import UmamiAnalytics from "@danielgtmn/umami-react";
|
||||||
import type { Experience, MiniProject, Project } from "./types";
|
import type { Experience, MiniProject, Project, RealWork } from "./types";
|
||||||
import { MiniProjectModal } from "./components/MiniProjectModal";
|
import { MiniProjectModal } from "./components/MiniProjectModal";
|
||||||
import { ExperienceModal } from "./components/ExperienceModal";
|
import { ExperienceModal } from "./components/ExperienceModal";
|
||||||
import { Navbar } from "./components/Navbar";
|
import { Navbar } from "./components/Navbar";
|
||||||
@@ -29,6 +29,7 @@ function App() {
|
|||||||
const [projects, setProjects] = useState<Project[]>([]);
|
const [projects, setProjects] = useState<Project[]>([]);
|
||||||
const [miniProjects, setMiniProjects] = useState<MiniProject[]>([]);
|
const [miniProjects, setMiniProjects] = useState<MiniProject[]>([]);
|
||||||
const [experiences, setExperiences] = useState<Experience[]>([]);
|
const [experiences, setExperiences] = useState<Experience[]>([]);
|
||||||
|
const [realWork, setRealWork] = useState<RealWork[]>([]);
|
||||||
|
|
||||||
const oldUsernames = [
|
const oldUsernames = [
|
||||||
"getspaced (ingame)",
|
"getspaced (ingame)",
|
||||||
@@ -143,6 +144,23 @@ function App() {
|
|||||||
|
|
||||||
// Fetch data from API on mount
|
// Fetch data from API on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const fetchRealWork = async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(
|
||||||
|
"https://shsf-api.reversed.dev/api/exec/4/e942538c-caa1-49d1-8953-dfab1e62f8cb/real_work",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error("Failed to fetch real work data");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = (await res.json()) as RealWork[];
|
||||||
|
setRealWork(data);
|
||||||
|
} catch {
|
||||||
|
setRealWork([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
fetch(
|
fetch(
|
||||||
"https://shsf-api.reversed.dev/api/exec/4/e942538c-caa1-49d1-8953-dfab1e62f8cb/projects",
|
"https://shsf-api.reversed.dev/api/exec/4/e942538c-caa1-49d1-8953-dfab1e62f8cb/projects",
|
||||||
)
|
)
|
||||||
@@ -163,6 +181,8 @@ function App() {
|
|||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then(setExperiences)
|
.then(setExperiences)
|
||||||
.catch(() => setExperiences([]));
|
.catch(() => setExperiences([]));
|
||||||
|
|
||||||
|
fetchRealWork();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -212,6 +232,7 @@ function App() {
|
|||||||
setSelectedMiniProject={setSelectedMiniProject}
|
setSelectedMiniProject={setSelectedMiniProject}
|
||||||
experiences={experiences}
|
experiences={experiences}
|
||||||
setSelectedExperience={setSelectedExperience}
|
setSelectedExperience={setSelectedExperience}
|
||||||
|
realWork={realWork}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Hero } from "../sections/Hero";
|
import { Hero } from "../sections/Hero";
|
||||||
import type { MiniProject, Experience, Project } from "../types";
|
import { WorkExperience } from "../sections/WorkExperience";
|
||||||
|
import type { MiniProject, Experience, Project, RealWork } from "../types";
|
||||||
import { ProjectCard } from "../components/ProjectCard";
|
import { ProjectCard } from "../components/ProjectCard";
|
||||||
import { MiniProjectCard } from "../components/MiniProjectCard";
|
import { MiniProjectCard } from "../components/MiniProjectCard";
|
||||||
import { ExperienceCard } from "../components/ExperienceCard";
|
import { ExperienceCard } from "../components/ExperienceCard";
|
||||||
@@ -18,6 +19,7 @@ interface HomeProps {
|
|||||||
setSelectedMiniProject: (p: MiniProject) => void;
|
setSelectedMiniProject: (p: MiniProject) => void;
|
||||||
experiences: Experience[];
|
experiences: Experience[];
|
||||||
setSelectedExperience: (e: Experience) => void;
|
setSelectedExperience: (e: Experience) => void;
|
||||||
|
realWork: RealWork[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Home({
|
export function Home({
|
||||||
@@ -34,6 +36,7 @@ export function Home({
|
|||||||
setSelectedMiniProject,
|
setSelectedMiniProject,
|
||||||
experiences,
|
experiences,
|
||||||
setSelectedExperience,
|
setSelectedExperience,
|
||||||
|
realWork,
|
||||||
}: HomeProps) {
|
}: HomeProps) {
|
||||||
const groupedExperiences = experiences.reduce(
|
const groupedExperiences = experiences.reduce(
|
||||||
(acc, exp) => {
|
(acc, exp) => {
|
||||||
@@ -48,16 +51,16 @@ export function Home({
|
|||||||
|
|
||||||
const rewriteType = (type: string) => {
|
const rewriteType = (type: string) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "language":
|
case "languages":
|
||||||
return "Languages";
|
return "Languages";
|
||||||
case "service":
|
case "software":
|
||||||
return "Services";
|
return "Software";
|
||||||
case "platform":
|
case "plattforms":
|
||||||
return "Platforms";
|
return "Platforms";
|
||||||
case "real life experience":
|
case "experience":
|
||||||
return "Real Life Experience";
|
return "Experience";
|
||||||
case "roles":
|
case "other":
|
||||||
return "Roles";
|
return "Other";
|
||||||
default:
|
default:
|
||||||
return type.charAt(0).toUpperCase() + type.slice(1);
|
return type.charAt(0).toUpperCase() + type.slice(1);
|
||||||
}
|
}
|
||||||
@@ -76,6 +79,8 @@ export function Home({
|
|||||||
oldUsernames={oldUsernames}
|
oldUsernames={oldUsernames}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<WorkExperience realWork={realWork} />
|
||||||
|
|
||||||
<section className="w-full max-w-6xl space-y-12">
|
<section className="w-full max-w-6xl space-y-12">
|
||||||
<div className="text-center space-y-4">
|
<div className="text-center space-y-4">
|
||||||
<h2 className="text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500">
|
<h2 className="text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-500">
|
||||||
|
|||||||
73
src/sections/WorkExperience.tsx
Normal file
73
src/sections/WorkExperience.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import type { RealWork } from "../types";
|
||||||
|
|
||||||
|
interface WorkExperienceProps {
|
||||||
|
realWork: RealWork[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WorkExperience({ realWork }: WorkExperienceProps) {
|
||||||
|
return (
|
||||||
|
<section className="w-full max-w-4xl mx-auto px-4 space-y-8">
|
||||||
|
<div className="text-center space-y-2">
|
||||||
|
<h2 className="text-3xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-blue-500">
|
||||||
|
Work Experience
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-400 max-w-2xl mx-auto">
|
||||||
|
Professional collaborations and product work I have contributed to.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{realWork.length === 0 ? (
|
||||||
|
<div className="p-6 md:p-8 rounded-2xl bg-gradient-to-br from-cyan-500/10 to-blue-500/5 backdrop-blur-sm border border-cyan-500/20 text-center">
|
||||||
|
<p className="text-gray-300">No work experience entries available yet.</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-4">
|
||||||
|
{realWork.map((entry, index) => (
|
||||||
|
<div
|
||||||
|
key={`${entry.company}-${index}`}
|
||||||
|
className="p-6 md:p-8 rounded-2xl bg-gradient-to-br from-cyan-500/10 to-blue-500/5 backdrop-blur-sm border border-cyan-500/20 space-y-5"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
|
||||||
|
<h3 className="text-2xl font-semibold text-white">{entry.company}</h3>
|
||||||
|
{entry.url ? (
|
||||||
|
<a
|
||||||
|
href={entry.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 self-start sm:self-auto rounded-full border border-cyan-400/30 bg-cyan-400/10 px-3 py-1.5 text-sm font-medium text-cyan-200 hover:bg-cyan-400/20 hover:border-cyan-300/50 transition-colors"
|
||||||
|
>
|
||||||
|
<span>{new URL(entry.url).hostname.replace(/^www\./, "")}</span>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
aria-hidden="true"
|
||||||
|
className="h-4 w-4"
|
||||||
|
>
|
||||||
|
<path d="M5 6.75A1.75 1.75 0 0 1 6.75 5h2a.75.75 0 0 0 0-1.5h-2A3.25 3.25 0 0 0 3.5 6.75v6.5A3.25 3.25 0 0 0 6.75 16.5h6.5a3.25 3.25 0 0 0 3.25-3.25v-2a.75.75 0 0 0-1.5 0v2A1.75 1.75 0 0 1 13.25 15h-6.5A1.75 1.75 0 0 1 5 13.25v-6.5Z" />
|
||||||
|
<path d="M11.25 3.5a.75.75 0 0 0 0 1.5h2.69l-4.72 4.72a.75.75 0 1 0 1.06 1.06L15 6.06v2.69a.75.75 0 0 0 1.5 0V3.5h-5.25Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-gray-300 leading-relaxed">{entry.summary}</p>
|
||||||
|
|
||||||
|
{entry.tags && entry.tags.length > 0 ? (
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{entry.tags.map((tag) => (
|
||||||
|
<span
|
||||||
|
key={`${entry.company}-${tag}`}
|
||||||
|
className="px-3 py-1 rounded-full text-xs font-semibold bg-cyan-500/20 text-cyan-200 border border-cyan-500/30"
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ export interface MiniProject {
|
|||||||
|
|
||||||
export interface Experience {
|
export interface Experience {
|
||||||
name: string;
|
name: string;
|
||||||
type: "language" | "service" | "platform" | "real life experience" | "roles";
|
type: "languages" | "software" | "plattforms" | "experience" | "other";
|
||||||
description: string;
|
description: string;
|
||||||
image?: string;
|
image?: string;
|
||||||
learned_at?: string;
|
learned_at?: string;
|
||||||
@@ -31,3 +31,10 @@ export interface Project {
|
|||||||
rounded?: boolean;
|
rounded?: boolean;
|
||||||
last_commit?: Date;
|
last_commit?: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RealWork {
|
||||||
|
company: string;
|
||||||
|
url?: string;
|
||||||
|
summary: string;
|
||||||
|
tags?: string[];
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user