This commit is contained in:
h z
2024-12-03 09:41:58 +00:00
parent 8bbfc10a39
commit b355b867a5
8 changed files with 233 additions and 0 deletions

16
src/App.css Normal file
View File

@@ -0,0 +1,16 @@
.app-container {
display: flex;
flex-direction: column;
height: 100vh;
}
.content-container {
display: flex;
flex: 1;
}
.main-content {
flex: 1;
padding: 1rem;
overflow-y: auto;
}

View File

@@ -0,0 +1,26 @@
/*src/components/MainNavigation.css*/
.main-navigation {
background-color: #333;
color: white;
padding: 1rem;
}
.main-navigation ul {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
.main-navigation ul li {
margin-right: 1rem;
}
.main-navigation ul li a {
color: white;
text-decoration: none;
}
.main-navigation ul li a:hover {
text-decoration: underline;
}

View File

@@ -0,0 +1,32 @@
//src/components/MainNavigation.js
import React from "react";
import { Link } from "react-router-dom";
import "./MainNavigation.css";
const MainNavigation = () => {
return (
<nav className="main-navigation">
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/login">Login</Link>
</li>
<li>
<a href="https://mail.hangman-lab.top" target="_blank" rel="noopener noreferrer">
MailBox
</a>
</li>
<li>
<a href="https://git.hangman-lab.top" target="_blank" rel="noopener noreferrer">
Git
</a>
</li>
</ul>
</nav>
);
};
export default MainNavigation;

View File

View File

@@ -0,0 +1,34 @@
//src/components/MarkdownContent.js
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import {fetchWithCache} from "../utils/fetchWIthCache";
const MarkdownContent = () => {
const { id } = useParams();
const [content, setContent] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
fetchWithCache(`/api/markdown/${id}`)
.then((data) => setContent(data))
.catch((error) => setError(error));
}, [id]);
if (error) {
return <div>Error: {error}</div>;
}
if (!content) {
return <div>Loading...</div>;
}
return (
<div className="markdown-content">
<pre>{content}</pre>
</div>
);
};
export default MarkdownContent;

View File

@@ -0,0 +1,29 @@
/*src/components/SideNavigation.css*/
.side-navigation {
width: 250px;
background-color: #f4f4f4;
padding: 1rem;
border-right: 1px solid #ddd;
}
.side-navigation h3 {
margin-top: 0;
}
.side-navigation ul {
list-style: none;
padding: 0;
}
.side-navigation ul li {
margin-bottom: 0.5rem;
}
.side-navigation ul li a {
text-decoration: none;
color: #333;
}
.side-navigation ul li a:hover {
text-decoration: underline;
}

View File

@@ -0,0 +1,72 @@
// src/components/SideNavigation.js
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import "./SideNavigation.css";
import { fetchWithCache } from "../utils/fetchWithCache";
const SideNavigation = () => {
const [markdowns, setMarkdowns] = useState([]);
const [tree, setTree] = useState(null);
useEffect(() => {
fetchWithCache("/api/markdown/")
.then((data) => {
setMarkdowns(data);
setTree(buildTree(data));
})
.catch((error) => console.log(error));
}, []);
function buildTree(markdowns) {
const root = {};
markdowns.forEach((markdown) => {
const segments = markdown.path.split("/").filter(Boolean);
let current = root;
segments.forEach((segment, index) => {
if (!current[segment]) {
current[segment] =
index === segments.length - 1 ? { markdown } : {};
}
current = current[segment];
});
});
return root;
}
function renderTree(node, basePath = "") {
return (
<ul>
{Object.entries(node).map(([key, value]) => {
if (value.markdown) {
return (
<li key={value.markdown.id}>
<Link to={`/markdown/${value.markdown.id}`}>
{value.markdown.title}
</Link>
</li>
);
}
return (
<li key={key}>
<span>{key}</span>
{renderTree(value, `${basePath}/${key}`)}
</li>
);
})}
</ul>
);
}
return (
<nav className="side-navigation">
<h3>Markdown Directory</h3>
{tree ? renderTree(tree) : <p>Loading...</p>}
</nav>
);
};
export default SideNavigation;

View File

@@ -0,0 +1,24 @@
export async function fetchWithCache(url, cacheKey = url, cacheExpiry = 60) {
const cachedData = localStorage.getItem(cacheKey);
const now = Date.now();
if (cachedData) {
const { data, timestamp } = JSON.parse(cachedData);
if (now - timestamp < cacheExpiry * 1000) {
console.log("Cache hit for:", url);
return data;
} else {
console.log("Cache expired for:", url);
}
}
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
localStorage.setItem(cacheKey, JSON.stringify({ data, timestamp: now }));
return data;
}