Begin converting to composition api

This commit is contained in:
Dan Elbert 2024-09-29 13:35:49 -05:00
parent b957d44aed
commit a071e6b21e
17 changed files with 574 additions and 612 deletions

2
.gitignore vendored
View File

@ -9,7 +9,7 @@
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
/db/*.sqlite3*
# Ignore all logfiles and tempfiles.
/log/*

View File

@ -9,7 +9,7 @@
<component v-if="!hasError" :is="Component" />
<div v-else>
<h1>Error!</h1>
<p>{{ error }}</p>
<p>{{ appConfig.error }}</p>
</div>
</transition>
</router-view>
@ -18,70 +18,56 @@
</div>
</template>
<script>
import { mapState } from "pinia";
<script setup>
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from "vue";
import { useGlobalTweenGroup } from "../lib/useGlobalTweenGroup";
import { useAppConfigStore } from "../stores/appConfig";
import { useLoadResource } from "../lib/useLoadResource";
import { useCheckAuthentication } from "../lib/useCheckAuthentication";
const globalTweenGroup = useGlobalTweenGroup();
let animationLoop = true;
export default {
data() {
return {
};
},
const appConfig = useAppConfigStore();
const hasError = computed(() => appConfig.error !== null);
computed: {
...mapState(useAppConfigStore, {
hasError: store => store.error !== null,
error: store => store.error,
authChecked: store => store.authChecked,
initialLoad: store => store.initialLoad
})
},
const { loadResource } = useLoadResource();
const { checkAuthentication } = useCheckAuthentication(loadResource);
watch: {
isLoading(val) {
watch(
() => appConfig.initialLoad,
(val) => {
if (val) {
// this.$Progress.start();
} else {
// this.$Progress.finish();
nextTick(() => document.body.classList.remove("loading"));
}
},
{ immediate: true }
);
initialLoad(val) {
if (val) {
this.$nextTick(() => {
document.body.classList.remove("loading");
});
watch(
() => appConfig.isLoading,
(val) => {
// Update Progress
}
}
},
)
created() {
onMounted(() => {
// Setup global animation loop
function animate(time) {
globalTweenGroup.update(time);
function animate() {
if (animationLoop) {
globalTweenGroup.update();
requestAnimationFrame(animate);
}
}
animate();
if (this.user === null && this.authChecked === false) {
this.checkAuthentication();
if (appConfig.user === null && appConfig.authChecked === false) {
checkAuthentication();
}
},
mounted() {
if (this.initialLoad) {
this.$nextTick(() => {
document.body.classList.remove("loading");
});
}
},
components: {
}
}
onUnmounted(() => {
animationLoop = false;
});
</script>

View File

@ -27,12 +27,14 @@
</div>
</template>
<script>
<script setup>
import { computed, ref, watch } from "vue";
import debounce from 'lodash/debounce';
export default {
props: {
const emit = defineEmits(["update:modelValue", "inputClick", "optionSelected"]);
const props = defineProps({
modelValue: String,
id: String,
placeholder: String,
@ -58,163 +60,145 @@
onGetOptions: Function,
searchOptions: Array
},
});
data() {
return {
options: [],
rawValue: "",
isListOpen: false,
activeListIndex: 0
}
},
const options = ref([]);
const rawValue = ref("");
const isListOpen = ref(false);
const activeListIndex = ref(0);
created() {
this.rawValue = this.modelValue;
},
watch: {
modelValue(newValue) {
this.rawValue = newValue;
}
},
computed: {
finalInputClass() {
const finalInputClass = computed(() => {
let cls = ['input'];
if (this.inputClass === null) {
if (props.inputClass === null) {
return cls;
} else if (Array.isArray(this.inputClass)) {
return cls.concat(this.inputClass);
} else if (Array.isArray(props.inputClass)) {
return cls.concat(props.inputClass);
} else {
cls.push(this.inputClass);
cls.push(props.inputClass);
return cls;
}
},
});
debouncedUpdateOptions() {
return debounce(this.updateOptions, this.debounce);
watch(
() => props.modelValue,
(newValue) => { rawValue.value = newValue; },
{ immediate: true }
);
function optionClass(idx) {
return activeListIndex.value === idx ? 'option active' : 'option';
}
},
methods: {
optionClass(idx) {
return this.activeListIndex === idx ? 'option active' : 'option';
},
function optionClick(opt) {
selectOption(opt);
}
optionClick(opt) {
this.selectOption(opt);
},
optionKey(opt) {
if (this.keyAttribute) {
return opt[this.keyAttribute]
} else if (this.valueAttribute) {
return opt[this.valueAttribute];
function optionKey(opt) {
if (props.keyAttribute) {
return opt[props.keyAttribute]
} else if (props.valueAttribute) {
return opt[props.valueAttribute];
} else {
return opt.toString();
}
},
}
optionValue(opt) {
if (this.valueAttribute) {
return opt[this.valueAttribute];
function optionValue(opt) {
if (props.valueAttribute) {
return opt[props.valueAttribute];
} else {
return opt.toString();
}
},
}
optionLabel(opt) {
if (this.labelAttribute) {
return opt[this.labelAttribute];
function optionLabel(opt) {
if (props.labelAttribute) {
return opt[props.labelAttribute];
} else {
return null;
}
},
}
optionMousemove(idx) {
this.activeListIndex = idx;
},
function optionMousemove(idx) {
activeListIndex.value = idx;
}
clickHandler(evt) {
this.$emit("inputClick", evt);
},
function clickHandler(evt) {
emit('inputClick', evt);
}
blurHandler(evt) {
function blurHandler(evt) {
// blur fires before click. If the blur was fired because the user clicked a list item, immediately hiding the list here
// would prevent the click event from firing
setTimeout(() => {
this.isListOpen = false;
isListOpen.value = false;
},250);
},
}
inputHandler(evt) {
function inputHandler(evt) {
const newValue = evt.target.value;
if (this.rawValue !== newValue) {
if (rawValue.value !== newValue) {
this.rawValue = newValue;
rawValue.value = newValue;
this.$emit("update:modelValue", newValue);
emit("update:modelValue", newValue);
if (newValue.length >= Math.max(1, this.minLength)) {
this.debouncedUpdateOptions(newValue);
if (newValue.length >= Math.max(1, props.minLength)) {
this.updateOptions(newValue);
} else {
this.isListOpen = false;
isListOpen.value = false;
}
}
}
},
keydownHandler(evt) {
if (this.isListOpen === false)
function keydownHandler(evt) {
if (isListOpen.value === false)
return;
switch (evt.key) {
case "ArrowUp":
evt.preventDefault();
this.activeListIndex = Math.max(0, this.activeListIndex - 1);
activeListIndex.value = Math.max(0, activeListIndex.value - 1);
break;
case "ArrowDown":
evt.preventDefault();
this.activeListIndex = Math.min(this.options.length - 1, this.activeListIndex + 1);
activeListIndex.value = Math.min(options.value.length - 1, activeListIndex.value + 1);
break;
case "Enter":
evt.preventDefault();
this.selectOption(this.options[this.activeListIndex]);
selectOption(options.value[activeListIndex.value]);
break;
case "Escape":
evt.preventDefault();
this.isListOpen = false;
isListOpen.value = false;
break;
}
},
}
selectOption(opt) {
this.rawValue = this.optionValue(opt);
this.$emit("update:modelValue", this.rawValue);
this.$emit("optionSelected", opt);
this.isListOpen = false;
},
function selectOption(opt) {
rawValue.value = optionValue(opt);
emit("update:modelValue", rawValue.value);
emit("optionSelected", opt);
isListOpen.value = false;
}
updateOptions(value) {
const updateOptions = debounce(function(value) {
let p = null;
if (this.searchOptions) {
if (props.searchOptions) {
const reg = new RegExp("^" + value, "i");
const matcher = o => reg.test(this.optionValue(o));
p = Promise.resolve(this.searchOptions.filter(matcher));
const matcher = o => reg.test(optionValue(o));
p = Promise.resolve(props.searchOptions.filter(matcher));
} else {
p = this.onGetOptions(value)
p = props.onGetOptions(value)
}
p.then(opts => {
this.options = opts;
this.isListOpen = opts.length > 0;
this.activeListIndex = 0;
options.value = opts;
isListOpen.value = opts.length > 0;
activeListIndex.value = 0;
})
}
}
}
}, props.debounce);
</script>

View File

@ -7,10 +7,9 @@
</app-modal>
</template>
<script>
<script setup>
export default {
props: {
const props = defineProps({
cancel: {
type: Function,
required: true
@ -31,17 +30,14 @@
type: Boolean,
required: true
}
},
});
methods: {
runConfirm() {
this.confirm();
},
function runConfirm() {
props.confirm();
}
runCancel() {
this.cancel();
}
}
}
function runCancel() {
props.cancel();
}
</script>

View File

@ -2,12 +2,13 @@
<app-text-field :value="stringValue" @input="input" :label="label" type="date"></app-text-field>
</template>
<script>
<script setup>
import { computed } from "vue";
import DateTimeUtils from "../lib/DateTimeUtils";
export default {
props: {
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
modelValue: {
required: false,
type: [Date, String]
@ -18,21 +19,16 @@
type: String,
default: null
}
},
});
computed: {
stringValue() {
const d = DateTimeUtils.toDate(this.modelValue);
const stringValue = computed(() => {
const d = DateTimeUtils.toDate(props.modelValue);
return DateTimeUtils.formatDateForEdit(d);
}
},
});
methods: {
input(val) {
function input(val) {
let d = DateTimeUtils.toDate(val + " 00:00");
this.$emit("update:modelValue", d);
}
}
emit("update:modelValue", d);
}
</script>

View File

@ -5,12 +5,12 @@
</span>
</template>
<script>
<script setup>
import { computed } from "vue";
import DateTimeUtils from "../lib/DateTimeUtils";
export default {
props: {
const props = defineProps({
dateTime: {
required: true,
type: [Date, String]
@ -33,29 +33,21 @@
type: Boolean,
default: false
}
},
});
computed: {
dateObj() {
return DateTimeUtils.toDate(this.dateTime);
},
const dateObj = computed(() => DateTimeUtils.toDate(props.dateTime));
const fullString = computed(() => DateTimeUtils.formatTimestamp(dateObj.value));
friendlyString() {
const friendlyString = computed(() => {
const parts = [];
if (this.showDate) {
parts.push(DateTimeUtils.formatDate(this.dateObj));
if (props.showDate) {
parts.push(DateTimeUtils.formatDate(dateObj.value));
}
if (this.showTime) {
parts.push(DateTimeUtils.formatTime(this.dateObj, true));
if (props.showTime) {
parts.push(DateTimeUtils.formatTime(dateObj.value, true));
}
return parts.join(" ");
},
fullString() {
return DateTimeUtils.formatTimestamp(this.dateObj);
}
}
}
});
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="dropdown" :class="{'is-active': open, 'is-hoverable': hover}">
<div ref="dropdown" class="dropdown" :class="{'is-active': open, 'is-hoverable': hover}">
<div class="dropdown-trigger">
<slot name="button">
<button type="button" class="button" :class="buttonClass" @click="toggle">
@ -19,10 +19,13 @@
</div>
</template>
<script>
<script setup>
export default {
props: {
import { useTemplateRef } from "vue";
import { onClickOutside } from '@vueuse/core'
const emit = defineEmits(["close", "open"]);
const props = defineProps({
open: {
required: false,
type: Boolean,
@ -45,41 +48,34 @@
required: false,
default: ""
}
},
});
methods: {
toggle() {
if (this.open) {
this.triggerClose();
const dropdownElement = useTemplateRef("dropdown");
onClickOutside(dropdownElement, event => handleOutsideClick(event))
function toggle() {
if (props.open) {
triggerClose();
} else {
this.triggerOpen();
triggerOpen();
}
},
}
triggerOpen() {
this.$emit("open");
},
function triggerOpen() {
emit("open");
}
triggerClose() {
this.$emit("close");
},
function triggerClose() {
emit("close");
}
handleOutsideClick(evt) {
if (this.open) {
if (!this.$el.contains(evt.target)) {
this.triggerClose();
}
}
}
},
mounted() {
document.addEventListener("click", this.handleOutsideClick);
},
beforeDestroy() {
document.removeEventListener("click", this.handleOutsideClick);
function handleOutsideClick(evt) {
if (props.open) {
if (!dropdownElement.value.contains(evt.target)) {
triggerClose();
}
}
}
</script>

View File

@ -9,34 +9,28 @@
</transition>
</template>
<script>
<script setup>
import TWEEN from '@tweenjs/tween.js';
import { useGlobalTweenGroup } from "../lib/useGlobalTweenGroup";
export default {
props: {
const props = defineProps({
expandTime: {
type: Number,
default: 250
}
},
});
data() {
return {
animation: null
let animation = null;
function cancel () {
if (animation) {
animation.stop();
animation = null;
}
},
methods: {
cancel () {
if (this.animation) {
this.animation.stop();
this.animation = null;
}
},
enter(element, done) {
function enter(element, done) {
const width = parseInt(getComputedStyle(element).width);
const paddingTop = parseInt(getComputedStyle(element).paddingTop);
const paddingBottom = parseInt(getComputedStyle(element).paddingBottom);
@ -54,15 +48,15 @@
element.style.overflow = 'hidden';
element.style.height = 0;
this.animation = new TWEEN.Tween({height: 0, paddingTop: 0, paddingBottom: 0})
.to({height: height, paddingTop: paddingTop, paddingBottom: paddingBottom}, this.expandTime)
animation = new TWEEN.Tween({height: 0, paddingTop: 0, paddingBottom: 0})
.to({height: height, paddingTop: paddingTop, paddingBottom: paddingBottom}, props.expandTime)
.onUpdate(obj => {
element.style.height = obj.height + "px";
element.style.paddingBottom = obj.paddingBottom + "px";
element.style.paddingTop = obj.paddingTop + "px";
})
.onComplete(() => {
this.animation = null;
animation = null;
element.removeAttribute('style');
element.style.opacity = 0.99;
setTimeout(() => {
@ -73,32 +67,30 @@
})
.group(useGlobalTweenGroup())
.start();
},
}
leave(element, done) {
function leave(element, done) {
const height = parseInt(getComputedStyle(element).height);
const paddingTop = parseInt(getComputedStyle(element).paddingTop);
const paddingBottom = parseInt(getComputedStyle(element).paddingBottom);
element.style.overflow = 'hidden';
this.animation = new TWEEN.Tween({height: height, paddingTop: paddingTop, paddingBottom: paddingBottom})
.to({height: 0, paddingTop: 0, paddingBottom: 0}, this.expandTime)
animation = new TWEEN.Tween({height: height, paddingTop: paddingTop, paddingBottom: paddingBottom})
.to({height: 0, paddingTop: 0, paddingBottom: 0}, props.expandTime)
.onUpdate(obj => {
element.style.height = obj.height + "px";
element.style.paddingBottom = obj.paddingBottom + "px";
element.style.paddingTop = obj.paddingTop + "px";
})
.onComplete(() => {
this.animation = null;
animation = null;
element.removeAttribute('style');
done();
})
.group(useGlobalTweenGroup())
.start();
}
}
}
</script>

View File

@ -6,6 +6,8 @@
<script>
import { computed } from "vue";
class IconData {
constructor(iconicIcon, dataAttributes) {
this.iconicIcon = iconicIcon;
@ -49,6 +51,7 @@
};
export default {
emits: ["click"],
props: {
icon: {
validator: (i) => iconMap[i] !== undefined
@ -66,38 +69,21 @@
}
},
data() {
setup(props) {
const iconData = computed(() => iconMap[props.icon]);
const sizeData = computed(() => sizeMap[props.size]);
const iconClasses = computed(() => [sizeData.value.bulmaIconClass, sizeData.value.customIconClass]);
const iconicSize = computed(() => sizeData.value.iconicSize);
const iconicIcon = computed(() => iconData.value.iconicIcon);
const iconicAttributes = computed(() => iconData.value.dataAttributes);
return {
injectedSvg: null
}
},
computed: {
iconData() {
return iconMap[this.icon];
},
sizeData() {
return sizeMap[this.size];
},
iconClasses() {
return [
this.sizeData.bulmaIconClass,
this.sizeData.customIconClass
]
},
iconicSize() {
return this.sizeData.iconicSize;
},
iconicIcon() {
return this.iconData.iconicIcon;
},
iconicAttributes() {
return this.iconData.dataAttributes;
iconClasses,
iconData,
sizeData,
iconicAttributes,
iconicIcon,
iconicSize
}
}
}

View File

@ -1,9 +1,11 @@
<template>
<svg v-bind="svgAttributes" v-html="svgContent" :class="calculatedClasses"></svg>
<svg ref="svg" v-bind="svgAttributes" v-html="svgContent" :class="calculatedClasses"></svg>
</template>
<script>
import { computed, nextTick, useTemplateRef, watch } from "vue";
import Caret from "../iconic/svg/smart/caret";
import Check from "../iconic/svg/smart/check";
import CircleCheck from "../iconic/svg/smart/circle-check";
@ -68,29 +70,15 @@
}
},
data() {
return {
calculatedClasses: []
}
},
setup(props) {
const svgElement = useTemplateRef("svg");
const svgData = computed(() => iconMap[props.icon]);
const svgAttributes = computed(() => svgData.value.attributes);
const svgName = computed(() => svgAttributes.value['data-icon']);
const svgContent = computed(() => {
let content = String(svgData.value.content);
computed: {
svgData() {
return iconMap[this.icon];
},
svgAttributes() {
return this.svgData.attributes;
},
svgName() {
return this.svgAttributes['data-icon'];
},
svgContent() {
let content = String(this.svgData.content);
for (let idRep of this.svgData.idReplacements) {
for (let idRep of svgData.value.idReplacements) {
let newId = `__new_id_${globalIdCounter}`;
globalIdCounter += 1;
@ -98,63 +86,66 @@
}
return content;
}
},
});
methods: {
const calculatedClasses = computed(() => {
const classes = (svgAttributes.value.class || "").split(" ");
rebind() {
const apis = APIS;
classes.push(`iconic-${props.size}`);
if (apis && this.svgName && apis[this.svgName]) {
const iconApi = apis[this.svgName](this.$el);
for (let func in iconApi) this.$el[func] = iconApi[func]
} else {
this.$el.update = function() {}
if (props.iconSizeOverride) {
classes.push(`iconic-icon-${props.iconSizeOverride}`);
}
this.calculatedClasses = (this.svgAttributes.class || "").split(" ");
this.calculatedClasses.push(`iconic-${this.size}`);
if (this.iconSizeOverride) {
this.calculatedClasses.push(`iconic-icon-${this.iconSizeOverride}`);
if (props.displaySizeOverride) {
classes.push(`iconic-size-${props.displaySizeOverride}`);
}
if (this.displaySizeOverride) {
this.calculatedClasses.push(`iconic-size-${this.displaySizeOverride}`);
}
return classes;
});
this.$el.update();
}
},
created() {
if (LOADED_APIS[this.svgName] !== true) {
for (let sb of this.svgData.scriptBlocks) {
function ensureSvgApi(name, scripts) {
if (!name) { return; }
if (LOADED_APIS[name] !== true) {
for (let sb of scripts) {
try {
new Function(sb)(window);
} catch (e) {
console.log(sb);
console.log(e);
}
}
LOADED_APIS[name] = true;
}
}
function setupSvgApi(name) {
const apis = APIS;
if (apis && apis[name]) {
const iconApi = apis[name](svgElement.value);
for (let func in iconApi) svgElement.value[func] = iconApi[func]
} else {
svgElement.value.update = function() {}
}
LOADED_APIS[this.svgName] = true;
svgElement.value.update();
}
watch(
() => props.icon,
() => {
ensureSvgApi(svgName.value, svgData.value.scriptBlocks);
nextTick(() => setupSvgApi(svgName.value));
},
mounted() {
this.$watch(
function() { return [this.$attrs, this.icon, this.fluid] },
function() {
this.rebind()
},
{
immediate: true
}
{ immediate: true }
);
return {
svgData,
svgAttributes,
svgName,
svgContent,
calculatedClasses
};
}
}

View File

@ -4,10 +4,7 @@
</div>
</template>
<script>
export default {
}
<script setup>
</script>
<style lang="scss" scoped>

View File

@ -18,15 +18,14 @@
</Teleport>
</template>
<script>
<script setup>
import { mapState } from "pinia";
import { computed } from "vue";
import { useAppConfigStore } from "../stores/appConfig";
export default {
emits: ["dismiss"],
const emit = defineEmits(["dismiss"]);
props: {
const props = defineProps({
open: {
type: Boolean,
default: false
@ -36,22 +35,13 @@
type: Boolean,
default: false
}
},
});
computed: {
...mapState(useAppConfigStore, [
'error'
])
},
const appConfig = useAppConfigStore();
const error = computed(() => appConfig.error);
methods: {
close() {
this.$emit("dismiss");
}
},
components: {
}
function close() {
emit("dismiss");
}
</script>

View File

@ -51,47 +51,27 @@
</nav>
</template>
<script>
<script setup>
import { ref, watch } from "vue";
import UserLogin from "./UserLogin";
import { mapState } from "pinia";
import { storeToRefs } from "pinia";
import { useAppConfigStore } from "../stores/appConfig";
import { swUpdate } from "../lib/ServiceWorker";
import { useRoute } from "vue-router";
export default {
data() {
return {
menuActive: false
};
},
const appConfig = useAppConfigStore();
const menuActive = ref(false);
const route = useRoute();
const { isAdmin, isLoggedIn, updateAvailable, user } = storeToRefs(appConfig);
computed: {
...mapState(useAppConfigStore, [
'route',
'user',
'updateAvailable'
])
},
methods: {
updateApp() {
function updateApp() {
swUpdate();
}
},
watch: {
route() {
this.menuActive = false;
},
user() {
this.menuActive = false;
}
},
components: {
UserLogin
}
}
watch(
() => [route, appConfig.user],
() => menuActive.value = false
);
</script>

View File

@ -0,0 +1,12 @@
import { useAppConfigStore } from "../stores/appConfig";
export function useCheckAuthentication(loadResource) {
const appConfig = useAppConfigStore();
const checkAuthentication = function() {
return loadResource(appConfig.updateCurrentUser());
}
return {
checkAuthentication
}
}

View File

@ -0,0 +1,27 @@
import { computed, ref } from "vue";
import { useAppConfigStore } from "../stores/appConfig";
export function useLoadResource() {
const appConfig = useAppConfigStore();
const localLoadingCount = ref(0);
const localLoading = computed(() => localLoadingCount.value > 0);
const loadResource = async (promise) => {
appConfig.setLoading(true);
localLoadingCount.value = localLoadingCount.value + 1;
try {
return await promise;
} catch (error) {
appConfig.setError(error);
} finally {
appConfig.setLoading(false);
localLoadingCount.value = localLoadingCount.value - 1;
}
};
return {
loadResource,
localLoading,
localLoadingCount
};
}

View File

@ -24,6 +24,7 @@
"@tweenjs/tween.js": "^25.0.0",
"@types/babel__core": "7",
"@types/webpack": "5",
"@vueuse/core": "^11.1.0",
"babel-loader": "8",
"bulma": "^1.0.2",
"cheerio": "^1.0.0",

View File

@ -1895,6 +1895,13 @@ __metadata:
languageName: node
linkType: hard
"@types/web-bluetooth@npm:^0.0.20":
version: 0.0.20
resolution: "@types/web-bluetooth@npm:0.0.20"
checksum: 10c0/3a49bd9396506af8f1b047db087aeeea9fe4301b7fad4fe06ae0f6e00d331138caae878fd09e6410658b70b4aaf10e4b191c41c1a5ff72211fe58da290c7d003
languageName: node
linkType: hard
"@types/webpack@npm:5":
version: 5.28.5
resolution: "@types/webpack@npm:5.28.5"
@ -2038,6 +2045,34 @@ __metadata:
languageName: node
linkType: hard
"@vueuse/core@npm:^11.1.0":
version: 11.1.0
resolution: "@vueuse/core@npm:11.1.0"
dependencies:
"@types/web-bluetooth": "npm:^0.0.20"
"@vueuse/metadata": "npm:11.1.0"
"@vueuse/shared": "npm:11.1.0"
vue-demi: "npm:>=0.14.10"
checksum: 10c0/ecbeb277de81608c78aa4ebc7e4cae8a6d5f0650e2ee5ed71bf387676df4725bd2e8bcfeadcc0798ab6850e6317ff79822ef32adef4646184086764fe7f684ac
languageName: node
linkType: hard
"@vueuse/metadata@npm:11.1.0":
version: 11.1.0
resolution: "@vueuse/metadata@npm:11.1.0"
checksum: 10c0/5063d8b81c31e3c7ea24ff7fad0d0ec43a951540066329f36daf96fc0e8780ed902282d36c6df856288f07d0c5edb525f551cf9e8b84837782e2ac0a1988c498
languageName: node
linkType: hard
"@vueuse/shared@npm:11.1.0":
version: 11.1.0
resolution: "@vueuse/shared@npm:11.1.0"
dependencies:
vue-demi: "npm:>=0.14.10"
checksum: 10c0/ed9a4625537825fe783c66823592560696604f5301e8dcef12dda3a816b85334e7c70ccbaaf1c0c62ea2b8efcce58893b780210162374d2e9bc1e4c5889e066b
languageName: node
linkType: hard
"@webassemblyjs/ast@npm:1.12.1, @webassemblyjs/ast@npm:^1.12.1":
version: 1.12.1
resolution: "@webassemblyjs/ast@npm:1.12.1"
@ -2419,6 +2454,7 @@ __metadata:
"@tweenjs/tween.js": "npm:^25.0.0"
"@types/babel__core": "npm:7"
"@types/webpack": "npm:5"
"@vueuse/core": "npm:^11.1.0"
babel-loader: "npm:8"
bulma: "npm:^1.0.2"
cheerio: "npm:^1.0.0"
@ -6606,7 +6642,7 @@ __metadata:
languageName: node
linkType: hard
"vue-demi@npm:^0.14.10":
"vue-demi@npm:>=0.14.10, vue-demi@npm:^0.14.10":
version: 0.14.10
resolution: "vue-demi@npm:0.14.10"
peerDependencies: