summaryrefslogtreecommitdiff
path: root/frontend/components/prism/TopBar.tsx
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-17 13:07:40 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-17 13:07:40 -0700
commit62bdd79b3473262dde5fb0a90eab34fe7bf344fd (patch)
tree84f75baf7503e1df77c8335750650a72b088468a /frontend/components/prism/TopBar.tsx
parent1482422f2f5b236cdcdff4429ae06bb55dca4083 (diff)
'UI Shell and General Architecture'
Diffstat (limited to 'frontend/components/prism/TopBar.tsx')
-rw-r--r--frontend/components/prism/TopBar.tsx61
1 files changed, 61 insertions, 0 deletions
diff --git a/frontend/components/prism/TopBar.tsx b/frontend/components/prism/TopBar.tsx
new file mode 100644
index 0000000..38e8447
--- /dev/null
+++ b/frontend/components/prism/TopBar.tsx
@@ -0,0 +1,61 @@
+import type { FormEvent } from "react";
+import type { SearchResult } from "@/types/api";
+
+type Props = {
+ query: string;
+ searching: boolean;
+ results: SearchResult[];
+ marketStatus: { isOpen: boolean; status: string; time: string };
+ onChangeQuery: (value: string) => void;
+ onSubmit: (event: FormEvent<HTMLFormElement>) => void;
+ onSelectTicker: (symbol: string) => void;
+};
+
+export function TopBar({ query, searching, results, marketStatus, onChangeQuery, onSubmit, onSelectTicker }: Props) {
+ const showDropdown = query.trim().length >= 2;
+
+ return (
+ <header className="psm-top">
+ <div className="psm-search-shell">
+ <form className="psm-search-form" onSubmit={onSubmit}>
+ <span className="psm-icon icon-search" aria-hidden />
+ <input value={query} onChange={(event) => onChangeQuery(event.target.value)} placeholder="Search ticker or company" aria-label="Search ticker" />
+ <span className="psm-kbd">Enter</span>
+ </form>
+
+ {showDropdown ? (
+ <div className="psm-search-dropdown">
+ {searching ? <div className="psm-search-status">Searching...</div> : null}
+ {!searching && results.length === 0 ? <div className="psm-search-status">No matches</div> : null}
+ {!searching
+ ? results.map((result) => (
+ <button key={`${result.symbol}-${result.exchange}`} type="button" className="psm-search-result" onClick={() => onSelectTicker(result.symbol)}>
+ <span className="psm-search-result-symbol">{result.symbol}</span>
+ <span className="psm-search-result-copy">
+ {result.name}
+ {result.exchange ? ` ยท ${result.exchange}` : ""}
+ </span>
+ </button>
+ ))
+ : null}
+ </div>
+ ) : null}
+ </div>
+
+ <div className="psm-clock-group">
+ <div className="psm-market-status">
+ <span className={`psm-market-dot${marketStatus.isOpen ? " open" : ""}`} aria-hidden />
+ <span>{marketStatus.status}</span>
+ <span>{marketStatus.time}</span>
+ </div>
+
+ <div className="psm-account">
+ <span className="psm-icon icon-user" aria-hidden />
+ <span className="psm-account-avatar">T</span>
+ <span>Local Profile</span>
+ </div>
+ </div>
+ </header>
+ );
+}
+