@nu-art/ts-workspace-frontend 0.400.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/module-pack.d.ts +2 -0
- package/core/module-pack.js +22 -0
- package/index.d.ts +5 -0
- package/index.js +23 -0
- package/modules/ModuleFE_Workspace.d.ts +17 -0
- package/modules/ModuleFE_Workspace.js +50 -0
- package/package.json +62 -0
- package/ui/Panels.d.ts +17 -0
- package/ui/Panels.js +42 -0
- package/ui/TS_OrientedWorkspace.d.ts +44 -0
- package/ui/TS_OrientedWorkspace.js +129 -0
- package/ui/TS_Workspace.d.ts +20 -0
- package/ui/TS_Workspace.js +57 -0
- package/ui/TS_Workspace.scss +69 -0
- package/ui/types.d.ts +52 -0
- package/ui/types.js +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Live-Docs will allow you to add and edit tool-tips from within your app...
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
import { ModuleFE_Workspace } from '../modules/ModuleFE_Workspace.js';
|
|
19
|
+
export const ModulePack_Frontend_TSWorkspace = [
|
|
20
|
+
ModuleFE_Workspace,
|
|
21
|
+
];
|
|
22
|
+
export * from '../modules/ModuleFE_Workspace.js';
|
package/index.d.ts
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Permissions management system, define access level for each of
|
|
3
|
+
* your server apis, and restrict users by giving them access levels
|
|
4
|
+
*
|
|
5
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
6
|
+
*
|
|
7
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License.
|
|
9
|
+
* You may obtain a copy of the License at
|
|
10
|
+
*
|
|
11
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
*
|
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
* See the License for the specific language governing permissions and
|
|
17
|
+
* limitations under the License.
|
|
18
|
+
*/
|
|
19
|
+
export * from './core/module-pack.js';
|
|
20
|
+
export * from './ui/TS_Workspace.js';
|
|
21
|
+
export * from './ui/Panels.js';
|
|
22
|
+
export * from './ui/TS_OrientedWorkspace.js';
|
|
23
|
+
export * from './ui/types.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Module, TypedMap } from '@nu-art/ts-common';
|
|
2
|
+
import { PanelConfig } from '../index.js';
|
|
3
|
+
type Config = {
|
|
4
|
+
defaultConfigs: TypedMap<PanelConfig>;
|
|
5
|
+
accountResolver: () => string;
|
|
6
|
+
};
|
|
7
|
+
export declare class ModuleFE_Workspace_Class extends Module<Config> {
|
|
8
|
+
private workspacesToUpsert;
|
|
9
|
+
private upsertRunnable;
|
|
10
|
+
getWorkspaceConfigByKey: (key: string) => PanelConfig<any>;
|
|
11
|
+
private getWorkspaceByKey;
|
|
12
|
+
private getStorageKeyForWorkspace;
|
|
13
|
+
setWorkspaceByKey: (key: string, config: PanelConfig<any>) => Promise<void>;
|
|
14
|
+
deleteWorkspaceByKey: (key: string) => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare const ModuleFE_Workspace: ModuleFE_Workspace_Class;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* A typescript & react boilerplate with api call example
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
import { StorageKey } from '@nu-art/thunderstorm-frontend/index';
|
|
19
|
+
import { _values, BadImplementationException, Module } from '@nu-art/ts-common';
|
|
20
|
+
export class ModuleFE_Workspace_Class extends Module {
|
|
21
|
+
workspacesToUpsert = {};
|
|
22
|
+
upsertRunnable;
|
|
23
|
+
getWorkspaceConfigByKey = (key) => {
|
|
24
|
+
const workspace = this.getWorkspaceByKey(key);
|
|
25
|
+
const config = workspace?.config || this.config.defaultConfigs[key];
|
|
26
|
+
if (!config)
|
|
27
|
+
throw new BadImplementationException(`Could not find config for key ${key}`);
|
|
28
|
+
return config;
|
|
29
|
+
};
|
|
30
|
+
getWorkspaceByKey = (key) => {
|
|
31
|
+
return this.getStorageKeyForWorkspace(key).get();
|
|
32
|
+
};
|
|
33
|
+
getStorageKeyForWorkspace = (key) => new StorageKey(`workspace_key__${key}`);
|
|
34
|
+
setWorkspaceByKey = async (key, config) => {
|
|
35
|
+
this.workspacesToUpsert[key] = { key: key, config: config };
|
|
36
|
+
clearTimeout(this.upsertRunnable);
|
|
37
|
+
this.upsertRunnable = setTimeout(async () => {
|
|
38
|
+
const values = _values(this.workspacesToUpsert);
|
|
39
|
+
values.forEach(workspace => {
|
|
40
|
+
this.logInfo('SET WORKSPACE KEY', `KEY: ${workspace.key}`);
|
|
41
|
+
this.getStorageKeyForWorkspace(workspace.key).set(workspace);
|
|
42
|
+
});
|
|
43
|
+
this.workspacesToUpsert = {};
|
|
44
|
+
}, 500);
|
|
45
|
+
};
|
|
46
|
+
deleteWorkspaceByKey = async (key) => {
|
|
47
|
+
this.getStorageKeyForWorkspace(key).delete();
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export const ModuleFE_Workspace = new ModuleFE_Workspace_Class();
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nu-art/ts-workspace-frontend",
|
|
3
|
+
"version": "0.400.7",
|
|
4
|
+
"description": "TS Workspace Frontend",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"TacB0sS",
|
|
7
|
+
"express",
|
|
8
|
+
"infra",
|
|
9
|
+
"live-docs",
|
|
10
|
+
"nu-art",
|
|
11
|
+
"thunderstorm",
|
|
12
|
+
"typescript"
|
|
13
|
+
],
|
|
14
|
+
"license": "Apache-2.0",
|
|
15
|
+
"author": "TacB0sS",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"directory": "dist",
|
|
21
|
+
"linkDirectory": true
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@nu-art/ts-workspace-shared": "0.400.7",
|
|
25
|
+
"@nu-art/firebase-frontend": "0.400.7",
|
|
26
|
+
"@nu-art/firebase-shared": "0.400.7",
|
|
27
|
+
"@nu-art/thunderstorm-frontend": "0.400.7",
|
|
28
|
+
"@nu-art/thunderstorm-shared": "0.400.7",
|
|
29
|
+
"@nu-art/ts-common": "0.400.7",
|
|
30
|
+
"@nu-art/user-account-frontend": "0.400.7",
|
|
31
|
+
"@nu-art/user-account-shared": "0.400.7",
|
|
32
|
+
"express": "^4.18.2",
|
|
33
|
+
"firebase": "^11.9.0",
|
|
34
|
+
"firebase-admin": "13.4.0",
|
|
35
|
+
"firebase-functions": "6.3.2",
|
|
36
|
+
"moment": "^2.29.4",
|
|
37
|
+
"react": "^18.0.0",
|
|
38
|
+
"react-dom": "^18.0.0",
|
|
39
|
+
"react-router-dom": "^6.9.0",
|
|
40
|
+
"request": "^2.88.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/react": "^18.0.0",
|
|
44
|
+
"@types/express": "^4.17.17",
|
|
45
|
+
"@types/history": "^4.7.2",
|
|
46
|
+
"@types/request": "^2.48.1"
|
|
47
|
+
},
|
|
48
|
+
"unitConfig": {
|
|
49
|
+
"type": "typescript-lib"
|
|
50
|
+
},
|
|
51
|
+
"type": "module",
|
|
52
|
+
"exports": {
|
|
53
|
+
".": {
|
|
54
|
+
"types": "./index.d.ts",
|
|
55
|
+
"import": "./index.js"
|
|
56
|
+
},
|
|
57
|
+
"./*": {
|
|
58
|
+
"types": "./*.d.ts",
|
|
59
|
+
"import": "./*.js"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
package/ui/Panels.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Config_PanelParent, PanelConfig, Props_WorkspacePanel, State_WorkspacePanel } from './types.js';
|
|
2
|
+
import { ComponentAsync, ComponentSync } from '@nu-art/thunderstorm-frontend/index';
|
|
3
|
+
export declare abstract class PanelBaseSync<Config, State = {}, Props = {}> extends ComponentSync<Props_WorkspacePanel<Config, Props> & Props, State_WorkspacePanel<Config, State>> {
|
|
4
|
+
protected shouldAlwaysReDerive: boolean;
|
|
5
|
+
protected deriveStateFromProps(nextProps: Props_WorkspacePanel<Config, Props>): State_WorkspacePanel<Config, State>;
|
|
6
|
+
shouldReDeriveState(nextProps: Readonly<Props_WorkspacePanel<Config, Props>>): boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare abstract class PanelBaseAsync<Config, State = {}, Props = {}> extends ComponentAsync<Props_WorkspacePanel<Config, Props>, State_WorkspacePanel<Config, State>> {
|
|
9
|
+
protected deriveStateFromProps(nextProps: Props_WorkspacePanel<Config, Props>): Promise<State_WorkspacePanel<Config, State>>;
|
|
10
|
+
shouldReDeriveState(nextProps: Readonly<Props_WorkspacePanel<Config, Props>>): boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare abstract class PanelParentSync<Config = {}, State = {}, Props = {}> extends PanelBaseSync<Config_PanelParent<Config>, State, Props> {
|
|
13
|
+
renderPanel(panel: PanelConfig): string | number | true | Iterable<import("react").ReactNode> | import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
}
|
|
15
|
+
export declare abstract class PanelParentAsync<Config = {}, State = {}, Props = {}> extends PanelBaseAsync<Config_PanelParent<Config>, State, Props> {
|
|
16
|
+
renderPanel(panel: PanelConfig): string | number | true | Iterable<import("react").ReactNode> | import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
}
|
package/ui/Panels.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ComponentAsync, ComponentSync } from '@nu-art/thunderstorm-frontend/index';
|
|
3
|
+
import { compare, resolveContent } from '@nu-art/ts-common';
|
|
4
|
+
export class PanelBaseSync extends ComponentSync {
|
|
5
|
+
shouldAlwaysReDerive = false;
|
|
6
|
+
deriveStateFromProps(nextProps) {
|
|
7
|
+
return { config: { ...nextProps.config } };
|
|
8
|
+
}
|
|
9
|
+
shouldReDeriveState(nextProps) {
|
|
10
|
+
return this.shouldAlwaysReDerive || !compare(this.state.config, nextProps.config);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class PanelBaseAsync extends ComponentAsync {
|
|
14
|
+
async deriveStateFromProps(nextProps) {
|
|
15
|
+
return { config: { ...nextProps.config } };
|
|
16
|
+
}
|
|
17
|
+
shouldReDeriveState(nextProps) {
|
|
18
|
+
return !compare(this.state.config, nextProps.config);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class PanelParentSync extends PanelBaseSync {
|
|
22
|
+
renderPanel(panel) {
|
|
23
|
+
const ComponentToRender = resolveContent(this.props.instances?.[panel.key], panel.data, this.props.onConfigChanged);
|
|
24
|
+
if (ComponentToRender) {
|
|
25
|
+
this.shouldAlwaysReDerive = true;
|
|
26
|
+
return ComponentToRender;
|
|
27
|
+
}
|
|
28
|
+
const PanelRenderer = this.props.renderers[panel.key];
|
|
29
|
+
return _jsx(PanelRenderer, { config: panel.data, instances: this.props.instances, renderers: this.props.renderers, onConfigChanged: this.props.onConfigChanged });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export class PanelParentAsync extends PanelBaseAsync {
|
|
33
|
+
renderPanel(panel) {
|
|
34
|
+
const ComponentToRender = resolveContent(this.props.instances?.[panel.key], panel.data, this.props.onConfigChanged);
|
|
35
|
+
if (ComponentToRender)
|
|
36
|
+
return ComponentToRender;
|
|
37
|
+
const PanelRenderer = this.props.renderers[panel.key];
|
|
38
|
+
if (!PanelRenderer)
|
|
39
|
+
return `NO RENDERER DEFINED FOR KEY: ${panel.key}`;
|
|
40
|
+
return _jsx(PanelRenderer, { config: panel.data, renderers: this.props.renderers, instances: this.props.instances });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { PanelParentSync } from './Panels.js';
|
|
3
|
+
import { Config_PanelParent, Props_OrientedWorkspace, Props_WorkspaceParentPanel, State_WorkspaceParentPanel } from './types.js';
|
|
4
|
+
type State = {
|
|
5
|
+
factors: number[];
|
|
6
|
+
panelRefs: React.RefObject<HTMLDivElement>[];
|
|
7
|
+
};
|
|
8
|
+
export declare class TS_OrientedWorkspace extends PanelParentSync<{}, State, Props_OrientedWorkspace> {
|
|
9
|
+
private dragStart;
|
|
10
|
+
private firstPanelBounds;
|
|
11
|
+
private secondPanelBounds;
|
|
12
|
+
private ref?;
|
|
13
|
+
protected deriveStateFromProps(nextProps: Props_WorkspaceParentPanel<Config_PanelParent, Props_OrientedWorkspace>): State_WorkspaceParentPanel<{}, State>;
|
|
14
|
+
private calcFactors;
|
|
15
|
+
separatorOnDrag: (e: React.DragEvent<HTMLDivElement>, firstPanelIndex: number, secondPanelIndex: number) => void;
|
|
16
|
+
onDragStart: (e: React.DragEvent<HTMLDivElement>) => void;
|
|
17
|
+
onDragEnd: (e: React.DragEvent<HTMLDivElement>, firstPanelIndex: number, secondPanelIndex: number) => void;
|
|
18
|
+
implementFactors: (factors: {
|
|
19
|
+
index: number;
|
|
20
|
+
factor: number;
|
|
21
|
+
}[]) => void;
|
|
22
|
+
render(): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
}
|
|
24
|
+
export declare class TS_HorizontalWorkspace extends TS_OrientedWorkspace {
|
|
25
|
+
static defaultProps: {
|
|
26
|
+
firstEdge: string;
|
|
27
|
+
secondEdge: string;
|
|
28
|
+
orientation: string;
|
|
29
|
+
dimensionProp: string;
|
|
30
|
+
dimensionClientProp: string;
|
|
31
|
+
mousePos: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export declare class TS_VerticalWorkspace extends TS_OrientedWorkspace {
|
|
35
|
+
static defaultProps: {
|
|
36
|
+
firstEdge: string;
|
|
37
|
+
secondEdge: string;
|
|
38
|
+
orientation: string;
|
|
39
|
+
dimensionProp: string;
|
|
40
|
+
dimensionClientProp: string;
|
|
41
|
+
mousePos: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/* QWorkspaceVertical - content display and resizing
|
|
3
|
+
* When given panel contents and a page, displays content in resizable panels.*/
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { Fragment } from 'react';
|
|
6
|
+
import { PanelParentSync } from './Panels.js';
|
|
7
|
+
export class TS_OrientedWorkspace extends PanelParentSync {
|
|
8
|
+
dragStart = 0;
|
|
9
|
+
firstPanelBounds;
|
|
10
|
+
secondPanelBounds;
|
|
11
|
+
ref;
|
|
12
|
+
deriveStateFromProps(nextProps) {
|
|
13
|
+
this.ref = undefined;
|
|
14
|
+
const panelRefs = this.state?.panelRefs || nextProps.config.panels.map(i => React.createRef());
|
|
15
|
+
return { ...super.deriveStateFromProps(nextProps), factors: [], panelRefs };
|
|
16
|
+
}
|
|
17
|
+
calcFactors(nextProps) {
|
|
18
|
+
let factors = nextProps.config.panels.map(p => p.factor);
|
|
19
|
+
const current = this.ref;
|
|
20
|
+
if (current) {
|
|
21
|
+
const wrapperWidth = current.getBoundingClientRect()[this.props.dimensionProp];
|
|
22
|
+
const separatorPixels = Array.from(current.children).reduce((toRet, element, index) => {
|
|
23
|
+
if (index % 2 === 0)
|
|
24
|
+
return toRet;
|
|
25
|
+
const rect = element.getBoundingClientRect();
|
|
26
|
+
return toRet + rect[this.props.dimensionProp];
|
|
27
|
+
}, 0);
|
|
28
|
+
const containerFactor = (wrapperWidth - separatorPixels) / wrapperWidth;
|
|
29
|
+
factors = factors.map(f => f * containerFactor);
|
|
30
|
+
}
|
|
31
|
+
// const sumOfFactors = factors.reduce((a, b) => a + b, 0);
|
|
32
|
+
this.implementFactors(factors.map((factor, index) => ({ factor, index })));
|
|
33
|
+
return { factors };
|
|
34
|
+
}
|
|
35
|
+
//On drag logic for separator
|
|
36
|
+
separatorOnDrag = (e, firstPanelIndex, secondPanelIndex) => {
|
|
37
|
+
const firstPanel = this.props.config.panels[firstPanelIndex];
|
|
38
|
+
const secondPanel = this.props.config.panels[secondPanelIndex];
|
|
39
|
+
const statePanelsFactors = this.state.factors;
|
|
40
|
+
//Gather data
|
|
41
|
+
const delta = e[this.props.mousePos] - this.dragStart;
|
|
42
|
+
const parentSize = e.currentTarget.parentElement?.[this.props.dimensionClientProp];
|
|
43
|
+
const separatorSize = e.currentTarget?.[this.props.dimensionClientProp];
|
|
44
|
+
//Calculate new heights
|
|
45
|
+
const firstPanelDimension = this.firstPanelBounds[this.props.secondEdge] - this.firstPanelBounds[this.props.firstEdge];
|
|
46
|
+
const secondPanelDimension = this.secondPanelBounds[this.props.secondEdge] - this.secondPanelBounds[this.props.firstEdge];
|
|
47
|
+
let firstPanelSize = firstPanelDimension + delta;
|
|
48
|
+
let secondPanelSize = secondPanelDimension - delta;
|
|
49
|
+
const minFirstPanel = firstPanel.min || 100;
|
|
50
|
+
const minSecondPanel = secondPanel.min || 100;
|
|
51
|
+
if (firstPanelDimension + delta < minFirstPanel) {
|
|
52
|
+
firstPanelSize = minFirstPanel;
|
|
53
|
+
secondPanelSize = firstPanelDimension + secondPanelDimension - firstPanelSize;
|
|
54
|
+
}
|
|
55
|
+
if (secondPanelDimension - delta < minSecondPanel) {
|
|
56
|
+
secondPanelSize = minSecondPanel;
|
|
57
|
+
firstPanelSize = firstPanelDimension + secondPanelDimension - secondPanelSize;
|
|
58
|
+
}
|
|
59
|
+
const firstPanelFactor = firstPanelSize / parentSize;
|
|
60
|
+
const sum = statePanelsFactors[firstPanelIndex] + statePanelsFactors[secondPanelIndex];
|
|
61
|
+
statePanelsFactors[firstPanelIndex] = firstPanelFactor;
|
|
62
|
+
statePanelsFactors[secondPanelIndex] = sum - firstPanelFactor;
|
|
63
|
+
//Set config panels factors
|
|
64
|
+
const originalFactorSum = firstPanel.factor + secondPanel.factor;
|
|
65
|
+
firstPanel.factor = (firstPanelSize + separatorSize / 2) / parentSize;
|
|
66
|
+
secondPanel.factor = originalFactorSum - firstPanel.factor;
|
|
67
|
+
this.implementFactors([
|
|
68
|
+
{ index: firstPanelIndex, factor: firstPanel.factor },
|
|
69
|
+
{ index: secondPanelIndex, factor: secondPanel.factor }
|
|
70
|
+
]);
|
|
71
|
+
};
|
|
72
|
+
//Gets called whenever dragging starts
|
|
73
|
+
onDragStart = (e) => {
|
|
74
|
+
//Set new empty image as the ghost image, position far offscreen
|
|
75
|
+
const img = new Image();
|
|
76
|
+
e.dataTransfer.setDragImage(img, -9999, -9999);
|
|
77
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
78
|
+
e.dataTransfer.dropEffect = 'none';
|
|
79
|
+
this.dragStart = e[this.props.mousePos];
|
|
80
|
+
this.firstPanelBounds = e.currentTarget.previousElementSibling?.getBoundingClientRect();
|
|
81
|
+
this.secondPanelBounds = e.currentTarget.nextElementSibling?.getBoundingClientRect();
|
|
82
|
+
};
|
|
83
|
+
//Gets called whenever dragging stops
|
|
84
|
+
onDragEnd = (e, firstPanelIndex, secondPanelIndex) => {
|
|
85
|
+
//Init vars
|
|
86
|
+
this.dragStart = 0;
|
|
87
|
+
this.props.onConfigChanged();
|
|
88
|
+
};
|
|
89
|
+
//Script to implement the factor on panels in the dom
|
|
90
|
+
implementFactors = (factors) => {
|
|
91
|
+
factors.forEach(factor => {
|
|
92
|
+
const element = this.state.panelRefs[factor.index].current;
|
|
93
|
+
if (!element)
|
|
94
|
+
return;
|
|
95
|
+
element.style[this.props.dimensionProp] = ((factor.factor) * 100) + '%';
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
//Main Render
|
|
99
|
+
render() {
|
|
100
|
+
const panels = this.props.config.panels;
|
|
101
|
+
return (_jsx("div", { ref: _ref => {
|
|
102
|
+
if (this.ref || !_ref)
|
|
103
|
+
return;
|
|
104
|
+
this.ref = _ref;
|
|
105
|
+
this.setState(this.calcFactors(this.props));
|
|
106
|
+
}, className: `ts-workspace__${this.props.orientation}`, children: panels.map((panel, i) => _jsxs(Fragment, { children: [_jsx("div", { className: 'ts-workspace__panel', ref: this.state.panelRefs[i], draggable: false, children: this.renderPanel(panel) }), i !== (panels.length - 1) &&
|
|
107
|
+
_jsx("div", { className: `ts-workspace__separator`, draggable: true, tabIndex: 1, onDragStart: this.onDragStart, onDrag: (e) => this.separatorOnDrag(e, i, i + 1), onDragEnd: (e) => this.onDragEnd(e, i, i + 1) })] }, i)) }));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export class TS_HorizontalWorkspace extends TS_OrientedWorkspace {
|
|
111
|
+
static defaultProps = {
|
|
112
|
+
firstEdge: 'left',
|
|
113
|
+
secondEdge: 'right',
|
|
114
|
+
orientation: 'horizontal',
|
|
115
|
+
dimensionProp: 'width',
|
|
116
|
+
dimensionClientProp: 'clientWidth',
|
|
117
|
+
mousePos: 'pageX'
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export class TS_VerticalWorkspace extends TS_OrientedWorkspace {
|
|
121
|
+
static defaultProps = {
|
|
122
|
+
firstEdge: 'top',
|
|
123
|
+
secondEdge: 'bottom',
|
|
124
|
+
orientation: 'vertical',
|
|
125
|
+
dimensionProp: 'height',
|
|
126
|
+
dimensionClientProp: 'clientHeight',
|
|
127
|
+
mousePos: 'pageY'
|
|
128
|
+
};
|
|
129
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BaseAsyncState, ComponentSync } from '@nu-art/thunderstorm-frontend/index';
|
|
2
|
+
import './TS_Workspace.scss';
|
|
3
|
+
import { Props_BaseWorkspace } from './types.js';
|
|
4
|
+
type Props = Props_BaseWorkspace & {
|
|
5
|
+
workspaceKey: string;
|
|
6
|
+
id?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
};
|
|
9
|
+
type State = {
|
|
10
|
+
key: string;
|
|
11
|
+
};
|
|
12
|
+
export declare class TS_Workspace extends ComponentSync<Props, State> {
|
|
13
|
+
private toRender;
|
|
14
|
+
protected deriveStateFromProps(nextProps: Props, state: State): State;
|
|
15
|
+
protected _deriveStateFromProps(nextProps: Props): (BaseAsyncState & State) | undefined;
|
|
16
|
+
shouldComponentUpdate(nextProps: Readonly<Props>, nextState: Readonly<BaseAsyncState & State>, nextContext: any): boolean;
|
|
17
|
+
private onConfigChanged;
|
|
18
|
+
render(): string | import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Thunderstorm is a full web app framework!
|
|
4
|
+
*
|
|
5
|
+
* Typescript & Express backend infrastructure that natively runs on firebase function
|
|
6
|
+
* Typescript & React frontend infrastructure
|
|
7
|
+
*
|
|
8
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
9
|
+
*
|
|
10
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
11
|
+
* you may not use this file except in compliance with the License.
|
|
12
|
+
* You may obtain a copy of the License at
|
|
13
|
+
*
|
|
14
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
15
|
+
*
|
|
16
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
17
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
18
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
19
|
+
* See the License for the specific language governing permissions and
|
|
20
|
+
* limitations under the License.
|
|
21
|
+
*/
|
|
22
|
+
/* QWorkspaceVertical - content display and resizing
|
|
23
|
+
* When given panel contents and a page, displays content in resizable panels.*/
|
|
24
|
+
import { _className, ComponentSync } from '@nu-art/thunderstorm-frontend/index';
|
|
25
|
+
import './TS_Workspace.scss';
|
|
26
|
+
import { ModuleFE_Workspace } from '../modules/ModuleFE_Workspace.js';
|
|
27
|
+
export class TS_Workspace extends ComponentSync {
|
|
28
|
+
toRender = false;
|
|
29
|
+
deriveStateFromProps(nextProps, state) {
|
|
30
|
+
state.key = nextProps.workspaceKey;
|
|
31
|
+
return state;
|
|
32
|
+
}
|
|
33
|
+
_deriveStateFromProps(nextProps) {
|
|
34
|
+
const state = super._deriveStateFromProps(nextProps);
|
|
35
|
+
this.toRender = true;
|
|
36
|
+
return state;
|
|
37
|
+
}
|
|
38
|
+
shouldComponentUpdate(nextProps, nextState, nextContext) {
|
|
39
|
+
if (this.toRender) {
|
|
40
|
+
this.toRender = false;
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return super.shouldComponentUpdate(nextProps, nextState, nextContext);
|
|
44
|
+
}
|
|
45
|
+
onConfigChanged = async () => {
|
|
46
|
+
const config = ModuleFE_Workspace.getWorkspaceConfigByKey(this.state.key);
|
|
47
|
+
await ModuleFE_Workspace.setWorkspaceByKey(this.state.key, config);
|
|
48
|
+
};
|
|
49
|
+
render() {
|
|
50
|
+
const config = ModuleFE_Workspace.getWorkspaceConfigByKey(this.state.key);
|
|
51
|
+
const PanelRenderer = this.props.renderers[config.key];
|
|
52
|
+
if (!PanelRenderer)
|
|
53
|
+
return `COULD NOT GET THE WORKSPACE RENDERER FOR KEY ${config.key}`;
|
|
54
|
+
const className = _className('ts-workspace', this.props.className);
|
|
55
|
+
return _jsx("div", { className: className, id: this.props.id, children: _jsx(PanelRenderer, { config: config.data, renderers: this.props.renderers, instances: this.props.instances, onConfigChanged: this.onConfigChanged }) });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
@mixin separator ($dir) {
|
|
2
|
+
background: #eeeeee;
|
|
3
|
+
position: relative;
|
|
4
|
+
-webkit-user-drag: element;
|
|
5
|
+
|
|
6
|
+
@if $dir == 'horizontal' {
|
|
7
|
+
width: 5px;
|
|
8
|
+
height: 100%;
|
|
9
|
+
cursor: col-resize;
|
|
10
|
+
border-right: 1px solid black;
|
|
11
|
+
}
|
|
12
|
+
@if $dir == 'vertical' {
|
|
13
|
+
width: 100%;
|
|
14
|
+
height: 5px;
|
|
15
|
+
cursor: row-resize;
|
|
16
|
+
border-bottom: 1px solid black;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@mixin tsWorkspace ($dir) {
|
|
21
|
+
width: 100%;
|
|
22
|
+
height: 100%;
|
|
23
|
+
display: flex;
|
|
24
|
+
|
|
25
|
+
@if $dir == 'horizontal' {
|
|
26
|
+
& > .ts-workspace__separator {
|
|
27
|
+
@include separator($dir);
|
|
28
|
+
}
|
|
29
|
+
& > .ts-workspace__panel {
|
|
30
|
+
width: 33%;
|
|
31
|
+
height: 100%;
|
|
32
|
+
display: flex;
|
|
33
|
+
position: relative;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
//Apply right padding to left and middle panels for scrollbar
|
|
36
|
+
&.left, &.middle {
|
|
37
|
+
padding-right: 5px;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
@if $dir == 'vertical' {
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
|
|
44
|
+
& > .ts-workspace__separator {
|
|
45
|
+
@include separator($dir);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
& > .ts-workspace__panel {
|
|
49
|
+
width: 100%;
|
|
50
|
+
display: flex;
|
|
51
|
+
position: relative;
|
|
52
|
+
overflow: hidden;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.ts-workspace {
|
|
58
|
+
width: 100%;
|
|
59
|
+
height: 100%;
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
|
|
63
|
+
.ts-workspace__vertical {
|
|
64
|
+
@include tsWorkspace('vertical')
|
|
65
|
+
}
|
|
66
|
+
.ts-workspace__horizontal {
|
|
67
|
+
@include tsWorkspace('horizontal')
|
|
68
|
+
}
|
|
69
|
+
}
|
package/ui/types.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { DB_Object, ResolvableContent, TypedMap } from '@nu-art/ts-common';
|
|
3
|
+
import { BaseAsyncState } from '@nu-art/thunderstorm-frontend/index';
|
|
4
|
+
export type Props_BaseWorkspace = {
|
|
5
|
+
renderers: TypedMap<React.ElementType>;
|
|
6
|
+
instances?: TypedMap<ResolvableContent<React.ReactNode, [any, Props_ConfigChanged['onConfigChanged']]>>;
|
|
7
|
+
};
|
|
8
|
+
export type Props_ConfigChanged = {
|
|
9
|
+
onConfigChanged: () => void;
|
|
10
|
+
};
|
|
11
|
+
export type Props_WorkspacePanel<Config, Props = {}> = Props & Props_ConfigChanged & Props_BaseWorkspace & {
|
|
12
|
+
config: Config;
|
|
13
|
+
};
|
|
14
|
+
export type State_WorkspacePanel<Config, State = {}> = BaseAsyncState & State & {
|
|
15
|
+
config: Config;
|
|
16
|
+
};
|
|
17
|
+
export type Config_PanelParent<ChildConfig = {}> = ChildConfig & {
|
|
18
|
+
panels: PanelConfig[];
|
|
19
|
+
};
|
|
20
|
+
export type State_WorkspaceParentPanel<Config, State = {}> = State_WorkspacePanel<Config_PanelParent<Config>, State>;
|
|
21
|
+
export type Props_WorkspaceParentPanel<Config, Props = {}> = Props_WorkspacePanel<Config_PanelParent<Config>, Props>;
|
|
22
|
+
export type Props_OrientedWorkspace = {
|
|
23
|
+
firstEdge: 'top' | 'left';
|
|
24
|
+
secondEdge: 'bottom' | 'right';
|
|
25
|
+
orientation: 'horizontal' | 'vertical';
|
|
26
|
+
dimensionProp: 'height' | 'width';
|
|
27
|
+
dimensionClientProp: 'clientHeight' | 'clientWidth';
|
|
28
|
+
mousePos: 'pageY' | 'pageX';
|
|
29
|
+
};
|
|
30
|
+
export type PanelsData = {
|
|
31
|
+
horizontalSpace: {
|
|
32
|
+
panels: PanelConfig<any, any>[];
|
|
33
|
+
};
|
|
34
|
+
verticalSpace: {
|
|
35
|
+
panels: PanelConfig<any, any>[];
|
|
36
|
+
};
|
|
37
|
+
topPanel: never;
|
|
38
|
+
leftPanel: never;
|
|
39
|
+
centerPanel: never;
|
|
40
|
+
rightPanel: never;
|
|
41
|
+
bottomPanel: never;
|
|
42
|
+
};
|
|
43
|
+
export type PanelConfig<PanelType extends keyof PanelsData = keyof PanelsData, PanelData extends PanelsData[PanelType] = PanelsData[PanelType]> = {
|
|
44
|
+
name: string;
|
|
45
|
+
visible: boolean;
|
|
46
|
+
factor: number;
|
|
47
|
+
min: number;
|
|
48
|
+
key: PanelType;
|
|
49
|
+
} & {
|
|
50
|
+
data?: PanelData;
|
|
51
|
+
};
|
|
52
|
+
export type WorkspaceConfig = DB_Object & PanelConfig;
|
package/ui/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|