@3cr/viewer-browser 0.0.1

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.
Files changed (49) hide show
  1. package/.browserslistrc +4 -0
  2. package/.editorconfig +5 -0
  3. package/.idea/git_toolbox_prj.xml +15 -0
  4. package/.idea/vcs.xml +6 -0
  5. package/.idea/workspace.xml +183 -0
  6. package/.vite/deps/_metadata.json +8 -0
  7. package/.vite/deps/package.json +3 -0
  8. package/README.md +81 -0
  9. package/components.d.ts +19 -0
  10. package/dist/3cr-viewer-browser.mjs +18644 -0
  11. package/dist/3cr-viewer-browser.umd.js +18 -0
  12. package/dist/style.css +5 -0
  13. package/index.html +24 -0
  14. package/index.ts +37 -0
  15. package/package.json +41 -0
  16. package/src/App.vue +40 -0
  17. package/src/assets/images/MainBackdrop.svg +48 -0
  18. package/src/assets/images/dark/3DICOM.png +0 -0
  19. package/src/assets/images/dark/3dicom-logo.svg +1 -0
  20. package/src/assets/images/dark/Singular-Health-Disc-Mono.svg +9 -0
  21. package/src/assets/images/dark/Singular-Health-Trademark-mono.svg +23 -0
  22. package/src/assets/images/light/3DICOM.png +0 -0
  23. package/src/assets/images/light/3dicom-logo.svg +1 -0
  24. package/src/assets/images/light/Singular-Health-Disc-Mono.svg +9 -0
  25. package/src/assets/images/light/Singular-Health-Trademark-mono.svg +23 -0
  26. package/src/assets/logo.png +0 -0
  27. package/src/assets/logo.svg +6 -0
  28. package/src/components/DoubleSliderSelector.vue +112 -0
  29. package/src/components/ExpansionHeaderMiniMenu.vue +19 -0
  30. package/src/components/HelloWorld.vue +157 -0
  31. package/src/components/LoadingSpinner.vue +157 -0
  32. package/src/components/MftpWebGL3DRModal.vue +995 -0
  33. package/src/components/README.md +35 -0
  34. package/src/components/SliderSelector.vue +101 -0
  35. package/src/components/VerticalSliderSelector.vue +83 -0
  36. package/src/components/WebGL3DR.vue +107 -0
  37. package/src/helpers/layoutOverlayStyle.ts +86 -0
  38. package/src/helpers/modelHelper.ts +109 -0
  39. package/src/helpers/models.ts +69 -0
  40. package/src/helpers/utils.ts +16 -0
  41. package/src/main.ts +23 -0
  42. package/src/plugins/README.md +3 -0
  43. package/src/plugins/index.ts +15 -0
  44. package/src/plugins/vuetify.ts +27 -0
  45. package/src/types/window.shim.ts +24 -0
  46. package/src/vite-env.d.ts +7 -0
  47. package/tsconfig.json +34 -0
  48. package/tsconfig.node.json +9 -0
  49. package/vite.config.mts +74 -0
@@ -0,0 +1,35 @@
1
+ # Components
2
+
3
+ Vue template files in this folder are automatically imported.
4
+
5
+ ## 🚀 Usage
6
+
7
+ Importing is handled by [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components). This plugin automatically imports `.vue` files created in the `src/components` directory, and registers them as global components. This means that you can use any component in your application without having to manually import it.
8
+
9
+ The following example assumes a component located at `src/components/MyComponent.vue`:
10
+
11
+ ```vue
12
+ <template>
13
+ <div>
14
+ <MyComponent />
15
+ </div>
16
+ </template>
17
+
18
+ <script lang="ts" setup>
19
+ //
20
+ </script>
21
+ ```
22
+
23
+ When your template is rendered, the component's import will automatically be inlined, which renders to this:
24
+
25
+ ```vue
26
+ <template>
27
+ <div>
28
+ <MyComponent />
29
+ </div>
30
+ </template>
31
+
32
+ <script lang="ts" setup>
33
+ import MyComponent from '@/components/MyComponent.vue'
34
+ </script>
35
+ ```
@@ -0,0 +1,101 @@
1
+ <script setup lang="ts">
2
+ import {computed, defineEmits} from 'vue';
3
+
4
+
5
+
6
+ export interface Props {
7
+ value: number;
8
+ loading: boolean;
9
+ label: string;
10
+ min: number;
11
+ max: number;
12
+ step: number,
13
+ prepend: string,
14
+ }
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ value: 0,
18
+ loading: false,
19
+ label: "Test",
20
+ min: -99999,
21
+ max: 99999,
22
+ step: 1,
23
+ prepend: '',
24
+ });
25
+ const emit = defineEmits<{
26
+ input: [number];
27
+ }>();
28
+ const sliderValue = computed({
29
+ get() {
30
+ return props.value
31
+ },
32
+ set(value: number) {
33
+ emit('input', value);
34
+ }
35
+ })
36
+ </script>
37
+
38
+ <template>
39
+ <div class="single-slider-selector">
40
+ <!-- <v-card-subtitle class="pb-0 pt-1 text-caption">{{ label }}</v-card-subtitle>-->
41
+ <v-card-actions class="px-2 pb-0">
42
+ <span class="text-caption">
43
+ {{ label }}
44
+ </span>
45
+ <v-spacer />
46
+ <v-text-field
47
+ v-model="sliderValue"
48
+ outlined
49
+ dense
50
+ class="mt-0 pt-0"
51
+ hide-details
52
+ type="number"
53
+ :append-icon="prepend"
54
+ style="width: 44px"
55
+ ></v-text-field>
56
+ </v-card-actions>
57
+ <!-- <v-slider-->
58
+ <!-- v-model="sliderValue"-->
59
+ <!-- :loading="loading"-->
60
+ <!-- thumb-label-->
61
+ <!-- :max="max"-->
62
+ <!-- :min="min"-->
63
+ <!-- :step="step"-->
64
+ <!-- hide-details-->
65
+ <!-- class="align-center px-2 black&#45;&#45;text"-->
66
+ <!-- >-->
67
+ <!-- &lt;!&ndash; <template v-slot:append>&ndash;&gt;-->
68
+ <!-- &lt;!&ndash; <v-text-field&ndash;&gt;-->
69
+ <!-- &lt;!&ndash; v-model="sliderValue"&ndash;&gt;-->
70
+ <!-- &lt;!&ndash; outlined&ndash;&gt;-->
71
+ <!-- &lt;!&ndash; hide-details&ndash;&gt;-->
72
+ <!-- &lt;!&ndash; dense&ndash;&gt;-->
73
+ <!-- &lt;!&ndash; class="mt-0 pt-0 ml-2"&ndash;&gt;-->
74
+ <!-- &lt;!&ndash; type="number"&ndash;&gt;-->
75
+ <!-- &lt;!&ndash; style="width: 68px"&ndash;&gt;-->
76
+ <!-- &lt;!&ndash; ></v-text-field>&ndash;&gt;-->
77
+ <!-- &lt;!&ndash; </template>&ndash;&gt;-->
78
+ <!-- </v-slider>-->
79
+ </div>
80
+ </template>
81
+
82
+ <style>
83
+ .single-slider-selector
84
+ .v-text-field.v-text-field--enclosed:not(.v-text-field--rounded)
85
+ > .v-input__control
86
+ > .v-input__slot,
87
+ .single-slider-selector .v-text-field.v-text-field--enclosed .v-text-field__details {
88
+ padding: 0px 8px !important;
89
+ }
90
+
91
+ .single-slider-selector
92
+ .v-text-field--outlined.v-input--dense.v-text-field--outlined
93
+ > .v-input__control
94
+ > .v-input__slot {
95
+ min-height: 32px !important;
96
+ }
97
+
98
+ .single-slider-selector .v-slider__thumb-label {
99
+ color: black;
100
+ }
101
+ </style>
@@ -0,0 +1,83 @@
1
+ <script setup lang="ts">
2
+ import {computed, defineEmits, ref, unref, watch} from 'vue';
3
+
4
+ export interface Props {
5
+ value: number;
6
+ loading: boolean;
7
+ label: string;
8
+ lower: number;
9
+ upper: number;
10
+ min: number;
11
+ max: number;
12
+ }
13
+
14
+ const props = withDefaults(defineProps<Props>(), {
15
+ value: 0,
16
+ loading: false,
17
+ label: "Test",
18
+ lower: 0,
19
+ upper: 100,
20
+ min: -99999,
21
+ max: 99999,
22
+ });
23
+
24
+ const emit = defineEmits<{
25
+ input: [number];
26
+ }>();
27
+
28
+ const prevValue = ref<number>(0)
29
+ const showThumb = ref<"always" | boolean>(true)
30
+ const showThumbTimeout = ref<number>(0)
31
+ const sliderValue = computed({
32
+ get() {
33
+ return props.value
34
+ },
35
+ set(value: number) {
36
+ emit('input', value);
37
+ }
38
+ })
39
+
40
+ watch(sliderValue, async (currentValue: number) => {
41
+ if (JSON.stringify(unref(prevValue)) !== JSON.stringify(currentValue)) {
42
+ clearTimeout(unref(showThumbTimeout));
43
+ showThumb.value = 'always';
44
+ showThumbTimeout.value = setTimeout(() => {
45
+ showThumb.value = true;
46
+ }, 1000);
47
+ }
48
+ prevValue.value = currentValue;
49
+ }, {deep: true})
50
+
51
+ </script>
52
+
53
+ <template>
54
+ <v-slider
55
+ style="position: absolute; right: 16px; top: 0; height: 100%"
56
+ v-model="sliderValue"
57
+ :thumb-label="showThumb"
58
+ :min="min"
59
+ :max="max"
60
+ height="100%"
61
+ vertical
62
+ hide-details
63
+ class="vertical-slider-selector"
64
+ >
65
+ <template #append>
66
+ <div class="white--text py-1 my-0">{{ max }}</div>
67
+ </template>
68
+ <template #prepend>
69
+ <div class="white--text py-1 my-0">{{ min }}</div>
70
+ </template>
71
+ </v-slider>
72
+ </template>
73
+
74
+ <style lang="scss">
75
+ .vertical-slider-selector .v-slider__thumb-label {
76
+ width: 40px !important;
77
+ height: 40px !important;
78
+ transform: translateY(50%) translateX(-19px) translateX(-100%) rotate(-45deg) !important;
79
+ & div {
80
+ transform: rotate(45deg);
81
+ }
82
+ }
83
+ </style>
@@ -0,0 +1,107 @@
1
+ <template>
2
+ <div id="screenshotWindow" class="" @mouseover="emit('hover', true)" @mouseout="emit('hover', false)">
3
+ <canvas
4
+ id="unity-canvas"
5
+ width="100%"
6
+ height="calc(100vh - 48px)"
7
+ tabindex="-1"
8
+ style="
9
+ width: 100%;
10
+ height: calc(100vh - 50px);
11
+ background: url('~@/assets/images/MainBackdrop.svg') !important;
12
+ background-size: cover !important;
13
+ "
14
+ >
15
+ </canvas>
16
+ <div id="parent-canvas" ref="parent_canvas">
17
+ <slot></slot>
18
+ </div>
19
+ </div>
20
+ </template>
21
+ <script setup lang="ts">
22
+ import {defineEmits, nextTick, onMounted, ref} from 'vue';
23
+
24
+ import { createInstance, executePayload, registerOnPayloadHandler } from '@3cr/sdk-browser';
25
+ import {FrontEndInterfaces, FrontEndPayload} from '@3cr/sdk-browser/types/payload';
26
+
27
+ const emit = defineEmits<{
28
+ instance_loaded: [void];
29
+ on_payload: [FrontEndInterfaces, string, string];
30
+ hover: [boolean];
31
+ }>();
32
+
33
+ defineExpose({
34
+ sendPayload,
35
+ snap,
36
+
37
+ });
38
+
39
+ onMounted(async () => {
40
+ await nextTick()
41
+ const canvas = document.querySelector('#unity-canvas') as HTMLCanvasElement;
42
+
43
+ await registerOnPayloadHandler(receiveMessageFromUnity);
44
+
45
+ if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
46
+ // Mobile device style: fill the whole browser client area with the game canvas:
47
+ const meta = document.createElement('meta');
48
+ meta.name = 'viewport';
49
+ meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
50
+ document.getElementsByTagName('head')[0].appendChild(meta);
51
+
52
+ canvas.style.width = '100%';
53
+ canvas.style.height = '80vh';
54
+ canvas.style.position = 'fixed';
55
+
56
+ document.body.style.textAlign = 'left';
57
+ }
58
+ await nextTick()
59
+ unityInstance.value = await createInstance(canvas);
60
+
61
+ await nextTick()
62
+
63
+ if (navigator.storage && navigator.storage.estimate) {
64
+ const quota = await navigator.storage.estimate();
65
+ if (quota) {
66
+ const percentageUsed = (quota.usage! / quota.quota!) * 100;
67
+ console.log(`You've used ${percentageUsed}% of the available storage.`);
68
+ const remaining = quota.quota! - quota.usage!;
69
+ console.log(`You can write up to ${remaining} more bytes.`);
70
+
71
+ }
72
+ }
73
+ emit('instance_loaded')
74
+ // Overlay scroll events to the container instance
75
+ const fixedDiv = document.getElementById('parent-canvas');
76
+ fixedDiv?.addEventListener('wheel', function (e: WheelEvent) {
77
+ e.preventDefault();
78
+ const evt = new WheelEvent('wheel', {
79
+ deltaY: e.deltaY,
80
+ });
81
+ canvas.dispatchEvent(evt);
82
+ });
83
+ fixedDiv?.addEventListener(
84
+ 'contextmenu',
85
+ function (ev) {
86
+ ev.preventDefault();
87
+ const evt = new MouseEvent('contextmenu', {});
88
+ canvas.dispatchEvent(evt);
89
+ },
90
+ false,
91
+ );
92
+ })
93
+ async function sendPayload(payload: string) {
94
+ await executePayload(JSON.parse(payload));
95
+ }
96
+ function receiveMessageFromUnity(json: FrontEndPayload) {
97
+ emit('on_payload', json.Interface, json.Action, json.Message);
98
+ }
99
+ function snap() {
100
+ }
101
+ // function snapCanvas(canvas: HTMLCanvasElement) {
102
+ // // this.$emit('screenshot', canvas);
103
+ // }
104
+
105
+ const unityInstance = ref<any>(null);
106
+
107
+ </script>
@@ -0,0 +1,86 @@
1
+ import { AnchorPoint, PositionData } from '@3cr/types-ts';
2
+
3
+ import { toNumber } from '@/helpers/utils';
4
+
5
+ export function generateDivStyleForLayout(layout: PositionData) {
6
+ const padding = '0px';
7
+ const canvas = document.getElementById('unity-canvas');
8
+
9
+ const props = {} as any;
10
+
11
+ if (layout.Anchor === AnchorPoint.TOP) {
12
+ props['left'] = '50%';
13
+ props['transform'] = 'translateX(-50%)';
14
+ }
15
+ if (layout.Anchor === AnchorPoint.BOTTOM) {
16
+ props['left'] = '50%';
17
+ props['transform'] = 'translateX(-50%)';
18
+ }
19
+ if (layout.Anchor === AnchorPoint.LEFT) {
20
+ props['top'] = '50%';
21
+ props['transform'] = 'translateY(-50%)';
22
+ }
23
+ if (layout.Anchor === AnchorPoint.RIGHT) {
24
+ props['top'] = '50%';
25
+ props['transform'] = 'translateY(-50%)';
26
+ }
27
+ if (
28
+ layout.Anchor === AnchorPoint.TOP_LEFT ||
29
+ layout.Anchor === AnchorPoint.TOP ||
30
+ layout.Anchor === AnchorPoint.TOP_RIGHT ||
31
+ layout.Anchor === AnchorPoint.CENTER
32
+ ) {
33
+ props['top'] = padding;
34
+ }
35
+ if (
36
+ layout.Anchor === AnchorPoint.LEFT ||
37
+ layout.Anchor === AnchorPoint.BOTTOM_LEFT ||
38
+ layout.Anchor === AnchorPoint.TOP_LEFT ||
39
+ layout.Anchor === AnchorPoint.CENTER
40
+ ) {
41
+ props['left'] = padding;
42
+ }
43
+ if (
44
+ layout.Anchor === AnchorPoint.RIGHT ||
45
+ layout.Anchor === AnchorPoint.TOP_RIGHT ||
46
+ layout.Anchor === AnchorPoint.BOTTOM_RIGHT
47
+ ) {
48
+ props['right'] = padding;
49
+ }
50
+ if (
51
+ layout.Anchor === AnchorPoint.BOTTOM ||
52
+ layout.Anchor === AnchorPoint.BOTTOM_LEFT ||
53
+ layout.Anchor === AnchorPoint.BOTTOM_RIGHT
54
+ ) {
55
+ props['bottom'] = '4px';
56
+ }
57
+ if (layout.Anchor === AnchorPoint.TOP_LEFT || layout.Anchor === AnchorPoint.CENTER) {
58
+ props['border-top-left-radius'] = padding;
59
+ }
60
+ if (layout.Anchor === AnchorPoint.TOP_RIGHT || layout.Anchor === AnchorPoint.CENTER) {
61
+ props['border-top-right-radius'] = padding;
62
+ }
63
+ if (layout.Anchor === AnchorPoint.BOTTOM_LEFT || layout.Anchor === AnchorPoint.CENTER) {
64
+ props['border-bottom-left-radius'] = padding;
65
+ }
66
+ if (layout.Anchor === AnchorPoint.BOTTOM_RIGHT || layout.Anchor === AnchorPoint.CENTER) {
67
+ props['border-bottom-right-radius'] = padding;
68
+ }
69
+
70
+ props['width'] = `calc(${layout.MaxSize.X * 100}% - ${padding})`;
71
+ props['height'] = `calc(${layout.MaxSize.Y * 100}% - ${'2px'})`;
72
+ if (layout.Anchor === AnchorPoint.CENTER) {
73
+ props['width'] = `calc(${layout.MaxSize.X * 100}% - ${padding} - ${padding})`;
74
+ props['height'] = `calc(${layout.MaxSize.Y * 100}% - ${'2px'} - ${'2px'})`;
75
+ }
76
+
77
+ if (layout.AspectRatio === 1) {
78
+ if (layout.MaxSize.X === 1) {
79
+ props['width'] = `calc(${layout.MaxSize.Y * toNumber(canvas?.offsetHeight)}px)`;
80
+ }
81
+ if (layout.MaxSize.Y === 1) {
82
+ props['height'] = `calc(${layout.MaxSize.X * toNumber(canvas?.offsetWidth)}px)`;
83
+ }
84
+ }
85
+ return props;
86
+ }
@@ -0,0 +1,109 @@
1
+ import {AnchorPoint, CurrentScanState, InitialScanState, ScanView, ViewInteractiveMode,} from '@3cr/types-ts';
2
+
3
+ export function inflateScanState(): CurrentScanState {
4
+ return {
5
+ Version: '1.0.0',
6
+ Display: {
7
+ Version: '1.0.0',
8
+ Brightness: 50,
9
+ Contrast: 50,
10
+ Opacity: 50,
11
+ WindowLower: 0,
12
+ WindowUpper: 100,
13
+ ThresholdLower: 0,
14
+ ThresholdUpper: 100,
15
+ },
16
+ CurrentView: ScanView.Volume,
17
+ Slice: {
18
+ Version: '1.0.0',
19
+ TransverseLower: 0,
20
+ TransverseUpper: 0,
21
+ SagittalLower: 0,
22
+ SagittalUpper: 0,
23
+ CoronalLower: 0,
24
+ CoronalUpper: 0,
25
+ },
26
+ InteractionSettings: {
27
+ Version: '1.0.0',
28
+ PanSensivitity: 0,
29
+ ZoomSensitivity: 0,
30
+ RotateSensitivity: 0,
31
+ CameraRotateSensitivity: 0,
32
+ KeyboardEnabled: true,
33
+ MouseEnabled: true,
34
+ InteractionMode: ViewInteractiveMode.STATIC,
35
+ },
36
+ Orientations: {
37
+ Version: '1.0.0',
38
+ Transverse: {
39
+ Version: '1.0.0',
40
+ View: ScanView.Transverse,
41
+ VFlip: false,
42
+ HFlip: false,
43
+ Rotation: 0,
44
+ Slice: 0,
45
+ },
46
+ Sagittal: {
47
+ Version: '1.0.0',
48
+ View: ScanView.Transverse,
49
+ VFlip: false,
50
+ HFlip: false,
51
+ Rotation: 0,
52
+ Slice: 0,
53
+ },
54
+ Coronal: {
55
+ Version: '1.0.0',
56
+ View: ScanView.Transverse,
57
+ VFlip: false,
58
+ HFlip: false,
59
+ Rotation: 0,
60
+ Slice: 0,
61
+ },
62
+ },
63
+ Layout: {
64
+ Version: '1.0.0',
65
+ SwitchOnViewChange: false,
66
+ PositionData: [],
67
+ },
68
+ NavigationCube: {
69
+ Version: '1.0.0',
70
+ Transform: {
71
+ Version: '1.0.0',
72
+ AnchorPoint: AnchorPoint.DEFAULT,
73
+ Position: {
74
+ Version: '1.0.0',
75
+ X: 0,
76
+ Y: 0,
77
+ },
78
+ Size: {
79
+ Version: '1.0.0',
80
+ X: 0,
81
+ Y: 0,
82
+ },
83
+ },
84
+ Visibility: {
85
+ Version: '1.0.0',
86
+ Value: false,
87
+ },
88
+ Interactivity: {
89
+ Version: '1.0.0',
90
+ Value: false,
91
+ },
92
+ },
93
+ };
94
+ }
95
+
96
+ export function inflateInitialScanState(): InitialScanState {
97
+ return {
98
+ Version: '1.0.0',
99
+ XSlices: 0,
100
+ YSlices: 0,
101
+ ZSlices: 0,
102
+ Modality: 'CT',
103
+ HuUpper: 0,
104
+ HuLower: 0,
105
+ DefaultDisplaySettings: inflateScanState(),
106
+ GreyscalePresets: [],
107
+ ColourPresets: [],
108
+ };
109
+ }
@@ -0,0 +1,69 @@
1
+ export interface FrontEndPayload {
2
+ Interface: FrontEndInterfaces;
3
+ Action: FrontEndInterfaces;
4
+ Message: string;
5
+ }
6
+ export enum FrontEndInterfaces {
7
+ scan_loading = 'scan_loading',
8
+ file_management = 'file_management',
9
+ view_selection = 'view_selection',
10
+ layout = 'layout',
11
+ presets = 'presets',
12
+ sliders = 'sliders',
13
+ scan_orientation = 'scan_orientation',
14
+ scan_movement = 'scan_movement',
15
+ interactivity = 'interactivity',
16
+ }
17
+ export enum FrontEndActions {
18
+ pong = 'pong',
19
+ announcement = 'announcement',
20
+ fm02 = 'fm_02',
21
+ }
22
+ export enum FileManagementActions {
23
+ fm01 = 'fm_01',
24
+ fm02 = 'fm_02',
25
+ }
26
+ export enum NotificationActions {
27
+ no01 = 'no_01',
28
+ no02 = 'no_02',
29
+ no03 = 'no_03',
30
+ }
31
+ export enum ScanOrientationActions {
32
+ so01 = 'so_01',
33
+ }
34
+ export enum PresetActions {
35
+ pr01 = 'pr_01',
36
+ pr02 = 'pr_02',
37
+ }
38
+ export enum ScanMovementActions {
39
+ sm01 = 'sm_01',
40
+ sm02 = 'sm_02',
41
+ sm03 = 'sm_03',
42
+ sm04 = 'sm_04',
43
+ sm05 = 'sm_05',
44
+ sm06 = 'sm_06',
45
+ sm07 = 'sm_07',
46
+ sm08 = 'sm_08',
47
+ sm09 = 'sm_09',
48
+ sm10 = 'sm_10',
49
+ sm11 = 'sm_11',
50
+ sm12 = 'sm_12',
51
+ }
52
+ export enum SliderActions {
53
+ sl01 = 'sl_01',
54
+ sl02 = 'sl_02',
55
+ sl03 = 'sl_03',
56
+ sl04 = 'sl_04',
57
+ sl05 = 'sl_05',
58
+ sl06 = 'sl_06',
59
+ sl07 = 'sl_07',
60
+ sl08 = 'sl_08',
61
+ sl09 = 'sl_09',
62
+ sl10 = 'sl_10',
63
+ sl11 = 'sl_11',
64
+ sl12 = 'sl_12',
65
+ sl13 = 'sl_13',
66
+ sl14 = 'sl_14',
67
+ sl15 = 'sl_15',
68
+ sl16 = 'sl_16',
69
+ }
@@ -0,0 +1,16 @@
1
+
2
+ export function toNumber(value: any): number {
3
+ return parseInt((value || 0) + '');
4
+ }
5
+ export function MockRunOnNewThread(callback: () => void) {
6
+ setTimeout(callback, 1);
7
+ }
8
+ export function registerEvents(
9
+ domElement: HTMLElement,
10
+ eventList: Array<string>,
11
+ listener: EventListenerOrEventListenerObject,
12
+ ) {
13
+ for (const event of eventList) {
14
+ domElement.addEventListener(event, listener);
15
+ }
16
+ }
package/src/main.ts ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * main.ts
3
+ *
4
+ * Bootstraps Vuetify and other plugins then mounts the App`
5
+ */
6
+
7
+ // Plugins
8
+ // import { registerPlugins } from '@/plugins'
9
+ import 'material-design-icons-iconfont/dist/material-design-icons.css' // Ensure your project is capable of handling css files
10
+
11
+ // Components
12
+ import App from './App.vue'
13
+ import './types/window.shim';
14
+
15
+ // Composables
16
+ // import { createApp } from 'vue'
17
+ //
18
+ // export const app = createApp(App)
19
+ //
20
+ // registerPlugins(app)
21
+ export { App }
22
+
23
+ // app.mount('#app')
@@ -0,0 +1,3 @@
1
+ # Plugins
2
+
3
+ Plugins are a way to extend the functionality of your Vue application. Use this folder for registering plugins that you want to use globally.
@@ -0,0 +1,15 @@
1
+ /**
2
+ * plugins/index.ts
3
+ *
4
+ * Automatically included in `./src/main.ts`
5
+ */
6
+
7
+ // Plugins
8
+ import vuetify from './vuetify'
9
+
10
+ // Types
11
+ import type { App } from 'vue'
12
+
13
+ export function registerPlugins (app: App) {
14
+ app.use(vuetify)
15
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * plugins/vuetify.ts
3
+ *
4
+ * Framework documentation: https://vuetifyjs.com`
5
+ */
6
+
7
+ // Styles
8
+ import '@mdi/font/css/materialdesignicons.css'
9
+ import 'vuetify/styles'
10
+
11
+ // Composables
12
+ import { createVuetify } from 'vuetify'
13
+ import { aliases, md } from 'vuetify/iconsets/md'
14
+
15
+ // https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
16
+ export default createVuetify({
17
+ theme: {
18
+ defaultTheme: 'dark',
19
+ },
20
+ icons: {
21
+ defaultSet: 'md',
22
+ aliases,
23
+ sets: {
24
+ md,
25
+ },
26
+ },
27
+ })