vojtam commited on
Commit
88f4632
·
1 Parent(s): 89fed47
src/App.svelte CHANGED
@@ -1,47 +1,84 @@
1
  <script lang="ts">
2
- import svelteLogo from './assets/svelte.svg'
3
- import viteLogo from '/vite.svg'
4
- import Counter from './lib/Counter.svelte'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  </script>
6
 
7
- <main>
8
- <div>
9
- <a href="https://vite.dev" target="_blank" rel="noreferrer">
10
- <img src={viteLogo} class="logo" alt="Vite Logo" />
11
- </a>
12
- <a href="https://svelte.dev" target="_blank" rel="noreferrer">
13
- <img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
14
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  </div>
16
- <h1>Vite + Svelte</h1>
17
 
18
- <div class="card">
19
- <Counter />
 
 
 
 
20
  </div>
 
21
 
22
- <p>
23
- Check out <a href="https://github.com/sveltejs/kit#readme" target="_blank" rel="noreferrer">SvelteKit</a>, the official Svelte app framework powered by Vite!
24
- </p>
25
-
26
- <p class="read-the-docs">
27
- Click on the Vite and Svelte logos to learn more
28
- </p>
29
- </main>
30
-
31
- <style>
32
- .logo {
33
- height: 6em;
34
- padding: 1.5em;
35
- will-change: filter;
36
- transition: filter 300ms;
37
- }
38
- .logo:hover {
39
- filter: drop-shadow(0 0 2em #646cffaa);
40
- }
41
- .logo.svelte:hover {
42
- filter: drop-shadow(0 0 2em #ff3e00aa);
43
- }
44
- .read-the-docs {
45
- color: #888;
46
- }
47
- </style>
 
1
  <script lang="ts">
2
+ import ImageCard from "./lib/components/ImageCard.svelte";
3
+ import ImageModal from "./lib/components/ImageModal.svelte";
4
+ import { onMount } from "svelte";
5
+ import Papa from "papaparse";
6
+ import "simple-datatables/dist/style.css";
7
+ let rows: string[][] = [];
8
+ let headers: string[] = [];
9
+ let tableEl: HTMLTableElement;
10
+
11
+ let items: any[] = [];
12
+ let q = "";
13
+ let active: any = null;
14
+
15
+ export function fmt2(val: any) {
16
+ const num = Number(val);
17
+ if (isNaN(num)) return val;
18
+ return num.toFixed(2);
19
+ }
20
+
21
+ onMount(async () => {
22
+ const res = await fetch("/data/manifest.json");
23
+ items = await res.json();
24
+ const csv = await (await fetch("/data/results_avg_stats.csv")).text();
25
+ const { data } = Papa.parse<string[]>(csv, { header: false });
26
+ headers = data.shift() ?? [];
27
+ rows = data;
28
+
29
+ // init Simple-DataTables after the table renders
30
+ const { DataTable } = await import("simple-datatables");
31
+ new DataTable(tableEl, {
32
+ searchable: true,
33
+ fixedHeight: true,
34
+ perPage: 25,
35
+ });
36
+ });
37
+
38
+ $: filtered = q
39
+ ? items.filter((i) =>
40
+ (i.file + " " + (i.labels || []).join(" "))
41
+ .toLowerCase()
42
+ .includes(q.toLowerCase()),
43
+ )
44
+ : items;
45
  </script>
46
 
47
+ <div class="p-4 max-w-7xl mx-auto">
48
+ <div class="p-4 overflow-x-auto">
49
+ <table bind:this={tableEl} class="min-w-full">
50
+ <thead>
51
+ <tr
52
+ >{#each headers as h}<th class="text-left p-2">{h}</th>{/each}</tr
53
+ >
54
+ </thead>
55
+ <tbody>
56
+ {#each rows as r}
57
+ <tr
58
+ >{#each r as cell}<td class="p-2">{fmt2(cell)}</td>{/each}</tr
59
+ >
60
+ {/each}
61
+ </tbody>
62
+ </table>
63
+ </div>
64
+ <div class="flex gap-3 items-center mb-4">
65
+ <input
66
+ class="input input-bordered w-full"
67
+ placeholder="Search by filename or label…"
68
+ bind:value={q}
69
+ />
70
+ <span class="text-sm opacity-70">{filtered.length} / {items.length}</span>
71
  </div>
 
72
 
73
+ <div
74
+ class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-3"
75
+ >
76
+ {#each filtered as item (item.id)}
77
+ <ImageCard {item} on:open={() => (active = item)} />
78
+ {/each}
79
  </div>
80
+ </div>
81
 
82
+ {#if active}
83
+ <ImageModal {active} on:close={() => (active = null)} />
84
+ {/if}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/app.css CHANGED
@@ -1,79 +1,2 @@
1
- :root {
2
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
- line-height: 1.5;
4
- font-weight: 400;
5
-
6
- color-scheme: light dark;
7
- color: rgba(255, 255, 255, 0.87);
8
- background-color: #242424;
9
-
10
- font-synthesis: none;
11
- text-rendering: optimizeLegibility;
12
- -webkit-font-smoothing: antialiased;
13
- -moz-osx-font-smoothing: grayscale;
14
- }
15
-
16
- a {
17
- font-weight: 500;
18
- color: #646cff;
19
- text-decoration: inherit;
20
- }
21
- a:hover {
22
- color: #535bf2;
23
- }
24
-
25
- body {
26
- margin: 0;
27
- display: flex;
28
- place-items: center;
29
- min-width: 320px;
30
- min-height: 100vh;
31
- }
32
-
33
- h1 {
34
- font-size: 3.2em;
35
- line-height: 1.1;
36
- }
37
-
38
- .card {
39
- padding: 2em;
40
- }
41
-
42
- #app {
43
- max-width: 1280px;
44
- margin: 0 auto;
45
- padding: 2rem;
46
- text-align: center;
47
- }
48
-
49
- button {
50
- border-radius: 8px;
51
- border: 1px solid transparent;
52
- padding: 0.6em 1.2em;
53
- font-size: 1em;
54
- font-weight: 500;
55
- font-family: inherit;
56
- background-color: #1a1a1a;
57
- cursor: pointer;
58
- transition: border-color 0.25s;
59
- }
60
- button:hover {
61
- border-color: #646cff;
62
- }
63
- button:focus,
64
- button:focus-visible {
65
- outline: 4px auto -webkit-focus-ring-color;
66
- }
67
-
68
- @media (prefers-color-scheme: light) {
69
- :root {
70
- color: #213547;
71
- background-color: #ffffff;
72
- }
73
- a:hover {
74
- color: #747bff;
75
- }
76
- button {
77
- background-color: #f9f9f9;
78
- }
79
- }
 
1
+ @import 'tailwindcss';
2
+ @plugin '@tailwindcss/typography';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/Counter.svelte DELETED
@@ -1,10 +0,0 @@
1
- <script lang="ts">
2
- let count: number = $state(0)
3
- const increment = () => {
4
- count += 1
5
- }
6
- </script>
7
-
8
- <button onclick={increment}>
9
- count is {count}
10
- </button>
 
 
 
 
 
 
 
 
 
 
 
src/lib/assets/favicon.svg ADDED
src/lib/components/ImageCard.svelte ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ export let item: any;
3
+ import { createEventDispatcher } from 'svelte';
4
+ const dispatch = createEventDispatcher();
5
+ </script>
6
+
7
+ <button class="group relative rounded-xl overflow-hidden shadow" on:click={() => dispatch('open')}>
8
+ <img loading="lazy" src={item.thumb} alt={item.file} class="w-full h-auto block" />
9
+ <div
10
+ class="absolute bottom-0 left-0 right-0 bg-black/50 text-white text-xs p-2 flex justify-between"
11
+ >
12
+ <span class="truncate">{item.file}</span>
13
+ {#if item.score}<span>{Math.round(item.score.levenshtein * 100)}%</span>{/if}
14
+ </div>
15
+ </button>
src/lib/components/ImageModal.svelte ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { createEventDispatcher } from 'svelte';
3
+ import JsonView from './JsonView.svelte';
4
+ export let active: any;
5
+ const dispatch = createEventDispatcher();
6
+ </script>
7
+
8
+ <div
9
+ class="fixed inset-0 bg-black/60 flex items-center justify-center p-4 z-50"
10
+ role="dialog"
11
+ aria-modal="true"
12
+ aria-label="Image preview"
13
+ tabindex="0"
14
+ on:click={(e) => {
15
+ if (e.target === e.currentTarget) dispatch('close');
16
+ }}
17
+ on:keydown={(e) => {
18
+ if (e.key === 'Escape' || e.key === 'Enter' || e.key === ' ') dispatch('close');
19
+ }}
20
+ >
21
+ <div
22
+ class="bg-white rounded-2xl w-full max-w-6xl shadow-xl max-h-[90vh] overflow-hidden flex flex-col"
23
+ role="document"
24
+ tabindex="-1"
25
+ >
26
+ <div class="flex items-center justify-between p-3 border-b sticky top-0 bg-white z-20">
27
+ <h2 class="font-semibold">{active.file}</h2>
28
+ <button class="btn btn-sm" on:click={() => dispatch('close')}>Close</button>
29
+ </div>
30
+
31
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-0 min-h-0 flex-1 overflow-auto">
32
+ <div class="min-h-0 flex items-center justify-center bg-neutral-50">
33
+ <img src={active.full} alt={active.file} class="w-full object-contain max-h-[80vh]" />
34
+ </div>
35
+ <div class="p-4 space-y-4 overflow-auto min-h-0">
36
+ <section>
37
+ <h3 class="font-semibo/ld mb-1">Prediction</h3>
38
+ <JsonView data={active.prediction} />
39
+ </section>
40
+ <section>
41
+ <h3 class="font-semibold mb-1">Ground truth</h3>
42
+ <JsonView data={active.ground_truth} />
43
+ </section>
44
+ {#if active.score}
45
+ <section>
46
+ <h3 class="font-semibold mb-1">Scores</h3>
47
+ <JsonView data={active.score} />
48
+ </section>
49
+ {/if}
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </div>
src/lib/components/JsonView.svelte ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ export let data: any;
3
+ </script>
4
+
5
+ <pre class="text-xs leading-5 p-3 bg-neutral-100 rounded-lg overflow-auto">
6
+ {JSON.stringify(data, null, 2)}
7
+ </pre>
src/lib/index.ts ADDED
@@ -0,0 +1 @@
 
 
1
+ // place files you want to import through the `$lib` alias in this folder.