diff --git a/.changeset/dry-shoes-prove.md b/.changeset/dry-shoes-prove.md
new file mode 100644
index 0000000..2a0ce53
--- /dev/null
+++ b/.changeset/dry-shoes-prove.md
@@ -0,0 +1,5 @@
+---
+"astro-vtbot": patch
+---
+
+Makes the implementation of `` more robust and adds configuration options for image and position
diff --git a/components/LoadingIndicator.astro b/components/LoadingIndicator.astro
index 38f381b..342d77c 100644
--- a/components/LoadingIndicator.astro
+++ b/components/LoadingIndicator.astro
@@ -1,7 +1,24 @@
---
-export interface Props {}
+export interface Props {
+ top?: string;
+ bottom?: string;
+ left?: string;
+ right?: string;
+ src?: string;
+}
+const { top = '', bottom = '', left = '', right = '', src = '' } = Astro.props;
---
+
+
+
-
diff --git a/components/ProgressBar.astro b/components/ProgressBar.astro
index 7303074..433e100 100644
--- a/components/ProgressBar.astro
+++ b/components/ProgressBar.astro
@@ -15,9 +15,6 @@ export interface Props {}
() => plugin.startShowingProgress(),
() => plugin.stopShowingProgress()
);
-
-
+ // you can style the progressbar by defining the .swup-progress-bar class
+
diff --git a/components/loading-indicator.ts b/components/loading-indicator.ts
index 7ad2efb..af42a9c 100644
--- a/components/loading-indicator.ts
+++ b/components/loading-indicator.ts
@@ -7,54 +7,81 @@ import {
let show: () => void;
let hide: () => void;
-let ownIndicator: boolean = false;
+let initializer: (() => void | Promise) | undefined;
-export function loading(newShow: () => void, newHide: () => void) {
- init(false);
+export function loading(newShow: () => void, newHide: () => void, newInit: () => void = () => {}) {
show = newShow;
hide = newHide;
+ initialize(newInit);
}
-export async function ensureLoadingIndicator() {
+const doShow = () => {
+ document.documentElement.classList.add(`loading`);
+ show && show();
+};
+
+const doHide = () => {
+ document.documentElement.classList.remove(`loading`);
+ hide && hide();
+};
+
+const doInit = () => {
+ initializer && initializer();
+};
+
+export function initialize(onPageLoad?: () => void | Promise, lowPrio = false) {
+ if (!(initializer && lowPrio)) initializer = onPageLoad;
+ document.addEventListener(TRANSITION_PAGE_LOAD, doInit);
+ document.addEventListener(TRANSITION_BEFORE_PREPARATION, doShow);
+ document.addEventListener(TRANSITION_BEFORE_SWAP, doHide);
+}
+
+type Options = { src: string; top: string; bottom: string; left: string; right: string };
+
+export async function vtbotLoadingIndicator(options: Options) {
const loadingIndicator = document.getElementById('vtbot-loading-indicator');
- if (!loadingIndicator) {
- const favicon = (document.querySelector(`link[rel="icon"]:last-of-type`) as HTMLLinkElement)
- ?.href;
- let img: HTMLImageElement | SVGSVGElement | null;
- if (favicon && favicon.endsWith('.svg')) {
+ if (loadingIndicator) return;
+
+ const favicon =
+ (options.src ||
+ (document.querySelector(`link[rel="icon"]:last-of-type`) as HTMLLinkElement)?.href) ??
+ '/favicon.ico';
+
+ let src = '';
+ try {
+ if (!(await fetch(favicon)).ok) throw new Error();
+ } catch (_) {
+ // not ok, or aborted in fetch
+ src =
+ 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"%3E%3Ccircle cx="50" cy="50" r="50" fill="%23888" /%3E%3C/svg%3E';
+ }
+
+ let img: HTMLImageElement | SVGSVGElement | null = null;
+
+ if (!src) {
+ if (favicon?.endsWith('.svg')) {
const response = await fetch(favicon);
const text = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(text, 'image/svg+xml');
img = doc.querySelector('svg');
} else {
- img = document.createElement('img');
- img.src = favicon;
- img.alt = 'Loading indicator';
+ src = favicon;
}
- const div = document.createElement('div');
- div.id = 'vtbot-loading-indicator';
- div.appendChild(img);
- document.body.appendChild(div);
}
-}
-
-const beforePreparation = () => {
- if (!ownIndicator) ensureLoadingIndicator();
- document.documentElement.classList.add(`loading`);
- show && show();
-};
+ if (!img) {
+ img = document.createElement('img');
+ img.src = src;
+ img.alt = 'Loading indicator';
+ }
+ const div = document.createElement('div');
-const beforeSwap = (event: Event) => {
- document.documentElement.classList.remove(`loading`);
- hide && hide();
-};
+ div.style[options.top || !options.bottom ? 'top' : 'bottom'] =
+ options.top || options.bottom || '3vh';
+ div.style[options.right || !options.left ? 'right' : 'left'] =
+ options.right || options.left || '3vw';
-export function init(createIndicator: boolean = false) {
- if (ownIndicator) return;
- ownIndicator = !createIndicator;
- document.addEventListener(TRANSITION_BEFORE_PREPARATION, beforePreparation);
- document.addEventListener(TRANSITION_BEFORE_SWAP, beforeSwap);
- createIndicator && document.addEventListener(TRANSITION_PAGE_LOAD, ensureLoadingIndicator);
- !createIndicator && document.removeEventListener(TRANSITION_PAGE_LOAD, ensureLoadingIndicator);
+ div.id = 'vtbot-loading-indicator';
+ div.appendChild(img!);
+ document.body.appendChild(div);
}
diff --git a/components/template/LoadingIndicatorTemplate_CSS.astro b/components/template/LoadingIndicatorTemplate_CSS.astro
index 910c539..f3fa6ca 100644
--- a/components/template/LoadingIndicatorTemplate_CSS.astro
+++ b/components/template/LoadingIndicatorTemplate_CSS.astro
@@ -3,17 +3,18 @@ import LoadingIndicator from 'astro-vtbot/components/LoadingIndicator.astro';
---
{
- /* By rendering here,
+ /* By rendering here,
you inherit the logic that sets the "loading" CSS class */
}
{
- /* Defining this div is only necessary
+ /* Defining this div is only necessary
if you do not want to use the default element that holds the favicon image */
}