feat: Rename image and data files

- Add PostCard component
    - Add WysiwygEditor component
    - Use 'front-matter' to parse front matter in markdown files for metadata instead of using redundant data objects
This commit is contained in:
2025-09-27 11:48:32 -05:00
parent f22d9f08bf
commit dceef32ba2
20 changed files with 500 additions and 52 deletions

View File

@@ -0,0 +1,80 @@
// PostCard.jsx
import React from 'react';
import { Button } from '@progress/kendo-react-buttons';
import { Card, CardImage, CardBody } from '@progress/kendo-react-layout';
const PostCard = ({ post, onEdit }) => {
const dataPath = post.header.image;
const relativePath = `../../${dataPath}`;
const imageUrl = new URL(relativePath, import.meta.url).href;
const formatDate = (utcString) => {
if (!utcString) return '';
// 1. Create Date object. It parses the UTC string automatically.
const date = new Date(utcString);
// 2. Define options for the desired output format (local time zone)
const dateOptions = {
year: 'numeric',
month: 'short', // e.g., 'Sep'
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: true, // e.g., '9:51 PM'
timeZoneName: undefined // Removes the timezone name from the output
};
// 3. Convert to local, human-readable string and clean up formatting
// The space between date and time may vary by locale, so we use string replacement for consistency.
const formattedDate = date.toLocaleDateString(undefined, dateOptions);
// This attempts to convert the format '9/20/2025, 9:51 PM' to 'Sep 20, 2025, 9:51 PM'
const parts = formattedDate.split(',');
if (parts.length > 1) {
const timePart = date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit', hour12: true });
const datePart = date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
return `${datePart}, ${timePart}`;
}
return formattedDate;
};
return (
<Card key={post.slug} style={{ width: '250px', textAlign: 'center', display: 'flex' }}>
{/* 1. Thumbnail Image */}
<CardImage
src={imageUrl}
alt={post.title}
style={{ width: '100%', height: '100px', objectFit: 'cover' }}
/>
{/* 2. Title, Date, and Button Container */}
<CardBody style={{ flexGrow: 1, padding: '10px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
{/* Title Link */}
<div style={{ marginBottom: '5px' }}>
<a className="k-link" href={post.canonical_url} target="_blank" rel="noreferrer" style={{ fontWeight: 'bold' }}>
{post.title}
</a>
</div>
{/* Date and Edit Button */}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontSize: '0.85em' }}>
<span>{formatDate(post.date)}</span>
<Button
look="flat"
themeColor="primary"
onClick={() => onEdit(post.slug)}
>
Edit
</Button>
</div>
</CardBody>
</Card>
);
};
export default PostCard;

View File

@@ -0,0 +1,44 @@
import {
RichTextEditorComponent,
Inject,
Toolbar,
HtmlEditor,
MarkdownEditor,
SourceCode,
Link, Image
} from '@syncfusion/ej2-react-richtexteditor';
import * as React from 'react';
function CampfireToggleEditor(props) {
const toolbarOptions = {
items: [
'Bold', 'Italic', 'Underline', '|',
'Formats', 'Alignments', 'OrderedList', 'UnorderedList', '|',
'CreateLink', 'Image', '|',
'SourceCode',
'Undo', 'Redo'
]
};
return (
<RichTextEditorComponent
value={props.value}
change={handleEditorChange}
editorMode={'Html'}
toolbarSettings={toolbarOptions}
>
<Inject
services={[
Toolbar,
Link,
Image,
HtmlEditor,
MarkdownEditor,
SourceCode
]}
/>
</RichTextEditorComponent>
);
};
export default CampfireToggleEditor;

View File

@@ -11,7 +11,7 @@ export default function Copyright() {
>
<p>
&copy; 2025{" | "}Derek L. Seitz{" | "}
<a href="https://dlseitz.dev" target="_blank" rel="noopener noreferrer" class="k-link">
<a href="https://dlseitz.dev" target="_blank" rel="noopener noreferrer" className="k-link">
dlseitz.dev
</a>
</p>