Skip to content

Commit 8d777d9

Browse files
committed
Failure update
1 parent b81782c commit 8d777d9

1 file changed

Lines changed: 82 additions & 50 deletions

File tree

app/page.js

Lines changed: 82 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import React, { useEffect, useMemo, useRef, useState } from 'react';
3+
import React, { useEffect, useMemo, useRef, useState } from 'react'; from 'react';
44

55
const STORAGE_KEYS = {
66
history: 'ptc_history_v1',
@@ -260,6 +260,7 @@ function commandSuggestions(query) {
260260
function App() {
261261
const [prefs, setPrefs] = useState(DEFAULT_PREFS);
262262
const [input, setInput] = useState('');
263+
const [selectedSuggestion, setSelectedSuggestion] = uconst [isPaletteOpen, setIsPaletteOpen] = useState(false); useState(false);
263264
const [result, setResult] = useState(null);
264265
const [history, setHistory] = useState([]);
265266
const [pinned, setPinned] = useState([]);
@@ -400,14 +401,10 @@ function App() {
400401
}
401402
}
402403

403-
function runSuggestion(text) {
404-
setInput(text);
404+
function runSuggessetInput(text);
405405
inputRef.current?.focus();
406-
executeCommand(text);
407-
}
408-
409-
function runSpeedTest() {
410-
const testUrl = 'https://speed.hetzner.de/10MB.bin';
406+
setIsPaletteOpen(false);
407+
executeCommand(text);https://speed.hetzner.de/10MB.bin';
411408
const started = performance.now();
412409
setSpeedState({ running: true, dl: null, ul: null, ping: null, message: 'Downloading a test payload…' });
413410
fetch(testUrl, { cache: 'no-store' })
@@ -447,35 +444,38 @@ function App() {
447444

448445
const suggestions = useMemo(() => commandSuggestions(input), [input]);
449446

447+
useEffect(() => {
448+
setSelectedSuggestion(0);
449+
}, [input]);
450+
450451
useEffect(() => {
451452
const onKeyDown = (e) => {
452453
if (e.key === '/' && document.activeElement !== inputRef.current) {
453454
e.preventDefault();
454455
inputRef.current?.focus();
455456
}
456-
if (e.key === 'Enter' && document.activeElement === inputRef.current) {
457-
e.preventDefault();
458-
if (normalize(input) === 'speed test' || normalize(input) === 'speed') runSpeedTest();
459-
else executeCommand(input);
457+
if (document.activeElement === inputRef.current) {
458+
if (e.key === 'ArrowDown') {
459+
e.pprev) => Math.min(prev + 1, Math.max(suggestions.length - 1, 0)));
460+
}
461+
462+
if (e.key === 'ArrowUp') {
463+
e.preventDefault();
464+
setSelectedSuggestion((prev) => Math.max(prev - 1, 0));
465+
}
466+
467+
if (e.key === 'Tab') {
468+
e.preventDefault();
469+
if (suggestions[selectedSuggestion]) {
470+
setInput(suggestions[selectedSuggestid test' || normalize(finalCommand) === 'speed') runSpeedTest();
471+
else executeCommand(finalCommand);
472+
}
460473
}
461474
};
462475
window.addEventListener('keydown', onKeyDown);
463-
return () => window.removeEventListener('keydown', onKeyDown);
464-
}, [input, prefs]);
465-
466-
const commandExamples = [
467-
'100 usd to myr',
468-
'10 km to mi',
469-
'16 * 24 + 10',
470-
'gen password 16 strong',
471-
'qr https://example.com',
472-
'speed test',
473-
];
474-
475-
return (
476-
<div className="min-h-screen bg-slate-950 text-slate-100">
476+
return () => window.removeEventListh-screen bg-slate-950 text-slate-100">
477477
<div className="mx-auto max-w-7xl px-4 py-6 lg:px-8">
478-
<header className="mb-6 flex flex-col gap-3 rounded-3xl border border-slate-800 bg-slate-900/70 p-5 shadow-2xl shadow-black/20 backdrop-blur">
478+
<header className="sticky top-4 z-20 mb-6 flex flex-col gap-3 rounded-3xl border border-slate-800 bg-slate-900/90 p-5 shadow-2xl shadow-black/30 backdrop-blur-xl">
479479
<div className="flex flex-wrap items-center justify-between gap-3">
480480
<div>
481481
<h1 className="text-2xl font-semibold tracking-tight">Personal Tool Console</h1>
@@ -488,31 +488,68 @@ function App() {
488488
</div>
489489

490490
<div className="grid gap-3 lg:grid-cols-[1fr_auto]">
491-
<div className="relative">
491+
<div className="relative group">
492492
<input
493493
ref={inputRef}
494494
value={input}
495-
onChange={(e) => setInput(e.target.value)}
495+
onChange={(e) => {
496+
setInput(e.target.value);
497+
setIsPaletteOpen(true);
498+
}}
496499
onKeyDown={(e) => {
500+
501+
}}
502+
placeholder="Search or run a command… 100 usd to myr, password 20, qr https://..., 16*24+10"
503+
className="w-full rounded-2xl border border-slate-700 bg-black/70 px-5 py-5 pr-28 text-lg outline-none ring-0 transition placeholder:text-slate-500 focus:border-slate-400 focus:bg-black"
504+
/>
505+
<onChange={(e) => {
506+
setInput(e.target.value);
507+
setIsPaletteOpen(true);
508+
}}e inset-y-0 right-3 flex items-center gap-2 text-xs texif (e.key === 'Escape') {
509+
e.preventDefault();
510+
setIsPaletteOpen(false);
511+
return;
512+
}
513+
497514
if (e.key === 'Enter') {
498515
e.preventDefault();
499516
if (normalize(input) === 'speed test' || normalize(input) === 'speed') runSpeedTest();
500517
else executeCommand(input);
501-
}
502-
}}
503-
placeholder="Type a command: 100 usd to myr, gen password 16 strong, qr https://..., 16*24+10"
504-
className="w-full rounded-2xl border border-slate-700 bg-slate-950/80 px-4 py-4 pr-24 text-base outline-none ring-0 placeholder:text-slate-500 focus:border-slate-500"
505-
/>
506-
<div className="pointer-events-none absolute inset-y-0 right-3 flex items-center gap-2 text-xs text-slate-500">
507-
<span className="rounded-lg border border-slate-800 px-2 py-1">Cmd</span>
508-
</div>
518+
setIsPaletteOpen(false);
519+
}-0 top-[calc(100%+12px)] z-30 overflow-hidden rounded-2xl border border-slate-800 bg-slate-950/95 shadow-2xl shadow-black/50 backdrop-blur-xl">
520+
<div className="border-b border-slate-800 px-4 py-2 text-xs uppercase tracking-[0.2em] text-slate-500">
521+
Command palette
522+
</div>
523+
524+
<div className="max-h-80 overflow-auto p-2">
525+
{suggestions.map((s, idx) => (
526+
<button
527+
key={s}
528+
onClick={() => runSuggestion(s)}
529+
className={`flex isPaletteOpens-center justify-between rounded-xl px-4 py-3 text-left transition ${idx === selectedSuggestion ? 'bg-slate-800 text-white' : 'text-slate-300 hover:bg-slate-900'}`}
530+
>
531+
<div className="flex flex-col">
532+
<span className="font-mono text-sm">{s}</span>
533+
<span className="mt-1 text-xs text-slate-500">
534+
{s.includes('to') ? 'Conversion command' : s.includes('password') ? 'Password generation' : s.includes('qr') ? 'QR generation' : s.includes('speed') ? 'Network test' : 'Calculator'}
535+
</span>
536+
</div>
537+
538+
<div className="rounded-lg border border-slate-700 px-2 py-1 text-[10px] text-slate-500">
539+
540+
</div>
541+
</button>
542+
))}
543+
</div>
544+
</div>
545+
)}
509546
</div>
510547
<div className="flex gap-2">
511548
<button
512549
onClick={() => (normalize(input) === 'speed test' || normalize(input) === 'speed' ? runSpeedTest() : executeCommand(input))}
513550
className="rounded-2xl bg-slate-100 px-4 py-3 font-medium text-slate-950 transition hover:bg-white"
514551
>
515-
Run
552+
Execute
516553
</button>
517554
<button
518555
onClick={() => setInput('')}
@@ -523,16 +560,11 @@ function App() {
523560
</div>
524561
</div>
525562

526-
<div className="flex flex-wrap gap-2">
527-
{suggestions.map((s) => (
528-
<button
529-
key={s}
530-
onClick={() => runSuggestion(s)}
531-
className="rounded-full border border-slate-700 bg-slate-950/80 px-3 py-1.5 text-sm text-slate-300 transition hover:border-slate-500 hover:bg-slate-800"
532-
>
533-
{s}
534-
</button>
535-
))}
563+
<div className="flex flex-wrap items-center gap-2 pt-2 text-xs text-slate-500">
564+
<span className="rounded-full border border-slate-800 px-3 py-1">↑↓ navigate</span>
565+
<span className="rounded-full border border-slate-800 px-3 py-1">Tab autocomplete</span>
566+
<span className="rounded-full border border-slate-800 px-3 py-1">Enter execute</span>
567+
<span className="rounded-full border border-slate-800 px-3 py-1">/ focus</span>
536568
</div>
537569
</header>
538570

@@ -556,7 +588,7 @@ function App() {
556588

557589
{!result && (
558590
<div className="rounded-2xl border border-dashed border-slate-700 bg-slate-950/50 p-6 text-sm text-slate-400">
559-
Run a command to see a structured result here.
591+
Execute a command to see a structured result here.
560592
</div>
561593
)}
562594

@@ -635,7 +667,7 @@ function App() {
635667
onClick={runSpeedTest}
636668
className="rounded-2xl bg-slate-100 px-4 py-3 font-medium text-slate-950 transition hover:bg-white"
637669
>
638-
Run download test
670+
Execute download test
639671
</button>
640672
</div>
641673
)}

0 commit comments

Comments
 (0)