Skip to content

Commit

Permalink
♻️ [loadingIndicator] update to composition API
Browse files Browse the repository at this point in the history
  • Loading branch information
jxn-30 committed Jul 8, 2023
1 parent 99a7e9d commit fb3de00
Showing 1 changed file with 107 additions and 136 deletions.
243 changes: 107 additions & 136 deletions src/components/LoadingIndicator.vue
Original file line number Diff line number Diff line change
@@ -1,167 +1,138 @@
<template>
<svg
v-show="totalSize"
:height="size"
:width="size"
v-show="requestedFilesSize"
:height="loaderSize"
:width="loaderSize"
:style="`stroke-dasharray: ${strokeDashArray}; stroke-dashoffset: ${strokeDashOffset}`"
:data-total-size="totalSize"
:data-finished-size="finishedSize"
:data-total-size="requestedFilesSize"
:data-finished-size="finishedFilesSize"
:data-pull-up="pageHasBottomNavbar"
>
<circle
:cx="size / 2"
:cy="size / 2"
:r="radius"
:cx="loaderSize / 2"
:cy="loaderSize / 2"
:r="RADIUS"
stroke="#d9534f"
:stroke-width="strokeWidth"
:stroke-width="STROKE_WIDTH"
fill="transparent"
/>
<image
:x="size / 2 - imageWidth / 2"
:y="size / 2 - imageHeight / 2"
:x="loaderSize / 2 - imageWidth / 2"
:y="loaderSize / 2 - imageHeight / 2"
:height="imageHeight"
:width="imageWidth"
:href="lssmLogo"
:href="lssmLogoUrl"
></image>
</svg>
</template>

<script lang="ts">
import Vue from 'vue';
<script setup lang="ts">
import { computed, nextTick, onMounted, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useAPIStore } from '@stores/api';
import { useRootStore } from '@stores/index';
import type { DefaultMethods } from 'vue/types/options';
export default Vue.extend<
{
total: string[];
finished: string[];
fileSizes: Record<string, number>;
radius: number;
strokeWidth: number;
padding: number;
imageHeight: number;
lssmLogo: string;
pageHasBottomNavbar: boolean;
rootStore: ReturnType<typeof useRootStore>;
},
DefaultMethods<Vue>,
{
totalSize: number;
finishedSize: number;
size: number;
strokeDashArray: number;
strokeDashOffset: number;
offsetOneFile: number;
imageWidth: number;
const STORAGE = localStorage;
const STORAGE_KEY = `${PREFIX}-file-sizes-${VERSION}`;
const RADIUS = 20;
const STROKE_WIDTH = 3;
const PADDING = 15;
const rootStore = useRootStore();
const fileSizes = ref<Record<string, number>>(
JSON.parse(STORAGE.getItem(STORAGE_KEY) ?? '{}')
);
const requestedFiles = ref<string[]>([]);
const finishedFiles = ref<string[]>([]);
const pageHasBottomNavbar = ref<boolean>(false);
const { lssmLogoUrl } = storeToRefs(rootStore);
const requestedFilesSize = computed(() =>
requestedFiles.value
.map(chunk => fileSizes.value[chunk])
.reduce((a, b) => a + b, 0)
);
const finishedFilesSize = computed(() =>
finishedFiles.value
.map(chunk => fileSizes.value[chunk])
.reduce((a, b) => a + b, 0)
);
const loaderSize = (RADIUS + STROKE_WIDTH + PADDING) * 2;
const imageHeight = ref<number>(22);
const imageWidth = (RADIUS - STROKE_WIDTH) * 2;
const strokeDashArray = RADIUS * 2 * Math.PI;
const dashOffsetOneFile = computed(
() => strokeDashArray / requestedFilesSize.value
);
const strokeDashOffset = computed(
() => strokeDashArray - dashOffsetOneFile.value * finishedFilesSize.value
);
onMounted(() => {
// clear old cached file-sizes
Object.keys(STORAGE)
.filter(
key =>
key.startsWith(`${PREFIX}-file-sizes-`) && key !== STORAGE_KEY
)
.forEach(key => STORAGE.removeItem(key));
// if there are no file-sizes cached, fetch them
if (Object.values(fileSizes.value).length === 0) {
useAPIStore()
.request({
url: rootStore.lssmUrl('/static/fileSizes.json', true),
feature: 'loading-indicator',
})
.then(res => res.json())
.then(sizes => {
fileSizes.value = sizes;
STORAGE.setItem(STORAGE_KEY, JSON.stringify(fileSizes.value));
});
}
>({
name: 'lssmv4-loading-indicator',
data() {
const rootStore = useRootStore();
return {
total: [],
finished: [],
fileSizes: {},
radius: 20,
strokeWidth: 3,
padding: 15,
imageHeight: 22,
lssmLogo: rootStore.lssmLogoUrl,
pageHasBottomNavbar: !!document.querySelector(
'.navbar.navbar-fixed-bottom:not(#navbar-mobile-footer)'
),
rootStore,
};
},
computed: {
totalSize() {
return this.total
.map(chunk => this.fileSizes[chunk])
.reduce((a, b) => a + b, 0);
},
finishedSize() {
return this.finished
.map(chunk => this.fileSizes[chunk])
.reduce((a, b) => a + b, 0);
},
size() {
return (this.radius + this.padding + this.strokeWidth) * 2;
},
strokeDashArray() {
return this.radius * 2 * Math.PI;
},
strokeDashOffset() {
return (
this.strokeDashArray - this.offsetOneFile * this.finishedSize
);
},
offsetOneFile() {
return this.strokeDashArray / this.totalSize;
},
imageWidth() {
return (this.radius - this.strokeWidth) * 2;
},
},
mounted() {
const fileSizeStorageKey = `${PREFIX}-file-sizes-${VERSION}`;
Object.keys(localStorage)
.filter(
key =>
key.startsWith(`${PREFIX}-file-sizes-`) &&
key !== fileSizeStorageKey
)
.forEach(key => localStorage.removeItem(key));
const storageFileSizes = localStorage.getItem(fileSizeStorageKey);
if (storageFileSizes) {
this.fileSizes = JSON.parse(storageFileSizes);
} else {
useAPIStore()
.request({
url: this.rootStore.lssmUrl('/static/fileSizes.json', true),
feature: 'loading-indicator',
})
.then(res => res.json())
.then(sizes => {
this.fileSizes = sizes;
localStorage.setItem(
fileSizeStorageKey,
JSON.stringify(this.fileSizes)
);
});
}
const img = new Image();
img.addEventListener('load', () => {
const scale = img.width / this.imageWidth;
this.imageHeight = img.height / scale;
});
img.src = this.lssmLogo;
let clearTimeout: number | null = null;
// check if the current page has a bottom navbar
pageHasBottomNavbar.value = !!document.querySelector(
'.navbar.navbar-fixed-bottom:not(#navbar-mobile-footer)'
);
window.addEventListener(LOADSCRIPT_EVENT_START, e => {
if (!(e instanceof CustomEvent)) return;
this.total.push(e.detail.chunkId);
});
window.addEventListener(LOADSCRIPT_EVENT_END, e => {
if (!(e instanceof CustomEvent)) return;
if (this.total.includes(e.detail.chunkId))
this.finished.push(e.detail.chunkId);
// load the image to get the correct height
const img = new Image();
img.addEventListener('load', () => {
const scale = img.width / imageWidth;
imageHeight.value = img.height / scale;
});
img.src = lssmLogoUrl.value;
// reset the total and finished arrays after 1s
let clearTimeout: number | null = null;
// when a script is being loaded, add it to the total array
window.addEventListener(LOADSCRIPT_EVENT_START, e => {
if (!(e instanceof CustomEvent)) return;
requestedFiles.value.push(e.detail.chunkId);
});
// once finished, add the script to the finished array and reset the clearing timer
window.addEventListener(LOADSCRIPT_EVENT_END, e => {
if (!(e instanceof CustomEvent)) return;
if (requestedFiles.value.includes(e.detail.chunkId))
finishedFiles.value.push(e.detail.chunkId);
if (clearTimeout) window.clearTimeout(clearTimeout);
if (this.totalSize === this.finishedSize) {
if (clearTimeout) window.clearTimeout(clearTimeout);
nextTick(() => {
if (requestedFilesSize.value <= finishedFilesSize.value) {
clearTimeout = window.setTimeout(() => {
this.total = [];
this.finished = [];
requestedFiles.value = [];
finishedFiles.value = [];
}, 1000);
}
});
},
});
});
</script>

Expand Down

0 comments on commit fb3de00

Please sign in to comment.