chore: apply code formatting and linting

- format long import statements with consistent line wrapping
- apply consistent indentation across client and server modules
- remove generated tsconfig.tsbuildinfo file
This commit is contained in:
2026-04-14 22:54:03 +03:00
parent a71be39076
commit e66e53c817
57 changed files with 851 additions and 478 deletions
+6 -3
View File
@@ -36,15 +36,18 @@ export function Breadcrumbs({ items, separator, className }: BreadcrumbsProps) {
<li key={i} className={styles.item}>
{isLast ? (
<span className={styles.current} aria-current="page">
{item.icon}{item.label}
{item.icon}
{item.label}
</span>
) : item.href ? (
<a href={item.href} className={styles.link} onClick={item.onClick}>
{item.icon}{item.label}
{item.icon}
{item.label}
</a>
) : (
<button type="button" className={styles.link} onClick={item.onClick}>
{item.icon}{item.label}
{item.icon}
{item.label}
</button>
)}
{!isLast && <span className={styles.separator}>{sep}</span>}
+34 -45
View File
@@ -1,9 +1,8 @@
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { AlertCircle, CheckCircle2, Info, X } from 'lucide-react';
import styles from './ToastProvider.module.css';
import { subscribeApiErrorToasts } from '../../lib/toast-events';
type ToastVariant = 'success' | 'error' | 'info';
import { ToastContext, type ToastApi, type ToastVariant } from './toast-context';
interface ToastItem {
id: number;
@@ -12,15 +11,6 @@ interface ToastItem {
closing: boolean;
}
interface ToastApi {
show: (message: string, variant?: ToastVariant) => void;
success: (message: string) => void;
error: (message: string) => void;
info: (message: string) => void;
}
const ToastContext = createContext<ToastApi | null>(null);
const ICONS: Record<ToastVariant, React.ReactNode> = {
success: <CheckCircle2 size={16} />,
error: <AlertCircle size={16} />,
@@ -41,33 +31,38 @@ export function ToastProvider({ children, durationMs = 3500 }: ToastProviderProp
setItems((prev) => prev.filter((item) => item.id !== id));
}, []);
const dismiss = useCallback((id: number) => {
setItems((prev) =>
prev.map((item) =>
item.id === id ? { ...item, closing: true } : item,
),
);
window.setTimeout(() => remove(id), EXIT_ANIMATION_MS);
}, [remove]);
const dismiss = useCallback(
(id: number) => {
setItems((prev) => prev.map((item) => (item.id === id ? { ...item, closing: true } : item)));
window.setTimeout(() => remove(id), EXIT_ANIMATION_MS);
},
[remove],
);
const show = useCallback((message: string, variant: ToastVariant = 'info') => {
const now = Date.now();
const dedupeKey = `${variant}:${message}`;
const previousTs = lastShownAtRef.current.get(dedupeKey) ?? 0;
if (now - previousTs < 600) return;
lastShownAtRef.current.set(dedupeKey, now);
const show = useCallback(
(message: string, variant: ToastVariant = 'info') => {
const now = Date.now();
const dedupeKey = `${variant}:${message}`;
const previousTs = lastShownAtRef.current.get(dedupeKey) ?? 0;
if (now - previousTs < 600) return;
lastShownAtRef.current.set(dedupeKey, now);
const id = Date.now() + Math.floor(Math.random() * 1000);
setItems((prev) => [...prev, { id, message, variant, closing: false }]);
window.setTimeout(() => dismiss(id), durationMs);
}, [dismiss, durationMs]);
const id = Date.now() + Math.floor(Math.random() * 1000);
setItems((prev) => [...prev, { id, message, variant, closing: false }]);
window.setTimeout(() => dismiss(id), durationMs);
},
[dismiss, durationMs],
);
const api = useMemo<ToastApi>(() => ({
show,
success: (message: string) => show(message, 'success'),
error: (message: string) => show(message, 'error'),
info: (message: string) => show(message, 'info'),
}), [show]);
const api = useMemo<ToastApi>(
() => ({
show,
success: (message: string) => show(message, 'success'),
error: (message: string) => show(message, 'error'),
info: (message: string) => show(message, 'info'),
}),
[show],
);
useEffect(() => {
return subscribeApiErrorToasts((message) => api.error(message));
@@ -86,7 +81,9 @@ export function ToastProvider({ children, durationMs = 3500 }: ToastProviderProp
role="status"
>
<div className={styles.content}>
<span className={styles.icon} aria-hidden="true">{ICONS[item.variant]}</span>
<span className={styles.icon} aria-hidden="true">
{ICONS[item.variant]}
</span>
<p className={styles.message}>{item.message}</p>
</div>
<button
@@ -103,11 +100,3 @@ export function ToastProvider({ children, durationMs = 3500 }: ToastProviderProp
</ToastContext.Provider>
);
}
export function useToast(): ToastApi {
const ctx = useContext(ToastContext);
if (!ctx) {
throw new Error('useToast must be used within ToastProvider');
}
return ctx;
}
+12
View File
@@ -0,0 +1,12 @@
import { createContext } from 'react';
export type ToastVariant = 'success' | 'error' | 'info';
export interface ToastApi {
show: (message: string, variant?: ToastVariant) => void;
success: (message: string) => void;
error: (message: string) => void;
info: (message: string) => void;
}
export const ToastContext = createContext<ToastApi | null>(null);
+10
View File
@@ -0,0 +1,10 @@
import { useContext } from 'react';
import { ToastContext, type ToastApi } from './toast-context';
export function useToast(): ToastApi {
const ctx = useContext(ToastContext);
if (!ctx) {
throw new Error('useToast must be used within ToastProvider');
}
return ctx;
}
+2 -1
View File
@@ -27,8 +27,9 @@ export type { BreadcrumbsProps, BreadcrumbItem } from './Breadcrumbs/Breadcrumbs
export { ThemeSwitcher } from './ThemeSwitcher/ThemeSwitcher';
export { ToastProvider, useToast } from './Toast/ToastProvider';
export { ToastProvider } from './Toast/ToastProvider';
export type { ToastProviderProps } from './Toast/ToastProvider';
export { useToast } from './Toast/useToast';
export { Timestamp } from './Timestamp/Timestamp';
export type { TimestampProps } from './Timestamp/Timestamp';