Compare commits
9 Commits
main
...
feat/table
Author | SHA1 | Date |
---|---|---|
Tomáš Mládek | 4a2305722c | |
Tomáš Mládek | cb6460032d | |
Tomáš Mládek | 90c9725469 | |
Tomáš Mládek | 24457a5b6a | |
Tomáš Mládek | dc2cf94ba7 | |
Tomáš Mládek | 1483497479 | |
Tomáš Mládek | 3e51645510 | |
Tomáš Mládek | 3e42fbd60a | |
Tomáš Mládek | 8dda83fbd7 |
|
@ -0,0 +1,19 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="dev backend storybook" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run -- serve ./example_vault --clean --no-browser --reinitialize --rescan-mode mirror --bind 127.0.0.1:8099" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<envs />
|
||||
<option name="emulateTerminal" value="true" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="storybook" type="CompoundRunConfigurationType">
|
||||
<toRun name="dev backend storybook" type="CargoCommandRunConfiguration" />
|
||||
<toRun name="storybook:serve" type="js.build_tools.npm" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
|
@ -0,0 +1,12 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="storybook:serve" type="js.build_tools.npm" nameIsGenerated="true">
|
||||
<package-json value="$PROJECT_DIR$/webui/package.json" />
|
||||
<command value="run" />
|
||||
<scripts>
|
||||
<script value="storybook:serve" />
|
||||
</scripts>
|
||||
<node-interpreter value="project" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
|
@ -0,0 +1,11 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="test js sdk" type="JavaScriptTestRunnerJest">
|
||||
<config-file value="$PROJECT_DIR$/sdks/js/jest.config.js" />
|
||||
<node-interpreter value="project" />
|
||||
<jest-package value="$PROJECT_DIR$/sdks/js/node_modules/jest" />
|
||||
<working-dir value="$PROJECT_DIR$" />
|
||||
<envs />
|
||||
<scope-kind value="ALL" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"concurrently": "^8.2.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
devDependencies:
|
||||
concurrently:
|
||||
specifier: ^8.2.2
|
||||
version: 8.2.2
|
||||
|
||||
packages:
|
||||
|
||||
/@babel/runtime@7.23.9:
|
||||
resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
regenerator-runtime: 0.14.1
|
||||
dev: true
|
||||
|
||||
/ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/ansi-styles@4.3.0:
|
||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
dev: true
|
||||
|
||||
/chalk@4.1.2:
|
||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
supports-color: 7.2.0
|
||||
dev: true
|
||||
|
||||
/cliui@8.0.1:
|
||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 7.0.0
|
||||
dev: true
|
||||
|
||||
/color-convert@2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
dev: true
|
||||
|
||||
/color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
dev: true
|
||||
|
||||
/concurrently@8.2.2:
|
||||
resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==}
|
||||
engines: {node: ^14.13.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
date-fns: 2.30.0
|
||||
lodash: 4.17.21
|
||||
rxjs: 7.8.1
|
||||
shell-quote: 1.8.1
|
||||
spawn-command: 0.0.2
|
||||
supports-color: 8.1.1
|
||||
tree-kill: 1.2.2
|
||||
yargs: 17.7.2
|
||||
dev: true
|
||||
|
||||
/date-fns@2.30.0:
|
||||
resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
|
||||
engines: {node: '>=0.11'}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.9
|
||||
dev: true
|
||||
|
||||
/emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
dev: true
|
||||
|
||||
/escalade@3.1.2:
|
||||
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/get-caller-file@2.0.5:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
dev: true
|
||||
|
||||
/has-flag@4.0.0:
|
||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/is-fullwidth-code-point@3.0.0:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
dev: true
|
||||
|
||||
/regenerator-runtime@0.14.1:
|
||||
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
|
||||
dev: true
|
||||
|
||||
/require-directory@2.1.1:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/rxjs@7.8.1:
|
||||
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/shell-quote@1.8.1:
|
||||
resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
|
||||
dev: true
|
||||
|
||||
/spawn-command@0.0.2:
|
||||
resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==}
|
||||
dev: true
|
||||
|
||||
/string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
strip-ansi: 6.0.1
|
||||
dev: true
|
||||
|
||||
/strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
dev: true
|
||||
|
||||
/supports-color@7.2.0:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
dev: true
|
||||
|
||||
/supports-color@8.1.1:
|
||||
resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
dev: true
|
||||
|
||||
/tree-kill@1.2.2:
|
||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/tslib@2.6.2:
|
||||
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
||||
dev: true
|
||||
|
||||
/wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
dev: true
|
||||
|
||||
/y18n@5.0.8:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/yargs-parser@21.1.1:
|
||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/yargs@17.7.2:
|
||||
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
escalade: 3.1.2
|
||||
get-caller-file: 2.0.5
|
||||
require-directory: 2.1.1
|
||||
string-width: 4.2.3
|
||||
y18n: 5.0.8
|
||||
yargs-parser: 21.1.1
|
||||
dev: true
|
|
@ -5,7 +5,8 @@ module.exports = {
|
|||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:svelte/recommended',
|
||||
'prettier'
|
||||
'prettier',
|
||||
'plugin:storybook/recommended'
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint'],
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import type { StorybookConfig } from '@storybook/sveltekit';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-interactions'
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/sveltekit',
|
||||
options: {}
|
||||
},
|
||||
docs: {
|
||||
autodocs: 'tag'
|
||||
},
|
||||
viteFinal: (config) => {
|
||||
config.server!.proxy = {
|
||||
'/api': {
|
||||
target: 'http://localhost:8099/'
|
||||
}
|
||||
};
|
||||
return config;
|
||||
}
|
||||
};
|
||||
export default config;
|
|
@ -0,0 +1,16 @@
|
|||
import type { Preview } from '@storybook/svelte';
|
||||
import '../src/lib/styles/main.scss';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
actions: { argTypesRegex: '^on[A-Z].*' },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default preview;
|
|
@ -10,9 +10,19 @@
|
|||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format": "prettier --write ."
|
||||
"format": "prettier --write .",
|
||||
"storybook": "concurrently \"npm run storybook:serve\" \"cargo run -- serve ../example_vault --clean --no-browser --reinitialize --rescan-mode mirror --bind 127.0.0.1:8099\"",
|
||||
"storybook:serve": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-essentials": "^7.6.16",
|
||||
"@storybook/addon-interactions": "^7.6.16",
|
||||
"@storybook/addon-links": "^7.6.16",
|
||||
"@storybook/blocks": "^7.6.16",
|
||||
"@storybook/svelte": "^7.6.16",
|
||||
"@storybook/sveltekit": "^7.6.16",
|
||||
"@storybook/test": "^7.6.16",
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
|
@ -21,9 +31,13 @@
|
|||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-storybook": "^0.8.0",
|
||||
"eslint-plugin-svelte": "^2.35.1",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"storybook": "^7.6.16",
|
||||
"svelte": "^4.2.7",
|
||||
"svelte-check": "^3.6.0",
|
||||
"tslib": "^2.4.1",
|
||||
|
|
6678
webui/pnpm-lock.yaml
6678
webui/pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,53 @@
|
|||
<script lang="ts">
|
||||
import { attributeLabels } from '$lib/util/labels';
|
||||
import UpLink from '$lib/components/display/UpLink.svelte';
|
||||
import Ellipsis from '$lib/components/utils/Ellipsis.svelte';
|
||||
|
||||
export let attribute: string;
|
||||
export let mark = false;
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="attribute mark-attribute"
|
||||
class:formatted={Boolean(Object.keys($attributeLabels).includes(attribute))}
|
||||
class:mark
|
||||
>
|
||||
<UpLink to={{ attribute }}>
|
||||
<Ellipsis
|
||||
value={$attributeLabels[attribute] || attribute}
|
||||
title={$attributeLabels[attribute]
|
||||
? `${$attributeLabels[attribute]} (${attribute})`
|
||||
: attribute}
|
||||
/>
|
||||
</UpLink>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.attribute {
|
||||
min-width: 0;
|
||||
font-family: var(--monospace-font);
|
||||
&.formatted {
|
||||
font-family: var(--default-font);
|
||||
}
|
||||
|
||||
&.mark {
|
||||
position: relative;
|
||||
top: 0.2em;
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
font-size: 0.9em;
|
||||
&::after {
|
||||
content: '\00a0→';
|
||||
|
||||
position: absolute;
|
||||
top: calc(-50% + 2px);
|
||||
left: calc(50% - 2px);
|
||||
|
||||
transform: translateX(-50%);
|
||||
font-size: 0.66em;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,7 +1,8 @@
|
|||
<script lang="ts">
|
||||
import type { UpEntry } from '@upnd/upend';
|
||||
import { attributeLabels } from '../../util/labels';
|
||||
import UpObject from './UpObject.svelte';
|
||||
import Ellipsis from '$lib/components/utils/Ellipsis.svelte';
|
||||
import UpAttribute from '$lib/components/display/UpAttribute.svelte';
|
||||
export let resolve = true;
|
||||
|
||||
export let entry: UpEntry;
|
||||
|
@ -11,14 +12,12 @@
|
|||
<div class="entity">
|
||||
<UpObject plain link address={entry.entity} labels={resolve ? undefined : []} />
|
||||
</div>
|
||||
<div class="attribute" title={entry.attribute}>
|
||||
{$attributeLabels[entry.attribute] || entry.attribute}
|
||||
</div>
|
||||
<UpAttribute attribute={entry.attribute} mark />
|
||||
<div class="value value-{entry.value.t.toLowerCase()}">
|
||||
{#if entry.value.t === 'Address'}
|
||||
<UpObject link address={entry.value.c} labels={resolve ? undefined : []} />
|
||||
{:else}
|
||||
{entry.value.c}
|
||||
<Ellipsis value={entry.value.c} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -40,18 +39,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.attribute {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
&::before {
|
||||
content: '→\00a0';
|
||||
}
|
||||
&::after {
|
||||
content: '\00a0→';
|
||||
}
|
||||
}
|
||||
|
||||
:global(.value-value) {
|
||||
font-family: var(--monospace-font);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
import { vaultInfo } from '$lib/util/info';
|
||||
import type { BrowseContext } from '$lib/util/browse';
|
||||
import { Query, type UpObject } from '@upnd/upend';
|
||||
import type { ADDRESS_TYPE, EntityInfo, IValue } from '@upnd/upend/types';
|
||||
import type { ADDRESS_TYPE, EntityInfo } from '@upnd/upend/types';
|
||||
import { useEntity } from '$lib/entity';
|
||||
import { i18n } from '$lib/i18n';
|
||||
import api from '$lib/api';
|
||||
|
@ -29,7 +29,7 @@
|
|||
export let labels: string[] | undefined = undefined;
|
||||
export let link = false;
|
||||
export let banner = false;
|
||||
export let resolve = !(labels || []).length || banner;
|
||||
export let resolve: boolean = !(labels || []).length || banner;
|
||||
export let backpath = 0;
|
||||
export let select = true;
|
||||
export let plain = false;
|
||||
|
@ -168,7 +168,6 @@
|
|||
class:show-type={$entityInfo?.t === 'Url' && !addressIds.length}
|
||||
>
|
||||
<HashBadge {address} />
|
||||
<div class="separator" />
|
||||
<div class="label" class:resolving title={displayLabel}>
|
||||
<Editable
|
||||
value={{ t: 'String', c: displayLabel }}
|
||||
|
@ -295,11 +294,11 @@
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
margin-left: 0.25em;
|
||||
}
|
||||
|
||||
.label-inner {
|
||||
max-width: 100%;
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
|
||||
&.banner .label {
|
||||
|
@ -348,10 +347,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
width: 0.5em;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin: 0 0.1em;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<script lang="ts">
|
||||
import { formatDuration } from '$lib/util/fragments/time';
|
||||
import Ellipsis from '$lib/components/utils/Ellipsis.svelte';
|
||||
import Editable from '$lib/components/utils/Editable.svelte';
|
||||
import UpObject from '$lib/components/display/UpObject.svelte';
|
||||
import { IValue } from '@upnd/upend';
|
||||
import { formatRelative, fromUnixTime } from 'date-fns';
|
||||
import filesize from 'filesize';
|
||||
import { ATTR_ADDED } from '@upnd/upend/constants';
|
||||
|
||||
export let value: IValue;
|
||||
export let attribute: string | undefined;
|
||||
export let labels: string[] | undefined = undefined;
|
||||
|
||||
function formatValue(value: string | number | null, attribute: string | undefined): string {
|
||||
if (attribute) {
|
||||
try {
|
||||
switch (attribute) {
|
||||
case 'FILE_SIZE':
|
||||
return filesize(parseInt(String(value), 10), { base: 2 });
|
||||
case ATTR_ADDED:
|
||||
case 'LAST_VISITED':
|
||||
return formatRelative(fromUnixTime(parseInt(String(value), 10)), new Date());
|
||||
case 'NUM_VISITED':
|
||||
return `${value} times`;
|
||||
case 'MEDIA_DURATION':
|
||||
return formatDuration(parseInt(String(value), 10));
|
||||
}
|
||||
} catch {
|
||||
// noop.
|
||||
}
|
||||
}
|
||||
return String(value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="cell value mark-value" data-address={value.t === 'Address' ? value.c : undefined}>
|
||||
<Editable {value} on:edit>
|
||||
{#if value.t === 'Address'}
|
||||
<UpObject link address={String(value.c)} {labels} on:resolved />
|
||||
{:else}
|
||||
<div class:formatted={Boolean(formatValue(value.c, attribute))}>
|
||||
<Ellipsis value={formatValue(value.c, attribute) || String(value.c)} />
|
||||
</div>
|
||||
{/if}
|
||||
</Editable>
|
||||
</div>
|
|
@ -72,6 +72,10 @@
|
|||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.editable {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
{/if}
|
||||
<div class="items">
|
||||
{#each sortedEntities as entity (entity)}
|
||||
<div data-address={entity} data-select-mode={select} use:observe class="item">
|
||||
<div data-address={entity} data-select-mode={select} use:observe class="row">
|
||||
{#if visible.has(entity)}
|
||||
{#if thumbnails}
|
||||
<UpObjectCard
|
||||
|
@ -247,7 +247,7 @@
|
|||
align-items: stretch;
|
||||
}
|
||||
|
||||
.item {
|
||||
.row {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -259,7 +259,7 @@
|
|||
}
|
||||
|
||||
.entitylist:not(.has-thumbnails) {
|
||||
.item {
|
||||
.row {
|
||||
display: flex;
|
||||
.object {
|
||||
width: 100%;
|
||||
|
@ -280,7 +280,7 @@
|
|||
}
|
||||
|
||||
.entitylist.has-thumbnails {
|
||||
.item {
|
||||
.row {
|
||||
position: relative;
|
||||
|
||||
.icon {
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
import { i18n } from '$lib/i18n';
|
||||
import UpLink from '../display/UpLink.svelte';
|
||||
import { ATTR_ADDED, ATTR_LABEL } from '@upnd/upend/constants';
|
||||
import UpAttribute from '$lib/components/display/UpAttribute.svelte';
|
||||
import UpValue from '$lib/components/display/UpValue.svelte';
|
||||
|
||||
const dispatch = createEventDispatcher<{ change: WidgetChange }>();
|
||||
|
||||
|
@ -40,7 +42,7 @@
|
|||
|
||||
$: templateColumns = (
|
||||
(displayColumns || []).map((column, idx) => {
|
||||
if (columnWidths?.[idx]) return columnWidths[idx];
|
||||
if (columnWidths?.[idx]) return columnWidths?.[idx];
|
||||
return 'minmax(6em, auto)';
|
||||
}) as string[]
|
||||
)
|
||||
|
@ -193,25 +195,6 @@
|
|||
value: $i18n.t('Value')
|
||||
};
|
||||
|
||||
function formatValue(value: string | number | null, attribute: string): string {
|
||||
try {
|
||||
switch (attribute) {
|
||||
case 'FILE_SIZE':
|
||||
return filesize(parseInt(String(value), 10), { base: 2 });
|
||||
case ATTR_ADDED:
|
||||
case 'LAST_VISITED':
|
||||
return formatRelative(fromUnixTime(parseInt(String(value), 10)), new Date());
|
||||
case 'NUM_VISITED':
|
||||
return `${value} times`;
|
||||
case 'MEDIA_DURATION':
|
||||
return formatDuration(parseInt(String(value), 10));
|
||||
}
|
||||
} catch {
|
||||
// noop.
|
||||
}
|
||||
return String(value);
|
||||
}
|
||||
|
||||
// Unused attributes
|
||||
let unusedAttributes: string[] = [];
|
||||
|
||||
|
@ -255,42 +238,19 @@
|
|||
/>
|
||||
</div>
|
||||
{:else if column == ATTR_COL}
|
||||
<div
|
||||
class="cell mark-attribute"
|
||||
class:formatted={Boolean(Object.keys($attributeLabels).includes(entry.attribute))}
|
||||
>
|
||||
<UpLink to={{ attribute: entry.attribute }}>
|
||||
<Ellipsis
|
||||
value={$attributeLabels[entry.attribute] || entry.attribute}
|
||||
title={$attributeLabels[entry.attribute]
|
||||
? `${$attributeLabels[entry.attribute]} (${entry.attribute})`
|
||||
: entry.attribute}
|
||||
/>
|
||||
</UpLink>
|
||||
<div class="cell">
|
||||
<UpAttribute attribute={entry.attribute} />
|
||||
</div>
|
||||
{:else if column == VALUE_COL}
|
||||
<div
|
||||
class="cell value mark-value"
|
||||
data-address={entry.value.t === 'Address' ? entry.value.c : undefined}
|
||||
>
|
||||
<Editable value={entry.value} on:edit={(ev) => updateEntry(entry, ev.detail)}>
|
||||
{#if entry.value.t === 'Address'}
|
||||
<UpObject
|
||||
link
|
||||
address={String(entry.value.c)}
|
||||
labels={$labelListing?.getObject(String(entry.value.c))?.identify() || []}
|
||||
on:resolved={(event) => {
|
||||
addSortKeys(String(entry.value.c), event.detail, true);
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<div class:formatted={Boolean(formatValue(entry.value.c, entry.attribute))}>
|
||||
<Ellipsis
|
||||
value={formatValue(entry.value.c, entry.attribute) || String(entry.value.c)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</Editable>
|
||||
<div class="cell">
|
||||
<UpValue
|
||||
value={entry.value}
|
||||
labels={$labelListing?.getObject(String(entry.value.c))?.identify() || []}
|
||||
on:edit={(ev) => updateEntry(entry, ev.detail)}
|
||||
on:resolved={(event) => {
|
||||
addSortKeys(String(entry.value.c), event.detail, true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<div>?</div>
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
<script lang="ts">
|
||||
import { readable, type Readable } from 'svelte/store';
|
||||
import { Query, type UpListing } from '@upnd/upend';
|
||||
import { Any } from '@upnd/upend/query';
|
||||
import type { Address } from '@upnd/upend/types';
|
||||
import { query } from '$lib/entity';
|
||||
import UpObject from '../display/UpObject.svelte';
|
||||
import UpObjectCard from '../display/UpObjectCard.svelte';
|
||||
import { ATTR_LABEL } from '@upnd/upend/constants';
|
||||
import { i18n } from '$lib/i18n';
|
||||
import IconButton from '../utils/IconButton.svelte';
|
||||
import Selector, { type SelectorValue } from '../utils/Selector.svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import type { WidgetChange } from '$lib/types/base';
|
||||
import debug from 'debug';
|
||||
import api from '$lib/api';
|
||||
import UpAttribute from '$lib/components/display/UpAttribute.svelte';
|
||||
import UpValue from '$lib/components/display/UpValue.svelte';
|
||||
const dispatch = createEventDispatcher();
|
||||
const dbg = debug(`kestrel:Table`);
|
||||
|
||||
export let entities: Address[];
|
||||
export let sort = true;
|
||||
export let address: Address | undefined = undefined;
|
||||
export let columns: string[] = [];
|
||||
|
||||
let currentColumns: string[] = columns;
|
||||
|
||||
let values: UpListing | undefined = undefined;
|
||||
$: update(entities, currentColumns);
|
||||
async function update(entities: Address[], columns: string[]) {
|
||||
values = await api.query(
|
||||
Query.matches(
|
||||
entities.map((entity) => `@${entity}`),
|
||||
columns,
|
||||
Any
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$: deduplicatedEntities = Array.from(new Set(entities));
|
||||
|
||||
// Sorting
|
||||
let sortedEntities: Address[] = [];
|
||||
|
||||
let sortKeys: { [key: string]: string[] } = {};
|
||||
function addSortKeys(key: string, vals: string[], resort: boolean) {
|
||||
if (!sortKeys[key]) {
|
||||
sortKeys[key] = [];
|
||||
}
|
||||
let changed = false;
|
||||
vals.forEach((val) => {
|
||||
if (!sortKeys[key].includes(val)) {
|
||||
changed = true;
|
||||
sortKeys[key].push(val);
|
||||
}
|
||||
});
|
||||
|
||||
if (resort && changed) sortEntities();
|
||||
}
|
||||
|
||||
function sortEntities() {
|
||||
if (!sort) return;
|
||||
|
||||
sortedEntities = deduplicatedEntities.concat();
|
||||
|
||||
sortedEntities.sort((a, b) => {
|
||||
if (!sortKeys[a]?.length || !sortKeys[b]?.length) {
|
||||
if (Boolean(sortKeys[a]?.length) && !sortKeys[b]?.length) {
|
||||
return -1;
|
||||
} else if (!sortKeys[a]?.length && Boolean(sortKeys[b]?.length)) {
|
||||
return 1;
|
||||
} else {
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
} else {
|
||||
return sortKeys[a][0].localeCompare(sortKeys[b][0], undefined, {
|
||||
numeric: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Labelling
|
||||
let labelListing: Readable<UpListing | undefined> = readable(undefined);
|
||||
$: {
|
||||
const addressesString = deduplicatedEntities.map((addr) => `@${addr}`).join(' ');
|
||||
|
||||
labelListing = query(`(matches (in ${addressesString}) "${ATTR_LABEL}" ? )`).result;
|
||||
}
|
||||
|
||||
$: {
|
||||
if ($labelListing) {
|
||||
deduplicatedEntities.forEach((address) => {
|
||||
addSortKeys(address, $labelListing?.getObject(address).identify() || [], false);
|
||||
});
|
||||
sortEntities();
|
||||
}
|
||||
}
|
||||
|
||||
if (!sort) {
|
||||
sortedEntities = entities;
|
||||
}
|
||||
|
||||
// Visibility
|
||||
let visible: Set<string> = new Set();
|
||||
let observer = new IntersectionObserver((intersections) => {
|
||||
intersections.forEach((intersection) => {
|
||||
const address = (intersection.target as HTMLElement).dataset['address'];
|
||||
if (!address) {
|
||||
console.warn('Intersected wrong element?');
|
||||
return;
|
||||
}
|
||||
|
||||
if (intersection.isIntersecting) {
|
||||
visible.add(address);
|
||||
}
|
||||
visible = visible;
|
||||
});
|
||||
});
|
||||
|
||||
function observe(node: HTMLElement) {
|
||||
observer.observe(node);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
observer.unobserve(node);
|
||||
}
|
||||
};
|
||||
}
|
||||
//
|
||||
// // Adding
|
||||
// let addSelector: Selector | undefined;
|
||||
// let adding = false;
|
||||
//
|
||||
// $: if (adding && addSelector) addSelector.focus();
|
||||
//
|
||||
// function addEntity(ev: CustomEvent<SelectorValue>) {
|
||||
// dbg('Adding entity', ev.detail);
|
||||
// const addAddress = ev.detail?.t == 'Address' ? ev.detail.c : undefined;
|
||||
// if (!addAddress) return;
|
||||
//
|
||||
// dispatch('change', {
|
||||
// type: 'entry-add',
|
||||
// address: addAddress
|
||||
// } as WidgetChange);
|
||||
// }
|
||||
//
|
||||
// function removeEntity(address: string) {
|
||||
// if (confirm($i18n.t('Are you sure you want to remove this entry from members?') || '')) {
|
||||
// dbg('Removing entity', address);
|
||||
// dispatch('change', {
|
||||
// type: 'entry-delete',
|
||||
// address
|
||||
// } as WidgetChange);
|
||||
// }
|
||||
// }
|
||||
</script>
|
||||
|
||||
<div class="table" style="--columns-count: {currentColumns.length}">
|
||||
{#if !sortedEntities.length}
|
||||
<div class="message">
|
||||
{$i18n.t('No entries.')}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="header">
|
||||
<div>
|
||||
{$i18n.t('Name')}
|
||||
</div>
|
||||
{#each currentColumns as attribute}
|
||||
<UpAttribute {attribute} />
|
||||
{/each}
|
||||
</div>
|
||||
{#each sortedEntities as entity (entity)}
|
||||
<div data-address={entity} use:observe class="row" class:visible={visible.has(entity)}>
|
||||
{#if visible.has(entity)}
|
||||
<div class="object">
|
||||
<UpObject
|
||||
link
|
||||
address={entity}
|
||||
labels={sortKeys[entity]}
|
||||
on:resolved={(event) => {
|
||||
addSortKeys(entity, event.detail, true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{#each currentColumns as attribute}
|
||||
{@const value = values?.getObject(entity)?.get(attribute)}
|
||||
{#if value}
|
||||
<UpValue {value} {attribute} />
|
||||
{:else}
|
||||
<div class="null">X</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{:else}
|
||||
<div class="skeleton" style="text-align: center">...</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use '../../styles/colors';
|
||||
|
||||
.table {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr repeat(var(--columns-count), 1fr);
|
||||
|
||||
gap: 0.2em;
|
||||
|
||||
.header,
|
||||
.row.visible {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.row:not(.visible) {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -2,10 +2,15 @@ import api from '$lib/api';
|
|||
import { i18n } from '$lib/i18n';
|
||||
import { derived, readable, type Readable } from 'svelte/store';
|
||||
import type { AttributeListingResult } from '@upnd/upend/types';
|
||||
import debug from 'debug';
|
||||
|
||||
const dbg = debug('kestrel:labels');
|
||||
|
||||
const databaseAttributeLabels: Readable<{ [key: string]: string }> = readable({}, (set) => {
|
||||
const result: Record<string, string> = {};
|
||||
dbg('Fetching all attributes');
|
||||
api.fetchAllAttributes().then((attributes: AttributeListingResult) => {
|
||||
dbg('Fetched all attributes: %o', attributes);
|
||||
attributes.forEach((attribute) => {
|
||||
if (attribute.labels.length) {
|
||||
result[attribute.name] = attribute.labels.sort()[0];
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import type { Meta, StoryObj } from '@storybook/svelte';
|
||||
import BlobPreview from '../lib/components/display/BlobPreview.svelte';
|
||||
import {
|
||||
audioAddress,
|
||||
imageAddress,
|
||||
imageVerticalAddress,
|
||||
stlAddress,
|
||||
videoAddress,
|
||||
videoVerticalAddress
|
||||
} from './common';
|
||||
|
||||
const meta: Meta<BlobPreview> = {
|
||||
title: 'Blobs/BlobPreview',
|
||||
component: BlobPreview,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
onLoaded: {
|
||||
action: 'loaded'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<BlobPreview>;
|
||||
|
||||
export const Image: Story = {
|
||||
args: { address: imageAddress }
|
||||
};
|
||||
|
||||
export const ImageVertical: Story = {
|
||||
args: { address: imageVerticalAddress }
|
||||
};
|
||||
|
||||
export const Audio: Story = {
|
||||
args: { address: audioAddress }
|
||||
};
|
||||
|
||||
export const Video: Story = {
|
||||
args: { address: videoAddress }
|
||||
};
|
||||
|
||||
export const VideoVertical: Story = {
|
||||
args: { address: videoVerticalAddress }
|
||||
};
|
||||
|
||||
export const Model3d: Story = {
|
||||
args: { address: stlAddress }
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
import type { Meta, StoryObj } from '@storybook/svelte';
|
||||
import BlobViewer from '../lib/components/display/BlobViewer.svelte';
|
||||
import {
|
||||
audioAddress,
|
||||
imageAddress,
|
||||
imageVerticalAddress,
|
||||
stlAddress,
|
||||
videoAddress,
|
||||
videoVerticalAddress
|
||||
} from './common';
|
||||
|
||||
const meta: Meta<BlobViewer> = {
|
||||
title: 'Blobs/BlobViewer',
|
||||
component: BlobViewer,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
detail: {
|
||||
control: {
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<BlobViewer>;
|
||||
|
||||
export const Image: Story = {
|
||||
args: { address: imageAddress }
|
||||
};
|
||||
|
||||
export const ImageVertical: Story = {
|
||||
args: { address: imageVerticalAddress }
|
||||
};
|
||||
|
||||
export const Audio: Story = {
|
||||
args: { address: audioAddress }
|
||||
};
|
||||
|
||||
export const Video: Story = {
|
||||
args: { address: videoAddress }
|
||||
};
|
||||
|
||||
export const VideoVertical: Story = {
|
||||
args: { address: videoVerticalAddress }
|
||||
};
|
||||
|
||||
export const Model3d: Story = {
|
||||
args: { address: stlAddress }
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
import type { Meta, StoryObj } from '@storybook/svelte';
|
||||
import EntityList from '../lib/components/widgets/EntityList.svelte';
|
||||
import { imageAddress, imageVerticalAddress, videoAddress, videoVerticalAddress } from './common';
|
||||
|
||||
const meta: Meta<EntityList> = {
|
||||
title: 'Widgets/EntityList',
|
||||
component: EntityList,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
entities: [imageAddress, imageVerticalAddress, videoAddress, videoVerticalAddress]
|
||||
}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<EntityList>;
|
||||
|
||||
export const Thumbnails: Story = {
|
||||
args: {
|
||||
thumbnails: true
|
||||
}
|
||||
};
|
||||
|
||||
export const Plain: Story = {
|
||||
args: {
|
||||
thumbnails: false
|
||||
}
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
<slot />
|
||||
|
||||
<style>
|
||||
:global(body.sb-main-fullscreen) {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
:global(#storybook-root) {
|
||||
display: contents;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,11 @@
|
|||
<div class="narrow">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.narrow {
|
||||
width: 256px;
|
||||
border: 1px dashed red;
|
||||
padding: 1em 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,90 @@
|
|||
import type { Meta, StoryObj } from '@storybook/svelte';
|
||||
import Selector from '../lib/components/utils/Selector.svelte';
|
||||
import NarrowDecorator from './NarrowDecorator.svelte';
|
||||
|
||||
const meta: Meta<Selector> = {
|
||||
title: 'Widgets/Selector',
|
||||
component: Selector,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
onInput: {
|
||||
action: 'input'
|
||||
},
|
||||
onFocus: {
|
||||
action: 'focus'
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<Selector>;
|
||||
|
||||
export const Attribute: Story = {
|
||||
args: {
|
||||
types: ['Attribute', 'NewAttribute']
|
||||
}
|
||||
};
|
||||
|
||||
export const AttributeInitial: Story = {
|
||||
args: {
|
||||
types: ['Attribute'],
|
||||
initial: {
|
||||
t: 'Attribute',
|
||||
name: 'INITIAL_ATTR'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const AllValues: Story = {
|
||||
args: {
|
||||
types: ['Attribute', 'NewAttribute', 'Address', 'NewAddress', 'String', 'Number']
|
||||
}
|
||||
};
|
||||
|
||||
export const Entities: Story = {
|
||||
args: {
|
||||
types: ['Address', 'NewAddress']
|
||||
}
|
||||
};
|
||||
|
||||
export const ExistingEntities: Story = {
|
||||
args: {
|
||||
types: ['Address']
|
||||
}
|
||||
};
|
||||
|
||||
export const Strings: Story = {
|
||||
args: {
|
||||
types: ['String']
|
||||
}
|
||||
};
|
||||
|
||||
export const StringInitial: Story = {
|
||||
args: {
|
||||
types: ['String'],
|
||||
initial: {
|
||||
t: 'String',
|
||||
c: 'An Initial String.'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const Numbers: Story = {
|
||||
args: {
|
||||
types: ['Number']
|
||||
}
|
||||
};
|
||||
|
||||
export const MultipleValues: Story = {
|
||||
args: {
|
||||
types: ['String', 'Number']
|
||||
}
|
||||
};
|
||||
|
||||
export const Narrow: Story = {
|
||||
args: {
|
||||
types: AllValues.args!.types
|
||||
},
|
||||
decorators: [() => NarrowDecorator as any]
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
import type { Meta, StoryObj } from '@storybook/svelte';
|
||||
import Table from '../lib/components/widgets/Table.svelte';
|
||||
import { imageAddress, imageVerticalAddress, videoAddress, videoVerticalAddress } from './common';
|
||||
|
||||
const meta: Meta<Table> = {
|
||||
title: 'Widgets/Table',
|
||||
component: Table,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
entities: [imageAddress, imageVerticalAddress, videoAddress, videoVerticalAddress]
|
||||
}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<Table>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const Mixed: Story = {
|
||||
args: {
|
||||
columns: ['MEDIA_DURATION', 'FILE_SIZE']
|
||||
}
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
import type { Meta, StoryObj } from '@storybook/svelte';
|
||||
import { UpEntry, UpListing } from '@upnd/upend';
|
||||
import { entryAddress, videoAddress } from './common';
|
||||
import NarrowDecorator from './NarrowDecorator.svelte';
|
||||
import UpEntryComponent from '../lib/components/display/UpEntry.svelte';
|
||||
|
||||
const entry = new UpEntry(
|
||||
entryAddress,
|
||||
{
|
||||
entity: videoAddress,
|
||||
attribute: 'ATTRIBUTE_PERHAPS_LONG',
|
||||
value: { t: 'String', c: 'This Is A Video' },
|
||||
provenance: 'MOCK',
|
||||
timestamp: new Date().toISOString()
|
||||
},
|
||||
new UpListing({})
|
||||
);
|
||||
|
||||
const meta: Meta<UpEntryComponent> = {
|
||||
title: 'Display/UpEntry',
|
||||
component: UpEntryComponent,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
entry
|
||||
},
|
||||
argTypes: {
|
||||
address: {
|
||||
defaultValue: entry,
|
||||
name: 'Entry'
|
||||
},
|
||||
onResolved: {
|
||||
action: 'resolved'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<UpEntryComponent>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const Overflow: Story = {
|
||||
args: {
|
||||
labels: ['qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm'.repeat(3)]
|
||||
},
|
||||
decorators: [() => NarrowDecorator as any]
|
||||
};
|
|
@ -0,0 +1,63 @@
|
|||
import type { Meta, StoryObj } from '@storybook/svelte';
|
||||
import UpObject from '../lib/components/display/UpObject.svelte';
|
||||
import { videoAddress } from './common';
|
||||
import NarrowDecorator from './NarrowDecorator.svelte';
|
||||
|
||||
const address = videoAddress;
|
||||
|
||||
const meta: Meta<UpObject> = {
|
||||
title: 'Display/UpObject',
|
||||
component: UpObject,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
address
|
||||
},
|
||||
argTypes: {
|
||||
address: {
|
||||
defaultValue: address,
|
||||
name: 'Address',
|
||||
type: 'string'
|
||||
},
|
||||
onResolved: {
|
||||
action: 'resolved'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<UpObject>;
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/7.0/svelte/writing-stories/args
|
||||
export const Default: Story = {};
|
||||
|
||||
export const WithLabels: Story = {
|
||||
args: {
|
||||
labels: ['Label 1', 'Label B', 'Label III']
|
||||
}
|
||||
};
|
||||
|
||||
export const Link: Story = {
|
||||
args: {
|
||||
link: true
|
||||
}
|
||||
};
|
||||
|
||||
export const Banner: Story = {
|
||||
args: {
|
||||
banner: true
|
||||
}
|
||||
};
|
||||
|
||||
export const BannerWithLabels: Story = {
|
||||
args: {
|
||||
banner: true,
|
||||
labels: ['Label 1', 'Label B', 'Label III']
|
||||
}
|
||||
};
|
||||
|
||||
export const Overflow: Story = {
|
||||
args: {
|
||||
labels: ['qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm'.repeat(3)]
|
||||
},
|
||||
decorators: [() => NarrowDecorator as any]
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
import type { Meta, StoryObj } from '@storybook/svelte';
|
||||
import UpObjectCard from '../lib/components/display/UpObjectCard.svelte';
|
||||
import { imageAddress } from './common';
|
||||
|
||||
const address = imageAddress;
|
||||
|
||||
const meta: Meta<UpObjectCard> = {
|
||||
title: 'Display/UpObjectCard',
|
||||
component: UpObjectCard,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
address
|
||||
},
|
||||
argTypes: {
|
||||
address: {
|
||||
defaultValue: address,
|
||||
name: 'Address',
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<UpObjectCard>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const WithLabels: Story = {
|
||||
args: {
|
||||
labels: ['Label 1', 'Label B', 'Label III']
|
||||
}
|
||||
};
|
||||
|
||||
export const WithoutThumbnail: Story = {
|
||||
args: {
|
||||
thumbnail: false
|
||||
}
|
||||
};
|
||||
|
||||
export const Small: Story = {
|
||||
args: {
|
||||
banner: false
|
||||
}
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
export const imageAddress = 'zb2rhYSdmX5kD5vkUErWkmTpyhGugBX8WqBuLLQdgox8ztwwx';
|
||||
export const imageVerticalAddress = 'zb2rhmTC5cXbcQ3kgXkcksWWBbR4VrzU5L3S9kbyMPCicVy9L';
|
||||
|
||||
export const audioAddress = 'zb2rhj3LpjUDtka3WuygZJGcEbgmrEyjBY6Y6ya9PVVEkbkke';
|
||||
|
||||
export const videoAddress = 'zb2rhnhv2Me2ZWohSYp7kyf1KAQbZ1zsLficHsaWTgoex67iJ';
|
||||
export const videoVerticalAddress = 'zb2rhocWjf4rc39Wi7TDv6KaVxs2iTQqN6CVYR6m7M8AYgp9c';
|
||||
|
||||
export const stlAddress = 'zb2rhbprcQL38kifW8aMW8cvgWymtaBEe6fK9n3nzDum25Paf';
|
||||
|
||||
export const entryAddress = 'zb2rhkxWUCBYuXGF4dCEDWrR48V19ujimULcSGvThknLEBrDm';
|
|
@ -10,7 +10,8 @@
|
|||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist", "src/stories"]
|
||||
// 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
|
||||
|
|
Loading…
Reference in New Issue