feat: implement Figlet, Pastel, and Unit tools with a unified layout

- Add Figlet text converter with font selection and history
- Add Pastel color palette generator and manipulation suite
- Add comprehensive Units converter with category-based logic
- Introduce AppShell with Sidebar and Header for navigation
- Modernize theme system with CSS variables and new animations
- Update project configuration and dependencies
This commit is contained in:
2026-02-22 21:35:53 +01:00
parent ff6bb873eb
commit 2000623c67
540 changed files with 338653 additions and 809 deletions

38
lib/utils/animations.ts Normal file
View File

@@ -0,0 +1,38 @@
// Animation utility classes and keyframes
export const fadeIn = {
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
};
export const slideUp = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -20 },
};
export const slideDown = {
initial: { opacity: 0, y: -20 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: 20 },
};
export const scaleIn = {
initial: { opacity: 0, scale: 0.95 },
animate: { opacity: 1, scale: 1 },
exit: { opacity: 0, scale: 0.95 },
};
export const staggerChildren = {
animate: {
transition: {
staggerChildren: 0.05,
},
},
};
export const staggerItem = {
initial: { opacity: 0, y: 10 },
animate: { opacity: 1, y: 0 },
};

6
lib/utils/cn.ts Normal file
View File

@@ -0,0 +1,6 @@
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

18
lib/utils/debounce.ts Normal file
View File

@@ -0,0 +1,18 @@
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeout: NodeJS.Timeout | null = null;
return function executedFunction(...args: Parameters<T>) {
const later = () => {
timeout = null;
func(...args);
};
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
};
}

4
lib/utils/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export * from './cn';
export * from './debounce';
export * from './urlSharing';
export * from './animations';

64
lib/utils/urlSharing.ts Normal file
View File

@@ -0,0 +1,64 @@
'use client';
export interface ShareableState {
text: string;
font: string;
}
/**
* Encode text and font to URL parameters
*/
export function encodeToUrl(text: string, font: string): string {
const params = new URLSearchParams();
if (text) {
params.set('text', text);
}
if (font && font !== 'Standard') {
params.set('font', font);
}
const queryString = params.toString();
return queryString ? `?${queryString}` : '';
}
/**
* Decode URL parameters to get text and font
*/
export function decodeFromUrl(): ShareableState | null {
if (typeof window === 'undefined') return null;
const params = new URLSearchParams(window.location.search);
const text = params.get('text');
const font = params.get('font');
if (!text && !font) return null;
return {
text: text || '',
font: font || 'Standard',
};
}
/**
* Update the URL without reloading the page
*/
export function updateUrl(text: string, font: string): void {
if (typeof window === 'undefined') return;
const url = encodeToUrl(text, font);
const newUrl = url ? `${window.location.pathname}${url}` : window.location.pathname;
window.history.replaceState({}, '', newUrl);
}
/**
* Get shareable URL
*/
export function getShareableUrl(text: string, font: string): string {
if (typeof window === 'undefined') return '';
const query = encodeToUrl(text, font);
return `${window.location.origin}${window.location.pathname}${query}`;
}