fix: resolve all ESLint errors blocking CI releases

- Extract ThemeContext and ToolCollapseContext definitions into separate
  files to satisfy react-refresh/only-export-components rule
- Move useTheme and useToolCollapse hooks to dedicated hook files
- Fix empty catch block in ThemeContext (add comment)
- Replace Date.now() ref in ThinkingIndicator with useState initializer
- Update all imports across components

Closes feedback #58
This commit is contained in:
Nicolas Varrot
2026-02-13 00:13:12 +00:00
parent 8ab4f83666
commit 73a46f3ba7
11 changed files with 108 additions and 50 deletions

View File

@@ -6,7 +6,7 @@ import type { ChatMessage, ConnectionStatus } from '../types';
import { Bot, ArrowDown, Loader2, ChevronsDownUp, ChevronsUpDown } from 'lucide-react';
import { useT } from '../hooks/useLocale';
import { getLocale, type TranslationKey } from '../lib/i18n';
import { useToolCollapse } from '../contexts/ToolCollapseContext';
import { useToolCollapse } from '../hooks/useToolCollapse';
interface Props {
messages: ChatMessage[];

View File

@@ -1,6 +1,7 @@
import { useState, useRef, useEffect } from 'react';
import { Palette, Sun, Moon, Monitor, Check } from 'lucide-react';
import { useTheme, type ThemeName, type AccentColor } from '../contexts/ThemeContext';
import { useTheme } from '../hooks/useTheme';
import type { ThemeName, AccentColor } from '../contexts/ThemeContextDef';
import { useT } from '../hooks/useLocale';
import type { TranslationKey } from '../lib/i18n';

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useRef } from 'react';
import { useState, useEffect } from 'react';
import { Brain } from 'lucide-react';
import { useT } from '../hooks/useLocale';
@@ -10,14 +10,14 @@ import { useT } from '../hooks/useLocale';
export function ThinkingIndicator() {
const t = useT();
const [elapsed, setElapsed] = useState(0);
const startRef = useRef(Date.now());
const [start] = useState(() => Date.now());
useEffect(() => {
const interval = setInterval(() => {
setElapsed(Math.floor((Date.now() - startRef.current) / 1000));
setElapsed(Math.floor((Date.now() - start) / 1000));
}, 1000);
return () => clearInterval(interval);
}, []);
}, [start]);
const formatElapsed = (s: number) => {
if (s < 60) return `${s}s`;

View File

@@ -3,7 +3,7 @@ import { ChevronRight, ChevronDown, Check, Copy, WrapText, AlignLeft } from 'luc
import hljs from 'highlight.js/lib/common';
import { useT } from '../hooks/useLocale';
import { ImageBlock } from './ImageBlock';
import { useToolCollapse } from '../contexts/ToolCollapseContext';
import { useToolCollapse } from '../hooks/useToolCollapse';
type ToolColor = { border: string; bg: string; text: string; icon: string; glow: string; expandBorder: string; expandBg: string };

View File

@@ -1,23 +1,7 @@
import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react';
import { useState, useEffect, useCallback, type ReactNode } from 'react';
import { ThemeContext, type ThemeName, type AccentColor } from './ThemeContextDef';
export type ThemeName = 'dark' | 'light' | 'oled';
export type AccentColor = 'cyan' | 'violet' | 'emerald' | 'amber' | 'rose' | 'blue';
interface ThemeContextValue {
theme: ThemeName;
accent: AccentColor;
setTheme: (t: ThemeName) => void;
setAccent: (a: AccentColor) => void;
}
const ThemeContext = createContext<ThemeContextValue>({
theme: 'dark',
accent: 'cyan',
setTheme: () => {},
setAccent: () => {},
});
export const useTheme = () => useContext(ThemeContext);
export type { ThemeName, AccentColor } from './ThemeContextDef';
const STORAGE_KEY = 'pinchchat-theme';
@@ -145,7 +129,7 @@ function loadStored(): StoredTheme {
const parsed = JSON.parse(raw);
if (parsed.theme in themes && parsed.accent in accents) return parsed;
}
} catch {}
} catch { /* ignore invalid stored JSON */ }
return { theme: 'dark', accent: 'cyan' };
}

View File

@@ -0,0 +1,18 @@
import { createContext } from 'react';
export type ThemeName = 'dark' | 'light' | 'oled';
export type AccentColor = 'cyan' | 'violet' | 'emerald' | 'amber' | 'rose' | 'blue';
export interface ThemeContextValue {
theme: ThemeName;
accent: AccentColor;
setTheme: (t: ThemeName) => void;
setAccent: (a: AccentColor) => void;
}
export const ThemeContext = createContext<ThemeContextValue>({
theme: 'dark',
accent: 'cyan',
setTheme: () => {},
setAccent: () => {},
});

View File

@@ -1,25 +1,10 @@
import { createContext, useContext, useState, useCallback, type ReactNode } from 'react';
import { useState, useCallback, type ReactNode } from 'react';
import { ToolCollapseContext } from './ToolCollapseContextDef';
type ToolCollapseState = 'none' | 'collapse-all' | 'expand-all';
interface ToolCollapseContextValue {
/** Global override: 'none' means each tool manages its own state */
globalState: ToolCollapseState;
/** Monotonically increasing version — tool calls reset local state when this changes */
version: number;
collapseAll: () => void;
expandAll: () => void;
}
const ToolCollapseContext = createContext<ToolCollapseContextValue>({
globalState: 'none',
version: 0,
collapseAll: () => {},
expandAll: () => {},
});
export { ToolCollapseContext } from './ToolCollapseContextDef';
export function ToolCollapseProvider({ children }: { children: ReactNode }) {
const [globalState, setGlobalState] = useState<ToolCollapseState>('none');
const [globalState, setGlobalState] = useState<'none' | 'collapse-all' | 'expand-all'>('none');
const [version, setVersion] = useState(0);
const collapseAll = useCallback(() => {
@@ -38,7 +23,3 @@ export function ToolCollapseProvider({ children }: { children: ReactNode }) {
</ToolCollapseContext.Provider>
);
}
export function useToolCollapse() {
return useContext(ToolCollapseContext);
}

View File

@@ -0,0 +1,19 @@
import { createContext } from 'react';
type ToolCollapseState = 'none' | 'collapse-all' | 'expand-all';
export interface ToolCollapseContextValue {
/** Global override: 'none' means each tool manages its own state */
globalState: ToolCollapseState;
/** Monotonically increasing version — tool calls reset local state when this changes */
version: number;
collapseAll: () => void;
expandAll: () => void;
}
export const ToolCollapseContext = createContext<ToolCollapseContextValue>({
globalState: 'none',
version: 0,
collapseAll: () => {},
expandAll: () => {},
});

4
src/hooks/useTheme.ts Normal file
View File

@@ -0,0 +1,4 @@
import { useContext } from 'react';
import { ThemeContext } from '../contexts/ThemeContextDef';
export const useTheme = () => useContext(ThemeContext);

View File

@@ -0,0 +1,6 @@
import { useContext } from 'react';
import { ToolCollapseContext } from '../contexts/ToolCollapseContextDef';
export function useToolCollapse() {
return useContext(ToolCollapseContext);
}