document view complete

This commit is contained in:
Youwen Wu 2024-02-10 15:02:29 -08:00
parent aac0e10cc6
commit 7d047560e8
8 changed files with 346 additions and 153 deletions

153
src/app/db/data.ts Normal file
View file

@ -0,0 +1,153 @@
/*
documents db schema
documents {
slug: {
manifest: {
title: string
authors: string[]
date: unix epoch integer[]
type: presentation | report | white paper | other
latest: integer >= 1
keywords: string[]
topics: string[]
references: string[],
code: url[]
},
abstract: string,
file: pdf | docx | pptx | targz | other, named file[rev].[ext]
(eg. revision 1 = file1.pdf, revision 2 = file2.pdf, etc)
the "latest" should be the latest revision
}
}
*/
export type FileType = 'pdf' | 'docx' | 'pptx' | 'targz' | 'other'
export type DocumentType = 'presentation' | 'report' | 'white paper' | 'other'
export interface DocumentDB {
[key: string]: {
manifest: {
title: string
authors: string[]
topics: string[]
dates: number[]
references?: string[]
code?: string[]
type: DocumentType
latest: number
}
abstract: string
file: FileType
}
}
export const documents: DocumentDB = {
'day-5-principles': {
manifest: {
title: 'Day 5 Principles',
authors: ['shasan'],
topics: ['frc', 'mech'],
dates: [1707281608],
type: 'presentation',
latest: 1,
},
abstract:
'This guide to mechanical engineering covers gears and gear ratios, gear types, gear diagrams and measurements and sprockets and chains. It also introduces a discussion of power in the context of gears and mechanical engineering specific to FRC robotics.',
file: 'pdf',
},
}
export interface Topics {
[key: string]: {
name: string
description: string
wiki: string
}
}
export const topics: Topics = {
frc: {
name: 'FIRST Robotics Competition',
description:
'FRC is an international robotics competition that was founded by FIRST in 1983 and is currently one of the largest professional robotics competitions in the world.',
wiki: 'https://en.wikipedia.org/wiki/FIRST_Robotics_Competition',
},
mech: {
name: 'Mechanical Engineering',
description:
'Mechanical engineering is a branch of engineering that involves the design, development, and use of machines, mechanisms, and other devices.',
wiki: 'https://en.wikipedia.org/wiki/Mechanical_engineering',
},
eecs: {
name: 'Electrical Engineering and Computer Science',
description:
'Electrical engineering and computer science are fields that combine engineering, science, and computing. The acronym EECS is derived from ther world-renowned electrical engineering and computer science program at the University of California, Berkeley.',
wiki: 'https://en.wikipedia.org/wiki/Computer_science_and_engineering',
},
ai: {
name: 'Artificial Intelligence',
description:
'Artificial intelligence (AI) refers to the simulation of human intelligence in machines that are programmed to think like humans and mimic their actions.',
wiki: 'https://en.wikipedia.org/wiki/Artificial_intelligence',
},
econ: {
name: 'Economics',
description:
'Economics is the study of the production, distribution, consumption, and trade of goods and services.',
wiki: 'https://en.wikipedia.org/wiki/Economics',
},
}
export interface Authors {
[key: string]: {
name: {
first: string
last: string
}
affiliation: string[]
image: string
nationality: string[]
}
}
export const authors: Authors = {
shasan: {
name: {
first: 'Saim',
last: 'Hasan',
},
affiliation: [
'Lead Mechanical Engineer @1280-mech',
'Undergraduate @usc-viterbi',
],
image: 'https://team-1280.vercel.app/assets/img/gallery6.jpg',
nationality: ['pak'],
},
mbohsali: {
name: {
first: 'Majd',
last: 'Bohsali',
},
affiliation: ['Lead Programming Engineer @1280-eecs'],
image: 'https://cdn-icons-png.freepik.com/512/3177/3177440.png',
nationality: ['lbn'],
},
avenkatesh: {
name: {
first: 'Ananth',
last: 'Venkatesh',
},
affiliation: [
'Programming Lead @1280-programming',
'Lead Controls Engineer @1280-eecs',
],
image: 'https://cdn-icons-png.freepik.com/512/3177/3177440.png',
nationality: ['ind', 'eth'],
},
ywu: {
name: {
first: 'Youwen',
last: 'Wu',
},
affiliation: ['Artificial Intelligence Lead @1280-eecs'],
image:
'https://static.wikia.nocookie.net/discoelysium_gamepedia_en/images/9/95/Portrait_evrart.png/revision/latest?cb=20191028100247',
nationality: ['chn'],
},
}

View file

@ -1,61 +0,0 @@
.itemTitle {
margin: 0;
font-size: 2em;
}
.itemAuthors {
margin-bottom: 0;
}
.itemDates {
margin-top: 0;
}
.itemType {
display: inline-block;
width: fit-content;
padding-left: 10px;
padding-right: 10px;
padding-top: 5px;
padding-bottom: 5px;
margin-right: 10px;
border-radius: 5px;
margin-top: 10px;
}
.typeReport {
background-color: #28a745;
}
.itemRevision {
display: inline-block;
}
.itemAbstractHeader {
margin-top: 20px;
margin-bottom: 10px;
color: 33;
font-size: 1.5em;
}
.itemAbstract {
margin-top: 10px;
color: #666;
font-size: 1.2em;
}
.typePresentation {
background-color: #007bff;
}
.typeOther {
background-color: #6c757d;
}
.resultAbstract {
color: #333;
}
.downloadButton {
padding: 10px;
}

View file

@ -1,92 +0,0 @@
'use client'
import styles from './documentViewer.module.css'
import { Zilla_Slab } from 'next/font/google'
import { saveAs } from 'file-saver'
const zillaSlab = Zilla_Slab({ subsets: ['latin'], weight: ['500'] })
export default function Page({
params,
}: Readonly<{ params: { docName: string } }>) {
const handleDownload = () => {
saveAs(`/download/${params.docName}/file.pdf`, `${params.docName}.pdf`)
}
type ItemType = 'report' | 'presentation' | 'other'
const generateItemBadge = (itemName: ItemType) => {
let itemStyle: string
switch (itemName) {
case 'report':
itemStyle = `${styles.itemType} bg-green-400`
break
case 'presentation':
itemStyle = `${styles.itemType} bg-blue-400`
break
case 'other':
itemStyle = `${styles.itemType} bg-amber-400`
}
return (
<p className={itemStyle}>
{itemName.charAt(0).toUpperCase()}
{itemName.slice(1)}
</p>
)
}
return (
<div id='content'>
<div>
<h3
className={`
${styles.itemTitle}
text-slate-800
${zillaSlab.className}
`}
>
2024 Controls/Programming DWM
</h3>
<p className={`${styles.itemAuthors} text-slate-800 mt-2`}>
<a href='../author/#mbohsali'>Majd Bohsali</a> and{' '}
<a href='../author/#avenkatesh'>Ananth Venkatesh</a>
</p>
<p className='mt-4'>Published Jan 22, 2024</p>
{generateItemBadge('report')}
<p className={styles.itemRevision}>Revision 1</p>
<h4 className={styles.itemAbstractHeader}>Abstract</h4>
<p className='my-2 text-xl text-slate-600'>
This document outlines the first two weeks of prototyping conducted by
the EECS subteam for Team 1280. Action items are presented in a
doing/working/moving format to keep track of new developments related
to EECS projects.
</p>
<p className='my-2'>
<strong>Topics</strong>:{' '}
<a href='../topic/#frc'>FIRST Robotics Competition</a>,{' '}
<a href='../topic/#eecs'>
Electrical Engineering and Computer Science
</a>
</p>
<p className='my-2'>
<strong>Code</strong>:{' '}
<a href='https://github.com/Team-1280/Swerve' target='_blank'>
https://github.com/Team-1280/Swerve
</a>
,{' '}
<a href='https://github.com/Team-1280/Jankboard' target='_blank'>
https://github.com/Team-1280/Jankboard
</a>
,{' '}
<a href='https://github.com/Team-1280/identity' target='_blank'>
https://github.com/Team-1280/identity
</a>
</p>
<button
className='bg-blue-600 text-slate-100 hover:bg-blue-300 font-semibold rounded py-2 px-4 my-2'
onClick={handleDownload}
>
Download PDF
</button>
</div>
</div>
)
}

View file

@ -0,0 +1,7 @@
'use server'
import { redirect } from 'next/navigation'
export async function navigate(url: string) {
redirect(url)
}

View file

@ -0,0 +1,27 @@
.itemTitle {
margin: 0;
font-size: 2em;
}
.itemAbstractHeader {
margin-top: 20px;
margin-bottom: 10px;
color: 33;
font-size: 1.5em;
}
.typePresentation {
background-color: #007bff;
}
.typeOther {
background-color: #6c757d;
}
.resultAbstract {
color: #333;
}
.downloadButton {
padding: 10px;
}

View file

@ -0,0 +1 @@
declare module 'unix-timestamp'

View file

@ -0,0 +1,158 @@
'use client'
import styles from './documentViewer.module.css'
import { Zilla_Slab } from 'next/font/google'
import { saveAs } from 'file-saver'
import {
DocumentType,
documents,
topics as topicList,
authors as authorList,
} from '../../../db/data'
import { navigate } from './actions'
import Link from 'next/link'
const zillaSlab = Zilla_Slab({ subsets: ['latin'], weight: ['500'] })
function epoch2datestring(epoch: number): string {
// Create a new Date object from the epoch
const date = new Date(epoch * 1000)
// Format the date to the specified format
const formattedDate = date.toLocaleDateString('en-US', {
month: 'short', // abbreviated month name
day: '2-digit', // day as two digits
year: 'numeric', // four digit year
})
return formattedDate
}
export default function Page({
params,
}: Readonly<{ params: { slug: string } }>) {
const doc = documents[params.slug]
if (!doc) {
navigate('/404')
return
}
const { abstract, file } = doc
const { title, authors, topics, dates, references, code, type, latest } =
doc.manifest
const handleDownloadLatest = () => {
saveAs(
`/download/${params.slug}/file${latest}.pdf`,
`${params.slug}-rev-${latest}.pdf`
)
}
const generateTopics = () => {
return (
<>
<span className='font-bold'>Topics: </span>
{topics.map((t: string, i) => (
<>
<Link href={topicList[t].wiki} target='_blank'>
{topicList[t].name}
</Link>
{i !== topics.length - 1 ? ', ' : null}
</>
))}
</>
)
}
const generateCode = () => {
if (code) {
return (
<>
<span className='font-bold'>Code: </span>
{code.map((c: string, i) => (
<>
<Link href={c} target='_blank'>
{c}
</Link>
{i !== code.length - 1 ? ', ' : null}
</>
))}
</>
)
}
}
const generateAuthors = () => {
return (
<>
{authors.map((a: string, i) => (
<>
<Link href={`/author/${a}`} target='_blank'>
{authorList[a].name.first} {authorList[a].name.last}
</Link>
{i !== authors.length - 1 && authors.length > 2 ? ', ' : null}
{i === authors.length - 2 ? ' and ' : null}
</>
))}
</>
)
}
const generateItemBadge = (itemName: DocumentType) => {
let itemStyle: string = 'px-3 py-1 rounded inline-block w-fit mr-2 mt-4 '
switch (itemName) {
case 'report':
itemStyle += 'bg-green-400 text-slate-50'
break
case 'presentation':
itemStyle += `bg-blue-400 text-slate-50`
break
case 'white paper':
itemStyle += `bg-fuchsia-700 text-slate-50`
break
case 'other':
itemStyle += `bg-gray-400 text-slate-50`
break
}
return (
<p className={itemStyle}>
{itemName.charAt(0).toUpperCase()}
{itemName.slice(1)}
</p>
)
}
return (
<div>
<div>
<h3
className={`
${styles.itemTitle}
text-slate-800
${zillaSlab.className}
`}
>
{title}
</h3>
<p className={`text-slate-800 mt-2`}>{generateAuthors()}</p>
<p className='mt-4'>
Latest revision published{' '}
<span className='font-bold'>
{epoch2datestring(dates[dates.length - 1])}
</span>
</p>
{generateItemBadge('report')}
<p className='inline-block'>Revision {latest}</p>
<hr className='w-10/12 my-4' />
<h4 className='text-2xl mt-5 font-serif font-semibold'>Abstract</h4>
<p className='my-4 text-xl text-slate-600 font-serif '>{abstract}</p>
<p className='my-2'>{generateTopics()}</p>
<p className='my-2'>{generateCode()}</p>
<button
className='bg-blue-600 text-slate-100 hover:bg-blue-400 font-semibold rounded py-2 px-4 my-2'
onClick={handleDownloadLatest}
>
Download {file !== 'other' ? file.toUpperCase() : null}
</button>
</div>
</div>
)
}