mirror of
https://github.com/anotherhadi/iknowyou.git
synced 2026-04-12 00:47:26 +02:00
Responsive
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
This commit is contained in:
@@ -87,17 +87,27 @@
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Logo à gauche sur écran moyen et grand -->
|
||||
<a
|
||||
href="/"
|
||||
class="btn btn-ghost text-xl flex justify-center gap-2 items-center"
|
||||
class="btn btn-ghost text-xl hidden sm:flex justify-center gap-2 items-center"
|
||||
>
|
||||
<img src="/logo.svg" class="m-auto h-6" alt="iky logo" />
|
||||
<img src="/logo-large.svg" class="m-auto h-6" alt="iky logo large" />
|
||||
<img src="/logo.svg" class="m-auto h-4 lg:h-6" alt="iky logo" />
|
||||
<img src="/logo-large.svg" class="m-auto h-4 lg:h-6" alt="iky logo large" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<div class="navbar-center lg:flex">
|
||||
<!-- Logo centré sur petit écran (mobile) -->
|
||||
<a
|
||||
href="/"
|
||||
class="btn btn-ghost text-xl flex sm:hidden justify-center gap-2 items-center"
|
||||
>
|
||||
<img src="/logo.svg" class="m-auto h-4" alt="iky logo" />
|
||||
<img src="/logo-large.svg" class="m-auto h-4" alt="iky logo large" />
|
||||
</a>
|
||||
<!-- Nav links sur grand écran -->
|
||||
<ul class="menu menu-horizontal px-1 hidden lg:flex">
|
||||
{#each navLinks as link}
|
||||
<li>
|
||||
{#if link.children}
|
||||
|
||||
@@ -164,19 +164,19 @@
|
||||
onselect={(v) => { profile = v; }}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-primary btn-sm flex-1 gap-1"
|
||||
onclick={submit}
|
||||
disabled={demo || loading || !target.trim()}
|
||||
>
|
||||
{#if loading}
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
{:else}
|
||||
<Search size={14} />
|
||||
{/if}
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-primary btn-sm w-full gap-1"
|
||||
onclick={submit}
|
||||
disabled={demo || loading || !target.trim()}
|
||||
>
|
||||
{#if loading}
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
{:else}
|
||||
<Search size={14} />
|
||||
{/if}
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Desktop layout -->
|
||||
|
||||
@@ -28,42 +28,48 @@
|
||||
href={`/search/${s.id}`}
|
||||
class="card bg-base-200 hover:bg-base-300 transition-colors shadow-sm cursor-pointer"
|
||||
>
|
||||
<div class="card-body flex-row items-center gap-4 py-3 px-4">
|
||||
<div class="text-base-content/40 w-6 flex items-center justify-center shrink-0">
|
||||
{#each [INPUT_TYPE_ICON[s.input_type] ?? FileText] as Icon}
|
||||
<Icon size={16} />
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex flex-col min-w-0 flex-1">
|
||||
<span class="font-mono font-semibold truncate">{s.target}</span>
|
||||
<div class="flex items-center gap-1.5 flex-wrap text-xs text-base-content/50">
|
||||
<span>{s.input_type}</span>
|
||||
{#if s.profile}
|
||||
<span class="badge badge-outline badge-xs font-semibold">{s.profile}</span>
|
||||
{/if}
|
||||
<span>· {fmtDate(s.started_at)}</span>
|
||||
<div class="card-body py-3 px-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<!-- Icon -->
|
||||
<div class="text-base-content/40 flex items-center justify-center shrink-0 mt-0.5">
|
||||
{#each [INPUT_TYPE_ICON[s.input_type] ?? FileText] as Icon}
|
||||
<Icon size={16} />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- Target + meta -->
|
||||
<div class="flex flex-col min-w-0 flex-1 gap-0.5">
|
||||
<span class="font-mono font-semibold truncate leading-snug">{s.target}</span>
|
||||
<div class="flex items-center gap-1.5 flex-wrap text-xs text-base-content/50">
|
||||
<span>{s.input_type}</span>
|
||||
{#if s.profile}
|
||||
<span class="badge badge-outline badge-xs font-semibold">{s.profile}</span>
|
||||
{/if}
|
||||
<span>· {fmtDate(s.started_at)}</span>
|
||||
{#if s.status !== "running"}
|
||||
{@const total = (s.planned_tools ?? []).reduce((sum, t) => sum + (t.result_count ?? 0), 0)}
|
||||
{#if total > 0}
|
||||
<span>· {total} result{total !== 1 ? "s" : ""}</span>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status + delete -->
|
||||
<div class="flex items-center gap-1.5 shrink-0 ml-auto">
|
||||
<span class="badge {STATUS_BADGE[s.status] ?? 'badge-ghost'} badge-sm">
|
||||
{#if s.status === "running"}
|
||||
<span class="loading loading-ring loading-xs mr-1"></span>
|
||||
{/if}
|
||||
{s.status}
|
||||
</span>
|
||||
<button
|
||||
class="btn btn-ghost btn-xs text-base-content/30 hover:text-error"
|
||||
onclick={(e) => { e.preventDefault(); onDelete(s.id); }}
|
||||
title="Delete"
|
||||
><X size={14} /></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if s.status !== "running"}
|
||||
{@const total = (s.planned_tools ?? []).reduce((sum, t) => sum + (t.result_count ?? 0), 0)}
|
||||
{#if total > 0}
|
||||
<span class="text-xs font-mono text-base-content/50 shrink-0">{total} result{total !== 1 ? "s" : ""}</span>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<span class="badge {STATUS_BADGE[s.status] ?? 'badge-ghost'} badge-sm shrink-0">
|
||||
{#if s.status === "running"}
|
||||
<span class="loading loading-ring loading-xs mr-1"></span>
|
||||
{/if}
|
||||
{s.status}
|
||||
</span>
|
||||
|
||||
<button
|
||||
class="btn btn-ghost btn-xs text-base-content/30 hover:text-error shrink-0"
|
||||
onclick={(e) => { e.preventDefault(); onDelete(s.id); }}
|
||||
title="Delete"
|
||||
><X size={14} /></button>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
let error = $state("");
|
||||
|
||||
let selectedInputType = $state("all");
|
||||
let nameFilter = $state("");
|
||||
|
||||
const inputTypeOptions = ["all", ...INPUT_TYPES];
|
||||
|
||||
@@ -47,11 +48,14 @@
|
||||
);
|
||||
|
||||
let visibleTools = $derived(
|
||||
selectedInputType === "all"
|
||||
? toolsWithStatus
|
||||
: toolsWithStatus.filter((t) =>
|
||||
t.input_types.includes(selectedInputType),
|
||||
),
|
||||
toolsWithStatus.filter((t) => {
|
||||
const matchesInput =
|
||||
selectedInputType === "all" || t.input_types.includes(selectedInputType);
|
||||
const matchesName =
|
||||
nameFilter.trim() === "" ||
|
||||
t.name.toLowerCase().includes(nameFilter.trim().toLowerCase());
|
||||
return matchesInput && matchesName;
|
||||
}),
|
||||
);
|
||||
|
||||
let active = $derived(
|
||||
@@ -170,6 +174,19 @@
|
||||
<div class="alert alert-error gap-3"><AlertTriangle size={18} class="shrink-0" />{error}</div>
|
||||
{:else}
|
||||
<div class="flex flex-wrap items-center gap-x-6 gap-y-3 mb-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<span
|
||||
class="text-xs uppercase tracking-widest text-base-content/50 shrink-0"
|
||||
>Search</span
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
class="input input-sm input-bordered w-40"
|
||||
placeholder="tool name..."
|
||||
bind:value={nameFilter}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
<span
|
||||
class="text-xs uppercase tracking-widest text-base-content/50 shrink-0"
|
||||
|
||||
@@ -42,7 +42,7 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site ?? Astro.url.origin)
|
||||
slot="action"
|
||||
target="_blank"
|
||||
class="btn btn-primary btn-sm"
|
||||
><Coffee class="size-3" /> Support me</a
|
||||
><Coffee class="size-3" /><span class="hidden sm:inline">Support me</span></a
|
||||
>
|
||||
</Navbar>
|
||||
<div class="m-auto max-w-5xl md:py-10 md:px-10 py-5 px-5 animate-fade-in">
|
||||
|
||||
Reference in New Issue
Block a user