mirror of
https://github.com/jzillmann/pdf-to-markdown.git
synced 2025-06-26 20:41:27 +02:00
Remove UI package
This commit is contained in:
parent
02c2fd04fe
commit
e56d70c599
4
ui/.gitignore
vendored
4
ui/.gitignore
vendored
@ -1,4 +0,0 @@
|
|||||||
.build
|
|
||||||
build
|
|
||||||
web_modules
|
|
||||||
node_modules
|
|
@ -1,2 +0,0 @@
|
|||||||
package-lock.json
|
|
||||||
public/build/
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"svelteSortOrder": "scripts-markup-styles",
|
|
||||||
"printWidth": 120,
|
|
||||||
"tabWidth": 4,
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"endOfLine": "lf"
|
|
||||||
}
|
|
16
ui/README.md
16
ui/README.md
@ -1,16 +0,0 @@
|
|||||||
# PDF-To-Markdown Converter Core
|
|
||||||
|
|
||||||
Javascript UI to parse PDF files and convert them into Markdown format. Online at http://pdf2md.morethan.io!
|
|
||||||
|
|
||||||
## Contribute
|
|
||||||
|
|
||||||
Use the [issue tracker](https://github.com/jzillmann/pdf-to-markdown/issues) and/or open [pull requests](https://github.com/jzillmann/pdf-to-markdown/pulls)!
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
- `npm install` Download all necessary npm packages
|
|
||||||
- `npm start` Run local development build
|
|
||||||
|
|
||||||
## Release
|
|
||||||
|
|
||||||
//TBD
|
|
9586
ui/package-lock.json
generated
9586
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,57 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "pdf-to-markdown",
|
|
||||||
"version": "0.2.0",
|
|
||||||
"description": "A PDF to Markdown Converter",
|
|
||||||
"keywords": [
|
|
||||||
"PDF",
|
|
||||||
"Markdown",
|
|
||||||
"Converter"
|
|
||||||
],
|
|
||||||
"author": "Johannes Zillmann",
|
|
||||||
"license": "AGPL-3.0",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/jzillmann/pdf-to-markdown"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "snowpack dev",
|
|
||||||
"build": "snowpack build",
|
|
||||||
"svelte-check": "svelte-check",
|
|
||||||
"test": "web-test-runner \"src/**/*.test.ts\""
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@fortawesome/free-solid-svg-icons": "5.15.2",
|
|
||||||
"pdfjs-dist": "2.6.347",
|
|
||||||
"simple-statistics": "^7.7.0",
|
|
||||||
"string-similarity": "4.0.4",
|
|
||||||
"svelte-file-dropzone": "0.0.15",
|
|
||||||
"uuid": "^8.3.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@snowpack/plugin-build-script": "^2.1.0",
|
|
||||||
"@snowpack/plugin-dotenv": "^2.0.5",
|
|
||||||
"@snowpack/plugin-svelte": "^3.5.2",
|
|
||||||
"@snowpack/plugin-typescript": "^1.2.1",
|
|
||||||
"@snowpack/web-test-runner-plugin": "^0.2.1",
|
|
||||||
"@testing-library/svelte": "^3.0.3",
|
|
||||||
"@types/chai": "^4.2.15",
|
|
||||||
"@types/snowpack-env": "^2.3.2",
|
|
||||||
"@web/test-runner": "^0.10.0",
|
|
||||||
"chai": "^4.3.0",
|
|
||||||
"fa-svelte": "^3.1.0",
|
|
||||||
"postcss": "^8.2.6",
|
|
||||||
"postcss-cli": "^8.3.1",
|
|
||||||
"postcss-import": "^14.0.0",
|
|
||||||
"postcss-load-config": "^3.0.1",
|
|
||||||
"prettier": "^2.2.1",
|
|
||||||
"prettier-plugin-svelte": "^1.4.2",
|
|
||||||
"rollup-plugin-svelte": "^7.1.0",
|
|
||||||
"snowpack": "^3.0.13",
|
|
||||||
"svelte": "^3.34.0",
|
|
||||||
"svelte-check": "^1.1.36",
|
|
||||||
"svelte-hero-icons": "^1.5.0",
|
|
||||||
"svelte-preprocess": "^4.6.9",
|
|
||||||
"tailwindcss": "^2.0.3",
|
|
||||||
"typescript": "^4.2.2"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: [
|
|
||||||
require("postcss-import"),
|
|
||||||
require("tailwindcss"),
|
|
||||||
require("autoprefixer"),
|
|
||||||
],
|
|
||||||
};
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 318 B |
@ -1,19 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<base href="%PUBLIC_URL%" />
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="icon" href="favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<meta name="description" content="Converts PDF files to Markdown." />
|
|
||||||
<meta name="keywords" content="PDF, Markdown, converter, online" />
|
|
||||||
<title>PDF to Markdown</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
||||||
<script type="module" src="dist/index.js"></script>
|
|
||||||
<!--
|
|
||||||
This HTML file is a template.
|
|
||||||
-->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,3 +0,0 @@
|
|||||||
# https://www.robotstxt.org/robotstxt.html
|
|
||||||
User-agent: *
|
|
||||||
Disallow:
|
|
@ -1,36 +0,0 @@
|
|||||||
/** @type {import("snowpack").SnowpackUserConfig } */
|
|
||||||
module.exports = {
|
|
||||||
mount: {
|
|
||||||
public: { url: '/', static: true },
|
|
||||||
src: { url: '/dist' },
|
|
||||||
'../core/src': { url: '/core' },
|
|
||||||
'node_modules/pdfjs-dist/es5/build/': { url: '/worker', static: true },
|
|
||||||
},
|
|
||||||
optimize: {
|
|
||||||
bundle: true,
|
|
||||||
minify: true,
|
|
||||||
target: 'es2020',
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
['@snowpack/plugin-build-script', { cmd: 'postcss', input: ['.css'], output: ['.css'] }],
|
|
||||||
'@snowpack/plugin-svelte',
|
|
||||||
'@snowpack/plugin-dotenv',
|
|
||||||
'@snowpack/plugin-typescript',
|
|
||||||
],
|
|
||||||
packageOptions: {
|
|
||||||
installTypes: true,
|
|
||||||
packageLookupFields: ['svelte', 'module', 'main'],
|
|
||||||
// rollup: { plugins: [require('rollup-plugin-svelte')()] },
|
|
||||||
},
|
|
||||||
devOptions: {
|
|
||||||
port: 3005,
|
|
||||||
},
|
|
||||||
buildOptions: {
|
|
||||||
baseUrl: '/pdf-to-markdown-staging/',
|
|
||||||
metaUrlPath: 'modules',
|
|
||||||
},
|
|
||||||
alias: {
|
|
||||||
'@core': '../core/src/index.js',
|
|
||||||
'@core/*': '../core/src/*',
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,46 +0,0 @@
|
|||||||
<script>
|
|
||||||
import Upload from './main/Upload.svelte';
|
|
||||||
import { blur } from 'svelte/transition';
|
|
||||||
|
|
||||||
import { parseResult, debug } from './store';
|
|
||||||
import DebugView from './debug/DebugView.svelte';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div in:blur={{ duration: 450 }} class="text-2xl font-semibold font-serif text-center bg-gray-400">
|
|
||||||
PDF to Markdown Converter
|
|
||||||
</div>
|
|
||||||
<main class="mt-2 h-full">
|
|
||||||
<div class="transition-container">
|
|
||||||
{#if $debug}
|
|
||||||
<span in:blur={{ duration: 1200 }} out:blur={{ duration: 900 }}>
|
|
||||||
<DebugView debug={$debug} />
|
|
||||||
</span>
|
|
||||||
{:else}
|
|
||||||
<span in:blur={{ duration: 900 }} out:blur={{ duration: 900 }}>
|
|
||||||
<Upload />
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
:global(body) {
|
|
||||||
margin: 0;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
@apply text-gray-800;
|
|
||||||
@apply bg-gray-50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transition-container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: 1;
|
|
||||||
grid-template-columns: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transition-container > * {
|
|
||||||
/* autoprefixer: off */
|
|
||||||
grid-row: 1;
|
|
||||||
/* autoprefixer: off */
|
|
||||||
grid-column: 1;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,11 +0,0 @@
|
|||||||
import {render} from '@testing-library/svelte';
|
|
||||||
import {expect} from 'chai';
|
|
||||||
import App from './App.svelte';
|
|
||||||
|
|
||||||
describe('<App>', () => {
|
|
||||||
it('renders learn svelte link', () => {
|
|
||||||
const {getByText} = render(App);
|
|
||||||
const linkElement = getByText(/learn svelte/i);
|
|
||||||
expect(document.body.contains(linkElement));
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,3 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
@ -1,23 +0,0 @@
|
|||||||
export function clickOutside(node: HTMLElement, { enabled: initialEnabled, cb }) {
|
|
||||||
const handleOutsideClick = ({ target }) => {
|
|
||||||
if (!node.contains(target)) {
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function update({ enabled }) {
|
|
||||||
if (enabled) {
|
|
||||||
window.addEventListener('click', handleOutsideClick);
|
|
||||||
} else {
|
|
||||||
window.removeEventListener('click', handleOutsideClick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update({ enabled: initialEnabled });
|
|
||||||
return {
|
|
||||||
update,
|
|
||||||
destroy() {
|
|
||||||
window.removeEventListener('click', handleOutsideClick);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
export default function inView(node: HTMLElement) {
|
|
||||||
const handleIntersect = (e: IntersectionObserverEntry[]) => {
|
|
||||||
node.dispatchEvent(
|
|
||||||
new CustomEvent('intersect', {
|
|
||||||
detail: e[0].isIntersecting,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const root = null;
|
|
||||||
const rootMargin = `0px 0px 300px 0px`;
|
|
||||||
const options = { root, rootMargin };
|
|
||||||
const observer = new IntersectionObserver(handleIntersect, options);
|
|
||||||
observer.observe(node);
|
|
||||||
|
|
||||||
return {
|
|
||||||
destroy() {
|
|
||||||
if (observer) observer.disconnect();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
<script>
|
|
||||||
export let name: string;
|
|
||||||
export let enabled = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input id="checkbox-{name}" type="checkbox" class="hidden" bind:checked={enabled} />
|
|
||||||
<label
|
|
||||||
for="checkbox-{name}"
|
|
||||||
class="px-1 border-t-2 border-b-2 border-transparent cursor-pointer select-none whitespace-nowrap">{name}</label>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
input:not(:checked) + label:hover {
|
|
||||||
transform: scale(1.1);
|
|
||||||
@apply text-select;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:checked + label:hover {
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
input:checked + label {
|
|
||||||
@apply border-select;
|
|
||||||
}
|
|
||||||
|
|
||||||
input + label:hover:not(:active) {
|
|
||||||
@apply border-dotted;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,5 +0,0 @@
|
|||||||
import type { SvelteComponent } from 'svelte';
|
|
||||||
|
|
||||||
export default class ComponentDefinition {
|
|
||||||
constructor(public component: object, public args: object = {}) {}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { writable } from 'svelte/store';
|
|
||||||
import { setContext } from 'svelte';
|
|
||||||
import { clickOutside } from '../actions/clickOutside';
|
|
||||||
|
|
||||||
let opened = writable(false);
|
|
||||||
setContext('popupOpened', opened);
|
|
||||||
|
|
||||||
function toogle() {
|
|
||||||
opened.update((old) => !old);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<span use:clickOutside={{ enabled: opened, cb: () => opened.set(false) }}>
|
|
||||||
<span on:click={toogle}>
|
|
||||||
<slot name="trigger" opened={$opened} />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{#if $opened}
|
|
||||||
<span class="popupContent">
|
|
||||||
<slot name="content" class="z-20" />
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.popupContent :global(*) {
|
|
||||||
@apply z-30;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,35 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { tweened } from 'svelte/motion';
|
|
||||||
import { cubicOut } from 'svelte/easing';
|
|
||||||
|
|
||||||
export let radius: number;
|
|
||||||
export let stroke: number;
|
|
||||||
export let progress: number;
|
|
||||||
|
|
||||||
const normalizedRadius = radius - stroke * 2;
|
|
||||||
const circumference = normalizedRadius * 2 * Math.PI;
|
|
||||||
const progressTweened = tweened(0, {
|
|
||||||
duration: 400,
|
|
||||||
easing: cubicOut,
|
|
||||||
});
|
|
||||||
$: progressTweened.set(progress);
|
|
||||||
$: strokeDashoffset = circumference - ($progressTweened / 100) * circumference;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svg
|
|
||||||
height={radius * 2}
|
|
||||||
width={radius * 2}
|
|
||||||
class="text-select stroke-current"
|
|
||||||
style="filter: brightness({$progressTweened / 100 / 2 + 0.5}) sepia({0.5 - $progressTweened / 100 / 2}) blur({0.6 - $progressTweened / 100 / 3}px)">
|
|
||||||
<circle
|
|
||||||
fill="transparent"
|
|
||||||
stroke-width={stroke}
|
|
||||||
stroke-dasharray={circumference + ' ' + circumference}
|
|
||||||
stroke-dashoffset={strokeDashoffset}
|
|
||||||
r={normalizedRadius}
|
|
||||||
cx={radius}
|
|
||||||
cy={radius} />
|
|
||||||
<text x="50%" y="53%" text-anchor="middle" class="text-gray-800 fill-current" stroke-width="1px" dy=".2em">
|
|
||||||
{Math.round($progressTweened)}%
|
|
||||||
</text>
|
|
||||||
</svg>
|
|
@ -1,22 +0,0 @@
|
|||||||
import { Writable, writable } from 'svelte/store';
|
|
||||||
import { debugFromParams, debugStageFromParams } from './processParameters';
|
|
||||||
|
|
||||||
export const debugEnabled = storedWritable('debugEnabled', false, debugFromParams);
|
|
||||||
export const debugStage = storedWritable('debugStage', 0, debugStageFromParams);
|
|
||||||
|
|
||||||
function storedWritable<T>(key: string, defaultValue: T, paramLoadFunction: (defaultValue: T) => T): Writable<T> {
|
|
||||||
const value = paramLoadFunction(fromLocalStore(key, defaultValue));
|
|
||||||
const store = writable(value);
|
|
||||||
store.subscribe((value) => {
|
|
||||||
localStorage.setItem(key, JSON.stringify(value));
|
|
||||||
});
|
|
||||||
return store;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fromLocalStore<T>(key: string, defaultValue: T): T {
|
|
||||||
const storedValue = localStorage.getItem(key);
|
|
||||||
if (storedValue === null || storedValue === 'null') {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
return JSON.parse(storedValue);
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
<script>
|
|
||||||
import type EvaluationIndex from '@core/debug/EvaluationIndex';
|
|
||||||
import type ChangeIndex from '@core/debug/ChangeIndex';
|
|
||||||
import type Item from '@core/Item';
|
|
||||||
import { Addition, Removal, ContentChange, PositionChange, Direction } from '../../../core/src/debug/ChangeIndex';
|
|
||||||
import ComponentDefinition from '../components/ComponentDefinition';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PlusCircle as Plus,
|
|
||||||
ExclamationCircle as Changed,
|
|
||||||
MinusCircle as Minus,
|
|
||||||
ArrowCircleUp as Up,
|
|
||||||
ArrowCircleDown as Down,
|
|
||||||
Eye,
|
|
||||||
} from 'svelte-hero-icons';
|
|
||||||
|
|
||||||
export let evaluations: EvaluationIndex;
|
|
||||||
export let changes: ChangeIndex;
|
|
||||||
export let item: Item;
|
|
||||||
|
|
||||||
$: evaluated = evaluations.evaluated(item);
|
|
||||||
$: hasChanged = changes.hasChanged(item);
|
|
||||||
let changeContent: string;
|
|
||||||
let iconComp: ComponentDefinition;
|
|
||||||
$: {
|
|
||||||
let args = { size: '14' };
|
|
||||||
if (hasChanged) {
|
|
||||||
let change = changes.change(item);
|
|
||||||
switch (change.constructor.name) {
|
|
||||||
case PositionChange.name:
|
|
||||||
const positionChange = change as PositionChange;
|
|
||||||
changeContent = `${positionChange.amount}`;
|
|
||||||
iconComp =
|
|
||||||
positionChange.direction === Direction.UP
|
|
||||||
? new ComponentDefinition(Up, args)
|
|
||||||
: new ComponentDefinition(Down, args);
|
|
||||||
break;
|
|
||||||
case Addition.name:
|
|
||||||
iconComp = new ComponentDefinition(Plus, args);
|
|
||||||
break;
|
|
||||||
case Removal.name:
|
|
||||||
iconComp = new ComponentDefinition(Minus, args);
|
|
||||||
break;
|
|
||||||
case ContentChange.name:
|
|
||||||
iconComp = new ComponentDefinition(Changed, args);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(`${change.constructor.name}: ${change}`);
|
|
||||||
}
|
|
||||||
} else if (evaluated) {
|
|
||||||
iconComp = new ComponentDefinition(Eye, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if evaluated || hasChanged}
|
|
||||||
<div class="flex space-x-0.5 items-center text-xs">
|
|
||||||
{#if iconComp}
|
|
||||||
<svelte:component this={iconComp.component} {...iconComp.args} />
|
|
||||||
{/if}
|
|
||||||
{#if changeContent}
|
|
||||||
<div>{changeContent}</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
@ -1,99 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { slide } from 'svelte/transition';
|
|
||||||
import slideH from '../svelte/slideH';
|
|
||||||
|
|
||||||
import { BookOpen, ArrowLeft, ArrowRight } from 'svelte-hero-icons';
|
|
||||||
|
|
||||||
import { debugStage } from '../config';
|
|
||||||
|
|
||||||
import PageControl from './PageControl';
|
|
||||||
import Popup from '../components/Popup.svelte';
|
|
||||||
import PageSelectionPopup from './PageSelectionPopup.svelte';
|
|
||||||
import Checkbox from '../components/Checkbox.svelte';
|
|
||||||
import TransformerSelectionPopup from './TransformerSelectionPopup.svelte';
|
|
||||||
import FontEntry from './FontEntry.svelte';
|
|
||||||
|
|
||||||
export let stageNames: string[];
|
|
||||||
export let stageDescriptions: string[];
|
|
||||||
export let pageControl: PageControl;
|
|
||||||
export let fontMap: Map<string, object>;
|
|
||||||
export let supportsGrouping: boolean;
|
|
||||||
export let supportsRelevanceFiltering: boolean;
|
|
||||||
|
|
||||||
export let groupingEnabled = true;
|
|
||||||
export let onlyRelevantItems = true;
|
|
||||||
|
|
||||||
$: canNext = $debugStage + 1 < stageNames.length;
|
|
||||||
$: canPrev = $debugStage > 0;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="sticky top-0 pt-2 pb-1 z-20 bg-gray-50">
|
|
||||||
<div class="flex items-center space-x-2">
|
|
||||||
<Popup>
|
|
||||||
<span slot="trigger" let:opened>
|
|
||||||
<BookOpen size="1x" class="hover:text-select cursor-pointer {opened && 'text-select'}" />
|
|
||||||
</span>
|
|
||||||
<span slot="content">
|
|
||||||
<PageSelectionPopup {pageControl} />
|
|
||||||
</span>
|
|
||||||
</Popup>
|
|
||||||
<Popup>
|
|
||||||
<span slot="trigger" let:opened>
|
|
||||||
<div
|
|
||||||
class="hover:text-select cursor-pointer {opened && 'text-select'}"
|
|
||||||
style="font-family: AmericanTypewriter, verdana">
|
|
||||||
F
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
<span slot="content">
|
|
||||||
<div class="absolute mt-1 py-2 px-2 bg-gray-200 rounded-br">
|
|
||||||
<div class=" overflow-y-scroll " style="max-height: 65vh" transition:slide={{ duration: 400 }}>
|
|
||||||
{#each [...fontMap.keys()] as fontName}
|
|
||||||
<FontEntry {fontMap} {fontName} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</Popup>
|
|
||||||
|
|
||||||
<div>|</div>
|
|
||||||
<div>Transformation:</div>
|
|
||||||
<span on:click={() => canPrev && debugStage.update((cur) => cur - 1)}>
|
|
||||||
<ArrowLeft size="1x" class={canPrev ? 'hover:text-select cursor-pointer' : 'opacity-25'} />
|
|
||||||
</span>
|
|
||||||
<span on:click={() => canNext && debugStage.update((cur) => cur + 1)}>
|
|
||||||
<ArrowRight size="1x" class={canNext ? 'hover:text-select cursor-pointer' : 'opacity-25'} />
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<Popup>
|
|
||||||
<span slot="trigger">
|
|
||||||
<div class="w-52 cursor-pointer hover:underline whitespace-nowrap italic">
|
|
||||||
{stageNames[$debugStage]}
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
<span slot="content">
|
|
||||||
<TransformerSelectionPopup
|
|
||||||
{stageNames}
|
|
||||||
{stageDescriptions}
|
|
||||||
currentStage={$debugStage}
|
|
||||||
on:selectTransformer={({ detail }) => debugStage.set(detail)} />
|
|
||||||
</span>
|
|
||||||
</Popup>
|
|
||||||
</span>
|
|
||||||
<div class="w-full flex flex-row-reverse space-x-2 space-x-reverse text-sm">
|
|
||||||
{#if supportsGrouping}
|
|
||||||
<span class="inline-flex" transition:slideH={{ duration: 700 }}>
|
|
||||||
<Checkbox name="Grouped" bind:enabled={groupingEnabled} />
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
{#if supportsRelevanceFiltering}
|
|
||||||
<span class="inline-flex" transition:slideH={{ duration: 700 }}>
|
|
||||||
<Checkbox name="Relevant Items" bind:enabled={onlyRelevantItems} />
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Little cushion sitting between the control bar and the item header. Relevant is the z-index. Item headers should go over it, item rows under! -->
|
|
||||||
<div class="sticky top-8 h-3 bg-gray-50" style="z-index:1" />
|
|
@ -1,40 +0,0 @@
|
|||||||
<script>
|
|
||||||
import slideH from '../svelte/slideH';
|
|
||||||
import { linear } from 'svelte/easing';
|
|
||||||
|
|
||||||
import Icon from 'fa-svelte';
|
|
||||||
import { faMapPin as pin } from '@fortawesome/free-solid-svg-icons/faMapPin';
|
|
||||||
import { ArrowLeft, ArrowRight } from 'svelte-hero-icons';
|
|
||||||
|
|
||||||
import PageControl from './PageControl';
|
|
||||||
|
|
||||||
export let pageControl: PageControl;
|
|
||||||
export let pageIndex: number;
|
|
||||||
|
|
||||||
let { pagePinned, canPrev, canNext, pageMapping } = pageControl;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="flex items-center space-x-1">
|
|
||||||
{#if $pagePinned}
|
|
||||||
<span on:click={() => pageControl.unpinPage()} transition:slideH={{ duration: 180, easing: linear }}>
|
|
||||||
<Icon class="text-xs hover:text-select hover:opacity-25 cursor-pointer opacity-75" icon={pin} />
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
<div>
|
|
||||||
Page
|
|
||||||
{$pageMapping.pageLabel(pageIndex)}
|
|
||||||
{#if $pageMapping.shifted()}
|
|
||||||
<span class="font-light"> ({pageIndex + 1}/{pageControl.totalPages}) </span>
|
|
||||||
{:else}/ {pageControl.totalPages + $pageMapping.pageFactor - 1}{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{#if $pagePinned}
|
|
||||||
<div class="absolute flex ml-4 space-x-2">
|
|
||||||
<span on:click={() => pageControl.prev()}>
|
|
||||||
<ArrowLeft size="1x" class={$canPrev ? 'hover:text-select cursor-pointer' : 'opacity-25'} />
|
|
||||||
</span>
|
|
||||||
<span on:click={() => pageControl.next()}>
|
|
||||||
<ArrowRight size="1x" class={$canNext ? 'hover:text-select cursor-pointer' : 'opacity-25'} />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
@ -1,93 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { slide, blur } from 'svelte/transition';
|
|
||||||
import { flip } from 'svelte/animate';
|
|
||||||
|
|
||||||
import type Debugger from '@core/Debugger';
|
|
||||||
import { PAGE_MAPPING } from '../../../core/src/transformer/CacluclateStatistics';
|
|
||||||
|
|
||||||
import { debugStage } from '../config';
|
|
||||||
import ControlBar from './ControlBar.svelte';
|
|
||||||
import ItemTable from './ItemTable.svelte';
|
|
||||||
import PageControl from './PageControl';
|
|
||||||
import CurrentPage from './CurrentPage.svelte';
|
|
||||||
|
|
||||||
export let debug: Debugger;
|
|
||||||
|
|
||||||
const pageControl = new PageControl(debug.pageCount);
|
|
||||||
const stageNames = debug.stageNames;
|
|
||||||
const { pinnedPageIndex, pagePinned } = pageControl;
|
|
||||||
let groupingEnabled = true;
|
|
||||||
let onlyRelevantItems = true;
|
|
||||||
|
|
||||||
$: stageResult = debug.stageResult($debugStage);
|
|
||||||
$: pageControl.updateMapping(stageResult.globals.getOptional(PAGE_MAPPING));
|
|
||||||
$: supportsGrouping = !!stageResult.descriptor?.debug?.itemMerger;
|
|
||||||
$: supportsRelevanceFiltering = !stageResult.descriptor?.debug?.showAll;
|
|
||||||
$: visiblePages = pageControl.selectPages(stageResult, onlyRelevantItems, groupingEnabled, $pinnedPageIndex);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="mx-4">
|
|
||||||
<!-- <div>Parsed {parseResult.pageCount()} pages with {parseResult.items.length} items</div>
|
|
||||||
<div>Title: {parseResult.metadata.title()}</div>
|
|
||||||
<div>Author: {parseResult.metadata.author()}</div> -->
|
|
||||||
|
|
||||||
<!-- Sticky Controls -->
|
|
||||||
<ControlBar
|
|
||||||
{stageNames}
|
|
||||||
stageDescriptions={debug.stageDescriptions}
|
|
||||||
{pageControl}
|
|
||||||
fontMap={debug.fontMap}
|
|
||||||
{supportsGrouping}
|
|
||||||
{supportsRelevanceFiltering}
|
|
||||||
bind:groupingEnabled
|
|
||||||
bind:onlyRelevantItems />
|
|
||||||
|
|
||||||
<!-- Stage Messages -->
|
|
||||||
<ul class="messages list-disc list-inside mb-2 p-2 bg-blue-50 rounded shadow text-sm">
|
|
||||||
{#each stageResult.messages as message (message)}
|
|
||||||
<li animate:flip in:slide>{message}</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- Items -->
|
|
||||||
{#if visiblePages.find((page) => page.itemGroups.length > 0)}
|
|
||||||
<ItemTable
|
|
||||||
schema={stageResult.schema}
|
|
||||||
pages={visiblePages}
|
|
||||||
{pageControl}
|
|
||||||
evaluations={stageResult.evaluations}
|
|
||||||
changes={stageResult.changes} />
|
|
||||||
{:else}
|
|
||||||
<!-- No items visible -->
|
|
||||||
<div class="flex mt-8">
|
|
||||||
{#if $pagePinned}
|
|
||||||
<span class="w-36">
|
|
||||||
<CurrentPage {pageControl} pageIndex={$pinnedPageIndex} />
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
<div class="flex w-full space-x-1 items-center justify-center text-xl">
|
|
||||||
<div in:blur={{ delay: 500 }}>No visible changes from the transformation.</div>
|
|
||||||
{#if supportsRelevanceFiltering && onlyRelevantItems}
|
|
||||||
<div in:blur={{ delay: 900 }}>Disable the</div>
|
|
||||||
<div
|
|
||||||
in:blur={{ delay: 950 }}
|
|
||||||
class="font-bold cursor-pointer hover:underline"
|
|
||||||
on:click={() => (onlyRelevantItems = false)}>
|
|
||||||
relevance filter
|
|
||||||
</div>
|
|
||||||
<div in:blur={{ delay: 990 }}>?</div>
|
|
||||||
{/if}
|
|
||||||
{#if supportsGrouping && !groupingEnabled}
|
|
||||||
<div in:blur={{ delay: 1000 }}>Enable</div>
|
|
||||||
<div
|
|
||||||
in:blur={{ delay: 1050 }}
|
|
||||||
class="font-bold cursor-pointer hover:underline"
|
|
||||||
on:click={() => (groupingEnabled = true)}>
|
|
||||||
grouping
|
|
||||||
</div>
|
|
||||||
<div in:blur={{ delay: 1090 }}>?</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
@ -1,58 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { slide } from 'svelte/transition';
|
|
||||||
export let fontName: string;
|
|
||||||
export let fontMap: Map<string, object>;
|
|
||||||
|
|
||||||
let collapsed = true;
|
|
||||||
$: font = fontMap.get(fontName);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="pb-1 rounded shadow bg-gray-300 min-w-max">
|
|
||||||
<div
|
|
||||||
class="twoColumned header py-1 px-2 text-sm bg-gray-400 rounded-t cursor-pointer"
|
|
||||||
class:opened={!collapsed}
|
|
||||||
on:click={() => (collapsed = !collapsed)}>
|
|
||||||
<div class="font-semibold">{fontName}</div>
|
|
||||||
<div class="">{font['name']}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if !collapsed}
|
|
||||||
<div class="twoColumned px-2 text-sm" transition:slide>
|
|
||||||
<div>Type:</div>
|
|
||||||
<div>{font['type']}</div>
|
|
||||||
<div>MimeType:</div>
|
|
||||||
<div>{font['mimetype']}</div>
|
|
||||||
<div>Ascent:</div>
|
|
||||||
<div>{font['ascent'].toFixed(2)}</div>
|
|
||||||
<div>Descent:</div>
|
|
||||||
<div>{font['descent'].toFixed(2)}</div>
|
|
||||||
<div>BBox:</div>
|
|
||||||
<div>{font['bbox'].join(', ')}</div>
|
|
||||||
<div>Matrix:</div>
|
|
||||||
<div>{font['fontMatrix'].join(', ')}</div>
|
|
||||||
<div>Vertical:</div>
|
|
||||||
<div>{font['vertical']}</div>
|
|
||||||
<div>Monospace:</div>
|
|
||||||
<div>{font['isMonospace']}</div>
|
|
||||||
<div>Setif:</div>
|
|
||||||
<div>{font['isSerifFont']}</div>
|
|
||||||
<div>Type3:</div>
|
|
||||||
<div>{font['isType3Font']}</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.twoColumned {
|
|
||||||
@apply grid;
|
|
||||||
@apply gap-x-2;
|
|
||||||
grid-template-columns: 1fr 2.5fr;
|
|
||||||
}
|
|
||||||
.header:hover {
|
|
||||||
@apply bg-select;
|
|
||||||
transform: scale(1.02);
|
|
||||||
}
|
|
||||||
.opened {
|
|
||||||
@apply bg-select;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,135 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { fade } from 'svelte/transition';
|
|
||||||
|
|
||||||
import type ItemGroup from '@core/debug/ItemGroup';
|
|
||||||
import type EvaluationIndex from '@core/debug/EvaluationIndex';
|
|
||||||
import type ChangeIndex from '@core/debug/ChangeIndex';
|
|
||||||
import type AnnotatedColumn from '@core/debug/AnnotatedColumn';
|
|
||||||
|
|
||||||
import ChangeSymbol from './ChangeSymbol.svelte';
|
|
||||||
import { formatValue } from './formatValues';
|
|
||||||
import PageControl from './PageControl';
|
|
||||||
import CurrentPage from './CurrentPage.svelte';
|
|
||||||
|
|
||||||
export let pageControl: PageControl;
|
|
||||||
export let pageIdx: number;
|
|
||||||
export let itemIdx: number;
|
|
||||||
export let schema: AnnotatedColumn[];
|
|
||||||
export let itemGroup: ItemGroup;
|
|
||||||
export let evaluations: EvaluationIndex;
|
|
||||||
export let changes: ChangeIndex;
|
|
||||||
|
|
||||||
let expandedItemGroup: { pageIndex: number; itemIndex: number };
|
|
||||||
|
|
||||||
$: expanded =
|
|
||||||
expandedItemGroup && expandedItemGroup.pageIndex === pageIdx && expandedItemGroup.itemIndex === itemIdx;
|
|
||||||
|
|
||||||
const toggleRow = (pageIndex: number, itemIndex: number) => {
|
|
||||||
expandedItemGroup = expanded ? undefined : { pageIndex, itemIndex };
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<tr
|
|
||||||
class:expandable={itemGroup.hasMany()}
|
|
||||||
class:expanded
|
|
||||||
class:changePlus={changes.isPlusChange(itemGroup.top)}
|
|
||||||
class:changeNeutral={changes.isNeutralChange(itemGroup.top)}
|
|
||||||
class:changeMinus={changes.isMinusChange(itemGroup.top)}
|
|
||||||
in:fade>
|
|
||||||
<!-- Page number in first page item row -->
|
|
||||||
{#if itemIdx === 0}
|
|
||||||
<td id="page" class="page bg-gray-50 align-top">
|
|
||||||
<CurrentPage pageIndex={pageIdx} {pageControl} />
|
|
||||||
</td>
|
|
||||||
{:else}
|
|
||||||
<td id="page" />
|
|
||||||
{/if}
|
|
||||||
<td class="align-baseline">
|
|
||||||
<ChangeSymbol {evaluations} {changes} item={itemGroup.top} />
|
|
||||||
</td>
|
|
||||||
{#if evaluations.hasScores()}
|
|
||||||
<td class="whitespace-nowrap">{evaluations.evaluationScore(itemGroup.top)}</td>
|
|
||||||
{/if}
|
|
||||||
<span class="contents" on:click={() => itemGroup.hasMany() && toggleRow(pageIdx, itemIdx)}>
|
|
||||||
<!-- ID & change marker column -->
|
|
||||||
<td class="align-top">
|
|
||||||
<div class="flex space-x-0.5 items-center">
|
|
||||||
<div>{itemIdx}{itemGroup.hasMany() ? '…' : ''}</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<!-- Row values -->
|
|
||||||
{#each schema as column}
|
|
||||||
<td class="select-all">{formatValue(itemGroup.top.data[column.name])}</td>
|
|
||||||
{/each}
|
|
||||||
</span>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Expanded childs -->
|
|
||||||
{#if expanded}
|
|
||||||
{#each itemGroup.elements as child, childIdx}
|
|
||||||
<tr
|
|
||||||
class="childs"
|
|
||||||
class:changePlus={changes.isPlusChange(child)}
|
|
||||||
class:changeNeutral={changes.isNeutralChange(child)}
|
|
||||||
class:changeMinus={changes.isMinusChange(child)}>
|
|
||||||
<td id="page" />
|
|
||||||
<td class="align-baseline">
|
|
||||||
<ChangeSymbol {evaluations} {changes} item={child} />
|
|
||||||
</td>
|
|
||||||
{#if evaluations.hasScores()}
|
|
||||||
<td class="whitespace-nowrap">{evaluations.evaluationScore(itemGroup.top)}</td>
|
|
||||||
{/if}
|
|
||||||
<td class="whitespace-nowrap">
|
|
||||||
<div class="flex space-x-1">
|
|
||||||
<div class="w-8">{'└ ' + childIdx}</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
{#each schema as column}
|
|
||||||
<td class="select-all">{formatValue(child.data[column.name])}</td>
|
|
||||||
{/each}
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.page {
|
|
||||||
@apply font-semibold;
|
|
||||||
@apply pr-4;
|
|
||||||
@apply whitespace-nowrap;
|
|
||||||
position: -webkit-sticky;
|
|
||||||
position: sticky;
|
|
||||||
top: 2.4em;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
td:not(#page) {
|
|
||||||
@apply px-1;
|
|
||||||
@apply border-b;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:hover td:not(#page) {
|
|
||||||
@apply bg-gray-200;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.expandable:hover td:not(#page) {
|
|
||||||
@apply cursor-pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.expanded td:not(#page) {
|
|
||||||
@apply bg-gray-300;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.childs td:not(#page) {
|
|
||||||
@apply bg-gray-200;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.changePlus td:not(#page) {
|
|
||||||
@apply text-green-700;
|
|
||||||
}
|
|
||||||
tr.changeMinus td:not(#page) {
|
|
||||||
@apply text-red-700;
|
|
||||||
}
|
|
||||||
tr.changeNeutral td:not(#page) {
|
|
||||||
@apply text-yellow-500;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,113 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { scale } from 'svelte/transition';
|
|
||||||
|
|
||||||
import { PresentationChartLine } from 'svelte-hero-icons';
|
|
||||||
|
|
||||||
import type AnnotatedColumn from '@core/debug/AnnotatedColumn';
|
|
||||||
import type EvaluationIndex from '@core/debug/EvaluationIndex';
|
|
||||||
import type ChangeIndex from '@core/debug/ChangeIndex';
|
|
||||||
import type Page from '@core/debug/Page';
|
|
||||||
import ColumnAnnotation from '../../../core/src/debug/ColumnAnnotation';
|
|
||||||
|
|
||||||
import inView from '../actions/inView';
|
|
||||||
import PageControl from './PageControl';
|
|
||||||
import ItemRow from './ItemRow.svelte';
|
|
||||||
|
|
||||||
export let schema: AnnotatedColumn[];
|
|
||||||
export let pages: Page[];
|
|
||||||
export let pageControl: PageControl;
|
|
||||||
export let evaluations: EvaluationIndex;
|
|
||||||
export let changes: ChangeIndex;
|
|
||||||
|
|
||||||
let { pagePinned } = pageControl;
|
|
||||||
let maxItemsToRenderInOneLoad = 200;
|
|
||||||
let renderedMaxPage = 0;
|
|
||||||
|
|
||||||
let renderedPages: Page[];
|
|
||||||
$: {
|
|
||||||
if ($pagePinned) {
|
|
||||||
renderedPages = pages;
|
|
||||||
renderedMaxPage = 0;
|
|
||||||
} else {
|
|
||||||
if (renderedMaxPage === 0) {
|
|
||||||
calculateNextPageToRenderTo();
|
|
||||||
}
|
|
||||||
renderedPages = pages.slice(0, renderedMaxPage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateNextPageToRenderTo() {
|
|
||||||
if (renderedMaxPage >= pages.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let itemCount = 0;
|
|
||||||
for (let index = 0; index < pages.length; index++) {
|
|
||||||
renderedMaxPage++;
|
|
||||||
itemCount += pages[index].itemGroups.length;
|
|
||||||
if (itemCount > maxItemsToRenderInOneLoad) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// console.log(`Render pages 0 to ${renderedMaxPage} with ${itemCount} items`);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Item table -->
|
|
||||||
<table class="w-full text-left">
|
|
||||||
<!-- Sticky header -->
|
|
||||||
<thead class="">
|
|
||||||
<th />
|
|
||||||
{#if changes.changeCount() > 0}
|
|
||||||
<th class="bg-gray-300 shadow">
|
|
||||||
<PresentationChartLine size="1x" />
|
|
||||||
</th>
|
|
||||||
{:else}
|
|
||||||
<th class="bg-gray-50" />
|
|
||||||
{/if}
|
|
||||||
{#if evaluations.hasScores()}
|
|
||||||
<th class="bg-gray-300 shadow">score</th>
|
|
||||||
{/if}
|
|
||||||
<th class="bg-gray-300 shadow">#</th>
|
|
||||||
{#each schema as column (column.name)}
|
|
||||||
<th
|
|
||||||
transition:scale
|
|
||||||
class="bg-gray-300 shadow {column.annotation === ColumnAnnotation.ADDED ? 'text-green-800' : column.annotation === ColumnAnnotation.REMOVED ? 'text-red-800' : ''} transition-colors duration-300 delay-200">
|
|
||||||
{column.name}
|
|
||||||
</th>
|
|
||||||
{/each}
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{#each renderedPages as page, pageIdx}
|
|
||||||
<!-- Separator between pages -->
|
|
||||||
{#if pageIdx > 0}
|
|
||||||
<tr class="h-5" />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- Page items -->
|
|
||||||
{#each page.itemGroups as itemGroup, itemIdx}
|
|
||||||
<ItemRow pageIdx={page.index} {itemIdx} {schema} {itemGroup} {evaluations} {changes} {pageControl} />
|
|
||||||
{/each}
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{#if $pagePinned}
|
|
||||||
<div class="mb-8" />
|
|
||||||
{:else}
|
|
||||||
{#if renderedMaxPage < pages.length}
|
|
||||||
<span use:inView on:intersect={({ detail }) => detail && calculateNextPageToRenderTo()} />
|
|
||||||
<div class="my-6 text-center text-2xl">...</div>
|
|
||||||
{:else}
|
|
||||||
<div class="my-6 text-center text-2xl">FIN!</div>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
th {
|
|
||||||
@apply px-1;
|
|
||||||
position: -webkit-sticky;
|
|
||||||
position: sticky;
|
|
||||||
top: 2.4em;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,74 +0,0 @@
|
|||||||
import StageResult from '@core/debug/StageResult';
|
|
||||||
import PageMapping from '../../../core/src/PageMapping';
|
|
||||||
import { Writable, writable, get, Readable, derived } from 'svelte/store';
|
|
||||||
|
|
||||||
export default class PageControl {
|
|
||||||
pinnedPageIndex: Writable<number | undefined>;
|
|
||||||
pagePinned: Readable<boolean>;
|
|
||||||
canPrev: Readable<boolean>;
|
|
||||||
canNext: Readable<boolean>;
|
|
||||||
pagesWithItems: Set<number> = new Set();
|
|
||||||
pageMapping: Writable<PageMapping> = writable(new PageMapping());
|
|
||||||
|
|
||||||
constructor(public totalPages: number) {
|
|
||||||
this.pinnedPageIndex = writable(undefined);
|
|
||||||
this.pagePinned = derived(this.pinnedPageIndex, (page) => !isNaN(page));
|
|
||||||
this.canPrev = derived([this.pinnedPageIndex, this.pagePinned], ([page, pinned]) => pinned && page > 0);
|
|
||||||
this.canNext = derived(
|
|
||||||
[this.pinnedPageIndex, this.pagePinned],
|
|
||||||
([page, pinned]) => pinned && page < totalPages - 1
|
|
||||||
);
|
|
||||||
this.next.bind(this);
|
|
||||||
this.prev.bind(this);
|
|
||||||
this.unpinPage.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateMapping(pageMapping: PageMapping | undefined) {
|
|
||||||
if (pageMapping) {
|
|
||||||
this.pageMapping.set(pageMapping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectPages(stageResult: StageResult, relevantChangesOnly: boolean, groupItems: boolean, pinnedPage?: number) {
|
|
||||||
const allRelevantPages = stageResult.selectPages(relevantChangesOnly, groupItems);
|
|
||||||
this.pagesWithItems = new Set(
|
|
||||||
allRelevantPages.filter((page) => page.itemGroups.length > 0).map((page) => page.index)
|
|
||||||
);
|
|
||||||
if (Number.isInteger(pinnedPage)) {
|
|
||||||
return allRelevantPages.filter((page) => page.index === pinnedPage);
|
|
||||||
}
|
|
||||||
return allRelevantPages;
|
|
||||||
}
|
|
||||||
|
|
||||||
pageHasItems(pageIdx: number) {
|
|
||||||
return this.pagesWithItems.has(pageIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
next() {
|
|
||||||
if (get(this.canNext)) {
|
|
||||||
this.pinnedPageIndex.update((page) => page + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prev() {
|
|
||||||
if (get(this.canPrev)) {
|
|
||||||
this.pinnedPageIndex.update((page) => page - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pinPage(pageIdx: number) {
|
|
||||||
this.pinnedPageIndex.set(pageIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
unpinPage() {
|
|
||||||
this.pinnedPageIndex.set(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
pinnedPage() {
|
|
||||||
return get(this.pinnedPageIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
pageIsPinned() {
|
|
||||||
return get(this.pagePinned);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { slide } from 'svelte/transition';
|
|
||||||
import { getContext } from 'svelte';
|
|
||||||
import { Collection } from 'svelte-hero-icons';
|
|
||||||
import type { Writable } from 'svelte/store';
|
|
||||||
|
|
||||||
import PageControl from './PageControl';
|
|
||||||
|
|
||||||
export let pageControl: PageControl;
|
|
||||||
|
|
||||||
let { pinnedPageIndex, pagePinned, pageMapping } = pageControl;
|
|
||||||
let showIndex = false;
|
|
||||||
|
|
||||||
const popupOpened: Writable<boolean> = getContext('popupOpened');
|
|
||||||
|
|
||||||
function pinPage(index: number) {
|
|
||||||
popupOpened.set(false);
|
|
||||||
pageControl.pinPage(index);
|
|
||||||
}
|
|
||||||
function unpinPage() {
|
|
||||||
popupOpened.set(false);
|
|
||||||
pageControl.unpinPage();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="absolute my-2 p-2 flex bg-gray-200 shadow-lg rounded-sm overflow-auto max-h-96"
|
|
||||||
style="max-width: 77%;"
|
|
||||||
transition:slide>
|
|
||||||
<span class="mt-1 pr-2" on:click={$pagePinned && unpinPage}>
|
|
||||||
<Collection size="1x" class={$pagePinned ? 'hover:text-select cursor-pointer' : 'opacity-50'} />
|
|
||||||
</span>
|
|
||||||
<div class="flex flex-wrap gap-1">
|
|
||||||
{#each new Array(pageControl.totalPages) as _, idx}
|
|
||||||
<div
|
|
||||||
class="flex-grow-0 px-2 w-12 max-w-xs border border-gray-300 rounded-full text-center {pageControl.pageHasItems(idx) ? ($pinnedPageIndex === idx ? 'bg-select' : 'hover:text-select hover:border-select cursor-pointer') : 'opacity-50'}"
|
|
||||||
on:click={() => pageControl.pageHasItems(idx) && pinPage(idx)}>
|
|
||||||
{#if showIndex}{idx}{:else}{$pageMapping.pageLabel(idx)}{/if}
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
width: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
box-shadow: 0 0 1px rgba(255, 255, 255, 0.5);
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,83 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { slide } from 'svelte/transition';
|
|
||||||
import { getContext } from 'svelte';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
|
|
||||||
import type { Writable } from 'svelte/store';
|
|
||||||
|
|
||||||
export let stageNames: string[];
|
|
||||||
export let stageDescriptions: string[];
|
|
||||||
export let currentStage: number;
|
|
||||||
|
|
||||||
const popupOpened: Writable<boolean> = getContext('popupOpened');
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
function selectTransformer(index: number) {
|
|
||||||
popupOpened.set(false);
|
|
||||||
dispatch('selectTransformer', index);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="absolute -mt-6 " transition:slide>
|
|
||||||
<div class="p-2 bg-gray-200 shadow-lg rounded-sm overflow-auto max-h-96">
|
|
||||||
{#each stageNames as stageName, idx}
|
|
||||||
<div
|
|
||||||
on:click={() => selectTransformer(idx)}
|
|
||||||
class="tooltip px-2"
|
|
||||||
class:selected={idx == currentStage}
|
|
||||||
class:selectable={idx != currentStage}
|
|
||||||
data-text={stageDescriptions[idx]}>
|
|
||||||
{stageName}
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.selected {
|
|
||||||
@apply cursor-default;
|
|
||||||
@apply bg-gray-300;
|
|
||||||
@apply rounded;
|
|
||||||
}
|
|
||||||
.selectable {
|
|
||||||
@apply cursor-pointer;
|
|
||||||
}
|
|
||||||
.selectable:hover {
|
|
||||||
@apply bg-select;
|
|
||||||
@apply rounded;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip:before {
|
|
||||||
content: attr(data-text); /* here's the magic */
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
transform: translateY(-2px);
|
|
||||||
|
|
||||||
/* move to right */
|
|
||||||
left: 100%;
|
|
||||||
|
|
||||||
/* the arrow */
|
|
||||||
border: 10px solid;
|
|
||||||
@apply border-select;
|
|
||||||
@apply border-t-transparent;
|
|
||||||
@apply border-r-transparent;
|
|
||||||
@apply border-b-transparent;
|
|
||||||
|
|
||||||
/* basic styles */
|
|
||||||
@apply ml-2;
|
|
||||||
@apply px-2;
|
|
||||||
@apply py-1;
|
|
||||||
@apply w-72;
|
|
||||||
@apply bg-gray-300;
|
|
||||||
@apply text-gray-800;
|
|
||||||
@apply rounded;
|
|
||||||
@apply shadow-sm;
|
|
||||||
@apply text-center;
|
|
||||||
@apply italic;
|
|
||||||
|
|
||||||
display: none; /* hide by default */
|
|
||||||
}
|
|
||||||
.tooltip:hover:before {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,19 +0,0 @@
|
|||||||
export function formatValue(value: object) {
|
|
||||||
if (typeof value === 'undefined') {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
if (Number.isInteger(value)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
if (typeof value === 'number') {
|
|
||||||
return (value as number).toFixed(2);
|
|
||||||
}
|
|
||||||
if (typeof value === 'object' && typeof Array.isArray(value)) {
|
|
||||||
let array = value as Array<object>;
|
|
||||||
if (array.length > 0 && typeof array[0] === 'number') {
|
|
||||||
array = (array.map((element) => ((element as unknown) as number).toFixed(2)) as unknown) as Array<object>;
|
|
||||||
}
|
|
||||||
return '[' + array.join(', ') + ']';
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
import App from './App.svelte';
|
|
||||||
import './Tailwind.css';
|
|
||||||
|
|
||||||
var app = new App({
|
|
||||||
target: document.body,
|
|
||||||
intro: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default app;
|
|
||||||
|
|
||||||
// Hot Module Replacement (HMR) - Remove this snippet to remove HMR.
|
|
||||||
// Learn more: https://www.snowpack.dev/concepts/hot-module-replacement
|
|
||||||
if (import.meta.hot) {
|
|
||||||
import.meta.hot.accept();
|
|
||||||
import.meta.hot.dispose(() => {
|
|
||||||
app.$destroy();
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,158 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { blur, slide } from 'svelte/transition';
|
|
||||||
import Dropzone from 'svelte-file-dropzone';
|
|
||||||
import { Download, Check } from 'svelte-hero-icons';
|
|
||||||
import { processUpload, loadExample, loadUrl } from '../store';
|
|
||||||
import type Progress from '@core/Progress';
|
|
||||||
import ProgressRing from '../components/ProgressRing.svelte';
|
|
||||||
import Checkbox from '../components/Checkbox.svelte';
|
|
||||||
import { debugEnabled } from '../config';
|
|
||||||
import { urlFromParams } from '../processParameters';
|
|
||||||
|
|
||||||
let specifiedFileName: string;
|
|
||||||
let dragover = false;
|
|
||||||
let upload: Promise<any>;
|
|
||||||
let rejectionError: string;
|
|
||||||
let parseProgress: Progress;
|
|
||||||
|
|
||||||
const url = urlFromParams();
|
|
||||||
if (url) {
|
|
||||||
dragover = true;
|
|
||||||
specifiedFileName = url;
|
|
||||||
upload = loadUrl(handleProgress, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleUrlLoad() {
|
|
||||||
dragover = true;
|
|
||||||
let answer = prompt('Url of the pdf');
|
|
||||||
specifiedFileName = answer;
|
|
||||||
rejectionError = undefined;
|
|
||||||
parseProgress = undefined;
|
|
||||||
upload = loadUrl(handleProgress, answer);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleExampleLoad() {
|
|
||||||
dragover = true;
|
|
||||||
specifiedFileName = 'ExamplePdf.pdf';
|
|
||||||
rejectionError = undefined;
|
|
||||||
parseProgress = undefined;
|
|
||||||
upload = loadExample(handleProgress);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFilesSelect(e) {
|
|
||||||
specifiedFileName = undefined;
|
|
||||||
rejectionError = undefined;
|
|
||||||
parseProgress = undefined;
|
|
||||||
const { acceptedFiles, fileRejections } = e.detail;
|
|
||||||
if (acceptedFiles.length === 1) {
|
|
||||||
const specifiedFile = acceptedFiles[0];
|
|
||||||
specifiedFileName = specifiedFile.name;
|
|
||||||
upload = processUpload(specifiedFile, handleProgress);
|
|
||||||
}
|
|
||||||
if (fileRejections.length > 1) {
|
|
||||||
const fileNames = fileRejections.map((r) => r.file.name);
|
|
||||||
rejectionError = `Only one file at a time allowed! Rejected ${fileRejections.length} files: '${fileNames}'.`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleProgress(progress: Progress) {
|
|
||||||
parseProgress = progress;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="container mx-auto">
|
|
||||||
<!-- Options -->
|
|
||||||
<div class="mb-0.5 flex flex-row-reverse space-x-2 space-x-reverse text-sm items-center">
|
|
||||||
<div class="py-0.5 border-2 border-gray-50 hover:underline cursor-pointer" on:click={handleExampleLoad}>
|
|
||||||
Load Example
|
|
||||||
</div>
|
|
||||||
<div class="py-0.5 border-2 border-gray-50 hover:underline cursor-pointer" on:click={handleUrlLoad}>
|
|
||||||
Open Url
|
|
||||||
</div>
|
|
||||||
<Checkbox name="Debug" bind:enabled={$debugEnabled} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Upload Box -->
|
|
||||||
<div class="mb-5 border-2 border-dashed border-gray-400 hover:border-select" class:dragover>
|
|
||||||
<Dropzone
|
|
||||||
on:drop={handleFilesSelect}
|
|
||||||
on:dragenter={() => (dragover = true)}
|
|
||||||
on:dragleave={() => (dragover = false)}
|
|
||||||
multiple={false}
|
|
||||||
noClick={false}
|
|
||||||
disableDefaultStyles={true}>
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 justify-items-center">
|
|
||||||
<span class:dragoverItem={dragover}>
|
|
||||||
<Download size="21x" />
|
|
||||||
</span>
|
|
||||||
<div class="px-5 mb-5">
|
|
||||||
<div class="text-5xl font-bold my-4">Drop your PDF file here...</div>
|
|
||||||
<div class="text-2xl font-bold">Or click the box to select one...</div>
|
|
||||||
<div class="mt-14"><strong>Note:</strong> Your data stays locally in your browser.</div>
|
|
||||||
<div class="mt-5 text-sm italic font-serif">
|
|
||||||
This tool converts a PDF file into a Markdown text format! Simply drag & drop your PDF file on
|
|
||||||
the upload area and go from there. Don't expect wonders, there are a lot of variances in
|
|
||||||
generated PDF's from different tools and different ages. No matter how good the parser works for
|
|
||||||
your PDF, you will have to invest a good amount of manuell work to complete it.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Dropzone>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Progress Info -->
|
|
||||||
<div class="mt-5 text-xl font-bold">
|
|
||||||
<div style="min-width: 70%;">
|
|
||||||
{#if specifiedFileName}
|
|
||||||
<div in:blur class="text-2xl mb-2">Parsing {specifiedFileName} ...</div>
|
|
||||||
{/if}
|
|
||||||
{#if parseProgress}
|
|
||||||
<div in:blur class="flex space-x-4">
|
|
||||||
<ProgressRing radius={50} stroke={7} progress={parseProgress?.totalProgress() * 100} />
|
|
||||||
<div>
|
|
||||||
{#each parseProgress.stages as stage, index}
|
|
||||||
{#if parseProgress.isProgressing(index)}
|
|
||||||
<div class="flex space-x-2 items-center">
|
|
||||||
<div>
|
|
||||||
Parsing
|
|
||||||
{stage}
|
|
||||||
{parseProgress.stageDetails[index] ? parseProgress.stageDetails[index] : ''}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else if parseProgress.isComplete(index)}
|
|
||||||
<div class="flex space-x-2 items-center ">
|
|
||||||
<div>
|
|
||||||
Parsing
|
|
||||||
{stage}
|
|
||||||
{parseProgress.stageDetails[index] ? parseProgress.stageDetails[index] : ''}
|
|
||||||
</div>
|
|
||||||
<Check size="1.5x" class="text-select" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{#if rejectionError}
|
|
||||||
<div in:slide class="text-red-700">{rejectionError}</div>
|
|
||||||
{/if}
|
|
||||||
{#await upload}
|
|
||||||
<!-- -->
|
|
||||||
{:catch error}
|
|
||||||
<div in:blur={{ delay: 200 }} class="text-red-700">
|
|
||||||
Failed to parse '{specifiedFileName}':
|
|
||||||
{error?.message}
|
|
||||||
</div>
|
|
||||||
{/await}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.dragover {
|
|
||||||
@apply border-select;
|
|
||||||
}
|
|
||||||
.dragoverItem {
|
|
||||||
@apply text-select;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,29 +0,0 @@
|
|||||||
const params = new URLSearchParams(window.location.search);
|
|
||||||
|
|
||||||
export function debugFromParams(defaultValue: boolean): boolean {
|
|
||||||
const defined = params.has('debug');
|
|
||||||
if (!defined) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
return params.get('debug') !== 'false';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function debugStageFromParams(defaultValue: number): number {
|
|
||||||
if (!params.has('stage')) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
const stage = +params.get('stage');
|
|
||||||
if (!Number.isInteger(stage)) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
return stage;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function urlFromParams(): string {
|
|
||||||
return getParameterByName('url');
|
|
||||||
}
|
|
||||||
|
|
||||||
function getParameterByName(name: string): string {
|
|
||||||
const match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
|
|
||||||
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
import { createPipeline } from '@core';
|
|
||||||
import type ProgressListenFunction from '@core/ProgressListenFunction';
|
|
||||||
import type ParseResult from '@core/ParseResult';
|
|
||||||
import type Debugger from '@core/Debugger';
|
|
||||||
import * as pdfjs from 'pdfjs-dist/es5/build/pdf';
|
|
||||||
|
|
||||||
import { Writable, writable } from 'svelte/store';
|
|
||||||
|
|
||||||
export let debug: Writable<Debugger> = writable(undefined);
|
|
||||||
export let parseResult: Writable<ParseResult> = writable(undefined);
|
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = `worker/pdf.worker.min.js`;
|
|
||||||
|
|
||||||
const pdfPipeline = createPipeline(pdfjs, {});
|
|
||||||
|
|
||||||
export async function loadExample(progressListener: ProgressListenFunction): Promise<any> {
|
|
||||||
return parsePdf('ExamplePdf.pdf', progressListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function loadUrl(progressListener: ProgressListenFunction, url: String): Promise<any> {
|
|
||||||
return parsePdf('https://pdf-to-markdown-proxy.herokuapp.com/' + url, progressListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function processUpload(file: File, progressListener: ProgressListenFunction): Promise<any> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onerror = reject;
|
|
||||||
reader.onload = () => {
|
|
||||||
resolve(reader.result as ArrayBuffer);
|
|
||||||
};
|
|
||||||
reader.readAsArrayBuffer(file);
|
|
||||||
}).then((buffer) => {
|
|
||||||
const data = new Uint8Array(buffer as ArrayBuffer);
|
|
||||||
return parsePdf(data, progressListener);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function parsePdf(src: string | Uint8Array, progressListener: ProgressListenFunction): Promise<any> {
|
|
||||||
return pdfPipeline.debug(src, progressListener).then((debugInstance) => {
|
|
||||||
debug.set(debugInstance);
|
|
||||||
return debug;
|
|
||||||
});
|
|
||||||
//TODO without debug-flag
|
|
||||||
// return pdfPipeline.execute(src, progressListener).then((result) => {
|
|
||||||
// parseResult.set(result);
|
|
||||||
// return result;
|
|
||||||
// });
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
import { backInOut as easing } from 'svelte/easing';
|
|
||||||
|
|
||||||
const defaultOptions = {
|
|
||||||
delay: 0,
|
|
||||||
duration: 400,
|
|
||||||
easing,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Slide the element horizontally, across the X-axis.
|
|
||||||
* @param node
|
|
||||||
* @param options
|
|
||||||
*/
|
|
||||||
export default function slideH(node: HTMLElement, options: object) {
|
|
||||||
const mergedOptions = { ...defaultOptions, ...options };
|
|
||||||
|
|
||||||
const style = getComputedStyle(node);
|
|
||||||
const opacity = +style.opacity;
|
|
||||||
const width = parseFloat(style.width);
|
|
||||||
const padding_left = parseFloat(style.paddingLeft);
|
|
||||||
const padding_right = parseFloat(style.paddingRight);
|
|
||||||
const margin_left = parseFloat(style.marginLeft);
|
|
||||||
const margin_right = parseFloat(style.marginRight);
|
|
||||||
const border_left_width = parseFloat(style.borderLeftWidth);
|
|
||||||
const border_right_width = parseFloat(style.borderRightWidth);
|
|
||||||
|
|
||||||
return {
|
|
||||||
delay: mergedOptions.delay,
|
|
||||||
duration: mergedOptions.duration,
|
|
||||||
easing: mergedOptions.easing,
|
|
||||||
css: (t: number) =>
|
|
||||||
`overflow: hidden;` +
|
|
||||||
`opacity: ${Math.min(t * 20, 1) * opacity};` +
|
|
||||||
`width: ${t * width}px;` +
|
|
||||||
`padding-left: ${t * padding_left}px;` +
|
|
||||||
`padding-right: ${t * padding_right}px;` +
|
|
||||||
`margin-left: ${t * margin_left}px;` +
|
|
||||||
`margin-right: ${t * margin_right}px;` +
|
|
||||||
`border-left-width: ${t * border_left_width}px;` +
|
|
||||||
`border-right-width: ${t * border_right_width}px;`,
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
const autoPreprocess = require('svelte-preprocess');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
preprocess: autoPreprocess({
|
|
||||||
defaults: {
|
|
||||||
script: 'typescript',
|
|
||||||
},
|
|
||||||
postcss: true,
|
|
||||||
}),
|
|
||||||
};
|
|
@ -1,47 +0,0 @@
|
|||||||
const plugin = require('tailwindcss/plugin');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
future: {
|
|
||||||
removeDeprecatedGapUtilities: true,
|
|
||||||
purgeLayersByDefault: true,
|
|
||||||
},
|
|
||||||
purge: {
|
|
||||||
content: ['./src/**/*.svelte', './src/**/*.ts'],
|
|
||||||
},
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
// gray-400 hue-rotated 180deg
|
|
||||||
select: '#A8A297',
|
|
||||||
},
|
|
||||||
gridTemplateColumns: {
|
|
||||||
15: 'repeat(15, minmax(0, 1fr))',
|
|
||||||
20: 'repeat(20, minmax(0, 1fr))',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
variants: {
|
|
||||||
extend: {},
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
plugin(function ({ addUtilities, theme }) {
|
|
||||||
const themeColors = theme('colors');
|
|
||||||
const individualBorderColors = Object.keys(themeColors).map((colorName) => ({
|
|
||||||
[`.border-b-${colorName}`]: {
|
|
||||||
borderBottomColor: themeColors[colorName],
|
|
||||||
},
|
|
||||||
[`.border-t-${colorName}`]: {
|
|
||||||
borderTopColor: themeColors[colorName],
|
|
||||||
},
|
|
||||||
[`.border-l-${colorName}`]: {
|
|
||||||
borderLeftColor: themeColors[colorName],
|
|
||||||
},
|
|
||||||
[`.border-r-${colorName}`]: {
|
|
||||||
borderRightColor: themeColors[colorName],
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
addUtilities(individualBorderColors);
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
};
|
|
@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"include": ["src", "types"],
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "esnext",
|
|
||||||
"target": "esnext",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"jsx": "preserve",
|
|
||||||
"baseUrl": "./",
|
|
||||||
/* paths - If you configure Snowpack import aliases, add them here. */
|
|
||||||
"paths": {
|
|
||||||
"@core": ["../core/src"],
|
|
||||||
"@core/*": ["../core/src/*"]
|
|
||||||
},
|
|
||||||
/* noEmit - Snowpack builds (emits) files, not tsc. */
|
|
||||||
"noEmit": true,
|
|
||||||
/* Additional Options */
|
|
||||||
"strict": true,
|
|
||||||
"noImplicitAny": false,
|
|
||||||
// "noImplicitThis": false,
|
|
||||||
// "alwaysStrict": false,
|
|
||||||
// "strictBindCallApply": false,
|
|
||||||
"strictNullChecks": false,
|
|
||||||
// "strictFunctionTypes": false,
|
|
||||||
// "strictPropertyInitialization": false,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"useDefineForClassFields": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"importsNotUsedAsValues": "remove"
|
|
||||||
}
|
|
||||||
}
|
|
68
ui/types/static.d.ts
vendored
68
ui/types/static.d.ts
vendored
@ -1,68 +0,0 @@
|
|||||||
/* Use this file to declare any custom file extensions for importing */
|
|
||||||
/* Use this folder to also add/extend a package d.ts file, if needed. */
|
|
||||||
|
|
||||||
declare module 'svelte-file-dropzone';
|
|
||||||
|
|
||||||
declare namespace svelte.JSX {
|
|
||||||
interface HTMLProps<T> {
|
|
||||||
// inView.ts action
|
|
||||||
onintersect?: (e: CustomEvent) => void;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CSS MODULES */
|
|
||||||
declare module '*.module.css' {
|
|
||||||
const classes: { [key: string]: string };
|
|
||||||
export default classes;
|
|
||||||
}
|
|
||||||
declare module '*.module.scss' {
|
|
||||||
const classes: { [key: string]: string };
|
|
||||||
export default classes;
|
|
||||||
}
|
|
||||||
declare module '*.module.sass' {
|
|
||||||
const classes: { [key: string]: string };
|
|
||||||
export default classes;
|
|
||||||
}
|
|
||||||
declare module '*.module.less' {
|
|
||||||
const classes: { [key: string]: string };
|
|
||||||
export default classes;
|
|
||||||
}
|
|
||||||
declare module '*.module.styl' {
|
|
||||||
const classes: { [key: string]: string };
|
|
||||||
export default classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CSS */
|
|
||||||
declare module '*.css';
|
|
||||||
declare module '*.scss';
|
|
||||||
declare module '*.sass';
|
|
||||||
declare module '*.less';
|
|
||||||
declare module '*.styl';
|
|
||||||
|
|
||||||
/* IMAGES */
|
|
||||||
declare module '*.svg' {
|
|
||||||
const ref: string;
|
|
||||||
export default ref;
|
|
||||||
}
|
|
||||||
declare module '*.bmp' {
|
|
||||||
const ref: string;
|
|
||||||
export default ref;
|
|
||||||
}
|
|
||||||
declare module '*.gif' {
|
|
||||||
const ref: string;
|
|
||||||
export default ref;
|
|
||||||
}
|
|
||||||
declare module '*.jpg' {
|
|
||||||
const ref: string;
|
|
||||||
export default ref;
|
|
||||||
}
|
|
||||||
declare module '*.jpeg' {
|
|
||||||
const ref: string;
|
|
||||||
export default ref;
|
|
||||||
}
|
|
||||||
declare module '*.png' {
|
|
||||||
const ref: string;
|
|
||||||
export default ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CUSTOM: ADD YOUR OWN HERE */
|
|
@ -1,6 +0,0 @@
|
|||||||
// NODE_ENV=test - Needed by "@snowpack/web-test-runner-plugin"
|
|
||||||
process.env.NODE_ENV = 'test';
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
plugins: [require('@snowpack/web-test-runner-plugin')()],
|
|
||||||
};
|
|
Loading…
x
Reference in New Issue
Block a user