mirror of
https://github.com/soconnor0919/personal-website.git
synced 2025-12-15 16:24:44 -05:00
Add resume/switcher
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
"@radix-ui/react-select": "^2.1.2",
|
"@radix-ui/react-select": "^2.1.2",
|
||||||
"@radix-ui/react-separator": "^1.1.0",
|
"@radix-ui/react-separator": "^1.1.0",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
|
"@radix-ui/react-tabs": "^1.1.1",
|
||||||
"@radix-ui/react-toast": "^1.2.2",
|
"@radix-ui/react-toast": "^1.2.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.3",
|
"@radix-ui/react-tooltip": "^1.1.3",
|
||||||
"@react-pdf/renderer": "^3.4.5",
|
"@react-pdf/renderer": "^3.4.5",
|
||||||
|
|||||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -35,6 +35,9 @@ importers:
|
|||||||
'@radix-ui/react-slot':
|
'@radix-ui/react-slot':
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0(@types/react@18.3.12)(react@18.3.1)
|
version: 1.1.0(@types/react@18.3.12)(react@18.3.1)
|
||||||
|
'@radix-ui/react-tabs':
|
||||||
|
specifier: ^1.1.1
|
||||||
|
version: 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
'@radix-ui/react-toast':
|
'@radix-ui/react-toast':
|
||||||
specifier: ^1.2.2
|
specifier: ^1.2.2
|
||||||
version: 1.2.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 1.2.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|||||||
BIN
public/resume.pdf
Normal file
BIN
public/resume.pdf
Normal file
Binary file not shown.
@@ -1,8 +1,17 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from '~/components/ui/tabs';
|
||||||
|
import { Badge } from '~/components/ui/badge';
|
||||||
|
import { Card, CardHeader, CardContent, CardTitle, CardDescription } from '~/components/ui/card';
|
||||||
|
import { Download } from 'lucide-react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
export default function CVPage() {
|
export default function CVPage() {
|
||||||
|
const [activeTab, setActiveTab] = useState('cv');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-6">
|
||||||
<section className="prose prose-zinc dark:prose-invert max-w-none">
|
<section className="prose prose-zinc dark:prose-invert max-w-none">
|
||||||
<h1 className="text-2xl font-bold">Curriculum Vitae 📄</h1>
|
<h1 className="text-2xl font-bold">Curriculum Vitae 📄</h1>
|
||||||
<p className="text-lg text-muted-foreground">
|
<p className="text-lg text-muted-foreground">
|
||||||
@@ -10,26 +19,83 @@ export default function CVPage() {
|
|||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div className="bg-white shadow-sm rounded-lg overflow-hidden">
|
<Tabs value={activeTab} onValueChange={setActiveTab}>
|
||||||
<object
|
<TabsList>
|
||||||
data="/cv.pdf"
|
<TabsTrigger value="cv">CV</TabsTrigger>
|
||||||
type="application/pdf"
|
<TabsTrigger value="resume">Resume</TabsTrigger>
|
||||||
className="w-full h-[calc(100vh-18rem)] lg:h-[calc(100vh-15rem)]"
|
</TabsList>
|
||||||
>
|
|
||||||
<div className="flex flex-col items-center justify-center p-8">
|
<TabsContent value="cv">
|
||||||
<p className="text-lg text-muted-foreground">
|
<div className="bg-background shadow-sm rounded-lg overflow-hidden">
|
||||||
Your browser doesn't support PDF preview.
|
<object
|
||||||
</p>
|
data="/cv.pdf"
|
||||||
<a
|
type="application/pdf"
|
||||||
href="/cv.pdf"
|
className="w-full h-[calc(100vh-20.5rem)] lg:h-[calc(100vh-18rem)]"
|
||||||
download
|
|
||||||
className="mt-4 inline-flex items-center justify-center px-4 pt-2 pb-0 border border-transparent text-sm font-medium rounded-md text-white bg-primary hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"
|
|
||||||
>
|
>
|
||||||
Download PDF
|
<Card>
|
||||||
</a>
|
<CardHeader className="pb-2">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<CardTitle>PDF Preview Not Supported</CardTitle>
|
||||||
|
</div>
|
||||||
|
<CardDescription className="text-base">
|
||||||
|
Your browser doesn't support PDF preview.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-2">
|
||||||
|
<Link
|
||||||
|
href="/cv.pdf"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Badge variant="secondary" className="capitalize">
|
||||||
|
<Download className="h-4 w-4" />
|
||||||
|
Download CV
|
||||||
|
</Badge>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</object>
|
||||||
</div>
|
</div>
|
||||||
</object>
|
</TabsContent>
|
||||||
</div>
|
|
||||||
|
<TabsContent value="resume">
|
||||||
|
<div className="bg-background shadow-sm rounded-lg overflow-hidden">
|
||||||
|
<object
|
||||||
|
data="/resume.pdf"
|
||||||
|
type="application/pdf"
|
||||||
|
className="w-full h-[calc(100vh-20.5rem)] lg:h-[calc(100vh-18rem)]"
|
||||||
|
>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="pb-2">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<CardTitle>PDF Preview Not Supported</CardTitle>
|
||||||
|
</div>
|
||||||
|
<CardDescription className="text-base">
|
||||||
|
Your browser doesn't support PDF preview.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-2">
|
||||||
|
<Link
|
||||||
|
href="/resume.pdf"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Badge variant="secondary" className="capitalize">
|
||||||
|
<Download className="h-4 w-4" />
|
||||||
|
Download Resume
|
||||||
|
</Badge>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</object>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export default function HomePage() {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Featured Projects Section */}
|
{/* Featured Projects Section */}
|
||||||
<section className="space-y-4">
|
<section className="space-y-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-2xl font-bold">Featured Projects 🌟</h2>
|
<h2 className="text-2xl font-bold">Featured Projects 🌟</h2>
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default function ProjectsPage() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-6">
|
||||||
<section className="prose prose-zinc dark:prose-invert max-w-none">
|
<section className="prose prose-zinc dark:prose-invert max-w-none">
|
||||||
<h1 className="text-2xl font-bold">Featured Projects 🌟</h1>
|
<h1 className="text-2xl font-bold">Featured Projects 🌟</h1>
|
||||||
<p className="text-lg text-muted-foreground">
|
<p className="text-lg text-muted-foreground">
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export default function PublicationsPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-6">
|
||||||
<section className="prose prose-zinc dark:prose-invert max-w-none">
|
<section className="prose prose-zinc dark:prose-invert max-w-none">
|
||||||
<h1 className="text-2xl font-bold">Publications 📚</h1>
|
<h1 className="text-2xl font-bold">Publications 📚</h1>
|
||||||
<p className="text-lg text-muted-foreground">
|
<p className="text-lg text-muted-foreground">
|
||||||
|
|||||||
55
src/components/ui/tabs.tsx
Normal file
55
src/components/ui/tabs.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
||||||
|
|
||||||
|
import { cn } from "~/lib/utils"
|
||||||
|
|
||||||
|
const Tabs = TabsPrimitive.Root
|
||||||
|
|
||||||
|
const TabsList = React.forwardRef<
|
||||||
|
React.ElementRef<typeof TabsPrimitive.List>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<TabsPrimitive.List
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TabsList.displayName = TabsPrimitive.List.displayName
|
||||||
|
|
||||||
|
const TabsTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<TabsPrimitive.Trigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
||||||
|
|
||||||
|
const TabsContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<TabsPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TabsContent.displayName = TabsPrimitive.Content.displayName
|
||||||
|
|
||||||
|
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
||||||
Reference in New Issue
Block a user