diff --git a/public/publications.bib b/public/publications.bib index fcb4dd0..ee41d5c 100644 --- a/public/publications.bib +++ b/public/publications.bib @@ -7,6 +7,7 @@ abstract = {Human-robot interaction (HRI) research plays a pivotal role in shaping how robots communicate and collaborate with humans. However, conducting HRI studies can be challenging, particularly those employing the Wizard-of-Oz (WoZ) technique. WoZ user studies can have technical and methodological complexities that may render the results irreproducible. We propose to address these challenges with HRIStudio, a modular web-based platform designed to streamline the design, the execution, and the analysis of WoZ experiments. HRIStudio offers an intuitive interface for experiment creation, real-time control and monitoring during experimental runs, and comprehensive data logging and playback tools for analysis and reproducibility. By lowering technical barriers, promoting collaboration, and offering methodological guidelines, HRIStudio aims to make human-centered robotics research easier and empower researchers to develop scientifically rigorous user studies.}, url = {https://soconnor.dev/api/publications/ROMAN25_0574_FI.pdf}, paperUrl = {/api/publications/ROMAN25_0574_FI.pdf} + slidesUrl = {/api/publications/ROMAN25_0574_SLIDES.pdf} } @inproceedings{OConnor2024, diff --git a/public/publications/ROMAN25_0574_SLIDES.pdf b/public/publications/ROMAN25_0574_SLIDES.pdf new file mode 100644 index 0000000..e218428 Binary files /dev/null and b/public/publications/ROMAN25_0574_SLIDES.pdf differ diff --git a/src/app/api/publications/[filename]/route.ts b/src/app/api/publications/[filename]/route.ts index c0925e0..bade654 100644 --- a/src/app/api/publications/[filename]/route.ts +++ b/src/app/api/publications/[filename]/route.ts @@ -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", diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 56a1614..e116ff6 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -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" }], diff --git a/src/app/publications/page.tsx b/src/app/publications/page.tsx index 5814695..8f54862 100644 --- a/src/app/publications/page.tsx +++ b/src/app/publications/page.tsx @@ -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 (
@@ -199,7 +211,10 @@ export default function PublicationsPage() {

)}
- + {pub.type} {pub.doi && ( @@ -209,7 +224,10 @@ export default function PublicationsPage() { rel="noopener noreferrer" onClick={() => handleDoiClick(pub)} > - + DOI @@ -222,7 +240,10 @@ export default function PublicationsPage() { rel="noopener noreferrer" onClick={() => handlePaperClick(pub)} > - + Paper @@ -235,15 +256,34 @@ export default function PublicationsPage() { rel="noopener noreferrer" onClick={() => handlePosterClick(pub)} > - + Poster )} + {pub.slidesUrl && ( + handleSlidesClick(pub)} + > + + + Slides + + + )} downloadBibtex(pub)} - className="cursor-pointer capitalize" + className="flex h-6 cursor-pointer items-center capitalize" variant="secondary" > diff --git a/src/components/ui/skeletons.tsx b/src/components/ui/skeletons.tsx index 4aefcfb..7b46c46 100644 --- a/src/components/ui/skeletons.tsx +++ b/src/components/ui/skeletons.tsx @@ -9,12 +9,12 @@ export function CardSkeleton() {
- + - -
+ +
@@ -37,4 +37,4 @@ export function AboutCardSkeleton() { ); -} \ No newline at end of file +} diff --git a/src/lib/analytics.ts b/src/lib/analytics.ts index 4c3264d..a73e44e 100644 --- a/src/lib/analytics.ts +++ b/src/lib/analytics.ts @@ -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, +) { + track("Publication Slides View", { + title: data.publicationTitle, + type: data.publicationType, + year: data.publicationYear.toString(), + citation_key: data.citationKey || "", + venue: data.venue || "", + }); +} diff --git a/src/lib/bibtex.ts b/src/lib/bibtex.ts index f0c6d07..22988ed 100644 --- a/src/lib/bibtex.ts +++ b/src/lib/bibtex.ts @@ -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,