maintenance: Clean up codebase and improve formatting
• Remove placeholder comments and unused code • Standardize inline styles and formatting • Update component structure and organization
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
// AppBar.jsx
|
||||
import React from 'react';
|
||||
import { AppBar, AppBarSection, AppBarSpacer } from '@progress/kendo-react-layout';
|
||||
import { Button } from '@progress/kendo-react-buttons';
|
||||
import { Avatar } from '@progress/kendo-react-layout';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import Logo from '../assets/images/campfire_logs_square_logo_bg_match.png';
|
||||
import CampfireBreadcrumb from './UI/Breadcrumb';
|
||||
|
||||
const CampfireAppBar = ({ isLoggedIn, onLogin, onDrawerToggle }) => {
|
||||
const navigate = useNavigate();
|
||||
@@ -12,16 +16,29 @@ const CampfireAppBar = ({ isLoggedIn, onLogin, onDrawerToggle }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 style={{ color: "#ff5733", textAlign: "center" }}>Campfire Logs</h1>
|
||||
<AppBar position="sticky" style={{ backgroundColor: "#edbd7d"}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', height: 'auto', marginTop: '10px' }}>
|
||||
<img
|
||||
src={Logo}
|
||||
alt="Campfire Logs Logo"
|
||||
loading="eager"
|
||||
fetchPriority="high"
|
||||
style={{
|
||||
width: "200px",
|
||||
height: "200px",
|
||||
cursor: "pointer",
|
||||
borderRadius: "50%",
|
||||
border: "2px solid #edbd7d",
|
||||
objectFit: "cover",
|
||||
position: "relative",
|
||||
zIndex: 2
|
||||
}}
|
||||
onClick={() => navigate('/dashboard')}
|
||||
/>
|
||||
<AppBar position="sticky" style={{ backgroundColor: "#242424", display: 'flex', justifyContent: 'space-between', flex: 1, marginLeft: "-100px", minHeight: '60px' }}>
|
||||
<AppBarSection>
|
||||
<CampfireBreadcrumb />
|
||||
</AppBarSection>
|
||||
<AppBarSection>
|
||||
<Button look="flat" onClick={onDrawerToggle}>
|
||||
<span className="k-icon k-i-menu" />
|
||||
</Button>
|
||||
|
||||
<AppBarSpacer style={{ width: 800 }} />
|
||||
|
||||
<Link to="/dashboard">
|
||||
<Button look="flat">Dashboard</Button>
|
||||
</Link>
|
||||
@@ -31,11 +48,9 @@ const CampfireAppBar = ({ isLoggedIn, onLogin, onDrawerToggle }) => {
|
||||
<Link to="/editor">
|
||||
<Button look="flat">+ New Post</Button>
|
||||
</Link>
|
||||
</AppBarSection>
|
||||
|
||||
<AppBarSpacer style={{width: 50 }} />
|
||||
|
||||
<AppBarSection>
|
||||
|
||||
<AppBarSpacer style={{ width: 20 }} />
|
||||
|
||||
{isLoggedIn ? (
|
||||
<Button look="flat" onClick={handleLogout}>
|
||||
Logout
|
||||
@@ -45,6 +60,7 @@ const CampfireAppBar = ({ isLoggedIn, onLogin, onDrawerToggle }) => {
|
||||
<Button look="flat">Login</Button>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
</AppBarSection>
|
||||
</AppBar>
|
||||
</div>
|
||||
|
@@ -11,25 +11,20 @@ const PostCard = ({ post, onEdit }) => {
|
||||
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'
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
hour12: true, // e.g., '9:51 PM'
|
||||
timeZoneName: undefined // Removes the timezone name from the output
|
||||
hour12: true,
|
||||
timeZoneName: undefined
|
||||
};
|
||||
|
||||
// 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 });
|
||||
@@ -41,7 +36,7 @@ const PostCard = ({ post, onEdit }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card key={post.slug} style={{ width: '250px', textAlign: 'center', display: 'flex' }}>
|
||||
<Card key={post.slug} style={{ width: 'calc(100% - 50px)', textAlign: 'center', display: 'flex' }}>
|
||||
|
||||
{/* 1. Thumbnail Image */}
|
||||
<CardImage
|
||||
|
@@ -1,44 +1,91 @@
|
||||
import {
|
||||
RichTextEditorComponent,
|
||||
Inject,
|
||||
Toolbar,
|
||||
HtmlEditor,
|
||||
MarkdownEditor,
|
||||
SourceCode,
|
||||
Link, Image
|
||||
} from '@syncfusion/ej2-react-richtexteditor';
|
||||
import * as React from 'react';
|
||||
// WysiwygEditor.jsx
|
||||
// KendoReact Editor implementation for HTML editing with custom toolbar
|
||||
// Demonstrates custom tool integration and advanced editor configuration
|
||||
import React, { useState } from 'react';
|
||||
import { Editor, EditorTools, EditorToolsSettings } from '@progress/kendo-react-editor';
|
||||
import InlineCodeTool from './custom/InlineCodeTool';
|
||||
|
||||
function CampfireToggleEditor(props) {
|
||||
const toolbarOptions = {
|
||||
items: [
|
||||
'Bold', 'Italic', 'Underline', '|',
|
||||
'Formats', 'Alignments', 'OrderedList', 'UnorderedList', '|',
|
||||
'CreateLink', 'Image', '|',
|
||||
'SourceCode',
|
||||
'Undo', 'Redo'
|
||||
]
|
||||
const {
|
||||
Bold, Italic, Underline, Strikethrough,
|
||||
Subscript, Superscript,
|
||||
CleanFormatting,
|
||||
Indent, Outdent,
|
||||
OrderedList, UnorderedList,
|
||||
NumberedList,
|
||||
BulletedList,
|
||||
Undo, Redo,
|
||||
Link, Unlink, InsertImage, ViewHtml,
|
||||
InsertFile,
|
||||
SelectAll,
|
||||
Print,
|
||||
Pdf,
|
||||
} = EditorTools;
|
||||
|
||||
// Custom inline code tool for the editor toolbar
|
||||
const inlineCode = InlineCodeTool;
|
||||
|
||||
function WysiwygEditor({ content, onContentChange }) {
|
||||
// KendoReact Editor change handler
|
||||
const handleEditorChange = (event) => {
|
||||
onContentChange(event.html);
|
||||
};
|
||||
|
||||
return (
|
||||
<RichTextEditorComponent
|
||||
value={props.value}
|
||||
change={handleEditorChange}
|
||||
editorMode={'Html'}
|
||||
toolbarSettings={toolbarOptions}
|
||||
>
|
||||
<Inject
|
||||
services={[
|
||||
Toolbar,
|
||||
Link,
|
||||
Image,
|
||||
HtmlEditor,
|
||||
MarkdownEditor,
|
||||
SourceCode
|
||||
]}
|
||||
/>
|
||||
</RichTextEditorComponent>
|
||||
);
|
||||
};
|
||||
|
||||
export default CampfireToggleEditor;
|
||||
// KendoReact Editor toolbar configuration with custom inline code tool
|
||||
const tools = [
|
||||
[Bold, Italic, Underline, Strikethrough],
|
||||
[Subscript, Superscript],
|
||||
[inlineCode], // Custom tool for inline code formatting
|
||||
[CleanFormatting],
|
||||
[Indent, Outdent],
|
||||
[OrderedList, UnorderedList],
|
||||
[NumberedList, BulletedList],
|
||||
[SelectAll],
|
||||
[Undo, Redo],
|
||||
[Link, Unlink, InsertImage, InsertFile, ViewHtml]
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<style>
|
||||
{`
|
||||
.k-editor-content a {
|
||||
color: var(--kendo-color-primary, #d94f27) !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.k-editor-content a:hover {
|
||||
color: var(--kendo-color-primary-hover, #ff6f48) !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.k-editor-content a:visited {
|
||||
color: var(--kendo-color-primary, #d94f27) !important;
|
||||
}
|
||||
.k-textarea {
|
||||
background-color: #f5f1e9 !important;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
{/* KendoReact Editor with custom toolbar and styling */}
|
||||
<div style={{ width: '1000px' }}>
|
||||
<Editor
|
||||
value={content}
|
||||
onChange={handleEditorChange}
|
||||
tools={tools}
|
||||
style={{
|
||||
height: '400px',
|
||||
width: '1000px'
|
||||
}}
|
||||
contentStyle={{
|
||||
fontFamily: 'Arial, sans-serif',
|
||||
fontSize: '14px',
|
||||
lineHeight: '1.5',
|
||||
backgroundColor: '#f5f1e9'
|
||||
}}
|
||||
className="custom-editor"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default WysiwygEditor;
|
@@ -1,3 +1,4 @@
|
||||
// LoginComponent.jsx
|
||||
import React, { useState } from 'react';
|
||||
import { Input } from '@progress/kendo-react-inputs';
|
||||
import { Label } from '@progress/kendo-react-labels';
|
||||
@@ -28,18 +29,20 @@ const LoginComponent = ({ onLogin }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<div style={{ marginBottom: '100px', width: '350px', margin: '0 auto 100px auto' }}>
|
||||
<form onSubmit={handleSubmit} style={{ width: '350px', contain: 'layout' }}>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Label htmlFor="username">Username: </Label>
|
||||
<Input style={{ border: '1px solid #edbd7d' }} type="text" id="username" value={username} onChange={(e) => setUsername(e.target.value)} autoComplete="username" />
|
||||
<Input style={{ border: '1px solid #edbd7d', width: '300px', maxWidth: '300px', minWidth: '300px' }} type="text" id="username" value={username} onChange={(e) => setUsername(e.target.value)} autoComplete="username" />
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Label htmlFor="password">Password: </Label>
|
||||
<Input style={{ border: '1px solid #edbd7d', marginBottom: '10px' }} type="password" id="password" value={password} onChange={(e) => setPassword(e.target.value)} autoComplete="current-password" />
|
||||
<Input style={{ border: '1px solid #edbd7d', marginBottom: '10px', width: '300px', maxWidth: '300px', minWidth: '300px' }} type="password" id="password" value={password} onChange={(e) => setPassword(e.target.value)} autoComplete="current-password" />
|
||||
</div>
|
||||
|
||||
<Button look="flat" type="submit" style={{ padding: '0 20px' }}>Login</Button>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Button look="flat" type="submit" style={{ padding: '0 20px' }}>Login</Button>
|
||||
</div>
|
||||
<div>
|
||||
<NotificationGroup style={{ textAlign: 'center' }}>
|
||||
{error && (<Notification type={{ style: 'error', icon: true }} closeable={true} onClose={() => setError('')}>
|
||||
@@ -48,7 +51,7 @@ const LoginComponent = ({ onLogin }) => {
|
||||
</NotificationGroup>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// PanelBar.jsx
|
||||
import React from 'react';
|
||||
import { PanelBar, PanelBarItem } from '@progress/kendo-react-layout';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
@@ -9,10 +10,25 @@ import {
|
||||
} from '@progress/kendo-svg-icons';
|
||||
import { panelbarData } from '../data/panelbar-data';
|
||||
|
||||
// Import custom icon images (PNG files)
|
||||
import GiteaIcon from '../assets/icons/Gitea_Logo.png';
|
||||
import NotionIcon from '../assets/icons/Notion-logo.png';
|
||||
import HashnodeIcon from '../assets/icons/Hashnode_icon.png';
|
||||
import DevIcon from '../assets/icons/DEV_Community_Badge.png';
|
||||
import VeniceIcon from '../assets/icons/venice_icon.png';
|
||||
import DlseitzIcon from '../assets/icons/dlseitz-icon.svg';
|
||||
|
||||
const iconMap = {
|
||||
bookIcon, inboxIcon, trackChangesIcon, plusOutlineIcon,
|
||||
globeOutlineIcon, linkIcon, tellAFriendIcon,
|
||||
facebookIcon, xLogoIcon, linkedinIcon, redditIcon
|
||||
facebookIcon, xLogoIcon, linkedinIcon, redditIcon,
|
||||
// Custom SVG icons
|
||||
giteaIcon: GiteaIcon,
|
||||
notionIcon: NotionIcon,
|
||||
hashnodeIcon: HashnodeIcon,
|
||||
devIcon: DevIcon,
|
||||
veniceIcon: VeniceIcon,
|
||||
dlseitzIcon: DlseitzIcon
|
||||
};
|
||||
|
||||
const CampfirePanelBar = ({ isExpanded = true }) => {
|
||||
@@ -38,11 +54,24 @@ const CampfirePanelBar = ({ isExpanded = true }) => {
|
||||
textDecoration: 'none'
|
||||
}}
|
||||
>
|
||||
<SvgIcon
|
||||
icon={iconMap[item.icon]}
|
||||
size="medium"
|
||||
style={{ marginLeft: '30px' }}
|
||||
/>
|
||||
{iconMap[item.icon] && typeof iconMap[item.icon] === 'string' ? (
|
||||
<img
|
||||
src={iconMap[item.icon]}
|
||||
alt={item.title}
|
||||
style={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
marginLeft: '30px',
|
||||
objectFit: 'contain'
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<SvgIcon
|
||||
icon={iconMap[item.icon]}
|
||||
size="medium"
|
||||
style={{ marginLeft: '30px' }}
|
||||
/>
|
||||
)}
|
||||
<span style={{ marginLeft: '8px' }}>{item.title}</span>
|
||||
</a>
|
||||
}
|
||||
@@ -77,7 +106,7 @@ const CampfirePanelBar = ({ isExpanded = true }) => {
|
||||
);
|
||||
}
|
||||
|
||||
// Parent items with children
|
||||
// Headers with children
|
||||
return (
|
||||
<PanelBarItem
|
||||
key={item.title}
|
||||
@@ -102,7 +131,8 @@ const CampfirePanelBar = ({ isExpanded = true }) => {
|
||||
<div style={{
|
||||
width: isExpanded ? 300 : 200,
|
||||
minWidth: isExpanded ? 240 : 60,
|
||||
transition: 'width 0.3s'
|
||||
transition: 'width 0.3s',
|
||||
marginTop: '-10px',
|
||||
}}>
|
||||
<PanelBar>
|
||||
{panelbarData.map(renderItem)}
|
||||
|
@@ -10,10 +10,16 @@ export default function Copyright() {
|
||||
}}
|
||||
>
|
||||
<p>
|
||||
© 2025{" | "}Derek L. Seitz{" | "}
|
||||
<a href="https://dlseitz.dev" target="_blank" rel="noopener noreferrer" className="k-link">
|
||||
© 2025 Derek L. Seitz{" | "}
|
||||
<a href="https://dlseitz.dev" target="_blank" rel="noopener noreferrer" style={{
|
||||
color: '#d94f27',
|
||||
textDecoration: 'none',
|
||||
transition: 'color 0.2s ease'
|
||||
}}
|
||||
onMouseEnter={(e) => e.target.style.color = '#ff6f48'}
|
||||
onMouseLeave={(e) => e.target.style.color = '#d94f27'}>
|
||||
dlseitz.dev
|
||||
</a>
|
||||
</a>{" | "}All Rights Reserved
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
Reference in New Issue
Block a user