2024-09-09 11:51:54 -04:00
|
|
|
'use client';
|
|
|
|
|
|
|
|
import React, { useState, useEffect } from 'react';
|
2024-09-09 15:31:19 -04:00
|
|
|
import Image from 'next/image';
|
2024-09-09 11:51:54 -04:00
|
|
|
import ColorSchemeCard from "./components/ColorSchemeCard";
|
2024-09-09 16:02:26 -04:00
|
|
|
import HistoryPopup from "./components/HistoryPopup";
|
2024-09-09 16:59:00 -04:00
|
|
|
import Settings from "./components/Settings";
|
2024-09-09 17:59:21 -04:00
|
|
|
import HelpDialog from "./components/HelpDialog";
|
2024-09-09 13:31:32 -04:00
|
|
|
import { ColorScheme, knownSchemes, generateRandomScheme, generateSchemeFromGeneticAlgorithm } from './utils/colorSchemes';
|
|
|
|
import { AnimatePresence } from 'framer-motion';
|
2024-09-09 18:08:56 -04:00
|
|
|
import { CodeSample } from './utils/types';
|
2024-09-09 09:50:12 -04:00
|
|
|
|
|
|
|
export default function Home() {
|
2024-09-09 11:51:54 -04:00
|
|
|
const [schemes, setSchemes] = useState<ColorScheme[]>([]);
|
|
|
|
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
|
|
const [likedSchemes, setLikedSchemes] = useState<ColorScheme[]>([]);
|
|
|
|
const [dislikedSchemes, setDislikedSchemes] = useState<ColorScheme[]>([]);
|
2024-09-09 16:02:26 -04:00
|
|
|
const [isHistoryOpen, setIsHistoryOpen] = useState(false);
|
2024-09-09 16:59:00 -04:00
|
|
|
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
2024-09-09 17:59:21 -04:00
|
|
|
const [isHelpOpen, setIsHelpOpen] = useState(false);
|
2024-09-09 16:59:00 -04:00
|
|
|
const [outputFormat, setOutputFormat] = useState('yaml');
|
2024-09-09 18:08:56 -04:00
|
|
|
const [codeSample, setCodeSample] = useState<CodeSample>('javascript');
|
2024-09-09 16:59:00 -04:00
|
|
|
const [saveSettings, setSaveSettings] = useState(false);
|
2024-09-09 11:51:54 -04:00
|
|
|
|
2024-09-09 18:08:56 -04:00
|
|
|
const generateNewSchemes = (count: number) => {
|
|
|
|
const knownCount = Math.floor(count / 2);
|
|
|
|
const generatedCount = count - knownCount;
|
|
|
|
const newSchemes = [
|
|
|
|
...knownSchemes.sort(() => 0.5 - Math.random()).slice(0, knownCount),
|
|
|
|
...Array(generatedCount).fill(null).map(() =>
|
|
|
|
likedSchemes.length > 0 ? generateSchemeFromGeneticAlgorithm(likedSchemes, dislikedSchemes) : generateRandomScheme()
|
|
|
|
)
|
|
|
|
];
|
|
|
|
|
|
|
|
setSchemes(prevSchemes => [...prevSchemes, ...newSchemes].sort(() => 0.5 - Math.random()));
|
|
|
|
};
|
|
|
|
|
2024-09-09 11:51:54 -04:00
|
|
|
useEffect(() => {
|
2024-09-09 13:31:32 -04:00
|
|
|
generateNewSchemes(8);
|
2024-09-09 11:51:54 -04:00
|
|
|
setIsDarkMode(window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
|
|
const storedLikedSchemes = localStorage.getItem('likedSchemes');
|
|
|
|
const storedDislikedSchemes = localStorage.getItem('dislikedSchemes');
|
|
|
|
if (storedLikedSchemes) {
|
|
|
|
setLikedSchemes(JSON.parse(storedLikedSchemes));
|
|
|
|
}
|
|
|
|
if (storedDislikedSchemes) {
|
|
|
|
setDislikedSchemes(JSON.parse(storedDislikedSchemes));
|
|
|
|
}
|
2024-09-09 16:59:00 -04:00
|
|
|
|
|
|
|
// Load settings from cookie if available
|
|
|
|
const storedSettings = document.cookie.split('; ').find(row => row.startsWith('settings='));
|
|
|
|
if (storedSettings) {
|
|
|
|
const settings = JSON.parse(storedSettings.split('=')[1]);
|
|
|
|
setOutputFormat(settings.outputFormat);
|
|
|
|
setCodeSample(settings.codeSample);
|
|
|
|
setSaveSettings(true);
|
|
|
|
}
|
2024-09-09 11:51:54 -04:00
|
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
document.documentElement.classList.toggle('dark', isDarkMode);
|
|
|
|
}, [isDarkMode]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
localStorage.setItem('likedSchemes', JSON.stringify(likedSchemes));
|
|
|
|
}, [likedSchemes]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
localStorage.setItem('dislikedSchemes', JSON.stringify(dislikedSchemes));
|
|
|
|
}, [dislikedSchemes]);
|
2024-09-09 09:50:12 -04:00
|
|
|
|
2024-09-09 16:59:00 -04:00
|
|
|
useEffect(() => {
|
|
|
|
if (saveSettings) {
|
|
|
|
const settings = JSON.stringify({ outputFormat, codeSample });
|
|
|
|
document.cookie = `settings=${settings}; max-age=31536000; path=/`; // 1 year expiration
|
|
|
|
} else {
|
|
|
|
document.cookie = 'settings=; max-age=0; path=/';
|
|
|
|
}
|
|
|
|
}, [saveSettings, outputFormat, codeSample]);
|
2024-09-09 11:51:54 -04:00
|
|
|
|
2024-09-09 13:31:32 -04:00
|
|
|
const handleLike = (scheme: ColorScheme) => {
|
|
|
|
setLikedSchemes(prev => [...prev, scheme]);
|
|
|
|
removeTopScheme();
|
2024-09-09 11:51:54 -04:00
|
|
|
};
|
|
|
|
|
2024-09-09 13:31:32 -04:00
|
|
|
const handleDislike = (scheme: ColorScheme) => {
|
|
|
|
setDislikedSchemes(prev => [...prev, scheme]);
|
|
|
|
removeTopScheme();
|
|
|
|
};
|
|
|
|
|
|
|
|
const removeTopScheme = () => {
|
|
|
|
setSchemes(prevSchemes => {
|
|
|
|
const newSchemes = prevSchemes.slice(1);
|
|
|
|
if (newSchemes.length < 3) {
|
|
|
|
generateNewSchemes(3);
|
|
|
|
}
|
|
|
|
return newSchemes;
|
|
|
|
});
|
2024-09-09 11:51:54 -04:00
|
|
|
};
|
|
|
|
|
2024-09-09 16:02:26 -04:00
|
|
|
const toggleHistory = () => {
|
|
|
|
setIsHistoryOpen(!isHistoryOpen);
|
|
|
|
};
|
|
|
|
|
2024-09-09 16:59:00 -04:00
|
|
|
const toggleSettings = () => {
|
|
|
|
setIsSettingsOpen(!isSettingsOpen);
|
|
|
|
};
|
|
|
|
|
2024-09-09 17:59:21 -04:00
|
|
|
const toggleHelp = () => {
|
|
|
|
setIsHelpOpen(!isHelpOpen);
|
|
|
|
};
|
|
|
|
|
2024-09-09 18:54:57 -04:00
|
|
|
const handleClearHistory = () => {
|
|
|
|
setLikedSchemes([]);
|
|
|
|
setDislikedSchemes([]);
|
|
|
|
localStorage.removeItem('likedSchemes');
|
|
|
|
localStorage.removeItem('dislikedSchemes');
|
|
|
|
};
|
|
|
|
|
2024-09-09 11:51:54 -04:00
|
|
|
return (
|
2024-09-09 16:59:00 -04:00
|
|
|
<div className="min-h-screen w-screen overflow-hidden font-[family-name:var(--font-geist-sans)] dark:bg-gray-900 dark:text-white transition-colors duration-300">
|
2024-09-09 17:59:21 -04:00
|
|
|
<header className="absolute top-2 left-2 right-2 flex justify-between items-start z-20">
|
|
|
|
<div className="flex items-center">
|
|
|
|
<Image src="/app-icon.svg" alt="App Icon" width={32} height={32} className="mr-2" />
|
|
|
|
<div>
|
|
|
|
<h1 className="text-lg font-bold">TerminalTinder</h1>
|
|
|
|
<p className="text-xs">Fall in love with your next color scheme</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="flex space-x-2">
|
|
|
|
<button onClick={toggleHistory}>
|
|
|
|
<Image src={isDarkMode ? "/history-icon-dark.svg" : "/history-icon-light.svg"} alt="History" width={24} height={24} />
|
|
|
|
</button>
|
|
|
|
<button onClick={toggleSettings}>
|
|
|
|
<Image src={isDarkMode ? "/settings-icon-dark.svg" : "/settings-icon-light.svg"} alt="Settings" width={24} height={24} />
|
|
|
|
</button>
|
|
|
|
<button onClick={toggleHelp}>
|
|
|
|
<Image src={isDarkMode ? "/help-icon-dark.svg" : "/help-icon-light.svg"} alt="Help" width={24} height={24} />
|
|
|
|
</button>
|
|
|
|
</div>
|
2024-09-09 11:51:54 -04:00
|
|
|
</header>
|
2024-09-09 17:59:21 -04:00
|
|
|
<main className="flex flex-col items-center justify-center h-screen pt-16 sm:pt-20">
|
2024-09-09 13:31:32 -04:00
|
|
|
<AnimatePresence>
|
|
|
|
{schemes.slice(0, 3).map((scheme, index) => (
|
2024-09-09 11:51:54 -04:00
|
|
|
<ColorSchemeCard
|
2024-09-09 13:31:32 -04:00
|
|
|
key={`${scheme.name}-${index}`}
|
2024-09-09 11:51:54 -04:00
|
|
|
scheme={scheme}
|
2024-09-09 13:31:32 -04:00
|
|
|
onLike={() => handleLike(scheme)}
|
|
|
|
onDislike={() => handleDislike(scheme)}
|
|
|
|
index={index}
|
2024-09-09 15:31:19 -04:00
|
|
|
isDarkMode={isDarkMode}
|
2024-09-09 16:59:00 -04:00
|
|
|
codeSample={codeSample}
|
|
|
|
outputFormat={outputFormat}
|
2024-09-09 09:50:12 -04:00
|
|
|
/>
|
2024-09-09 11:51:54 -04:00
|
|
|
))}
|
2024-09-09 13:31:32 -04:00
|
|
|
</AnimatePresence>
|
2024-09-09 09:50:12 -04:00
|
|
|
</main>
|
2024-09-09 16:02:26 -04:00
|
|
|
{isHistoryOpen && (
|
|
|
|
<HistoryPopup
|
|
|
|
likedSchemes={likedSchemes}
|
|
|
|
dislikedSchemes={dislikedSchemes}
|
|
|
|
onClose={toggleHistory}
|
2024-09-09 18:54:57 -04:00
|
|
|
onClearHistory={handleClearHistory} // Add this line
|
2024-09-09 16:02:26 -04:00
|
|
|
isDarkMode={isDarkMode}
|
2024-09-09 16:59:00 -04:00
|
|
|
outputFormat={outputFormat}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{isSettingsOpen && (
|
|
|
|
<Settings
|
|
|
|
isOpen={isSettingsOpen}
|
|
|
|
onClose={toggleSettings}
|
|
|
|
isDarkMode={isDarkMode}
|
|
|
|
onToggleDarkMode={() => setIsDarkMode(!isDarkMode)}
|
|
|
|
outputFormat={outputFormat}
|
|
|
|
setOutputFormat={setOutputFormat}
|
|
|
|
codeSample={codeSample}
|
2024-09-09 18:08:56 -04:00
|
|
|
setCodeSample={(sample: CodeSample) => setCodeSample(sample)}
|
2024-09-09 16:59:00 -04:00
|
|
|
saveSettings={saveSettings}
|
|
|
|
setSaveSettings={setSaveSettings}
|
2024-09-09 16:02:26 -04:00
|
|
|
/>
|
|
|
|
)}
|
2024-09-09 17:59:21 -04:00
|
|
|
{isHelpOpen && (
|
|
|
|
<HelpDialog
|
|
|
|
isOpen={isHelpOpen}
|
|
|
|
onClose={toggleHelp}
|
|
|
|
isDarkMode={isDarkMode}
|
|
|
|
/>
|
|
|
|
)}
|
2024-09-09 09:50:12 -04:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|