implemented pdf viewer functionality.
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default function PageNotFound() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>404</h1>
|
||||||
|
<p>This is not the page you are looking for.</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
+4
-1
@@ -4,7 +4,10 @@ import PdfViewer from "./components/PdfViewer";
|
|||||||
export default function Resume() {
|
export default function Resume() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PdfViewer file="resume.pdf" />
|
<div id="resume-section">
|
||||||
|
<h1>Resume</h1>
|
||||||
|
<PdfViewer file="resume.pdf" />
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { Document, Page, pdfjs } from "react-pdf";
|
import { Document, Page, pdfjs } from "react-pdf";
|
||||||
import "react-pdf/dist/Page/TextLayer.css";
|
import "react-pdf/dist/Page/TextLayer.css";
|
||||||
import "react-pdf/dist/Page/AnnotationLayer.css";
|
import "react-pdf/dist/Page/AnnotationLayer.css";
|
||||||
@@ -9,13 +9,40 @@ export default function PdfViewer({ file }) {
|
|||||||
import.meta.url,
|
import.meta.url,
|
||||||
).toString();
|
).toString();
|
||||||
|
|
||||||
|
const [numPages, setNumPages] = useState(0);
|
||||||
|
const [pageNumber, setPageNumber] = useState(1);
|
||||||
|
function prev() {
|
||||||
|
if (pageNumber >= 2) {
|
||||||
|
setPageNumber(pageNumber - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
if (pageNumber < numPages - 1) {
|
||||||
|
setPageNumber(pageNumber + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("numPages: " + numPages);
|
||||||
|
console.log("pageNumber: " + pageNumber);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="pdf-container">
|
<div className="pdf-container">
|
||||||
<Document file={file}>
|
<button className="pdf-button shadow" onClick={() => prev()}>
|
||||||
<Page pageNumber={1} />
|
<span className="material-icons">arrow_back</span>
|
||||||
<Page pageNumber={2} />
|
</button>
|
||||||
|
<Document
|
||||||
|
file={file}
|
||||||
|
onLoadSuccess={({ numPages: numPagesInPdf }) => {
|
||||||
|
setNumPages(numPagesInPdf);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Page pageNumber={pageNumber} />
|
||||||
</Document>
|
</Document>
|
||||||
|
<button className="pdf-button shadow" onClick={() => next()}>
|
||||||
|
<span className="material-icons">arrow_forward</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const SkillCard = ({ header, symbol, list, isActive, onToggle }) => {
|
|||||||
<span className="material-icons skill-symbol">{symbol}</span>
|
<span className="material-icons skill-symbol">{symbol}</span>
|
||||||
<h3>{header}</h3>
|
<h3>{header}</h3>
|
||||||
</div>
|
</div>
|
||||||
{isActive && (
|
{(isActive || !isMobile) && (
|
||||||
<ul>
|
<ul>
|
||||||
{list.map((item, index) => (
|
{list.map((item, index) => (
|
||||||
<li key={index}>{item}</li>
|
<li key={index}>{item}</li>
|
||||||
|
|||||||
+30
-12
@@ -211,7 +211,6 @@ h4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#skill-cards {
|
#skill-cards {
|
||||||
border: 1px solid white;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +227,7 @@ h4 {
|
|||||||
background-color: #ebd2ff;
|
background-color: #ebd2ff;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
min-width: 20vw;
|
min-width: 20vw;
|
||||||
max-width: 40vw;
|
max-width: 50vw;
|
||||||
margin: 1vw;
|
margin: 1vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +235,7 @@ h4 {
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 20% 60%;
|
grid-template-columns: 20% 60%;
|
||||||
grid-template-rows: 100%;
|
grid-template-rows: 100%;
|
||||||
column-gap: 20%;
|
column-gap: 10%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -246,6 +245,10 @@ h4 {
|
|||||||
background-color: #4a245e;
|
background-color: #4a245e;
|
||||||
border-radius: 18px 18px 0 0;
|
border-radius: 18px 18px 0 0;
|
||||||
}
|
}
|
||||||
|
.skill-card-header h3 {
|
||||||
|
font-size: clamp(1.3rem, 2vw, 3rem);
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
.skill-symbol {
|
.skill-symbol {
|
||||||
font-variation-settings:
|
font-variation-settings:
|
||||||
@@ -311,6 +314,7 @@ h4 {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
margin-left: 1vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-card img {
|
.project-card img {
|
||||||
@@ -447,12 +451,31 @@ h4 {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#resume-section {
|
||||||
|
margin: 2vw;
|
||||||
|
}
|
||||||
|
|
||||||
/**PDF Viewer**/
|
/**PDF Viewer**/
|
||||||
.pdf-container {
|
.pdf-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
max-width: 100%;
|
||||||
|
height: 70vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-button {
|
||||||
|
background-color: #ebd2ff;
|
||||||
|
color: #4a245e;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
padding: 1vw;
|
||||||
|
margin: 1vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-button span {
|
||||||
|
color: #4a245e;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Animations**/
|
/**Animations**/
|
||||||
@@ -614,21 +637,16 @@ h4 {
|
|||||||
margin-left: 5vw;
|
margin-left: 5vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pdf-viewer {
|
|
||||||
max-width: 100%;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pdf-page {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#card-grid {
|
#card-grid {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 485px) {
|
@media (max-width: 485px) {
|
||||||
|
|||||||
+4
-2
@@ -3,14 +3,16 @@ import { createRoot } from "react-dom/client";
|
|||||||
import { BrowserRouter as Router, Routes, Route } from "react-router";
|
import { BrowserRouter as Router, Routes, Route } from "react-router";
|
||||||
import App from "./App.jsx";
|
import App from "./App.jsx";
|
||||||
import Resume from "./Resume.jsx";
|
import Resume from "./Resume.jsx";
|
||||||
|
import PageNotFound from "./PageNotFound.jsx";
|
||||||
|
|
||||||
const container = document.getElementById("app");
|
const container = document.getElementById("app");
|
||||||
const root = createRoot(container); // createRoot(container!) if you use TypeScript
|
const root = createRoot(container); // createRoot(container!) if you use TypeScript
|
||||||
root.render(
|
root.render(
|
||||||
<Router>
|
<Router>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<App />} />
|
<Route exact path="/" element={<App />} />
|
||||||
<Route path="/resume" element={<Resume />} />
|
<Route exact path="/resume" element={<Resume />} />
|
||||||
|
<Route path="*" element={<PageNotFound />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>,
|
</Router>,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user