mirror of
https://github.com/soconnor0919/personal-website.git
synced 2026-02-05 00:06:36 -05:00
Add presentation slides for ROMAN 2025 paper
This commit is contained in:
@@ -6,9 +6,9 @@ import { join } from "path";
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { filename: string } },
|
||||
context: { params: Promise<{ filename: string }> },
|
||||
) {
|
||||
const filename = params.filename;
|
||||
const { filename } = await context.params;
|
||||
|
||||
// Validate filename to prevent path traversal
|
||||
if (!filename || filename.includes("..") || !filename.endsWith(".pdf")) {
|
||||
@@ -24,18 +24,25 @@ export async function GET(
|
||||
// Find the publication that matches this PDF
|
||||
const publication = publications.find(
|
||||
(pub) =>
|
||||
pub.paperUrl?.includes(filename) || pub.posterUrl?.includes(filename),
|
||||
pub.paperUrl?.includes(filename) ||
|
||||
pub.posterUrl?.includes(filename) ||
|
||||
pub.slidesUrl?.includes(filename),
|
||||
);
|
||||
|
||||
// Track the PDF access
|
||||
if (publication) {
|
||||
const isPoster = publication.posterUrl?.includes(filename);
|
||||
const isSlides = publication.slidesUrl?.includes(filename);
|
||||
|
||||
let fileType = "paper";
|
||||
if (isPoster) fileType = "poster";
|
||||
if (isSlides) fileType = "slides";
|
||||
|
||||
await track("Publication PDF Access", {
|
||||
title: publication.title,
|
||||
type: publication.type,
|
||||
year: publication.year.toString(),
|
||||
pdf_type: isPoster ? "poster" : "paper",
|
||||
pdf_type: fileType,
|
||||
citation_key: publication.citationKey || "",
|
||||
venue: publication.venue || "",
|
||||
access_method: "direct_url",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Analytics } from "@vercel/analytics/react";
|
||||
import { SpeedInsights } from "@vercel/speed-insights/next";
|
||||
import type { Metadata } from "next";
|
||||
import { Footer } from "~/components/Footer";
|
||||
import { Navigation } from "~/components/Navigation";
|
||||
import { Sidebar } from "~/components/Sidebar";
|
||||
@@ -9,7 +10,7 @@ import { inter } from "~/lib/fonts";
|
||||
import { description, name } from "~/lib/data";
|
||||
import "~/styles/globals.css";
|
||||
|
||||
export const metadata = {
|
||||
export const metadata: Metadata = {
|
||||
title: `${name[0]?.first} ${name[0]?.last}`,
|
||||
description: description,
|
||||
icons: [{ rel: "icon", url: "/favicon.ico" }],
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
FileText,
|
||||
Presentation,
|
||||
BookOpen,
|
||||
Monitor,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
@@ -25,6 +26,7 @@ import {
|
||||
trackPdfView,
|
||||
trackDoiClick,
|
||||
trackBibtexDownload,
|
||||
trackSlidesView,
|
||||
} from "~/lib/analytics";
|
||||
|
||||
export default function PublicationsPage() {
|
||||
@@ -128,6 +130,16 @@ export default function PublicationsPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSlidesClick = (pub: Publication) => {
|
||||
trackSlidesView({
|
||||
publicationTitle: pub.title,
|
||||
publicationType: pub.type,
|
||||
publicationYear: pub.year,
|
||||
citationKey: pub.citationKey,
|
||||
venue: pub.venue,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<section className="animate-fade-in-up prose prose-zinc dark:prose-invert max-w-none">
|
||||
@@ -199,7 +211,10 @@ export default function PublicationsPage() {
|
||||
</p>
|
||||
)}
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
<Badge variant="secondary" className="capitalize">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="flex h-6 items-center capitalize"
|
||||
>
|
||||
{pub.type}
|
||||
</Badge>
|
||||
{pub.doi && (
|
||||
@@ -209,7 +224,10 @@ export default function PublicationsPage() {
|
||||
rel="noopener noreferrer"
|
||||
onClick={() => handleDoiClick(pub)}
|
||||
>
|
||||
<Badge variant="secondary" className="capitalize">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="flex h-6 items-center capitalize"
|
||||
>
|
||||
<ArrowUpRight className="mr-1 h-3 w-3" />
|
||||
DOI
|
||||
</Badge>
|
||||
@@ -222,7 +240,10 @@ export default function PublicationsPage() {
|
||||
rel="noopener noreferrer"
|
||||
onClick={() => handlePaperClick(pub)}
|
||||
>
|
||||
<Badge variant="secondary" className="capitalize">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="flex h-6 items-center capitalize"
|
||||
>
|
||||
<FileText className="mr-1 h-3 w-3" />
|
||||
Paper
|
||||
</Badge>
|
||||
@@ -235,15 +256,34 @@ export default function PublicationsPage() {
|
||||
rel="noopener noreferrer"
|
||||
onClick={() => handlePosterClick(pub)}
|
||||
>
|
||||
<Badge variant="secondary" className="capitalize">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="flex h-6 items-center capitalize"
|
||||
>
|
||||
<Presentation className="mr-1 h-3 w-3" />
|
||||
Poster
|
||||
</Badge>
|
||||
</Link>
|
||||
)}
|
||||
{pub.slidesUrl && (
|
||||
<Link
|
||||
href={pub.slidesUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={() => handleSlidesClick(pub)}
|
||||
>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="flex h-6 items-center capitalize"
|
||||
>
|
||||
<Monitor className="mr-1 h-3 w-3" />
|
||||
Slides
|
||||
</Badge>
|
||||
</Link>
|
||||
)}
|
||||
<Badge
|
||||
onClick={() => downloadBibtex(pub)}
|
||||
className="cursor-pointer capitalize"
|
||||
className="flex h-6 cursor-pointer items-center capitalize"
|
||||
variant="secondary"
|
||||
>
|
||||
<BookOpenText className="mr-1 h-3 w-3" />
|
||||
|
||||
@@ -9,12 +9,12 @@ export function CardSkeleton() {
|
||||
<Skeleton className="h-6 w-1/3" />
|
||||
<Skeleton className="h-5 w-5 rounded-full" />
|
||||
</div>
|
||||
<Skeleton className="h-4 w-full mt-2" />
|
||||
<Skeleton className="mt-2 h-4 w-full" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-5/6 mt-2" />
|
||||
<div className="flex gap-2 mt-4">
|
||||
<Skeleton className="mt-2 h-4 w-5/6" />
|
||||
<div className="mt-4 flex gap-2">
|
||||
<Skeleton className="h-5 w-16" />
|
||||
<Skeleton className="h-5 w-16" />
|
||||
<Skeleton className="h-5 w-16" />
|
||||
@@ -37,4 +37,4 @@ export function AboutCardSkeleton() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface PublicationTrackingData {
|
||||
publicationTitle: string;
|
||||
publicationType: "conference" | "journal" | "workshop" | "thesis";
|
||||
publicationYear: number;
|
||||
linkType: "paper" | "poster" | "doi" | "bibtex";
|
||||
linkType: "paper" | "poster" | "slides" | "doi" | "bibtex";
|
||||
citationKey?: string;
|
||||
venue?: string;
|
||||
}
|
||||
@@ -94,3 +94,18 @@ export function trackDoiClick(
|
||||
venue: data.venue || "",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Track slides views specifically
|
||||
*/
|
||||
export function trackSlidesView(
|
||||
data: Omit<PublicationTrackingData, "linkType">,
|
||||
) {
|
||||
track("Publication Slides View", {
|
||||
title: data.publicationTitle,
|
||||
type: data.publicationType,
|
||||
year: data.publicationYear.toString(),
|
||||
citation_key: data.citationKey || "",
|
||||
venue: data.venue || "",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export type Publication = {
|
||||
url?: string;
|
||||
paperUrl?: string;
|
||||
posterUrl?: string;
|
||||
slidesUrl?: string;
|
||||
abstract?: string;
|
||||
citationType?: string;
|
||||
citationKey?: string;
|
||||
@@ -115,6 +116,7 @@ export function parseBibtex(bibtex: string): Publication[] {
|
||||
url: entry.fields.url,
|
||||
paperUrl: entry.fields.paperurl,
|
||||
posterUrl: entry.fields.posterurl,
|
||||
slidesUrl: entry.fields.slidesurl,
|
||||
abstract: entry.fields.abstract,
|
||||
citationType: entry.type,
|
||||
citationKey: entry.citationKey,
|
||||
|
||||
Reference in New Issue
Block a user