diff --git a/public/download/day-5-principles-1/file.pdf b/public/download/day-5-principles/file1.pdf
similarity index 100%
rename from public/download/day-5-principles-1/file.pdf
rename to public/download/day-5-principles/file1.pdf
diff --git a/src/app/db/data.ts b/src/app/db/data.ts
new file mode 100644
index 0000000..696631d
--- /dev/null
+++ b/src/app/db/data.ts
@@ -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'],
+ },
+}
diff --git a/src/app/document/view/[docName]/documentViewer.module.css b/src/app/document/view/[docName]/documentViewer.module.css
deleted file mode 100644
index 3d9e24b..0000000
--- a/src/app/document/view/[docName]/documentViewer.module.css
+++ /dev/null
@@ -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;
-}
diff --git a/src/app/document/view/[docName]/page.tsx b/src/app/document/view/[docName]/page.tsx
deleted file mode 100644
index 23158c1..0000000
--- a/src/app/document/view/[docName]/page.tsx
+++ /dev/null
@@ -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 (
-
- {itemName.charAt(0).toUpperCase()}
- {itemName.slice(1)}
-
- )
- }
-
- return (
-
- )
-}
diff --git a/src/app/document/view/[slug]/actions.ts b/src/app/document/view/[slug]/actions.ts
new file mode 100644
index 0000000..badbcda
--- /dev/null
+++ b/src/app/document/view/[slug]/actions.ts
@@ -0,0 +1,7 @@
+'use server'
+
+import { redirect } from 'next/navigation'
+
+export async function navigate(url: string) {
+ redirect(url)
+}
diff --git a/src/app/document/view/[slug]/documentViewer.module.css b/src/app/document/view/[slug]/documentViewer.module.css
new file mode 100644
index 0000000..1ae3e1c
--- /dev/null
+++ b/src/app/document/view/[slug]/documentViewer.module.css
@@ -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;
+}
diff --git a/src/app/document/view/[slug]/page.d.ts b/src/app/document/view/[slug]/page.d.ts
new file mode 100644
index 0000000..4cc74f3
--- /dev/null
+++ b/src/app/document/view/[slug]/page.d.ts
@@ -0,0 +1 @@
+declare module 'unix-timestamp'
diff --git a/src/app/document/view/[slug]/page.tsx b/src/app/document/view/[slug]/page.tsx
new file mode 100644
index 0000000..78ac6de
--- /dev/null
+++ b/src/app/document/view/[slug]/page.tsx
@@ -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 (
+ <>
+ Topics:
+ {topics.map((t: string, i) => (
+ <>
+
+ {topicList[t].name}
+
+ {i !== topics.length - 1 ? ', ' : null}
+ >
+ ))}
+ >
+ )
+ }
+
+ const generateCode = () => {
+ if (code) {
+ return (
+ <>
+ Code:
+ {code.map((c: string, i) => (
+ <>
+
+ {c}
+
+ {i !== code.length - 1 ? ', ' : null}
+ >
+ ))}
+ >
+ )
+ }
+ }
+
+ const generateAuthors = () => {
+ return (
+ <>
+ {authors.map((a: string, i) => (
+ <>
+
+ {authorList[a].name.first} {authorList[a].name.last}
+
+ {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 (
+
+ {itemName.charAt(0).toUpperCase()}
+ {itemName.slice(1)}
+
+ )
+ }
+
+ return (
+
+
+
+ {title}
+
+
{generateAuthors()}
+
+ Latest revision published{' '}
+
+ {epoch2datestring(dates[dates.length - 1])}
+
+
+ {generateItemBadge('report')}
+
Revision {latest}
+
+
Abstract
+
{abstract}
+
{generateTopics()}
+
{generateCode()}
+
+ Download {file !== 'other' ? file.toUpperCase() : null}
+
+
+
+ )
+}