Skip to content

Commit bd8dfd9

Browse files
committed
feat: new pg app
1 parent b6f0725 commit bd8dfd9

File tree

4 files changed

+354
-0
lines changed

4 files changed

+354
-0
lines changed

IDEAS.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Fezcodex Improvement Ideas
2+
3+
This document outlines various suggestions for enhancing the Fezcodex website, categorized for clarity.
4+
5+
## I. Initial Core Feature Suggestions
6+
7+
These are foundational improvements identified early in the project analysis.
8+
9+
* **Implement Robust Search Functionality:**
10+
* **Details:** Create a comprehensive client-side search (e.g., using Fuse.js) that indexes all blog posts, logs, project descriptions, and D&D lore. Provide a dedicated search overlay or page with instant results, filtering, and sorting options.
11+
* **Why:** Makes content highly discoverable, crucial for a content-rich site.
12+
* **Add Comments Section:**
13+
* **Details:** Integrate a backend-less commenting system (e.g., Giscus or Utterances using GitHub Discussions/Issues) to allow user engagement on blog posts and log entries.
14+
* **Why:** Fosters community and interaction with content.
15+
* **Improve SEO/Metadata Generation:**
16+
* **Details:** Dynamically generate more specific meta tags (Open Graph, Twitter Cards) for each blog post, project, or D&D page to improve social media sharing and search engine visibility.
17+
* **Why:** Enhances content discoverability and presentation on external platforms.
18+
* **Implement Newsletter Subscription:**
19+
* **Details:** Add a form to collect email addresses for a newsletter, integrating with a third-party service (e.g., Mailchimp, ConvertKit) via a serverless function if a backend is introduced.
20+
* **Why:** Engages audience and provides a direct communication channel.
21+
* **Enhance the "Apps" Section:**
22+
* **Details:** Populate the `src/pages/apps` directory with small, interactive web applications or tools. Given the D&D content, a full-fledged dice roller or a simple character sheet generator could be good starting points.
23+
* **Why:** Adds interactive value and utility to the site.
24+
25+
## II. Backend Functionality (Free Hosting Options)
26+
27+
These options allow for server-side features without significant cost, often leveraging serverless functions or Backend-as-a-Service (BaaS).
28+
29+
* **Netlify Functions / Vercel Functions:**
30+
* **Use Cases:** Contact forms (Netlify has a built-in Forms feature), simple API endpoints, newsletter subscriptions.
31+
* **Recommendation:** Excellent for simple, integrated backend needs if hosting on Netlify/Vercel.
32+
* **Firebase (Google) - Firestore/Realtime Database + Cloud Functions:**
33+
* **Use Cases:** Ideal for comments, contact forms, dynamic content management, user authentication.
34+
* **Recommendation:** Strong contender for data-heavy dynamic features due to its comprehensive suite and generous free tier.
35+
* **Cloudflare Workers:**
36+
* **Use Cases:** API proxies, edge logic (redirects, A/B testing), simple form handling.
37+
* **Recommendation:** Great for extremely fast, edge-based tasks, but not a full database solution.
38+
39+
## III. App Enhancements (UX, Interactivity, Content, Performance)
40+
41+
Suggestions to improve the user experience, content presentation, and overall site performance.
42+
43+
### UX & Interactivity:
44+
45+
* **Reading Progress Indicator:** Add a subtle progress bar at the top of the viewport for long articles (blog posts, D&D lore).
46+
* **"Table of Contents" for Long Pages:** Automatically generate a sticky table of contents for markdown-rendered pages based on headings (H2, H3), allowing users to jump to sections.
47+
* **Interactive D&D Tools:** Expand the D&D section with tools like a full dice roller, simple character sheet builder, encounter generator, or spell/item lookup.
48+
* **Image Gallery/Lightbox:** Implement a full-screen lightbox/gallery for images embedded in posts or projects.
49+
* **"Related Posts" / "You Might Also Like" Section:** Suggest other relevant content at the end of articles based on tags, categories, or keywords.
50+
* **Dynamic Theme Toggling (Light/Dark Mode):** Provide a UI toggle (e.g., sun/moon icon) for users to switch between light and dark modes, persisting their preference.
51+
52+
### Content & Management:
53+
54+
* **Tagging/Categorization System:** Implement a robust system for tagging and categorizing blog posts, logs, and projects. Display tags on cards/detail pages and create dedicated tag/category archive pages.
55+
* **RSS Feed Enhancement:** Review and enhance the `generate-rss.js` script to include more metadata or different types of content (e.g., separate RSS feeds).
56+
57+
### Performance & SEO:
58+
59+
* **Image Optimization:** Implement automatic image optimization during the build process (compression, WebP generation) and use lazy loading for off-screen images.
60+
* **Advanced SEO Metadata Generation:** Dynamically generate Open Graph (OG) tags, Twitter Cards, and JSON-LD schema markup for each unique page.
61+
62+
## IV. Other Improvement Choices
63+
64+
Broader categories of improvement covering content strategy, accessibility, reliability, and development practices.
65+
66+
### Content & Engagement Strategy:
67+
68+
* **Content Series/Themed Collections:** Group related content into explicit series with dedicated landing pages and clear navigation.
69+
* **Guest Posts / Community Contributions:** Explore allowing curated guest posts to expand content variety and audience.
70+
* **Interactive Tutorials/Code Sandboxes:** Embed interactive code examples or sandboxes in technical posts.
71+
* **Video Content Integration:** Integrate video content directly into relevant posts or create a dedicated video section.
72+
73+
### Accessibility & Inclusivity:
74+
75+
* **Comprehensive Accessibility Audit & Fixes (WCAG Compliance):** Conduct a thorough audit using tools and manual testing to ensure the site meets WCAG standards (keyboard navigation, screen reader compatibility, ARIA, color contrast, focus management).
76+
* **Internationalization (i18n) / Localization (l10n):** Implement a system to support multiple languages with translation files and a language switcher.
77+
78+
### Performance & Reliability:
79+
80+
* **Pre-rendering / Static Site Generation (SSG) for Dynamic Routes:** Pre-render content-heavy pages into static HTML at build time for improved performance and SEO.
81+
* **Service Worker for Offline Capabilities / PWA:** Implement a Service Worker to cache assets and content, enabling offline access and PWA features.
82+
83+
### Development & Maintenance:
84+
85+
* **Automated Testing (Unit, Integration, E2E):** Expand test coverage for components, user flows, and critical paths.
86+
* **CI/CD Pipeline Enhancement:** Enhance the CI/CD pipeline (e.g., GitHub Actions) to include linting, formatting, type checking, testing, and automated deployment.
87+
* **Upgrade to React 19 (Concurrent Features):** Leverage new concurrent features like `useTransition` and `useDeferredValue` to improve perceived performance and responsiveness.
88+
89+
## V. Further Improvement Choices
90+
91+
These suggestions delve into deeper user engagement, potential monetization, and more advanced technical optimizations.
92+
93+
### Community & Interaction (Beyond Comments):
94+
95+
* **User Profiles / Personalization (if a backend is introduced):** Allow users to create profiles, save favorite posts/projects, track reading progress, or customize their experience. Requires user authentication and a database.
96+
* **Forum / Discussion Board:** Implement a dedicated forum (e.g., using Discourse, Flarum) for deeper community engagement, especially for D&D or tech discussions.
97+
* **Live Chat / Q&A Sessions:** Host occasional live chat or Q&A sessions related to blog topics or D&D, using embedded chat widgets or platforms like Discord.
98+
99+
### Monetization & Support:
100+
101+
* **"Buy Me a Coffee" / Sponsorship Integration:** Add an unobtrusive button or section for visitors to financially support the site (e.g., via Buy Me a Coffee, Patreon, PayPal).
102+
* **Affiliate Marketing (Contextual):** Integrate relevant affiliate links for products or services mentioned in content (e.g., books, development tools, D&D accessories), with careful disclosure.
103+
104+
### Content Diversification & Presentation:
105+
106+
* **Interactive Data Visualizations:** For data-heavy posts or projects, create interactive charts, graphs, or maps (e.g., using D3.js, Chart.js).
107+
* **Audio Content (Podcasts / Audio Articles):** Convert popular blog posts into audio articles or start a podcast series, embedding an audio player directly.
108+
* **"Now Playing" / Personal Dashboard:** A small, dynamic section showing what the site owner is currently listening to, reading, or working on (e.g., via Last.fm API, Goodreads API).
109+
110+
### Technical & Infrastructure (Advanced):
111+
112+
* **Edge Caching / CDN Optimization:** Ensure all static assets are served efficiently from a Content Delivery Network (CDN) with aggressive caching policies, fine-tuning beyond basic platform defaults.
113+
* **Server-Side Rendering (SSR) / Hydration (if moving to Next.js/Gatsby):** Leverage SSR capabilities of frameworks like Next.js or Gatsby for initial HTML rendering on the server, improving perceived performance and SEO (a significant architectural change).
114+
* **Web Analytics (Privacy-Focused):** Implement a privacy-focused analytics solution (e.g., Plausible Analytics, Fathom Analytics, self-hosted Matomo) for insights without compromising user privacy.

src/components/AnimatedRoutes.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import DiceRollerPage from '../pages/apps/DiceRollerPage';
3333
import PickerWheelPage from '../pages/apps/PickerWheelPage';
3434
import CodenameGeneratorPage from '../pages/apps/CodenameGeneratorPage';
3535
import ImageToolkitPage from '../pages/apps/ImageToolkitPage';
36+
import PasswordGeneratorPage from '../pages/apps/PasswordGeneratorPage';
3637

3738
import UsefulLinksPage from '../pages/UsefulLinksPage';
3839

@@ -318,6 +319,7 @@ function AnimatedRoutes() {
318319
<Route path="/apps::pw" element={<Navigate to="/apps/picker-wheel" replace />} />
319320
<Route path="/apps::cg" element={<Navigate to="/apps/codename-generator" replace />} />
320321
<Route path="/apps::itk" element={<Navigate to="/apps/image-toolkit" replace />} />
322+
<Route path="/apps::pg" element={<Navigate to="/apps/password-generator" replace />} />
321323
{/* End of hardcoded redirects */}
322324
<Route
323325
path="/apps/ip"
@@ -544,6 +546,20 @@ function AnimatedRoutes() {
544546
</motion.div>
545547
}
546548
/>
549+
<Route
550+
path="/apps/password-generator"
551+
element={
552+
<motion.div
553+
initial="initial"
554+
animate="in"
555+
exit="out"
556+
variants={pageVariants}
557+
transition={pageTransition}
558+
>
559+
<PasswordGeneratorPage />
560+
</motion.div>
561+
}
562+
/>
547563
{/* D&D specific 404 page */}
548564
<Route
549565
path="/dnd/*"

src/pages/AppPage.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ const apps = [
8383
description: 'Generate UUID v4.',
8484
icon: Key,
8585
},
86+
{
87+
to: '/apps/password-generator',
88+
title: 'Password Generator',
89+
description: 'Generate strong, random passwords with customizable options.',
90+
icon: Key,
91+
},
8692
{
8793
to: '/apps/color-palette-generator',
8894
title: 'Color Palette Generator',
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
import React, { useState, useCallback } from 'react';
2+
import usePageTitle from '../../utils/usePageTitle';
3+
import { Link } from 'react-router-dom';
4+
import { ArrowLeftIcon, CopySimple } from '@phosphor-icons/react';
5+
import colors from '../../config/colors';
6+
import { useToast } from '../../hooks/useToast';
7+
import '../../styles/app-buttons.css'; // Assuming general app button styles are here
8+
9+
const PasswordGeneratorPage = () => {
10+
usePageTitle('Password Generator');
11+
const { addToast } = useToast();
12+
13+
const [password, setPassword] = useState('');
14+
const [length, setLength] = useState(12);
15+
const [includeUppercase, setIncludeUppercase] = useState(true);
16+
const [includeLowercase, setIncludeLowercase] = useState(true);
17+
const [includeNumbers, setIncludeNumbers] = useState(true);
18+
const [includeSymbols, setIncludeSymbols] = useState(false);
19+
20+
const generatePassword = useCallback(() => {
21+
let charset = '';
22+
if (includeUppercase) charset += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
23+
if (includeLowercase) charset += 'abcdefghijklmnopqrstuvwxyz';
24+
if (includeNumbers) charset += '0123456789';
25+
if (includeSymbols) charset += '!@#$%^&*()_+~`|}{[]:;?><,./-=';
26+
27+
if (charset.length === 0) {
28+
setPassword('Select at least one character type.');
29+
return;
30+
}
31+
32+
let generatedPassword = '';
33+
for (let i = 0; i < length; i++) {
34+
const randomIndex = Math.floor(Math.random() * charset.length);
35+
generatedPassword += charset[randomIndex];
36+
}
37+
setPassword(generatedPassword);
38+
}, [length, includeUppercase, includeLowercase, includeNumbers, includeSymbols]);
39+
40+
// Generate password on initial load and whenever options change
41+
React.useEffect(() => {
42+
generatePassword();
43+
}, [generatePassword]);
44+
45+
const copyToClipboard = () => {
46+
if (password && password !== 'Select at least one character type.') {
47+
navigator.clipboard.writeText(password);
48+
addToast({ title: 'Copied!', message: 'Password copied to clipboard.', duration: 2000 });
49+
} else {
50+
addToast({ title: 'Cannot Copy', message: 'No password to copy.', duration: 2000, type: 'error' });
51+
}
52+
};
53+
54+
const cardStyle = {
55+
backgroundColor: colors['app-alpha-10'],
56+
borderColor: colors['app-alpha-50'],
57+
color: colors.app,
58+
};
59+
60+
const inputStyle = `mt-1 block w-full p-2 border rounded-md bg-gray-700 text-white focus:ring-blue-500 focus:border-blue-500 border-gray-600`;
61+
const checkboxStyle = `h-4 w-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500`;
62+
const labelStyle = `ml-2 text-sm font-medium text-gray-300`;
63+
64+
return (
65+
<div className="py-16 sm:py-24">
66+
<div className="mx-auto max-w-7xl px-6 lg:px-8 text-gray-300">
67+
<Link
68+
to="/apps"
69+
className="text-article hover:underline flex items-center justify-center gap-2 text-lg mb-4"
70+
>
71+
<ArrowLeftIcon size={24} /> Back to Apps
72+
</Link>
73+
<h1 className="text-4xl font-bold tracking-tight sm:text-6xl mb-4 flex items-center">
74+
<span className="codex-color">fc</span>
75+
<span className="separator-color">::</span>
76+
<span className="apps-color">apps</span>
77+
<span className="separator-color">::</span>
78+
<span className="single-app-color">password</span>
79+
</h1>
80+
<hr className="border-gray-700" />
81+
<div className="flex justify-center items-center mt-16">
82+
<div
83+
className="group bg-transparent border rounded-lg shadow-2xl p-6 flex flex-col justify-between relative transform overflow-hidden h-full w-full max-w-4xl"
84+
style={cardStyle}
85+
>
86+
<div
87+
className="absolute top-0 left-0 w-full h-full opacity-10"
88+
style={{
89+
backgroundImage:
90+
'radial-gradient(circle, white 1px, transparent 1px)',
91+
backgroundSize: '10px 10px',
92+
}}
93+
></div>
94+
<div className="relative z-10 p-1">
95+
<h1 className="text-3xl font-arvo font-normal mb-4 text-app"> Password Generator </h1>
96+
<hr className="border-gray-700 mb-4" />
97+
98+
{/* Client-Side Notification */}
99+
<div className="bg-yellow-900 bg-opacity-30 border border-yellow-700 text-yellow-300 px-4 py-3 rounded relative mb-6" role="alert">
100+
<strong className="font-bold">Client-Side Only:</strong>
101+
<span className="block sm:inline ml-2">This password generator operates entirely within your browser. No data is sent to any server, ensuring maximum privacy for your generated passwords.</span>
102+
</div>
103+
104+
<div className="mb-6">
105+
<label htmlFor="passwordOutput" className="block text-sm font-medium text-gray-300 mb-2">
106+
Generated Password
107+
</label>
108+
<div className="flex">
109+
<input
110+
type="text"
111+
id="passwordOutput"
112+
className={`${inputStyle} flex-grow`}
113+
value={password}
114+
readOnly
115+
/>
116+
<button
117+
onClick={copyToClipboard}
118+
className="ml-2 px-4 py-2 rounded-md text-lg font-arvo font-normal transition-colors duration-300 ease-in-out roll-button flex items-center justify-center"
119+
style={{
120+
backgroundColor: 'rgba(0, 0, 0, 0.2)',
121+
color: cardStyle.color,
122+
borderColor: cardStyle.borderColor,
123+
border: '1px solid',
124+
}}
125+
title="Copy to Clipboard"
126+
>
127+
<CopySimple size={20} />
128+
</button>
129+
</div>
130+
</div>
131+
132+
<div className="mb-6">
133+
<label htmlFor="length" className="block text-sm font-medium text-gray-300 mb-2">
134+
Password Length: {length}
135+
</label>
136+
<input
137+
type="range"
138+
id="length"
139+
min="4"
140+
max="64"
141+
value={length}
142+
onChange={(e) => setLength(Number(e.target.value))}
143+
className="w-full h-2 bg-gray-600 rounded-lg appearance-none cursor-pointer range-sm"
144+
/>
145+
</div>
146+
147+
<div className="grid grid-cols-2 gap-4 mb-6">
148+
<div>
149+
<input
150+
type="checkbox"
151+
id="includeUppercase"
152+
checked={includeUppercase}
153+
onChange={(e) => setIncludeUppercase(e.target.checked)}
154+
className={checkboxStyle}
155+
/>
156+
<label htmlFor="includeUppercase" className={labelStyle}>
157+
Include Uppercase (A-Z)
158+
</label>
159+
</div>
160+
<div>
161+
<input
162+
type="checkbox"
163+
id="includeLowercase"
164+
checked={includeLowercase}
165+
onChange={(e) => setIncludeLowercase(e.target.checked)}
166+
className={checkboxStyle}
167+
/>
168+
<label htmlFor="includeLowercase" className={labelStyle}>
169+
Include Lowercase (a-z)
170+
</label>
171+
</div>
172+
<div>
173+
<input
174+
type="checkbox"
175+
id="includeNumbers"
176+
checked={includeNumbers}
177+
onChange={(e) => setIncludeNumbers(e.target.checked)}
178+
className={checkboxStyle}
179+
/>
180+
<label htmlFor="includeNumbers" className={labelStyle}>
181+
Include Numbers (0-9)
182+
</label>
183+
</div>
184+
<div>
185+
<input
186+
type="checkbox"
187+
id="includeSymbols"
188+
checked={includeSymbols}
189+
onChange={(e) => setIncludeSymbols(e.target.checked)}
190+
className={checkboxStyle}
191+
/>
192+
<label htmlFor="includeSymbols" className={labelStyle}>
193+
Include Symbols
194+
</label>
195+
</div>
196+
</div>
197+
198+
<button
199+
onClick={generatePassword}
200+
className={`px-6 py-2 rounded-md text-lg font-arvo font-normal transition-colors duration-300 ease-in-out roll-button w-full`}
201+
style={{
202+
backgroundColor: 'rgba(0, 0, 0, 0.2)',
203+
color: cardStyle.color,
204+
borderColor: cardStyle.borderColor,
205+
border: '1px solid',
206+
}}
207+
>
208+
Generate New Password
209+
</button>
210+
</div>
211+
</div>
212+
</div>
213+
</div>
214+
</div>
215+
);
216+
};
217+
218+
export default PasswordGeneratorPage;

0 commit comments

Comments
 (0)