Skip to content
Open
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
4 changes: 4 additions & 0 deletions src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,10 @@ export default function DashboardPage() {
value={tableSearch}
onChange={(e) => setTableSearch(e.target.value)}
placeholder="Search callsign, name, grid, frequency…"
autoComplete="off"
data-lpignore="true"
data-1p-ignore=""
data-form-type="other"
className="flex-1 min-w-0 bg-transparent border-0 outline-none text-fg text-[15px] placeholder:text-fg-3"
/>
<Kbd>/</Kbd>
Expand Down
17 changes: 17 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,20 @@
background: var(--line-hi);
filter: brightness(1.4);
}

/* ──────────────────────────────────────────────────────────────
Suppress password-manager autofill icon overlays
──────────────────────────────────────────────────────────────
LastPass injects <svg data-lastpass-icon="true"> overlays
positioned absolutely over inputs it thinks are credentials,
regardless of data-lpignore. Since this app is ham-radio data
(callsign, RST, datetime, city, etc.) and not credentials, we
hide the in-field icon globally. LP/1P autofill still works on
the auth forms via the extension's keyboard shortcut and
dropdown — only the in-field icon overlay is hidden. */
svg[data-lastpass-icon="true"],
com-1password-button,
[data-dashlane-rid],
[data-bitwarden-watching] {
display: none !important;
}
11 changes: 11 additions & 0 deletions src/app/new-contact/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,9 @@ export default function NewContactPage() {
onChange={handleChange}
placeholder="W1AW"
autoComplete="off"
data-lpignore="true"
data-1p-ignore=""
data-form-type="other"
className={cn(
'w-full bg-transparent border-0 border-b-2 border-line-hi text-fg font-mono text-[32px] sm:text-[56px] font-semibold tracking-[0.04em] py-3 sm:py-4 outline-none transition-colors uppercase placeholder:text-fg-3',
'focus:border-accent',
Expand Down Expand Up @@ -652,6 +655,10 @@ export default function NewContactPage() {
name="rst_sent"
value={formData.rst_sent}
onChange={handleChange}
autoComplete="off"
data-lpignore="true"
data-1p-ignore=""
data-form-type="other"
className="w-full bg-transparent border-0 outline-none text-center text-fg font-mono text-[28px] font-semibold mt-1"
/>
<div className="flex justify-center gap-1 mt-2">
Expand All @@ -675,6 +682,10 @@ export default function NewContactPage() {
name="rst_received"
value={formData.rst_received}
onChange={handleChange}
autoComplete="off"
data-lpignore="true"
data-1p-ignore=""
data-form-type="other"
className="w-full bg-transparent border-0 outline-none text-center text-fg font-mono text-[28px] font-semibold mt-1"
/>
<div className="flex justify-center gap-1 mt-2">
Expand Down
15 changes: 15 additions & 0 deletions src/app/search/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,16 @@ export default function SearchPage() {
<FilterChips chips={activeFilterChips} onRemoveFilter={removeFilter} />
</CardHeader>
<CardContent className="space-y-6">
{/* Wrapping the filter fields in a <form> gives LastPass a form
context to bind to, so it respects data-lpignore on the
individual inputs and stops attaching its autofill icon.
Search is debounced on filter change, so the form has no
real submit action — Enter is suppressed via preventDefault. */}
<form
autoComplete="off"
onSubmit={(e) => e.preventDefault()}
className="space-y-6"
>
{/* Quick Filters */}
<div className="space-y-2">
<Label>Quick Filters</Label>
Expand All @@ -793,6 +803,7 @@ export default function SearchPage() {
<Label htmlFor="callsign">Callsign</Label>
<Input
id="callsign"
type="search"
placeholder="e.g., W1AW"
value={filters.callsign}
onChange={(e) => handleFilterChange('callsign', e.target.value)}
Expand All @@ -802,6 +813,7 @@ export default function SearchPage() {
<Label htmlFor="name">Name</Label>
<Input
id="name"
type="search"
placeholder="Operator name"
value={filters.name}
onChange={(e) => handleFilterChange('name', e.target.value)}
Expand All @@ -811,6 +823,7 @@ export default function SearchPage() {
<Label htmlFor="qth">QTH</Label>
<Input
id="qth"
type="search"
placeholder="Location"
value={filters.qth}
onChange={(e) => handleFilterChange('qth', e.target.value)}
Expand Down Expand Up @@ -885,6 +898,7 @@ export default function SearchPage() {
<Label htmlFor="gridLocator">Grid Locator</Label>
<Input
id="gridLocator"
type="search"
placeholder="e.g., FN31pr"
value={filters.gridLocator}
onChange={(e) => handleFilterChange('gridLocator', e.target.value)}
Expand Down Expand Up @@ -931,6 +945,7 @@ export default function SearchPage() {
</div>
</>
)}
</form>
</CardContent>
</Card>

Expand Down
4 changes: 4 additions & 0 deletions src/components/ui/combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ export function Combobox({
placeholder={searchPlaceholder}
value={search}
onChange={(e) => setSearch(e.target.value)}
autoComplete="off"
data-lpignore="true"
data-1p-ignore=""
data-form-type="other"
/>
</div>
<div className="max-h-[300px] overflow-y-auto">
Expand Down
8 changes: 8 additions & 0 deletions src/components/ui/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
type={type}
className={cn(inputVariants({ size, mono, className }))}
ref={ref}
// Suppress password-manager autofill UI by default — this app is
// ham-radio data, not credentials. Auth forms pass an explicit
// autoComplete value (e.g. "email", "current-password") which
// overrides via prop spread below.
autoComplete="off"
data-lpignore="true"
data-1p-ignore=""
data-form-type="other"
{...props}
/>
)
Expand Down
Loading