This commit is contained in:
2025-04-06 00:10:19 +00:00
parent b753252b3c
commit 3f8360f3f3
101 changed files with 167 additions and 141 deletions

View File

@@ -1,13 +1,10 @@
import { useLayoutEffect, useState, useRef, useEffect } from "react";
import { pdfjs, Document, Page } from "react-pdf";
import { ArrowBackIcon, ArrowForwardIcon, MenuBookIcon, MyLocationIcon } from "./icons/Icons";
import structureOriginal from "./structure.json";
const structure = structureOriginal.map((topic) => ({ ...topic, version: 0 }));
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
export function TopicListView({ selectedIndex, onChange }) {
const itemRefs = useRef([]);
@@ -72,9 +69,9 @@ export function TopicListView({ selectedIndex, onChange }) {
function Layout({ children, title }) {
return (
<div className="max-w-xl mx-auto h-full relative flex flex-col">
<div className="w-full p-4 font-medium text-large text-white bg-blue-600">
<span className="line-clamp-2">{title}</span>
<div className="max-w-7xl mx-auto h-full relative flex flex-col">
<div className="w-full px-4 py-2 font-medium text-large text-white bg-blue-600">
<span>{title}</span>
</div>
{children}
</div>
@@ -101,12 +98,9 @@ export default function App() {
return (
<Layout title={`${selectedIndex + 1}: ${structure[selectedIndex].title}`}>
<div className="flex-1 overflow-y-scroll">
<Reader
key={structure[selectedIndex].files[versions[selectedIndex]]}
file={structure[selectedIndex].files[versions[selectedIndex]]}
/>
<div className="absolute bottom-14 flex justify-between p-2 w-full z-999">
<div className="flex-1">
<Reader file={structure[selectedIndex].files[versions[selectedIndex]]} />
<div className="absolute bottom-10 flex justify-between px-4 py-2 w-full z-999">
<button
className="cursor-pointer p-2 rounded-full bg-blue-600 text-white"
onClick={() => {
@@ -115,27 +109,29 @@ export default function App() {
>
<MenuBookIcon className="fill-gray-100" />
</button>
<div className="flex space-x-1">
{structure[selectedIndex].files.map((file, vIndex) => (
<button
key={file}
className={`flex-1 cursor-pointer px-2 py-1 rounded-md text-xs whitespace-nowrap ${
versions[selectedIndex] === vIndex
? "bg-blue-100 text-blue-800 font-medium"
: "bg-gray-100 hover:bg-gray-200"
}`}
onClick={() => {
setVersions((prev) => {
const newVersions = [...prev];
newVersions[selectedIndex] = vIndex;
return newVersions;
});
}}
>
Version {vIndex + 1}
</button>
))}
</div>
{structure[selectedIndex].files.length > 1 && (
<div className="flex space-x-1">
{structure[selectedIndex].files.map((file, vIndex) => (
<button
key={file}
className={`flex-1 cursor-pointer px-2 py-1 rounded-md text-xs whitespace-nowrap ${
versions[selectedIndex] === vIndex
? "bg-blue-100 text-blue-800 font-medium"
: "bg-gray-100 hover:bg-gray-200"
}`}
onClick={() => {
setVersions((prev) => {
const newVersions = [...prev];
newVersions[selectedIndex] = vIndex;
return newVersions;
});
}}
>
Version {vIndex + 1}
</button>
))}
</div>
)}
</div>
</div>
<div className="w-full flex flex-col space-y-2">
@@ -145,7 +141,7 @@ export default function App() {
) : (
<div
onClick={() => setSelectedIndex((prev) => prev - 1)}
className="border-r border-blue-200 w-1/2 flex-1 p-4 hover:bg-blue-200 cursor-pointer flex align-center justify-start"
className="border-r border-blue-200 w-1/2 flex-1 px-4 py-2 hover:bg-blue-200 cursor-pointer flex align-center justify-start"
>
<ArrowBackIcon />
<span className="ml-2 truncate w-full ">
@@ -158,7 +154,7 @@ export default function App() {
) : (
<div
onClick={() => setSelectedIndex((prev) => prev + 1)}
className="flex-1 p-4 hover:bg-blue-200 w-1/2 cursor-pointer flex align-center justify-end"
className="flex-1 px-4 py-2 hover:bg-blue-200 w-1/2 cursor-pointer flex align-center justify-end"
>
<span className="mr-2 w-full truncate">
{selectedIndex + 2}: {structure[selectedIndex + 1].title}
@@ -202,10 +198,9 @@ export function Reader({ file }) {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
line-height: 1.5;
color: #333;
padding: 20px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding-bottom: 56px;
padding-bottom: 40px;
}
pre, code {
font-family: 'SF Mono', Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
@@ -236,15 +231,11 @@ export function Reader({ file }) {
}
if (isLoading) {
return (
<div className="p-4 flex justify-center items-center h-40">
<div className="animate-pulse">Loading...</div>
</div>
);
return <DelayedLoader />;
}
return (
<div className="w-full h-full border border-gray-300 rounded overflow-hidden">
<div className="w-full h-full overflow-hidden">
<iframe
srcDoc={content}
title={`File: ${file}`}
@@ -255,3 +246,33 @@ export function Reader({ file }) {
</div>
);
}
const DelayedLoader = ({
delayMs = 2000,
className = "p-4 flex justify-center items-center h-40",
text = "Loading...",
}) => {
const [showLoader, setShowLoader] = useState(false);
useEffect(() => {
// Set a timeout to show the loader after the specified delay
const timer = setTimeout(() => {
setShowLoader(true);
}, delayMs);
// Clear the timeout on unmount
return () => clearTimeout(timer);
}, []); // Empty dependency array - only run on mount
// Only render if the delay has passed
if (showLoader) {
return (
<div className={className}>
<div className="animate-pulse">{text}</div>
</div>
);
}
// Return null before delay threshold
return null;
};

View File

@@ -1,5 +1,9 @@
@import "tailwindcss";
body {
overflow: hidden;
}
#root {
height: 100dvh;
}