Mostly ready for release

This commit is contained in:
2024-09-09 15:31:19 -04:00
parent 5bbfa98ed3
commit 7851d2c0f6
11 changed files with 121 additions and 73 deletions

View File

@ -10,9 +10,10 @@ interface ColorSchemeCardProps {
onLike: () => void;
onDislike: () => void;
index: number;
isDarkMode: boolean;
}
const ColorSchemeCard: React.FC<ColorSchemeCardProps> = ({ scheme, onLike, onDislike, index }) => {
const ColorSchemeCard: React.FC<ColorSchemeCardProps> = ({ scheme, onLike, onDislike, index, isDarkMode }) => {
const [overlayColor, setOverlayColor] = useState('rgba(0, 0, 0, 0)');
const controls = useAnimation();
@ -97,7 +98,7 @@ fetchData().then(data => console.log(data)); `;
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 transition-colors duration-300"
onClick={handleDownload}
>
<Image src="/download-icon.svg" alt="Download" width={24} height={24} />
<Image src={isDarkMode ? "/download-icon-dark.svg" : "/download-icon-light.svg"} alt="Download" width={24} height={24} />
</button>
</div>
<div className="bg-gray-100 dark:bg-gray-700 rounded-md mb-4 flex-grow overflow-hidden z-10 shadow-md">
@ -144,13 +145,13 @@ fetchData().then(data => console.log(data)); `;
className="bg-red-500 text-white p-3 rounded-full shadow-lg hover:bg-red-600 transition-colors duration-300"
onClick={handleDislike}
>
<Image src="/cross-icon.svg" alt="Dislike" width={28} height={28} />
<Image src={isDarkMode ? "/cross-icon-dark.svg" : "/cross-icon-light.svg"} alt="Dislike" width={28} height={28} />
</button>
<button
className="bg-green-500 text-white p-3 rounded-full shadow-lg hover:bg-green-600 transition-colors duration-300"
onClick={handleLike}
>
<Image src="/heart-icon.svg" alt="Like" width={28} height={28} />
<Image src={isDarkMode ? "/heart-icon-dark.svg" : "/heart-icon-light.svg"} alt="Like" width={28} height={28} />
</button>
</div>
</div>

View File

@ -18,6 +18,7 @@ body {
color: var(--foreground);
background: var(--background);
font-family: var(--font-geist-sans), Arial, sans-serif;
overflow: hidden;
}
@layer utilities {

View File

@ -1,16 +1,14 @@
'use client';
import React, { useState, useEffect } from 'react';
import Image from 'next/image';
import ColorSchemeCard from "./components/ColorSchemeCard";
import SettingsIcon from "./components/SettingsIcon";
import Settings from "./components/Settings";
import { ColorScheme, knownSchemes, generateRandomScheme, generateSchemeFromGeneticAlgorithm } from './utils/colorSchemes';
import { AnimatePresence } from 'framer-motion';
export default function Home() {
const [schemes, setSchemes] = useState<ColorScheme[]>([]);
const [isDarkMode, setIsDarkMode] = useState(false);
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const [likedSchemes, setLikedSchemes] = useState<ColorScheme[]>([]);
const [dislikedSchemes, setDislikedSchemes] = useState<ColorScheme[]>([]);
@ -40,20 +38,28 @@ export default function Home() {
}, [dislikedSchemes]);
const generateNewSchemes = (count: number) => {
const knownCount = Math.floor(count / 2);
const generatedCount = count - knownCount;
const newSchemes = Array(count).fill(null).map(() => {
const schemeType = Math.random();
if (schemeType < 0.25) {
// 25% chance of known scheme
return knownSchemes[Math.floor(Math.random() * knownSchemes.length)];
} else if (schemeType < 0.5) {
// 25% chance of random scheme
return generateRandomScheme();
} else if (likedSchemes.length > 2 && dislikedSchemes.length > 2) {
// 50% chance of genetic scheme if there are more than 2 liked and disliked schemes
return generateSchemeFromGeneticAlgorithm(likedSchemes, dislikedSchemes);
} else {
// 30% known, 20% random for other cases
if (Math.random() < 0.3) {
return generateRandomScheme();
} else {
return knownSchemes[Math.floor(Math.random() * knownSchemes.length)];
}
}
});
const newSchemes = [
...knownSchemes.sort(() => 0.5 - Math.random()).slice(0, knownCount),
...Array(generatedCount).fill(null).map(() =>
likedSchemes.length > 0 ? generateSchemeFromGeneticAlgorithm(likedSchemes, dislikedSchemes) : generateRandomScheme()
)
];
// Shuffle the new schemes
const shuffledSchemes = newSchemes.sort(() => 0.5 - Math.random());
setSchemes(prevSchemes => [...prevSchemes, ...shuffledSchemes]);
setSchemes(prevSchemes => [...prevSchemes, ...newSchemes]);
};
const handleLike = (scheme: ColorScheme) => {
@ -81,12 +87,11 @@ export default function Home() {
};
return (
<div className="min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)] dark:bg-gray-900 dark:text-white transition-colors duration-300">
<header className="flex justify-between items-center mb-8">
<h1 className="text-2xl font-bold">Terminal Color Scheme Generator</h1>
<SettingsIcon onClick={() => setIsSettingsOpen(true)} />
<div className="h-screen w-screen overflow-hidden p-8 font-[family-name:var(--font-geist-sans)] dark:bg-gray-900 dark:text-white transition-colors duration-300">
<header className="flex items-center mb-8">
<Image src="/app-icon.svg" alt="App Icon" width={40} height={40} />
</header>
<main className="flex flex-col items-center justify-center h-[calc(100vh-200px)] relative">
<main className="flex flex-col items-center justify-center h-[calc(100vh-100px)]">
<AnimatePresence>
{schemes.slice(0, 3).map((scheme, index) => (
<ColorSchemeCard
@ -95,16 +100,11 @@ export default function Home() {
onLike={() => handleLike(scheme)}
onDislike={() => handleDislike(scheme)}
index={index}
isDarkMode={isDarkMode}
/>
))}
</AnimatePresence>
</main>
<Settings
isDarkMode={isDarkMode}
onToggleDarkMode={toggleDarkMode}
isOpen={isSettingsOpen}
onClose={() => setIsSettingsOpen(false)}
/>
</div>
);
}

View File

@ -30,7 +30,7 @@ function generateCreativeName(): string {
function generateRandomScheme(): ColorScheme {
let x = {
name: generateCreativeName(),
name: generateCreativeName() + "rand",
colors: {
primary: { background: generateRandomColor(), foreground: generateRandomColor() },
normal: {
@ -58,45 +58,6 @@ function crossTitles(title1: string, title2: string): string {
return `${firstWord} ${secondWord}`;
}
function crossSchemes(scheme1: ColorScheme, scheme2: ColorScheme): ColorScheme {
const crossColor = (color1: Color, color2: Color): Color => {
const r = Math.round((parseInt(color1.slice(1, 3), 16) + parseInt(color2.slice(1, 3), 16)) / 2);
const g = Math.round((parseInt(color1.slice(3, 5), 16) + parseInt(color2.slice(3, 5), 16)) / 2);
const b = Math.round((parseInt(color1.slice(5, 7), 16) + parseInt(color2.slice(5, 7), 16)) / 2);
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
};
return {
name: crossTitles(scheme1.name, scheme2.name),
colors: {
primary: {
background: crossColor(scheme1.colors.primary.background, scheme2.colors.primary.background),
foreground: crossColor(scheme1.colors.primary.foreground, scheme2.colors.primary.foreground)
},
normal: {
black: crossColor(scheme1.colors.normal.black, scheme2.colors.normal.black),
red: crossColor(scheme1.colors.normal.red, scheme2.colors.normal.red),
green: crossColor(scheme1.colors.normal.green, scheme2.colors.normal.green),
yellow: crossColor(scheme1.colors.normal.yellow, scheme2.colors.normal.yellow),
blue: crossColor(scheme1.colors.normal.blue, scheme2.colors.normal.blue),
magenta: crossColor(scheme1.colors.normal.magenta, scheme2.colors.normal.magenta),
cyan: crossColor(scheme1.colors.normal.cyan, scheme2.colors.normal.cyan),
white: crossColor(scheme1.colors.normal.white, scheme2.colors.normal.white)
},
bright: {
black: crossColor(scheme1.colors.bright.black, scheme2.colors.bright.black),
red: crossColor(scheme1.colors.bright.red, scheme2.colors.bright.red),
green: crossColor(scheme1.colors.bright.green, scheme2.colors.bright.green),
yellow: crossColor(scheme1.colors.bright.yellow, scheme2.colors.bright.yellow),
blue: crossColor(scheme1.colors.bright.blue, scheme2.colors.bright.blue),
magenta: crossColor(scheme1.colors.bright.magenta, scheme2.colors.bright.magenta),
cyan: crossColor(scheme1.colors.bright.cyan, scheme2.colors.bright.cyan),
white: crossColor(scheme1.colors.bright.white, scheme2.colors.bright.white)
}
}
};
}
function mutateColor(color: Color): Color {
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
@ -142,9 +103,9 @@ function generateSchemeFromGeneticAlgorithm(likedSchemes: ColorScheme[], dislike
});
});
newScheme.name = generateCreativeName();
newScheme.name = generateCreativeName() + "gen";
return newScheme;
}
export type { ColorScheme };
export { knownSchemes, generateRandomScheme, crossSchemes, generateSchemeFromGeneticAlgorithm };
export { knownSchemes, generateRandomScheme, generateSchemeFromGeneticAlgorithm };