switched to nextjs

This commit is contained in:
2024-11-14 16:25:56 +01:00
parent eded2294d4
commit 98c401c9e1
20 changed files with 2251 additions and 345 deletions
+119
View File
@@ -0,0 +1,119 @@
"use client";
import { useEffect, useState } from "react";
import ContentLoader from "react-content-loader"
export default function LoadingBlog(props: any) {
const [numComponents, setNumComponents] = useState(0);
const [isClient, setIsClient] = useState(false);
useEffect(() => {
// Only set to client after mount
setIsClient(true);
}, []);
useEffect(() => {
const updateComponentCount = () => {
const windowHeight = window.innerHeight; // Get window height
const componentHeight = 100; // Set the height of your component
const count = Math.floor(windowHeight / componentHeight); // Calculate how many components fit
setNumComponents(count);
};
// Initial calculation
updateComponentCount();
// Add resize event listener
window.addEventListener('resize', updateComponentCount);
// Cleanup listener on unmount
return () => {
window.removeEventListener('resize', updateComponentCount);
};
}, []); // Empty dependency array ensures the effect runs once after the initial render
// Only render on the client
if (!isClient) {
return null;
}
return (
<div className="container">
{Array.from({ length: numComponents }, (_, index) => (
<ContentLoader
speed={2}
viewBox="0 0 340 50"
backgroundColor="#3b3b3b"
foregroundColor="#f5304c"
key={index}
{...props}
>
<rect x="0" y="0" rx="7" ry="7" width="290" height="18" />
<rect x="0" y="25" rx="3" ry="3" width="78" height="7" />
<rect x="0" y="37" rx="3" ry="3" width="200" height="7" />
</ContentLoader>
))}
</div>
);
}
export function LoadingBlogRead(props: any) {
const [isClient, setIsClient] = useState(false);
const [numRects, setNumRects] = useState(0);
useEffect(() => {
setIsClient(true);
}, []);
useEffect(() => {
const updateRectCount = () => {
// Calculate the number of rectangles based on window height
const windowHeight = window.innerHeight;
const rectHeight = 46; // Height of each rectangle
const count = Math.floor(windowHeight / rectHeight); // Number of rectangles that fit
setNumRects(count);
};
// Update on mount and window resize
updateRectCount();
window.addEventListener('resize', updateRectCount);
// Cleanup event listener on unmount
return () => {
window.removeEventListener('resize', updateRectCount);
};
}, []);
// Only render on the client
if (!isClient) {
return null;
}
// Dynamically set the viewBox height based on the number of rectangles
const viewBoxHeight = window.innerHeight / 3;
return (
<ContentLoader
speed={2}
viewBox={`0 0 340 ${viewBoxHeight}`}
backgroundColor="#3b3b3b"
foregroundColor="#f5304c"
style={{ marginTop: "20px" }}
{...props}
>
<rect x="0" y="0" rx="7" ry="7" width="290" height="18" />
<rect x="0" y="25" rx="3" ry="3" width="78" height="7" />
{Array.from({ length: numRects }).map((_, i) => (
<rect
x="0"
y={45 + i * 14} // Adjust position based on index
rx="3"
ry="3"
width={Math.random() * (300 - 80) + 80} // Random width
height="9"
key={i}
/>
))}
</ContentLoader>
);
}
+6
View File
@@ -0,0 +1,6 @@
import React from 'react';
import ReactMarkdown from 'react-markdown';
export default function MarkdownRenderer({ children }: { children: string }) {
return <ReactMarkdown>{children}</ReactMarkdown>;
};
+60
View File
@@ -0,0 +1,60 @@
"use client";
import React, { useEffect, useState } from 'react';
import '../../Blog.css';
import MarkdownRenderer from './MarkdownRenderer';
import LoadingBlog, { LoadingBlogRead } from '../Loading';
export default function Blog({ params }: { params: Promise<{ id: string }> }) {
const [blog, setBlog] = useState({ title: '', date: '', markdown: '' });
const [error, setError] = useState('');
const [loading, setLoading] = useState(true);
const date = new Date(blog.date).toLocaleString('default', { month: 'long', day: 'numeric', year: 'numeric' });
useEffect(() => {
const fetchBlog = async () => {
try {
console.log('obtaining blog')
const response = await fetch(`/api/${(await params).id}`);
if (response.ok) {
const blog = await response.json();
document.title = blog.title + " - Leo's blog";
setBlog(blog);
} else {
const errorData = await response.text();
setError(errorData);
}
} catch (err: any) {
setError(err);
} finally {
setLoading(false);
}
};
fetchBlog();
}, [params]);
if (loading) {
return <main>
<a href="/blog"><h1 className='name'>Leo's blog</h1></a>
<div className='blog_container'>
<LoadingBlogRead/>
</div>
</main>;
}
if (error) {
return <div className="error">Error loading blog: {error}</div>; // Show error if there is one
}
return (
<main>
<a href="/blog"><h1 className='name'>Leo's blog</h1></a>
<div className='blog_container'>
<h2 className='blog_title'>{blog.title}</h2>
<p className='date'>{date}</p>
<div className='markdown'><MarkdownRenderer>{blog.markdown}</MarkdownRenderer></div>
</div>
</main>
);
}
+63
View File
@@ -0,0 +1,63 @@
"use client";
import React, { useEffect, useState } from 'react';
import '../Blog.css';
import LoadingBlog from './Loading';
export default function Blog() {
const [data, setData] = useState([{ title: '', description: '', id: '', date: '' }]);
const [error, setError] = useState('');
useEffect(() => {
const fetchData = async () => {
setTimeout(async () => {
try {
const response = await fetch('/api/');
if (response.ok) {
const result = await response.json();
setData(result);
} else {
const errorData = await response.text();
setError(errorData);
}
} catch (err: any) {
setError(err.toString());
}
}, 500);
};
fetchData();
}, []);
if (error) {
return <div>Error: {JSON.stringify(error)}</div>; // Display any errors
} if (data.length === 1 && data[0].id === '') {
return (
<main>
<a href="/blog"><h1 className='name'>Leo's blog</h1></a>
<LoadingBlog/>
</main>
);
}
document.title = "Leo's blog";
return (
<main>
<a href="/blog"><h1 className='name'>Leo's blog</h1></a>
<div className='container'>
{data.map((blog, i) => {
return (
<a key={i} href={`/blog/${blog.id}`} style={{ textDecoration: 'none' }}>
<div className='blog'>
<h2 className='title'>{blog.title}</h2>
<p className='date'>{new Date(blog.date).toLocaleString('default', { month: 'long', day: 'numeric', year: 'numeric' })}</p>
<p className='description'>{blog.description}</p>
</div>
</a>
);
})}
</div>
</main>
);
}