Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,15 @@
height: 52px;
}

.search-form input {
.search-input-wrapper {
position: relative;
flex: 1;
min-width: 0;
}

.search-form input {
width: 100%;
box-sizing: border-box;
padding: 13px 18px;
border: 2px solid var(--border);
border-radius: 999px;
Expand All @@ -55,6 +61,44 @@
box-shadow: 0 0 0 4px var(--accent-bg);
}

.recent-searches {
position: absolute;
top: calc(100% + 8px);
left: 0;
right: 0;
z-index: 10;
margin: 0;
padding: 6px;
list-style: none;
background: var(--bg);
border: 2px solid var(--border);
border-radius: 16px;
box-shadow: 0 12px 24px rgb(0 0 0 / 12%);
}

.recent-searches li + li {
margin-top: 2px;
}

.recent-searches button {
display: block;
width: 100%;
padding: 10px 14px;
border: 0;
border-radius: 10px;
background: transparent;
color: var(--text-h);
font: inherit;
text-align: left;
cursor: pointer;
}

.recent-searches button:hover,
.recent-searches button:focus-visible {
background: var(--accent-bg);
outline: none;
}

.search-form button {
padding: 0 26px;
border: 0;
Expand Down
79 changes: 69 additions & 10 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ import FavoritesSidebar from './FavoritesSidebar';
import './App.css';

const SEARCH_STORAGE_KEY = 'pokemon-search';
const RECENT_SEARCHES_STORAGE_KEY = 'pokemon-recent-searches';
const MAX_RECENT_SEARCHES = 5;

function loadRecentSearches(): string[] {
try {
const raw = sessionStorage.getItem(RECENT_SEARCHES_STORAGE_KEY);
const parsed = raw ? JSON.parse(raw) : [];
return Array.isArray(parsed) ? parsed : [];
} catch {
return [];
}
}

function capitalize(text: string): string {
return text.charAt(0).toUpperCase() + text.slice(1);
Expand All @@ -33,6 +45,8 @@ function App() {
);

const [error, setError] = useState('');
const [recentSearches, setRecentSearches] = useState(loadRecentSearches);
const [showSuggestions, setShowSuggestions] = useState(false);

const { favorites, isFavorite, toggleFavorite } = useFavorites();

Expand All @@ -44,9 +58,23 @@ function App() {
.slice(0, 24)
: [];

function handleSearch(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const trimmedQuery = query.trim();
function addToRecentSearches(trimmedQuery: string) {
const withoutDuplicate = recentSearches.filter(
(entry) => entry.toLowerCase() !== trimmedQuery.toLowerCase(),
);
const updated = [trimmedQuery, ...withoutDuplicate].slice(
0,
MAX_RECENT_SEARCHES,
);
setRecentSearches(updated);
sessionStorage.setItem(
RECENT_SEARCHES_STORAGE_KEY,
JSON.stringify(updated),
);
}

function runSearch(rawQuery: string) {
const trimmedQuery = rawQuery.trim();

if (!trimmedQuery) {
setSubmittedQuery('');
Expand All @@ -57,6 +85,18 @@ function App() {
sessionStorage.setItem(SEARCH_STORAGE_KEY, trimmedQuery);
setSubmittedQuery(trimmedQuery);
setError('');
addToRecentSearches(trimmedQuery);
}

function handleSearch(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
runSearch(query);
}

function handleSelectRecentSearch(recentQuery: string) {
setQuery(recentQuery);
setShowSuggestions(false);
runSearch(recentQuery);
}

return (
Expand All @@ -70,13 +110,32 @@ function App() {
«pikachu».
</p>
<form className="search-form" onSubmit={handleSearch}>
<input
type="search"
value={query}
onChange={(event) => setQuery(event.target.value)}
placeholder="For eksempel: bulba"
aria-label="Søk etter Pokémon"
/>
<div className="search-input-wrapper">
<input
type="search"
value={query}
onChange={(event) => setQuery(event.target.value)}
onFocus={() => setShowSuggestions(true)}
onBlur={() => setShowSuggestions(false)}
placeholder="For eksempel: bulba"
aria-label="Søk etter Pokémon"
/>
{showSuggestions && recentSearches.length > 0 && (
<ul className="recent-searches">
{recentSearches.map((recentQuery) => (
<li key={recentQuery}>
<button
type="button"
onMouseDown={(event) => event.preventDefault()}
onClick={() => handleSelectRecentSearch(recentQuery)}
>
{recentQuery}
</button>
</li>
))}
</ul>
)}
</div>
<button type="submit" disabled={isPending}>
{isPending ? 'Laster Pokémon...' : 'Søk'}
</button>
Expand Down