initial commit

This commit is contained in:
2022-11-23 17:22:15 +08:00
commit d4d248ee17
35 changed files with 4845 additions and 0 deletions

13
frontend/.eslintignore Normal file
View File

@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

20
frontend/.eslintrc.cjs Normal file
View File

@@ -0,0 +1,20 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
plugins: ['svelte3', '@typescript-eslint'],
ignorePatterns: ['*.cjs'],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
settings: {
'svelte3/typescript': () => require('typescript')
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
},
env: {
browser: true,
es2017: true,
node: true
}
};

10
frontend/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

1
frontend/.npmrc Normal file
View File

@@ -0,0 +1 @@
engine-strict=true

13
frontend/.prettierignore Normal file
View File

@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

9
frontend/.prettierrc Normal file
View File

@@ -0,0 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

38
frontend/README.md Normal file
View File

@@ -0,0 +1,38 @@
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

1
frontend/example.env Normal file
View File

@@ -0,0 +1 @@
VITE_BACKEND_URL=http://localhost:8000

42
frontend/package.json Normal file
View File

@@ -0,0 +1,42 @@
{
"name": "datadonkey-frontend-proto",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"test": "playwright test",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@playwright/test": "1.25.0",
"@sveltejs/adapter-auto": "next",
"@sveltejs/kit": "next",
"@typescript-eslint/eslint-plugin": "^5.27.0",
"@typescript-eslint/parser": "^5.27.0",
"carbon-components-svelte": "^0.70.12",
"carbon-preprocess-svelte": "^0.9.1",
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-svelte3": "^4.0.0",
"prettier": "^2.6.2",
"prettier-plugin-svelte": "^2.7.0",
"sass": "^1.56.1",
"svelte": "^3.44.0",
"svelte-check": "^2.7.1",
"svelte-preprocess": "^4.10.6",
"tslib": "^2.3.1",
"typescript": "^4.7.4",
"vite": "^3.1.0"
},
"type": "module",
"dependencies": {
"@carbon/charts-svelte": "^1.6.1",
"carbon-icons-svelte": "^11.4.0",
"svelte-mathquill": "^0.4.1"
}
}

View File

@@ -0,0 +1,10 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'yarn build && yarn preview',
port: 4173
}
};
export default config;

9
frontend/src/app.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
declare namespace App {
// interface Locals {}
// interface PageData {}
// interface Error {}
// interface Platform {}
}

12
frontend/src/app.html Normal file
View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body>
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

28
frontend/src/app.sass Normal file
View File

@@ -0,0 +1,28 @@
.row-centered
display: flex
flex-direction: row
align-items: center
.title-row
@extend .row-centered
justify-items: left
gap: 0px 1rem
.tile-row
@extend .row-centered
justify-items: left
gap: 0px 1rem
.tile-col
display: flex
flex-direction: column
align-items: left
.mathquill
width: 40rem
height: 6rem
font-size: 24px
.image-math-legend-table
width: 40rem
height: 13.5rem

View File

@@ -0,0 +1,24 @@
<script lang="ts">
import { FileUploader, FileUploaderButton, Modal } from "carbon-components-svelte";
export let type: "image" | "data" = "image";
export let files: File[] = [];
</script>
<FileUploader
multiple={false}
buttonLabel="Upload file"
status="complete"
accept={(() => {
switch (type) {
case "image": {
return [".jpg", ".jpeg", ".png", ".tiff"]
}
case "data": {
return [".csv", ".xlsx"]
}
}
})()}
bind:files
/>

View File

@@ -0,0 +1,5 @@
export const mathInputConfig = {
autoCommands: 'pi theta sqrt sum',
autoOperatorNames: 'sin cons tan arcsin arccos',
maxDepth: 4,
}

29
frontend/src/lib/nav.ts Normal file
View File

@@ -0,0 +1,29 @@
export type NavItem = {
name: string,
urlPath: string,
};
export interface NavItemList {
[details: string]: NavItem[]
}
const navItems: NavItemList = {
imaging: [
{
name: "Mathematical Transform",
urlPath: "math-transform"
},
{
name: "Pixel Intensity Heatmap",
urlPath: "heatmap"
},
{
name: "Smooth Image (Convolutional)",
urlPath: "smooth-conv"
}
],
data: [
]
};
export default navItems;

View File

@@ -0,0 +1,67 @@
<script lang="ts">
import "carbon-components-svelte/css/white.css";
import "../app.sass";
import { MathQuillSetup } from 'svelte-mathquill';
import { Content, Header, HeaderAction, HeaderNav, HeaderNavItem, HeaderPanelDivider, HeaderPanelLink, HeaderPanelLinks, HeaderUtilities, Modal, SideNav, SideNavItems, SideNavLink, SideNavMenu, SideNavMenuItem, SkipToContent } from "carbon-components-svelte";
import { InformationFilled } from "carbon-icons-svelte";
import { goto } from "$app/navigation";
import { page } from "$app/stores";
import navItems from "$lib/nav";
let sidenavOpen = false;
</script>
<MathQuillSetup/>
<Header company="DataDonkey" platformName="Lab Tools" bind:isSideNavOpen={sidenavOpen} expandedByDefault={true}>
<svelte:fragment slot="skip-to-content">
<SkipToContent />
</svelte:fragment>
<HeaderNav>
<HeaderNavItem isSelected={$page.url.pathname == "/"} href="/" text="Home"/>
<HeaderNavItem isSelected={
$page.url.pathname == '/imaging' || /^\/imaging\/.*$/.test($page.url.pathname)
} href="/imaging" text="Imaging"/>
<HeaderNavItem isSelected={
$page.url.pathname == '/data' || /^\/data\/.*$/.test($page.url.pathname)
} href="/data" text="Data Analysis"/>
</HeaderNav>
<HeaderUtilities>
<HeaderAction icon={InformationFilled} closeIcon={InformationFilled} text="About">
<HeaderPanelDivider>Information Links</HeaderPanelDivider>
<HeaderPanelLinks>
<HeaderPanelLink href="https://datadonkey.xyz" target="_blank">DataDonkey Homepage</HeaderPanelLink>
<HeaderPanelLink href="https://git.turtlebasket.ml/datadonkey-com" target="_blank">DataDonkey Git Repos</HeaderPanelLink>
<HeaderPanelLink href="https://git.turtlebasket.ml/datadonkey-com/proto" target="_blank">Lab Tools Source Code</HeaderPanelLink>
</HeaderPanelLinks>
</HeaderAction>
</HeaderUtilities>
</Header>
{#if $page.url.pathname != "/"}
<SideNav bind:isOpen={sidenavOpen}>
<SideNavItems>
{#each Object.keys(navItems) as navType}
{#if $page.url.pathname == `/${navType}` || (new RegExp(`^\/${navType}\/.*$`)).test($page.url.pathname)}
{#each navItems[navType].sort((a, b) => {
if (a.name > b.name) {
return 1
}
else {
return -1
}
}) as navItem}
<SideNavLink text={`${navItem.name}`} href={`/imaging/${navItem.urlPath}`} isSelected={
$page.url.pathname == `/imaging/${navItem.urlPath}`
}/>
{/each}
{/if}
{/each}
</SideNavItems>
</SideNav>
{/if}
<Content>
<slot/>
</Content>

View File

@@ -0,0 +1,66 @@
<script>
import { goto } from "$app/navigation";
import { ClickableTile, Column, Grid, Row} from "carbon-components-svelte";
import { Fire, FunctionMath, WatsonHealthSmoothing } from "carbon-icons-svelte";
</script>
<h1>Lab Tools</h1>
<br>
<p>A collection of useful utilities for image & data processing work.
Built with ❤️ by DataDonkey, and fully open-source.</p>
<br>
<br>
<h3>Popular Workflows</h3>
<br>
<Grid noGutter padding={true}>
<Row>
<Column>
<ClickableTile href="/imaging/math-transform">
<div class="tile-row">
<FunctionMath size={32}/>
<div class="tile-col">
<h4>Mathematical Transform</h4>
<p>Transforms an image using a LaTeX-formatted math formula.</p>
</div>
</div>
</ClickableTile>
</Column>
<Column>
<ClickableTile href="/imaging/heatmap">
<div class="tile-row">
<Fire size={32}/>
<div class="tile-col">
<h4>Heatmap</h4>
<p>Generates a heatmap of pixel intensities.</p>
</div>
</div>
</ClickableTile>
</Column>
</Row>
<Row>
<Column>
<ClickableTile href="/imaging/smooth-conv">
<div class="tile-row">
<WatsonHealthSmoothing size={32}/>
<div class="tile-col">
<h4>Convolutional Smooth</h4>
<p>Applies a smoothing kernel to an image.</p>
</div>
</div>
</ClickableTile>
</Column>
<Column>
<ClickableTile href="/imaging/heatmap">
<div class="tile-row">
<Fire size={32}/>
<div class="tile-col">
<h4>Heatmap</h4>
<p>Generates a heatmap of pixel intensities.</p>
</div>
</div>
</ClickableTile>
</Column>
</Row>
</Grid>

View File

@@ -0,0 +1,4 @@
<h1>Data Analysis</h1>
<br>
<p>To get started, select an analysis workflow from the sidebar.</p>
<br>

View File

@@ -0,0 +1,4 @@
<h1>Imaging</h1>
<br>
<p>To get started, select an imaging tool from the sidebar.</p>
<br>

View File

@@ -0,0 +1,11 @@
<script>
import { Fire } from "carbon-icons-svelte";
</script>
<div class="title-row">
<Fire size={32}/>
<h1>Pixel Intensity Heatmap</h1>
</div>
<br>
<p>Generates a heatmap based on pixel intensities.</p>
<br>

View File

@@ -0,0 +1,78 @@
<script lang="ts">
import { Button, Checkbox, FileUploaderButton, FormLabel, Select, SelectItem, SelectItemGroup, StructuredList, StructuredListBody, StructuredListCell, StructuredListHead, StructuredListRow } from "carbon-components-svelte";
import { Checkmark, FunctionMath, Group, Label, Save } from "carbon-icons-svelte";
import SelectFileSingle from "src/components/SelectFileSingle.svelte";
import { MathQuill } from "svelte-mathquill";
// inputs
let files: File[] = [];
let latex: string = "";
// options
let autoMinMax = true;
let heatmapOutput = true;
// state
let loading = false;
let finished = false;
</script>
<div class="title-row">
<FunctionMath size={32}/>
<h1>Mathematical Transform</h1>
</div>
<br>
<p>Applies a mathematical operation to every pixel in the image.</p>
<br>
<SelectFileSingle
type="image"
bind:files
/>
<br>
<FormLabel>Enter Transform Formula:</FormLabel><br>
<MathQuill bind:latex class="mathquill"/>
<br><br>
<!-- Legend -->
<div class="image-math-legend-table">
<StructuredList condensed>
<StructuredListHead>
<StructuredListRow head>
<StructuredListCell head>Variable</StructuredListCell>
<StructuredListCell head>Value</StructuredListCell>
<StructuredListCell head>Description</StructuredListCell>
</StructuredListRow>
</StructuredListHead>
<StructuredListBody>
<StructuredListRow>
<StructuredListCell><strong>R</strong></StructuredListCell>
<StructuredListCell>0 to 255</StructuredListCell>
<StructuredListCell>Pixel Red Intensity</StructuredListCell>
</StructuredListRow>
<StructuredListRow>
<StructuredListCell><strong>G</strong></StructuredListCell>
<StructuredListCell>0 to 255</StructuredListCell>
<StructuredListCell>Pixel Green Intensity</StructuredListCell>
</StructuredListRow>
<StructuredListRow>
<StructuredListCell><strong>B</strong></StructuredListCell>
<StructuredListCell>0 to 255</StructuredListCell>
<StructuredListCell>Pixel Blue Intensity</StructuredListCell>
</StructuredListRow>
<StructuredListRow>
<StructuredListCell><strong>A</strong></StructuredListCell>
<StructuredListCell>0 to 255</StructuredListCell>
<StructuredListCell>Pixel Alpha Intensity (optional)</StructuredListCell>
</StructuredListRow>
</StructuredListBody>
</StructuredList>
</div>
<Checkbox labelText="Automatically calculate intensity maxima & minima" bind:checked={autoMinMax}/>
<Checkbox labelText="Ouptut a heatmap" bind:checked={heatmapOutput}/>
<br>
<Button on:click={() => {}} icon={Checkmark}>Apply Transformation</Button>
<Button on:click={() => {}} icon={Save} kind="secondary" disabled={!finished}>Save Output</Button>

View File

@@ -0,0 +1,12 @@
<script>
import { WatsonHealthSmoothing } from "carbon-icons-svelte";
</script>
<div class="title-row">
<WatsonHealthSmoothing size={32}/>
<h1>Convolutional Smoothing</h1>
</div>
<br>
<p>Applies a convolutional smoothing kernel of a customizable radius.</p>
<br>

BIN
frontend/static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

28
frontend/svelte.config.js Normal file
View File

@@ -0,0 +1,28 @@
import adapter from '@sveltejs/adapter-auto';
import { optimizeImports } from 'carbon-preprocess-svelte';
import preprocess from 'svelte-preprocess';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: [
preprocess(),
optimizeImports()
],
kit: {
adapter: adapter(),
alias: {
"src": "./src",
"/src": "./src",
"$components": "./src/components"
}
// prerender: {
// enabled: false
// }
},
};
export default config;

6
frontend/tests/test.ts Normal file
View File

@@ -0,0 +1,6 @@
import { expect, test } from '@playwright/test';
test('index page has expected h1', async ({ page }) => {
await page.goto('/');
expect(await page.textContent('h1')).toBe('Welcome to SvelteKit');
});

17
frontend/tsconfig.json Normal file
View File

@@ -0,0 +1,17 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

18
frontend/vite.config.ts Normal file
View File

@@ -0,0 +1,18 @@
import { sveltekit } from '@sveltejs/kit/vite';
import type { UserConfig } from 'vite';
const config: UserConfig = {
plugins: [sveltekit()],
ssr: {
noExternal: ['@carbon/charts', 'carbon-components'],
},
resolve: {
alias: {
"src": "./src",
"/src": "./src",
"$lib": "./src/lib",
}
}
};
export default config;

1874
frontend/yarn-error.log Normal file

File diff suppressed because it is too large Load Diff

1822
frontend/yarn.lock Normal file

File diff suppressed because it is too large Load Diff