mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-10-01 22:24:53 +02:00
fix(frontend): hover is a colour change, never an underline
Claude-Session: https://claude.ai/code/session_01C7wFUhK99JTpbtP6i5yFK5
This commit is contained in:
@@ -111,7 +111,7 @@
|
||||
{#snippet child(props)}
|
||||
<a
|
||||
{...props}
|
||||
class="inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground hover:text-foreground"
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@@ -280,7 +280,7 @@
|
||||
{#snippet child(props)}
|
||||
<a
|
||||
{...props}
|
||||
class="w-fit text-xs text-muted-foreground underline-offset-2 hover:text-foreground hover:underline"
|
||||
class="w-fit text-xs text-muted-foreground hover:text-foreground"
|
||||
href={ROUTES.settings('api-keys')}
|
||||
>
|
||||
No API key
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
href={program.url ?? bountyVocabulary.url(program.platform)}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
class="inline-flex items-center gap-1 font-mono text-xs hover:underline"
|
||||
class="inline-flex items-center gap-1 font-mono text-xs hover:text-primary"
|
||||
>
|
||||
@{program.handle}
|
||||
<ExternalLinkIcon class="size-3" />
|
||||
@@ -267,7 +267,7 @@
|
||||
{#if bountyVocabulary.platform(program.platform)?.tracks_reports}
|
||||
<a
|
||||
href={ROUTES.bountyReports(program.platform, program.handle)}
|
||||
class="text-xs text-foreground underline-offset-4 hover:underline"
|
||||
class="text-xs text-foreground hover:text-primary"
|
||||
>
|
||||
{program.reports_for_user}
|
||||
{program.reports_for_user === 1 ? 'report' : 'reports'}{program.earnings_for_user
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
href={href(p)}
|
||||
target={p.in_hub ? undefined : '_blank'}
|
||||
rel={p.in_hub ? undefined : 'noopener noreferrer'}
|
||||
class="block truncate text-sm font-medium hover:underline">{p.name}</a
|
||||
class="block truncate text-sm font-medium hover:text-primary">{p.name}</a
|
||||
>
|
||||
<div class="flex items-center gap-1.5 text-2xs text-muted-foreground">
|
||||
<span class="font-mono">@{p.handle}</span>
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
href={programHref}
|
||||
target={report.program_in_hub ? undefined : '_blank'}
|
||||
rel={report.program_in_hub ? undefined : 'noopener noreferrer'}
|
||||
class="block truncate text-sm hover:underline"
|
||||
class="block truncate text-sm hover:text-primary"
|
||||
>
|
||||
{programName}
|
||||
</a>
|
||||
@@ -266,7 +266,7 @@
|
||||
href={programHref}
|
||||
target={report.program_in_hub ? undefined : '_blank'}
|
||||
rel={report.program_in_hub ? undefined : 'noopener noreferrer'}
|
||||
class="truncate text-sm font-medium hover:underline">{programName}</a
|
||||
class="truncate text-sm font-medium hover:text-primary">{programName}</a
|
||||
>
|
||||
{/if}
|
||||
<span class="font-mono text-2xs text-muted-foreground">@{report.program_handle}</span>
|
||||
@@ -309,7 +309,7 @@
|
||||
<dd class="min-w-0">
|
||||
<button
|
||||
type="button"
|
||||
class="truncate text-left hover:underline"
|
||||
class="truncate text-left hover:text-primary"
|
||||
onclick={() => onSearch(report.weakness!)}>{report.weakness}</button
|
||||
>
|
||||
</dd>
|
||||
@@ -319,7 +319,7 @@
|
||||
<dd class="flex min-w-0 items-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
class="truncate text-left font-mono text-xs hover:underline"
|
||||
class="truncate text-left font-mono text-xs hover:text-primary"
|
||||
onclick={() => onSearch(report.asset_identifier!)}>{report.asset_identifier}</button
|
||||
>
|
||||
<CopyButton value={report.asset_identifier} class="shrink-0" />
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => onOpenProgram(event.handle, event.platform)}
|
||||
class="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
{event.program_name}
|
||||
<ArrowUpRightIcon class="size-3" />
|
||||
|
||||
@@ -120,8 +120,9 @@
|
||||
Added{result.attached ? ` · ${result.attached} attached` : ''}
|
||||
</span>
|
||||
{#if result.scan_id}
|
||||
<a href={ROUTES.scan(result.scan_id)} class="text-primary text-xs hover:underline"
|
||||
>Scan running</a
|
||||
<a
|
||||
href={ROUTES.scan(result.scan_id)}
|
||||
class="text-primary text-xs hover:text-primary/80">Scan running</a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
</span>
|
||||
<span class="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 text-xs">
|
||||
{#if step.software > 0}
|
||||
<a href={softwareHref(step)} class="hover:underline">
|
||||
<a href={softwareHref(step)} class="hover:text-primary">
|
||||
{step.software.toLocaleString()} in {software.label}
|
||||
</a>
|
||||
{/if}
|
||||
{#if step.findings > 0}
|
||||
<a href={findingsHref(step)} class="hover:underline">
|
||||
<a href={findingsHref(step)} class="hover:text-primary">
|
||||
{step.findings.toLocaleString()} in {findings.label}
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<a
|
||||
{...props}
|
||||
href={link(postureQuery(key))}
|
||||
class="block text-sm leading-5 hover:underline">{spec?.label ?? key}</a
|
||||
class="block text-sm leading-5 hover:text-primary">{spec?.label ?? key}</a
|
||||
>
|
||||
{/snippet}
|
||||
</Hint>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
{#snippet footer()}
|
||||
<span>
|
||||
{total.toLocaleString()} runs in {days} days ·
|
||||
<a href={ROUTES.scansWhere({ status: 'failed', range: window })} class="hover:underline">
|
||||
<a href={ROUTES.scansWhere({ status: 'failed', range: window })} class="hover:text-primary">
|
||||
{failed} failed
|
||||
</a>
|
||||
</span>
|
||||
|
||||
@@ -75,14 +75,14 @@
|
||||
<div class={STAT}>
|
||||
<a
|
||||
href={actionableHref}
|
||||
class="text-lg leading-tight font-semibold tracking-tight tabular-nums hover:underline {data.actionable
|
||||
class="text-lg leading-tight font-semibold tracking-tight tabular-nums hover:text-primary {data.actionable
|
||||
? 'text-[var(--sev-critical-ink)]'
|
||||
: ''}"
|
||||
>
|
||||
{data.actionable.toLocaleString()}
|
||||
</a>
|
||||
<span class="truncate text-2xs text-muted-foreground">
|
||||
actionable · <a href={actHref} class="hover:underline"
|
||||
actionable · <a href={actHref} class="hover:text-primary"
|
||||
>{data.act.toLocaleString()} act now</a
|
||||
>
|
||||
</span>
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
<div class="flex items-baseline justify-between gap-2">
|
||||
<a
|
||||
href={ROUTES.target(r.target_id)}
|
||||
class="truncate text-sm font-semibold hover:underline">{r.target_value}</a
|
||||
class="truncate text-sm font-semibold hover:text-primary">{r.target_value}</a
|
||||
>
|
||||
<span class="shrink-0 text-2xs text-muted-foreground">
|
||||
{#if r.last_at}{relativeTime(r.last_at)}{/if}{#if !settled && r.scan_status}
|
||||
@@ -146,13 +146,16 @@
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<a href={liveQuery(r)} class="flex justify-between gap-2 rounded-sm hover:underline">
|
||||
<a href={liveQuery(r)} class="flex justify-between gap-2 rounded-sm hover:text-primary">
|
||||
<span class="text-muted-foreground">Live web assets</span>
|
||||
<span class="font-medium tabular-nums"
|
||||
>{r.live.toLocaleString()} of {r.names.toLocaleString()}</span
|
||||
>
|
||||
</a>
|
||||
<a href={findingsQuery(r)} class="flex justify-between gap-2 rounded-sm hover:underline">
|
||||
<a
|
||||
href={findingsQuery(r)}
|
||||
class="flex justify-between gap-2 rounded-sm hover:text-primary"
|
||||
>
|
||||
<span class="text-muted-foreground">Open findings</span>
|
||||
<span class="font-medium tabular-nums">{r.findings.toLocaleString()}</span>
|
||||
</a>
|
||||
|
||||
@@ -131,14 +131,18 @@
|
||||
<a
|
||||
href="https://github.com/yogeshojha/rengine"
|
||||
target="_blank"
|
||||
class="text-sm text-primary hover:underline"
|
||||
class="text-sm text-primary hover:text-primary/80"
|
||||
>
|
||||
github.com/yogeshojha/rengine
|
||||
</a>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h4 class="font-medium">Wiki</h4>
|
||||
<a href="https://rengine.wiki" target="_blank" class="text-sm text-primary hover:underline">
|
||||
<a
|
||||
href="https://rengine.wiki"
|
||||
target="_blank"
|
||||
class="text-sm text-primary hover:text-primary/80"
|
||||
>
|
||||
rengine.wiki
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
<span class="text-muted-foreground/40">·</span>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center gap-0.5 text-2xs font-medium text-primary hover:underline"
|
||||
class="inline-flex items-center gap-0.5 text-2xs font-medium text-primary hover:text-primary/80"
|
||||
onclick={(e) => onAction(notification.id, e)}
|
||||
>
|
||||
{meta.action_label}
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
{/if}
|
||||
{#if showAnchor}
|
||||
<span class="text-muted-foreground/60">·</span>
|
||||
<a href={ROUTES.target(note.target_id)} class="hover:text-foreground hover:underline">
|
||||
<a href={ROUTES.target(note.target_id)} class="hover:text-foreground">
|
||||
{note.target_value}
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
href={meta.chatUrl(status.bot.username)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="font-mono text-xs text-primary hover:underline">@{status.bot.username}</a
|
||||
class="font-mono text-xs text-primary hover:text-primary/80">@{status.bot.username}</a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
href={meta.tokenSourceUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="font-medium text-primary hover:underline">{meta.tokenSource}</a
|
||||
class="font-medium text-primary hover:text-primary/80">{meta.tokenSource}</a
|
||||
>
|
||||
and copy its token.
|
||||
</span>
|
||||
|
||||
@@ -77,7 +77,8 @@
|
||||
href={meta.chatUrl(status.bot.username)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="font-mono text-sm text-primary hover:underline">@{status.bot.username}</a
|
||||
class="font-mono text-sm text-primary hover:text-primary/80"
|
||||
>@{status.bot.username}</a
|
||||
>
|
||||
{/if}
|
||||
<span class="font-mono text-xs text-muted-foreground">{status.secret_masked}</span>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
<div class="min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<a {href} class="truncate text-sm font-medium hover:underline">{template.name}</a>
|
||||
<a {href} class="truncate text-sm font-medium hover:text-primary">{template.name}</a>
|
||||
<OriginBadge builtin={template.is_builtin} />
|
||||
</div>
|
||||
<p class="line-clamp-1 text-xs text-muted-foreground">{template.description}</p>
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
{#if evidence}
|
||||
<Collapsible.Root bind:open class="mt-1">
|
||||
<Collapsible.Trigger
|
||||
class="inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline"
|
||||
class="inline-flex items-center gap-1 text-xs font-medium text-primary hover:text-primary/80"
|
||||
>
|
||||
<ChevronRight class={cn('size-3.5 transition-transform', open && 'rotate-90')} />
|
||||
{open ? 'Hide' : 'Show'} what differs
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="font-medium text-primary hover:underline"
|
||||
class="font-medium text-primary hover:text-primary/80"
|
||||
onclick={() => (baseline = data?.suggestion?.scan_id ?? null)}
|
||||
>
|
||||
Compare with this run
|
||||
@@ -108,7 +108,7 @@
|
||||
{#each data.dimensions as d (d.dimension)}
|
||||
<tr class="border-t border-border/50">
|
||||
<td class="py-1.5 pr-3">
|
||||
<a href={ROUTES.compare(scan.id, data.baseline.scan_id)} class="hover:underline"
|
||||
<a href={ROUTES.compare(scan.id, data.baseline.scan_id)} class="hover:text-primary"
|
||||
>{d.label}</a
|
||||
>
|
||||
{#if d.verdict.comparability !== COMPARABILITY.LIKE_FOR_LIKE}
|
||||
@@ -135,7 +135,7 @@
|
||||
</ScrollArea>
|
||||
<a
|
||||
href={ROUTES.compare(scan.id, data.baseline.scan_id)}
|
||||
class="px-1 text-xs text-primary hover:underline"
|
||||
class="px-1 text-xs text-primary hover:text-primary/80"
|
||||
>
|
||||
Open comparison
|
||||
</a>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
{#if scan.engine_id}
|
||||
<a
|
||||
href={ROUTES.engine(scan.engine_id)}
|
||||
class="text-xl font-semibold tracking-tight hover:underline"
|
||||
class="text-xl font-semibold tracking-tight hover:text-primary"
|
||||
>
|
||||
{scan.engine_name}
|
||||
</a>
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
{#if !historyPrefs.showMedium && (findings?.medium ?? 0) > 0}
|
||||
<button
|
||||
type="button"
|
||||
class="text-primary hover:underline"
|
||||
class="text-primary hover:text-primary/80"
|
||||
onclick={() => (historyPrefs.showMedium = true)}
|
||||
>
|
||||
Show {findings?.medium} medium
|
||||
@@ -237,7 +237,10 @@
|
||||
{/each}
|
||||
{/each}
|
||||
{#if total > (items?.length ?? 0)}
|
||||
<a href={findingsHref(scanId, shown)} class="px-4 py-2 text-xs text-primary hover:underline">
|
||||
<a
|
||||
href={findingsHref(scanId, shown)}
|
||||
class="px-4 py-2 text-xs text-primary hover:text-primary/80"
|
||||
>
|
||||
Open all {total} in results
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
@@ -114,12 +114,12 @@
|
||||
{#if added}
|
||||
<a
|
||||
href={ROUTES.results(WEB.tab, scan.id, { [WEB.queryParam]: 'is:new' })}
|
||||
class="text-primary hover:underline"
|
||||
class="text-primary hover:text-primary/80"
|
||||
>
|
||||
Open new {WEB.nounPlural}
|
||||
</a>
|
||||
{/if}
|
||||
<button type="button" class="text-primary hover:underline" onclick={onCompare}>
|
||||
<button type="button" class="text-primary hover:text-primary/80" onclick={onCompare}>
|
||||
Compare with previous
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -77,7 +77,10 @@
|
||||
{c.n}
|
||||
{SEVERITY_LABELS[c.sev].toLowerCase()}
|
||||
</span>
|
||||
<a href={findingsHref(scanId, [c.sev])} class="text-2xs text-primary hover:underline">
|
||||
<a
|
||||
href={findingsHref(scanId, [c.sev])}
|
||||
class="text-2xs text-primary hover:text-primary/80"
|
||||
>
|
||||
Open in results
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1106,7 +1106,7 @@
|
||||
{#if i > 0}<span class="text-muted-foreground/60">›</span>{/if}
|
||||
<button
|
||||
type="button"
|
||||
class="max-w-64 truncate font-mono text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="max-w-64 truncate font-mono text-muted-foreground hover:text-foreground"
|
||||
onclick={() => outline?.jumpTo(crumb.key)}
|
||||
>
|
||||
{crumb.name}
|
||||
@@ -1326,7 +1326,7 @@
|
||||
{/if}
|
||||
<button
|
||||
type="button"
|
||||
class="ml-auto rounded-sm text-foreground hover:underline focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
class="ml-auto rounded-sm text-foreground hover:text-primary focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
onclick={() => (goneLens = false)}
|
||||
>
|
||||
Back to this scan
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<span>·</span>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-sm text-primary hover:underline focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
class="rounded-sm text-primary hover:text-primary/80 focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
onclick={onShowStatic}
|
||||
>
|
||||
{n(hidden)} static hidden
|
||||
@@ -105,7 +105,7 @@
|
||||
<span>·</span>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-sm text-primary hover:underline focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
class="rounded-sm text-primary hover:text-primary/80 focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
onclick={onShowRootOnly}
|
||||
>
|
||||
{n(rootOnly)} root-only {rootOnly === 1 ? 'host' : 'hosts'} hidden
|
||||
@@ -115,7 +115,7 @@
|
||||
<span>·</span>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-sm text-info hover:underline focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
class="rounded-sm text-info hover:text-info/80 focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
onclick={onShowNew}
|
||||
>
|
||||
{n(summary.new)} new since the previous scan
|
||||
@@ -125,7 +125,7 @@
|
||||
<span>·</span>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-sm text-foreground hover:underline focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
class="rounded-sm text-foreground hover:text-primary focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
onclick={onShowGone}
|
||||
>
|
||||
{n(summary.gone)} gone
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
{#if column.key === 'host'}
|
||||
<button
|
||||
type="button"
|
||||
class="block w-full truncate text-left text-xs hover:text-primary hover:underline"
|
||||
class="block w-full truncate text-left text-xs hover:text-primary"
|
||||
onclick={(e) => {
|
||||
e.stopPropagation();
|
||||
onFilter?.(filterToken('host', endpoint.host));
|
||||
|
||||
@@ -137,34 +137,34 @@
|
||||
><b class="font-semibold text-foreground tabular-nums">{n(brief.total)}</b> endpoints</span
|
||||
>
|
||||
{#if brief.probed}
|
||||
<button type="button" class="hover:underline" onclick={() => onPivot('is:probed')}>
|
||||
<button type="button" class="hover:text-primary" onclick={() => onPivot('is:probed')}>
|
||||
<b class="font-semibold text-foreground tabular-nums">{n(brief.probed)}</b> verified
|
||||
</button>
|
||||
{/if}
|
||||
{#if brief.with_params}
|
||||
<button type="button" class="hover:underline" onclick={() => onPivot('is:param')}>
|
||||
<button type="button" class="hover:text-primary" onclick={() => onPivot('is:param')}>
|
||||
<b class="font-semibold text-foreground tabular-nums">{n(brief.with_params)}</b> take input
|
||||
</button>
|
||||
{/if}
|
||||
{#if brief.api}
|
||||
<button type="button" class="hover:underline" onclick={() => onPivot('class:api')}>
|
||||
<button type="button" class="hover:text-primary" onclick={() => onPivot('class:api')}>
|
||||
<b class="font-semibold text-foreground tabular-nums">{n(brief.api)}</b> API
|
||||
</button>
|
||||
{/if}
|
||||
{#if brief.walled}
|
||||
<button type="button" class="hover:underline" onclick={() => onPivot('is:auth')}>
|
||||
<button type="button" class="hover:text-primary" onclick={() => onPivot('is:auth')}>
|
||||
<b class="font-semibold text-foreground tabular-nums">{n(brief.walled)}</b> behind auth
|
||||
</button>
|
||||
{/if}
|
||||
{#if brief.new}
|
||||
<button type="button" class="hover:underline" onclick={onNew}>
|
||||
<button type="button" class="hover:text-primary" onclick={onNew}>
|
||||
<b class="font-semibold text-success tabular-nums">+{n(brief.new)}</b>
|
||||
new{#if brief.previous_scan_at}
|
||||
since {formatShortDate(brief.previous_scan_at)}{/if}
|
||||
</button>
|
||||
{/if}
|
||||
{#if brief.findings && onFindings}
|
||||
<button type="button" class="hover:underline" onclick={onFindings}>
|
||||
<button type="button" class="hover:text-primary" onclick={onFindings}>
|
||||
<b class="font-semibold text-destructive tabular-nums">{n(brief.findings)}</b>
|
||||
{brief.findings === 1 ? 'finding' : 'findings'}
|
||||
</button>
|
||||
@@ -196,7 +196,7 @@
|
||||
{#if hiddenParams > 0}
|
||||
<button
|
||||
type="button"
|
||||
class="text-2xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="text-2xs text-muted-foreground hover:text-foreground"
|
||||
onclick={() => (allParams = true)}
|
||||
>
|
||||
+{n(hiddenParams)} more
|
||||
@@ -204,7 +204,7 @@
|
||||
{:else if allParams && brief.params_total > PARAM_LIMIT}
|
||||
<button
|
||||
type="button"
|
||||
class="text-2xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="text-2xs text-muted-foreground hover:text-foreground"
|
||||
onclick={() => (allParams = false)}
|
||||
>
|
||||
Show fewer
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-sm text-primary hover:underline focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
class="rounded-sm text-primary hover:text-primary/80 focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||
onclick={onShowRootOnly}
|
||||
>
|
||||
Show
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="text-2xs text-muted-foreground hover:text-primary hover:underline"
|
||||
class="text-2xs text-muted-foreground hover:text-primary"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
on {leaf.hosts} hosts
|
||||
@@ -165,7 +165,7 @@
|
||||
{:else if leaf.host_names[0]}
|
||||
<button
|
||||
type="button"
|
||||
class="font-mono text-2xs text-muted-foreground hover:text-primary hover:underline"
|
||||
class="font-mono text-2xs text-muted-foreground hover:text-primary"
|
||||
onclick={(e) => {
|
||||
e.stopPropagation();
|
||||
onHost(leaf.host_names[0]);
|
||||
|
||||
@@ -287,7 +287,7 @@
|
||||
<span class="size-4 shrink-0"></span>
|
||||
<button
|
||||
type="button"
|
||||
class="font-medium text-primary hover:underline disabled:opacity-60"
|
||||
class="font-medium text-primary hover:text-primary/80 disabled:opacity-60"
|
||||
disabled={loading}
|
||||
onclick={() => load(page + 1)}
|
||||
>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{#if host}
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center gap-1 font-mono hover:text-primary hover:underline"
|
||||
class="flex items-center gap-1 font-mono hover:text-primary"
|
||||
onclick={() => onSelect(host, '/')}
|
||||
>
|
||||
<Globe class="size-3" />
|
||||
@@ -30,7 +30,7 @@
|
||||
<ChevronRight class="size-3 shrink-0 text-muted-foreground" />
|
||||
<button
|
||||
type="button"
|
||||
class="font-mono hover:text-primary hover:underline"
|
||||
class="font-mono hover:text-primary"
|
||||
onclick={() => onSelect(host, '/' + segments.slice(0, i + 1).join('/') + '/')}
|
||||
>
|
||||
{segment}
|
||||
|
||||
@@ -220,7 +220,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="min-w-0 truncate font-mono hover:text-foreground hover:underline"
|
||||
class="min-w-0 truncate font-mono hover:text-foreground"
|
||||
onclick={(e) => pivot(e, filterToken('ptr', ptr[0]))}
|
||||
>
|
||||
<HighlightText text={ptr[0]} {term} />
|
||||
@@ -244,7 +244,7 @@
|
||||
class="block min-w-0 max-w-full text-left"
|
||||
onclick={(e) => pivot(e, `asn:${g.asn}`)}
|
||||
>
|
||||
<span class="block font-mono text-xs hover:underline">AS{g.asn}</span>
|
||||
<span class="block font-mono text-xs hover:text-primary">AS{g.asn}</span>
|
||||
{#if g.asn_org}
|
||||
<span class="block truncate text-xs text-muted-foreground">
|
||||
<HighlightText text={g.asn_org} {term} />
|
||||
@@ -336,7 +336,7 @@
|
||||
{#if g.country}
|
||||
<button
|
||||
type="button"
|
||||
class="text-xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="text-xs text-muted-foreground hover:text-foreground"
|
||||
onclick={(e) => pivot(e, exactToken('country', g.country ?? ''))}
|
||||
>
|
||||
<CountryFlag code={g.country} />
|
||||
@@ -348,7 +348,7 @@
|
||||
{#if g.prefix}
|
||||
<button
|
||||
type="button"
|
||||
class="min-w-0 truncate font-mono text-xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="min-w-0 truncate font-mono text-xs text-muted-foreground hover:text-foreground"
|
||||
onclick={(e) => pivot(e, exactToken('prefix', g.prefix ?? ''))}
|
||||
>
|
||||
{g.prefix}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
onpointerleave={() => (hovered = null)}
|
||||
>
|
||||
<CountryFlag code={dominant.name} showCode={false} />
|
||||
<span class="min-w-0 flex-1 truncate text-sm font-medium group-hover:underline">
|
||||
<span class="min-w-0 flex-1 truncate text-sm font-medium group-hover:text-primary">
|
||||
{countryName(dominant.name)}
|
||||
</span>
|
||||
<span class="text-sm font-medium tabular-nums">{dominant.count.toLocaleString()}</span>
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
{#each severities as part (part.severity)}
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center gap-1.5 text-xs hover:underline"
|
||||
class="flex items-center gap-1.5 text-xs hover:text-primary"
|
||||
onclick={() => pick(exactToken('severity', part.severity))}
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
{#if !isRecheckLive(entry)}
|
||||
<a
|
||||
href={ROUTES.scan(entry.scan_id)}
|
||||
class="mt-2 ml-4 inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline"
|
||||
class="mt-2 ml-4 inline-flex items-center gap-1 text-xs font-medium text-primary hover:text-primary/80"
|
||||
>
|
||||
Open focused scan <ArrowUpRight class="size-3" />
|
||||
</a>
|
||||
|
||||
@@ -290,7 +290,7 @@
|
||||
type="button"
|
||||
class="font-mono text-sm tabular-nums {httpStatusTextClass(
|
||||
s.status_code
|
||||
)} hover:underline"
|
||||
)} hover:text-primary"
|
||||
onclick={() => onFilter?.(`status:${s.status_code}`)}
|
||||
>
|
||||
{s.status_code}
|
||||
@@ -312,7 +312,7 @@
|
||||
href={s.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center gap-1 font-mono text-xs break-all hover:underline"
|
||||
class="inline-flex items-center gap-1 font-mono text-xs break-all hover:text-primary"
|
||||
>
|
||||
{s.url}
|
||||
<ExternalLink class="size-3 shrink-0" />
|
||||
|
||||
@@ -322,7 +322,7 @@
|
||||
<span class="flex h-4 shrink-0 items-center">
|
||||
<TechIcon name={productBrand(s.product)} class="size-3.5" />
|
||||
</span>
|
||||
<span class="min-w-0 text-xs leading-4 wrap-anywhere hover:underline">
|
||||
<span class="min-w-0 text-xs leading-4 wrap-anywhere hover:text-primary">
|
||||
<HighlightText text={software} {term} />
|
||||
</span>
|
||||
</span>
|
||||
@@ -382,7 +382,7 @@
|
||||
type="button"
|
||||
class="shrink-0 font-mono text-xs tabular-nums {httpStatusTextClass(
|
||||
s.status_code
|
||||
)} hover:underline"
|
||||
)} hover:text-primary"
|
||||
onclick={(e) => pivot(e, `status:${s.status_code}`)}
|
||||
>
|
||||
{s.status_code}
|
||||
@@ -412,7 +412,7 @@
|
||||
class="block min-w-0 max-w-full text-left"
|
||||
onclick={(e) => pivot(e, `asn:${s.asn}`)}
|
||||
>
|
||||
<span class="block font-mono text-xs hover:underline">AS{s.asn}</span>
|
||||
<span class="block font-mono text-xs hover:text-primary">AS{s.asn}</span>
|
||||
{#if s.asn_org}
|
||||
<span class="block truncate text-xs text-muted-foreground">
|
||||
<HighlightText text={s.asn_org} {term} />
|
||||
@@ -428,7 +428,7 @@
|
||||
{#if s.country}
|
||||
<button
|
||||
type="button"
|
||||
class="text-xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="text-xs text-muted-foreground hover:text-foreground"
|
||||
onclick={(e) => pivot(e, exactToken('country', s.country ?? ''))}
|
||||
>
|
||||
<CountryFlag code={s.country} />
|
||||
@@ -443,7 +443,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="min-w-0 truncate text-xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="min-w-0 truncate text-xs text-muted-foreground hover:text-foreground"
|
||||
onclick={(e) => pivot(e, exactToken('source', s.source))}
|
||||
>
|
||||
{PORT_SOURCE_LABELS[s.source] ?? s.source}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="min-w-0 truncate text-xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="min-w-0 truncate text-xs text-muted-foreground hover:text-foreground"
|
||||
onclick={(event) => {
|
||||
event.stopPropagation();
|
||||
onFilter?.(exactToken('target', first));
|
||||
|
||||
+7
-6
@@ -105,7 +105,7 @@
|
||||
{/if}
|
||||
<button
|
||||
type="button"
|
||||
class="truncate font-mono hover:underline"
|
||||
class="truncate font-mono hover:text-primary"
|
||||
onclick={() => onTab(WEB.tab, hostToken)}>{v.host}</button
|
||||
>
|
||||
</dd>
|
||||
@@ -137,14 +137,14 @@
|
||||
<dd class="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5">
|
||||
<button
|
||||
type="button"
|
||||
class="font-mono hover:underline"
|
||||
class="font-mono hover:text-primary"
|
||||
onclick={() => onTab(IPS.tab, ipToken)}>{v.ip}</button
|
||||
>
|
||||
{#if asset?.country}<CountryFlag code={asset.country} showCode />{/if}
|
||||
{#if asset?.asn}
|
||||
<button
|
||||
type="button"
|
||||
class="truncate text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="truncate text-muted-foreground hover:text-foreground"
|
||||
onclick={() => onFilter(`asn:${asset.asn}`)}
|
||||
>
|
||||
AS{asset.asn}{asset.asn_org ? ` · ${asset.asn_org}` : ''}
|
||||
@@ -186,7 +186,7 @@
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="ml-auto text-2xs text-primary hover:underline"
|
||||
class="ml-auto text-2xs text-primary hover:text-primary/80"
|
||||
onclick={() => onFilter(hostToken)}
|
||||
>
|
||||
Filter to this {WEB.noun}
|
||||
@@ -220,7 +220,7 @@
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="ml-auto text-2xs text-primary hover:underline"
|
||||
class="ml-auto text-2xs text-primary hover:text-primary/80"
|
||||
onclick={() => onFilter(templateToken)}
|
||||
>
|
||||
All {checkTotal || ''} findings from this check
|
||||
@@ -308,7 +308,8 @@
|
||||
{#if v.cve_ids.length}
|
||||
<dt class="text-muted-foreground">CVE</dt>
|
||||
<dd class="flex flex-wrap gap-x-2 font-mono">
|
||||
{#each v.cve_ids as c (c)}<a href={ROUTES.cve(c)} class="hover:underline">{c}</a>{/each}
|
||||
{#each v.cve_ids as c (c)}<a href={ROUTES.cve(c)} class="hover:text-primary">{c}</a
|
||||
>{/each}
|
||||
</dd>
|
||||
{/if}
|
||||
{#if v.cwe_ids.length}
|
||||
|
||||
+10
-10
@@ -181,7 +181,7 @@
|
||||
<div class="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
|
||||
<button
|
||||
type="button"
|
||||
class="min-w-0 text-left text-sm leading-6 font-medium wrap-anywhere hover:underline {suppressed
|
||||
class="min-w-0 text-left text-sm leading-6 font-medium wrap-anywhere hover:text-primary {suppressed
|
||||
? 'text-muted-foreground line-through decoration-muted-foreground/40'
|
||||
: ''}"
|
||||
onclick={(e) => {
|
||||
@@ -225,7 +225,7 @@
|
||||
{#if projectWide && v.target_value}
|
||||
<button
|
||||
type="button"
|
||||
class="font-medium text-foreground/80 hover:underline {NARROW.target}"
|
||||
class="font-medium text-foreground/80 hover:text-primary {NARROW.target}"
|
||||
onclick={(e) => pivot(e, exactToken('target', v.target_value ?? ''))}
|
||||
>{v.target_value}</button
|
||||
>
|
||||
@@ -233,7 +233,7 @@
|
||||
{/if}
|
||||
<button
|
||||
type="button"
|
||||
class="font-mono text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="font-mono text-muted-foreground hover:text-foreground"
|
||||
onclick={(e) => pivot(e, templateToken)}
|
||||
>
|
||||
<HighlightText text={v.template_id} {term} />
|
||||
@@ -244,7 +244,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="min-w-0 truncate text-left font-mono text-foreground/80 hover:underline"
|
||||
class="min-w-0 truncate text-left font-mono text-foreground/80 hover:text-primary"
|
||||
onclick={(e) => pivot(e, filterToken('location', path))}
|
||||
>
|
||||
<span class={NARROW.origin}>{origin}</span><HighlightText text={path} {term} />
|
||||
@@ -298,7 +298,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="min-w-0 truncate font-mono text-xs hover:underline"
|
||||
class="min-w-0 truncate font-mono text-xs hover:text-primary"
|
||||
onclick={(e) => pivot(e, hostToken)}
|
||||
>
|
||||
<HighlightText text={v.host ?? ''} {term} />
|
||||
@@ -307,14 +307,14 @@
|
||||
{#snippet footer()}
|
||||
<button
|
||||
type="button"
|
||||
class="text-primary hover:underline"
|
||||
class="text-primary hover:text-primary/80"
|
||||
onclick={() => onFilter(hostToken)}
|
||||
>
|
||||
Filter to this {WEB.noun}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="text-primary hover:underline"
|
||||
class="text-primary hover:text-primary/80"
|
||||
onclick={() => onTab(WEB.tab, hostToken)}
|
||||
>
|
||||
Open in {WEB.nounPlural}
|
||||
@@ -387,7 +387,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="w-fit text-left text-2xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="w-fit text-left text-2xs text-muted-foreground hover:text-foreground"
|
||||
onclick={(e) => pivot(e, templateToken)}
|
||||
>
|
||||
Same check on {others} more
|
||||
@@ -408,7 +408,7 @@
|
||||
{#if v.cve_ids.length}
|
||||
<a
|
||||
href={ROUTES.cve(v.cve_ids[0])}
|
||||
class="h-6 truncate font-mono text-xs leading-6 hover:underline"
|
||||
class="h-6 truncate font-mono text-xs leading-6 hover:text-primary"
|
||||
onclick={stopProp}
|
||||
>
|
||||
{v.cve_ids[0]}{v.cve_ids.length > 1 ? ` +${v.cve_ids.length - 1}` : ''}
|
||||
@@ -420,7 +420,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="w-fit text-left font-mono text-2xs tabular-nums hover:underline"
|
||||
class="w-fit text-left font-mono text-2xs tabular-nums hover:text-primary"
|
||||
onclick={(e) => pivot(e, `exploit:>=${Math.max(10, v.exploit_score - 10)}`)}
|
||||
>
|
||||
<span class="text-muted-foreground">Rank</span>
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="min-w-0 font-mono text-2xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="min-w-0 font-mono text-2xs text-muted-foreground hover:text-foreground"
|
||||
onclick={(e) => pivot(e, exactToken('template', it.template_id))}
|
||||
>
|
||||
<HighlightText text={it.template_id} {term} />
|
||||
|
||||
@@ -335,22 +335,20 @@
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="font-mono hover:text-foreground hover:underline"
|
||||
class="font-mono hover:text-foreground"
|
||||
onclick={() => filter(templateToken)}>{s.template_id}</button
|
||||
>
|
||||
{#if s.host}
|
||||
<span class="text-muted-foreground/50">·</span>
|
||||
<button
|
||||
type="button"
|
||||
class="font-mono text-foreground/90 hover:underline"
|
||||
class="font-mono text-foreground/90 hover:text-primary"
|
||||
onclick={() => onHost?.(hostToken)}>{s.host}</button
|
||||
>
|
||||
{/if}
|
||||
{#each s.cve_ids.filter((c) => c.toLowerCase() !== s.template_id.toLowerCase()) as cve (cve)}
|
||||
<span class="text-muted-foreground/50">·</span>
|
||||
<a href={ROUTES.cve(cve)} class="font-mono hover:text-foreground hover:underline"
|
||||
>{cve}</a
|
||||
>
|
||||
<a href={ROUTES.cve(cve)} class="font-mono hover:text-foreground">{cve}</a>
|
||||
{/each}
|
||||
{#if s.cvss_score != null}
|
||||
<span class="text-muted-foreground/50">·</span>
|
||||
@@ -582,7 +580,7 @@
|
||||
{/if}
|
||||
<button
|
||||
type="button"
|
||||
class="min-w-0 truncate font-mono text-base font-medium hover:underline"
|
||||
class="min-w-0 truncate font-mono text-base font-medium hover:text-primary"
|
||||
onclick={() => onHost?.(hostToken)}
|
||||
>{s.host ?? s.ip}{s.port ? `:${s.port}` : ''}</button
|
||||
>
|
||||
@@ -630,7 +628,7 @@
|
||||
<dd class="flex min-w-0 items-center gap-2 text-xs">
|
||||
<button
|
||||
type="button"
|
||||
class="font-mono hover:underline disabled:no-underline"
|
||||
class="font-mono hover:text-primary"
|
||||
disabled={!onTab}
|
||||
onclick={() => onTab?.(IPS.tab, exactToken('ip', s.ip ?? ''))}
|
||||
>{s.ip}</button
|
||||
@@ -651,7 +649,7 @@
|
||||
<dd class="min-w-0 text-xs">
|
||||
<button
|
||||
type="button"
|
||||
class="max-w-full truncate hover:underline"
|
||||
class="max-w-full truncate hover:text-primary"
|
||||
onclick={() => filter(`asn:${asset.asn}`)}
|
||||
>
|
||||
<span class="font-mono">AS{asset.asn}</span>{asset.asn_org
|
||||
@@ -704,7 +702,7 @@
|
||||
{@render heading(`Other findings on this ${WEB.noun}`)}
|
||||
<button
|
||||
type="button"
|
||||
class="ml-auto text-2xs text-primary hover:underline"
|
||||
class="ml-auto text-2xs text-primary hover:text-primary/80"
|
||||
onclick={() => filter(hostToken)}>Filter to this {WEB.noun}</button
|
||||
>
|
||||
</div>
|
||||
@@ -801,7 +799,7 @@
|
||||
<dd>
|
||||
<button
|
||||
type="button"
|
||||
class="text-xs hover:underline"
|
||||
class="text-xs hover:text-primary"
|
||||
onclick={() => onLocation?.(s.matched_at)}
|
||||
>
|
||||
{s.colocated}
|
||||
@@ -893,7 +891,7 @@
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="ml-auto text-2xs text-primary hover:underline"
|
||||
class="ml-auto text-2xs text-primary hover:text-primary/80"
|
||||
onclick={() => filter(templateToken)}>All findings from this check</button
|
||||
>
|
||||
</div>
|
||||
@@ -952,7 +950,7 @@
|
||||
href={ref}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-start gap-1.5 text-xs break-all text-primary hover:underline"
|
||||
class="flex items-start gap-1.5 text-xs break-all text-primary hover:text-primary/80"
|
||||
>
|
||||
<ScrollText class="mt-0.5 size-3 shrink-0" />{ref}
|
||||
</a>
|
||||
@@ -962,7 +960,7 @@
|
||||
href={s.template_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center gap-1.5 text-xs text-primary hover:underline"
|
||||
class="flex items-center gap-1.5 text-xs text-primary hover:text-primary/80"
|
||||
>
|
||||
<ExternalLink class="size-3" /> View check
|
||||
</a>
|
||||
|
||||
@@ -451,7 +451,7 @@
|
||||
href={sub.final_url}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
class="ml-1 font-mono break-all hover:underline">{sub.final_url}</a
|
||||
class="ml-1 font-mono break-all hover:text-primary">{sub.final_url}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -571,7 +571,7 @@
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
class="font-mono text-sm break-all hover:underline">{url}</a
|
||||
class="font-mono text-sm break-all hover:text-primary">{url}</a
|
||||
>
|
||||
</dd>
|
||||
</div>
|
||||
@@ -626,7 +626,7 @@
|
||||
Covered by
|
||||
<button
|
||||
type="button"
|
||||
class="font-mono hover:underline"
|
||||
class="font-mono hover:text-primary"
|
||||
onclick={() => {
|
||||
const rep = surface.representative_value ?? '';
|
||||
const host = rep.replace(/^https?:\/\//, '').replace(/:\d+$/, '');
|
||||
@@ -717,7 +717,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="text-left text-sm leading-5 hover:underline"
|
||||
class="text-left text-sm leading-5 hover:text-primary"
|
||||
onclick={() => onFilter?.(hygieneQuery(key))}
|
||||
>
|
||||
{checkLabel(key)}
|
||||
@@ -775,7 +775,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="text-left text-sm leading-5 hover:underline"
|
||||
class="text-left text-sm leading-5 hover:text-primary"
|
||||
onclick={() => onFilter?.(postureQuery(key))}
|
||||
>
|
||||
{spec?.label ?? key}
|
||||
|
||||
@@ -515,7 +515,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="inline-flex items-center gap-1 font-mono text-xs hover:underline {httpStatusTextClass(
|
||||
class="inline-flex items-center gap-1 font-mono text-xs hover:text-primary {httpStatusTextClass(
|
||||
code
|
||||
)}"
|
||||
onclick={(e) => pivot(e, `status:${code}`)}
|
||||
@@ -604,7 +604,7 @@
|
||||
<button
|
||||
{...props}
|
||||
type="button"
|
||||
class="max-w-full truncate text-left font-mono text-xs hover:underline {isPrivateIp(
|
||||
class="max-w-full truncate text-left font-mono text-xs hover:text-primary {isPrivateIp(
|
||||
ip
|
||||
)
|
||||
? 'text-warning'
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
{#if summary.clean > 0}
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center gap-1 text-left text-primary hover:underline {cleanOn
|
||||
class="flex items-center gap-1 text-left text-primary hover:text-primary/80 {cleanOn
|
||||
? 'font-medium'
|
||||
: ''}"
|
||||
aria-pressed={cleanOn}
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
{#if summary.clean > 0}
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center gap-1 text-left text-primary hover:underline {cleanOn
|
||||
class="flex items-center gap-1 text-left text-primary hover:text-primary/80 {cleanOn
|
||||
? 'font-medium'
|
||||
: ''}"
|
||||
aria-pressed={cleanOn}
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => onHost(host)}
|
||||
class="truncate text-left font-mono text-2xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="truncate text-left font-mono text-2xs text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
{host}
|
||||
</button>
|
||||
@@ -164,7 +164,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => onFilter(g.query)}
|
||||
class="truncate text-left text-2xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="truncate text-left text-2xs text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
Open all {g.count}
|
||||
</button>
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
</span>
|
||||
<a
|
||||
href={ROUTES.target(row.target_id)}
|
||||
class="min-w-0 flex-1 truncate text-xs leading-5 hover:underline"
|
||||
class="min-w-0 flex-1 truncate text-xs leading-5 hover:text-primary"
|
||||
>
|
||||
{row.target_value}
|
||||
</a>
|
||||
@@ -95,7 +95,7 @@
|
||||
{#if row.scan_id}
|
||||
<a
|
||||
href={ROUTES.scan(row.scan_id)}
|
||||
class="shrink-0 text-2xs leading-5 text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="shrink-0 text-2xs leading-5 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
run
|
||||
</a>
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
<div class="flex min-w-0 items-center gap-1.5">
|
||||
<a
|
||||
href={ROUTES.target(target.id)}
|
||||
class="truncate font-mono text-sm font-medium hover:underline"
|
||||
class="truncate font-mono text-sm font-medium hover:text-primary"
|
||||
onclick={stopProp}>{target.target_value}</a
|
||||
>
|
||||
<CopyButton
|
||||
|
||||
@@ -215,7 +215,9 @@
|
||||
{/if}
|
||||
{#if note.text}<span class="truncate">{note.text}</span>{/if}
|
||||
{#if href}
|
||||
<a {href} class="font-medium text-primary hover:underline">open in {IPS.label}</a>
|
||||
<a {href} class="font-medium text-primary hover:text-primary/80"
|
||||
>open in {IPS.label}</a
|
||||
>
|
||||
{/if}
|
||||
</span>
|
||||
<span
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
{/if}
|
||||
<a
|
||||
href={ROUTES.whatsNew({ window: '30d', target: target.id })}
|
||||
class="text-xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="text-xs text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
What's new
|
||||
</a>
|
||||
@@ -184,7 +184,7 @@
|
||||
</span>
|
||||
<span class="flex min-w-0 flex-col gap-1.5 pb-[18px]">
|
||||
<span class="flex flex-wrap items-center gap-x-2 gap-y-1 text-sm">
|
||||
<a href={ROUTES.scan(s.id)} class="font-semibold hover:underline">{s.engine_name}</a>
|
||||
<a href={ROUTES.scan(s.id)} class="font-semibold hover:text-primary">{s.engine_name}</a>
|
||||
<span
|
||||
class="rounded-full px-[7px] text-2xs font-semibold tracking-[0.02em] {SCAN_STATUS_PILL[
|
||||
s.status
|
||||
@@ -240,7 +240,7 @@
|
||||
</span>
|
||||
<span class="flex min-w-0 flex-col gap-1 pb-3.5">
|
||||
<span class="flex flex-wrap items-center gap-x-2 gap-y-1 text-sm">
|
||||
<a href={ROUTES.scan(r.id)} class="font-medium hover:underline">{r.engine_name}</a>
|
||||
<a href={ROUTES.scan(r.id)} class="font-medium hover:text-primary">{r.engine_name}</a>
|
||||
<span
|
||||
class="rounded-full px-[7px] text-2xs font-semibold tracking-[0.02em] {SCAN_STATUS_PILL[
|
||||
r.status
|
||||
|
||||
@@ -112,7 +112,11 @@
|
||||
</dl>
|
||||
{#snippet footer()}
|
||||
<span>{enrichedAt ? `Enriched ${relativeTime(enrichedAt)}` : 'Not enriched'}</span>
|
||||
<button type="button" class="font-medium text-primary hover:underline" onclick={onRefresh}>
|
||||
<button
|
||||
type="button"
|
||||
class="font-medium text-primary hover:text-primary/80"
|
||||
onclick={onRefresh}
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
{/snippet}
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
href={scanHref}
|
||||
class="truncate font-mono text-sm {asset.current
|
||||
? ''
|
||||
: 'text-muted-foreground line-through decoration-muted-foreground/40'} hover:underline"
|
||||
: 'text-muted-foreground line-through decoration-muted-foreground/40'} hover:text-primary"
|
||||
>
|
||||
<HighlightText text={asset.name} terms={[term]} />
|
||||
</a>
|
||||
|
||||
@@ -287,7 +287,7 @@
|
||||
</Badge>
|
||||
{/if}
|
||||
<a
|
||||
class="inline-flex min-w-0 items-center gap-1 truncate font-mono text-2xs text-muted-foreground hover:text-foreground hover:underline"
|
||||
class="inline-flex min-w-0 items-center gap-1 truncate font-mono text-2xs text-muted-foreground hover:text-foreground"
|
||||
href={poc.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
data-slot="accordion-trigger"
|
||||
bind:ref
|
||||
class={cn(
|
||||
'focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-start text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180',
|
||||
'focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-start text-sm font-medium transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180',
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
'bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border shadow-xs',
|
||||
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-xs',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
||||
link: 'text-primary underline-offset-4 hover:underline'
|
||||
link: 'text-primary hover:text-primary/80'
|
||||
},
|
||||
size: {
|
||||
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
|
||||
|
||||
@@ -103,7 +103,10 @@
|
||||
{#if entity.email}
|
||||
<div class="flex items-start gap-2.5">
|
||||
<Mail class="h-3.5 w-3.5 text-muted-foreground mt-0.5 shrink-0" />
|
||||
<a href="mailto:{entity.email}" class="text-sm text-primary hover:underline">
|
||||
<a
|
||||
href="mailto:{entity.email}"
|
||||
class="text-sm text-primary hover:text-primary/80"
|
||||
>
|
||||
{entity.email}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -381,7 +381,7 @@
|
||||
<p class="mt-5 text-xs text-muted-foreground">
|
||||
<button
|
||||
type="button"
|
||||
class="font-medium text-foreground underline-offset-4 hover:underline"
|
||||
class="font-medium text-foreground hover:text-primary"
|
||||
onclick={() => (showImportDialog = true)}
|
||||
>
|
||||
Import a YAML file
|
||||
|
||||
@@ -475,7 +475,7 @@
|
||||
href="{platformUrl}/{summary.username}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center gap-0.5 font-mono text-foreground hover:underline"
|
||||
class="flex items-center gap-0.5 font-mono text-foreground hover:text-primary"
|
||||
>
|
||||
@{summary.username}<ArrowUpRight class="size-3" />
|
||||
</a>
|
||||
|
||||
@@ -194,17 +194,17 @@
|
||||
{#if headline.critical}
|
||||
<a
|
||||
href={headlineHref(VULNS, `severity:critical and ${NEW_IN_WINDOW}`)}
|
||||
class="text-destructive hover:underline"
|
||||
class="text-destructive hover:text-destructive/80"
|
||||
>{plural(headline.critical, 'critical finding', 'critical findings')}</a
|
||||
>
|
||||
and
|
||||
{/if}
|
||||
<a href={headlineHref(VULNS, NEW_IN_WINDOW)} class="hover:underline"
|
||||
<a href={headlineHref(VULNS, NEW_IN_WINDOW)} class="hover:text-primary"
|
||||
>{plural(headline.findings, 'finding', 'findings')}</a
|
||||
>
|
||||
in {days} days.
|
||||
<span class="font-medium text-muted-foreground">
|
||||
<a href={headlineHref(WEB, NEW_IN_WINDOW)} class="hover:underline"
|
||||
<a href={headlineHref(WEB, NEW_IN_WINDOW)} class="hover:text-primary"
|
||||
>{plural(headline.web, 'new web asset', 'new web assets')}</a
|
||||
>{headline.targets ? ` on ${plural(headline.targets, 'target', 'targets')}` : ''}.
|
||||
</span>
|
||||
|
||||
@@ -1014,7 +1014,7 @@
|
||||
{#if surfaceLink}
|
||||
<a
|
||||
href={surfaceLink}
|
||||
class="hidden shrink-0 items-center gap-1 py-2.5 pl-2 text-xs whitespace-nowrap text-muted-foreground hover:text-foreground hover:underline sm:flex"
|
||||
class="hidden shrink-0 items-center gap-1 py-2.5 pl-2 text-xs whitespace-nowrap text-muted-foreground hover:text-foreground sm:flex"
|
||||
>
|
||||
Across all targets
|
||||
<ArrowUpRight class="size-3.5" />
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
{#if description.length > DESCRIPTION_CLAMP}
|
||||
<button
|
||||
type="button"
|
||||
class="ml-1 text-xs text-foreground hover:underline"
|
||||
class="ml-1 text-xs text-foreground hover:text-primary"
|
||||
onclick={() => (showDescription = !showDescription)}
|
||||
>
|
||||
{showDescription ? 'Show less' : 'Show more'}
|
||||
|
||||
@@ -945,7 +945,7 @@
|
||||
{#if selectedTargetIds.size >= rows.length && selectedTargetIds.size < targetsStore.pagination.totalItems}
|
||||
<button
|
||||
type="button"
|
||||
class="text-xs font-medium text-primary hover:underline"
|
||||
class="text-xs font-medium text-primary hover:text-primary/80"
|
||||
onclick={handleSelectAllMatching}
|
||||
>
|
||||
Select all {targetsStore.pagination.totalItems} matching
|
||||
|
||||
Reference in New Issue
Block a user