switched to nextjs
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
|
||||
export default function MarkdownRenderer({ children }: { children: string }) {
|
||||
return <ReactMarkdown>{children}</ReactMarkdown>;
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user