document view complete
This commit is contained in:
parent
aac0e10cc6
commit
7d047560e8
8 changed files with 346 additions and 153 deletions
153
src/app/db/data.ts
Normal file
153
src/app/db/data.ts
Normal 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'],
|
||||||
|
},
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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>
|
|
||||||
)
|
|
||||||
}
|
|
7
src/app/document/view/[slug]/actions.ts
Normal file
7
src/app/document/view/[slug]/actions.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
'use server'
|
||||||
|
|
||||||
|
import { redirect } from 'next/navigation'
|
||||||
|
|
||||||
|
export async function navigate(url: string) {
|
||||||
|
redirect(url)
|
||||||
|
}
|
27
src/app/document/view/[slug]/documentViewer.module.css
Normal file
27
src/app/document/view/[slug]/documentViewer.module.css
Normal 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;
|
||||||
|
}
|
1
src/app/document/view/[slug]/page.d.ts
vendored
Normal file
1
src/app/document/view/[slug]/page.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
declare module 'unix-timestamp'
|
158
src/app/document/view/[slug]/page.tsx
Normal file
158
src/app/document/view/[slug]/page.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in a new issue