mirror of
https://github.com/jzillmann/pdf-to-markdown.git
synced 2025-01-07 22:28:58 +01:00
Page selection
This commit is contained in:
parent
8783e3cf9e
commit
93d067b346
@ -5,7 +5,7 @@
|
|||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="description" content="Web site created using create-snowpack-app" />
|
<meta name="description" content="Web site created using create-snowpack-app" />
|
||||||
<title>Snowpack App</title>
|
<title>PDF to Markdown</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import type ParseResult from 'pdf-to-markdown-core/lib/src/ParseResult';
|
import type ParseResult from 'pdf-to-markdown-core/lib/src/ParseResult';
|
||||||
import type Item from '@core/Item';
|
|
||||||
import Table from './Table.svelte';
|
import Table from './Table.svelte';
|
||||||
|
|
||||||
export let parseResult: ParseResult;
|
export let parseResult: ParseResult;
|
||||||
|
@ -1,11 +1,74 @@
|
|||||||
<script>
|
<script>
|
||||||
import type Item from '@core/Item';
|
import type Item from '@core/Item';
|
||||||
|
import { Collection, BookOpen, Support, ArrowLeft, ArrowRight } from 'svelte-hero-icons';
|
||||||
|
|
||||||
export let columns: string[];
|
export let columns: string[];
|
||||||
export let items: Item[];
|
export let items: Item[];
|
||||||
|
const pages = [...new Set(items.map((item) => item.page))];
|
||||||
|
const maxPage = Math.max(...pages);
|
||||||
|
let focusedPage: number;
|
||||||
|
$: focused = typeof focusedPage === 'number';
|
||||||
|
let openedPageIndex = false;
|
||||||
|
|
||||||
|
const itemsGroupedByPage = items.reduce((map, item) => {
|
||||||
|
if (!map.has(item.page)) {
|
||||||
|
map.set(item.page, []);
|
||||||
|
}
|
||||||
|
map.get(item.page).push(item);
|
||||||
|
return map;
|
||||||
|
}, new Map<number, Item[]>());
|
||||||
|
|
||||||
|
function focusOnPage(pageNumber: number) {
|
||||||
|
openedPageIndex = false;
|
||||||
|
focusedPage = pageNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAllPages() {
|
||||||
|
openedPageIndex = false;
|
||||||
|
focusedPage = undefined;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Sticky Controls -->
|
||||||
|
<div class="controls pb-3">
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<span>
|
||||||
|
<span on:click={() => (openedPageIndex = !openedPageIndex)}>
|
||||||
|
<BookOpen size="1x" class="hover:text-green-700 cursor-pointer" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- Page selection popup-->
|
||||||
|
{#if openedPageIndex}
|
||||||
|
<div class="absolute mt-2 p-2 flex bg-gray-200 shadow-lg rounded-sm overflow-auto max-h-96">
|
||||||
|
<span class="mt-1 pr-2" on:click={showAllPages}>
|
||||||
|
<Collection size="1x" class="hover:text-green-700 cursor-pointer" />
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="grid gap-3"
|
||||||
|
style="grid-template-columns: repeat({Math.min(20, maxPage + 1)}, minmax(0, 1fr));">
|
||||||
|
{#each new Array(maxPage + 1) as _, idx}
|
||||||
|
<div
|
||||||
|
on:click={() => itemsGroupedByPage.has(idx) && focusOnPage(idx)}
|
||||||
|
class="px-2 border border-gray-300 rounded-full text-center {itemsGroupedByPage.has(idx) ? 'hover:text-green-700 hover:border-green-700 cursor-pointer' : 'opacity-50'}">
|
||||||
|
{idx}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div>|</div>
|
||||||
|
<div>Transformation:</div>
|
||||||
|
<ArrowLeft size="1x" class="hover:text-green-700 cursor-pointer opacity-50" />
|
||||||
|
<div>Parse Result</div>
|
||||||
|
<ArrowRight size="1x" class="hover:text-green-700 cursor-pointer" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Item table -->
|
||||||
<table class="w-full text-left">
|
<table class="w-full text-left">
|
||||||
|
<!-- Sticky header -->
|
||||||
<thead class=" ">
|
<thead class=" ">
|
||||||
<th />
|
<th />
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
@ -14,31 +77,67 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each items as item, idx}
|
{#each [...itemsGroupedByPage].filter(([page]) => !focused || page === focusedPage) as [pageNumber, items], pageIdx}
|
||||||
{#if idx > 0 && item.page !== items[idx - 1].page}
|
<!-- Separator between pages -->
|
||||||
<tr class="h-5 bg-blue-200" />
|
{#if pageIdx > 0}
|
||||||
|
<tr class="h-5" />
|
||||||
{/if}
|
{/if}
|
||||||
<tr class="">
|
{#each items as item, itemIdx}
|
||||||
{#if idx === 0 || item.page !== items[idx - 1].page}
|
<tr>
|
||||||
<td class="page bg-gray-50">Page {item.page}</td>
|
<!-- Page number in first page item row -->
|
||||||
|
{#if itemIdx === 0}
|
||||||
|
<td class="page bg-gray-50">
|
||||||
|
<div>Page {pageNumber} {focused ? '' : ' / ' + maxPage}</div>
|
||||||
|
<div class="absolute flex">
|
||||||
|
{#if !focused}
|
||||||
|
<span on:click={() => focusOnPage(pageNumber)}>
|
||||||
|
<Support size="1x" class="hover:text-green-700 cursor-pointer" />
|
||||||
|
</span>
|
||||||
|
{:else}
|
||||||
|
<span on:click={showAllPages}>
|
||||||
|
<Collection size="1x" class="hover:text-green-700 cursor-pointer" />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
{:else}
|
{:else}
|
||||||
<td />
|
<td />
|
||||||
{/if}
|
{/if}
|
||||||
<td class="">{idx}</td>
|
<td class="">{itemIdx}</td>
|
||||||
{#each columns as column}
|
{#each columns as column}
|
||||||
<td class="borde2r">{item.data[column]}</td>
|
<td class="borde2r">{item.data[column]}</td>
|
||||||
{/each}
|
{/each}
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.controls {
|
||||||
|
@apply bg-gray-50;
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
@apply text-lg;
|
||||||
|
@apply font-semibold;
|
||||||
|
@apply pr-4;
|
||||||
|
@apply whitespace-nowrap;
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
top: 1.7em;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
@apply px-1;
|
@apply px-1;
|
||||||
position: -webkit-sticky;
|
position: -webkit-sticky;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 2.1em;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
th:not(:first-child) {
|
th:not(:first-child) {
|
||||||
@ -53,15 +152,4 @@
|
|||||||
tr:hover td:not(:first-child) {
|
tr:hover td:not(:first-child) {
|
||||||
@apply bg-gray-200;
|
@apply bg-gray-200;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
|
||||||
@apply text-lg;
|
|
||||||
@apply font-semibold;
|
|
||||||
@apply pr-4;
|
|
||||||
@apply whitespace-nowrap;
|
|
||||||
position: -webkit-sticky;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user