Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Failing after 1m31s
Build & Deploy / 🏗️ Build (push) Failing after 3m51s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
82 lines
2.4 KiB
TypeScript
82 lines
2.4 KiB
TypeScript
"use client";
|
|
|
|
import * as React from "react";
|
|
import { useState, useRef } from "react";
|
|
|
|
interface SearchBarProps {
|
|
value?: string;
|
|
onChange?: (value: string) => void;
|
|
size?: "small" | "large";
|
|
}
|
|
|
|
export const SearchBar: React.FC<SearchBarProps> = ({
|
|
value: propValue,
|
|
onChange,
|
|
size = "small",
|
|
}) => {
|
|
const [internalValue, setInternalValue] = useState("");
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
const [isFocused, setIsFocused] = useState(false);
|
|
|
|
const value = propValue !== undefined ? propValue : internalValue;
|
|
|
|
const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const newValue = e.target.value;
|
|
if (onChange) {
|
|
onChange(newValue);
|
|
} else {
|
|
setInternalValue(newValue);
|
|
}
|
|
};
|
|
|
|
const clearSearch = () => {
|
|
if (onChange) {
|
|
onChange("");
|
|
} else {
|
|
setInternalValue("");
|
|
}
|
|
if (inputRef.current) {
|
|
inputRef.current.focus();
|
|
}
|
|
};
|
|
|
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
if (e.key === "Escape") {
|
|
clearSearch();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="relative w-full max-w-full">
|
|
<div className="relative flex items-center w-full">
|
|
<input
|
|
ref={inputRef}
|
|
type="text"
|
|
placeholder="Suchen..."
|
|
value={value}
|
|
className={`w-full max-w-full px-8 py-4 font-bold text-slate-900 bg-white rounded-2xl border transition-all focus:outline-none placeholder:text-slate-300 ${size === "large"
|
|
? "text-2xl md:text-4xl py-6 rounded-3xl"
|
|
: "text-lg"
|
|
} ${isFocused ? "border-slate-400" : "border-slate-200"}`}
|
|
onChange={handleInput}
|
|
onKeyDown={handleKeyDown}
|
|
onFocus={() => setIsFocused(true)}
|
|
onBlur={() => setIsFocused(false)}
|
|
aria-label="Search blog posts"
|
|
/>
|
|
|
|
{value && (
|
|
<button
|
|
onClick={clearSearch}
|
|
className="absolute right-4 top-1/2 -translate-y-1/2 px-3 py-1 border border-slate-200 rounded-full text-[10px] font-bold uppercase tracking-widest text-slate-400 hover:text-slate-900 hover:border-slate-400 hover:bg-slate-50 transition-all duration-500 ease-[cubic-bezier(0.23,1,0.32,1)] hover:-translate-y-[calc(50%+2px)] hover:shadow-lg hover:shadow-slate-100"
|
|
aria-label="Clear search"
|
|
type="button"
|
|
>
|
|
Löschen
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|