(null);
useEffect(() => {
let cancelled = false;
@@ -71,6 +73,7 @@ export default function BlogApp() {
›
setQuery(e.target.value)}
placeholder="Filter by title, tag, or summary"
@@ -78,6 +81,19 @@ export default function BlogApp() {
aria-label="Filter posts"
maxLength={100} // Security: prevent DoS via extremely long input strings
/>
+ {query && (
+
+ )}
diff --git a/src/components/os/apps/ProjectsApp.tsx b/src/components/os/apps/ProjectsApp.tsx
index 4ad173b..a64191b 100644
--- a/src/components/os/apps/ProjectsApp.tsx
+++ b/src/components/os/apps/ProjectsApp.tsx
@@ -1,9 +1,11 @@
-import { useMemo, useState } from 'react';
+import { useMemo, useState, useRef } from 'react';
+import { X } from 'lucide-react';
import { useProjects, relativeTime } from '../../../hooks/useProjects';
export default function ProjectsApp() {
const { payload, error } = useProjects();
const [query, setQuery] = useState('');
+ const inputRef = useRef(null);
const filtered = useMemo(() => {
if (!payload) return [];
@@ -35,6 +37,7 @@ export default function ProjectsApp() {
›
setQuery(e.target.value)}
placeholder="Filter by name, language, or description"
@@ -42,6 +45,19 @@ export default function ProjectsApp() {
aria-label="Filter projects"
maxLength={100} // Security: prevent DoS via extremely long input strings
/>
+ {query && (
+
+ )}