fix: Address dependency issues within KendoReact components.
- add gray-matter to reduce duplicated meta data for posts - rename files in data/BlogPosts/ to address limitations in path handling
This commit is contained in:
926
package-lock.json
generated
926
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
|||||||
"@progress/kendo-licensing": "^1.7.1",
|
"@progress/kendo-licensing": "^1.7.1",
|
||||||
"@progress/kendo-react-animation": "^12.0.1",
|
"@progress/kendo-react-animation": "^12.0.1",
|
||||||
"@progress/kendo-react-buttons": "^12.0.1",
|
"@progress/kendo-react-buttons": "^12.0.1",
|
||||||
"@progress/kendo-react-common": "^12.0.2",
|
"@progress/kendo-react-common": "^12.0.1",
|
||||||
"@progress/kendo-react-data-tools": "^12.0.1",
|
"@progress/kendo-react-data-tools": "^12.0.1",
|
||||||
"@progress/kendo-react-dateinputs": "^12.0.1",
|
"@progress/kendo-react-dateinputs": "^12.0.1",
|
||||||
"@progress/kendo-react-dialogs": "^12.0.1",
|
"@progress/kendo-react-dialogs": "^12.0.1",
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
"@progress/kendo-svg-icons": "^4.5.0",
|
"@progress/kendo-svg-icons": "^4.5.0",
|
||||||
"@progress/kendo-theme-default": "^12.0.1",
|
"@progress/kendo-theme-default": "^12.0.1",
|
||||||
"campfire-logs-dashboard": "file:./campfire-logs-dashboard",
|
"campfire-logs-dashboard": "file:./campfire-logs-dashboard",
|
||||||
|
"gray-matter": "^4.0.3",
|
||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.1.1",
|
"react-dom": "^19.1.1",
|
||||||
"react-router-dom": "^7.9.1"
|
"react-router-dom": "^7.9.1"
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
---
|
---
|
||||||
title: #0 - Setting Up Camp
|
title: #0 - Setting Up Camp
|
||||||
|
slug: 0-setting-up-camp
|
||||||
|
fileName:
|
||||||
published: true
|
published: true
|
||||||
date: 2025-08-24 05:00:00 UTC
|
date: 2025-08-24 05:00:00 UTC
|
||||||
tags: fullstack,developerjourney,BuildInPublic,introduction
|
tags: fullstack,developerjourney,BuildInPublic,introduction
|
||||||
canonical_url: https://campfire.dlseitz.dev/0-setting-up-camp
|
canonical_url: https://campfire.dlseitz.dev/0-setting-up-camp
|
||||||
header:
|
header:
|
||||||
image: /assets/#0-setting-up-camp.jpg
|
image: /assets/0-setting-up-camp.jpg
|
||||||
attribution: 'Photo by <a href="https://unsplash.com/@kemaldgn?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Kemal Berkay Dogan</a> on <a href="https://unsplash.com/photos/a-campfire-with-a-cup-of-coffee-sitting-in-front-of-it-TcUN5sDZPZ8?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a>'
|
attribution: 'Photo by <a href="https://unsplash.com/@kemaldgn?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Kemal Berkay Dogan</a> on <a href="https://unsplash.com/photos/a-campfire-with-a-cup-of-coffee-sitting-in-front-of-it-TcUN5sDZPZ8?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a>'
|
||||||
---
|
---
|
||||||
|
|
@@ -1,4 +1,25 @@
|
|||||||
// /data/blog-post-data.js
|
import matter from 'gray-matter';
|
||||||
|
|
||||||
|
const modules = import.meta.glob('./BlogPosts/*.md', { query: '?raw', import: 'default' });
|
||||||
|
|
||||||
|
export async function loadPosts() {
|
||||||
|
const posts = [];
|
||||||
|
|
||||||
|
for (const path in modules) {
|
||||||
|
const fileContent = await modules[path]();
|
||||||
|
const { data } = matter(fileContent);
|
||||||
|
|
||||||
|
posts.push({
|
||||||
|
...data,
|
||||||
|
path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return posts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* // /data/blog-post-data.js
|
||||||
export const blogPosts = [
|
export const blogPosts = [
|
||||||
{
|
{
|
||||||
title: "#0 - Setting Up Camp",
|
title: "#0 - Setting Up Camp",
|
||||||
@@ -87,4 +108,4 @@ export const blogPosts = [
|
|||||||
tags: null,
|
tags: null,
|
||||||
published: false
|
published: false
|
||||||
}
|
}
|
||||||
];
|
]; */
|
||||||
|
@@ -1,56 +1,67 @@
|
|||||||
// DashboardPage.jsx
|
// DashboardPage.jsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { blogPosts } from '../data/blog-post-data';
|
import { loadPosts } from '../data/blog-post-data';
|
||||||
import { Button } from '@progress/kendo-react-buttons';
|
import { Button } from '@progress/kendo-react-buttons';
|
||||||
|
|
||||||
const Dashboard = React.forwardRef((props, ref) => {
|
const Dashboard = React.forwardRef((props, ref) => {
|
||||||
// Separate published and draft posts
|
// State to hold posts loaded asynchronously
|
||||||
|
const [blogPosts, setBlogPosts] = useState([]);
|
||||||
|
|
||||||
|
// Load posts on component mount
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchPosts = async () => {
|
||||||
|
const postsData = await loadPosts();
|
||||||
|
setBlogPosts(postsData);
|
||||||
|
};
|
||||||
|
fetchPosts();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Separate published and draft posts (no changes here)
|
||||||
const publishedPosts = blogPosts.filter(post => post.published);
|
const publishedPosts = blogPosts.filter(post => post.published);
|
||||||
const draftPosts = blogPosts.filter(post => !post.published);
|
const draftPosts = blogPosts.filter(post => !post.published);
|
||||||
|
|
||||||
const handleEdit = (slug) => {
|
const handleEdit = (slug) => {
|
||||||
// Navigate to editor page for the given post slug
|
|
||||||
props.navigate(`/editor/${slug}`);
|
props.navigate(`/editor/${slug}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ textAlign: 'center' }} ref={ref}>
|
<div style={{ textAlign: 'center' }} ref={ref}>
|
||||||
<h1>Dashboard</h1>
|
<h1>Dashboard</h1>
|
||||||
|
|
||||||
<section style={{ textAlign: 'center' }}>
|
<section style={{ textAlign: 'center' }}>
|
||||||
<h2>Published Posts</h2>
|
<h2>Published Posts</h2>
|
||||||
{publishedPosts.length ? (
|
{publishedPosts.length ? (
|
||||||
<ul>
|
<ul>
|
||||||
{publishedPosts.map(post => (
|
{publishedPosts.map(post => (
|
||||||
<li key={post.slug}>
|
<li key={post.slug}>
|
||||||
<a class="k-link" href={post.canonical_url} target="_blank" rel="noreferrer">
|
<a className="k-link" href={post.canonical_url} target="_blank" rel="noreferrer">
|
||||||
{post.title}
|
{post.title}
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
<span style={{ marginLeft: '30px', padding: '0 20px' }} >{post.date}</span>{' '}
|
<span style={{ marginLeft: '30px', padding: '0 20px' }}>{post.date}</span>{' '}
|
||||||
<Button style={{ marginLeft: '30px', padding: '0 20px' }} onClick={() => handleEdit(post.slug)}>Edit</Button>
|
<Button style={{ marginLeft: '30px', padding: '0 20px' }} onClick={() => handleEdit(post.slug)}>Edit</Button>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
<p>No published posts.</p>
|
<p>No published posts.</p>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section style={{ textAlign: 'center' }}>
|
<section style={{ textAlign: 'center' }}>
|
||||||
<h2>Drafts</h2>
|
<h2>Drafts</h2>
|
||||||
{draftPosts.length ? (
|
{draftPosts.length ? (
|
||||||
<ul>
|
<ul>
|
||||||
{draftPosts.map(post => (
|
{draftPosts.map(post => (
|
||||||
<li key={post.slug}>
|
<li key={post.slug}>
|
||||||
{post.title}{' '}
|
{post.title}{' '}
|
||||||
<Button style={{ marginLeft: '30px', padding: '0 20px' }} onClick={() => handleEdit(post.slug)}>Edit</Button>
|
<Button style={{ marginLeft: '30px', padding: '0 20px' }} onClick={() => handleEdit(post.slug)}>Edit</Button>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
<p>No drafts.</p>
|
<p>No drafts.</p>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user