Compare commits
509 Commits
Author | SHA1 | Date | |
---|---|---|---|
87872191e2 | |||
2d3fd74333 | |||
eebe898dcc | |||
ca73d00f68 | |||
14bdc46073 | |||
bf04ce6a8f | |||
9dc6dab3a5 | |||
a21a3b6918 | |||
6ae21d73aa | |||
941871991f | |||
497c38f426 | |||
bfaa1623d9 | |||
5ffa5a2adc | |||
16d1375e47 | |||
30eda34f37 | |||
2cc7eb1ead | |||
64f5bee801 | |||
9d57f983dd | |||
8ccd21df36 | |||
c22c994d12 | |||
01369444b7 | |||
4beb15f70c | |||
30170bcd2e | |||
f29a8de504 | |||
965ab02315 | |||
991784eae6 | |||
b474b7986c | |||
98542252cb | |||
0d78deadf2 | |||
5108f47e56 | |||
7d4e5f2ca7 | |||
c0ad0f4570 | |||
d56eb602a9 | |||
f1c791eb12 | |||
e872188be7 | |||
2d712e78b0 | |||
ebeecd0686 | |||
1d09f994c6 | |||
686c3714fc | |||
e29086036c | |||
78e24aa720 | |||
7c8876c835 | |||
2222fb1e01 | |||
46b30a1ef0 | |||
d49d5f70ef | |||
76a950e2ba | |||
077aba5e58 | |||
857362423f | |||
e7232b6a53 | |||
2eb26544b3 | |||
a40834d1cf | |||
0c1159d4c7 | |||
4584765046 | |||
5817068cb5 | |||
8fa01fbaad | |||
9cdae8ccdb | |||
7e1c5f3dbb | |||
1f3f17247c | |||
f07f2bb95e | |||
0b2f6715e0 | |||
e473364d40 | |||
554b72b075 | |||
2c34ec8b39 | |||
e6b8e2de19 | |||
a99d270ef1 | |||
93ee42135c | |||
f3ca4a114a | |||
7515b824eb | |||
18b98b831a | |||
d99fc8bde9 | |||
f8d5f86814 | |||
9c1de08b4b | |||
7f26337e1b | |||
49f3fc8feb | |||
5613ad7fa6 | |||
5af43900c4 | |||
c5598f95ef | |||
13d0cf729c | |||
032e928dde | |||
14ab3682f2 | |||
c554e730a6 | |||
4d5a490e80 | |||
7708c89fe1 | |||
0a0be3e357 | |||
7b7c469fab | |||
d852186888 | |||
6cfda1ebf3 | |||
8e0062fdd5 | |||
844cc30551 | |||
64074e37fc | |||
cd9b028e9b | |||
81da871e38 | |||
90e78a2e31 | |||
5cec1fea73 | |||
52130d67e2 | |||
a73ad40eb1 | |||
6589818b0b | |||
555fa32ac2 | |||
50a84f2422 | |||
c724a3e85b | |||
b47530e254 | |||
b80fdf113e | |||
963edbffa3 | |||
f3687f724f | |||
a736ee9800 | |||
bea2047092 | |||
7d98ac8f38 | |||
32244bb450 | |||
b154631c77 | |||
466a24ac10 | |||
7db91a2fe6 | |||
46652dec6f | |||
50e591b80c | |||
6710a163a9 | |||
a39f43f79a | |||
964520a2f9 | |||
6e680085a4 | |||
286a843b67 | |||
df7c5ebafc | |||
9927323a9d | |||
66f3e66c8b | |||
c68b0c5090 | |||
53ac03507d | |||
0031b51bcf | |||
67a8c6e591 | |||
806390a068 | |||
508b18bc3b | |||
c2499ea507 | |||
c0c91aec94 | |||
a27008a295 | |||
7e11627618 | |||
968ce63a53 | |||
7c0eb3290f | |||
62403625ba | |||
9a34b03540 | |||
8bb63df7e3 | |||
65cd73845a | |||
8534bc254b | |||
2a2fd324a0 | |||
58e3de2559 | |||
c30736870d | |||
cfd48de885 | |||
462df2b648 | |||
f64da93cf9 | |||
a55db621ef | |||
c033bdfc3b | |||
2610e56ec1 | |||
08aa9e3fe4 | |||
411ae7ee07 | |||
41700c1eb1 | |||
8d7bac9793 | |||
0229eefa4d | |||
61f646743a | |||
e3babde7e8 | |||
c389e43e93 | |||
1511db4eea | |||
d713756034 | |||
17d224332d | |||
32dd5e769b | |||
12ace00a90 | |||
bbc09330c9 | |||
82ead7bd1a | |||
f8f9b150b8 | |||
494e8b7e26 | |||
c76d364071 | |||
760e0085f7 | |||
6890ca1f1f | |||
9ca000cf06 | |||
1c0f5129a9 | |||
69e17949f4 | |||
bcfd3495dd | |||
03a46a72c5 | |||
2465ce5f9b | |||
00ac83f205 | |||
67065b1ffb | |||
783c10479f | |||
d4eae1cd9e | |||
4e674f67c5 | |||
889a543780 | |||
fc5f3a9576 | |||
66644364b5 | |||
51febdae06 | |||
745ff299dc | |||
3606d60ba6 | |||
8970a79141 | |||
566a7ce148 | |||
362bef15e3 | |||
446c494863 | |||
dbe2f2f217 | |||
02ca92a431 | |||
a9015e787c | |||
9cd28fa819 | |||
7b3793e943 | |||
a22c04d98d | |||
5367512292 | |||
9c387f8ace | |||
c3ec288d09 | |||
9d952afebb | |||
621262fde7 | |||
e3e79d9a11 | |||
d08a92814e | |||
a6f277250e | |||
09cb82d587 | |||
316e2a0b27 | |||
e0d2679801 | |||
107800a057 | |||
4ee8512ee4 | |||
f75a3714ae | |||
d6047f2e78 | |||
03769c8412 | |||
1a782eb4ee | |||
a27adf25cb | |||
96e237b9af | |||
710e06b2f1 | |||
a3bc25c4ac | |||
ee5b712a37 | |||
879ae5ad91 | |||
2bbda416b2 | |||
de88957857 | |||
aa0c63d569 | |||
d843f27fd3 | |||
a26755b7d3 | |||
345a562a21 | |||
3fae99554d | |||
ed30ed3f8f | |||
beef47959b | |||
aec2cf18fd | |||
0f45633666 | |||
8588888ce7 | |||
2a62a635cd | |||
0eb2557956 | |||
9960bf7018 | |||
f26f0d0450 | |||
53fadfcbd5 | |||
497d3a3ac5 | |||
37524765ae | |||
ab0219d3e4 | |||
7cefd9cba5 | |||
4cf5ca2d7f | |||
a9791220fb | |||
4aed14c7a2 | |||
49d1cba3fd | |||
9bacca3070 | |||
42e7ae6d6b | |||
a8b244520c | |||
9879a2cb6a | |||
e2a54c6f18 | |||
dfd13e641a | |||
2284159b72 | |||
1de86c6bfa | |||
62087a686a | |||
572deb990e | |||
719c63a092 | |||
9d9700214f | |||
bc82e110ef | |||
fe15ebe82d | |||
1b8577d300 | |||
ef4cfb81d8 | |||
abea5942b7 | |||
a6274e9a2d | |||
8b3752f586 | |||
c8e1d24224 | |||
dbd7748ac0 | |||
68984d5702 | |||
5237439f88 | |||
c3df73616f | |||
a03b095d14 | |||
9a18658e09 | |||
2910757e8c | |||
a00bacd4ff | |||
01963447dd | |||
5d1d1ba4ba | |||
7885422033 | |||
fb48425c13 | |||
3792c5edf5 | |||
2abd91ab4a | |||
310910e8ee | |||
3301ad1556 | |||
0f8a7a5a7b | |||
f1a0c5741c | |||
cbf60db9fa | |||
34d5bda579 | |||
916ba68c94 | |||
46fc396772 | |||
0e77baf600 | |||
89fd8b5080 | |||
884f9725b5 | |||
48e093b1ba | |||
2b3875d738 | |||
279d1c2f3f | |||
29f2839d5b | |||
96683b4380 | |||
36fbf7f29e | |||
67d4c216ed | |||
9d51cdd480 | |||
d6679ca41f | |||
baadd1e06b | |||
600ab56026 | |||
ae40a9f541 | |||
48f7768b96 | |||
de3f9fcb34 | |||
313009d3ff | |||
83ede1edea | |||
ec50b4b3a0 | |||
4fbb1caaeb | |||
41a2529275 | |||
41ff71e6b0 | |||
2d07765c16 | |||
15db9fb6d9 | |||
73d92624de | |||
0d77685338 | |||
05bbfccd22 | |||
5cca89de37 | |||
ab5b7a5b89 | |||
253d5623c4 | |||
1048192bfa | |||
289e6d37fa | |||
7308c1454f | |||
cfc880d7c2 | |||
c32cff8126 | |||
4526c0c365 | |||
45e7f39af0 | |||
26b72fbccf | |||
8acf3f4196 | |||
75c8b409cc | |||
6509ddb81c | |||
7cc0173e3c | |||
f797d71e52 | |||
54db88e4b4 | |||
93c73c36c8 | |||
9c9bd4a180 | |||
0a54de3e59 | |||
d6b4b59e6d | |||
c4236d28c6 | |||
5f1b29f742 | |||
e7978a22e4 | |||
15de86774b | |||
8f57647c85 | |||
59c5bcabd5 | |||
cae421e140 | |||
05b2b09395 | |||
4dbd4f84c1 | |||
bb0ca2f19d | |||
55175f9ac7 | |||
0be0f9fa34 | |||
7baab5d7ea | |||
c3bdec176b | |||
2a84e2c270 | |||
c86f7d466c | |||
9a6db7d882 | |||
b69b1179a1 | |||
0df9fe750c | |||
0d05bfa5ff | |||
4dc9e04c2e | |||
5341a0d6b6 | |||
615bea9fc4 | |||
e518bc6976 | |||
076f8c7a91 | |||
b016b959cf | |||
eca68e28a2 | |||
68a164aac2 | |||
9b5448e096 | |||
232d063485 | |||
6a357cb227 | |||
7b8218ab77 | |||
5b6436b023 | |||
57edbb872b | |||
76f82fe15e | |||
0b03718f4a | |||
2754de26d8 | |||
abc91600e2 | |||
6a8a4aa4d2 | |||
6a6f3b1907 | |||
0dc8e21e07 | |||
68ccc02699 | |||
ed1c18b8ac | |||
e8cc4c7c90 | |||
187ebed3ab | |||
b909617271 | |||
9c2fe9f739 | |||
ed49de64bc | |||
162003ba7a | |||
5f793f0acc | |||
d23b298bd5 | |||
f9e2f00e9b | |||
6c3645f2f8 | |||
e3a6798469 | |||
60de4ef674 | |||
02e029edbc | |||
ff5a65bdce | |||
daacbbd042 | |||
42b44be143 | |||
7e4c186e66 | |||
f6823639cc | |||
f292fd9692 | |||
fa2ab7730a | |||
3a2ba14287 | |||
c1b5778d01 | |||
24a5f48ce1 | |||
d43b80298b | |||
27d338420c | |||
81f2e662fb | |||
d8905b687f | |||
75f6da194b | |||
e653450ec5 | |||
9de9f0c202 | |||
75929c089d | |||
6a97e8d020 | |||
6aeb970bbe | |||
ea7fa0816d | |||
1b1de04f86 | |||
7941628d1d | |||
369437ceba | |||
72f7782898 | |||
820d6ae40f | |||
5dd3da9f31 | |||
3ce0683a05 | |||
00d41f1b6e | |||
caba7ada28 | |||
6cff32cc36 | |||
e6e8ac9782 | |||
7a13fdcd95 | |||
c450fb32ea | |||
6554bfd721 | |||
9ce4ca14b8 | |||
76bcda760c | |||
6949aed381 | |||
1f3502685f | |||
8d1451fffa | |||
8b2fedf1d6 | |||
30ffb2650a | |||
55b65c7e4c | |||
5c81dd540a | |||
cb5bc809ea | |||
ab1956c452 | |||
3b99796073 | |||
20755775ea | |||
4e1b797377 | |||
4a3aa2d6d9 | |||
4e49045444 | |||
9e54c973d5 | |||
122c535dec | |||
aabda883cd | |||
5890977009 | |||
f4aebcf4e6 | |||
66bf117bfc | |||
f7ee4d77fd | |||
ab19e97c31 | |||
631502b480 | |||
ea519cf543 | |||
91c97cad1d | |||
de958303e3 | |||
95192ea3ce | |||
0b1e50bbc6 | |||
888f07db79 | |||
e14d83b3a7 | |||
f4055fb8c1 | |||
d0d4638264 | |||
7d63f16fc1 | |||
00cb552f44 | |||
2f52f14cf9 | |||
54ce305cf1 | |||
9d5f0b5ff8 | |||
c1594736ec | |||
4eb1abaa39 | |||
b8c231fc61 | |||
260c4a269a | |||
c1e7629f1f | |||
b84e2c4774 | |||
e9374900a0 | |||
486b8cb6a6 | |||
0adb319616 | |||
a6e7adc983 | |||
59dfbb34bb | |||
cf34cea94d | |||
7f5e72c27f | |||
4311c0fff6 | |||
e028f37493 | |||
c6967156d6 | |||
efaf2a78df | |||
e6adbf9b6d | |||
e88605a4aa | |||
6a161982b7 | |||
22d7883c04 | |||
2a613c96a0 | |||
bdd766e4bc | |||
b1ce8f093f | |||
056090856e | |||
fef0705acc | |||
6eced2321f | |||
05a9042de8 | |||
d369805ee8 | |||
3a2f3500fd | |||
2f9711a094 | |||
cf80efd1ec | |||
cf5cd37ebc | |||
88554396a4 | |||
2f13311098 | |||
5407b158d0 | |||
b171eaf3fc | |||
5585d7e304 | |||
02119a1ce4 | |||
222f06bda7 | |||
8ee99136cc | |||
faf35c3144 | |||
ae53459d56 | |||
5e1a32633a | |||
4b1b3ac615 | |||
9f8a5fedfa |
66
.gitea/workflows/default_nottags.yaml
Normal file
66
.gitea/workflows/default_nottags.yaml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
name: Default (not tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags-ignore:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install pnpm and npmci
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
|
||||||
|
- name: Run npm prepare
|
||||||
|
run: npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
124
.gitea/workflows/default_tags.yaml
Normal file
124
.gitea/workflows/default_tags.yaml
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
name: Default (tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm publish
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Code quality
|
||||||
|
run: |
|
||||||
|
npmci command npm install -g typescript
|
||||||
|
npmci npm install
|
||||||
|
|
||||||
|
- name: Trigger
|
||||||
|
run: npmci trigger
|
||||||
|
|
||||||
|
- name: Build docs and upload artifacts
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
pnpm install -g @git.zone/tsdoc
|
||||||
|
npmci command tsdoc
|
||||||
|
continue-on-error: true
|
@ -12,30 +12,38 @@ stages:
|
|||||||
- release
|
- release
|
||||||
- metadata
|
- metadata
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- pnpm install -g pnpm
|
||||||
|
- pnpm install -g @shipzone/npmci
|
||||||
|
- npmci npm prepare
|
||||||
|
|
||||||
# ====================
|
# ====================
|
||||||
# security stage
|
# security stage
|
||||||
# ====================
|
# ====================
|
||||||
mirror:
|
# ====================
|
||||||
stage: security
|
# security stage
|
||||||
script:
|
# ====================
|
||||||
- npmci git mirror
|
auditProductionDependencies:
|
||||||
tags:
|
|
||||||
- lossless
|
|
||||||
- docker
|
|
||||||
- notpriv
|
|
||||||
|
|
||||||
audit:
|
|
||||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
stage: security
|
stage: security
|
||||||
script:
|
script:
|
||||||
- npmci npm prepare
|
|
||||||
- npmci command npm install --ignore-scripts
|
|
||||||
- npmci command npm config set registry https://registry.npmjs.org
|
- npmci command npm config set registry https://registry.npmjs.org
|
||||||
- npmci command npm audit --audit-level=high
|
- npmci command pnpm audit --audit-level=high --prod
|
||||||
tags:
|
tags:
|
||||||
- lossless
|
- lossless
|
||||||
- docker
|
- docker
|
||||||
- notpriv
|
allow_failure: true
|
||||||
|
|
||||||
|
auditDevDependencies:
|
||||||
|
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
stage: security
|
||||||
|
script:
|
||||||
|
- npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
- npmci command pnpm audit --audit-level=high --dev
|
||||||
|
tags:
|
||||||
|
- lossless
|
||||||
|
- docker
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
# ====================
|
# ====================
|
||||||
# test stage
|
# test stage
|
||||||
@ -44,28 +52,22 @@ audit:
|
|||||||
testStable:
|
testStable:
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
- npmci npm prepare
|
|
||||||
- npmci node install stable
|
- npmci node install stable
|
||||||
- npmci npm install
|
- npmci npm install
|
||||||
- npmci npm test
|
- npmci npm test
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
coverage: /\d+.?\d+?\%\s*coverage/
|
||||||
tags:
|
tags:
|
||||||
- lossless
|
|
||||||
- docker
|
- docker
|
||||||
- priv
|
|
||||||
|
|
||||||
testBuild:
|
testBuild:
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
- npmci npm prepare
|
|
||||||
- npmci node install stable
|
- npmci node install stable
|
||||||
- npmci npm install
|
- npmci npm install
|
||||||
- npmci command npm run build
|
- npmci npm build
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
coverage: /\d+.?\d+?\%\s*coverage/
|
||||||
tags:
|
tags:
|
||||||
- lossless
|
|
||||||
- docker
|
- docker
|
||||||
- notpriv
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
stage: release
|
stage: release
|
||||||
@ -85,11 +87,12 @@ release:
|
|||||||
codequality:
|
codequality:
|
||||||
stage: metadata
|
stage: metadata
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
script:
|
script:
|
||||||
- npmci command npm install -g tslint typescript
|
- npmci command npm install -g typescript
|
||||||
- npmci npm prepare
|
- npmci npm prepare
|
||||||
- npmci npm install
|
- npmci npm install
|
||||||
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
|
|
||||||
tags:
|
tags:
|
||||||
- lossless
|
- lossless
|
||||||
- docker
|
- docker
|
||||||
@ -109,11 +112,9 @@ trigger:
|
|||||||
pages:
|
pages:
|
||||||
stage: metadata
|
stage: metadata
|
||||||
script:
|
script:
|
||||||
- npmci node install lts
|
- npmci node install stable
|
||||||
- npmci command npm install -g @gitzone/tsdoc
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci npm install
|
- npmci npm install
|
||||||
- npmci command tsdoc
|
- npmci command npm run buildDocs
|
||||||
tags:
|
tags:
|
||||||
- lossless
|
- lossless
|
||||||
- docker
|
- docker
|
||||||
|
24
.vscode/launch.json
vendored
24
.vscode/launch.json
vendored
@ -2,28 +2,10 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "current file",
|
"command": "npm test",
|
||||||
"type": "node",
|
"name": "Run npm test",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"args": [
|
"type": "node-terminal"
|
||||||
"${relativeFile}"
|
|
||||||
],
|
|
||||||
"runtimeArgs": ["-r", "@gitzone/tsrun"],
|
|
||||||
"cwd": "${workspaceRoot}",
|
|
||||||
"protocol": "inspector",
|
|
||||||
"internalConsoleOptions": "openOnSessionStart"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "test.ts",
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"args": [
|
|
||||||
"test/test.ts"
|
|
||||||
],
|
|
||||||
"runtimeArgs": ["-r", "@gitzone/tsrun"],
|
|
||||||
"cwd": "${workspaceRoot}",
|
|
||||||
"protocol": "inspector",
|
|
||||||
"internalConsoleOptions": "openOnSessionStart"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -15,7 +15,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"projectType": {
|
"projectType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["website", "element", "service", "npm"]
|
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--gitzone element-->
|
<!--gitzone element-->
|
||||||
<!-- made by Lossless GmbH -->
|
<!-- made by Task Venture Capital GmbH -->
|
||||||
<!-- checkout https://maintainedby.lossless.com for awesome OpenSource projects -->
|
<!-- checkout https://maintainedby.lossless.com for awesome OpenSource projects -->
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
@ -9,7 +9,10 @@
|
|||||||
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height"
|
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height"
|
||||||
/>
|
/>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
|
||||||
|
<!--Lets load standard fonts-->
|
||||||
|
<link rel="preconnect" href="https://assetbroker.lossless.one/" crossorigin>
|
||||||
|
<link rel="stylesheet" href="https://assetbroker.lossless.one/fonts/fonts.css">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@ -18,9 +21,8 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script src="../ts_web/index.ts"></script>
|
<script type="module" src="/bundle.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<></>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
10
html/index.ts
Normal file
10
html/index.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// dees tools
|
||||||
|
import * as deesWccTools from '@design.estate/dees-wcctools';
|
||||||
|
import * as deesDomTools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
// elements and pages
|
||||||
|
import * as elements from '../ts_web/elements/index.js';
|
||||||
|
import * as pages from '../ts_web/pages/index.js';
|
||||||
|
|
||||||
|
deesWccTools.setupWccTools(elements as any, pages);
|
||||||
|
deesDomTools.elementBasic.setup();
|
5
license
5
license
@ -8,7 +8,10 @@ copies of the Software, and to permit persons to whom the Software is
|
|||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in all
|
||||||
copies or substantial portions of the Software.
|
copies or substantial portions of the Software. You agree to being mentioned
|
||||||
|
as reference by Lossless GmbH. This includes the use of your entity logos
|
||||||
|
or profile picture by Lossless GmbH on websites and readme's, also on third party
|
||||||
|
pages like gitlab.com or github.com.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"gitzone": {
|
"gitzone": {
|
||||||
"projectType": "element",
|
"projectType": "wcc",
|
||||||
"module": {
|
"module": {
|
||||||
"githost": "gitlab.com",
|
"githost": "gitlab.com",
|
||||||
"gitscope": "designestate",
|
"gitscope": "design.estate",
|
||||||
"gitrepo": "dees-catalog",
|
"gitrepo": "dees-catalog",
|
||||||
"shortDescription": "a webcomponents catalog for handling daily stuff on the web",
|
"description": "a webcomponents catalog for handling daily stuff on the web",
|
||||||
"npmPackagename": "@designestate/dees-catalog",
|
"npmPackagename": "@design.estate/dees-catalog",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"projectDomain": "design.estate"
|
"projectDomain": "design.estate"
|
||||||
}
|
}
|
||||||
|
9798
package-lock.json
generated
9798
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
53
package.json
53
package.json
@ -1,31 +1,47 @@
|
|||||||
{
|
{
|
||||||
"name": "@losslessone_private/dees-catalog",
|
"name": "@design.estate/dees-catalog",
|
||||||
"version": "1.0.18",
|
"version": "1.0.273",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "website for lossless.com",
|
"description": "website for lossless.com",
|
||||||
"main": "dist_ts_web/index.js",
|
"main": "dist_ts_web/index.js",
|
||||||
"typings": "dist_ts_web/index.d.ts",
|
"typings": "dist_ts_web/index.d.ts",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "npm run build",
|
"test": "tstest test/ --web",
|
||||||
"build": "tsbuild custom ts_web --web",
|
"build": "tsbuild element --allowimplicitany && tsbundle element --production",
|
||||||
"watch": "tswatch element"
|
"watch": "tswatch element",
|
||||||
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"author": "Lossless GmbH",
|
"author": "Lossless GmbH",
|
||||||
"license": "UNLICENSED",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitzone/tsrun": "^1.1.17",
|
"@design.estate/dees-domtools": "^2.0.57",
|
||||||
"@pushrocks/smartexpress": "^3.0.10",
|
"@design.estate/dees-element": "^2.0.33",
|
||||||
"lit-element": "^2.0.0-rc.5",
|
"@design.estate/dees-wcctools": "^1.0.87",
|
||||||
"lit-html": "^1.0.0-rc.2",
|
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||||
"typescript": "^3.2.2"
|
"@fortawesome/free-brands-svg-icons": "^6.5.1",
|
||||||
|
"@fortawesome/free-regular-svg-icons": "^6.5.1",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||||
|
"@push.rocks/smarti18n": "^1.0.4",
|
||||||
|
"@push.rocks/smartpromise": "^4.0.3",
|
||||||
|
"@push.rocks/smartstring": "^4.0.13",
|
||||||
|
"@tsclass/tsclass": "^4.0.46",
|
||||||
|
"@webcontainer/api": "^1.1.8",
|
||||||
|
"highlight.js": "11.9.0",
|
||||||
|
"ibantools": "^4.3.9",
|
||||||
|
"monaco-editor": "^0.45.0",
|
||||||
|
"pdfjs-dist": "^4.0.379",
|
||||||
|
"xterm": "^5.3.0",
|
||||||
|
"xterm-addon-fit": "^0.8.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gitzone/tsbuild": "^2.1.8",
|
"@git.zone/tsbuild": "^2.1.72",
|
||||||
"@gitzone/tswatch": "^1.0.30",
|
"@git.zone/tsbundle": "^2.0.15",
|
||||||
"@pushrocks/parcel-plugin-wrapper": "^1.0.5",
|
"@git.zone/tstest": "^1.0.86",
|
||||||
"@pushrocks/projectinfo": "^4.0.2",
|
"@git.zone/tswatch": "^2.0.21",
|
||||||
"tslint": "^5.11.0",
|
"@push.rocks/projectinfo": "^5.0.2",
|
||||||
"tslint-config-prettier": "^1.17.0"
|
"@push.rocks/tapbundle": "^5.0.15",
|
||||||
|
"@types/node": "^20.11.5"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"ts/**/*",
|
"ts/**/*",
|
||||||
@ -38,5 +54,8 @@
|
|||||||
"cli.js",
|
"cli.js",
|
||||||
"npmextra.json",
|
"npmextra.json",
|
||||||
"readme.md"
|
"readme.md"
|
||||||
|
],
|
||||||
|
"browserslist": [
|
||||||
|
"last 1 chrome versions"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
6969
pnpm-lock.yaml
generated
Normal file
6969
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
readme.md
38
readme.md
@ -1,23 +1,32 @@
|
|||||||
# @designestate/dees-catalog
|
# @design.estate/dees-catalog
|
||||||
a webcomponents catalog for handling daily stuff on the web
|
a webcomponents catalog for handling daily stuff on the web
|
||||||
|
|
||||||
## Availabililty and Links
|
## Availabililty and Links
|
||||||
* [npmjs.org (npm package)](https://www.npmjs.com/package/@designestate/dees-catalog)
|
* [npmjs.org (npm package)](https://www.npmjs.com/package/@design.estate/dees-catalog)
|
||||||
* [gitlab.com (source)](https://gitlab.com/designestate/dees-catalog)
|
* [gitlab.com (source)](https://gitlab.com/design.estate/dees-catalog)
|
||||||
* [github.com (source mirror)](https://github.com/designestate/dees-catalog)
|
* [github.com (source mirror)](https://github.com/design.estate/dees-catalog)
|
||||||
* [docs (typedoc)](https://designestate.gitlab.io/dees-catalog/)
|
* [docs (typedoc)](https://design.estate.gitlab.io/dees-catalog/)
|
||||||
|
|
||||||
## Status for master
|
## Status for master
|
||||||
[](https://gitlab.com/designestate/dees-catalog/commits/master)
|
|
||||||
[](https://gitlab.com/designestate/dees-catalog/commits/master)
|
Status Category | Status Badge
|
||||||
[](https://www.npmjs.com/package/@designestate/dees-catalog)
|
-- | --
|
||||||
[](https://snyk.io/test/npm/@designestate/dees-catalog)
|
GitLab Pipelines | [](https://lossless.cloud)
|
||||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
GitLab Pipline Test Coverage | [](https://lossless.cloud)
|
||||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
npm | [](https://lossless.cloud)
|
||||||
[](https://prettier.io/)
|
Snyk | [](https://lossless.cloud)
|
||||||
|
TypeScript Support | [](https://lossless.cloud)
|
||||||
|
node Support | [](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||||
|
Code Style | [](https://lossless.cloud)
|
||||||
|
PackagePhobia (total standalone install weight) | [](https://lossless.cloud)
|
||||||
|
PackagePhobia (package size on registry) | [](https://lossless.cloud)
|
||||||
|
BundlePhobia (total size when bundled) | [](https://lossless.cloud)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
## Contribution
|
||||||
|
|
||||||
|
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
@ -25,7 +34,6 @@ We are always happy for code contributions. If you are not the code contributing
|
|||||||
|
|
||||||
For further information read the linked docs at the top of this readme.
|
For further information read the linked docs at the top of this readme.
|
||||||
|
|
||||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
## Legal
|
||||||
|
> MIT licensed | **©** [Task Venture Capital GmbH](https://task.vc)
|
||||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
||||||
|
|
||||||
[](https://maintainedby.lossless.com)
|
|
||||||
|
12
test/test.browser.ts
Normal file
12
test/test.browser.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { tap, expect, webhelpers } from '@push.rocks/tapbundle';
|
||||||
|
|
||||||
|
import * as deesCatalog from '../ts_web';
|
||||||
|
|
||||||
|
tap.test('should create a working button', async () => {
|
||||||
|
const button: deesCatalog.DeesButton = await webhelpers.fixture(
|
||||||
|
webhelpers.html`<dees-button></dees-button>`
|
||||||
|
);
|
||||||
|
expect(button).toBeInstanceOf(deesCatalog.DeesButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.start();
|
8
ts_web/00_commitinfo_data.ts
Normal file
8
ts_web/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* autocreated commitinfo by @pushrocks/commitinfo
|
||||||
|
*/
|
||||||
|
export const commitinfo = {
|
||||||
|
name: '@design.estate/dees-catalog',
|
||||||
|
version: '1.0.273',
|
||||||
|
description: 'website for lossless.com'
|
||||||
|
}
|
13
ts_web/elements/00colors.ts
Normal file
13
ts_web/elements/00colors.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export const dark = {
|
||||||
|
blue: '#0050b9',
|
||||||
|
blueActive: '#0069f2',
|
||||||
|
blueMuted: '#012452',
|
||||||
|
text: '#ffffff',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const bright = {
|
||||||
|
blue: '#0050b9',
|
||||||
|
blueActive: '#0069f2',
|
||||||
|
blueMuted: '#0069f2',
|
||||||
|
text: '#333333',
|
||||||
|
}
|
13
ts_web/elements/00plugins.ts
Normal file
13
ts_web/elements/00plugins.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// @push.rocks scope
|
||||||
|
import * as smartpromise from '@push.rocks/smartpromise';
|
||||||
|
|
||||||
|
export {
|
||||||
|
smartpromise,
|
||||||
|
}
|
||||||
|
|
||||||
|
// @tsclass scope
|
||||||
|
import * as tsclass from '@tsclass/tsclass';
|
||||||
|
|
||||||
|
export {
|
||||||
|
tsclass
|
||||||
|
}
|
48
ts_web/elements/dees-button-exit.ts
Normal file
48
ts_web/elements/dees-button-exit.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import {
|
||||||
|
cssManager,
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
html,
|
||||||
|
type TemplateResult,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
state,
|
||||||
|
property
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
@customElement('dees-button-exit')
|
||||||
|
export class DeesButtonExit extends DeesElement {
|
||||||
|
// DEMO
|
||||||
|
public static demo = () => html`
|
||||||
|
<dees-button-exit></dees-button-exit>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
@property({
|
||||||
|
type: Number
|
||||||
|
})
|
||||||
|
public size: number = 24;
|
||||||
|
|
||||||
|
public styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
|
||||||
|
`
|
||||||
|
]
|
||||||
|
|
||||||
|
public render (): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
.maincontainer {
|
||||||
|
position: relative;
|
||||||
|
width: ${this.size}px;
|
||||||
|
height: ${this.size}px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="maincontainer">
|
||||||
|
<div class="firstLine"></div>
|
||||||
|
<div class="secondLine"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
15
ts_web/elements/dees-button.demo.ts
Normal file
15
ts_web/elements/dees-button.demo.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<dees-button>This is a slotted Text</dees-button>
|
||||||
|
<p>
|
||||||
|
<dees-button text="Highlighted: This text shows" type="highlighted">Highlighted</dees-button>
|
||||||
|
</p>
|
||||||
|
<p><dees-button type="discreet">This is discreete button</dees-button></p>
|
||||||
|
<p><dees-button disabled>This is a disabled button</dees-button></p>
|
||||||
|
<p><dees-button type="big">This is a slotted Text</dees-button></p>
|
||||||
|
<p><dees-button status="normal">Normal Status</dees-button></p>
|
||||||
|
<p><dees-button disabled status="pending">Pending Status</dees-button></p>
|
||||||
|
<p><dees-button disabled status="success">Success Status</dees-button></p>
|
||||||
|
<p><dees-button disabled status="error">Error Status</dees-button></p>
|
||||||
|
`;
|
209
ts_web/elements/dees-button.ts
Normal file
209
ts_web/elements/dees-button.ts
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
import { demoFunc } from './dees-button.demo.js';
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
unsafeCSS,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-button': DeesButton;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-button')
|
||||||
|
export class DeesButton extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
reflect: true,
|
||||||
|
hasChanged() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
public text: string;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public eventDetailData: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean
|
||||||
|
})
|
||||||
|
public disabled = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean
|
||||||
|
})
|
||||||
|
public isHidden = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String
|
||||||
|
})
|
||||||
|
public type: 'normal' | 'highlighted' | 'discreet' | 'big' = 'normal';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String
|
||||||
|
})
|
||||||
|
public status: 'normal' | 'pending' | 'success' | 'error' = 'normal';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: 'Roboto', 'monospace';
|
||||||
|
}
|
||||||
|
:host([hidden]) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
transition: all 0.1s , color 0s;
|
||||||
|
position: relative;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: ${cssManager.bdTheme('#fff', '#333')};
|
||||||
|
box-shadow: ${cssManager.bdTheme('0px 1px 3px rgba(0,0,0,0.3)', 'none')};
|
||||||
|
border: 1px solid ${cssManager.bdTheme('#eee', '#333')};
|
||||||
|
border-top: ${cssManager.bdTheme('1px solid #eee', '1px solid #444')};
|
||||||
|
border-radius: 4px;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0px 8px;
|
||||||
|
min-width: 100px;
|
||||||
|
user-select: none;
|
||||||
|
color: ${cssManager.bdTheme('#333', ' #ccc')};
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background: #0050b9;
|
||||||
|
color: #ffffff;
|
||||||
|
border: 1px solid #0050b9;
|
||||||
|
border-top: 1px solid #0050b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:active {
|
||||||
|
background: #0069f2;
|
||||||
|
border-top: 1px solid #0069f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.disabled {
|
||||||
|
background: ${cssManager.bdTheme('#ffffff00', '#11111100')};
|
||||||
|
border: 1px dashed ${cssManager.bdTheme('#666666', '#666666')};
|
||||||
|
color: #9b9b9e;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.highlighted {
|
||||||
|
background: #e4002b;
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.highlighted:hover {
|
||||||
|
background: #b50021;
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.discreet {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid #9b9b9e;
|
||||||
|
color: ${cssManager.bdTheme('#000', '#fff')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.discreet:hover {
|
||||||
|
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(255, 255, 255, 0.1)')};
|
||||||
|
}
|
||||||
|
.button.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.big {
|
||||||
|
width: 300px;
|
||||||
|
line-height: 48px;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 0px 48px;
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.pending {
|
||||||
|
border: 1px dashed ${cssManager.bdTheme('#0069f2', '#0069f270')};
|
||||||
|
background: ${cssManager.bdTheme('#0069f2', '#0069f270')};
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.success {
|
||||||
|
border: 1px dashed ${cssManager.bdTheme('#689F38', '#8BC34A70')};
|
||||||
|
background: ${cssManager.bdTheme('#689F38', '#8BC34A70')};
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.error {
|
||||||
|
border: 1px dashed ${cssManager.bdTheme('#B71C1C', '#E64A1970')};
|
||||||
|
background: ${cssManager.bdTheme('#B71C1C', '#E64A1970')};
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
dees-spinner {
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
class="button ${this.isHidden ? 'hidden' : 'block'} ${this.type} ${this.status} ${this.disabled
|
||||||
|
? 'disabled'
|
||||||
|
: null}"
|
||||||
|
@click="${this.dispatchClick}"
|
||||||
|
>
|
||||||
|
${this.status === 'normal' ? html``: html`
|
||||||
|
<dees-spinner .bnw=${true} status="${this.status}"></dees-spinner>
|
||||||
|
`}
|
||||||
|
<div class="textbox">${this.text ? this.text : this.textContent}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async dispatchClick() {
|
||||||
|
if (this.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('clicked', {
|
||||||
|
detail: {
|
||||||
|
data: this.eventDetailData,
|
||||||
|
},
|
||||||
|
bubbles: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
if (!this.textContent) {
|
||||||
|
this.textContent = 'Button';
|
||||||
|
this.performUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
ts_web/elements/dees-chips.demo.ts
Normal file
41
ts_web/elements/dees-chips.demo.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<style>
|
||||||
|
.demoContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
background: #222;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="demoContainer">
|
||||||
|
<dees-chips
|
||||||
|
selectionMode="none"
|
||||||
|
.selectableChips=${[
|
||||||
|
{ key: 'account1', value: 'Payment Account 1' },
|
||||||
|
{ key: 'account2', value: 'PaymentAccount2' },
|
||||||
|
{ key: 'account3', value: 'Payment Account 3' },
|
||||||
|
]}
|
||||||
|
></dees-chips>
|
||||||
|
<dees-chips
|
||||||
|
selectionMode="single"
|
||||||
|
chipsAreRemovable
|
||||||
|
.selectableChips=${[
|
||||||
|
{ key: 'account1', value: 'Payment Account 1' },
|
||||||
|
{ key: 'account2', value: 'PaymentAccount2' },
|
||||||
|
{ key: 'account3', value: 'Payment Account 3' },
|
||||||
|
]}
|
||||||
|
></dees-chips>
|
||||||
|
<dees-chips
|
||||||
|
selectionMode="multiple"
|
||||||
|
.selectableChips=${[
|
||||||
|
{ key: 'account1', value: 'Payment Account 1' },
|
||||||
|
{ key: 'account2', value: 'PaymentAccount2' },
|
||||||
|
{ key: 'account3', value: 'Payment Account 3' },
|
||||||
|
]}
|
||||||
|
></dees-chips>
|
||||||
|
</div>
|
||||||
|
`;
|
195
ts_web/elements/dees-chips.ts
Normal file
195
ts_web/elements/dees-chips.ts
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
unsafeCSS,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { demoFunc } from './dees-chips.demo.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-chips': DeesChips;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tag = { key: string; value: string };
|
||||||
|
|
||||||
|
@customElement('dees-chips')
|
||||||
|
export class DeesChips extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public selectionMode: 'none' | 'single' | 'multiple' = 'single';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public chipsAreRemovable: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
public selectableChips: Tag[] = [];
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public selectedChip: Tag = null;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
public selectedChips: Tag[] = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainbox {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip {
|
||||||
|
border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #444')};
|
||||||
|
background: #333333;
|
||||||
|
display: inline-flex;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 0px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 40px;
|
||||||
|
margin-right: 4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip:hover {
|
||||||
|
background: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip.selected {
|
||||||
|
background: #00a3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chipKey {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
height: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: -8px;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dees-icon {
|
||||||
|
padding: 0px 6px 0px 4px;
|
||||||
|
margin-left: 4px;
|
||||||
|
margin-right: -8px;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
dees-icon:hover {
|
||||||
|
background: #e4002b;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="mainbox">
|
||||||
|
${this.selectableChips.map(
|
||||||
|
(chip) => html`
|
||||||
|
<div
|
||||||
|
@click=${() => this.selectChip(chip)}
|
||||||
|
class="chip ${this.isSelected(chip) ? 'selected' : ''}"
|
||||||
|
>
|
||||||
|
${chip.key ? html`<div class="chipKey">${chip.key}</div>` : html``} ${chip.value}
|
||||||
|
${this.chipsAreRemovable
|
||||||
|
? html`
|
||||||
|
<dees-icon
|
||||||
|
@click=${(event: Event) => {
|
||||||
|
event.stopPropagation(); // prevent the selectChip event from being triggered
|
||||||
|
this.removeChip(chip);
|
||||||
|
}}
|
||||||
|
.iconFA=${'xmark'}
|
||||||
|
></dees-icon>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
if (!this.textContent) {
|
||||||
|
this.textContent = 'Button';
|
||||||
|
this.performUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isSelected(chip: Tag): boolean {
|
||||||
|
if (this.selectionMode === 'single') {
|
||||||
|
return this.selectedChip?.key === chip.key;
|
||||||
|
} else {
|
||||||
|
return this.selectedChips.some((selected) => selected.key === chip.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async selectChip(chip: Tag) {
|
||||||
|
if (this.selectionMode === 'none') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.selectionMode === 'single') {
|
||||||
|
if (this.isSelected(chip)) {
|
||||||
|
this.selectedChip = null;
|
||||||
|
this.selectedChips = [];
|
||||||
|
} else {
|
||||||
|
this.selectedChip = chip;
|
||||||
|
this.selectedChips = [chip];
|
||||||
|
}
|
||||||
|
} else if (this.selectionMode === 'multiple') {
|
||||||
|
if (this.isSelected(chip)) {
|
||||||
|
this.selectedChips = this.selectedChips.filter((selected) => selected.key !== chip.key);
|
||||||
|
} else {
|
||||||
|
this.selectedChips = [...this.selectedChips, chip];
|
||||||
|
}
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
console.log(this.selectedChips);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeChip(chipToRemove: Tag): void {
|
||||||
|
// Remove the chip from selectableChips
|
||||||
|
this.selectableChips = this.selectableChips.filter((chip) => chip.key !== chipToRemove.key);
|
||||||
|
|
||||||
|
// Remove the chip from selectedChips if present
|
||||||
|
this.selectedChips = this.selectedChips.filter((chip) => chip.key !== chipToRemove.key);
|
||||||
|
|
||||||
|
// If the removed chip was the selectedChip, set selectedChip to null
|
||||||
|
if (this.selectedChip && this.selectedChip.key === chipToRemove.key) {
|
||||||
|
this.selectedChip = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger an update to re-render the component
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
}
|
57
ts_web/elements/dees-contextmenu.demo.ts
Normal file
57
ts_web/elements/dees-contextmenu.demo.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
|
||||||
|
import { DeesContextmenu } from './dees-contextmenu.js';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<style>
|
||||||
|
.withMargin {
|
||||||
|
display: block;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<dees-button @contextmenu=${(eventArg) => {
|
||||||
|
DeesContextmenu.openContextMenuWithOptions(eventArg, [
|
||||||
|
{
|
||||||
|
name: 'copy',
|
||||||
|
iconName: 'copySolid',
|
||||||
|
action: async () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'edit',
|
||||||
|
iconName: 'penToSquare',
|
||||||
|
action: async () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},{
|
||||||
|
name: 'paste',
|
||||||
|
iconName: 'pasteSolid',
|
||||||
|
action: async () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}}>Right-Click for contextmenu</dees-button>
|
||||||
|
<dees-contextmenu class="withMargin"></dees-contextmenu>
|
||||||
|
<dees-contextmenu
|
||||||
|
class="withMargin"
|
||||||
|
.menuItems=${[
|
||||||
|
{
|
||||||
|
name: 'copy',
|
||||||
|
iconName: 'copySolid',
|
||||||
|
action: async () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'edit',
|
||||||
|
iconName: 'penToSquare',
|
||||||
|
action: async () => {},
|
||||||
|
},{
|
||||||
|
name: 'paste',
|
||||||
|
iconName: 'pasteSolid',
|
||||||
|
action: async () => {},
|
||||||
|
},
|
||||||
|
] as plugins.tsclass.website.IMenuItem[]}
|
||||||
|
></dees-contextmenu>
|
||||||
|
`;
|
189
ts_web/elements/dees-contextmenu.ts
Normal file
189
ts_web/elements/dees-contextmenu.ts
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import * as colors from './00colors.js';
|
||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
import { demoFunc } from './dees-contextmenu.demo.js';
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
unsafeCSS,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { DeesWindowLayer } from './dees-windowlayer.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-contextmenu': DeesContextmenu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-contextmenu')
|
||||||
|
export class DeesContextmenu extends DeesElement {
|
||||||
|
// DEMO
|
||||||
|
public static demo = demoFunc
|
||||||
|
|
||||||
|
// STATIC
|
||||||
|
// This will store all the accumulated menu items
|
||||||
|
public static contextMenuDeactivated = false;
|
||||||
|
public static accumulatedMenuItems: plugins.tsclass.website.IMenuItem[] = [];
|
||||||
|
|
||||||
|
// Add a global event listener for the right-click context menu
|
||||||
|
public static initializeGlobalListener() {
|
||||||
|
document.addEventListener('contextmenu', (event: MouseEvent) => {
|
||||||
|
if (this.contextMenuDeactivated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// Get the target element of the right-click
|
||||||
|
let target: EventTarget | null = event.target;
|
||||||
|
|
||||||
|
// Clear previously accumulated items
|
||||||
|
DeesContextmenu.accumulatedMenuItems = [];
|
||||||
|
|
||||||
|
// Traverse up the DOM tree to accumulate menu items
|
||||||
|
while (target) {
|
||||||
|
if ((target as any).getContextMenuItems) {
|
||||||
|
DeesContextmenu.accumulatedMenuItems.push(...(target as any).getContextMenuItems());
|
||||||
|
}
|
||||||
|
target = (target as Node).parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the context menu with the accumulated items
|
||||||
|
DeesContextmenu.openContextMenuWithOptions(event, DeesContextmenu.accumulatedMenuItems);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// allows opening of a contextmenu with options
|
||||||
|
public static async openContextMenuWithOptions(eventArg: MouseEvent, menuItemsArg: plugins.tsclass.website.IMenuItem[]) {
|
||||||
|
if (this.contextMenuDeactivated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eventArg.preventDefault();
|
||||||
|
eventArg.stopPropagation();
|
||||||
|
const contextMenu = new DeesContextmenu();
|
||||||
|
contextMenu.style.position = 'fixed';
|
||||||
|
contextMenu.style.zIndex = '2000';
|
||||||
|
contextMenu.style.top = `${eventArg.clientY.toString()}px`;
|
||||||
|
contextMenu.style.left = `${eventArg.clientX.toString()}px`;
|
||||||
|
contextMenu.style.opacity = '0';
|
||||||
|
contextMenu.style.transform = 'scale(0.95,0.95)';
|
||||||
|
contextMenu.style.transformOrigin = 'top left';
|
||||||
|
contextMenu.menuItems = menuItemsArg;
|
||||||
|
contextMenu.windowLayer = await DeesWindowLayer.createAndShow();
|
||||||
|
contextMenu.windowLayer.addEventListener('click', async () => {
|
||||||
|
await contextMenu.destroy();
|
||||||
|
})
|
||||||
|
document.body.append(contextMenu);
|
||||||
|
await domtools.plugins.smartdelay.delayFor(0);
|
||||||
|
contextMenu.style.opacity = '1';
|
||||||
|
contextMenu.style.transform = 'scale(1,1)';
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
public menuItems: plugins.tsclass.website.IMenuItem[] = [];
|
||||||
|
windowLayer: DeesWindowLayer;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STATIC STYLES
|
||||||
|
*/
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
transition: all 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainbox {
|
||||||
|
color: ${cssManager.bdTheme('#222', '#ccc')};
|
||||||
|
font-size: 14px;
|
||||||
|
width: 200px;
|
||||||
|
border: 1px solid ${cssManager.bdTheme('#fff', '#ffffff10')};
|
||||||
|
min-height: 34px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: ${cssManager.bdTheme('#fff', '#222')};
|
||||||
|
box-shadow: 0px 1px 4px ${cssManager.bdTheme('#00000020', '#000000')};
|
||||||
|
user-select: none;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainbox .menuitem {
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainbox .menuitem dees-icon {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 8px;
|
||||||
|
width: 14px;
|
||||||
|
transform: translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainbox .menuitem:hover {
|
||||||
|
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainbox .menuitem:active {
|
||||||
|
background: #ffffff05;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="mainbox">
|
||||||
|
${this.menuItems.map((menuItemArg) => {
|
||||||
|
return html`
|
||||||
|
<div class="menuitem" @click=${() => this.handleClick(menuItemArg)}>
|
||||||
|
<dees-icon .iconFA=${(menuItemArg.iconName as any) || 'minus'}></dees-icon
|
||||||
|
>${menuItemArg.name}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
${this.menuItems.length === 0 ? html`
|
||||||
|
<div class="menuitem" @click=${() => {
|
||||||
|
DeesContextmenu.contextMenuDeactivated = true;
|
||||||
|
this.destroy();
|
||||||
|
}}>
|
||||||
|
<dees-icon .iconFA=${'xmark'}></dees-icon
|
||||||
|
>allow native context
|
||||||
|
</div>
|
||||||
|
` : html``}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleClick(menuItem: plugins.tsclass.website.IMenuItem) {
|
||||||
|
menuItem.action();
|
||||||
|
await this.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async destroy() {
|
||||||
|
if (this.windowLayer) {
|
||||||
|
this.windowLayer.destroy();
|
||||||
|
}
|
||||||
|
this.style.opacity = '0';
|
||||||
|
this.style.transform = 'scale(0.95,0,95)';
|
||||||
|
await domtools.plugins.smartdelay.delayFor(100);
|
||||||
|
this.parentElement.removeChild(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeesContextmenu.initializeGlobalListener();
|
18
ts_web/elements/dees-dataview-codebox.demo.ts
Normal file
18
ts_web/elements/dees-dataview-codebox.demo.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html` <style>
|
||||||
|
.demoWrapper {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="demoWrapper">
|
||||||
|
<dees-dataview-codebox proglang="typescript">
|
||||||
|
import * as text from './hello'; const hiThere = 'nice'; const myFunction = async () => {
|
||||||
|
console.log('nice one'); }
|
||||||
|
</dees-dataview-codebox>
|
||||||
|
</div>`
|
237
ts_web/elements/dees-dataview-codebox.ts
Normal file
237
ts_web/elements/dees-dataview-codebox.ts
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
import { demoFunc } from './dees-dataview-codebox.demo.js';
|
||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
html,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
state,
|
||||||
|
cssManager,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import hlight from 'highlight.js';
|
||||||
|
|
||||||
|
import * as smartstring from '@push.rocks/smartstring';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { DeesContextmenu } from './dees-contextmenu.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-dataview-codebox': DeesDataviewCodebox;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-dataview-codebox')
|
||||||
|
export class DeesDataviewCodebox extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public progLang: string = 'typescript';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public codeToDisplay: string = '';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${domtools.elementBasic.styles}
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
.mainbox {
|
||||||
|
position: relative;
|
||||||
|
color: ${this.goBright ? '#333333' : '#ffffff'};
|
||||||
|
border-top: 1px solid ${this.goBright ? '#ffffff' : '#333333'};
|
||||||
|
box-shadow: 0px 0px 5px ${this.goBright ? 'rgba(0,0,0,0.1)' : 'rgba(0,0,0,0.5)'};
|
||||||
|
background: ${this.goBright ? '#ffffff' : '#191919'};
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appbar {
|
||||||
|
position: relative;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
background: ${cssManager.bdTheme('#ffffff', '#161616')};
|
||||||
|
border-bottom: 1px solid ${cssManager.bdTheme('#eeeeeb', '#222222')};
|
||||||
|
height: 24px;
|
||||||
|
display: flex;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 24px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appbar .fileName {
|
||||||
|
line-height: inherit;
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottomBar {
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
background: ${cssManager.bdTheme('#ffffff', '#161616')};
|
||||||
|
border-top: 1px solid ${cssManager.bdTheme('#eeeeeb', '#222222')};
|
||||||
|
height: 24px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 24px;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.languageLabel {
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 24px;
|
||||||
|
z-index: 10;
|
||||||
|
background: #6596ff20;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0px;
|
||||||
|
padding: 0px 16px 0px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword {
|
||||||
|
color: #ff65ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codegrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50px auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineNumbers {
|
||||||
|
color: ${this.goBright ? '#acacac' : '#666666'};
|
||||||
|
padding: 30px 16px 0px 0px;
|
||||||
|
text-align: right;
|
||||||
|
border-right: 1px solid ${this.goBright ? '#eaeaea' : '#222222'};
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineCounter:last-child {
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 30px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-weight: ${this.goBright ? '400' : '300'};
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
code,
|
||||||
|
code *,
|
||||||
|
.lineNumbers {
|
||||||
|
line-height: 1.4em;
|
||||||
|
font-weight: 200;
|
||||||
|
font-family: 'Intel One Mono', 'monospace';
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string {
|
||||||
|
color: #ffa465;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-built_in {
|
||||||
|
color: #65ff6a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-function {
|
||||||
|
color: ${this.goBright ? '#2765DF' : '#6596ff'};
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-params {
|
||||||
|
color: ${this.goBright ? '#3DB420' : '#65d5ff'};
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment {
|
||||||
|
color: ${this.goBright ? '#EF9300' : '#ffd765'};
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div
|
||||||
|
class="mainbox"
|
||||||
|
@contextmenu="${(eventArg) => {
|
||||||
|
DeesContextmenu.openContextMenuWithOptions(eventArg, [
|
||||||
|
{
|
||||||
|
name: 'About',
|
||||||
|
iconName: 'circleInfo',
|
||||||
|
action: async () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
<div class="appbar">
|
||||||
|
<dees-windowcontrols type="mac" position="left"></dees-windowcontrols>
|
||||||
|
<div class="fileName">index.ts</div>
|
||||||
|
<dees-windowcontrols type="mac" position="right"></dees-windowcontrols>
|
||||||
|
</div>
|
||||||
|
<div class="codegrid">
|
||||||
|
<div class="lineNumbers">
|
||||||
|
${(() => {
|
||||||
|
let lineCounter = 0;
|
||||||
|
return this.codeToDisplay.split('\n').map((lineArg) => {
|
||||||
|
lineCounter++;
|
||||||
|
return html`<div class="lineCounter">${lineCounter}</div>`;
|
||||||
|
});
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
<pre><code></code></pre>
|
||||||
|
</div>
|
||||||
|
<div class="bottomBar">
|
||||||
|
Spaces: 2
|
||||||
|
<div class="languageLabel">${this.progLang}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private codeToDisplayStore = '';
|
||||||
|
|
||||||
|
public async updated(_changedProperties) {
|
||||||
|
super.updated(_changedProperties);
|
||||||
|
console.log('highlighting now');
|
||||||
|
console.log(this.childNodes);
|
||||||
|
const slottedCodeNodes: Text[] = [];
|
||||||
|
this.childNodes.forEach((childNode) => {
|
||||||
|
if (childNode.nodeName === '#text') {
|
||||||
|
slottedCodeNodes.push(childNode as Text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (this.codeToDisplay && this.codeToDisplay !== this.codeToDisplayStore) {
|
||||||
|
this.codeToDisplayStore = smartstring.indent.normalize(this.codeToDisplay).trimStart();
|
||||||
|
}
|
||||||
|
if (slottedCodeNodes[0] && slottedCodeNodes[0].wholeText && !this.codeToDisplay) {
|
||||||
|
this.codeToDisplayStore = smartstring.indent
|
||||||
|
.normalize(slottedCodeNodes[0].wholeText)
|
||||||
|
.trimStart();
|
||||||
|
this.codeToDisplay = this.codeToDisplayStore;
|
||||||
|
}
|
||||||
|
await domtools.plugins.smartdelay.delayFor(0);
|
||||||
|
const localCodeNode = this.shadowRoot.querySelector('code');
|
||||||
|
const html = hlight.highlight(this.codeToDisplayStore, {
|
||||||
|
language: this.progLang,
|
||||||
|
ignoreIllegals: true,
|
||||||
|
});
|
||||||
|
localCodeNode.innerHTML = html.value;
|
||||||
|
}
|
||||||
|
}
|
49
ts_web/elements/dees-dataview-statusobject.demo.ts
Normal file
49
ts_web/elements/dees-dataview-statusobject.demo.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { html, cssManager } from '@design.estate/dees-element';
|
||||||
|
import * as tsclass from '@tsclass/tsclass';
|
||||||
|
|
||||||
|
export const demoFunc = () => html` <style>
|
||||||
|
.demo {
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#000000')};
|
||||||
|
display: block;
|
||||||
|
content: '';
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="demo">
|
||||||
|
<dees-dataview-statusobject
|
||||||
|
.statusObject=${{
|
||||||
|
id: '1',
|
||||||
|
name: 'Demo Item',
|
||||||
|
combinedStatus: 'partly_ok',
|
||||||
|
combinedStatusText: 'partly_ok',
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
name: 'Detail 1',
|
||||||
|
value: 'Value 1',
|
||||||
|
status: 'ok',
|
||||||
|
statusText: 'OK',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Detail 2',
|
||||||
|
value: 'Value 2',
|
||||||
|
status: 'partly_ok',
|
||||||
|
statusText: 'partly_ok',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Detail 3',
|
||||||
|
value: 'Value 3',
|
||||||
|
status: 'not_ok',
|
||||||
|
statusText: 'not_ok',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Detail 4',
|
||||||
|
value:
|
||||||
|
'Value 4 jhdkfjhalskdfjhfdjskalsdkfjhfdjskalskdjfhjdkslaksjdhfjdkslaskdfjhfjdkslaskdjfhjdskalskdjhfdjskalskdjfhdjskl',
|
||||||
|
status: 'ok',
|
||||||
|
statusText: 'OK',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as tsclass.code.IStatusObject}
|
||||||
|
>
|
||||||
|
</dees-dataview-statusobject>
|
||||||
|
</div>`;
|
165
ts_web/elements/dees-dataview-statusobject.ts
Normal file
165
ts_web/elements/dees-dataview-statusobject.ts
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
import * as colors from './00colors.js';
|
||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
|
||||||
|
import { demoFunc } from './dees-dataview-statusobject.demo.js';
|
||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
html,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
state,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as tsclass from '@tsclass/tsclass';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-dataview-statusobject': DeesDataviewStatusobject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-dataview-statusobject')
|
||||||
|
export class DeesDataviewStatusobject extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
@property({ type: Object }) statusObject: tsclass.code.IStatusObject;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
.mainbox {
|
||||||
|
border-radius: 8px;
|
||||||
|
background: ${cssManager.bdTheme('#fff', '#1b1b1b')};
|
||||||
|
box-shadow: 0px 1px 3px #00000030;
|
||||||
|
min-height: 48px;
|
||||||
|
color: ${cssManager.bdTheme('#000', '#fff')};
|
||||||
|
border-top: ${cssManager.bdTheme('none', '1px solid #ffffff10')};
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: 40px auto 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
display: block;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
height: 48px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusdot {
|
||||||
|
height: 8px;
|
||||||
|
width: 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: grey;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyMain {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
border: 1px solid ${cssManager.bdTheme('#e0e0e0', '#444')};
|
||||||
|
text-align: center;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin-right: 16px;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ffffff80')};
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyMain:hover {
|
||||||
|
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
||||||
|
border: 1px solid ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyMain:active {
|
||||||
|
background: ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)};
|
||||||
|
border: 1px solid ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)};
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusdot.ok {
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusdot.not_ok{
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusdot.partly_ok {
|
||||||
|
background: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail {
|
||||||
|
min-height: 60px;
|
||||||
|
align-items: center;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 40px auto;
|
||||||
|
border-top: 1px dotted ${cssManager.bdTheme('#e0e0e0', '#282828')};
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail:hover {
|
||||||
|
background: #ffffff05;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail:active {
|
||||||
|
background: #ffffff10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail .detailsText {
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail .detailsText .label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #ffffff80
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail .detailsText .value {
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: 'Intel One Mono';
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="mainbox">
|
||||||
|
<div class="heading">
|
||||||
|
<div class="statusdot ${this.statusObject?.combinedStatus}"></div>
|
||||||
|
<h1>${this.statusObject?.name || 'no status object assigned'}</h1>
|
||||||
|
<div class="copyMain">Copy as JSON</div>
|
||||||
|
</div>
|
||||||
|
${this.statusObject?.details?.map((detailArg) => {
|
||||||
|
return html`
|
||||||
|
<div class="detail">
|
||||||
|
<div class="statusdot ${detailArg.status}"></div>
|
||||||
|
<div class="detailsText">
|
||||||
|
<div class="label">${detailArg.name}</div>
|
||||||
|
<div class="value">${detailArg.value}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {}
|
||||||
|
}
|
98
ts_web/elements/dees-editor-markdown.ts
Normal file
98
ts_web/elements/dees-editor-markdown.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
html,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
domtools
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
const deferred = domtools.plugins.smartpromise.defer();
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-editormarkdown': DeesEditorMarkdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-editormarkdown')
|
||||||
|
export class DeesEditorMarkdown extends DeesElement {
|
||||||
|
public static demo = () => html`<dees-editormarkdown></dees-editormarkdown>`;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
.gridcontainer {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 60% 40%;
|
||||||
|
}
|
||||||
|
.editorContainer {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.outletContainer {
|
||||||
|
background: #111;
|
||||||
|
color: #fff;
|
||||||
|
font-family: 'Roboto Slab';
|
||||||
|
padding: 20px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="gridcontainer">
|
||||||
|
<div class="editorContainer">
|
||||||
|
<dees-editor
|
||||||
|
.language=${'markdown'}
|
||||||
|
.content=${`# a test content
|
||||||
|
|
||||||
|
This is test content that is of longer form an hopefully starts to wrap when I need it. And yes, it does perfectly. nice.
|
||||||
|
|
||||||
|
Test | Hello
|
||||||
|
--- | ---
|
||||||
|
Yeah | So good
|
||||||
|
|
||||||
|
This is real asset I think. Why would we want to leave that on the table? Can you tell my that?
|
||||||
|
|
||||||
|
Why are we here?
|
||||||
|
|
||||||
|
Do you know?
|
||||||
|
|
||||||
|
> note:
|
||||||
|
There is something going on.
|
||||||
|
|
||||||
|
\`\`\`typescript
|
||||||
|
const hello = 'yes'
|
||||||
|
\`\`\`
|
||||||
|
`}
|
||||||
|
wordWrap="bounded"
|
||||||
|
></dees-editor>
|
||||||
|
</div>
|
||||||
|
<div class="outletContainer">
|
||||||
|
<dees-editormarkdownoutlet></dees-editormarkdownoutlet>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated(_changedPropertiesArg) {
|
||||||
|
await super.firstUpdated(_changedPropertiesArg);
|
||||||
|
const editor = this.shadowRoot.querySelector('dees-editor');
|
||||||
|
|
||||||
|
// lets care about wiring the markdown stuff.
|
||||||
|
const markdownOutlet = this.shadowRoot.querySelector('dees-editormarkdownoutlet');
|
||||||
|
const smartmarkdownInstance = new domtools.plugins.smartmarkdown.SmartMarkdown();
|
||||||
|
const mdParsedResult = await smartmarkdownInstance.getMdParsedResultFromMarkdown('loading...')
|
||||||
|
editor.contentSubject.subscribe(async contentArg => {
|
||||||
|
await mdParsedResult.updateFromMarkdownString(contentArg)
|
||||||
|
const html = mdParsedResult.html;
|
||||||
|
markdownOutlet.updateHtmlText(html);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
42
ts_web/elements/dees-editor-markdownoutlet.ts
Normal file
42
ts_web/elements/dees-editor-markdownoutlet.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { customElement, DeesElement, html, type TemplateResult } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-editormarkdownoutlet': DeesEditorMarkdownOutlet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-editormarkdownoutlet')
|
||||||
|
export class DeesEditorMarkdownOutlet extends DeesElement {
|
||||||
|
// DEMO
|
||||||
|
public static demo = () => html`<dees-editormarkdownoutlet></dees-editormarkdownoutlet>`;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
private outlet: HTMLElement;
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="outlet markdown-body">
|
||||||
|
<h1>Hi there</h1>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated(_changedProperties: Map<string | number | symbol, unknown>) {
|
||||||
|
await super.firstUpdated(_changedProperties);
|
||||||
|
const styleElement = document.createElement('style');
|
||||||
|
const cssText = await (
|
||||||
|
await fetch('https://unpkg.com/github-markdown-css@5.1.0/github-markdown-dark.css')
|
||||||
|
).text();
|
||||||
|
styleElement.textContent = cssText;
|
||||||
|
this.shadowRoot.append(styleElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateHtmlText(htmlTextArg: string) {
|
||||||
|
await this.updateComplete;
|
||||||
|
if (!this.outlet) {
|
||||||
|
this.outlet = this.shadowRoot.querySelector('.outlet');
|
||||||
|
}
|
||||||
|
this.outlet.innerHTML = htmlTextArg;
|
||||||
|
}
|
||||||
|
}
|
126
ts_web/elements/dees-editor.ts
Normal file
126
ts_web/elements/dees-editor.ts
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
html,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
import type * as monaco from 'monaco-editor';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-editor': DeesEditor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-editor')
|
||||||
|
export class DeesEditor extends DeesElement {
|
||||||
|
// DEMO
|
||||||
|
public static demo = () => html` <dees-editor></dees-editor> `;
|
||||||
|
|
||||||
|
// STATIC
|
||||||
|
public static monacoDeferred: ReturnType<typeof domtools.plugins.smartpromise.defer>;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public editorDeferred = domtools.plugins.smartpromise.defer<monaco.editor.IStandaloneCodeEditor>();
|
||||||
|
public language = 'typescript';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String
|
||||||
|
})
|
||||||
|
public content = "function hello() {\n\talert('Hello world!');\n}";
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Object
|
||||||
|
})
|
||||||
|
public contentSubject = new domtools.plugins.smartrx.rxjs.Subject<string>();
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean
|
||||||
|
})
|
||||||
|
public wordWrap: monaco.editor.IStandaloneEditorConstructionOptions['wordWrap'] = 'off';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
domtools.DomTools.setupDomTools();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
domtools.elementBasic.staticStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="mainbox">
|
||||||
|
<div id="container"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated(
|
||||||
|
_changedProperties: Map<string | number | symbol, unknown>
|
||||||
|
): Promise<void> {
|
||||||
|
super.firstUpdated(_changedProperties);
|
||||||
|
const container = this.shadowRoot.getElementById('container');
|
||||||
|
|
||||||
|
if (!DeesEditor.monacoDeferred) {
|
||||||
|
DeesEditor.monacoDeferred = domtools.plugins.smartpromise.defer();
|
||||||
|
const scriptUrl = `https://cdn.jsdelivr.net/npm/monaco-editor/min/vs/loader.js`;
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = scriptUrl;
|
||||||
|
script.onload = () => {
|
||||||
|
DeesEditor.monacoDeferred.resolve();
|
||||||
|
};
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
await DeesEditor.monacoDeferred.promise;
|
||||||
|
|
||||||
|
(window as any).require.config({
|
||||||
|
paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor/min/vs' },
|
||||||
|
});
|
||||||
|
(window as any).require(['vs/editor/editor.main'], async () => {
|
||||||
|
const editor = ((window as any).monaco.editor as typeof monaco.editor).create(container, {
|
||||||
|
value: this.content,
|
||||||
|
language: this.language,
|
||||||
|
theme: 'vs-dark',
|
||||||
|
useShadowDOM: true,
|
||||||
|
fontSize: 16,
|
||||||
|
automaticLayout: true,
|
||||||
|
wordWrap: this.wordWrap
|
||||||
|
});
|
||||||
|
this.editorDeferred.resolve(editor);
|
||||||
|
});
|
||||||
|
const css = await (
|
||||||
|
await fetch('https://cdn.jsdelivr.net/npm/monaco-editor/min/vs/editor/editor.main.css')
|
||||||
|
).text();
|
||||||
|
const styleElement = document.createElement('style');
|
||||||
|
styleElement.textContent = css;
|
||||||
|
this.shadowRoot.append(styleElement);
|
||||||
|
|
||||||
|
|
||||||
|
// editor is setup let do the rest
|
||||||
|
const editor = await this.editorDeferred.promise;
|
||||||
|
editor.onDidChangeModelContent(async eventArg => {
|
||||||
|
this.contentSubject.next(editor.getValue());
|
||||||
|
});
|
||||||
|
this.contentSubject.next(editor.getValue());
|
||||||
|
}
|
||||||
|
}
|
71
ts_web/elements/dees-form-submit.ts
Normal file
71
ts_web/elements/dees-form-submit.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
property,
|
||||||
|
type CSSResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import { DeesForm } from './dees-form.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-form-submit': DeesFormSubmit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-form-submit')
|
||||||
|
export class DeesFormSubmit extends DeesElement {
|
||||||
|
public static demo = () => html`<dees-form-submit>This is a sloted text</dees-form-submit>`;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public disabled = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public text: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public status: 'normal' | 'pending' | 'success' | 'error' = 'normal';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [cssManager.defaultStyles, css``];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<dees-button
|
||||||
|
status=${this.status}
|
||||||
|
@click=${this.submit}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
.text=${this.text ? this.text : this.textContent}
|
||||||
|
>
|
||||||
|
</dees-button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async submit() {
|
||||||
|
if (this.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const parentElement: DeesForm = this.parentElement as DeesForm;
|
||||||
|
parentElement.gatherAndDispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async focus() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
if (!this.disabled) {
|
||||||
|
domtools.convenience.smartdelay.delayFor(0);
|
||||||
|
this.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
69
ts_web/elements/dees-form.demo.ts
Normal file
69
ts_web/elements/dees-form.demo.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { html, domtools, cssManager } from '@design.estate/dees-element';
|
||||||
|
import type { DeesForm } from './dees-form.js';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<style>
|
||||||
|
.demoContainer {
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 24px auto;
|
||||||
|
padding: 16px;
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#111')};
|
||||||
|
box-shadow: 0px 1px 3px #00000030;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="demoContainer">
|
||||||
|
<dees-form
|
||||||
|
style="display: block; margin:auto; max-width: 500px; padding: 20px"
|
||||||
|
@formData=${async (eventArg) => {
|
||||||
|
const form: DeesForm = eventArg.currentTarget;
|
||||||
|
form.setStatus('pending', 'authenticating...');
|
||||||
|
await domtools.plugins.smartdelay.delayFor(1000);
|
||||||
|
form.setStatus('success', 'authenticated!');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<dees-input-dropdown
|
||||||
|
.label=${'title'}
|
||||||
|
.options=${[
|
||||||
|
{ option: 'option 1', key: 'option1' },
|
||||||
|
{ option: 'option 2', key: 'option2' },
|
||||||
|
{ option: 'option 3', key: 'option3' },
|
||||||
|
]}
|
||||||
|
></dees-input-dropdown>
|
||||||
|
<dees-input-multiselect
|
||||||
|
.label=${'title'}
|
||||||
|
.options=${[
|
||||||
|
{ option: 'option 1', key: 'option1' },
|
||||||
|
{ option: 'option 2', key: 'option2' },
|
||||||
|
{ option: 'option 3', key: 'option3' },
|
||||||
|
]}></dees-input-multiselect>
|
||||||
|
<dees-input-typelist
|
||||||
|
.label=${'a type list'}
|
||||||
|
></dees-input-typelist>
|
||||||
|
<dees-input-text .required="${true}" key="hello1" label="a text" .description=${`
|
||||||
|
This is an awesome description.
|
||||||
|
`}></dees-input-text>
|
||||||
|
<dees-input-text .required="${true}" key="hello2" label="also a text"></dees-input-text>
|
||||||
|
<dees-input-text
|
||||||
|
.required="${true}"
|
||||||
|
key="hello3"
|
||||||
|
label="a password"
|
||||||
|
isPasswordBool
|
||||||
|
></dees-input-text>
|
||||||
|
<dees-input-checkbox
|
||||||
|
.required="${true}"
|
||||||
|
key="hello3"
|
||||||
|
label="another text"
|
||||||
|
></dees-input-checkbox>
|
||||||
|
<dees-input-iban></dees-input-iban>
|
||||||
|
<dees-input-multitoggle
|
||||||
|
.label=${'multi select'}
|
||||||
|
.options=${['option 1', 'option 2', 'option 3']}
|
||||||
|
.selectedOption=${'option 1'}
|
||||||
|
></dees-input-multitoggle>
|
||||||
|
<dees-input-fileupload
|
||||||
|
.label=${'attachments'}
|
||||||
|
></dees-input-fileupload>
|
||||||
|
<dees-form-submit>Submit</dees-form-submit>
|
||||||
|
</dees-form>
|
||||||
|
</div>
|
||||||
|
`;
|
201
ts_web/elements/dees-form.ts
Normal file
201
ts_web/elements/dees-form.ts
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
type TemplateResult,
|
||||||
|
DeesElement,
|
||||||
|
type CSSResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
import { DeesInputCheckbox } from './dees-input-checkbox.js';
|
||||||
|
import { DeesInputText } from './dees-input-text.js';
|
||||||
|
import { DeesInputQuantitySelector } from './dees-input-quantityselector.js';
|
||||||
|
import { DeesInputRadio } from './dees-input-radio.js';
|
||||||
|
import { DeesFormSubmit } from './dees-form-submit.js';
|
||||||
|
import { DeesTable } from './dees-table.js';
|
||||||
|
import { demoFunc } from './dees-form.demo.js';
|
||||||
|
import { DeesInputIban } from './dees-input-iban.js';
|
||||||
|
|
||||||
|
// Unified set for form input types
|
||||||
|
const FORM_INPUT_TYPES = [
|
||||||
|
DeesInputCheckbox,
|
||||||
|
DeesInputIban,
|
||||||
|
DeesInputText,
|
||||||
|
DeesInputQuantitySelector,
|
||||||
|
DeesInputRadio,
|
||||||
|
DeesTable,
|
||||||
|
];
|
||||||
|
|
||||||
|
export type TFormInputElement =
|
||||||
|
| DeesInputCheckbox
|
||||||
|
| DeesInputIban
|
||||||
|
| DeesInputText
|
||||||
|
| DeesInputQuantitySelector
|
||||||
|
| DeesInputRadio
|
||||||
|
| DeesTable<any>;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-form': DeesForm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-form')
|
||||||
|
export class DeesForm extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
public name: string = 'myform';
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
||||||
|
public readyDeferred = domtools.plugins.smartpromise.defer();
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<slot></slot>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
const formChildren = this.getFormElements();
|
||||||
|
this.updateRequiredStatus();
|
||||||
|
|
||||||
|
for (const child of formChildren) {
|
||||||
|
child.changeSubject.subscribe(async () => {
|
||||||
|
const valueObject = await this.collectFormData();
|
||||||
|
this.changeSubject.next(valueObject);
|
||||||
|
console.log(valueObject);
|
||||||
|
this.updateRequiredStatus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await this.addBehaviours();
|
||||||
|
this.readyDeferred.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFormElements(): Array<TFormInputElement> {
|
||||||
|
return Array.from(this.children).filter((child) =>
|
||||||
|
FORM_INPUT_TYPES.includes(child.constructor as any)
|
||||||
|
) as unknown as TFormInputElement[];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSubmitButton(): DeesFormSubmit | undefined {
|
||||||
|
return Array.from(this.children).find(
|
||||||
|
(child) => child instanceof DeesFormSubmit
|
||||||
|
) as DeesFormSubmit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateRequiredStatus() {
|
||||||
|
console.log('checking the required status.');
|
||||||
|
|
||||||
|
let requiredOK = true;
|
||||||
|
for (const childArg of this.getFormElements()) {
|
||||||
|
if (childArg.required && !childArg.value) {
|
||||||
|
requiredOK = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.getSubmitButton()) {
|
||||||
|
this.getSubmitButton().disabled = !requiredOK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async collectFormData() {
|
||||||
|
const children = this.getFormElements();
|
||||||
|
const valueObject: { [key: string]: string | number | boolean | any[] } = {};
|
||||||
|
for (const child of children) {
|
||||||
|
if (!child.key) {
|
||||||
|
console.log(`form element with label "${child.label}" has no key. skipping.`);
|
||||||
|
}
|
||||||
|
valueObject[child.key] = child.value;
|
||||||
|
}
|
||||||
|
return valueObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async gatherAndDispatch() {
|
||||||
|
const valueObject = await this.collectFormData();
|
||||||
|
const formDataEvent = new CustomEvent('formData', {
|
||||||
|
detail: {
|
||||||
|
data: valueObject,
|
||||||
|
},
|
||||||
|
bubbles: true,
|
||||||
|
});
|
||||||
|
this.dispatchEvent(formDataEvent);
|
||||||
|
console.log('dispatched data:');
|
||||||
|
console.log(valueObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setStatus(
|
||||||
|
visualStateArg: 'normal' | 'pending' | 'error' | 'success',
|
||||||
|
textStateArg: string
|
||||||
|
) {
|
||||||
|
const inputChildren = this.getFormElements();
|
||||||
|
const submitButton = this.getSubmitButton();
|
||||||
|
|
||||||
|
switch (visualStateArg) {
|
||||||
|
case 'normal':
|
||||||
|
submitButton.disabled = false;
|
||||||
|
submitButton.status = 'normal';
|
||||||
|
for (const inputChild of inputChildren) {
|
||||||
|
inputChild.disabled = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'pending':
|
||||||
|
submitButton.disabled = true;
|
||||||
|
submitButton.status = 'pending';
|
||||||
|
for (const inputChild of inputChildren) {
|
||||||
|
inputChild.disabled = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'success':
|
||||||
|
submitButton.disabled = true;
|
||||||
|
submitButton.status = 'success';
|
||||||
|
for (const inputChild of inputChildren) {
|
||||||
|
inputChild.disabled = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
submitButton.disabled = true;
|
||||||
|
submitButton.status = 'error';
|
||||||
|
for (const inputChild of inputChildren) {
|
||||||
|
inputChild.disabled = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
submitButton.text = textStateArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resets the form
|
||||||
|
*/
|
||||||
|
reset() {
|
||||||
|
const inputChildren = this.getFormElements();
|
||||||
|
const submitButton = this.getSubmitButton();
|
||||||
|
|
||||||
|
for (const inputChild of inputChildren) {
|
||||||
|
inputChild.value = null;
|
||||||
|
}
|
||||||
|
this.setStatus('normal', 'Submit');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async addBehaviours() {
|
||||||
|
// Use event delegation
|
||||||
|
this.addEventListener('keydown', (event: KeyboardEvent) => {
|
||||||
|
const target = event.target as DeesElement;
|
||||||
|
if (!FORM_INPUT_TYPES.includes(target.constructor as any)) return;
|
||||||
|
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
const children = this.getFormElements();
|
||||||
|
const currentIndex = children.indexOf(target as any);
|
||||||
|
if (currentIndex < children.length - 1) {
|
||||||
|
children[currentIndex + 1].focus();
|
||||||
|
} else {
|
||||||
|
target.blur();
|
||||||
|
this.getSubmitButton()?.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
5
ts_web/elements/dees-hint.demo.ts
Normal file
5
ts_web/elements/dees-hint.demo.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<dees-hint></dees-hint>
|
||||||
|
`;
|
38
ts_web/elements/dees-hint.ts
Normal file
38
ts_web/elements/dees-hint.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
type CSSResult,
|
||||||
|
type TemplateResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { demoFunc } from './dees-hint.demo.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-hint': DeesHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-hint')
|
||||||
|
export class DeesHint extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
@property({ type: String })
|
||||||
|
public type: 'info' | 'warn' | 'error' | 'critical' = 'info';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
domtools.elementBasic.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [cssManager.defaultStyles, css``];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html` <div class="mainbox"></div> `;
|
||||||
|
}
|
||||||
|
}
|
55
ts_web/elements/dees-icon.demo.ts
Normal file
55
ts_web/elements/dees-icon.demo.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import { faIcons } from './dees-icon.js';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<style>
|
||||||
|
.demoContainer {
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
background: #111111;
|
||||||
|
padding: 10px; font-size: 30px;
|
||||||
|
}
|
||||||
|
dees-icon {
|
||||||
|
transition: color 0.02s;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
dees-icon:hover {
|
||||||
|
color: #e4002b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconContainer {
|
||||||
|
display: block;
|
||||||
|
padding: 16px 16px 0px 16px;
|
||||||
|
border: 1px solid #333333;
|
||||||
|
margin-right: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconName {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
color: #ccc;
|
||||||
|
background: #333333;
|
||||||
|
padding: 4px 8px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
margin-left: -16px;
|
||||||
|
margin-right: -16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="demoContainer">
|
||||||
|
${Object.keys(faIcons).map(
|
||||||
|
(iconName) => html`
|
||||||
|
<div class="iconContainer">
|
||||||
|
<dees-icon .iconFA=${iconName as any}></dees-icon>
|
||||||
|
<div class="iconName">${iconName}</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
`;
|
203
ts_web/elements/dees-icon.ts
Normal file
203
ts_web/elements/dees-icon.ts
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
customElement,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
import { icon, type IconDefinition } from '@fortawesome/fontawesome-svg-core';
|
||||||
|
import {
|
||||||
|
faFacebook,
|
||||||
|
faGoogle,
|
||||||
|
faLinkedin,
|
||||||
|
faMedium,
|
||||||
|
faSlackHash,
|
||||||
|
faTwitter,
|
||||||
|
faInstagram,
|
||||||
|
faTiktok,
|
||||||
|
} from '@fortawesome/free-brands-svg-icons';
|
||||||
|
|
||||||
|
import {
|
||||||
|
faCopy as faCopyRegular,
|
||||||
|
faCircleCheck as faCircleCheckRegular,
|
||||||
|
faCircleXmark as faCircleXmarkRegular,
|
||||||
|
faMessage as faMessageRegular,
|
||||||
|
faPaste as faPasteRegular,
|
||||||
|
faSun as faSunRegular,
|
||||||
|
faTrashCan as faTrashCanRegular,
|
||||||
|
} from '@fortawesome/free-regular-svg-icons';
|
||||||
|
import {
|
||||||
|
faArrowRight as faArrowRightSolid,
|
||||||
|
faArrowUpRightFromSquare as faArrowUpRightFromSquareSolid,
|
||||||
|
faBell as faBellSolid,
|
||||||
|
faBug as faBugSolid,
|
||||||
|
faBuilding as faBuildingSolid,
|
||||||
|
faCaretLeft as faCaretLeftSolid,
|
||||||
|
faCaretRight as faCaretRightSolid,
|
||||||
|
faCheck as faCheckSolid,
|
||||||
|
faCircleInfo as faCircleInfoSolid,
|
||||||
|
faCircleCheck as faCircleCheckSolid,
|
||||||
|
faCircleXmark as faCircleXmarkSolid,
|
||||||
|
faClockRotateLeft as faClockRotateLeftSolid,
|
||||||
|
faCopy as faCopySolid,
|
||||||
|
faDesktop as faDesktopSolid,
|
||||||
|
faEye as faEyeSolid,
|
||||||
|
faEyeSlash as faEyeSlashSolid,
|
||||||
|
faFileInvoice as faFileInvoiceSolid,
|
||||||
|
faFileInvoiceDollar as faFileInvoiceDollarSolid,
|
||||||
|
faGear as faGearSolid,
|
||||||
|
faGrip as faGripSolid,
|
||||||
|
faMagnifyingGlass as faMagnifyingGlassSolid,
|
||||||
|
faMessage as faMessageSolid,
|
||||||
|
faMoneyCheckDollar as faMoneyCheckDollarSolid,
|
||||||
|
faMugHot as faMugHotSolid,
|
||||||
|
faMinus as faMinusSolid,
|
||||||
|
faNetworkWired as faNetworkWiredSolid,
|
||||||
|
faPaperclip as faPaperclipSolid,
|
||||||
|
faPaste as faPasteSolid,
|
||||||
|
faPenToSquare as faPenToSquareSolid,
|
||||||
|
faPlus as faPlusSolid,
|
||||||
|
faReceipt as faReceiptSolid,
|
||||||
|
faRss as faRssSolid,
|
||||||
|
faUsers as faUsersSolid,
|
||||||
|
faShare as faShareSolid,
|
||||||
|
faSun as faSunSolid,
|
||||||
|
faTerminal as faTerminalSolid,
|
||||||
|
faTrash as faTrashSolid,
|
||||||
|
faTrashCan as faTrashCanSolid,
|
||||||
|
faWallet as faWalletSolid,
|
||||||
|
faXmark as faXmarkSolid,
|
||||||
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { demoFunc } from './dees-icon.demo.js';
|
||||||
|
|
||||||
|
export const faIcons = {
|
||||||
|
// normal
|
||||||
|
arrowRight: faArrowRightSolid,
|
||||||
|
arrowUpRightFromSquare: faArrowUpRightFromSquareSolid,
|
||||||
|
bell: faBellSolid,
|
||||||
|
bug: faBugSolid,
|
||||||
|
building: faBuildingSolid,
|
||||||
|
caretLeft: faCaretLeftSolid,
|
||||||
|
caretRight: faCaretRightSolid,
|
||||||
|
check: faCheckSolid,
|
||||||
|
circleInfo: faCircleInfoSolid,
|
||||||
|
circleCheck: faCircleCheckRegular,
|
||||||
|
circleCheckSolid: faCircleCheckSolid,
|
||||||
|
circleXmark: faCircleXmarkRegular,
|
||||||
|
circleXmarkSolid: faCircleXmarkSolid,
|
||||||
|
clockRotateLeft: faClockRotateLeftSolid,
|
||||||
|
copy: faCopyRegular,
|
||||||
|
copySolid: faCopySolid,
|
||||||
|
desktop: faDesktopSolid,
|
||||||
|
eye: faEyeSolid,
|
||||||
|
eyeSlash: faEyeSlashSolid,
|
||||||
|
fileInvoice: faFileInvoiceSolid,
|
||||||
|
fileInvoiceDoller: faFileInvoiceDollarSolid,
|
||||||
|
gear: faGearSolid,
|
||||||
|
grip: faGripSolid,
|
||||||
|
magnifyingGlass: faMagnifyingGlassSolid,
|
||||||
|
message: faMessageRegular,
|
||||||
|
messageSolid: faMessageSolid,
|
||||||
|
moneyCheckDollar: faMoneyCheckDollarSolid,
|
||||||
|
mugHot: faMugHotSolid,
|
||||||
|
minus: faMinusSolid,
|
||||||
|
networkWired: faNetworkWiredSolid,
|
||||||
|
paperclip: faPaperclipSolid,
|
||||||
|
paste: faPasteRegular,
|
||||||
|
pasteSolid: faPasteSolid,
|
||||||
|
penToSquare: faPenToSquareSolid,
|
||||||
|
plus: faPlusSolid,
|
||||||
|
receipt: faReceiptSolid,
|
||||||
|
rss: faRssSolid,
|
||||||
|
share: faShareSolid,
|
||||||
|
sun: faSunRegular,
|
||||||
|
sunSolid: faSunSolid,
|
||||||
|
terminal: faTerminalSolid,
|
||||||
|
trash: faTrashSolid,
|
||||||
|
trashSolid: faTrashSolid,
|
||||||
|
trashCan: faTrashCanRegular,
|
||||||
|
trashCanSolid: faTrashCanSolid,
|
||||||
|
users: faUsersSolid,
|
||||||
|
wallet: faWalletSolid,
|
||||||
|
xmark: faXmarkSolid,
|
||||||
|
// brands
|
||||||
|
facebook: faFacebook,
|
||||||
|
google: faGoogle,
|
||||||
|
instagram: faInstagram,
|
||||||
|
linkedin: faLinkedin,
|
||||||
|
medium: faMedium,
|
||||||
|
slack: faSlackHash,
|
||||||
|
tiktok: faTiktok,
|
||||||
|
twitter: faTwitter,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TIconKey = keyof typeof faIcons;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-icon': DeesIcon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-icon')
|
||||||
|
export class DeesIcon extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String
|
||||||
|
})
|
||||||
|
public iconFA: keyof typeof faIcons;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public iconSize: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
domtools.elementBasic.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
transition: inherit !important;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
${domtools.elementBasic.styles}
|
||||||
|
<style>
|
||||||
|
#iconContainer svg {
|
||||||
|
display: block;
|
||||||
|
height: ${this.iconSize}px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="iconContainer"></div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updated() {
|
||||||
|
if (!this.iconSize) {
|
||||||
|
this.iconSize = parseInt(globalThis.getComputedStyle(this).fontSize.replace(/\D/g,''));
|
||||||
|
}
|
||||||
|
if (this.iconFA) {
|
||||||
|
this.shadowRoot.querySelector('#iconContainer').innerHTML = this.iconFA
|
||||||
|
? icon(faIcons[this.iconFA]).html[0]
|
||||||
|
: 'icon not found';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
186
ts_web/elements/dees-input-checkbox.ts
Normal file
186
ts_web/elements/dees-input-checkbox.ts
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
type CSSResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-input-checkbox': DeesInputCheckbox;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-input-checkbox')
|
||||||
|
export class DeesInputCheckbox extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = () => html`<dees-input-checkbox></dees-input-checkbox>`;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public key: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public label: string = 'Label';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public value: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public required: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean
|
||||||
|
})
|
||||||
|
public disabled: boolean = false;
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${domtools.elementBasic.styles}
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
margin: 20px 0px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
:host(:hover) {
|
||||||
|
filter: ${cssManager.bdTheme('brightness(0.95)', 'brightness(1.1)')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 25px auto;
|
||||||
|
padding: 5px 0px;
|
||||||
|
color: ${this.goBright ? '#333' : '#ccc'};
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer:hover {
|
||||||
|
${this.goBright ? '#000' : '#ccc'};
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-left: 15px;
|
||||||
|
line-height: 25px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-bottom: 1px solid #e4002b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
transition: all 0.1s;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid ${this.goBright ? '#CCC' : '#999'};
|
||||||
|
border-radius: 2px;
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
display: inline-block;
|
||||||
|
background: ${this.goBright ? '#fafafa' : '#222'};
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox.selected {
|
||||||
|
background: #0050b9;
|
||||||
|
border: 1px solid #0050b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox.disabled {
|
||||||
|
background: none;
|
||||||
|
border: 1px dashed ${cssManager.bdTheme('#666666', '#666666')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox .checkmark {
|
||||||
|
display: inline-block;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
-ms-transform: rotate(45deg); /* IE 9 */
|
||||||
|
-webkit-transform: rotate(45deg); /* Chrome, Safari, Opera */
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox .checkmark_stem {
|
||||||
|
position: absolute;
|
||||||
|
width: 3px;
|
||||||
|
height: 9px;
|
||||||
|
background-color: #fff;
|
||||||
|
left: 11px;
|
||||||
|
top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox .checkmark_kick {
|
||||||
|
position: absolute;
|
||||||
|
width: 3px;
|
||||||
|
height: 3px;
|
||||||
|
background-color: #fff;
|
||||||
|
left: 8px;
|
||||||
|
top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox.disabled .checkmark_stem, .checkbox.disabled .checkmark_kick {
|
||||||
|
background-color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="maincontainer" @click="${this.toggleSelected}">
|
||||||
|
<div class="checkbox ${this.value ? 'selected' : ''} ${this.disabled ? 'disabled' : ''}" tabindex="0">
|
||||||
|
${this.value
|
||||||
|
? html`
|
||||||
|
<span class="checkmark">
|
||||||
|
<div class="checkmark_stem"></div>
|
||||||
|
<div class="checkmark_kick"></div>
|
||||||
|
</span>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
</div>
|
||||||
|
<div class="label">${this.label}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async toggleSelected() {
|
||||||
|
if (this.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.value = !this.value;
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('newValue', {
|
||||||
|
detail: this.value,
|
||||||
|
bubbles: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public focus(): void {
|
||||||
|
const checkboxDiv = this.shadowRoot.querySelector('.checkbox');
|
||||||
|
if (checkboxDiv) {
|
||||||
|
(checkboxDiv as any).focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
ts_web/elements/dees-input-dropdown.demo.ts
Normal file
27
ts_web/elements/dees-input-dropdown.demo.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<dees-input-dropdown
|
||||||
|
.options=${[
|
||||||
|
{option: 'option 1', key: 'option1'},
|
||||||
|
{option: 'option 2', key: 'option2'},
|
||||||
|
{option: 'option 3', key: 'option3'}
|
||||||
|
]}
|
||||||
|
></dees-input-dropdown>
|
||||||
|
<dees-input-dropdown
|
||||||
|
.enableSearch=${false}
|
||||||
|
.options=${[
|
||||||
|
{option: 'option 1', key: 'option1'},
|
||||||
|
{option: 'option 2', key: 'option2'},
|
||||||
|
{option: 'option 3', key: 'option3'}
|
||||||
|
]}
|
||||||
|
></dees-input-dropdown>
|
||||||
|
<div style="height: 300px"></div>
|
||||||
|
<dees-input-dropdown
|
||||||
|
.options=${[
|
||||||
|
{option: 'option 1', key: 'option1'},
|
||||||
|
{option: 'option 2', key: 'option2'},
|
||||||
|
{option: 'option 3', key: 'option3'}
|
||||||
|
]}
|
||||||
|
></dees-input-dropdown>
|
||||||
|
`
|
375
ts_web/elements/dees-input-dropdown.ts
Normal file
375
ts_web/elements/dees-input-dropdown.ts
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
state,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
type CSSResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { demoFunc } from './dees-input-dropdown.demo.js';
|
||||||
|
import { DeesWindowLayer } from './dees-windowlayer.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-input-dropdown': DeesInputDropdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-input-dropdown')
|
||||||
|
export class DeesInputDropdown extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public label: string = 'Label';
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public key: string;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public options: { option: string; key: string; payload?: any }[] = [];
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public selectedOption: { option: string; key: string; payload?: any } = null;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public required: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public enableSearch: boolean = true;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public disabled: boolean = false;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
public opensToTop: boolean = false;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private filteredOptions: { option: string; key: string; payload?: any }[] = [];
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private highlightedIndex: number = 0;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
public isOpened = false;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host {
|
||||||
|
font-family: Roboto;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
color: ${cssManager.bdTheme('#222', '#fff')};
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectedBox {
|
||||||
|
user-select: none;
|
||||||
|
position: relative;
|
||||||
|
max-width: 420px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0px 8px;
|
||||||
|
background: ${cssManager.bdTheme('#fafafa', '#222222')};
|
||||||
|
box-shadow: ${cssManager.bdTheme('0px 1px 4px rgba(0,0,0,0.3)', 'none')};
|
||||||
|
border-radius: 3px;
|
||||||
|
border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #ffffff10')};
|
||||||
|
border-bottom: ${cssManager.bdTheme('1px solid #CCC', '1px solid #222')};
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-size: 16px;
|
||||||
|
color: ${cssManager.bdTheme('#222', '#ccc')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectedBox:hover {
|
||||||
|
filter: ${cssManager.bdTheme('brightness(0.95)', 'brightness(1.1)')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.accentBottom {
|
||||||
|
filter: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accentTop {
|
||||||
|
filter: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectionBox {
|
||||||
|
will-change: transform;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
opacity: 0;
|
||||||
|
background: ${cssManager.bdTheme('#ffffff', '#222222')};
|
||||||
|
max-width: 420px;
|
||||||
|
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
min-height: 40px;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
position: absolute;
|
||||||
|
user-select: none;
|
||||||
|
margin: 3px 0px 0px 0px;
|
||||||
|
border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #ffffff10')};
|
||||||
|
}
|
||||||
|
.selectionBox.top {
|
||||||
|
transform: translate(0px, 4px);
|
||||||
|
}
|
||||||
|
.selectionBox.bottom {
|
||||||
|
transform: translate(0px, -4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectionBox.show {
|
||||||
|
pointer-events: all;
|
||||||
|
transform: scale(1, 1) translate(0px, 0px);
|
||||||
|
opacity: 1;
|
||||||
|
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option {
|
||||||
|
transition: all 0.1s;
|
||||||
|
line-height: 32px;
|
||||||
|
padding: 0px 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin: 4px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option.highlighted {
|
||||||
|
border-left: 2px solid #0069f2;
|
||||||
|
padding-left: 6px;
|
||||||
|
background: #ffffff20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option:hover {
|
||||||
|
color: #fff;
|
||||||
|
padding-left: 8px;
|
||||||
|
background: #0069f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search.top {
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
.search.bottom {
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
.search input {
|
||||||
|
display: block;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
height: 24px;
|
||||||
|
color: inherit;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search.top input {
|
||||||
|
border-bottom: 1px dotted #333;
|
||||||
|
}
|
||||||
|
.search.bottom input {
|
||||||
|
border-top: 1px dotted #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search input:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="maincontainer" @keydown="${this.isOpened ? this.handleKeyDown : undefined}">
|
||||||
|
${this.label ? html`<div class="label">${this.label}</div>` : html``}
|
||||||
|
<div class="selectionBox">
|
||||||
|
${this.enableSearch && !this.opensToTop
|
||||||
|
? html`
|
||||||
|
<div class="search top">
|
||||||
|
<input type="text" placeholder="Search" @input="${this.handleSearch}" />
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: null}
|
||||||
|
${this.filteredOptions.map((option, index) => {
|
||||||
|
const isHighlighted = this.highlightedIndex === index;
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
class="option ${isHighlighted ? 'highlighted' : ''}"
|
||||||
|
@click=${() => {
|
||||||
|
this.updateSelection(option);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${option.option}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
${this.enableSearch && this.opensToTop
|
||||||
|
? html`
|
||||||
|
<div class="search bottom">
|
||||||
|
<input type="text" placeholder="Search" @input="${this.handleSearch}" />
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="selectedBox"
|
||||||
|
@click="${(event) => {
|
||||||
|
if (!this.isElevated) {
|
||||||
|
this.toggleSelectionBox();
|
||||||
|
} else {
|
||||||
|
this.updateSelection(this.selectedOption);
|
||||||
|
}
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
${this.selectedOption?.option || 'Select...'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this.selectedOption = this.selectedOption || null;
|
||||||
|
this.filteredOptions = this.options; // Initialize filteredOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateSelection(selectedOption) {
|
||||||
|
this.selectedOption = selectedOption;
|
||||||
|
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('selectedOption', {
|
||||||
|
detail: selectedOption,
|
||||||
|
bubbles: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (this.isElevated) {
|
||||||
|
this.toggleSelectionBox();
|
||||||
|
}
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private isElevated: boolean = false;
|
||||||
|
private windowOverlay: DeesWindowLayer;
|
||||||
|
public async toggleSelectionBox() {
|
||||||
|
this.isOpened = !this.isOpened;
|
||||||
|
const domtoolsInstance = await this.domtoolsPromise;
|
||||||
|
const selectedBox: HTMLElement = this.shadowRoot.querySelector('.selectedBox');
|
||||||
|
const selectionBox: HTMLElement = this.shadowRoot.querySelector('.selectionBox');
|
||||||
|
if (!this.isElevated) {
|
||||||
|
this.windowOverlay = await DeesWindowLayer.createAndShow({
|
||||||
|
blur: false,
|
||||||
|
});
|
||||||
|
const elevatedDropdown = new DeesInputDropdown();
|
||||||
|
elevatedDropdown.isElevated = true;
|
||||||
|
elevatedDropdown.label = this.label;
|
||||||
|
elevatedDropdown.enableSearch = this.enableSearch;
|
||||||
|
elevatedDropdown.required = this.required;
|
||||||
|
elevatedDropdown.disabled = this.disabled;
|
||||||
|
elevatedDropdown.style.position = 'fixed';
|
||||||
|
elevatedDropdown.style.top = this.getBoundingClientRect().top + 'px';
|
||||||
|
elevatedDropdown.style.left = this.getBoundingClientRect().left + 'px';
|
||||||
|
elevatedDropdown.style.width = this.clientWidth + 'px';
|
||||||
|
elevatedDropdown.options = this.options;
|
||||||
|
elevatedDropdown.selectedOption = this.selectedOption;
|
||||||
|
elevatedDropdown.highlightedIndex = elevatedDropdown.selectedOption ? elevatedDropdown.options.indexOf(
|
||||||
|
elevatedDropdown.options.find((option) => option.key === this.selectedOption.key)
|
||||||
|
) : -1;
|
||||||
|
console.log(elevatedDropdown.options);
|
||||||
|
console.log(elevatedDropdown.selectedOption);
|
||||||
|
console.log(elevatedDropdown.highlightedIndex);
|
||||||
|
this.windowOverlay.appendChild(elevatedDropdown);
|
||||||
|
await domtoolsInstance.convenience.smartdelay.delayFor(0);
|
||||||
|
elevatedDropdown.toggleSelectionBox();
|
||||||
|
const destroyOverlay = async () => {
|
||||||
|
(elevatedDropdown.shadowRoot.querySelector('.selectionBox') as HTMLElement).style.opacity =
|
||||||
|
'0';
|
||||||
|
elevatedDropdown.removeEventListener('selectedOption', handleSelection);
|
||||||
|
this.windowOverlay.removeEventListener('clicked', destroyOverlay);
|
||||||
|
this.windowOverlay.destroy();
|
||||||
|
};
|
||||||
|
const handleSelection = async (event) => {
|
||||||
|
await this.updateSelection(elevatedDropdown.selectedOption);
|
||||||
|
destroyOverlay();
|
||||||
|
};
|
||||||
|
elevatedDropdown.addEventListener('selectedOption', handleSelection);
|
||||||
|
this.windowOverlay.addEventListener('clicked', destroyOverlay);
|
||||||
|
} else {
|
||||||
|
if (!selectionBox.classList.contains('show')) {
|
||||||
|
selectionBox.style.width = selectedBox.clientWidth + 'px';
|
||||||
|
const spaceData = selectedBox.getBoundingClientRect();
|
||||||
|
if (300 > window.innerHeight - spaceData.bottom) {
|
||||||
|
this.opensToTop = true;
|
||||||
|
selectedBox.classList.add('accentTop');
|
||||||
|
selectionBox.classList.add('top');
|
||||||
|
selectionBox.style.bottom = selectedBox.clientHeight + 2 + 'px';
|
||||||
|
} else {
|
||||||
|
selectedBox.classList.add('accentBottom');
|
||||||
|
selectionBox.classList.add('bottom');
|
||||||
|
this.opensToTop = false;
|
||||||
|
const labelOffset = this.label ? 24 : 0;
|
||||||
|
selectionBox.style.top = selectedBox.clientHeight + labelOffset + 'px';
|
||||||
|
}
|
||||||
|
await domtoolsInstance.convenience.smartdelay.delayFor(0);
|
||||||
|
const searchInput = selectionBox.querySelector('input');
|
||||||
|
searchInput?.focus();
|
||||||
|
selectionBox.classList.add('show');
|
||||||
|
} else {
|
||||||
|
selectedBox.style.pointerEvents = 'none';
|
||||||
|
selectionBox.classList.remove('show');
|
||||||
|
// selectedBox.style.opacity = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSearch(event: Event): void {
|
||||||
|
const searchTerm = (event.target as HTMLInputElement).value.toLowerCase();
|
||||||
|
this.filteredOptions = this.options.filter((option) =>
|
||||||
|
option.option.toLowerCase().includes(searchTerm)
|
||||||
|
);
|
||||||
|
this.highlightedIndex = 0; // Reset highlighted index
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleKeyDown(event: KeyboardEvent): void {
|
||||||
|
if (!this.isOpened) {
|
||||||
|
console.log('discarded key event. Check why this function is called.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const key = event.key;
|
||||||
|
const maxIndex = this.filteredOptions.length - 1;
|
||||||
|
|
||||||
|
if (key === 'ArrowDown') {
|
||||||
|
this.highlightedIndex = this.highlightedIndex + 1 > maxIndex ? 0 : this.highlightedIndex + 1;
|
||||||
|
event.preventDefault();
|
||||||
|
} else if (key === 'ArrowUp') {
|
||||||
|
this.highlightedIndex = this.highlightedIndex - 1 < 0 ? maxIndex : this.highlightedIndex - 1;
|
||||||
|
event.preventDefault();
|
||||||
|
} else if (key === 'Enter') {
|
||||||
|
this.updateSelection(this.filteredOptions[this.highlightedIndex]);
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
266
ts_web/elements/dees-input-fileupload.ts
Normal file
266
ts_web/elements/dees-input-fileupload.ts
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
import * as colors from './00colors.js';
|
||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
|
||||||
|
import { DeesContextmenu } from './dees-contextmenu.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
unsafeCSS,
|
||||||
|
cssManager,
|
||||||
|
type CSSResult,
|
||||||
|
domtools,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-input-fileupload': DeesInputFileupload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-input-fileupload')
|
||||||
|
export class DeesInputFileupload extends DeesElement {
|
||||||
|
public static demo = () =>
|
||||||
|
html`<dees-input-fileupload .label=${'Attachments'}></dees-input-fileupload>`;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public label: string = null;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public key: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
attribute: false,
|
||||||
|
})
|
||||||
|
public value: File[] = [];
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public state: 'idle' | 'dragOver' | 'dropped' | 'uploading' | 'completed' = 'idle';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public required: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public disabled: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public buttonText: string = 'Upload File...';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
margin: 10px 0px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 8px;
|
||||||
|
background: ${cssManager.bdTheme('#fafafa', '#222222')};
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
border-top: 1px solid #ffffff10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer::after {
|
||||||
|
top: 2px;
|
||||||
|
right: 2px;
|
||||||
|
left: 2px;
|
||||||
|
bottom: 2px;
|
||||||
|
transform: scale3d(0.98, 0.9, 1);
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
border: 2px dashed rgba(255, 255, 255, 0);
|
||||||
|
transition: all 0.2s;
|
||||||
|
pointer-events: none;
|
||||||
|
background: #00000000;
|
||||||
|
}
|
||||||
|
.maincontainer.dragOver::after {
|
||||||
|
transform: scale3d(1, 1, 1);
|
||||||
|
border: 2px dashed rgba(255, 255, 255, 0.3);
|
||||||
|
background: #00000080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploadButton {
|
||||||
|
position: relative;
|
||||||
|
padding: 8px;
|
||||||
|
max-width: 600px;
|
||||||
|
background: ${cssManager.bdTheme('#fafafa', '#333333')};
|
||||||
|
border-radius: 3px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploadButton:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: ${unsafeCSS(colors.dark.blue)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploadCandidate {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 48px auto;
|
||||||
|
background: #333;
|
||||||
|
padding: 8px 8px 8px 0px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
text-align: left;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: ${cssManager.bdTheme('#666', '#ccc')};
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
cursor: default;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border-top: 1px solid #ffffff10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploadCandidate:last-child {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploadCandidate .icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploadCandidate:hover {
|
||||||
|
background: #393939;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploadCandidate .description {
|
||||||
|
font-size: 14px;
|
||||||
|
border-left: 1px solid #ffffff10;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="hidden">
|
||||||
|
<input type="file"></div>
|
||||||
|
</div>
|
||||||
|
${this.label ? html`<div class="label">${this.label}</div>` : null}
|
||||||
|
<div class="maincontainer ${this.state === 'dragOver' ? 'dragOver' : ''}">
|
||||||
|
${this.value.map(
|
||||||
|
(fileArg) => html`
|
||||||
|
<div class="uploadCandidate" @contextmenu=${eventArg => {
|
||||||
|
DeesContextmenu.openContextMenuWithOptions(eventArg, [{
|
||||||
|
iconName: 'trash',
|
||||||
|
name: 'Remove',
|
||||||
|
action: async () => {
|
||||||
|
this.value.splice(this.value.indexOf(fileArg), 1);
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
}}>
|
||||||
|
<div class="icon">
|
||||||
|
<dees-icon .iconFA=${'paperclip'}></dees-icon>
|
||||||
|
</div>
|
||||||
|
<div class="description">
|
||||||
|
<span style="font-weight: 600">${fileArg.name}</span><br />
|
||||||
|
<span style="font-weight: 400">${fileArg.size}</span>
|
||||||
|
</div>
|
||||||
|
</div> `
|
||||||
|
)}
|
||||||
|
<div class="uploadButton" @click=${
|
||||||
|
this.openFileSelector
|
||||||
|
}>
|
||||||
|
${this.buttonText}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async openFileSelector() {
|
||||||
|
const inputFile: HTMLInputElement = this.shadowRoot.querySelector('input[type="file"]');
|
||||||
|
inputFile.click();
|
||||||
|
this.state = 'idle';
|
||||||
|
this.buttonText = 'Upload more files...';
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateValue(eventArg: Event) {
|
||||||
|
const target: any = eventArg.target;
|
||||||
|
this.value = target.value;
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public firstUpdated() {
|
||||||
|
const inputFile: HTMLInputElement = this.shadowRoot.querySelector('input[type="file"]');
|
||||||
|
inputFile.addEventListener('change', (event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
for (const file of Array.from(target.files)) {
|
||||||
|
this.value.push(file);
|
||||||
|
}
|
||||||
|
this.requestUpdate();
|
||||||
|
console.log(`Got ${this.value.length} files!`);
|
||||||
|
// Reset the input value to allow selecting the same file again if needed
|
||||||
|
target.value = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// lets handle drag and drop
|
||||||
|
const dropArea = this.shadowRoot.querySelector('.maincontainer');
|
||||||
|
const handlerFunction = (eventArg: DragEvent) => {
|
||||||
|
eventArg.preventDefault();
|
||||||
|
switch (eventArg.type) {
|
||||||
|
case 'dragover':
|
||||||
|
this.state = 'dragOver';
|
||||||
|
this.buttonText = 'release to upload file...';
|
||||||
|
break;
|
||||||
|
case 'dragleave':
|
||||||
|
this.state = 'idle';
|
||||||
|
this.buttonText = 'Upload File...';
|
||||||
|
break;
|
||||||
|
case 'drop':
|
||||||
|
this.state = 'idle';
|
||||||
|
this.buttonText = 'Upload more files...';
|
||||||
|
}
|
||||||
|
console.log(eventArg);
|
||||||
|
for (const file of Array.from(eventArg.dataTransfer.files)) {
|
||||||
|
this.value.push(file);
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
console.log(`Got ${this.value.length} files!`);
|
||||||
|
};
|
||||||
|
dropArea.addEventListener('dragenter', handlerFunction, false);
|
||||||
|
dropArea.addEventListener('dragleave', handlerFunction, false);
|
||||||
|
dropArea.addEventListener('dragover', handlerFunction, false);
|
||||||
|
dropArea.addEventListener('drop', handlerFunction, false);
|
||||||
|
}
|
||||||
|
}
|
3
ts_web/elements/dees-input-iban.demo.ts
Normal file
3
ts_web/elements/dees-input-iban.demo.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`<dees-input-iban .label=${'IBAN'}></dees-input-iban>`;
|
98
ts_web/elements/dees-input-iban.ts
Normal file
98
ts_web/elements/dees-input-iban.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
type TemplateResult,
|
||||||
|
state,
|
||||||
|
html,
|
||||||
|
domtools,
|
||||||
|
property,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as ibantools from 'ibantools';
|
||||||
|
import { demoFunc } from './dees-input-iban.demo.js';
|
||||||
|
|
||||||
|
@customElement('dees-input-iban')
|
||||||
|
export class DeesInputIban extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
@state()
|
||||||
|
enteredString: string = '';
|
||||||
|
|
||||||
|
@state()
|
||||||
|
enteredIbanIsValid: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public disabled = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public required = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public label = '';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public key = '';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public value = '';
|
||||||
|
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject<DeesInputIban>();
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
input[type='text'] {
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 5px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<dees-input-text
|
||||||
|
.label=${'IBAN'}
|
||||||
|
.value=${this.value}
|
||||||
|
@input=${(eventArg: InputEvent) => {
|
||||||
|
this.validateIban(eventArg);
|
||||||
|
}}
|
||||||
|
></dees-input-text>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
const deesInputText = this.shadowRoot.querySelector('dees-input-text');
|
||||||
|
deesInputText.disabled = this.disabled;
|
||||||
|
deesInputText.required = this.required;
|
||||||
|
deesInputText.changeSubject.subscribe(valueArg => {
|
||||||
|
this.value = valueArg.value;
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async validateIban(eventArg: InputEvent): Promise<void> {
|
||||||
|
const inputElement: HTMLInputElement = eventArg.target as HTMLInputElement;
|
||||||
|
let enteredString = inputElement?.value;
|
||||||
|
enteredString = enteredString || '';
|
||||||
|
if (this.enteredString !== enteredString) {
|
||||||
|
this.enteredString = ibantools.friendlyFormatIBAN(enteredString) || '';
|
||||||
|
if (inputElement) {
|
||||||
|
inputElement.value = this.enteredString;
|
||||||
|
this.value = this.enteredString;
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.enteredIbanIsValid = ibantools.isValidIBAN(this.enteredString.replace(/ /g, ''));
|
||||||
|
const deesInputText = this.shadowRoot.querySelector('dees-input-text');
|
||||||
|
deesInputText.validationText = `IBAN is valid: ${this.enteredIbanIsValid}`;
|
||||||
|
}
|
||||||
|
}
|
14
ts_web/elements/dees-input-multitoggle.demo.ts
Normal file
14
ts_web/elements/dees-input-multitoggle.demo.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<dees-input-multitoggle
|
||||||
|
.options=${['option 1', 'option 2', 'a longer option with multiple words']}
|
||||||
|
.selectedOption=${'option 2'}
|
||||||
|
></dees-input-multitoggle>
|
||||||
|
<dees-input-multitoggle
|
||||||
|
.type=${'boolean'}
|
||||||
|
.booleanTrueName=${'enabled'}
|
||||||
|
.booleanFalseName=${'disabled'}
|
||||||
|
.selectedOption=${'true'}
|
||||||
|
></dees-input-multitoggle>
|
||||||
|
`;
|
153
ts_web/elements/dees-input-multitoggle.ts
Normal file
153
ts_web/elements/dees-input-multitoggle.ts
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
type TemplateResult,
|
||||||
|
state,
|
||||||
|
html,
|
||||||
|
domtools,
|
||||||
|
property,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
const { demoFunc } = await import('./dees-input-multitoggle.demo.js');
|
||||||
|
|
||||||
|
@customElement('dees-input-multitoggle')
|
||||||
|
export class DeesInputMultitoggle extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public label: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public description: string;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
type: 'boolean' | 'multi' | 'single' = 'multi';
|
||||||
|
|
||||||
|
@property()
|
||||||
|
booleanTrueName: string = 'true';
|
||||||
|
|
||||||
|
@property()
|
||||||
|
booleanFalseName: string = 'false';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
options: string[] = [];
|
||||||
|
|
||||||
|
@property()
|
||||||
|
selectedOption: string = '';
|
||||||
|
|
||||||
|
@property()
|
||||||
|
boolValue: boolean = false;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
user-select: none;
|
||||||
|
margin: 8px 0px 24px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selections {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
background: ${cssManager.bdTheme('#fff', '#222')};
|
||||||
|
width: min-content;
|
||||||
|
border-radius: 20px;
|
||||||
|
height: 32px;
|
||||||
|
border-top: 1px solid #ffffff10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option {
|
||||||
|
color: #ccc;
|
||||||
|
position: relative;
|
||||||
|
padding: 0px 16px;
|
||||||
|
line-height: 32px;
|
||||||
|
cursor: default;
|
||||||
|
width: min-content; /* Make the width as per the content */
|
||||||
|
white-space: nowrap; /* Prevent text wrapping */
|
||||||
|
transition: all 0.1s;
|
||||||
|
font-size: 14px;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option.selected {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
height: 24px;
|
||||||
|
left: 4px;
|
||||||
|
top: 3px;
|
||||||
|
border-radius: 16px;
|
||||||
|
background: #0050b9;
|
||||||
|
min-width: 36px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<dees-label .label=${this.label} .description=${this.description}></dees-label>
|
||||||
|
<div class="mainbox">
|
||||||
|
<div class="selections">
|
||||||
|
<div class="indicator"></div>
|
||||||
|
${this.options.map(
|
||||||
|
(option) =>
|
||||||
|
html`<div class="option ${option === this.selectedOption ? 'selected': ''}" @click=${() => this.handleSelection(option)}>
|
||||||
|
${option}
|
||||||
|
</div> `
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
if (this.type === 'boolean') {
|
||||||
|
this.options = [this.booleanTrueName || 'true', this.booleanFalseName || 'false'];
|
||||||
|
}
|
||||||
|
this.setIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleSelection(optionArg: string) {
|
||||||
|
this.selectedOption = optionArg;
|
||||||
|
this.setIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setIndicator() {
|
||||||
|
const indicator: HTMLDivElement = this.shadowRoot.querySelector('.indicator');
|
||||||
|
const option: HTMLDivElement = this.shadowRoot.querySelector(
|
||||||
|
`.option:nth-child(${this.options.indexOf(this.selectedOption) + 2})`
|
||||||
|
);
|
||||||
|
if (indicator && option) {
|
||||||
|
indicator.style.width = `${option.clientWidth - 8}px`;
|
||||||
|
indicator.style.left = `${option.offsetLeft + 4}px`;
|
||||||
|
indicator.style.opacity = '1';
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
indicator.style.transition = 'all 0.1s';
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
3
ts_web/elements/dees-input-phone.demo.ts
Normal file
3
ts_web/elements/dees-input-phone.demo.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`<dees-input-phone .label=${'Phone Number'}></dees-input-phone>`;
|
29
ts_web/elements/dees-input-phone.ts
Normal file
29
ts_web/elements/dees-input-phone.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
unsafeCSS,
|
||||||
|
cssManager,
|
||||||
|
type CSSResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import { demoFunc } from './dees-input-phone.demo.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-input-phone': DeesInputPhone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-input-phone')
|
||||||
|
export class DeesInputPhone extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public render() {
|
||||||
|
return html`<div>Phone Input</div>`;
|
||||||
|
}
|
||||||
|
}
|
118
ts_web/elements/dees-input-quantityselector.ts
Normal file
118
ts_web/elements/dees-input-quantityselector.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { customElement, property, html, type TemplateResult, DeesElement, type CSSResult, } from '@design.estate/dees-element';
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-input-quantityselector': DeesInputQuantitySelector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-input-quantityselector')
|
||||||
|
export class DeesInputQuantitySelector extends DeesElement {
|
||||||
|
public static demo = () => html`<dees-input-quantityselector></dees-input-quantityselector>`;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public label: string = 'Label';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public key: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Number
|
||||||
|
})
|
||||||
|
public value: number = 1;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public required: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean
|
||||||
|
})
|
||||||
|
public disabled: boolean = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${domtools.elementBasic.styles}
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
width: 110px;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.maincontainer {
|
||||||
|
transition: all 0.1s;
|
||||||
|
font-size: 14px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 33% 34% 33%;
|
||||||
|
text-align: center;
|
||||||
|
background:none;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0px;
|
||||||
|
min-width: 100px;
|
||||||
|
color: ${this.goBright ? '#666' : '#CCC'};
|
||||||
|
border: ${this.goBright ? '1px solid #333' : '1px solid #CCC'};
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainContainer:hover {
|
||||||
|
color: ${this.goBright ? '#333' : '#fff'};
|
||||||
|
border: ${this.goBright ? '1px solid #333' : '1px solid #fff'};
|
||||||
|
}
|
||||||
|
|
||||||
|
.minus {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plus {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector:hover {
|
||||||
|
}
|
||||||
|
|
||||||
|
.quantity {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="maincontainer">
|
||||||
|
<div class="selector minus" @click="${() => {this.decrease();}}">-</div>
|
||||||
|
<div class="quantity">${this.value}</div>
|
||||||
|
<div class="selector plus" @click="${() => {this.increase();}}">+</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public increase () {
|
||||||
|
this.value++;
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public decrease () {
|
||||||
|
if (this.value > 0) {
|
||||||
|
this.value--;
|
||||||
|
} else {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
}
|
||||||
|
}
|
127
ts_web/elements/dees-input-radio.ts
Normal file
127
ts_web/elements/dees-input-radio.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import {customElement, DeesElement, type TemplateResult, property, html, type CSSResult,} from '@design.estate/dees-element';
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-input-radio': DeesInputRadio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-input-radio')
|
||||||
|
export class DeesInputRadio extends DeesElement {
|
||||||
|
public static demo = () => html`<dees-input-radio></dees-input-radio>`;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public key: string;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public label: string = 'Label';
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public value: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public required: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean
|
||||||
|
})
|
||||||
|
public disabled: boolean = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html `
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
margin: 20px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer {
|
||||||
|
transition: all 0.3s;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 25px auto;
|
||||||
|
padding: 5px 0px;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-left: 15px;
|
||||||
|
line-height: 25px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-bottom: 1px solid #e4002b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
transition: all 0.3s;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 1px solid #999;
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
display: inline-block;
|
||||||
|
background: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox.selected {
|
||||||
|
background: #0050b9;
|
||||||
|
border: 1px solid #0050b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer:hover .checkbox.selected {
|
||||||
|
background: #03A9F4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.innercircle {
|
||||||
|
transition: all 0.3s;
|
||||||
|
margin: 6px 0px 0px 6px;
|
||||||
|
background: #222;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="maincontainer" @click="${this.toggleSelected}">
|
||||||
|
<div class="checkbox ${this.value ? 'selected' : ''}">
|
||||||
|
${this.value ? html`<div class="innercircle"></div>`: html``}
|
||||||
|
</div>
|
||||||
|
<div class="label">${this.label}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async toggleSelected () {
|
||||||
|
this.value = !this.value;
|
||||||
|
this.dispatchEvent(new CustomEvent('newValue', {
|
||||||
|
detail: this.value,
|
||||||
|
bubbles: true
|
||||||
|
}));
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
}
|
||||||
|
}
|
0
ts_web/elements/dees-input-tags.ts
Normal file
0
ts_web/elements/dees-input-tags.ts
Normal file
254
ts_web/elements/dees-input-text.ts
Normal file
254
ts_web/elements/dees-input-text.ts
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
import * as colors from './00colors.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
html,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-input-text': DeesInputText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-input-text')
|
||||||
|
export class DeesInputText extends DeesElement {
|
||||||
|
public static demo = () => html`
|
||||||
|
<dees-input-text .label=${'this is a label'} .value=${'test'}></dees-input-text>
|
||||||
|
<dees-input-text .isPasswordBool=${true}></dees-input-text>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject<DeesInputText>();
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public label: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public description: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public key: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public value: string = '';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public required: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public disabled: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public isPasswordBool = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public showPasswordBool = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public validationState: 'valid' | 'warn' | 'invalid';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public validationText: string = '';
|
||||||
|
|
||||||
|
@property({})
|
||||||
|
validationFunction: (value: string) => boolean;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
margin: 8px 0px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
z-index: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer {
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin-top: 0px;
|
||||||
|
background: ${cssManager.bdTheme('#fafafa', '#222')};
|
||||||
|
border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #ffffff10')};
|
||||||
|
border-bottom: ${cssManager.bdTheme('1px solid #CCC', '1px solid #222')};
|
||||||
|
border-right: ${cssManager.bdTheme('1px solid #CCC', 'none')};
|
||||||
|
border-left: ${cssManager.bdTheme('1px solid #CCC', 'none')};
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
border-radius: 2px;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 36px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
outline: none;
|
||||||
|
font-size: 16px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:disabled {
|
||||||
|
background: ${cssManager.bdTheme('#ffffff00', '#11111100')};
|
||||||
|
border: 1px dashed ${cssManager.bdTheme('#666666', '#666666')};
|
||||||
|
color: #9b9b9e;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-bottom: 1px solid ${cssManager.bdTheme( colors.bright.blueActive, colors.dark.blueActive)};
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:hover {
|
||||||
|
filter: ${cssManager.bdTheme('brightness(0.95)', 'brightness(1.1)')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.showPassword {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 7px;
|
||||||
|
right: 10px;
|
||||||
|
border: 1px dashed #444;
|
||||||
|
border-radius: 7px;
|
||||||
|
padding: 4px 0px;
|
||||||
|
width: 40px;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.showPassword:hover {
|
||||||
|
background: ${cssManager.bdTheme('#00000010', '#ffffff10')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.validationContainer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 6px 2px 2px 2px;
|
||||||
|
margin-top: -4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #fff;
|
||||||
|
background: #e4002b;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
input {
|
||||||
|
font-family: ${this.isPasswordBool ? 'monospace' : 'Roboto'};
|
||||||
|
letter-spacing: ${this.isPasswordBool ? '1px' : 'normal'};
|
||||||
|
color: ${this.goBright ? '#333' : '#ccc'};
|
||||||
|
}
|
||||||
|
${this.validationText ? css`
|
||||||
|
.validationContainer {
|
||||||
|
height: 22px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
` : css`
|
||||||
|
.validationContainer {
|
||||||
|
height: 4px;
|
||||||
|
padding: 2px !important;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
|
<div class="maincontainer">
|
||||||
|
<dees-label .label=${this.label} .description=${this.description}></dees-label>
|
||||||
|
<input
|
||||||
|
type="${this.isPasswordBool && !this.showPasswordBool ? 'password' : 'text'}"
|
||||||
|
.value=${this.value}
|
||||||
|
@input="${this.updateValue}"
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
/>
|
||||||
|
<div class="validationContainer">
|
||||||
|
${this.validationText}
|
||||||
|
</div>
|
||||||
|
${this.isPasswordBool
|
||||||
|
? html`
|
||||||
|
<div class="showPassword" @click=${this.togglePasswordView}>
|
||||||
|
<dees-icon .iconFA=${this.showPasswordBool ? 'eye' : 'eyeSlash'}></dees-icon>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
const input = this.shadowRoot.querySelector('input');
|
||||||
|
input.addEventListener('input', (eventArg: InputEvent) => {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateValue(eventArg: Event) {
|
||||||
|
const target: any = eventArg.target;
|
||||||
|
this.value = target.value;
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async freeze() {
|
||||||
|
this.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async unfreeze() {
|
||||||
|
this.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async togglePasswordView() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
this.showPasswordBool = !this.showPasswordBool;
|
||||||
|
console.log(`this.showPasswordBool is: ${this.showPasswordBool}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async focus() {
|
||||||
|
const textInput = this.shadowRoot.querySelector('input');
|
||||||
|
textInput.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async blur() {
|
||||||
|
const textInput = this.shadowRoot.querySelector('input');
|
||||||
|
textInput.blur();
|
||||||
|
}
|
||||||
|
}
|
15
ts_web/elements/dees-input-typelist.demo.ts
Normal file
15
ts_web/elements/dees-input-typelist.demo.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<style>
|
||||||
|
.demoContainer {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 40px;
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="demoContainer">
|
||||||
|
<dees-input-typelist></dees-input-typelist>
|
||||||
|
</div>
|
||||||
|
`;
|
98
ts_web/elements/dees-input-typelist.ts
Normal file
98
ts_web/elements/dees-input-typelist.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
type TemplateResult,
|
||||||
|
state,
|
||||||
|
html,
|
||||||
|
domtools,
|
||||||
|
property,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
const { demoFunc } = await import('./dees-input-typelist.demo.js');
|
||||||
|
|
||||||
|
@customElement('dees-input-typelist')
|
||||||
|
export class DeesInputTypelist extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public label: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
margin: 8px 0px 24px 0px;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.mainbox {
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #222;
|
||||||
|
overflow: hidden;
|
||||||
|
border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #444')};
|
||||||
|
border-bottom: ${cssManager.bdTheme('1px solid #CCC', '1px solid #333')};
|
||||||
|
border-right: ${cssManager.bdTheme('1px solid #CCC', 'none')};
|
||||||
|
border-left: ${cssManager.bdTheme('1px solid #CCC', 'none')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
padding: 16px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notags {
|
||||||
|
text-align: center;
|
||||||
|
opacity: 0.5;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: #181818;
|
||||||
|
width: 100%;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
color: inherit;
|
||||||
|
padding: 0px 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
line-height: 32px;
|
||||||
|
height: 0px;
|
||||||
|
transition: height 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="label">${this.label}</div>
|
||||||
|
<div class="mainbox">
|
||||||
|
<div class="tags" @click=${() => {
|
||||||
|
this.shadowRoot.querySelector('input').focus();
|
||||||
|
}}>
|
||||||
|
<div class="notags">No tags yet</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" placeholder="Type, press Enter to add it..." />
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
7
ts_web/elements/dees-label.demo.ts
Normal file
7
ts_web/elements/dees-label.demo.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { html, cssManager } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => {
|
||||||
|
return html`
|
||||||
|
<dees-label .label=${'a label'}></dees-label>
|
||||||
|
`;
|
||||||
|
}
|
70
ts_web/elements/dees-label.ts
Normal file
70
ts_web/elements/dees-label.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
import * as colors from './00colors.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
unsafeCSS,
|
||||||
|
query,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import { demoFunc } from './dees-label.demo.js';
|
||||||
|
|
||||||
|
@customElement('dees-label')
|
||||||
|
export class DeesLabel extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public label = '';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public description: string;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
.label {
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
cursor: default;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
dees-icon {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
transform: translateY(1.5px);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
${this.label
|
||||||
|
? html`
|
||||||
|
<div class="label">
|
||||||
|
${this.label}
|
||||||
|
${this.description
|
||||||
|
? html`
|
||||||
|
<dees-icon .iconFA=${'circleInfo'}></dees-icon>
|
||||||
|
<dees-speechbubble .text=${this.description}></dees-speechbubble>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
184
ts_web/elements/dees-mobilenavigation.ts
Normal file
184
ts_web/elements/dees-mobilenavigation.ts
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
import {
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
domtools,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import { DeesWindowLayer } from './dees-windowlayer.js';
|
||||||
|
|
||||||
|
@customElement('dees-mobilenavigation')
|
||||||
|
export class DeesMobilenavigation extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = () => html`
|
||||||
|
<dees-button @click=${() => {
|
||||||
|
DeesMobilenavigation.createAndShow([
|
||||||
|
{
|
||||||
|
name: 'Test',
|
||||||
|
action: async (deesMobileNav) => {
|
||||||
|
alert('test');
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}}></dees-button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
private static singletonRef: DeesMobilenavigation;
|
||||||
|
public static async createAndShow(menuItemsArg: plugins.tsclass.website.IMenuItem<DeesMobilenavigation>[]) {
|
||||||
|
if (!this.singletonRef) {
|
||||||
|
this.singletonRef = new DeesMobilenavigation();
|
||||||
|
document.body.append(this.singletonRef);
|
||||||
|
await this.singletonRef.init();
|
||||||
|
}
|
||||||
|
this.singletonRef.menuItems = menuItemsArg;
|
||||||
|
await this.singletonRef.readyDeferred.promise;
|
||||||
|
this.singletonRef.show();
|
||||||
|
return this.singletonRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
public heading: string = `MENU`;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
public menuItems: plugins.tsclass.website.IMenuItem[] = [];
|
||||||
|
|
||||||
|
readyDeferred: plugins.smartpromise.Deferred<any> = domtools.plugins.smartpromise.defer();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
/* this.init().then(() => {
|
||||||
|
this.show();
|
||||||
|
}); */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inits the mobile navigation
|
||||||
|
*/
|
||||||
|
public async init() {
|
||||||
|
await this.updateComplete;
|
||||||
|
this.readyDeferred.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
transition: all 0.3s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
will-change: transform;
|
||||||
|
position: fixed;
|
||||||
|
height: 100vh;
|
||||||
|
min-width: 280px;
|
||||||
|
transform: translateX(200px);
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
z-index: 250;
|
||||||
|
opacity: 0;
|
||||||
|
padding: 16px 32px;
|
||||||
|
right: 0px;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#000')};
|
||||||
|
border-left: 1px solid ${cssManager.bdTheme('#eeeeeb', '#222')};
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main.show {
|
||||||
|
pointer-events: all;
|
||||||
|
transform: translateX(0px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuItem {
|
||||||
|
text-align: left;
|
||||||
|
padding: 8px;
|
||||||
|
margin-left: -8px;
|
||||||
|
margin-right: -8px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.menuItem:hover {
|
||||||
|
background: ${cssManager.bdTheme('#CCC', '#333')};;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
text-align: left;
|
||||||
|
font-size: 24px;
|
||||||
|
padding: 8px 0px;
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
font-weight: 300;
|
||||||
|
border-bottom: 1px dashed #444;
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="main">
|
||||||
|
<div class="heading">${this.heading}</div>
|
||||||
|
${this.menuItems.map((menuItem) => {
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
class="menuItem"
|
||||||
|
@click="${() => {
|
||||||
|
this.hide();
|
||||||
|
menuItem.action(this);
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
${menuItem.name}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private windowLayer: DeesWindowLayer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inits the show
|
||||||
|
*/
|
||||||
|
public async show() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
const main = this.shadowRoot.querySelector('.main');
|
||||||
|
if (!this.windowLayer) {
|
||||||
|
this.windowLayer = new DeesWindowLayer();
|
||||||
|
this.windowLayer.options.blur = true;
|
||||||
|
this.windowLayer.addEventListener('click', () => {
|
||||||
|
this.hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
document.body.append(this.windowLayer);
|
||||||
|
await domtools.convenience.smartdelay.delayFor(0);
|
||||||
|
this.windowLayer.show();
|
||||||
|
|
||||||
|
await domtools.convenience.smartdelay.delayFor(0);
|
||||||
|
main.classList.add('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inits the hide function
|
||||||
|
*/
|
||||||
|
public async hide() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
const main = this.shadowRoot.querySelector('.main');
|
||||||
|
main.classList.remove('show');
|
||||||
|
this.windowLayer.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnectedCallback() {
|
||||||
|
document.body.removeChild(this.windowLayer);
|
||||||
|
}
|
||||||
|
}
|
37
ts_web/elements/dees-modal.demo.ts
Normal file
37
ts_web/elements/dees-modal.demo.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
import { DeesModal } from './dees-modal.js';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<dees-button @click=${() => {
|
||||||
|
DeesModal.createAndShow({
|
||||||
|
heading: 'This is a heading',
|
||||||
|
content: html`
|
||||||
|
<dees-form>
|
||||||
|
<dees-input-text
|
||||||
|
.label=${'Username'}
|
||||||
|
>
|
||||||
|
</dees-input-text>
|
||||||
|
<dees-input-text
|
||||||
|
.label=${'Password'}
|
||||||
|
>
|
||||||
|
</dees-input-text>
|
||||||
|
</dees-form>
|
||||||
|
`,
|
||||||
|
menuOptions: [{
|
||||||
|
name: 'Cancel',
|
||||||
|
iconName: null,
|
||||||
|
action: async (deesModalArg) => {
|
||||||
|
deesModalArg.destroy();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Ok',
|
||||||
|
iconName: null,
|
||||||
|
action: async (deesModalArg) => {
|
||||||
|
deesModalArg.destroy();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}}>open modal</dees-button>
|
||||||
|
`
|
214
ts_web/elements/dees-modal.ts
Normal file
214
ts_web/elements/dees-modal.ts
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
import * as colors from './00colors.js';
|
||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
|
||||||
|
import { demoFunc } from './dees-modal.demo.js';
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
unsafeCSS,
|
||||||
|
unsafeHTML,
|
||||||
|
state,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { DeesWindowLayer } from './dees-windowlayer.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-modal': DeesModal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-modal')
|
||||||
|
export class DeesModal extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
public static async createAndShow(optionsArg: {
|
||||||
|
heading: string;
|
||||||
|
content: TemplateResult;
|
||||||
|
menuOptions: plugins.tsclass.website.IMenuItem<DeesModal>[];
|
||||||
|
}) {
|
||||||
|
const body = document.body;
|
||||||
|
const modal = new DeesModal();
|
||||||
|
modal.heading = optionsArg.heading;
|
||||||
|
modal.content = optionsArg.content;
|
||||||
|
modal.menuOptions = optionsArg.menuOptions;
|
||||||
|
modal.windowLayer = await DeesWindowLayer.createAndShow({
|
||||||
|
blur: true,
|
||||||
|
});
|
||||||
|
modal.windowLayer.addEventListener('click', async () => {
|
||||||
|
await modal.destroy();
|
||||||
|
});
|
||||||
|
body.append(modal.windowLayer);
|
||||||
|
body.append(modal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public heading = '';
|
||||||
|
|
||||||
|
@state({})
|
||||||
|
public content: TemplateResult;
|
||||||
|
|
||||||
|
@state({})
|
||||||
|
public menuOptions: plugins.tsclass.website.IMenuItem<DeesModal>[] = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
.modalContainer {
|
||||||
|
display: flex;
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 2000;
|
||||||
|
}
|
||||||
|
.modal {
|
||||||
|
will-change: transform;
|
||||||
|
transform: translateY(0px) scale(0.95);
|
||||||
|
opacity: 0;
|
||||||
|
width: 480px;
|
||||||
|
min-height: 120px;
|
||||||
|
background: #111;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #222;
|
||||||
|
transition: all 0.2s;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0px 2px 5px #00000080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.show {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0px) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.show.predestroy {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10px) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .heading {
|
||||||
|
height: 32px;
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .content {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.modal .bottomButtons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
border-top: 1px solid #222;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .bottomButtons .bottomButton {
|
||||||
|
margin: 8px 0px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
line-height: 16px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: default;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .bottomButtons .bottomButton:first-child {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
.modal .bottomButtons .bottomButton:last-child {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .bottomButtons .bottomButton:hover {
|
||||||
|
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
||||||
|
}
|
||||||
|
.modal .bottomButtons .bottomButton:active {
|
||||||
|
background: ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)};
|
||||||
|
}
|
||||||
|
.modal .bottomButtons .bottomButton:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
.modal .bottomButtons {
|
||||||
|
grid-template-columns: ${cssManager.cssGridColumns(this.menuOptions.length, 0)};
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="modalContainer" @click=${this.handleOutsideClick}>
|
||||||
|
<div class="modal">
|
||||||
|
<div class="heading">${this.heading}</div>
|
||||||
|
<div class="content">${this.content}</div>
|
||||||
|
<div class="bottomButtons">
|
||||||
|
${this.menuOptions.map(
|
||||||
|
(actionArg) => html`
|
||||||
|
<div class="bottomButton" @click=${() => {
|
||||||
|
actionArg.action(this);
|
||||||
|
}}>${actionArg.name}</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private windowLayer: DeesWindowLayer;
|
||||||
|
public async firstUpdated(_changedProperties: Map<string | number | symbol, unknown>) {
|
||||||
|
super.firstUpdated(_changedProperties);
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
await domtools.convenience.smartdelay.delayFor(30);
|
||||||
|
const modal = this.shadowRoot.querySelector('.modal');
|
||||||
|
modal.classList.add('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleOutsideClick(eventArg: MouseEvent) {
|
||||||
|
eventArg.stopPropagation();
|
||||||
|
const modalContainer = this.shadowRoot.querySelector('.modalContainer');
|
||||||
|
if (eventArg.target === modalContainer) {
|
||||||
|
await this.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async destroy() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
const modal = this.shadowRoot.querySelector('.modal');
|
||||||
|
modal.classList.add('predestroy');
|
||||||
|
await domtools.convenience.smartdelay.delayFor(200);
|
||||||
|
document.body.removeChild(this);
|
||||||
|
await this.windowLayer.destroy();
|
||||||
|
}
|
||||||
|
}
|
110
ts_web/elements/dees-pdf.ts
Normal file
110
ts_web/elements/dees-pdf.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import { DeesElement, property, html, customElement, domtools, type TemplateResult, type CSSResult, } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import { Deferred } from '@push.rocks/smartpromise';
|
||||||
|
|
||||||
|
// import type pdfjsTypes from 'pdfjs-dist';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-pdf': DeesPdf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-pdf')
|
||||||
|
export class DeesPdf extends DeesElement {
|
||||||
|
// DEMO
|
||||||
|
public static demo = () => html` <dees-pdf></dees-pdf> `;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public pdfUrl: string =
|
||||||
|
'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
// you have access to all kinds of things through this.
|
||||||
|
// this.setAttribute('gotIt','true');
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
:host([hidden]) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pdfcanvas {
|
||||||
|
box-shadow: 0px 0px 5px #ccc;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<canvas id="pdfcanvas" .height=${0} .width=${0}></canvas>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static pdfJsReady: Promise<any>;
|
||||||
|
public static pdfjsLib: any // typeof pdfjsTypes;
|
||||||
|
public async connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
if (!DeesPdf.pdfJsReady) {
|
||||||
|
const pdfJsReadyDeferred = domtools.plugins.smartpromise.defer();
|
||||||
|
DeesPdf.pdfJsReady = pdfJsReadyDeferred.promise;
|
||||||
|
// @ts-ignore
|
||||||
|
DeesPdf.pdfjsLib = await import('https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.379/+esm');
|
||||||
|
DeesPdf.pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.379/build/pdf.worker.mjs';
|
||||||
|
pdfJsReadyDeferred.resolve();
|
||||||
|
}
|
||||||
|
await DeesPdf.pdfJsReady;
|
||||||
|
this.displayContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async displayContent() {
|
||||||
|
await DeesPdf.pdfJsReady;
|
||||||
|
|
||||||
|
// Asynchronous download of PDF
|
||||||
|
const loadingTask = DeesPdf.pdfjsLib.getDocument(this.pdfUrl);
|
||||||
|
loadingTask.promise.then(
|
||||||
|
(pdf) => {
|
||||||
|
console.log('PDF loaded');
|
||||||
|
|
||||||
|
// Fetch the first page
|
||||||
|
const pageNumber = 1;
|
||||||
|
pdf.getPage(pageNumber).then((page) => {
|
||||||
|
console.log('Page loaded');
|
||||||
|
|
||||||
|
const scale = 10;
|
||||||
|
const viewport = page.getViewport({ scale: scale });
|
||||||
|
|
||||||
|
// Prepare canvas using PDF page dimensions
|
||||||
|
const canvas: any = this.shadowRoot.querySelector('#pdfcanvas');
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
canvas.height = viewport.height;
|
||||||
|
canvas.width = viewport.width;
|
||||||
|
|
||||||
|
// Render PDF page into canvas context
|
||||||
|
const renderContext = {
|
||||||
|
canvasContext: context,
|
||||||
|
viewport: viewport,
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderTask = page.render(renderContext);
|
||||||
|
renderTask.promise.then(function () {
|
||||||
|
console.log('Page rendered');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(reason) => {
|
||||||
|
// PDF loading error
|
||||||
|
console.error(reason);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
0
ts_web/elements/dees-preview.ts
Normal file
0
ts_web/elements/dees-preview.ts
Normal file
11
ts_web/elements/dees-progressbar.demo.ts
Normal file
11
ts_web/elements/dees-progressbar.demo.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import { DeesProgressbar } from './dees-progressbar.js';
|
||||||
|
|
||||||
|
export const demoFunc = () => {
|
||||||
|
return html`
|
||||||
|
<dees-progressbar
|
||||||
|
.percentage=${50}
|
||||||
|
></dees-progressbar>
|
||||||
|
`;
|
||||||
|
}
|
95
ts_web/elements/dees-progressbar.ts
Normal file
95
ts_web/elements/dees-progressbar.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
import * as colors from './00colors.js';
|
||||||
|
import { demoFunc } from './dees-progressbar.demo.js';
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
unsafeCSS,
|
||||||
|
unsafeHTML,
|
||||||
|
state,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
@customElement('dees-progressbar')
|
||||||
|
export class DeesProgressbar extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
@property({
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
public percentage = 0;
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
color: ${cssManager.bdTheme(colors.bright.text, colors.dark.text)};
|
||||||
|
}
|
||||||
|
.progressBarContainer {
|
||||||
|
padding: 8px;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progressBar {
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#444')};
|
||||||
|
height: 8px;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-top: 0.5px solid ${cssManager.bdTheme('none', '#555')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.progressBarFill {
|
||||||
|
background: ${cssManager.bdTheme(colors.dark.blueActive, colors.bright.blueActive)};
|
||||||
|
height: 8px;
|
||||||
|
margin-top: -0.5px;
|
||||||
|
transition: 0.2s width;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 0px;
|
||||||
|
border-top: 0.5 solid ${cssManager.bdTheme('none', '#398fff')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.progressText {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="progressBarContainer">
|
||||||
|
<div class="progressBar">
|
||||||
|
<div class="progressBarFill"></div>
|
||||||
|
<div class="progressText">
|
||||||
|
${this.percentage}%
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated (_changedProperties: Map<string | number | symbol, unknown>): void {
|
||||||
|
super.firstUpdated(_changedProperties);
|
||||||
|
this.updateComplete.then(() => {
|
||||||
|
this.updatePercentage();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updatePercentage() {
|
||||||
|
const progressBarFill = this.shadowRoot.querySelector('.progressBarFill') as HTMLElement;
|
||||||
|
progressBarFill.style.width = `${this.percentage}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(){
|
||||||
|
this.updatePercentage();
|
||||||
|
}
|
||||||
|
}
|
0
ts_web/elements/dees-search.ts
Normal file
0
ts_web/elements/dees-search.ts
Normal file
0
ts_web/elements/dees-searchbox.ts
Normal file
0
ts_web/elements/dees-searchbox.ts
Normal file
5
ts_web/elements/dees-simple-appdash.demo.ts
Normal file
5
ts_web/elements/dees-simple-appdash.demo.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<dees-simple-appdash>Hello there</dees-simple-appdash>
|
||||||
|
`;
|
171
ts_web/elements/dees-simple-appdash.ts
Normal file
171
ts_web/elements/dees-simple-appdash.ts
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import { demoFunc } from './dees-simple-appdash.demo.js';
|
||||||
|
import * as colors from './00colors.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
unsafeCSS,
|
||||||
|
type CSSResult,
|
||||||
|
state,
|
||||||
|
domtools,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import { DeesTerminal } from './dees-terminal.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-simple-appdash': DeesSimpleAppDash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-simple-appdash')
|
||||||
|
export class DeesSimpleAppDash extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = demoFunc;
|
||||||
|
// INSTANCE
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public name = 'Dees Simple Login';
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public views: Array<{ name: string; icon: string; viewFunction: () => Promise<TemplateResult> }> =
|
||||||
|
[];
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
user-select: none;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
height: 32px;
|
||||||
|
width: 100%;
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#222')};
|
||||||
|
border-bottom: 1px solid ${cssManager.bdTheme('#ccc', '#ffffff10')};
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 32px;
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
padding: 0px 16px;
|
||||||
|
z-index: 2;
|
||||||
|
box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.8);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: min-content 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appName {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appActions {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appActions .action {
|
||||||
|
}
|
||||||
|
.appActions .action:hover {
|
||||||
|
color: ${cssManager.bdTheme('#000', '#fff')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.appcontent {
|
||||||
|
z-index: 1;
|
||||||
|
position: fixed;
|
||||||
|
top: 32px;
|
||||||
|
height: calc(100vh - 32px - 24px);
|
||||||
|
bottom: 24px;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#000')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.controlbar {
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 100%;
|
||||||
|
height: 24px;
|
||||||
|
background: ${cssManager.bdTheme(colors.bright.blueMuted, colors.dark.blueMuted)};
|
||||||
|
z-index: 2;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control {
|
||||||
|
width: min-content;
|
||||||
|
margin-right: 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="maincontainer">
|
||||||
|
<div class="appbar">
|
||||||
|
<div class="appName">${this.name}</div>
|
||||||
|
<div class="viewTabs"></div>
|
||||||
|
<div class="appActions">
|
||||||
|
<div class="action">Logout</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="appcontent">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
<div class="controlbar">
|
||||||
|
<div class="control">
|
||||||
|
<dees-icon .iconFA=${'networkWired'}></dees-icon>
|
||||||
|
</div>
|
||||||
|
<div class="control" @click=${this.launchTerminal}>
|
||||||
|
<dees-icon .iconFA=${'terminal'}></dees-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated(_changedProperties): Promise<void> {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
super.firstUpdated(_changedProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async launchTerminal() {
|
||||||
|
const maincontainer = this.shadowRoot.querySelector('.maincontainer');
|
||||||
|
const terminal = new DeesTerminal();
|
||||||
|
maincontainer.appendChild(terminal);
|
||||||
|
terminal.style.position = 'absolute';
|
||||||
|
terminal.style.zIndex = '1';
|
||||||
|
terminal.style.top = '32px';
|
||||||
|
terminal.style.left = '0px';
|
||||||
|
terminal.style.right = '0px';
|
||||||
|
terminal.style.bottom = '24px';
|
||||||
|
terminal.style.opacity = '0';
|
||||||
|
terminal.style.transform = 'translateY(20px)';
|
||||||
|
terminal.style.transition = 'all 0.2s';
|
||||||
|
await domtools.plugins.smartdelay.delayFor(0);
|
||||||
|
terminal.style.opacity = '1';
|
||||||
|
terminal.style.transform = 'translateY(0px)';
|
||||||
|
}
|
||||||
|
}
|
3
ts_web/elements/dees-simple-login.demo.ts
Normal file
3
ts_web/elements/dees-simple-login.demo.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => html` <dees-simple-login name="someapp"> Hello there </dees-simple-login> `;
|
131
ts_web/elements/dees-simple-login.ts
Normal file
131
ts_web/elements/dees-simple-login.ts
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import { demoFunc } from './dees-simple-login.demo.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
unsafeCSS,
|
||||||
|
type CSSResult,
|
||||||
|
state,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-simple-login': DeesSimpleLogin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-simple-login')
|
||||||
|
export class DeesSimpleLogin extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = demoFunc
|
||||||
|
// INSTANCE
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public name = 'Dees Simple Login';
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.loginContainer {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center; /* aligns horizontally */
|
||||||
|
align-items: center; /* aligns vertically */
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slotContainer {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login {
|
||||||
|
min-width: 320px;
|
||||||
|
min-height: 100px;
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#111')};
|
||||||
|
box-shadow: ${cssManager.bdTheme('0px 1px 4px rgba(0,0,0,0.3)', 'none')};
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 24px;
|
||||||
|
transition: opacity 0.3s, transform 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.slotContainer {
|
||||||
|
opacity:0;
|
||||||
|
transition: opacity 0.3s, transform 0.3s;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="loginContainer">
|
||||||
|
<div class="login">
|
||||||
|
<dees-form>
|
||||||
|
<div class="header">Login to ${this.name}</div>
|
||||||
|
<dees-input-text key="username" label="username" required></dees-input-text>
|
||||||
|
<dees-input-text key="password" label="password" isPasswordBool required></dees-input-text>
|
||||||
|
<dees-form-submit disabled>login</dees-form-submit>
|
||||||
|
</dees-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="slotContainer">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated(_changedProperties): Promise<void> {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
super.firstUpdated(_changedProperties);
|
||||||
|
const form = this.shadowRoot.querySelector('dees-form');
|
||||||
|
await form.readyDeferred.promise;
|
||||||
|
const username = this.shadowRoot.querySelector('dees-input-text[label="username"]');
|
||||||
|
const password = this.shadowRoot.querySelector('dees-input-text[label="password"]');
|
||||||
|
const submit = this.shadowRoot.querySelector('dees-form-submit');
|
||||||
|
form.addEventListener('formData', (event: CustomEvent) => {
|
||||||
|
this.dispatchEvent(new CustomEvent('login', { detail: event.detail }));
|
||||||
|
// this.switchToSlottedContent();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* allows switching to slotted content
|
||||||
|
*/
|
||||||
|
public async switchToSlottedContent() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
const loginDiv: HTMLDivElement = this.shadowRoot.querySelector('.login');
|
||||||
|
const loginContainerDiv: HTMLDivElement = this.shadowRoot.querySelector('.loginContainer');
|
||||||
|
const slotContainerDiv: HTMLDivElement = this.shadowRoot.querySelector('.slotContainer');
|
||||||
|
loginDiv.style.opacity = '0';
|
||||||
|
loginDiv.style.transform = 'translateY(20px)';
|
||||||
|
loginContainerDiv.style.pointerEvents = 'none';
|
||||||
|
slotContainerDiv.style.transform = 'translateY(20px)';
|
||||||
|
await domtools.convenience.smartdelay.delayFor(300);
|
||||||
|
slotContainerDiv.style.opacity = '1';
|
||||||
|
slotContainerDiv.style.transform = 'translateY(0px)';
|
||||||
|
await domtools.convenience.smartdelay.delayFor(300);
|
||||||
|
slotContainerDiv.style.pointerEvents = 'all';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
23
ts_web/elements/dees-speechbubble.demo.ts
Normal file
23
ts_web/elements/dees-speechbubble.demo.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { html, cssManager } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = () => {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
.ref1 {
|
||||||
|
margin: 20px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="ref1"></div>
|
||||||
|
<dees-speechbubble .text=${`
|
||||||
|
**This is a longer markdown text that can be used the write**
|
||||||
|
a longer description about whats going on the app
|
||||||
|
|
||||||
|
**This is a subheader**
|
||||||
|
and another text
|
||||||
|
|
||||||
|
`}></dees-speechbubble>
|
||||||
|
`;
|
||||||
|
};
|
229
ts_web/elements/dees-speechbubble.ts
Normal file
229
ts_web/elements/dees-speechbubble.ts
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
import * as colors from './00colors.js';
|
||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
|
||||||
|
import { demoFunc } from './dees-speechbubble.demo.js';
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
unsafeCSS,
|
||||||
|
domtools,
|
||||||
|
directives,
|
||||||
|
unsafeHTML,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import { DeesWindowLayer } from './dees-windowlayer.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-speechbubble': DeesSpeechbubble;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-speechbubble')
|
||||||
|
export class DeesSpeechbubble extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
// STATIC
|
||||||
|
public static async createAndShow(refElement: HTMLElement, textArg: string) {
|
||||||
|
const windowLayer = await DeesWindowLayer.createAndShow({
|
||||||
|
blur: false,
|
||||||
|
});
|
||||||
|
const speechbubble = document.createElement('dees-speechbubble');
|
||||||
|
speechbubble.windowLayer = windowLayer;
|
||||||
|
speechbubble.reffedElement = refElement;
|
||||||
|
speechbubble.text = textArg;
|
||||||
|
speechbubble.manifested = true;
|
||||||
|
windowLayer.appendChild(speechbubble);
|
||||||
|
windowLayer.style.pointerEvents = 'none';
|
||||||
|
(windowLayer.shadowRoot.querySelector('.windowOverlay') as HTMLElement).style.pointerEvents = 'none';
|
||||||
|
return speechbubble;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
@property({
|
||||||
|
type: Object,
|
||||||
|
})
|
||||||
|
reffedElement: HTMLElement;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public text: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public wave: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public manifested = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public status: 'normal' | 'pending' | 'success' | 'error' = 'normal';
|
||||||
|
|
||||||
|
public windowLayer: DeesWindowLayer;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maincontainer {
|
||||||
|
position: relative;
|
||||||
|
will-change: transform;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
transform: translateX(0px);
|
||||||
|
transition: all 0.2s;
|
||||||
|
margin-left: 0px;
|
||||||
|
filter: drop-shadow(0px 0px 2px rgba(0, 0, 0, 0.2));
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
background: ${cssManager.bdTheme('#fff', '#333')};
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
left: 2px;
|
||||||
|
top: 12px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.speechbubble {
|
||||||
|
background: ${cssManager.bdTheme('#fff', '#333')};
|
||||||
|
padding: 0px 16px;
|
||||||
|
border-radius: 3px;
|
||||||
|
position: absolute;
|
||||||
|
min-width: 240px;
|
||||||
|
font-size: 12px;
|
||||||
|
top: 0px;
|
||||||
|
left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wave {
|
||||||
|
animation-name: wave-animation; /* Refers to the name of your @keyframes element below */
|
||||||
|
animation-duration: 2.5s; /* Change to speed up or slow down */
|
||||||
|
animation-iteration-count: infinite; /* Never stop waving :) */
|
||||||
|
transform-origin: 70% 70%; /* Pivot around the bottom-left palm */
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes wave-animation {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
transform: rotate(14deg);
|
||||||
|
} /* The following five values can be played with to make the waving more or less extreme */
|
||||||
|
20% {
|
||||||
|
transform: rotate(-8deg);
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
transform: rotate(14deg);
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: rotate(-4deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(10deg);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
} /* Reset for the last half to pause */
|
||||||
|
100% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${this.manifested
|
||||||
|
? html`
|
||||||
|
<div class="maincontainer" @click=${this.handleClick}>
|
||||||
|
<div class="arrow"></div>
|
||||||
|
<div class="speechbubble">
|
||||||
|
${this.wave ? html`<span class="wave">👋</span>` : html``}
|
||||||
|
${directives.resolve(this.getHtml())}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleClick() {
|
||||||
|
console.log('speechbubble got clicked.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
// lets make sure we have a ref
|
||||||
|
if (!this.reffedElement) {
|
||||||
|
this.reffedElement = this.previousElementSibling as HTMLElement;
|
||||||
|
}
|
||||||
|
if (this.manifested) {
|
||||||
|
await this.updatePosition();
|
||||||
|
(this.shadowRoot.querySelector('.maincontainer') as HTMLElement).style.opacity = '1';
|
||||||
|
} else {
|
||||||
|
// lets make sure we instrument it
|
||||||
|
let speechbubble: DeesSpeechbubble;
|
||||||
|
this.reffedElement.addEventListener('mouseenter', async () => {
|
||||||
|
speechbubble = await DeesSpeechbubble.createAndShow(this.reffedElement, this.text);
|
||||||
|
});
|
||||||
|
this.reffedElement.addEventListener('mouseleave', () => {
|
||||||
|
speechbubble.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updatePosition() {
|
||||||
|
const refElement = this.reffedElement;
|
||||||
|
const boundingClientRect = refElement.getBoundingClientRect();
|
||||||
|
this.style.position = 'fixed';
|
||||||
|
this.style.top = `${boundingClientRect.top - 13}px`;
|
||||||
|
this.style.left = `${boundingClientRect.left + refElement.clientWidth + 4}px`;
|
||||||
|
if (boundingClientRect.right > 250) {
|
||||||
|
this.style.width = `250px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getHtml(): Promise<any> {
|
||||||
|
if (!this.text) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const normalized = domtools.plugins.smartstring.normalize.standard(this.text);
|
||||||
|
const result = await domtools.plugins.smartmarkdown.SmartMarkdown.easyMarkdownToHtml(
|
||||||
|
normalized
|
||||||
|
);
|
||||||
|
return unsafeHTML(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async show() {}
|
||||||
|
|
||||||
|
public async destroy() {
|
||||||
|
(this.shadowRoot.querySelector('.maincontainer') as HTMLElement).style.opacity = '0';
|
||||||
|
this.windowLayer.destroy();
|
||||||
|
}
|
||||||
|
}
|
131
ts_web/elements/dees-spinner.ts
Normal file
131
ts_web/elements/dees-spinner.ts
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
type CSSResult,
|
||||||
|
unsafeCSS,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-spinner': DeesSpinner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-spinner')
|
||||||
|
export class DeesSpinner extends DeesElement {
|
||||||
|
public static demo = () => html`
|
||||||
|
<dees-spinner></dees-spinner>
|
||||||
|
<dees-spinner status="success"></dees-spinner>
|
||||||
|
<dees-spinner status="error"></dees-spinner>
|
||||||
|
<dees-spinner size=${64} status="success"></dees-spinner>
|
||||||
|
<dees-spinner .size=${64} status="error"></dees-spinner>
|
||||||
|
`;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
public size = 20;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public bnw: boolean = false;
|
||||||
|
|
||||||
|
@property()
|
||||||
|
public status: 'normal' | 'pending' | 'success' | 'error' = 'normal';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loading {
|
||||||
|
position: relative;
|
||||||
|
transition: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
background: #8bc34a00;
|
||||||
|
border: 3px solid ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(255, 255, 255, 0.3)')};
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top-color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
animation: spin 1s ease-in-out infinite;
|
||||||
|
-webkit-animation: spin 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loading.success {
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: none;
|
||||||
|
-webkit-animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loading.error {
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: none;
|
||||||
|
-webkit-animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dees-icon {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
#loading {
|
||||||
|
width: ${this.size}px;
|
||||||
|
height: ${this.size}px;
|
||||||
|
}
|
||||||
|
#loading.success {
|
||||||
|
color: ${cssManager.bdTheme(this.bnw ? '#333': `#8bc34a`, this.bnw ? '#fff' : `#8bc34a`)};
|
||||||
|
|
||||||
|
}
|
||||||
|
#loading.error {
|
||||||
|
color: ${cssManager.bdTheme(this.bnw ? '#333': `#e64a19`, this.bnw ? '#fff' : `#e64a19`)};
|
||||||
|
}
|
||||||
|
dees-icon {
|
||||||
|
font-size: ${this.size}px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="${this.status}" id="loading">
|
||||||
|
${(() => {
|
||||||
|
if (this.status === 'success') {
|
||||||
|
return html`<dees-icon style="transform: translateX(1%) translateY(3%);" .iconFA=${'circleCheck' as any}></dees-icon>`;
|
||||||
|
} else if (this.status === 'error') {
|
||||||
|
return html`<dees-icon .iconFA=${'circleXmark' as any}></dees-icon>`;
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
282
ts_web/elements/dees-stepper.ts
Normal file
282
ts_web/elements/dees-stepper.ts
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
import * as colors from './00colors.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
unsafeCSS,
|
||||||
|
type CSSResult,
|
||||||
|
cssManager,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
export interface IStep {
|
||||||
|
title: string;
|
||||||
|
content: TemplateResult;
|
||||||
|
validationFunc?: (stepper: DeesStepper, htmlElement: HTMLElement) => Promise<any>;
|
||||||
|
onReturnToStepFunc?: (stepper: DeesStepper, htmlElement: HTMLElement) => Promise<any>;
|
||||||
|
validationFuncCalled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-stepper': DeesStepper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-stepper')
|
||||||
|
export class DeesStepper extends DeesElement {
|
||||||
|
public static demo = () =>
|
||||||
|
html`
|
||||||
|
<dees-stepper
|
||||||
|
.steps=${[
|
||||||
|
{
|
||||||
|
title: 'Whats your name?',
|
||||||
|
content: html`
|
||||||
|
<dees-form>
|
||||||
|
<dees-input-text
|
||||||
|
key="email"
|
||||||
|
label="Your Email"
|
||||||
|
value="hello@something.com"
|
||||||
|
disabled
|
||||||
|
></dees-input-text>
|
||||||
|
<dees-input-text key="firstName" required label="Vorname"></dees-input-text>
|
||||||
|
<dees-input-text key="lastName" required label="Nachname"></dees-input-text>
|
||||||
|
<dees-form-submit>Next</dees-form-submit>
|
||||||
|
</dees-form>
|
||||||
|
`,
|
||||||
|
validationFunc: async (stepperArg, elementArg) => {
|
||||||
|
const deesForm = elementArg.querySelector('dees-form');
|
||||||
|
deesForm.addEventListener('formData', (eventArg) => {
|
||||||
|
stepperArg.goNext();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Whats your mobile number?',
|
||||||
|
content: html``,
|
||||||
|
},
|
||||||
|
] as IStep[]}
|
||||||
|
></dees-stepper>
|
||||||
|
`;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
public steps: IStep[] = [];
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Object,
|
||||||
|
})
|
||||||
|
public selectedStep: IStep;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.stepperContainer {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#000')};
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step {
|
||||||
|
position: relative;
|
||||||
|
pointer-events: none;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.7s ease-in-out;
|
||||||
|
max-width: 500px;
|
||||||
|
min-height: 300px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: ${cssManager.bdTheme('#ffffff', '#181818')};
|
||||||
|
border-top: 1px solid ${cssManager.bdTheme('#ffffff', '#181818')};
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
margin: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
filter: opacity(0.5) grayscale(1);
|
||||||
|
box-shadow: 0px 0px 3px #00000010;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step.selected {
|
||||||
|
border-top: 1px solid #e4002b;
|
||||||
|
pointer-events: all;
|
||||||
|
filter: opacity(1) grayscale(0);
|
||||||
|
box-shadow: 0px 0px 5px #00000010;
|
||||||
|
user-select: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step.hiddenStep {
|
||||||
|
filter: opacity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step:last-child {
|
||||||
|
margin-bottom: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step .stepCounter {
|
||||||
|
color: #999;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom-left-radius: 3px;
|
||||||
|
background: ${cssManager.bdTheme('#00000008', '#ffffff08')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.step .goBack {
|
||||||
|
color: #999;
|
||||||
|
cursor: default;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
background: ${cssManager.bdTheme('#00000008', '#ffffff08')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.step .goBack:hover {
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
background: ${cssManager.bdTheme('#00000012', colors.dark.blue)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.step .goBack:active {
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
background: ${cssManager.bdTheme('#00000012', colors.dark.blueActive)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.step .goBack span {
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step .goBack:hover span {
|
||||||
|
transform: translateX(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step .title {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 50px;
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
font-size: 25px;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step .content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="stepperContainer">
|
||||||
|
${this.steps.map(
|
||||||
|
(stepArg) =>
|
||||||
|
html`<div
|
||||||
|
class="step ${stepArg === this.selectedStep
|
||||||
|
? 'selected'
|
||||||
|
: null} ${this.getIndexOfStep(stepArg) > this.getIndexOfStep(this.selectedStep)
|
||||||
|
? 'hiddenStep'
|
||||||
|
: ''}"
|
||||||
|
>
|
||||||
|
${this.getIndexOfStep(stepArg) > 0
|
||||||
|
? html`<div class="goBack" @click=${this.goBack}><span style="font-family: Inter"><-</span> go to previous step</div>`
|
||||||
|
: ``}
|
||||||
|
<div class="stepCounter">
|
||||||
|
Step ${this.steps.findIndex((elementArg) => elementArg === stepArg) + 1} of
|
||||||
|
${this.steps.length}
|
||||||
|
</div>
|
||||||
|
<div class="title">${stepArg.title}</div>
|
||||||
|
<div class="content">${stepArg.content}</div>
|
||||||
|
</div> `
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getIndexOfStep = (stepArg: IStep): number => {
|
||||||
|
return this.steps.findIndex((stepArg2) => stepArg === stepArg2);
|
||||||
|
};
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
await this.domtoolsPromise;
|
||||||
|
await this.domtools.convenience.smartdelay.delayFor(0);
|
||||||
|
this.selectedStep = this.steps[0];
|
||||||
|
this.setScrollStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updated() {
|
||||||
|
this.setScrollStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public scroller: typeof domtools.plugins.SweetScroll.prototype;
|
||||||
|
|
||||||
|
public async setScrollStatus() {
|
||||||
|
const stepperContainer: HTMLElement = this.shadowRoot.querySelector('.stepperContainer');
|
||||||
|
const firstStepElement: HTMLElement = this.shadowRoot.querySelector('.step');
|
||||||
|
const selectedStepElement: HTMLElement = this.shadowRoot.querySelector('.selected');
|
||||||
|
if (!selectedStepElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!stepperContainer.style.paddingTop) {
|
||||||
|
stepperContainer.style.paddingTop = `${
|
||||||
|
stepperContainer.offsetHeight / 2 - selectedStepElement.offsetHeight / 2
|
||||||
|
}px`;
|
||||||
|
}
|
||||||
|
console.log('Setting scroll status');
|
||||||
|
console.log(selectedStepElement);
|
||||||
|
const scrollPosition =
|
||||||
|
selectedStepElement.offsetTop -
|
||||||
|
stepperContainer.offsetHeight / 2 +
|
||||||
|
selectedStepElement.offsetHeight / 2;
|
||||||
|
console.log(scrollPosition);
|
||||||
|
const domtoolsInstance = await domtools.DomTools.setupDomTools();
|
||||||
|
if (!this.scroller) {
|
||||||
|
this.scroller = new domtools.plugins.SweetScroll(
|
||||||
|
{
|
||||||
|
vertical: true,
|
||||||
|
horizontal: false,
|
||||||
|
easing: 'easeInOutExpo',
|
||||||
|
duration: 700,
|
||||||
|
},
|
||||||
|
stepperContainer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!this.selectedStep.validationFuncCalled && this.selectedStep.validationFunc) {
|
||||||
|
this.selectedStep.validationFuncCalled = true;
|
||||||
|
await this.selectedStep.validationFunc(this, selectedStepElement);
|
||||||
|
}
|
||||||
|
this.scroller.to(scrollPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async goBack() {
|
||||||
|
const currentIndex = this.steps.findIndex((stepArg) => stepArg === this.selectedStep);
|
||||||
|
this.selectedStep = this.steps[currentIndex - 1];
|
||||||
|
await this.domtoolsPromise;
|
||||||
|
await this.domtools.convenience.smartdelay.delayFor(100);
|
||||||
|
this.selectedStep.onReturnToStepFunc?.(this, this.shadowRoot.querySelector('.selected'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public goNext() {
|
||||||
|
const currentIndex = this.steps.findIndex((stepArg) => stepArg === this.selectedStep);
|
||||||
|
this.selectedStep = this.steps[currentIndex + 1];
|
||||||
|
}
|
||||||
|
}
|
129
ts_web/elements/dees-table.demo.ts
Normal file
129
ts_web/elements/dees-table.demo.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import { type ITableAction } from './dees-table.js';
|
||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
interface ITableDemoData {
|
||||||
|
date: string;
|
||||||
|
amount: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const demoFunc = () => html`
|
||||||
|
<style>
|
||||||
|
.demoWrapper {
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
background: #000000;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="demoWrapper">
|
||||||
|
<dees-table
|
||||||
|
heading1="Current Account Statement"
|
||||||
|
heading2="Bunq - Payment Account 2 - April 2021"
|
||||||
|
.editableFields="${['description']}"
|
||||||
|
.data=${[
|
||||||
|
{
|
||||||
|
date: '2021-04-01',
|
||||||
|
amount: '2464.65 €',
|
||||||
|
description: 'Printing Paper (Office Supplies) - STAPLES BREMEN',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2021-04-02',
|
||||||
|
amount: '165.65 €',
|
||||||
|
description: 'Logitech Mouse (Hardware) - logi.com OnlineShop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2021-04-03',
|
||||||
|
amount: '2999,00 €',
|
||||||
|
description: 'Macbook Pro 16inch (Hardware) - Apple.de OnlineShop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2021-04-01',
|
||||||
|
amount: '2464.65 €',
|
||||||
|
description: 'Office-Supplies - STAPLES BREMEN',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: '2021-04-01',
|
||||||
|
amount: '2464.65 €',
|
||||||
|
description: 'Office-Supplies - STAPLES BREMEN',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
dataName="transactions"
|
||||||
|
.dataActions="${[
|
||||||
|
{
|
||||||
|
name: 'upload',
|
||||||
|
iconName: 'bell',
|
||||||
|
useTableBehaviour: 'upload',
|
||||||
|
type: ['inRow'],
|
||||||
|
actionFunc: async (optionsArg) => {
|
||||||
|
alert(optionsArg.item.amount);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'visibility',
|
||||||
|
iconName: 'copy',
|
||||||
|
type: ['inRow'],
|
||||||
|
useTableBehaviour: 'preview',
|
||||||
|
actionFunc: async (itemArg: any) => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'create new',
|
||||||
|
iconName: 'instagram',
|
||||||
|
type: ['header'],
|
||||||
|
useTableBehaviour: 'preview',
|
||||||
|
actionFunc: async (itemArg: any) => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'to gallery',
|
||||||
|
iconName: 'message',
|
||||||
|
type: ['footer'],
|
||||||
|
useTableBehaviour: 'preview',
|
||||||
|
actionFunc: async (itemArg: any) => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'copy',
|
||||||
|
iconName: 'copySolid',
|
||||||
|
type: ['contextmenu', 'inRow'],
|
||||||
|
action: async () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'edit (from demo)',
|
||||||
|
iconName: 'penToSquare',
|
||||||
|
type: ['contextmenu'],
|
||||||
|
action: async () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'paste',
|
||||||
|
iconName: 'pasteSolid',
|
||||||
|
type: ['contextmenu'],
|
||||||
|
action: async () => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'preview',
|
||||||
|
type: ['doubleClick', 'contextmenu'],
|
||||||
|
iconName: 'eye',
|
||||||
|
actionFunc: async (itemArg) => {
|
||||||
|
alert(itemArg.item.amount);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
] as (ITableAction<ITableDemoData>)[] as any}"
|
||||||
|
.displayFunction=${(itemArg) => {
|
||||||
|
return {
|
||||||
|
...itemArg,
|
||||||
|
onlyDisplayProp: 'onlyDisplay',
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
>This is a slotted Text</dees-table
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
`;
|
784
ts_web/elements/dees-table.ts
Normal file
784
ts_web/elements/dees-table.ts
Normal file
@ -0,0 +1,784 @@
|
|||||||
|
import * as colors from './00colors.js';
|
||||||
|
import * as plugins from './00plugins.js';
|
||||||
|
import { demoFunc } from './dees-table.demo.js';
|
||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
type TemplateResult,
|
||||||
|
cssManager,
|
||||||
|
css,
|
||||||
|
unsafeCSS,
|
||||||
|
type CSSResult,
|
||||||
|
state,
|
||||||
|
resolveExec,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import { DeesContextmenu } from './dees-contextmenu.js';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { type TIconKey } from './dees-icon.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-table': DeesTable<any>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// interfaces
|
||||||
|
export interface ITableAction<T = any> {
|
||||||
|
name: string;
|
||||||
|
iconName: TIconKey;
|
||||||
|
/**
|
||||||
|
* the table behaviour to use for this action
|
||||||
|
* e.g. upload: allows to upload files to the table
|
||||||
|
*/
|
||||||
|
useTableBehaviour?: 'upload' | 'cancelUpload' | 'none';
|
||||||
|
/**
|
||||||
|
* the type of the action
|
||||||
|
*/
|
||||||
|
type: (
|
||||||
|
| 'inRow'
|
||||||
|
| 'contextmenu'
|
||||||
|
| 'doubleClick'
|
||||||
|
| 'footer'
|
||||||
|
| 'header'
|
||||||
|
| 'preview'
|
||||||
|
| 'keyCombination'
|
||||||
|
)[];
|
||||||
|
/**
|
||||||
|
* allows to check if the action is relevant for the given item
|
||||||
|
* @param itemArg
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
actionRelevancyCheckFunc?: (itemArg: T) => boolean;
|
||||||
|
/**
|
||||||
|
* the actual action function implementation
|
||||||
|
* @param itemArg
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
actionFunc: (actionDataArg: ITableActionDataArg<T>) => Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITableActionDataArg<T> {
|
||||||
|
item: T;
|
||||||
|
table: DeesTable<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TDisplayFunction<T = any> = (itemArg: T) => object;
|
||||||
|
|
||||||
|
// the table implementation
|
||||||
|
@customElement('dees-table')
|
||||||
|
export class DeesTable<T> extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public heading1: string = 'heading 1';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public heading2: string = 'heading 2';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
public data: T[] = [];
|
||||||
|
|
||||||
|
// dees-form compatibility -----------------------------------------
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public key: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
public label: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public disabled: boolean = false;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
public required: boolean = false;
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
set value(valueArg) {}
|
||||||
|
public changeSubject = new domtools.plugins.smartrx.rxjs.Subject<DeesTable<T>>();
|
||||||
|
// end dees-form compatibility -----------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What does a row of data represent?
|
||||||
|
*/
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public dataName: string;
|
||||||
|
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
searchable: boolean = true;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
public dataActions: ITableAction<T>[] = [];
|
||||||
|
|
||||||
|
@property({
|
||||||
|
attribute: false,
|
||||||
|
})
|
||||||
|
public displayFunction: TDisplayFunction = (itemArg: T) => itemArg as any;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
attribute: false,
|
||||||
|
})
|
||||||
|
public reverseDisplayFunction: (itemArg: any) => T = (itemArg: any) => itemArg as T;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Object,
|
||||||
|
})
|
||||||
|
public selectedDataRow: T;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Array,
|
||||||
|
})
|
||||||
|
public editableFields: string[] = [];
|
||||||
|
|
||||||
|
public files: File[] = [];
|
||||||
|
public fileWeakMap = new WeakMap();
|
||||||
|
|
||||||
|
public dataChangeSubject = new domtools.plugins.smartrx.rxjs.Subject();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
.mainbox {
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 16px;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 50px;
|
||||||
|
background: ${cssManager.bdTheme('#ffffff', '#222222')};
|
||||||
|
border-radius: 3px;
|
||||||
|
border-top: 1px solid ${cssManager.bdTheme('#fff', '#ffffff10')};
|
||||||
|
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3);
|
||||||
|
overflow-x: auto;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headingContainer {
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading1 {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.heading2 {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headingSeparation {
|
||||||
|
margin-top: 7px;
|
||||||
|
border-bottom: 1px solid ${cssManager.bdTheme('#bcbcbc', '#444444')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerActions {
|
||||||
|
user-select: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.headerAction {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerAction:hover {
|
||||||
|
color: ${cssManager.bdTheme('#555', '#fff')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerAction dees-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchGrid {
|
||||||
|
background: ${cssManager.bdTheme('#fff', '#111111')};
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 16px;
|
||||||
|
grid-template-columns: 1fr 200px;
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 0px 16px;
|
||||||
|
border-top: 1px solid ${cssManager.bdTheme('#fff', '#ffffff20')};
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchGrid.hidden {
|
||||||
|
height: 0px;
|
||||||
|
opacity: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table,
|
||||||
|
.noDataSet {
|
||||||
|
margin-top: 16px;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.noDataSet {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
border-bottom: 1px dashed ${cssManager.bdTheme('#999', '#808080')};
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
tr:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
tr:hover {
|
||||||
|
}
|
||||||
|
tr:hover td {
|
||||||
|
background: ${cssManager.bdTheme('#22222210', '#ffffff10')};
|
||||||
|
}
|
||||||
|
tr:first-child:hover {
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
tr:first-child:hover .innerCellContainer {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
tr.selected td {
|
||||||
|
background: ${cssManager.bdTheme('#22222220', '#ffffff20')};
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.hasAttachment td {
|
||||||
|
background: ${cssManager.bdTheme('#0098847c', '#0098847c')};
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-transform: none;
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
position: relative;
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
|
padding: 0px;
|
||||||
|
border-right: 1px dashed ${cssManager.bdTheme('#999', '#808080')};
|
||||||
|
}
|
||||||
|
.innerCellContainer {
|
||||||
|
min-height: 36px;
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 6px 8px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
th:first-child .innerCellContainer,
|
||||||
|
td:first-child .innerCellContainer {
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
th:last-child .innerCellContainer,
|
||||||
|
td:last-child .innerCellContainer {
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
th:last-child,
|
||||||
|
td:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
td input {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
outline: none;
|
||||||
|
border: 2px solid #fa6101;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0px;
|
||||||
|
left: 0px;
|
||||||
|
position: absolute;
|
||||||
|
background: #fa610140;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
padding: 0px 6px;
|
||||||
|
}
|
||||||
|
.actionsContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
height: 24px;
|
||||||
|
transform: translateY(-4px);
|
||||||
|
margin-left: -6px;
|
||||||
|
}
|
||||||
|
.action {
|
||||||
|
position: relative;
|
||||||
|
padding: 8px 10px;
|
||||||
|
line-height: 24px;
|
||||||
|
height: 32px;
|
||||||
|
size: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action:hover {
|
||||||
|
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.action:active {
|
||||||
|
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blueActive)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.action:hover dees-icon {
|
||||||
|
filter: ${cssManager.bdTheme('invert(1) brightness(3)', '')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
font-family: 'Roboto', 'Inter', sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
color: ${cssManager.bdTheme('#111', '#ffffff90')};
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#00000050')};
|
||||||
|
margin: 16px -16px -16px -16px;
|
||||||
|
border-bottom-left-radius: 3px;
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableStatistics {
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerActions {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerActions .footerAction {
|
||||||
|
padding: 8px 16px;
|
||||||
|
display: flex;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerActions .footerAction:hover {
|
||||||
|
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerActions .footerAction dees-icon {
|
||||||
|
display: flex;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerActions .footerAction:hover dees-icon {
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="mainbox">
|
||||||
|
<!-- the heading part -->
|
||||||
|
<div class="header">
|
||||||
|
<div class="headingContainer">
|
||||||
|
<div class="heading heading1">${this.label || this.heading1}</div>
|
||||||
|
<div class="heading heading2">${this.heading2}</div>
|
||||||
|
</div>
|
||||||
|
<div class="headerActions">
|
||||||
|
${resolveExec(async () => {
|
||||||
|
const resultArray: TemplateResult[] = [];
|
||||||
|
for (const action of this.dataActions) {
|
||||||
|
if (!action.type.includes('header')) continue;
|
||||||
|
resultArray.push(
|
||||||
|
html`<div
|
||||||
|
class="headerAction"
|
||||||
|
@click=${() => {
|
||||||
|
action.actionFunc({
|
||||||
|
item: this.selectedDataRow,
|
||||||
|
table: this,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${action.iconName
|
||||||
|
? html`<dees-icon .iconSize=${14} .iconFA=${action.iconName}></dees-icon>
|
||||||
|
${action.name}`
|
||||||
|
: action.name}
|
||||||
|
</div>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return resultArray;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="headingSeparation"></div>
|
||||||
|
<div class="searchGrid hidden">
|
||||||
|
<dees-input-text
|
||||||
|
.label=${'lucene syntax search'}
|
||||||
|
.description=${`
|
||||||
|
You can use the lucene syntax to search for data, e.g.:
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
name: "john" AND age: 18
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
`}
|
||||||
|
></dees-input-text>
|
||||||
|
<dees-input-multitoggle
|
||||||
|
.label=${'search mode'}
|
||||||
|
.options=${['table', 'data', 'server']}
|
||||||
|
.selectedOption=${'table'}
|
||||||
|
.description=${`
|
||||||
|
There are three basic modes:
|
||||||
|
|
||||||
|
* table: only searches data already in the table
|
||||||
|
* data: searches original data, ignoring table transforms
|
||||||
|
* server: searches data on the server
|
||||||
|
|
||||||
|
`}
|
||||||
|
></dees-input-multitoggle>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- the actual table -->
|
||||||
|
<style></style>
|
||||||
|
${this.data.length > 0
|
||||||
|
? (() => {
|
||||||
|
// Only pick up the keys from the first transformed data object
|
||||||
|
// as all data objects are assumed to have the same structure
|
||||||
|
const firstTransformedItem = this.displayFunction(this.data[0]);
|
||||||
|
const headings: string[] = Object.keys(firstTransformedItem);
|
||||||
|
return html`
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
${headings.map(
|
||||||
|
(headingArg) => html`
|
||||||
|
<th>
|
||||||
|
<div class="innerCellContainer">${headingArg}</div>
|
||||||
|
</th>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
${(() => {
|
||||||
|
if (this.dataActions && this.dataActions.length > 0) {
|
||||||
|
return html`
|
||||||
|
<th>
|
||||||
|
<div class="innerCellContainer">Actions</div>
|
||||||
|
</th>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
</tr>
|
||||||
|
${this.data.map((itemArg) => {
|
||||||
|
const transformedItem = this.displayFunction(itemArg);
|
||||||
|
const getTr = (elementArg: HTMLElement): HTMLElement => {
|
||||||
|
if (elementArg.tagName === 'TR') {
|
||||||
|
return elementArg;
|
||||||
|
} else {
|
||||||
|
return getTr(elementArg.parentElement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return html`
|
||||||
|
<tr
|
||||||
|
@click=${() => {
|
||||||
|
this.selectedDataRow = itemArg;
|
||||||
|
}}
|
||||||
|
@dragenter=${async (eventArg: DragEvent) => {
|
||||||
|
eventArg.preventDefault();
|
||||||
|
eventArg.stopPropagation();
|
||||||
|
const realTarget = getTr(eventArg.target as HTMLElement);
|
||||||
|
console.log('dragenter');
|
||||||
|
console.log(realTarget);
|
||||||
|
setTimeout(() => {
|
||||||
|
realTarget.classList.add('hasAttachment');
|
||||||
|
}, 0);
|
||||||
|
}}
|
||||||
|
@dragleave=${async (eventArg: DragEvent) => {
|
||||||
|
eventArg.preventDefault();
|
||||||
|
eventArg.stopPropagation();
|
||||||
|
const realTarget = getTr(eventArg.target as HTMLElement);
|
||||||
|
realTarget.classList.remove('hasAttachment');
|
||||||
|
}}
|
||||||
|
@dragover=${async (eventArg: DragEvent) => {
|
||||||
|
eventArg.preventDefault();
|
||||||
|
}}
|
||||||
|
@drop=${async (eventArg: DragEvent) => {
|
||||||
|
eventArg.preventDefault();
|
||||||
|
const newFiles = [];
|
||||||
|
for (const file of Array.from(eventArg.dataTransfer.files)) {
|
||||||
|
this.files.push(file);
|
||||||
|
newFiles.push(file);
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
const result: File[] = this.fileWeakMap.get(itemArg as object);
|
||||||
|
if (!result) {
|
||||||
|
this.fileWeakMap.set(itemArg as object, newFiles);
|
||||||
|
} else {
|
||||||
|
result.push(...newFiles);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
@contextmenu=${async (eventArg: MouseEvent) => {
|
||||||
|
DeesContextmenu.openContextMenuWithOptions(
|
||||||
|
eventArg,
|
||||||
|
this.getActionsForType('contextmenu').map((action) => {
|
||||||
|
const menuItem: plugins.tsclass.website.IMenuItem = {
|
||||||
|
name: action.name,
|
||||||
|
iconName: action.iconName as any,
|
||||||
|
action: async () => {
|
||||||
|
await action.actionFunc({
|
||||||
|
item: itemArg,
|
||||||
|
table: this,
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return menuItem;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
class="${itemArg === this.selectedDataRow ? 'selected' : ''}"
|
||||||
|
>
|
||||||
|
${headings.map(
|
||||||
|
(headingArg) => html`
|
||||||
|
<td
|
||||||
|
@dblclick=${(e: Event) => {
|
||||||
|
if (this.editableFields.includes(headingArg)) {
|
||||||
|
this.handleCellEditing(e, itemArg, headingArg);
|
||||||
|
} else {
|
||||||
|
const wantedAction = this.dataActions.find((actionArg) =>
|
||||||
|
actionArg.type.includes('doubleClick')
|
||||||
|
);
|
||||||
|
if (wantedAction) {
|
||||||
|
wantedAction.actionFunc({
|
||||||
|
item: itemArg,
|
||||||
|
table: this,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="innerCellContainer">${transformedItem[headingArg]}</div>
|
||||||
|
</td>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
${(() => {
|
||||||
|
if (this.dataActions && this.dataActions.length > 0) {
|
||||||
|
return html`
|
||||||
|
<td>
|
||||||
|
<div class="innerCellContainer">
|
||||||
|
<div class="actionsContainer">
|
||||||
|
${this.getActionsForType('inRow').map(
|
||||||
|
(actionArg) => html`
|
||||||
|
<div
|
||||||
|
class="action"
|
||||||
|
@click=${() =>
|
||||||
|
actionArg.actionFunc({
|
||||||
|
item: itemArg,
|
||||||
|
table: this,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
${actionArg.iconName
|
||||||
|
? html`
|
||||||
|
<dees-icon
|
||||||
|
.iconFA=${actionArg.iconName}
|
||||||
|
></dees-icon>
|
||||||
|
`
|
||||||
|
: actionArg.name}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</table>
|
||||||
|
`;
|
||||||
|
})()
|
||||||
|
: html` <div class="noDataSet">No data set!</div> `}
|
||||||
|
<div class="footer">
|
||||||
|
<div class="tableStatistics">
|
||||||
|
${this.data.length} ${this.dataName || 'data rows'} (total) |
|
||||||
|
${this.selectedDataRow ? '# ' + `${this.data.indexOf(this.selectedDataRow) + 1}` : `No`}
|
||||||
|
selected
|
||||||
|
</div>
|
||||||
|
<div class="footerActions">
|
||||||
|
${resolveExec(async () => {
|
||||||
|
const resultArray: TemplateResult[] = [];
|
||||||
|
for (const action of this.dataActions) {
|
||||||
|
if (!action.type.includes('footer')) continue;
|
||||||
|
resultArray.push(
|
||||||
|
html`<div
|
||||||
|
class="footerAction"
|
||||||
|
@click=${() => {
|
||||||
|
action.actionFunc({
|
||||||
|
item: this.selectedDataRow,
|
||||||
|
table: this,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${action.iconName
|
||||||
|
? html`<dees-icon .iconSize=${14} .iconFA=${action.iconName}></dees-icon>
|
||||||
|
${action.name}`
|
||||||
|
: action.name}
|
||||||
|
</div>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return resultArray;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async firstUpdated() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updated(changedProperties: Map<string | number | symbol, unknown>): Promise<void> {
|
||||||
|
super.updated(changedProperties);
|
||||||
|
this.determineColumnWidths();
|
||||||
|
if (this.searchable) {
|
||||||
|
const existing = this.dataActions.find((actionArg) => actionArg.type.includes('header') && actionArg.name === 'Search');
|
||||||
|
if (!existing) {
|
||||||
|
this.dataActions.unshift({
|
||||||
|
name: 'Search',
|
||||||
|
iconName: 'magnifyingGlass',
|
||||||
|
type: ['header'],
|
||||||
|
actionFunc: async () => {
|
||||||
|
console.log('open search');
|
||||||
|
const searchGrid = this.shadowRoot.querySelector('.searchGrid');
|
||||||
|
searchGrid.classList.toggle('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(this.dataActions);
|
||||||
|
this.requestUpdate();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async determineColumnWidths() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
await domtools.convenience.smartdelay.delayFor(0);
|
||||||
|
// Get the table element
|
||||||
|
const table = this.shadowRoot.querySelector('table');
|
||||||
|
if (!table) return;
|
||||||
|
|
||||||
|
// Get the first row's cells to measure the widths
|
||||||
|
const cells = table.rows[0].cells;
|
||||||
|
|
||||||
|
const handleColumnByIndex = async (i: number, waitForRenderArg: boolean = false) => {
|
||||||
|
const done = plugins.smartpromise.defer();
|
||||||
|
const cell = cells[i];
|
||||||
|
|
||||||
|
// Get computed width
|
||||||
|
const width = window.getComputedStyle(cell).width;
|
||||||
|
if (cell.textContent.includes('Actions')) {
|
||||||
|
const neededWidth =
|
||||||
|
this.dataActions.filter((actionArg) => actionArg.type.includes('inRow')).length * 36;
|
||||||
|
cell.style.width = `${Math.max(neededWidth, 68)}px`;
|
||||||
|
} else {
|
||||||
|
cell.style.width = width;
|
||||||
|
}
|
||||||
|
if (waitForRenderArg) {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
done.resolve();
|
||||||
|
});
|
||||||
|
await done.promise;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cells[cells.length - 1].textContent.includes('Actions')) {
|
||||||
|
await handleColumnByIndex(cells.length - 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < cells.length; i++) {
|
||||||
|
if (cells[i].textContent.includes('Actions')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
await handleColumnByIndex(i);
|
||||||
|
}
|
||||||
|
table.style.tableLayout = 'fixed';
|
||||||
|
}
|
||||||
|
|
||||||
|
getActionsForType(typeArg: ITableAction['type'][0]) {
|
||||||
|
const actions: ITableAction[] = [];
|
||||||
|
for (const action of this.dataActions) {
|
||||||
|
if (!action.type.includes(typeArg)) continue;
|
||||||
|
actions.push(action);
|
||||||
|
}
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleCellEditing(event: Event, itemArg: T, key: string) {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
const target = event.target as HTMLElement;
|
||||||
|
const originalColor = target.style.color;
|
||||||
|
target.style.color = 'transparent';
|
||||||
|
const transformedItem = this.displayFunction(itemArg);
|
||||||
|
const initialValue = (transformedItem[key] as unknown as string) || '';
|
||||||
|
// Create an input element
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'text';
|
||||||
|
input.value = initialValue;
|
||||||
|
|
||||||
|
const blurInput = async (blurArg = true, saveArg = false) => {
|
||||||
|
if (blurArg) {
|
||||||
|
input.blur();
|
||||||
|
}
|
||||||
|
if (saveArg) {
|
||||||
|
itemArg[key] = input.value as any; // Convert string to T (you might need better type casting depending on your data structure)
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
}
|
||||||
|
input.remove();
|
||||||
|
target.style.color = originalColor;
|
||||||
|
this.requestUpdate();
|
||||||
|
};
|
||||||
|
|
||||||
|
// When the input loses focus or the Enter key is pressed, update the data
|
||||||
|
input.addEventListener('blur', () => {
|
||||||
|
blurInput(false, false);
|
||||||
|
});
|
||||||
|
input.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
blurInput(true, true); // This will trigger the blur event handler above
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Replace the cell's content with the input
|
||||||
|
target.appendChild(input);
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
|
}
|
298
ts_web/elements/dees-terminal.ts
Normal file
298
ts_web/elements/dees-terminal.ts
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
import {
|
||||||
|
DeesElement,
|
||||||
|
property,
|
||||||
|
html,
|
||||||
|
customElement,
|
||||||
|
type TemplateResult,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
|
||||||
|
import * as webcontainer from '@webcontainer/api';
|
||||||
|
|
||||||
|
import { Terminal } from 'xterm';
|
||||||
|
import { FitAddon } from 'xterm-addon-fit';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-terminal': DeesTerminal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-terminal')
|
||||||
|
export class DeesTerminal extends DeesElement {
|
||||||
|
public static demo = () => html` <dees-terminal></dees-terminal> `;
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
private resizeObserver: ResizeObserver;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.resizeObserver = new ResizeObserver((entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
// Handle the resize event
|
||||||
|
console.log(`Terminal Resized`);
|
||||||
|
this.handleResize();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
domtools.elementBasic.staticStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
padding: 20px;
|
||||||
|
background: #000;
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
position: absolute;
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
width: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||||
|
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||||
|
* https://github.com/chjj/term.js
|
||||||
|
* @license MIT
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Originally forked from (with the author's permission):
|
||||||
|
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||||
|
* http://bellard.org/jslinux/
|
||||||
|
* Copyright (c) 2011 Fabrice Bellard
|
||||||
|
* The original design remains. The terminal itself
|
||||||
|
* has been extended to include xterm CSI codes, among
|
||||||
|
* other features.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default styles for xterm.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
.xterm {
|
||||||
|
font-feature-settings: 'liga' 0;
|
||||||
|
position: relative;
|
||||||
|
user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm.focus,
|
||||||
|
.xterm:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-helpers {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
/**
|
||||||
|
* The z-index of the helpers must be higher than the canvases in order for
|
||||||
|
* IMEs to appear on top.
|
||||||
|
*/
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-helper-textarea {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
left: -9999em;
|
||||||
|
top: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
z-index: -5;
|
||||||
|
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .composition-view {
|
||||||
|
/* TODO: Composition position got messed up somewhere */
|
||||||
|
background: #000;
|
||||||
|
color: #fff;
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
white-space: nowrap;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .composition-view.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-viewport {
|
||||||
|
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||||
|
background-color: #000;
|
||||||
|
overflow-y: scroll;
|
||||||
|
cursor: default;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-screen {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-screen canvas {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-scroll-area {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm-char-measure-element {
|
||||||
|
display: inline-block;
|
||||||
|
visibility: hidden;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -9999em;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm.enable-mouse-events {
|
||||||
|
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm.xterm-cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm.column-select.focus {
|
||||||
|
/* Column selection mode */
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-accessibility,
|
||||||
|
.xterm .xterm-message {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 10;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .live-region {
|
||||||
|
position: absolute;
|
||||||
|
left: -9999px;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm-dim {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm-underline {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<div class="mainbox">
|
||||||
|
<div id="container"></div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private fitAddon: FitAddon;
|
||||||
|
public async firstUpdated(
|
||||||
|
_changedProperties: Map<string | number | symbol, unknown>
|
||||||
|
): Promise<void> {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
super.firstUpdated(_changedProperties);
|
||||||
|
const container = this.shadowRoot.getElementById('container');
|
||||||
|
|
||||||
|
const term = new Terminal({
|
||||||
|
convertEol: true,
|
||||||
|
cursorBlink: true,
|
||||||
|
});
|
||||||
|
this.fitAddon = new FitAddon();
|
||||||
|
term.loadAddon(this.fitAddon);
|
||||||
|
|
||||||
|
// Open the terminal in #terminal-container
|
||||||
|
term.open(container);
|
||||||
|
|
||||||
|
// Make the terminal's size and geometry fit the size of #terminal-container
|
||||||
|
this.fitAddon.fit();
|
||||||
|
|
||||||
|
term.write(`dees-terminal custom terminal. \r\n$ `);
|
||||||
|
|
||||||
|
// lets start the webcontainer
|
||||||
|
// Call only once
|
||||||
|
const webcontainerInstance = await webcontainer.WebContainer.boot();
|
||||||
|
const shellProcess = await webcontainerInstance.spawn('jsh');
|
||||||
|
shellProcess.output.pipeTo(
|
||||||
|
new WritableStream({
|
||||||
|
write(data) {
|
||||||
|
term.write(data);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const input = shellProcess.input.getWriter();
|
||||||
|
term.onData((data) => {
|
||||||
|
input.write(data);
|
||||||
|
});
|
||||||
|
await domtools.convenience.smartdelay.delayFor(5000);
|
||||||
|
input.write(`pnpm add isomorphic-git @git.zone/tsbuild\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectedCallback(): Promise<void> {
|
||||||
|
await super.connectedCallback();
|
||||||
|
this.resizeObserver.observe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnectedCallback(): Promise<void> {
|
||||||
|
this.resizeObserver.unobserve(this);
|
||||||
|
await super.disconnectedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleResize() {
|
||||||
|
this.fitAddon.fit();
|
||||||
|
}
|
||||||
|
}
|
5
ts_web/elements/dees-toast.demo.ts
Normal file
5
ts_web/elements/dees-toast.demo.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export const demoFunc = async () => {
|
||||||
|
return html`<dees-toast></dees-toast>`;
|
||||||
|
}
|
28
ts_web/elements/dees-toast.ts
Normal file
28
ts_web/elements/dees-toast.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { customElement, DeesElement, type TemplateResult, html, type CSSResult, } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
|
import { demoFunc } from './dees-toast.demo.js';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-toast': DeesToast;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-toast')
|
||||||
|
export class DeesToast extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
domtools.elementBasic.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${domtools.elementBasic.styles}
|
||||||
|
<style></style>
|
||||||
|
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
1
ts_web/elements/dees-tooltip.ts
Normal file
1
ts_web/elements/dees-tooltip.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
import {} from '@design.estate/dees-element';
|
10
ts_web/elements/dees-updater.demo.ts
Normal file
10
ts_web/elements/dees-updater.demo.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
import { DeesUpdater } from './dees-updater.js';
|
||||||
|
|
||||||
|
export const demoFunc = async () => {
|
||||||
|
const updater = await DeesUpdater.createAndShow();
|
||||||
|
setTimeout(async () => {
|
||||||
|
await updater.destroy();
|
||||||
|
}, 10000);
|
||||||
|
}
|
110
ts_web/elements/dees-updater.ts
Normal file
110
ts_web/elements/dees-updater.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
type TemplateResult,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
type CSSResult,
|
||||||
|
domtools,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
import { demoFunc } from './dees-updater.demo.js';
|
||||||
|
|
||||||
|
import './dees-windowlayer';
|
||||||
|
import { css, cssManager } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-updater': DeesUpdater;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-updater')
|
||||||
|
export class DeesUpdater extends DeesElement {
|
||||||
|
public static demo = demoFunc;
|
||||||
|
|
||||||
|
public static async createAndShow() {
|
||||||
|
const updater = new DeesUpdater();
|
||||||
|
document.body.appendChild(updater);
|
||||||
|
return updater;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
currentVersion: string;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
updatedVersion: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
domtools.elementBasic.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
.modalContainer {
|
||||||
|
will-change: transform;
|
||||||
|
position: relative;
|
||||||
|
background: ${cssManager.bdTheme('#eeeeeb', '#222')};
|
||||||
|
max-width: 800px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border-top: 1px solid ${cssManager.bdTheme('#eeeeeb', '#333')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.headingContainer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 40px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: none;
|
||||||
|
font-size: 20px;
|
||||||
|
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||||
|
margin-left: 20px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonContainer {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50% 50%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<dees-windowlayer
|
||||||
|
@clicked="${this.windowLayerClicked}"
|
||||||
|
.options=${{
|
||||||
|
blur: true,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="modalContainer">
|
||||||
|
<div class="headingContainer">
|
||||||
|
<dees-spinner .size=${60}></dees-spinner>
|
||||||
|
<h1>Updating the application...</h1>
|
||||||
|
</div>
|
||||||
|
<div class="progress">
|
||||||
|
<dees-progressbar .progress=${0.5}></dees-progressbar>
|
||||||
|
</div>
|
||||||
|
<div class="buttonContainer">
|
||||||
|
<dees-button>More info</dees-button>
|
||||||
|
<dees-button>Changelog</dees-button>
|
||||||
|
</div>
|
||||||
|
</div> </dees-windowlayer
|
||||||
|
>>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async destroy() {
|
||||||
|
this.parentElement.removeChild(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private windowLayerClicked() {}
|
||||||
|
}
|
99
ts_web/elements/dees-windowcontrols.ts
Normal file
99
ts_web/elements/dees-windowcontrols.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
DeesElement,
|
||||||
|
domtools,
|
||||||
|
type TemplateResult,
|
||||||
|
html,
|
||||||
|
property,
|
||||||
|
type CSSResult,
|
||||||
|
state,
|
||||||
|
css,
|
||||||
|
cssManager,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-windowcontrols': DeesWindowControls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-windowcontrols')
|
||||||
|
export class DeesWindowControls extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = () => html`<dees-windowcontrols></dees-windowcontrols>`;
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
@property({
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public type: 'mac' | 'linux' | 'windows' = 'mac';
|
||||||
|
|
||||||
|
@property({
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
public position: 'left' | 'right' = 'left';
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.windowControls {
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.windowControls div {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
background: #222222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.windowControls div.close {
|
||||||
|
background: #ff5f57;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.windowControls div.toDock {
|
||||||
|
background: #ffbd2e;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.windowControls div.minMax {
|
||||||
|
background: #27c93f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.windowControls div:hover {
|
||||||
|
background: #333333;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${(this.type === 'mac' && this.position === 'left') ||
|
||||||
|
((this.type === 'linux' || this.type === 'windows') && this.position === 'right')
|
||||||
|
? html`
|
||||||
|
<div class="windowControls">
|
||||||
|
<div class="close"></div>
|
||||||
|
<div class="toDock"></div>
|
||||||
|
<div class="minMax"></div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
123
ts_web/elements/dees-windowlayer.ts
Normal file
123
ts_web/elements/dees-windowlayer.ts
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import { customElement, DeesElement, domtools, type TemplateResult, html, property, type CSSResult, state, } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
'dees-windowlayer': DeesWindowLayer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IOptions_DeesWindowLayer {
|
||||||
|
blur: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement('dees-windowlayer')
|
||||||
|
export class DeesWindowLayer extends DeesElement {
|
||||||
|
// STATIC
|
||||||
|
public static demo = () => html`<dees-windowlayer></dees-windowlayer>`;
|
||||||
|
|
||||||
|
public static async createAndShow(optionsArg?: IOptions_DeesWindowLayer) {
|
||||||
|
const domtoolsInstance = domtools.DomTools.getGlobalDomToolsSync();
|
||||||
|
const windowLayer = new DeesWindowLayer();
|
||||||
|
windowLayer.options = {
|
||||||
|
...windowLayer.options,
|
||||||
|
...optionsArg,
|
||||||
|
}
|
||||||
|
document.body.append(windowLayer);
|
||||||
|
await domtoolsInstance.convenience.smartdelay.delayFor(0);
|
||||||
|
windowLayer.show();
|
||||||
|
return windowLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@state()
|
||||||
|
public options: IOptions_DeesWindowLayer = {
|
||||||
|
blur: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
@property({
|
||||||
|
type: Boolean
|
||||||
|
})
|
||||||
|
public visible = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
domtools.elementBasic.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${domtools.elementBasic.styles}
|
||||||
|
<style>
|
||||||
|
.windowOverlay {
|
||||||
|
transition: all 0.2s;
|
||||||
|
will-change: transform;
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(0, 0, 0, 0.0);
|
||||||
|
backdrop-filter: brightness(1) ${this.options.blur ? 'blur(0px)' : ''};
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 200;
|
||||||
|
}
|
||||||
|
.slotContent {
|
||||||
|
position: fixed;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 201;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visible {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
backdrop-filter: brightness(0.9) ${this.options.blur ? 'blur(2px)' : ''};
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="windowOverlay ${this.visible ? 'visible' : null}">
|
||||||
|
</div>
|
||||||
|
<div @click=${this.dispatchClicked} class="slotContent">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.visible = true;
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchClicked() {
|
||||||
|
this.dispatchEvent(new CustomEvent('clicked'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggleVisibility () {
|
||||||
|
this.visible = !this.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async show() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
await domtools.convenience.smartdelay.delayFor(0);
|
||||||
|
this.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async hide() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
await domtools.convenience.smartdelay.delayFor(0);
|
||||||
|
this.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async destroy() {
|
||||||
|
const domtools = await this.domtoolsPromise;
|
||||||
|
await this.hide();
|
||||||
|
await domtools.convenience.smartdelay.delayFor(300);
|
||||||
|
this.remove();
|
||||||
|
}
|
||||||
|
}
|
3
ts_web/elements/helperclasses/formcontroller.ts
Normal file
3
ts_web/elements/helperclasses/formcontroller.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export class FormController {
|
||||||
|
|
||||||
|
}
|
39
ts_web/elements/index.ts
Normal file
39
ts_web/elements/index.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
export * from './dees-button-exit.js';
|
||||||
|
export * from './dees-button.js';
|
||||||
|
export * from './dees-chips.js';
|
||||||
|
export * from './dees-contextmenu.js';
|
||||||
|
export * from './dees-dataview-codebox.js';
|
||||||
|
export * from './dees-dataview-statusobject.js';
|
||||||
|
export * from './dees-editor.js';
|
||||||
|
export * from './dees-editor-markdown.js';
|
||||||
|
export * from './dees-editor-markdownoutlet.js';
|
||||||
|
export * from './dees-form-submit.js';
|
||||||
|
export * from './dees-form.js';
|
||||||
|
export * from './dees-hint.js';
|
||||||
|
export * from './dees-icon.js';
|
||||||
|
export * from './dees-input-checkbox.js';
|
||||||
|
export * from './dees-input-dropdown.js';
|
||||||
|
export * from './dees-input-fileupload.js';
|
||||||
|
export * from './dees-input-iban.js';
|
||||||
|
export * from './dees-input-typelist.js';
|
||||||
|
export * from './dees-input-phone.js';
|
||||||
|
export * from './dees-progressbar.js';
|
||||||
|
export * from './dees-input-quantityselector.js';
|
||||||
|
export * from './dees-input-radio.js';
|
||||||
|
export * from './dees-input-text.js';
|
||||||
|
export * from './dees-label.js';
|
||||||
|
export * from './dees-mobilenavigation.js';
|
||||||
|
export * from './dees-modal.js';
|
||||||
|
export * from './dees-input-multitoggle.js';
|
||||||
|
export * from './dees-pdf.js';
|
||||||
|
export * from './dees-simple-appdash.js';
|
||||||
|
export * from './dees-simple-login.js';
|
||||||
|
export * from './dees-speechbubble.js';
|
||||||
|
export * from './dees-spinner.js';
|
||||||
|
export * from './dees-stepper.js';
|
||||||
|
export * from './dees-table.js';
|
||||||
|
export * from './dees-terminal.js';
|
||||||
|
export * from './dees-toast.js';
|
||||||
|
export * from './dees-updater.js';
|
||||||
|
export * from './dees-windowcontrols.js';
|
||||||
|
export * from './dees-windowlayer.js';
|
@ -1,35 +0,0 @@
|
|||||||
import { LitElement, property, html, customElement } from 'lit-element';
|
|
||||||
import { TemplateResult } from 'lit-html';
|
|
||||||
|
|
||||||
@customElement('lele-element')
|
|
||||||
export class LeleElement extends LitElement {
|
|
||||||
@property()
|
|
||||||
public footerText = `Lossless GmbH - 2018`;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
// you have access to all kinds of things through this.
|
|
||||||
// this.setAttribute('gotIt','true');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
@import url('https://fonts.googleapis.com/css?family=Roboto');
|
|
||||||
:host {
|
|
||||||
font-family: 'Roboto', sans-serif;
|
|
||||||
background: #FCFCFC;
|
|
||||||
box-shadow: 0px 0px 5px rgba(0,0,0,0.6);
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
:host([hidden]) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<slot></slot>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,2 @@
|
|||||||
import { LeleElement } from './elements/lele-element';
|
export * from './elements/index.js';
|
||||||
|
export { commitinfo } from './00_commitinfo_data.js';
|
||||||
export {
|
|
||||||
LeleElement
|
|
||||||
};
|
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es2017",
|
|
||||||
"module": "es2015",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"lib": ["es2017", "dom"],
|
|
||||||
"declaration": true,
|
|
||||||
"inlineSources": true,
|
|
||||||
"inlineSourceMap": true,
|
|
||||||
"noUnusedLocals": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
|
||||||
"outDir": "dist/",
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"experimentalDecorators": true
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,14 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"target": "ES2017",
|
"useDefineForClassFields": false,
|
||||||
"moduleResolution": "Node"
|
"target": "ES2022",
|
||||||
}
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"verbatimModuleSyntax": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist_*/**/*.d.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
17
tslint.json
17
tslint.json
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
|
||||||
"rules": {
|
|
||||||
"semicolon": [true, "always"],
|
|
||||||
"no-console": false,
|
|
||||||
"ordered-imports": false,
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"member-ordering": {
|
|
||||||
"options":{
|
|
||||||
"order": [
|
|
||||||
"static-method"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"defaultSeverity": "warning"
|
|
||||||
}
|
|
Reference in New Issue
Block a user