refactor: use CodeSnippet in color ExportMenu, drop inline copy button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 14:13:41 +01:00
parent 11d4207f72
commit c545211cf7

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { Download, Copy, Check, Loader2 } from 'lucide-react'; import { Download, Loader2 } from 'lucide-react';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { import {
exportAsCSS, exportAsCSS,
@@ -13,6 +13,7 @@ import {
type ExportColor, type ExportColor,
} from '@/lib/color/utils/export'; } from '@/lib/color/utils/export';
import { colorAPI } from '@/lib/color/api/client'; import { colorAPI } from '@/lib/color/api/client';
import { CodeSnippet } from '@/components/ui/code-snippet';
import { cn } from '@/lib/utils/cn'; import { cn } from '@/lib/utils/cn';
interface ExportMenuProps { interface ExportMenuProps {
@@ -34,7 +35,6 @@ export function ExportMenu({ colors, className }: ExportMenuProps) {
const [colorSpace, setColorSpace] = useState<ColorSpace>('hex'); const [colorSpace, setColorSpace] = useState<ColorSpace>('hex');
const [convertedColors, setConvertedColors] = useState<string[]>(colors); const [convertedColors, setConvertedColors] = useState<string[]>(colors);
const [isConverting, setIsConverting] = useState(false); const [isConverting, setIsConverting] = useState(false);
const [copied, setCopied] = useState(false);
useEffect(() => { useEffect(() => {
async function convertColors() { async function convertColors() {
@@ -68,13 +68,6 @@ export function ExportMenu({ colors, className }: ExportMenuProps) {
const getExt = () => ({ css: 'css', scss: 'scss', tailwind: 'js', json: 'json', javascript: 'js' }[format]); const getExt = () => ({ css: 'css', scss: 'scss', tailwind: 'js', json: 'json', javascript: 'js' }[format]);
const handleCopy = () => {
navigator.clipboard.writeText(getContent());
setCopied(true);
toast.success('Copied!');
setTimeout(() => setCopied(false), 2000);
};
const handleDownload = () => { const handleDownload = () => {
downloadAsFile(getContent(), `palette.${getExt()}`, 'text/plain'); downloadAsFile(getContent(), `palette.${getExt()}`, 'text/plain');
toast.success('Downloaded!'); toast.success('Downloaded!');
@@ -111,31 +104,20 @@ export function ExportMenu({ colors, className }: ExportMenuProps) {
</div> </div>
{/* Code preview */} {/* Code preview */}
<div <div className="relative">
className="relative rounded-xl overflow-hidden border border-white/5 min-h-[80px]"
style={{ background: '#06060e' }}
>
{isConverting && ( {isConverting && (
<div className="absolute inset-0 flex items-center justify-center z-10 bg-black/30"> <div className="absolute inset-0 flex items-center justify-center z-20 rounded-xl bg-black/40">
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" /> <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
</div> </div>
)} )}
<pre className="p-3 text-[10px] font-mono text-white/60 overflow-x-auto leading-relaxed"> <CodeSnippet code={getContent()} />
<code>{getContent()}</code>
</pre>
</div> </div>
{/* Actions */} {/* Actions */}
<div className="flex gap-2"> <button onClick={handleDownload} disabled={isConverting} className={cn(actionBtn, 'w-full justify-center')}>
<button onClick={handleCopy} disabled={isConverting} className={cn(actionBtn, 'flex-1 justify-center')}> <Download className="w-3 h-3" />
{copied ? <Check className="w-3 h-3" /> : <Copy className="w-3 h-3" />} Download
{copied ? 'Copied' : 'Copy'} </button>
</button>
<button onClick={handleDownload} disabled={isConverting} className={cn(actionBtn, 'flex-1 justify-center')}>
<Download className="w-3 h-3" />
Download
</button>
</div>
</div> </div>
); );
} }