@vario-software/vario-app-framework-frontend 2025.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@vario-software/vario-app-framework-frontend",
3
+ "version": "2025.37.0",
4
+ "repository": "https://github.com/vario-software/vario-app-framework",
5
+ "author": "VARIO Software AG",
6
+ "homepage": "https://www.vario.ag",
7
+ "description": "Provides CSS and useful JavaScript utilities for app features and capabilities to make a VARIO Cloud App appear in the corporate design, giving it a consistent look.",
8
+ "license": "MIT",
9
+ "publishConfig": { "access": "public" }
10
+ }
@@ -0,0 +1,30 @@
1
+ import { appIdentifier, integrationId } from './parameters.js';
2
+
3
+ const sendMain = payload =>
4
+ {
5
+ window.parent.postMessage({
6
+ appIdentifier,
7
+ integrationId,
8
+ ...payload,
9
+ }, '*');
10
+ };
11
+
12
+ const receiveMain = actions =>
13
+ {
14
+ const controller = new AbortController();
15
+
16
+ window.addEventListener('message', ({ data }) =>
17
+ {
18
+ Object.keys(actions).forEach(key =>
19
+ {
20
+ if (typeof data === 'object' && key in data)
21
+ {
22
+ actions[key](data[key]);
23
+ }
24
+ });
25
+ }, { signal: controller.signal });
26
+
27
+ return () => controller.abort();
28
+ };
29
+
30
+ export { sendMain, receiveMain };
@@ -0,0 +1,31 @@
1
+ import { sendMain } from './communication.js';
2
+
3
+ let transferedHeight;
4
+
5
+ const transferHeight = () =>
6
+ {
7
+ const height = document.body.scrollHeight;
8
+
9
+ if (transferedHeight !== height)
10
+ {
11
+ sendMain({ height });
12
+
13
+ transferedHeight = height;
14
+ }
15
+ };
16
+
17
+ const initHeightTransfer = () =>
18
+ {
19
+ transferHeight();
20
+
21
+ const observer = new MutationObserver(transferHeight);
22
+
23
+ observer.observe(document.body, {
24
+ attributes: true,
25
+ characterData: true,
26
+ childList: true,
27
+ subtree: true,
28
+ });
29
+ };
30
+
31
+ export { initHeightTransfer };
@@ -0,0 +1,12 @@
1
+ import { secureIntegration } from './secure.js';
2
+ import { initHeightTransfer } from './height.js';
3
+ import { initAppTokenHandling } from './token.js';
4
+ import { initSharedSettings } from './sharedSettings.js';
5
+
6
+ window.addEventListener('DOMContentLoaded', () =>
7
+ {
8
+ secureIntegration();
9
+ initHeightTransfer();
10
+ initAppTokenHandling();
11
+ initSharedSettings();
12
+ });
@@ -0,0 +1,38 @@
1
+ import { sendMain, receiveMain } from './communication.js';
2
+
3
+ const confirm = (confirmation, callback) =>
4
+ {
5
+ sendMain({
6
+ confirmation,
7
+ });
8
+
9
+ const unsubscribe = receiveMain({
10
+ confimation: ({ key, values }) =>
11
+ {
12
+ callback(key, values);
13
+
14
+ unsubscribe();
15
+ },
16
+ });
17
+ };
18
+
19
+ const initStickynav = () => new Promise(resolve =>
20
+ {
21
+ sendMain({
22
+ initStickynav: true,
23
+ });
24
+
25
+ const handleResponse = ({ data }) =>
26
+ {
27
+ if (data.initStickynav)
28
+ {
29
+ window.removeEventListener('message', handleResponse);
30
+
31
+ resolve(data.initStickynav);
32
+ }
33
+ };
34
+
35
+ window.addEventListener('message', handleResponse);
36
+ });
37
+
38
+ export { initStickynav, confirm };
@@ -0,0 +1,33 @@
1
+ const url = new URL(window.location.href);
2
+
3
+ const parameters = url.searchParams;
4
+
5
+ const appIdentifier = parameters.get('appIdentifier');
6
+ const integrationId = parameters.get('integrationId');
7
+
8
+ const language = parameters.get('language');
9
+ const supportMode = parameters.get('supportMode');
10
+ const myCompanyId = parameters.get('myCompanyId');
11
+ const uimode = parameters.get('uimode');
12
+ const detailDatagridTable = parameters.get('detailDatagridTable');
13
+
14
+ const superUser = parameters.get('superUser');
15
+ const permissions = parameters.get('permissions');
16
+
17
+ const additionalPayload = parameters.get('additionalPayload');
18
+
19
+ export {
20
+ appIdentifier,
21
+ integrationId,
22
+
23
+ language,
24
+ supportMode,
25
+ myCompanyId,
26
+ uimode,
27
+ detailDatagridTable,
28
+
29
+ superUser,
30
+ permissions,
31
+
32
+ additionalPayload,
33
+ };
@@ -0,0 +1,11 @@
1
+ const url = new URL(window.location.href);
2
+
3
+ const parameters = url.searchParams;
4
+
5
+ const superUser = parameters.get('superUser');
6
+ const permissions = parameters.get('permissions');
7
+
8
+ export function hasPermission(permission)
9
+ {
10
+ return (superUser === 'true') || permissions.split(',').includes(permission);
11
+ }
@@ -0,0 +1,51 @@
1
+ import { superUser, permissions } from './parameters.js';
2
+
3
+ /* We need to ensure that this integration only
4
+ works when running in a "VARIO Cloud" frame.
5
+
6
+ So we make sure that it is embedded and that
7
+ the parent window is the VARIO Cloud.
8
+
9
+ {tenant}.vario.cloud ✓ valid
10
+ {tenant}.stage-vario.cloud ✓ valid
11
+ {tenant}.dev-vario.cloud ✓ valid
12
+ localhost ✓ valid
13
+ */
14
+
15
+ const getMainUrl = property =>
16
+ {
17
+ if (document.referrer)
18
+ {
19
+ const refUrl = new URL(document.referrer);
20
+ return refUrl[property];
21
+ }
22
+
23
+ return 'tenant.vario.cloud';
24
+ };
25
+
26
+ const isValidIntegration = () =>
27
+ {
28
+ if (window.parent === window)
29
+ {
30
+ return false;
31
+ }
32
+
33
+ if (!getMainUrl('hostname').match(/^[A-Za-z0-9-.]+\.(dev-|stage-)?vario\.cloud$|^localhost$/))
34
+ {
35
+ return false;
36
+ }
37
+
38
+ return true;
39
+ };
40
+
41
+ const secureIntegration = () =>
42
+ {
43
+ if (!isValidIntegration())
44
+ {
45
+ throw new Error('Application does not run within VARIO-Cloud.');
46
+ }
47
+ };
48
+
49
+ const hasPermission = permission => (superUser === 'true') || permissions.split(',').includes(permission);
50
+
51
+ export { secureIntegration, hasPermission };
@@ -0,0 +1,42 @@
1
+ import { sendMain, receiveMain } from './communication.js';
2
+ import { uimode, detailDatagridTable } from './parameters.js';
3
+
4
+ const sharedSettings = { uimode, detailDatagridTable };
5
+
6
+ const transferSettings = (key, value) =>
7
+ {
8
+ sendMain({
9
+ updateSettings: {
10
+ key,
11
+ value,
12
+ },
13
+ });
14
+ };
15
+
16
+ const initSharedSettings = () =>
17
+ {
18
+ initUIMode();
19
+
20
+ receiveMain({
21
+ updateSettings: data =>
22
+ {
23
+ sharedSettings[data.key] = data.value;
24
+
25
+ initUIMode();
26
+ },
27
+ });
28
+ };
29
+
30
+ const initUIMode = () =>
31
+ {
32
+ if (sharedSettings.uimode === 'dark')
33
+ {
34
+ window.document.body.classList.add('v-dark');
35
+ }
36
+ else
37
+ {
38
+ window.document.body.classList.remove('v-dark');
39
+ }
40
+ };
41
+
42
+ export { initSharedSettings, transferSettings, sharedSettings };
@@ -0,0 +1,56 @@
1
+ import { sendMain } from './communication.js';
2
+
3
+ export default class StickynavButtons
4
+ {
5
+ #buttons = {};
6
+
7
+ add = function (button)
8
+ {
9
+ this.#buttons[button.key] = button;
10
+
11
+ this.#update();
12
+ };
13
+
14
+ delete = function (key)
15
+ {
16
+ delete this.#buttons[key];
17
+
18
+ this.#update();
19
+ };
20
+
21
+ toggleLoading = function (key)
22
+ {
23
+ this.#buttons[key].loading = !this.#buttons[key].loading;
24
+
25
+ this.#update();
26
+ };
27
+
28
+ toggleActive = function (key)
29
+ {
30
+ this.#buttons[key].disabled = !this.#buttons[key].disabled;
31
+
32
+ this.#update();
33
+ };
34
+
35
+ keys = function ()
36
+ {
37
+ return Object.keys(this.#buttons);
38
+ };
39
+
40
+ values = function ()
41
+ {
42
+ return Object.values(this.#buttons);
43
+ };
44
+
45
+ get = function (key)
46
+ {
47
+ return this.#buttons[key];
48
+ };
49
+
50
+ #update = function()
51
+ {
52
+ const stickynavButtons = this.values();
53
+
54
+ sendMain({ stickynavButtons });
55
+ };
56
+ }
@@ -0,0 +1,76 @@
1
+ import { sendMain, receiveMain } from './communication.js';
2
+
3
+ export default class StickynavEditmode
4
+ {
5
+ #editFn = null;
6
+
7
+ #saveFn = null;
8
+
9
+ #cancelFn = null;
10
+
11
+ isActive = false;
12
+
13
+ constructor()
14
+ {
15
+ sendMain({ editmode: { add: true } });
16
+
17
+ this.unsubscribe = receiveMain({
18
+ edit: () =>
19
+ {
20
+ if (this.#editFn)
21
+ {
22
+ this.#editFn();
23
+ }
24
+
25
+ this.isActive = true;
26
+ },
27
+
28
+ save: () =>
29
+ {
30
+ if (this.#saveFn)
31
+ {
32
+ this.#saveFn();
33
+ }
34
+
35
+ this.isActive = false;
36
+ },
37
+
38
+ cancel: () =>
39
+ {
40
+ if (this.#cancelFn)
41
+ {
42
+ this.#cancelFn();
43
+ }
44
+
45
+ this.isActive = false;
46
+ },
47
+ });
48
+ }
49
+
50
+ activate = function ()
51
+ {
52
+ this.unsubscribe();
53
+
54
+ sendMain({ editmode: { activate: true } });
55
+ };
56
+
57
+ deactivate = function ()
58
+ {
59
+ sendMain({ editmode: { remove: true } });
60
+ };
61
+
62
+ setEditFn = function (callback)
63
+ {
64
+ this.#editFn = callback;
65
+ };
66
+
67
+ setSaveFn = function (callback)
68
+ {
69
+ this.#saveFn = callback;
70
+ };
71
+
72
+ setCancelFn = function (callback)
73
+ {
74
+ this.#cancelFn = callback;
75
+ };
76
+ }
@@ -0,0 +1,20 @@
1
+ let appToken;
2
+
3
+ const initAppTokenHandling = () =>
4
+ {
5
+ const url = new URL(window.location.href);
6
+
7
+ appToken = url.searchParams.get('appToken');
8
+
9
+ window.addEventListener('message', ({ data }) =>
10
+ {
11
+ if (data.appToken)
12
+ {
13
+ appToken = data.appToken;
14
+ }
15
+ });
16
+ };
17
+
18
+ const getAppToken = () => appToken;
19
+
20
+ export { initAppTokenHandling, getAppToken };
@@ -0,0 +1,54 @@
1
+ .v-button {
2
+ display: flex;
3
+ align-items: center;
4
+ position: relative;
5
+ border: 1px solid lightgrey;
6
+ border-radius: var(--v-border-radius);
7
+ outline: 0;
8
+ font-weight: 500;
9
+ padding: 0.2857em 1.1429em; /* 4px 16px */
10
+ font-family: inherit;
11
+ line-height: 1.715em; /* 24px */
12
+ color: var(--v-accent);
13
+ cursor: pointer;
14
+ min-height: 2.572em; /* 36px */
15
+ vertical-align: middle;
16
+ font-size: inherit;
17
+ transition: background 0.6s;
18
+ background: transparent radial-gradient(circle, transparent 1%, white 1%) center/14000%;
19
+ }
20
+
21
+ .v-button:active {
22
+ background-color: color-mix(in srgb, var(--v-accent), transparent 60%);
23
+ background-size: 100%;
24
+ transition: background 0s;
25
+ }
26
+
27
+ .v-button::after {
28
+ content: '';
29
+ display: block;
30
+ position: absolute;
31
+ inset: 0;
32
+ border-radius: inherit;
33
+ opacity: 0;
34
+ background-color: currentcolor;
35
+ transition: opacity 0.15s cubic-bezier(0.25, 0.8, 0.5, 1);
36
+ }
37
+
38
+ .v-button:hover::after {
39
+ opacity: 0.1;
40
+ }
41
+
42
+ .v-button:active::after {
43
+ opacity: 0.14;
44
+ }
45
+
46
+ .v-button:not(.v-icon-only) > .v-icon {
47
+ margin-right: 0.3333em; /* 6px */
48
+ }
49
+
50
+
51
+ .v-button:disabled {
52
+ opacity: 0.6;
53
+ cursor: not-allowed;
54
+ }
package/style/card.css ADDED
@@ -0,0 +1,36 @@
1
+ .v-card {
2
+ box-shadow: 0 0 0.2857em rgb(0 0 0 / 20%) !important; /* 0 0 4px */
3
+ border-radius: var(--v-border-radius);
4
+ overflow: hidden;
5
+ background-color: white;
6
+ }
7
+
8
+ .v-card > .v-head {
9
+ display: flex;
10
+ line-height: 2em; /* 28px */
11
+ letter-spacing: 0.0094em; /* 0.1316px */
12
+ }
13
+
14
+ .v-card > .v-head > .v-title {
15
+ color: var(--v-primary);
16
+ border-radius: var(--v-border-radius) 0 var(--v-border-radius) 0;
17
+ padding: 0.375em 1.125em; /* 6px 18px */
18
+ background-color: #e0e0e0;
19
+ text-overflow: ellipsis;
20
+ white-space: nowrap;
21
+ overflow: hidden;
22
+ margin-bottom: 0.5625em; /* 9px */
23
+ font-size: 1.1429em; /* 18px */
24
+ }
25
+
26
+ .v-card > .v-head > .v-header {
27
+ display: inherit;
28
+ flex: 1 0 auto;
29
+ padding: 0 1.1429em 0.3571em 0.5714em; /* 0 16px 5px 8px */
30
+ align-items: center;
31
+ justify-content: flex-end;
32
+ }
33
+
34
+ .v-card > .v-content:not(.v-no-padding) {
35
+ padding: 0 1.1429em 1.1429em; /* 0 16px 16px */
36
+ }
@@ -0,0 +1,69 @@
1
+ .v-checkbox {
2
+ position: relative;
3
+ }
4
+
5
+ .v-checkbox input {
6
+ display: none;
7
+ cursor: pointer;
8
+ }
9
+
10
+ .v-checkbox input + label {
11
+ position: relative;
12
+ cursor: pointer;
13
+ }
14
+
15
+ .v-checkbox input + label::before {
16
+ content: '';
17
+ background-color: transparent;
18
+ border: 0.1429em solid rgb(0 0 0 / 54%); /* 2px */
19
+ border-radius: var(--v-border-radius);
20
+ padding: 0.5em; /* 7px */
21
+ display: inline-block;
22
+ position: relative;
23
+ vertical-align: middle;
24
+ cursor: pointer;
25
+ margin-right: 0.3571em; /* 5px */
26
+ transition: background-color 150ms;
27
+ }
28
+
29
+ .v-checkbox input:checked + label::before {
30
+ background-color: var(--v-secondary);
31
+ border-color: var(--v-secondary);
32
+ }
33
+
34
+ .v-checkbox::after {
35
+ content: '';
36
+ position: absolute;
37
+ top: 0.32em; /* 4.5px */
38
+ left: -0.1em; /* -1.4px */
39
+ width: 1.4286em; /* 20px */
40
+ height: 1.4286em; /* 20px */
41
+ border-radius: 50%;
42
+ background: currentcolor;
43
+ opacity: 0.06;
44
+ transform: scale3d(0, 0, 1);
45
+ transition: transform 100ms cubic-bezier(0, 0, 0.2, 1);
46
+ pointer-events: none;
47
+ }
48
+
49
+ .v-checkbox:hover::after {
50
+ transform: scale3d(1.4, 1.4, 1);
51
+ }
52
+
53
+ .v-checkbox input + label::after {
54
+ content: '';
55
+ position: absolute;
56
+ top: 0.0714em; /* 1px */
57
+ left: 0.4286em; /* 6px */
58
+ width: 0.2857em; /* 4px */
59
+ height: 0.7857em; /* 11px */
60
+ border: solid #fff;
61
+ border-width: 0 0.1429em 0.1429em 0; /* 2px 2px */
62
+ transform: rotate(45deg);
63
+ opacity: 0;
64
+ transition: opacity 100ms 100ms;
65
+ }
66
+
67
+ .v-checkbox input:checked + label::after {
68
+ opacity: 1;
69
+ }
@@ -0,0 +1,64 @@
1
+ .v-datagrid > .v-head {
2
+ padding: 0.5714em 1.1429em; /* 8px 16px */
3
+ display: flex;
4
+ }
5
+
6
+ .v-datagrid > .v-head > .v-input {
7
+ flex: 1 0 auto;
8
+ max-width: 17.8572em; /* 250px */
9
+ min-width: 7.1429em; /* 100px */
10
+ }
11
+
12
+ .v-datagrid > .v-head > .v-header {
13
+ flex: 1 0 auto;
14
+ display: inherit;
15
+ justify-content: flex-end;
16
+ align-items: center;
17
+ }
18
+
19
+ .v-datagrid > .v-foot {
20
+ text-align: right;
21
+ font-weight: 400;
22
+ font-size: 0.8571em; /* 12px */
23
+ line-height: 3.5em; /* 42px */
24
+ padding: 0.3334em 1.1667em 0.3334em 1.3334em; /* 4px 14px 4px 16px */
25
+ border-top: 1px solid rgb(0 0 0 / 12%);
26
+ color: #666;
27
+ }
28
+
29
+ .v-datagrid > table {
30
+ width: 100%;
31
+ border-spacing: 0;
32
+ border-collapse: collapse;
33
+ }
34
+
35
+ .v-datagrid > table > thead > tr > th,
36
+ .v-datagrid > table > tbody > tr > td {
37
+ position: relative;
38
+ line-height: 4.1669em; /* 50px */
39
+ font-size: 0.8571em; /* 12px */
40
+ padding: 0;
41
+ text-align: center;
42
+ }
43
+
44
+ .v-datagrid > table > thead > tr > th {
45
+ background: var(--v-secondary);
46
+ font-weight: 500;
47
+ color: #fff;
48
+ }
49
+
50
+ .v-datagrid > table > tbody > tr > td {
51
+ cursor: pointer;
52
+ }
53
+
54
+ .v-datagrid > table > tbody > tr:hover > td::before {
55
+ content: '';
56
+ background: rgb(0 0 0 / 3%);
57
+ position: absolute;
58
+ inset: 0;
59
+ pointer-events: none;
60
+ }
61
+
62
+ .v-datagrid > table > tbody > tr:nth-child(2n) > td {
63
+ background: rgb(0 0 0 / 6%);
64
+ }
@@ -0,0 +1,159 @@
1
+ :root {
2
+ --spacing-xs: 0.286em;
3
+ --spacing-sm: 0.572em;
4
+ --spacing-md: 1.143em;
5
+ --spacing-lg: 1.715em;
6
+ }
7
+
8
+ .v-pa-xs {
9
+ padding: var(--spacing-xs);
10
+ }
11
+
12
+ .v-pa-sm {
13
+ padding: var(--spacing-sm);
14
+ }
15
+
16
+ .v-pa-md {
17
+ padding: var(--spacing-md);
18
+ }
19
+
20
+ .v-pa-lg {
21
+ padding: var(--spacing-lg);
22
+ }
23
+
24
+ .v-py-xs {
25
+ padding-top: var(--spacing-xs);
26
+ padding-bottom: var(--spacing-xs);
27
+ }
28
+
29
+ .v-py-sm {
30
+ padding-top: var(--spacing-sm);
31
+ padding-bottom: var(--spacing-sm);
32
+ }
33
+
34
+ .v-py-md {
35
+ padding-top: var(--spacing-md);
36
+ padding-bottom: var(--spacing-md);
37
+ }
38
+
39
+ .v-py-lg {
40
+ padding-top: var(--spacing-lg);
41
+ padding-bottom: var(--spacing-lg);
42
+ }
43
+
44
+ .v-px-xs {
45
+ padding-left: var(--spacing-xs);
46
+ padding-right: var(--spacing-xs);
47
+ }
48
+
49
+ .v-px-sm {
50
+ padding-left: var(--spacing-sm);
51
+ padding-right: var(--spacing-sm);
52
+ }
53
+
54
+ .v-px-md {
55
+ padding-left: var(--spacing-md);
56
+ padding-right: var(--spacing-md);
57
+ }
58
+
59
+ .v-px-lg {
60
+ padding-left: var(--spacing-lg);
61
+ padding-right: var(--spacing-lg);
62
+ }
63
+
64
+ .v-pt-xs { padding-top: var(--spacing-xs); }
65
+ .v-pt-sm { padding-top: var(--spacing-sm); }
66
+ .v-pt-md { padding-top: var(--spacing-md); }
67
+ .v-pt-lg { padding-top: var(--spacing-lg); }
68
+
69
+ .v-pb-xs { padding-bottom: var(--spacing-xs); }
70
+ .v-pb-sm { padding-bottom: var(--spacing-sm); }
71
+ .v-pb-md { padding-bottom: var(--spacing-md); }
72
+ .v-pb-lg { padding-bottom: var(--spacing-lg); }
73
+
74
+ .v-pl-xs { padding-left: var(--spacing-xs); }
75
+ .v-pl-sm { padding-left: var(--spacing-sm); }
76
+ .v-pl-md { padding-left: var(--spacing-md); }
77
+ .v-pl-lg { padding-left: var(--spacing-lg); }
78
+
79
+ .v-pr-xs { padding-right: var(--spacing-xs); }
80
+ .v-pr-sm { padding-right: var(--spacing-sm); }
81
+ .v-pr-md { padding-right: var(--spacing-md); }
82
+ .v-pr-lg { padding-right: var(--spacing-lg); }
83
+
84
+ .v-ma-xs {
85
+ margin: var(--spacing-xs);
86
+ }
87
+
88
+ .v-ma-sm {
89
+ margin: var(--spacing-sm);
90
+ }
91
+
92
+ .v-ma-md {
93
+ margin: var(--spacing-md);
94
+ }
95
+
96
+ .v-ma-lg {
97
+ margin: var(--spacing-lg);
98
+ }
99
+
100
+
101
+ .v-my-xs {
102
+ margin-top: var(--spacing-xs);
103
+ margin-bottom: var(--spacing-xs);
104
+ }
105
+
106
+ .v-my-sm {
107
+ margin-top: var(--spacing-sm);
108
+ margin-bottom: var(--spacing-sm);
109
+ }
110
+
111
+ .v-my-md {
112
+ margin-top: var(--spacing-md);
113
+ margin-bottom: var(--spacing-md);
114
+ }
115
+
116
+ .v-my-lg {
117
+ margin-top: var(--spacing-lg);
118
+ margin-bottom: var(--spacing-lg);
119
+ }
120
+
121
+ .v-mx-xs {
122
+ margin-left: var(--spacing-xs);
123
+ margin-right: var(--spacing-xs);
124
+ }
125
+
126
+ .v-mx-sm {
127
+ margin-left: var(--spacing-sm);
128
+ margin-right: var(--spacing-sm);
129
+ }
130
+
131
+ .v-mx-md {
132
+ margin-left: var(--spacing-md);
133
+ margin-right: var(--spacing-md);
134
+ }
135
+
136
+ .v-mx-lg {
137
+ margin-left: var(--spacing-lg);
138
+ margin-right: var(--spacing-lg);
139
+ }
140
+
141
+ .v-mt-xs { margin-top: var(--spacing-xs); }
142
+ .v-mt-sm { margin-top: var(--spacing-sm); }
143
+ .v-mt-md { margin-top: var(--spacing-md); }
144
+ .v-mt-lg { margin-top: var(--spacing-lg); }
145
+
146
+ .v-mb-xs { margin-bottom: var(--spacing-xs); }
147
+ .v-mb-sm { margin-bottom: var(--spacing-sm); }
148
+ .v-mb-md { margin-bottom: var(--spacing-md); }
149
+ .v-mb-lg { margin-bottom: var(--spacing-lg); }
150
+
151
+ .v-ml-xs { margin-left: var(--spacing-xs); }
152
+ .v-ml-sm { margin-left: var(--spacing-sm); }
153
+ .v-ml-md { margin-left: var(--spacing-md); }
154
+ .v-ml-lg { margin-left: var(--spacing-lg); }
155
+
156
+ .v-mr-xs { margin-right: var(--spacing-xs); }
157
+ .v-mr-sm { margin-right: var(--spacing-sm); }
158
+ .v-mr-md { margin-right: var(--spacing-md); }
159
+ .v-mr-lg { margin-right: var(--spacing-lg); }
@@ -0,0 +1,63 @@
1
+ .v-row {
2
+ display: flex;
3
+ width: 100%;
4
+ box-sizing: border-box;
5
+ align-items: flex-start;
6
+
7
+ --gap: 1.715em;
8
+
9
+ gap: var(--gap);
10
+ }
11
+
12
+ .v-row-xs { --gap: 0.286em; }
13
+ .v-row-sm { --gap: 0.572em; }
14
+ .v-row-md { --gap: 1.143em; }
15
+ .v-row-lg { --gap: 1.715em; }
16
+ .v-row-xl { --gap: 3.5em; }
17
+
18
+ .v-row-xs,
19
+ .v-row-sm,
20
+ .v-row-md,
21
+ .v-row-lg,
22
+ .v-row-xl {
23
+ gap: var(--gap);
24
+ }
25
+
26
+ [class^="v-col-"] {
27
+ display: flex;
28
+ flex-direction: column;
29
+ gap: var(--gap);
30
+ flex: 1 1 calc(var(--col) * 100%);
31
+ max-width: calc(var(--col) * 100%);
32
+ }
33
+
34
+ .v-col-shrink {
35
+ flex: 0 0 auto !important;
36
+ width: auto !important;
37
+ max-width: none !important;
38
+ }
39
+
40
+ .v-col-grow {
41
+ flex: 1 1 auto !important;
42
+ min-width: 0;
43
+ max-width: 100%;
44
+ }
45
+
46
+ .v-content > .v-row [class^="v-col-"],
47
+ .v-content.v-row [class^="v-col-"] {
48
+ max-width: calc(100% * var(--col) - (var(--gap) / 2));
49
+ flex: 1 1 calc(100% * var(--col) - (var(--gap) / 2));
50
+ }
51
+
52
+ .v-col-1 { --col: 1 / 12; }
53
+ .v-col-2 { --col: 2 / 12; }
54
+ .v-col-3 { --col: 3 / 12; }
55
+ .v-col-4 { --col: 4 / 12; }
56
+ .v-col-5 { --col: 5 / 12; }
57
+ .v-col-6 { --col: 6 / 12; }
58
+ .v-col-7 { --col: 7 / 12; }
59
+ .v-col-8 { --col: 8 / 12; }
60
+ .v-col-9 { --col: 9 / 12; }
61
+ .v-col-10 { --col: 10 / 12; }
62
+ .v-col-11 { --col: 11 / 12; }
63
+ .v-col-12 { --col: 1; }
package/style/grid.css ADDED
@@ -0,0 +1,67 @@
1
+ /* Grid container */
2
+ .v-row {
3
+ display: flex;
4
+ width: 100%;
5
+ box-sizing: border-box;
6
+ align-items: flex-start;
7
+
8
+ --gap: 1.715em;
9
+
10
+ gap: var(--gap);
11
+ }
12
+
13
+ .v-row-xs { --gap: 0.286em; }
14
+ .v-row-sm { --gap: 0.572em; }
15
+ .v-row-md { --gap: 1.143em; }
16
+ .v-row-lg { --gap: 1.715em; }
17
+ .v-row-xl { --gap: 3.5em; }
18
+
19
+ .v-col-1, .v-col-2, .v-col-3, .v-col-4,
20
+ .v-col-5, .v-col-6, .v-col-7, .v-col-8,
21
+ .v-col-9, .v-col-10, .v-col-11, .v-col-12 {
22
+ display: flex;
23
+ flex-direction: column;
24
+ box-sizing: border-box;
25
+ flex: 1 1 calc(var(--col) * 100%);
26
+ max-width: calc(var(--col) * 100%);
27
+ align-items: stretch;
28
+ }
29
+
30
+ .v-col-content-natural{
31
+ align-items: flex-start;
32
+ }
33
+
34
+ .v-col-1 { --col: 1/12; }
35
+ .v-col-2 { --col: 2/12; }
36
+ .v-col-3 { --col: 3/12; }
37
+ .v-col-4 { --col: 4/12; }
38
+ .v-col-5 { --col: 5/12; }
39
+ .v-col-6 { --col: 6/12; }
40
+ .v-col-7 { --col: 7/12; }
41
+ .v-col-8 { --col: 8/12; }
42
+ .v-col-9 { --col: 9/12; }
43
+ .v-col-10 { --col: 10/12; }
44
+ .v-col-11 { --col: 11/12; }
45
+ .v-col-12 { --col: 1; }
46
+
47
+ .v-col-shrink {
48
+ display: flex;
49
+ flex-direction: column;
50
+ gap: var(--gap);
51
+ box-sizing: border-box;
52
+ flex: 0 0 auto;
53
+ width: auto;
54
+ }
55
+
56
+ .v-col-grow {
57
+ display: flex;
58
+ flex-direction: column;
59
+ gap: var(--gap);
60
+ box-sizing: border-box;
61
+ flex: 1 1 auto;
62
+ min-width: 0;
63
+ }
64
+
65
+ .v-col-vertical-center {
66
+ align-self: center;
67
+ }
package/style/hr.css ADDED
@@ -0,0 +1,5 @@
1
+ .v-hr{
2
+ border:none;
3
+ border-bottom: 1px solid rgb(0 0 0 / 24%);
4
+ margin: 1.143em 0;
5
+ }
package/style/icon.css ADDED
@@ -0,0 +1,6 @@
1
+ .v-icon {
2
+ display: inline-block;
3
+ width: 1em; /* 18px */
4
+ height: 1em; /* 18px */
5
+ font-size: 1.2858em; /* 18px */
6
+ }
@@ -0,0 +1,13 @@
1
+ @import 'variables.css';
2
+ @import 'root.css';
3
+ @import 'card.css';
4
+ @import 'button.css';
5
+ @import 'icon.css';
6
+ @import 'input.css';
7
+ @import 'hr.css';
8
+ @import 'datagrid.css';
9
+ @import 'grid.css';
10
+ @import 'link.css';
11
+ @import 'distances.css';
12
+ @import 'checkbox.css';
13
+ @import 'toggle.css';
@@ -0,0 +1,96 @@
1
+ .v-input {
2
+ position: relative;
3
+ }
4
+
5
+ .v-input::before,
6
+ .v-input::after {
7
+ content: '';
8
+ position: absolute;
9
+ inset: 0;
10
+ pointer-events: none;
11
+ }
12
+
13
+ .v-input::before {
14
+ border-bottom: 1px solid rgb(0 0 0 / 24%);
15
+ transition: border-color 0.36s cubic-bezier(0.4, 0, 0.2, 1);
16
+ }
17
+
18
+ .v-input:hover::before {
19
+ border-color: var(--v-secondary);
20
+ }
21
+
22
+ .v-input::after {
23
+ height: 0.1429em; /* 2px */
24
+ top: auto;
25
+ transform-origin: center bottom;
26
+ transform: scale3d(0, 1, 1);
27
+ background: var(--v-secondary);
28
+ transition: transform 0.36s cubic-bezier(0.4, 0, 0.2, 1);
29
+ }
30
+
31
+ .v-input:focus-within::after {
32
+ transform: scale3d(1, 1, 1);
33
+ }
34
+
35
+ .v-input:focus-within .v-label {
36
+ color: var(--v-primary);
37
+ }
38
+
39
+ .v-input > input {
40
+ font: inherit;
41
+ line-height: 1.7143em; /* 24px */
42
+ overflow: hidden;
43
+ text-overflow: ellipsis;
44
+ width: 100%;
45
+ min-width: 0;
46
+ outline: 0;
47
+ user-select: auto;
48
+ letter-spacing: 0.0094em;
49
+ border: none;
50
+ color: rgb(0 0 0 / 87%);
51
+ padding: 1.1429em 0.4286em 0 0; /* 16px 6px 0 0 */
52
+ }
53
+
54
+ .v-input:has(.v-icon) > input {
55
+ padding-right: 1.7143em; /* 24px */
56
+ }
57
+
58
+ .v-input > .v-label {
59
+ pointer-events: none;
60
+ top: 0.7143em; /* 10px */
61
+ text-overflow: ellipsis;
62
+ white-space: nowrap;
63
+ overflow: hidden;
64
+ position: absolute;
65
+ letter-spacing: 0.0094em;
66
+ color: rgb(0 0 0 / 60%);
67
+ transform-origin: left top;
68
+ line-height: 1.4286em; /* 20px */
69
+ }
70
+
71
+ .v-input > .v-icon {
72
+ pointer-events: none;
73
+ top: 0.5556em; /* 10px */
74
+ position: absolute;
75
+ right: 0.2222em; /* 4px */
76
+ color: rgb(0 0 0 / 60%);
77
+ line-height: 1.1111em; /* 20px */
78
+ }
79
+
80
+ .v-input > .v-label,
81
+ .v-input:focus-within > .v-label.v-stack,
82
+ .v-input:has(input:not(:placeholder-shown)) > .v-label.v-stack{
83
+ transform: translateY(-30%) scale(0.75);
84
+ max-width: 133%;
85
+ }
86
+
87
+ .v-input:focus-within > .v-label.v-stackl {
88
+ color: currentcolor;
89
+ }
90
+
91
+ .v-input > .v-label.v-stack {
92
+ transform: translateY(0);
93
+ transition:
94
+ transform 0.36s cubic-bezier(0.4, 0, 0.2, 1),
95
+ max-width 0.324s cubic-bezier(0.4, 0, 0.2, 1);
96
+ }
package/style/link.css ADDED
@@ -0,0 +1,15 @@
1
+ .v-link:link,
2
+ .v-link:visited {
3
+ color: #588712;
4
+ text-decoration-color: #588712;
5
+ }
6
+
7
+ .v-link:hover,
8
+ .v-link:visited:hover {
9
+ color: var(--v-accent);
10
+ }
11
+
12
+ .v-link:hover:not(.v-banner),
13
+ .v-link:visited:hover:not(.v-banner) {
14
+ text-decoration-line: none;
15
+ }
package/style/root.css ADDED
@@ -0,0 +1,53 @@
1
+ :root {
2
+ --v-primary: #2e2e2e;
3
+ --v-secondary: #84b933;
4
+ --v-secondary-light: #96cc44;
5
+ --v-accent: #ab2e68;
6
+ --v-positive: #84b933;
7
+ --v-negative: #cd4837;
8
+ --v-info: #11518c;
9
+ --v-warning: #f0b618;
10
+ --v-dark: #1d1d1d;
11
+ --v-dark-page: #121212;
12
+ --v-border-radius: 4px;
13
+ }
14
+
15
+ body {
16
+ font-family:
17
+ Roboto,
18
+ -apple-system,
19
+ sans-serif;
20
+ font-size: 14px;
21
+ line-height: 1.5em;
22
+ padding: 0.7143em; /* 10px | to fit exact distance in the app */
23
+ margin: 0;
24
+ color: var(--v-primary);
25
+ overscroll-behavior-x: none; /* prevent scroll bounce effect */
26
+ background:#fff;
27
+ }
28
+
29
+ .text-center{
30
+ text-align: center;
31
+ }
32
+
33
+ .text-grey{
34
+ color: rgb(0 0 0 / 60%) !important;
35
+ text-decoration-color: rgb(0 0 0 / 60%) !important;
36
+ }
37
+
38
+ .text-white{
39
+ color: #fff !important;
40
+ text-decoration-color: #fff !important;
41
+ }
42
+
43
+ .hidden{
44
+ display:none !important;
45
+ }
46
+
47
+ .full-height: {
48
+ height: 100%;
49
+ }
50
+
51
+ .full-width: {
52
+ width: 100%;
53
+ }
@@ -0,0 +1,60 @@
1
+ .v-toggle {
2
+ position: relative;
3
+ }
4
+
5
+ .v-toggle input {
6
+ display: none;
7
+ cursor: pointer;
8
+ }
9
+
10
+ .v-toggle input + label {
11
+ position: relative;
12
+ cursor: pointer;
13
+ }
14
+
15
+ .v-toggle input + label::before {
16
+ content: '';
17
+ display: inline-block;
18
+ height: 1em; /* 14px */
19
+ width: 2.2858em; /* 32px */
20
+ opacity: 0.38;
21
+ border-radius: 0.5em /* 7px */;
22
+ vertical-align: middle;
23
+ background-color: currentcolor;
24
+ cursor: pointer;
25
+ margin-right: 0.3571em; /* 5px */
26
+ transition: background-color 150ms;
27
+ }
28
+
29
+ .v-toggle input:checked + label::before {
30
+ background-color: var(--v-secondary);
31
+ }
32
+
33
+ .v-toggle input + label::after {
34
+ content: '';
35
+ position: absolute;
36
+ background-color: #fff;
37
+ border-radius: 50vh;
38
+ padding: 0.7143em; /* 10px */
39
+ top: -0.0714em; /* -1px */
40
+ left: 0;
41
+ cursor: pointer;
42
+ margin-right: 0.3571em; /* 5px */
43
+ box-shadow:
44
+ 0 3px 1px -2px rgb(0 0 0 / 20%),
45
+ 0 2px 2px 0 rgb(0 0 0 / 14%),
46
+ 0 1px 5px 0 rgb(0 0 0 / 12%);
47
+ outline: 0 solid rgb(0 0 0 / 6%);
48
+ transition:
49
+ left 150ms cubic-bezier(0.4, 0, 0.2, 1),
50
+ outline 75ms cubic-bezier(0, 0, 0.2, 1);
51
+ }
52
+
53
+ .v-toggle input:checked + label::after {
54
+ left: 0.8571em; /* 12px */
55
+ background-color: var(--v-secondary);
56
+ }
57
+
58
+ .v-toggle:hover input + label::after {
59
+ outline-width: 0.2143em; /* 3px */
60
+ }
@@ -0,0 +1,13 @@
1
+ :root {
2
+ --v-primary: #2e2e2e;
3
+ --v-secondary: #84b933;
4
+ --v-secondary-light: #96cc44;
5
+ --v-accent: #ab2e68;
6
+ --v-positive: #84b933;
7
+ --v-negative: #cd4837;
8
+ --v-info: #11518c;
9
+ --v-warning: #f0b618;
10
+ --v-dark: #1d1d1d;
11
+ --v-dark-page: #121212;
12
+ --v-border-radius: 4px;
13
+ }