mirror of
https://github.com/soconnor0919/personal-website.git
synced 2026-02-05 00:06:36 -05:00
Citation generator added
This commit is contained in:
@@ -1,17 +1,18 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "~/components/ui/card";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { ArrowUpRight, FileText, Presentation } from "lucide-react";
|
||||
import { ArrowUpRight, BookOpenText, FileText, Presentation } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { parseBibtex } from "~/lib/bibtex";
|
||||
import { useEffect, useState } from "react";
|
||||
import type { Publication } from "~/lib/bibtex";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
|
||||
import { Skeleton } from "~/components/ui/skeleton";
|
||||
import type { Publication } from "~/lib/bibtex";
|
||||
import { parseBibtex } from "~/lib/bibtex";
|
||||
|
||||
export default function PublicationsPage() {
|
||||
const [publications, setPublications] = useState<Publication[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const tagsToStrip = ['paperUrl', 'posterUrl'];
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/publications.bib')
|
||||
@@ -23,6 +24,38 @@ export default function PublicationsPage() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const downloadBibtex = (pub: Publication) => {
|
||||
const { title, authors, venue, year, doi, abstract, type, citationType, citationKey } = pub;
|
||||
let bibtexEntry = `@${citationType}{${citationKey},\n`;
|
||||
bibtexEntry += ` title = {${title}},\n`;
|
||||
bibtexEntry += ` author = {${authors.join(' and ')}},\n`;
|
||||
bibtexEntry += ` year = {${year}},\n`;
|
||||
if (type === 'conference' || type === 'workshop') {
|
||||
bibtexEntry += ` organization = {${venue}},\n`;
|
||||
} else if (type === 'journal') {
|
||||
bibtexEntry += ` journal = {${venue}},\n`;
|
||||
} else if (type === 'thesis') {
|
||||
bibtexEntry += ` school = {${venue}},\n`;
|
||||
}
|
||||
if (doi) {
|
||||
bibtexEntry += ` doi = {${doi}},\n`;
|
||||
}
|
||||
if (abstract) {
|
||||
bibtexEntry += ` abstract = {${abstract}},\n`;
|
||||
}
|
||||
bibtexEntry += `}\n`;
|
||||
|
||||
const blob = new Blob([bibtexEntry], { type: 'text/plain' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `refs.bib`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<section className="prose prose-zinc dark:prose-invert max-w-none">
|
||||
@@ -49,9 +82,9 @@ export default function PublicationsPage() {
|
||||
<CardHeader className="pb-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle>{pub.title}</CardTitle>
|
||||
{pub.url && (
|
||||
{pub.paperUrl && (
|
||||
<Link
|
||||
href={pub.url}
|
||||
href={pub.paperUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-muted-foreground hover:text-primary"
|
||||
@@ -113,6 +146,14 @@ export default function PublicationsPage() {
|
||||
</Badge>
|
||||
</Link>
|
||||
)}
|
||||
<Badge
|
||||
onClick={() => downloadBibtex(pub)}
|
||||
className="cursor-pointer capitalize"
|
||||
variant="outline"
|
||||
>
|
||||
<BookOpenText className="h-4 w-4" />
|
||||
BibTeX
|
||||
</Badge>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -8,12 +8,15 @@ export type Publication = {
|
||||
paperUrl?: string;
|
||||
posterUrl?: string;
|
||||
abstract?: string;
|
||||
citationType?: string;
|
||||
citationKey?: string;
|
||||
type: 'conference' | 'journal' | 'workshop' | 'thesis';
|
||||
};
|
||||
|
||||
type BibTeXEntry = {
|
||||
type: string;
|
||||
fields: Record<string, string>;
|
||||
citationKey: string;
|
||||
};
|
||||
|
||||
function parseAuthors(authorString: string): string[] {
|
||||
@@ -31,10 +34,11 @@ function parseAuthors(authorString: string): string[] {
|
||||
|
||||
function parseBibTeXEntry(entry: string): BibTeXEntry | null {
|
||||
// Match the entry type and content
|
||||
const typeMatch = entry.match(/^(\w+)\s*{\s*[\w\d-_]+\s*,/);
|
||||
const typeMatch = entry.match(/^(\w+)\s*{\s*([\w\d-_]+)\s*,/);
|
||||
if (!typeMatch) return null;
|
||||
|
||||
const type = typeMatch[1]!.toLowerCase();
|
||||
const citationKey = typeMatch[2];
|
||||
const content = entry.slice(typeMatch[0].length);
|
||||
|
||||
const fields: Record<string, string> = {};
|
||||
@@ -68,7 +72,7 @@ function parseBibTeXEntry(entry: string): BibTeXEntry | null {
|
||||
fields[currentField] = buffer.trim();
|
||||
}
|
||||
|
||||
return { type, fields };
|
||||
return { type, fields, citationKey: citationKey! };
|
||||
}
|
||||
|
||||
export function parseBibtex(bibtex: string): Publication[] {
|
||||
@@ -79,10 +83,21 @@ export function parseBibtex(bibtex: string): Publication[] {
|
||||
.filter((entry): entry is BibTeXEntry => entry !== null);
|
||||
|
||||
return entries.map(entry => {
|
||||
const publicationType =
|
||||
entry.type === 'inproceedings' ? 'conference' :
|
||||
entry.type === 'article' ? 'journal' :
|
||||
entry.type === 'mastersthesis' ? 'thesis' : 'workshop';
|
||||
const publicationType = (() => {
|
||||
switch (entry.type) {
|
||||
case 'inproceedings':
|
||||
case 'conference':
|
||||
return 'conference';
|
||||
case 'article':
|
||||
return 'journal';
|
||||
case 'mastersthesis':
|
||||
return 'thesis';
|
||||
case 'workshop':
|
||||
return 'workshop';
|
||||
default:
|
||||
return 'journal';
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
title: entry.fields.title?.replace(/[{}]/g, '') || '',
|
||||
@@ -94,6 +109,8 @@ export function parseBibtex(bibtex: string): Publication[] {
|
||||
paperUrl: entry.fields.paperurl,
|
||||
posterUrl: entry.fields.posterurl,
|
||||
abstract: entry.fields.abstract,
|
||||
citationType: entry.type,
|
||||
citationKey: entry.citationKey,
|
||||
type: publicationType
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user