diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47429e57..5985bce1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,7 @@ Thank you for your interest in contributing to DocuGen! This document provides g - Node.js 18+ - npm 9+ - Git +- ESLint 9+ (for local development, ESLint uses flat config) ### Development Setup diff --git a/eslint.config.js b/eslint.config.js index fa32aae2..516300a2 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,10 +1,23 @@ import js from '@eslint/js'; import typescript from '@typescript-eslint/eslint-plugin'; import typescriptParser from '@typescript-eslint/parser'; -import reactRefresh from 'eslint-plugin-react-refresh'; import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; import globals from 'globals'; +const browserGlobals = { + window: 'readonly', + document: 'readonly', + console: 'readonly', + localStorage: 'readonly', + navigator: 'readonly', + setTimeout: 'readonly', + File: 'readonly', + Element: 'readonly', + HTMLInputElement: 'readonly', + React: 'readonly', +}; + export default [ js.configs.recommended, { @@ -34,21 +47,9 @@ export default [ }, }, globals: { - window: 'readonly', - document: 'readonly', - console: 'readonly', - localStorage: 'readonly', - navigator: 'readonly', - setTimeout: 'readonly', - File: 'readonly', - Element: 'readonly', - HTMLInputElement: 'readonly', - React: 'readonly', + ...browserGlobals, }, }, - rules: { - 'no-unused-vars': 'warn', - }, }, { files: ['**/*.{ts,tsx}'], @@ -62,28 +63,19 @@ export default [ }, }, globals: { - window: 'readonly', - document: 'readonly', - console: 'readonly', - localStorage: 'readonly', - navigator: 'readonly', - setTimeout: 'readonly', - File: 'readonly', - Element: 'readonly', - HTMLInputElement: 'readonly', - React: 'readonly', + ...browserGlobals, }, }, plugins: { '@typescript-eslint': typescript, - 'react-refresh': reactRefresh, 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, }, rules: { ...typescript.configs.recommended.rules, ...reactHooks.configs.recommended.rules, - '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], }, }, diff --git a/src/components/CookieConsent.tsx b/src/components/CookieConsent.tsx index 4ea3344e..2558a979 100644 --- a/src/components/CookieConsent.tsx +++ b/src/components/CookieConsent.tsx @@ -6,45 +6,29 @@ function getInitialConsentState(): boolean { try { const hasConsented = localStorage.getItem('docugen-cookie-consent'); return !hasConsented; - } catch (error) { - console.error('Failed to read cookie consent from localStorage:', error); + } catch { return true; } } -/** - * Cookie consent management component. - * Manages GDPR compliance for analytics tracking. - * Shows consent banner and stores user preference in localStorage. - * - * @returns Cookie consent banner component - */ export function CookieConsent() { const [showConsent, setShowConsent] = useState(getInitialConsentState); - /** - * Handles accepting all cookies. - * Stores acceptance preference and hides consent banner. - */ const handleAccept = () => { setShowConsent(false); try { localStorage.setItem('docugen-cookie-consent', 'accepted'); - } catch (e) { - console.error('Failed to save cookie consent to storage:', e); + } catch { + // Silently fail } }; - /** - * Handles declining optional cookies. - * Stores decline preference and hides consent banner. - */ const handleDecline = () => { setShowConsent(false); try { localStorage.setItem('docugen-cookie-consent', 'declined'); - } catch (e) { - console.error('Failed to save cookie consent to storage:', e); + } catch { + // Silently fail } }; diff --git a/src/components/UploadDemo.tsx b/src/components/UploadDemo.tsx index 9c7bc5fc..423e4c18 100644 --- a/src/components/UploadDemo.tsx +++ b/src/components/UploadDemo.tsx @@ -2,23 +2,6 @@ import { useState, useRef, useCallback } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Button } from './ui/Button'; -/** - * UploadDemo component that provides an interactive file upload demonstration. - * Supports drag-and-drop and click-to-select functionality for Markdown files (.md, .mdx). - * Features multiple states: initial dropzone, uploading, and completion with animated transitions. - * Includes file validation, progress simulation, and the ability to reset and try again. - * - * @example - * ```tsx - * import { UploadDemo } from '@/components/UploadDemo'; - * - * function UploadSection() { - * return ; - * } - * ``` - * - * @returns A JSX element representing the upload demonstration interface - */ export function UploadDemo() { const [isDragging, setIsDragging] = useState(false); const [file, setFile] = useState(null); @@ -26,10 +9,6 @@ export function UploadDemo() { const [isComplete, setIsComplete] = useState(false); const fileInputRef = useRef(null); - /** - * Simulates the file upload process with a 2-second delay. - * Sets uploading state to true immediately, then transitions to complete state after timeout. - */ const simulateUpload = useCallback(() => { setIsUploading(true); setTimeout(() => { @@ -38,28 +17,16 @@ export function UploadDemo() { }, 2000); }, []); - /** - * Handles the drag over event for the dropzone. - * Prevents default browser behavior and sets the dragging state to true. - */ const handleDragOver = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragging(true); }, []); - /** - * Handles the drag leave event for the dropzone. - * Prevents default browser behavior and sets the dragging state to false. - */ const handleDragLeave = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); }, []); - /** - * Handles the drop event for the dropzone. - * Validates file type and initiates upload simulation for valid Markdown files. - */ const handleDrop = useCallback( (e: React.DragEvent) => { e.preventDefault(); @@ -73,10 +40,6 @@ export function UploadDemo() { [simulateUpload] ); - /** - * Handles file selection via the file input dialog. - * Validates file type and initiates upload simulation for valid Markdown files. - */ const handleFileSelect = useCallback( (e: React.ChangeEvent) => { const selectedFile = e.target.files?.[0]; @@ -91,10 +54,6 @@ export function UploadDemo() { [simulateUpload] ); - /** - * Resets the upload demo to its initial state. - * Clears the selected file and resets all state variables. - */ const resetDemo = () => { setFile(null); setIsUploading(false); diff --git a/src/lib/ThemeContext.tsx b/src/lib/ThemeContext.tsx index eb3ff98a..30adb43f 100644 --- a/src/lib/ThemeContext.tsx +++ b/src/lib/ThemeContext.tsx @@ -13,12 +13,6 @@ export const ThemeContext = createContext(undefine const THEME_STORAGE_KEY = 'docugen-theme'; -/** - * Determines the initial theme based on localStorage and system preferences. - * Checks for stored theme first, then falls back to system preference. - * - * @returns Initial theme ('light' | 'dark') - */ function getInitialTheme(): Theme { if (typeof window === 'undefined') { return 'dark'; @@ -37,12 +31,6 @@ function getInitialTheme(): Theme { } } -/** - * Applies the theme to the document root element. - * Adds or removes the 'dark' class to enable Tailwind CSS dark mode. - * - * @param theme - Theme to apply ('light' | 'dark') - */ function applyTheme(theme: Theme) { const root = document.documentElement; if (theme === 'dark') { @@ -56,20 +44,6 @@ interface ThemeProviderProps { children: ReactNode; } -/** - * React context provider for theme management. - * Manages theme state, persistence, and DOM theme application. - * - * @param children - Child components to wrap with theme context - * @returns Theme context provider component - * - * @example - * ```typescript - * - * - * - * ``` - */ export function ThemeProvider({ children }: ThemeProviderProps) { const [theme, setTheme] = useState(getInitialTheme); @@ -82,8 +56,8 @@ export function ThemeProvider({ children }: ThemeProviderProps) { setTheme(newTheme); try { localStorage.setItem(THEME_STORAGE_KEY, newTheme); - } catch (error) { - console.warn('Failed to persist theme preference:', error); + } catch { + // Silently fail } }; @@ -91,8 +65,8 @@ export function ThemeProvider({ children }: ThemeProviderProps) { setTheme(newTheme); try { localStorage.setItem(THEME_STORAGE_KEY, newTheme); - } catch (error) { - console.warn('Failed to persist theme preference:', error); + } catch { + // Silently fail } };