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
}
};