refactor: move configs and hooks to global locations for reusability

Move previously nested configs and hooks to global src/ folders to make
them reusable across the application, reduce nesting, and establish
clearer organization patterns.

**New Global Structure:**
- src/config/theme-options.ts (moved from appearance/config/)
- src/config/api-providers.ts (moved from api-keys/config/)
- src/hooks/use-scroll-tracking.ts (moved from settings-view/hooks/)

**Changes:**
- Move theme-options.ts to src/config/ - app-wide theme configuration
- Move api-provider-config.ts to src/config/api-providers.ts - global API config
- Move use-scroll-tracking.ts to src/hooks/ - reusable scroll navigation hook
- Make useScrollTracking generic and more flexible with options object
- Update all imports across settings-view components
- Remove duplicate api-provider-config.ts from shared/ folder
- Remove empty config/ folders (appearance/config, api-keys/config)

**Benefits:**
 Single source of truth for themes and API providers
 Reusable scroll tracking hook available globally
 Cleaner structure with less nesting
 Better discoverability for developers
 No duplicate configuration files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Kacper
2025-12-11 01:10:36 +01:00
parent 82cc8abd29
commit 772b0e9e5c
9 changed files with 56 additions and 180 deletions

View File

@@ -0,0 +1,104 @@
import { useState, useEffect, useRef, useCallback } from "react";
interface ScrollTrackingItem {
id: string;
}
interface UseScrollTrackingOptions<T extends ScrollTrackingItem> {
/** Navigation items with at least an id property */
items: T[];
/** Optional filter function to determine which items should be tracked */
filterFn?: (item: T) => boolean;
/** Optional initial active section (defaults to first item's id) */
initialSection?: string;
/** Optional offset from top when scrolling to section (defaults to 24) */
scrollOffset?: number;
}
/**
* Generic custom hook for managing scroll-based navigation tracking
* Automatically highlights the active section based on scroll position
* and provides smooth scrolling to sections
*/
export function useScrollTracking<T extends ScrollTrackingItem>({
items,
filterFn = () => true,
initialSection,
scrollOffset = 24,
}: UseScrollTrackingOptions<T>) {
const [activeSection, setActiveSection] = useState(
initialSection || items[0]?.id || ""
);
const scrollContainerRef = useRef<HTMLDivElement>(null);
// Track scroll position to highlight active nav item
useEffect(() => {
const container = scrollContainerRef.current;
if (!container) return;
const handleScroll = () => {
const sections = items
.filter(filterFn)
.map((item) => ({
id: item.id,
element: document.getElementById(item.id),
}))
.filter((s) => s.element);
const containerRect = container.getBoundingClientRect();
const scrollTop = container.scrollTop;
const scrollHeight = container.scrollHeight;
const clientHeight = container.clientHeight;
// Check if scrolled to bottom (within a small threshold)
const isAtBottom = scrollTop + clientHeight >= scrollHeight - 50;
if (isAtBottom && sections.length > 0) {
// If at bottom, highlight the last visible section
setActiveSection(sections[sections.length - 1].id);
return;
}
for (let i = sections.length - 1; i >= 0; i--) {
const section = sections[i];
if (section.element) {
const rect = section.element.getBoundingClientRect();
const relativeTop = rect.top - containerRect.top + scrollTop;
if (scrollTop >= relativeTop - 100) {
setActiveSection(section.id);
break;
}
}
}
};
container.addEventListener("scroll", handleScroll);
return () => container.removeEventListener("scroll", handleScroll);
}, [items, filterFn]);
// Scroll to a specific section with smooth animation
const scrollToSection = useCallback(
(sectionId: string) => {
const element = document.getElementById(sectionId);
if (element && scrollContainerRef.current) {
const container = scrollContainerRef.current;
const containerRect = container.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
const relativeTop =
elementRect.top - containerRect.top + container.scrollTop;
container.scrollTo({
top: relativeTop - scrollOffset,
behavior: "smooth",
});
}
},
[scrollOffset]
);
return {
activeSection,
scrollToSection,
scrollContainerRef,
};
}