b9316552c2
- Add logo_url column to nodes table for custom branding - Refactor bots table to use owner_id foreign key relationship with users - Add is_bot and bot_owner_id columns to users table for bot account tracking - Add bot_id foreign key to posts table for bot-generated content tracking - Create database indexes on owner_id, bot_id, is_bot, and bot_owner_id for query performance - Remove bot handle, bio, avatar_url, and cryptographic keys from bots table (moved to user accounts) - Update bot_content_sources schema and remove fetch_interval_minutes column - Fix bot_content_items foreign key constraint with set null on delete - Remove hardcoded NODE_NAME and NODE_DESCRIPTION from environment configuration - Update admin panel, bot settings, and layout components to support new schema - Add AccentColorContext and ToastContext for improved UI state management - Update PostCard, Sidebar, RightSidebar, and LayoutWrapper components for context integration
68 lines
2.1 KiB
TypeScript
68 lines
2.1 KiB
TypeScript
'use client';
|
|
|
|
import { createContext, useContext, useEffect, useState, useCallback, ReactNode } from 'react';
|
|
|
|
interface AccentColorContextType {
|
|
accentColor: string;
|
|
refreshAccentColor: () => void;
|
|
}
|
|
|
|
const AccentColorContext = createContext<AccentColorContextType | null>(null);
|
|
|
|
function applyAccentColor(color: string) {
|
|
const cleaned = color.trim();
|
|
const normalized = cleaned.startsWith('#') ? cleaned : `#${cleaned}`;
|
|
const hexMatch = /^#([0-9a-fA-F]{6})$/.exec(normalized);
|
|
if (!hexMatch) return;
|
|
|
|
const hex = hexMatch[1];
|
|
const r = parseInt(hex.slice(0, 2), 16);
|
|
const g = parseInt(hex.slice(2, 4), 16);
|
|
const b = parseInt(hex.slice(4, 6), 16);
|
|
|
|
const mix = (channel: number, target: number, amount: number) =>
|
|
Math.round(channel + (target - channel) * amount);
|
|
|
|
const hover = `rgb(${mix(r, 255, 0.12)}, ${mix(g, 255, 0.12)}, ${mix(b, 255, 0.12)})`;
|
|
const muted = `rgba(${r}, ${g}, ${b}, 0.12)`;
|
|
|
|
const root = document.documentElement;
|
|
root.style.setProperty('--accent', `#${hex}`);
|
|
root.style.setProperty('--accent-hover', hover);
|
|
root.style.setProperty('--accent-muted', muted);
|
|
}
|
|
|
|
export function AccentColorProvider({ children }: { children: ReactNode }) {
|
|
const [accentColor, setAccentColor] = useState('#00D4AA');
|
|
|
|
const refreshAccentColor = useCallback(() => {
|
|
fetch('/api/node', { cache: 'no-store' })
|
|
.then((res) => res.json())
|
|
.then((data) => {
|
|
if (data?.accentColor) {
|
|
setAccentColor(data.accentColor);
|
|
applyAccentColor(data.accentColor);
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
refreshAccentColor();
|
|
}, [refreshAccentColor]);
|
|
|
|
return (
|
|
<AccentColorContext.Provider value={{ accentColor, refreshAccentColor }}>
|
|
{children}
|
|
</AccentColorContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useAccentColor() {
|
|
const context = useContext(AccentColorContext);
|
|
if (!context) {
|
|
throw new Error('useAccentColor must be used within an AccentColorProvider');
|
|
}
|
|
return context;
|
|
}
|