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