MVP complete

This commit is contained in:
2024-09-09 16:59:00 -04:00
parent e21173c8e4
commit 7c7b152d79
13 changed files with 1314 additions and 705 deletions

View File

@ -7,7 +7,7 @@ interface ColorPaletteProps {
const ColorPalette: React.FC<ColorPaletteProps> = ({ colors, size = 'small' }) => {
const [copiedColor, setCopiedColor] = useState<string | null>(null);
const [hoveredColor, setHoveredColor] = useState<string | null>(null);
const [hoveredColorId, setHoveredColorId] = useState<string | null>(null);
const textAreaRef = useRef<HTMLTextAreaElement>(null);
const handleColorClick = (color: string) => {
@ -39,33 +39,36 @@ const ColorPalette: React.FC<ColorPaletteProps> = ({ colors, size = 'small' }) =
return (
<>
<div className={`grid grid-cols-8 gap-2 ${size === 'large' ? 'mb-4' : 'mb-2'} z-10`}>
{colors.map((color, index) => (
<div
key={index}
className={`${sizeClasses} rounded-sm cursor-pointer relative group`}
style={{backgroundColor: color}}
onClick={() => handleColorClick(color)}
onMouseEnter={() => setHoveredColor(color)}
onMouseLeave={() => setHoveredColor(null)}
>
{size === 'small' && hoveredColor === color && (
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-2 py-1 bg-white dark:bg-gray-800 rounded shadow-lg z-10">
<div className="w-4 h-4 rounded-sm mb-1" style={{backgroundColor: color}}></div>
<span className="text-xs">{color}</span>
</div>
)}
{size === 'large' && (
<div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300 bg-black bg-opacity-50 text-white text-[8px]">
{color}
</div>
)}
{copiedColor === color && (
<div className="absolute inset-0 flex items-center justify-center bg-black bg-opacity-70 text-white text-xs">
Copied!
</div>
)}
</div>
))}
{colors.map((color, index) => {
const colorId = `color-${index}-${color}`;
return (
<div
key={colorId}
className={`${sizeClasses} rounded-sm cursor-pointer relative group`}
style={{backgroundColor: color}}
onClick={() => handleColorClick(color)}
onMouseEnter={() => setHoveredColorId(colorId)}
onMouseLeave={() => setHoveredColorId(null)}
>
{size === 'small' && hoveredColorId === colorId && (
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-2 py-1 bg-white dark:bg-gray-800 rounded shadow-lg z-10">
<div className="w-4 h-4 rounded-sm mb-1" style={{backgroundColor: color}}></div>
<span className="text-xs">{color}</span>
</div>
)}
{size === 'large' && (
<div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300 bg-black bg-opacity-50 text-white text-[8px]">
{color}
</div>
)}
{copiedColor === color && (
<div className="absolute inset-0 flex items-center justify-center bg-black bg-opacity-70 text-white text-xs">
Copied!
</div>
)}
</div>
);
})}
</div>
<textarea
ref={textAreaRef}

View File

@ -1,7 +1,7 @@
import React, { useState } from 'react';
import Image from 'next/image';
import { ColorScheme } from '../utils/colorSchemes';
import { generateYAML } from '../utils/yamlExport';
import { generateYAML, generateJSON, generateXResources, generateTOML } from '../utils/exportFormats';
import { Highlight, themes } from 'prism-react-renderer';
import { motion, useAnimation } from 'framer-motion';
import ColorPalette from './ColorPalette';
@ -12,49 +12,238 @@ interface ColorSchemeCardProps {
onDislike: () => void;
index: number;
isDarkMode: boolean;
codeSample: string;
outputFormat: string;
}
const ColorSchemeCard: React.FC<ColorSchemeCardProps> = ({ scheme, onLike, onDislike, index, isDarkMode }) => {
const ColorSchemeCard: React.FC<ColorSchemeCardProps> = ({ scheme, onLike, onDislike, index, isDarkMode, codeSample, outputFormat }) => {
const [overlayColor, setOverlayColor] = useState('rgba(0, 0, 0, 0)');
const controls = useAnimation();
const codeExample = `
// User object and function
const user = {
name: 'DWS',
power: 8999
};
const getCodeExample = () => {
// Add code samples for each language here
const samples = {
c: `#include <stdio.h>
class Shape {
constructor(color) {
this.color = color;
int is_prime(int n) {
if (n <= 1) return 0;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return 0;
}
return 1;
}
// Async data fetch simulation
async function fetchData() {
return await new Promise(resolve => setTimeout(() => resolve('Data loaded'), 500));
void print_primes(int limit) {
printf("Primes up to %d:\n", limit);
for (int i = 2; i <= limit; i++) {
if (is_prime(i)) {
printf("%d ", i);
}
}
printf("\n");
}
const [even, odd] = [2, 4, 6, 8].reduce(([e, o], n) => n % 2 ? [e, [...o, n]] : [
[...e, n], o
], [
[],
[]
]);
/*
Logging here
*/
fetchData().then(data => console.log(data)); `;
int main() {
int limit = 50;
print_primes(limit);
int num = 7;
printf("Is %d prime? %s\n", num, is_prime(num) ? "Yes" : "No");
return 0;
}`,
python: `import numpy as np
@timeit
def is_prime(n):
if n <= 1:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
def primes_up_to(limit):
"""
This function returns a list of prime numbers up to a given limit.
"""
primes = []
for i in range(2, limit + 1):
if is_prime(i):
primes.append(i)
return primes
def fibonacci(n):
fib_sequence = [0, 1] # Create a list with the first two numbers in the Fibonacci sequence
for i in range(2, n):
fib_sequence.append(fib_sequence[-1] + fib_sequence[-2])
return fib_sequence
limit = 50
print(f"Primes up to {limit}: {primes_up_to(limit)}")
print(f"Fibonacci sequence up to 10: {fibonacci(10)}")
`,
rust: `fn is_prime(n: u32) -> bool {
if n <= 1 {
return false;
}
for i in 2..=((n as f64).sqrt() as u32) {
if n % i == 0 {
return false;
}
}
true
}
fn primes_up_to(limit: u32) -> Vec<u32> {
let mut primes = Vec::new();
for i in 2..=limit {
if is_prime(i) {
primes.push(i);
}
}
primes
}
fn main() {
let limit = 50;
let primes = primes_up_to(limit);
println!("Primes up to {}: {:?}", limit, primes);
let num = 7;
println!("Is {} prime? {}", num, is_prime(num));
}`,
go: `package main
import (
"fmt"
"math"
)
func isPrime(n int) bool {
if n <= 1 {
return false
}
for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
if n%i == 0 {
return false
}
}
return true
}
func primesUpTo(limit int) []int {
primes := []int{}
for i := 2; i <= limit; i++ {
if isPrime(i) {
primes = append(primes, i)
}
}
return primes
}
func main() {
limit := 50
fmt.Printf("Primes up to %d: %v\n", limit, primesUpTo(limit))
num := 7
fmt.Printf("Is %d prime? %v\n", num, isPrime(num))
}`,
javascript: `function isPrime(n) {
if (n <= 1) return false;
for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) return false;
}
return true;
}
function primesUpTo(limit) {
let primes = [];
for (let i = 2; i <= limit; i++) {
if (isPrime(i)) primes.push(i);
}
return primes;
}
function fibonacci(n) {
let fib = [0, 1];
for (let i = 2; i < n; i++) {
fib.push(fib[i - 1] + fib[i - 2]);
}
return fib;
}
let limit = 50;`,
bash: `#!/bin/bash
is_prime() {
local n=$1
if [ $n -le 1 ]; then
echo 0
return
fi
for ((i=2; i*i<=n; i++)); do
if ((n % i == 0)); then
echo 0
return
fi
done
echo 1
}
primes_up_to() {
local limit=$1
for ((i=2; i<=limit; i++)); do
if [ $(is_prime $i) -eq 1 ]; then
echo -n "$i "
fi
done
echo
}
limit=50
echo "Primes up to $limit: $(primes_up_to $limit)"
num=7
if [ $(is_prime $num) -eq 1 ]; then
echo "$num is prime"
else
echo "$num is not prime"
fi`
};
return samples[codeSample] || samples.javascript;
};
const handleDownload = (e: React.MouseEvent) => {
e.stopPropagation();
const yaml = generateYAML(scheme);
const blob = new Blob([yaml], { type: 'text/yaml' });
let content: string;
let fileExtension: string;
switch (outputFormat) {
case 'json':
content = generateJSON(scheme);
fileExtension = 'json';
break;
case 'xresources':
content = generateXResources(scheme);
fileExtension = 'Xresources';
break;
case 'toml':
content = generateTOML(scheme);
fileExtension = 'toml';
break;
case 'yaml':
default:
content = generateYAML(scheme);
fileExtension = 'yaml';
}
const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${scheme.name.replace(/\s+/g, '_').toLowerCase()}.yaml`;
a.download = `${scheme.name.replace(/\s+/g, '_').toLowerCase()}.${fileExtension}`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
@ -71,55 +260,114 @@ fetchData().then(data => console.log(data)); `;
controls.start({ x: -300, opacity: 0, transition: { duration: 0.3 } }).then(onDislike);
};
const paletteColors = [
scheme.colors.normal.black,
scheme.colors.normal.red,
scheme.colors.normal.green,
scheme.colors.normal.yellow,
scheme.colors.normal.blue,
scheme.colors.normal.magenta,
scheme.colors.normal.cyan,
scheme.colors.normal.white,
scheme.colors.bright.black,
scheme.colors.bright.red,
scheme.colors.bright.green,
scheme.colors.bright.yellow,
scheme.colors.bright.blue,
scheme.colors.bright.magenta,
scheme.colors.bright.cyan,
scheme.colors.bright.white,
];
return (
<motion.div
className="absolute w-[350px] h-[600px] bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden"
className="absolute w-[80vw] max-w-[480px] h-[90vh] max-h-[600px] bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden"
initial={{ scale: 1 - index * 0.05, y: index * 15, opacity: 1 }}
animate={controls}
style={{
zIndex: 3 - index
}}
drag="x"
dragConstraints={{ left: -100, right: 100 }}
dragConstraints={{ left: -50, right: 50 }}
onDragEnd={(e, { offset, velocity }) => {
if (offset.x > 100) handleLike();
else if (offset.x < -100) handleDislike();
if (offset.x > 50) handleLike();
else if (offset.x < -50) handleDislike();
}}
>
<div className="p-6 h-full flex flex-col relative">
<div className="p-4 h-full flex flex-col relative">
<motion.div
className="absolute inset-0 rounded-lg"
animate={{ backgroundColor: overlayColor }}
initial={{ backgroundColor: 'rgba(0, 0, 0, 0)' }}
transition={{ duration: 0.2 }}
/>
<div className="flex justify-between items-center mb-4 z-10">
<h2 className="text-xl font-semibold">{scheme.name}</h2>
<div className="flex justify-between items-center mb-2 z-10">
<h2 className="text-lg font-semibold truncate">{scheme.name}</h2>
<button
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={isDarkMode ? "/download-icon-dark.svg" : "/download-icon-light.svg"} alt="Download" width={24} height={24} />
<Image src={isDarkMode ? "/download-icon-dark.svg" : "/download-icon-light.svg"} alt="Download" width={20} height={20} />
</button>
</div>
<div className="bg-gray-100 dark:bg-gray-700 rounded-md mb-4 flex-grow overflow-hidden z-10 shadow-md">
<Highlight theme={themes.dracula} code={codeExample} language="javascript">
<div className="bg-gray-100 dark:bg-gray-700 rounded-md mb-2 flex-grow overflow-hidden z-10 shadow-md">
<Highlight theme={themes.dracula} code={getCodeExample()} language={codeSample}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={`${className} text-xs p-4 overflow-x-auto`} style={{ ...style, backgroundColor: scheme.colors.primary.background }}>
{tokens.slice(0, 20).map((line, i) => (
<pre className={`${className} text-sm p-4 h-full overflow-auto`} style={{ ...style, backgroundColor: scheme.colors.primary.background }}>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({ line, key: i })}>
{line.map((token, key) => {
let color = scheme.colors.primary.foreground;
if (token.types.includes('keyword')) color = scheme.colors.normal.blue;
if (token.types.includes('string')) color = scheme.colors.normal.green;
if (token.types.includes('number')) color = scheme.colors.normal.magenta;
if (token.types.includes('comment')) color = scheme.colors.bright.black;
if (token.types.includes('function')) color = scheme.colors.normal.yellow;
if (token.types.includes('operator')) color = scheme.colors.normal.cyan;
if (token.types.includes('class-name')) color = scheme.colors.bright.magenta;
if (token.types.includes('constant')) color = scheme.colors.bright.red;
if (token.types.includes('punctuation')) color = scheme.colors.bright.cyan;
if (token.types.includes('variable')) color = scheme.colors.bright.yellow;
let color = scheme.colors.primary.foreground;
if (token.types.includes('keyword')) color = scheme.colors.normal.blue;
if (token.types.includes('string')) color = scheme.colors.normal.green;
if (token.types.includes('number')) color = scheme.colors.normal.magenta;
if (token.types.includes('comment')) color = scheme.colors.bright.black;
if (token.types.includes('function')) color = scheme.colors.normal.yellow;
if (token.types.includes('operator')) color = scheme.colors.normal.cyan;
if (token.types.includes('class-name')) color = scheme.colors.bright.magenta;
if (token.types.includes('constant')) color = scheme.colors.bright.red;
if (token.types.includes('punctuation')) color = scheme.colors.bright.cyan;
if (token.types.includes('variable')) color = scheme.colors.bright.yellow;
if (token.types.includes('boolean')) color = scheme.colors.bright.yellow;
if (token.types.includes('builtin')) color = scheme.colors.bright.magenta;
if (token.types.includes('attr-name')) color = scheme.colors.normal.red;
if (token.types.includes('attr-value')) color = scheme.colors.bright.green;
if (token.types.includes('tag')) color = scheme.colors.normal.blue;
if (token.types.includes('namespace')) color = scheme.colors.normal.magenta;
if (token.types.includes('selector')) color = scheme.colors.normal.yellow;
if (token.types.includes('property')) color = scheme.colors.normal.cyan;
if (token.types.includes('unit')) color = scheme.colors.bright.yellow;
if (token.types.includes('important')) color = scheme.colors.bright.red;
if (token.types.includes('symbol')) color = scheme.colors.normal.magenta; // Symbols (e.g., special characters)
if (token.types.includes('regex')) color = scheme.colors.bright.green; // Regular expressions
if (token.types.includes('template-string')) color = scheme.colors.normal.green; // Template literals
if (token.types.includes('char')) color = scheme.colors.bright.yellow; // Individual characters
if (token.types.includes('module')) color = scheme.colors.normal.cyan; // Modules
if (token.types.includes('directive')) color = scheme.colors.normal.magenta; // Directives (e.g., preprocessor)
if (token.types.includes('annotation')) color = scheme.colors.normal.green; // Annotations (e.g., decorators)
if (token.types.includes('parameter')) color = scheme.colors.bright.yellow; // Parameters in functions
if (token.types.includes('method')) color = scheme.colors.normal.yellow; // Methods
if (token.types.includes('field')) color = scheme.colors.bright.blue; // Fields within classes
if (token.types.includes('property-access')) color = scheme.colors.normal.cyan; // Property accessors (e.g., dot notation)
if (token.types.includes('escape')) color = scheme.colors.bright.red; // Escape sequences
if (token.types.includes('meta')) color = scheme.colors.bright.magenta; // Meta information (e.g., HTML meta tags)
if (token.types.includes('label')) color = scheme.colors.bright.yellow; // Labels (e.g., in loops)
if (token.types.includes('alias')) color = scheme.colors.normal.magenta; // Aliases (e.g., imports or type aliases)
if (token.types.includes('error')) color = scheme.colors.bright.red; // Error handling, error literals
if (token.types.includes('debug')) color = scheme.colors.bright.magenta; // Debugging statements (e.g., console logs)
if (token.types.includes('property-declaration')) color = scheme.colors.normal.blue; // Property declarations in classes
if (token.types.includes('module-declaration')) color = scheme.colors.normal.cyan; // Declarations of modules
if (token.types.includes('generic')) color = scheme.colors.bright.magenta; // Generics (e.g., <T>)
if (token.types.includes('type')) color = scheme.colors.bright.blue; // Types in TypeScript, Flow, etc.
if (token.types.includes('interface')) color = scheme.colors.normal.green; // Interfaces (e.g., TypeScript)
if (token.types.includes('enums')) color = scheme.colors.bright.cyan; // Enums in languages like TypeScript, Java
if (token.types.includes('modifier')) color = scheme.colors.normal.yellow; // Modifiers (e.g., public, static)
if (token.types.includes('event')) color = scheme.colors.bright.blue; // Events (e.g., DOM events or custom events)
if (token.types.includes('keyword-control')) color = scheme.colors.bright.yellow; // Control-flow keywords (e.g., if, for)
if (token.types.includes('loop')) color = scheme.colors.normal.magenta; // Loop keywords (e.g., for, while)
if (token.types.includes('storage')) color = scheme.colors.normal.red; // Storage-related keywords (e.g., var, let)
if (token.types.includes('annotation-function')) color = scheme.colors.bright.green; // Annotated functions
if (token.types.includes('doc-string')) color = scheme.colors.bright.blue; // Docstrings or comments that are part of documentation
return <span key={key} {...getTokenProps({ token, key })} style={{ ...getTokenProps({ token, key }).style, color }} />;
})}
</div>
@ -128,22 +376,24 @@ fetchData().then(data => console.log(data)); `;
)}
</Highlight>
</div>
<ColorPalette
colors={Object.values(scheme.colors.normal).concat(Object.values(scheme.colors.bright))}
size="large"
/>
<div className="flex justify-center space-x-8 mt-4 z-10">
<div className="mt-2 z-10">
<ColorPalette
colors={paletteColors}
size="small"
/>
</div>
<div className="flex justify-center space-x-4 mt-2 z-10">
<button
className="bg-red-500 text-white p-3 rounded-full shadow-lg hover:bg-red-600 transition-colors duration-300"
className="bg-red-500 text-white p-2 rounded-full shadow-lg hover:bg-red-600 transition-colors duration-300"
onClick={handleDislike}
>
<Image src={isDarkMode ? "/cross-icon-dark.svg" : "/cross-icon-light.svg"} alt="Dislike" width={28} height={28} />
<Image src={isDarkMode ? "/cross-icon-dark.svg" : "/cross-icon-light.svg"} alt="Dislike" width={24} height={24} />
</button>
<button
className="bg-green-500 text-white p-3 rounded-full shadow-lg hover:bg-green-600 transition-colors duration-300"
className="bg-green-500 text-white p-2 rounded-full shadow-lg hover:bg-green-600 transition-colors duration-300"
onClick={handleLike}
>
<Image src={isDarkMode ? "/heart-icon-dark.svg" : "/heart-icon-light.svg"} alt="Like" width={28} height={28} />
<Image src={isDarkMode ? "/heart-icon-dark.svg" : "/heart-icon-light.svg"} alt="Like" width={24} height={24} />
</button>
</div>
</div>

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { ColorScheme } from '../utils/colorSchemes';
import { generateYAML } from '../utils/yamlExport';
import { generateYAML, generateJSON, generateXResources, generateTOML } from '../utils/exportFormats';
import Image from 'next/image';
import ColorPalette from './ColorPalette';
@ -9,18 +9,40 @@ interface HistoryPopupProps {
dislikedSchemes: ColorScheme[];
onClose: () => void;
isDarkMode: boolean;
outputFormat: string;
}
const HistoryPopup: React.FC<HistoryPopupProps> = ({ likedSchemes, dislikedSchemes, onClose, isDarkMode }) => {
const HistoryPopup: React.FC<HistoryPopupProps> = ({ likedSchemes, dislikedSchemes, onClose, isDarkMode, outputFormat }) => {
const [copiedColor, setCopiedColor] = useState<string | null>(null);
const handleDownload = (scheme: ColorScheme) => {
const yaml = generateYAML(scheme);
const blob = new Blob([yaml], { type: 'text/yaml' });
let content: string;
let fileExtension: string;
switch (outputFormat) {
case 'json':
content = generateJSON(scheme);
fileExtension = 'json';
break;
case 'xresources':
content = generateXResources(scheme);
fileExtension = 'Xresources';
break;
case 'toml':
content = generateTOML(scheme);
fileExtension = 'toml';
break;
case 'yaml':
default:
content = generateYAML(scheme);
fileExtension = 'yaml';
}
const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${scheme.name.replace(/\s+/g, '_').toLowerCase()}.yaml`;
a.download = `${scheme.name.replace(/\s+/g, '_').toLowerCase()}.${fileExtension}`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);

View File

@ -1,41 +1,128 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import Image from 'next/image';
interface SettingsProps {
isDarkMode: boolean;
onToggleDarkMode: () => void;
isOpen: boolean;
onClose: () => void;
isDarkMode: boolean;
onToggleDarkMode: () => void;
outputFormat: string;
setOutputFormat: (format: string) => void;
codeSample: string;
setCodeSample: (sample: string) => void;
saveSettings: boolean;
setSaveSettings: (save: boolean) => void;
}
const Settings: React.FC<SettingsProps> = ({ isDarkMode, onToggleDarkMode, isOpen, onClose }) => {
const Settings: React.FC<SettingsProps> = ({
isOpen,
onClose,
isDarkMode,
onToggleDarkMode,
outputFormat,
setOutputFormat,
codeSample,
setCodeSample,
saveSettings,
setSaveSettings
}) => {
const [showCookieNotice, setShowCookieNotice] = useState(false);
useEffect(() => {
if (saveSettings && !localStorage.getItem('cookieNoticeShown')) {
setShowCookieNotice(true);
}
}, [saveSettings]);
const handleSaveSettingsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.checked;
setSaveSettings(newValue);
if (newValue && !localStorage.getItem('cookieNoticeShown')) {
setShowCookieNotice(true);
}
};
const handleCookieNoticeClose = () => {
setShowCookieNotice(false);
localStorage.setItem('cookieNoticeShown', 'true');
};
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-xl">
<h2 className="text-xl font-bold mb-4">Settings</h2>
<div className="flex items-center justify-between mb-4">
<span>Dark Mode</span>
<button
onClick={onToggleDarkMode}
className={`w-12 h-6 rounded-full p-1 transition-colors duration-300 ease-in-out ${
isDarkMode ? 'bg-blue-600' : 'bg-gray-300'
}`}
>
<div
className={`w-4 h-4 rounded-full bg-white transform transition-transform duration-300 ease-in-out ${
isDarkMode ? 'translate-x-6' : ''
}`}
/>
<div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-xl w-[90vw] max-w-md">
<div className="flex justify-between items-center mb-4">
<h2 className="text-2xl font-bold">Settings</h2>
<button onClick={onClose} className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
<Image src={isDarkMode ? "/close-icon-dark.svg" : "/close-icon-light.svg"} alt="Close" width={24} height={24} />
</button>
</div>
<button
onClick={onClose}
className="mt-4 bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded transition-colors duration-300"
>
Close
</button>
<div className="space-y-4">
<div className="flex items-center justify-between">
<span>Dark Mode</span>
<button
onClick={onToggleDarkMode}
className={`w-12 h-6 rounded-full p-1 transition-colors duration-300 ease-in-out ${
isDarkMode ? 'bg-blue-600' : 'bg-gray-300'
}`}
>
<div
className={`w-4 h-4 rounded-full bg-white transform transition-transform duration-300 ease-in-out ${
isDarkMode ? 'translate-x-6' : ''
}`}
/>
</button>
</div>
<div>
<label className="block mb-2">Output Format</label>
<select
value={outputFormat}
onChange={(e) => setOutputFormat(e.target.value)}
className="w-full p-2 border rounded dark:bg-gray-700 dark:border-gray-600"
>
<option value="json">JSON</option>
<option value="xresources">XResources</option>
<option value="yaml">YAML (Alacritty)</option>
<option value="toml">TOML (Alacritty)</option>
</select>
</div>
<div>
<label className="block mb-2">Code Sample</label>
<select
value={codeSample}
onChange={(e) => setCodeSample(e.target.value)}
className="w-full p-2 border rounded dark:bg-gray-700 dark:border-gray-600"
>
<option value="c">C</option>
<option value="python">Python</option>
<option value="rust">Rust</option>
<option value="go">Go</option>
<option value="javascript">JavaScript</option>
<option value="java">Java</option>
<option value="bash">Bash</option>
</select>
</div>
<div className="flex items-center">
<input
type="checkbox"
id="saveSettings"
checked={saveSettings}
onChange={handleSaveSettingsChange}
className="mr-2"
/>
<label htmlFor="saveSettings">Save settings in cookie</label>
</div>
</div>
</div>
{showCookieNotice && (
<div className="fixed bottom-0 left-0 right-0 bg-blue-500 text-white p-4">
<p>We will save your settings in a cookie. Is this okay?</p>
<button onClick={handleCookieNoticeClose} className="mt-2 bg-white text-blue-500 px-4 py-2 rounded">
Accept
</button>
</div>
)}
</div>
);
};