feat: add dark mode, fuzzy search, favorites, and URL sharing
Implemented Phases 5-7 of the implementation plan with major UX enhancements:
**Dark Mode (Phase 9)**
- Added ThemeToggle component with localStorage persistence
- System preference detection
- Smooth theme transitions
- Moon/Sun icon toggle in header
**Fuzzy Search with Fuse.js (Phase 5)**
- Integrated Fuse.js for intelligent font search
- 30% threshold for flexible matching
- Search by font name and filename
- Clear button for search input
- Much better than simple string matching
**Favorites & Recent Fonts System (Phase 7)**
- localStorage-based favorites with heart icon toggle
- Auto-tracking of recently used fonts (max 10)
- Filter tabs: All / Favorites / Recent
- Favorite hearts visible on hover
- Red filled heart for favorited fonts
- Stats showing favorite and recent counts
**Shareable URLs (Phase 6)**
- Encode text + font in URL parameters
- Auto-load from URL on page load
- Share button copies URL to clipboard
- Clean URL updates without page reload
- Perfect for sharing ASCII art creations
**Enhanced Font Selector**
- 3-tab filter system (All/Favorites/Recent)
- Visual feedback for selected fonts
- Empty states for each filter
- Font count statistics
- Heart icon for quick favoriting
- Recent fonts sorted by usage order
**UX Improvements**
- Copy feedback ("Copied to clipboard! ✓")
- Share feedback ("URL copied to clipboard! ✓")
- Responsive button layout
- Better empty states
- Improved accessibility with aria-labels
**Tech Highlights**
- Client-side localStorage management
- URL encoding/decoding utilities
- React hooks for state management
- Fuse.js fuzzy search integration
- Theme persistence across sessions
The app now has professional-grade features rivaling any modern web app!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
70
lib/storage/favorites.ts
Normal file
70
lib/storage/favorites.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
'use client';
|
||||
|
||||
const FAVORITES_KEY = 'figlet-ui-favorites';
|
||||
const RECENT_FONTS_KEY = 'figlet-ui-recent-fonts';
|
||||
const MAX_RECENT = 10;
|
||||
|
||||
export function getFavorites(): string[] {
|
||||
if (typeof window === 'undefined') return [];
|
||||
|
||||
try {
|
||||
const stored = localStorage.getItem(FAVORITES_KEY);
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function addFavorite(fontName: string): void {
|
||||
const favorites = getFavorites();
|
||||
if (!favorites.includes(fontName)) {
|
||||
favorites.push(fontName);
|
||||
localStorage.setItem(FAVORITES_KEY, JSON.stringify(favorites));
|
||||
}
|
||||
}
|
||||
|
||||
export function removeFavorite(fontName: string): void {
|
||||
const favorites = getFavorites();
|
||||
const filtered = favorites.filter(f => f !== fontName);
|
||||
localStorage.setItem(FAVORITES_KEY, JSON.stringify(filtered));
|
||||
}
|
||||
|
||||
export function isFavorite(fontName: string): boolean {
|
||||
return getFavorites().includes(fontName);
|
||||
}
|
||||
|
||||
export function toggleFavorite(fontName: string): boolean {
|
||||
const isCurrentlyFavorite = isFavorite(fontName);
|
||||
if (isCurrentlyFavorite) {
|
||||
removeFavorite(fontName);
|
||||
} else {
|
||||
addFavorite(fontName);
|
||||
}
|
||||
return !isCurrentlyFavorite;
|
||||
}
|
||||
|
||||
export function getRecentFonts(): string[] {
|
||||
if (typeof window === 'undefined') return [];
|
||||
|
||||
try {
|
||||
const stored = localStorage.getItem(RECENT_FONTS_KEY);
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function addRecentFont(fontName: string): void {
|
||||
let recent = getRecentFonts();
|
||||
|
||||
// Remove if already exists
|
||||
recent = recent.filter(f => f !== fontName);
|
||||
|
||||
// Add to beginning
|
||||
recent.unshift(fontName);
|
||||
|
||||
// Keep only MAX_RECENT items
|
||||
recent = recent.slice(0, MAX_RECENT);
|
||||
|
||||
localStorage.setItem(RECENT_FONTS_KEY, JSON.stringify(recent));
|
||||
}
|
||||
Reference in New Issue
Block a user