feat(content): add About Us page with markdown content support

- Create AboutUsPage component with markdown rendering
- Add react-markdown library for content rendering
- Create public/content directory for editable markdown files
- Add about-us.md with Lorem Ipsum placeholder content
- Create public/images/about directory for page images
- Add /about-us route in App.jsx
- Add About Us link to homepage footer
- Support for external links (open in new tab) and internal links
- Responsive image rendering with rounded corners and shadow
This commit is contained in:
Radosław Gierwiało
2025-12-05 18:30:44 +01:00
parent d8085f828f
commit 2c5689ac8e
6 changed files with 1293 additions and 4 deletions

View File

@@ -21,6 +21,7 @@ import PublicProfilePage from './pages/PublicProfilePage';
import ActivityLogsPage from './pages/admin/ActivityLogsPage';
import ContactMessagesPage from './pages/admin/ContactMessagesPage';
import ContactPage from './pages/ContactPage';
import AboutUsPage from './pages/AboutUsPage';
import NotFoundPage from './pages/NotFoundPage';
import VerificationBanner from './components/common/VerificationBanner';
import InstallPWA from './components/pwa/InstallPWA';
@@ -228,6 +229,9 @@ function App() {
{/* Contact Page - Public route */}
<Route path="/contact" element={<ContactPage />} />
{/* About Us Page - Public route */}
<Route path="/about-us" element={<AboutUsPage />} />
{/* Public Profile - /u/username format (no auth required) */}
<Route path="/u/:username" element={<PublicProfilePage />} />

View File

@@ -0,0 +1,91 @@
import { useState, useEffect } from 'react';
import ReactMarkdown from 'react-markdown';
import Layout from '../components/layout/Layout';
export default function AboutUsPage() {
const [content, setContent] = useState('');
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
useEffect(() => {
// Fetch markdown content
fetch('/content/about-us.md')
.then(response => {
if (!response.ok) {
throw new Error('Failed to load content');
}
return response.text();
})
.then(text => {
setContent(text);
setLoading(false);
})
.catch(err => {
console.error('Error loading about-us content:', err);
setError('Failed to load page content');
setLoading(false);
});
}, []);
if (loading) {
return (
<Layout>
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<div className="w-12 h-12 border-4 border-primary-600 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
<p className="text-gray-600">Loading...</p>
</div>
</div>
</Layout>
);
}
if (error) {
return (
<Layout>
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<p className="text-red-600">{error}</p>
</div>
</div>
</Layout>
);
}
return (
<Layout>
<div className="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-4xl mx-auto">
<article className="bg-white rounded-lg shadow-sm p-8 md:p-12 prose prose-lg max-w-none">
<ReactMarkdown
components={{
// Customize link rendering to use React Router for internal links
a: ({ node, href, children, ...props }) => {
const isInternal = href && href.startsWith('/');
if (isInternal) {
return (
<a href={href} {...props}>
{children}
</a>
);
}
return (
<a href={href} target="_blank" rel="noopener noreferrer" {...props}>
{children}
</a>
);
},
// Ensure images are responsive
img: ({ node, ...props }) => (
<img className="rounded-lg shadow-md" {...props} alt={props.alt || ''} />
),
}}
>
{content}
</ReactMarkdown>
</article>
</div>
</div>
</Layout>
);
}

View File

@@ -274,6 +274,11 @@ const HomePage = () => {
<div>
<h3 className="text-white font-semibold mb-4">Support</h3>
<ul className="space-y-2 text-sm">
<li>
<Link to="/about-us" className="hover:text-primary-400 transition">
About Us
</Link>
</li>
<li>
<Link to="/contact" className="hover:text-primary-400 transition">
Contact Us