* feat: implement light/dark mode theme system - Add semantic color CSS variables (success, warning, info, error) for both themes - Create ThemeProvider with React context and localStorage persistence - Add ThemeToggle component with sun/moon icons for header region - Add theme switcher in General Settings modal - Replace 200+ hardcoded Tailwind colors with CSS variables across 30+ components - Update layout.tsx to remove forced dark mode - Keep terminal colors unchanged as requested - Default to dark mode, with seamless light/dark switching Components updated: - High-priority: InstalledScriptsTab, ScriptInstallationCard, LXCSettingsModal, ScriptsGrid - All remaining component files with hardcoded colors - UI components: button, toggle, badge variants - Modal components: ErrorModal, ConfirmationModal, AuthModal, SetupModal - Form components: ServerForm, FilterBar, CategorySidebar - Display components: ScriptCard, ScriptCardList, DiffViewer, TextViewer Theme switchers: - Header: Small nuanced toggle in top-right - Settings: Detailed Light/Dark selection in General Settings * fix: resolve ESLint warnings - Fix missing dependencies in useCallback and useEffect hooks - Prefix unused parameter with underscore to satisfy ESLint rules - Build now completes without warnings * fix: improve toggle component styling for better visibility - Use explicit gray colors instead of CSS variables for toggle background - Ensure proper contrast in both light and dark modes - Toggle switches now display correctly with proper visual states * fix: improve toggle visual states for better UX - Use explicit conditional styling instead of peer classes - Active toggles now clearly show primary color background - Inactive toggles show gray background for clear distinction - Much easier to tell which toggles are on/off at a glance * fix: improve toggle contrast in dark mode - Change inactive toggle background from gray-700 to gray-600 for better visibility - Add darker border color (gray-500) for toggle handle in dark mode - Toggles now have proper contrast against dark backgrounds - Both light and dark modes now have clear visual distinction * fix: resolve dependency loop and improve dropdown styling - Fix circular dependency in InstalledScriptsTab status check - Remove fetchContainerStatuses function and inline logic in useEffect - Make all dropdown menu items grey with consistent hover effects - Update both ScriptInstallationCard and InstalledScriptsTab dropdowns - Remove unused useCallback import - Build now completes without warnings or errors * fix: restore proper button colors and eliminate dependency loop - Restore red color for Stop/Destroy buttons and green for Start buttons - Fix circular dependency by using ref for containerStatusMutation - Update both InstalledScriptsTab and ScriptInstallationCard dropdowns - Maintain grey color for other menu items (Update, Shell, Open UI, etc.) - Build now completes without warnings or dependency loops * feat: add missing hover utility classes for semantic colors - Add hover states for success, warning, info, error colors - Add hover:bg-success/20, hover:bg-error/20, etc. classes - Add hover:text-success-foreground, hover:text-error-foreground classes - Start/Stop and Destroy buttons now have proper hover effects - All dropdown menu items now have consistent hover behavior * feat: improve status cards with useful LXC container information - Replace useless 'Successful/Failed/In Progress' cards with meaningful data - Show 'Running LXC' count in green (actual running containers) - Show 'Stopped LXC' count in red (actual stopped containers) - Keep 'Total Installations' for overall count - Change layout from 4 columns to 3 columns for better spacing - Status cards now show real-time container states instead of installation status * style: center content in status cards - Add text-center class to each individual status card - Numbers and labels now centered within each card - Improves visual balance and readability - All three cards (Total, Running LXC, Stopped LXC) now have centered content
92 lines
3.0 KiB
TypeScript
92 lines
3.0 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { api } from '~/trpc/react';
|
|
import { Button } from './ui/button';
|
|
import { ContextualHelpIcon } from './ContextualHelpIcon';
|
|
|
|
export function ResyncButton() {
|
|
const [isResyncing, setIsResyncing] = useState(false);
|
|
const [lastSync, setLastSync] = useState<Date | null>(null);
|
|
const [syncMessage, setSyncMessage] = useState<string | null>(null);
|
|
|
|
const resyncMutation = api.scripts.resyncScripts.useMutation({
|
|
onSuccess: (data) => {
|
|
setIsResyncing(false);
|
|
setLastSync(new Date());
|
|
if (data.success) {
|
|
setSyncMessage(data.message ?? 'Scripts synced successfully');
|
|
// Reload the page after successful sync
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 2000); // Wait 2 seconds to show the success message
|
|
} else {
|
|
setSyncMessage(data.error ?? 'Failed to sync scripts');
|
|
// Clear message after 3 seconds for errors
|
|
setTimeout(() => setSyncMessage(null), 3000);
|
|
}
|
|
},
|
|
onError: (error) => {
|
|
setIsResyncing(false);
|
|
setSyncMessage(`Error: ${error.message}`);
|
|
setTimeout(() => setSyncMessage(null), 3000);
|
|
},
|
|
});
|
|
|
|
const handleResync = async () => {
|
|
setIsResyncing(true);
|
|
setSyncMessage(null);
|
|
resyncMutation.mutate();
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-col sm:flex-row sm:items-center gap-3">
|
|
<div className="text-sm text-muted-foreground font-medium">
|
|
Sync scripts with ProxmoxVE repo
|
|
</div>
|
|
<div className="flex flex-col sm:flex-row sm:items-center gap-3">
|
|
<div className="flex items-center gap-2">
|
|
<Button
|
|
onClick={handleResync}
|
|
disabled={isResyncing}
|
|
variant="outline"
|
|
size="default"
|
|
className="inline-flex items-center"
|
|
>
|
|
{isResyncing ? (
|
|
<>
|
|
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white mr-2"></div>
|
|
<span>Syncing...</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
</svg>
|
|
<span>Sync Json Files</span>
|
|
</>
|
|
)}
|
|
</Button>
|
|
<ContextualHelpIcon section="sync-button" tooltip="Help with Sync Button" />
|
|
</div>
|
|
|
|
{lastSync && (
|
|
<div className="text-xs text-muted-foreground">
|
|
Last sync: {lastSync.toLocaleTimeString()}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{syncMessage && (
|
|
<div className={`text-sm px-3 py-1 rounded-lg ${
|
|
syncMessage.includes('Error') || syncMessage.includes('Failed')
|
|
? 'bg-error/10 text-error'
|
|
: 'bg-success/10 text-success'
|
|
}`}>
|
|
{syncMessage}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|