mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-27 06:52:35 -04:00

the #shared alias used by Nuxt cannot be easily disabled and to prevent breackage with jiti, we make use of it
164 lines
5.7 KiB
TypeScript
164 lines
5.7 KiB
TypeScript
import { DateTime } from 'luxon';
|
|
import { defineNuxtPlugin, useCookie, useRouter } from 'nuxt/app';
|
|
import type { Pinia } from 'pinia';
|
|
import { decodeTime } from 'ulid';
|
|
|
|
import { LoadScriptError } from '#shared/errors.ts';
|
|
import { useMainStore } from '~/store/index.ts';
|
|
|
|
declare global {
|
|
interface Window {
|
|
fusetag: any;
|
|
}
|
|
}
|
|
|
|
declare module '#app' {
|
|
interface NuxtApp {
|
|
$loadScript(name: string, src: string, nonce?: string, target?: string): Promise<void>;
|
|
$loadStylesheet(name: string, src: string): Promise<void>;
|
|
$datetime(timestamp: number): string;
|
|
$date(timestamp: number): string;
|
|
$ulidTime(ulid: string): number;
|
|
}
|
|
}
|
|
|
|
declare module 'vue' {
|
|
interface ComponentCustomProperties {
|
|
$loadScript(name: string, src: string, nonce?: string, target?: string): Promise<void>;
|
|
$loadStylesheet(name: string, src: string): Promise<void>;
|
|
$datetime(timestamp: number): string;
|
|
$date(timestamp: number): string;
|
|
$ulidTime(ulid: string): number;
|
|
}
|
|
}
|
|
|
|
export default defineNuxtPlugin((nuxtApp) => {
|
|
const store = useMainStore(nuxtApp.$pinia as Pinia);
|
|
const spellingCookie = useCookie('spelling');
|
|
store.setSpelling(spellingCookie.value ?? null);
|
|
const translationsCookie = useCookie<Record<string, string>>('translations');
|
|
store.restoreTranslations(translationsCookie.value);
|
|
const translationModeVisibleCookie = useCookie('translationModeVisible');
|
|
if (translationModeVisibleCookie.value) {
|
|
store.showTranslationMode();
|
|
}
|
|
|
|
const awaitLoadedClass = (node: Element): Promise<void> => {
|
|
return new Promise((resolve) => {
|
|
if (node.classList.contains('loaded')) {
|
|
resolve();
|
|
} else {
|
|
const observer = new MutationObserver((mutations) => {
|
|
mutations.forEach((mutation) => {
|
|
const target = mutation.target as Element;
|
|
if (target.classList.contains('loaded')) {
|
|
observer.disconnect();
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
|
|
observer.observe(node, { attributes: true, attributeFilter: ['class'] });
|
|
}
|
|
});
|
|
};
|
|
|
|
const loadScript = (name: string, src: string, nonce: string | undefined = undefined, target: string | undefined = undefined): Promise<void> => {
|
|
if (!import.meta.client) {
|
|
return new Promise((resolve) => {
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
const existingScriptNode = document.querySelector(`script.${name}-script`);
|
|
if (existingScriptNode) {
|
|
return awaitLoadedClass(existingScriptNode);
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const script = document.createElement('script');
|
|
script.setAttribute('src', src);
|
|
script.async = true;
|
|
if (nonce) {
|
|
script.setAttribute('nonce', nonce);
|
|
}
|
|
script.classList.add(`${name}-script`);
|
|
// script.crossOrigin = 'true'; TODO proper fix (adding it breaks publift)
|
|
script.addEventListener('load', () => {
|
|
script.classList.add('loaded');
|
|
resolve();
|
|
});
|
|
script.addEventListener('error', (event) => {
|
|
script.classList.add('loaded'); // not really loaded, but let's stop other calls from waiting forever, see !493
|
|
reject(new LoadScriptError(name, src, typeof event === 'string' ? event : event.type));
|
|
});
|
|
|
|
let targetNode = target ? document.querySelector(target) : null;
|
|
targetNode = targetNode || document.body;
|
|
|
|
targetNode.appendChild(script);
|
|
});
|
|
};
|
|
|
|
const loadStylesheet = (name: string, src: string): Promise<void> => {
|
|
if (!import.meta.client) {
|
|
return new Promise((resolve) => {
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
const existingLinkNode = document.querySelector(`link.${name}-stylesheet`);
|
|
if (existingLinkNode) {
|
|
return awaitLoadedClass(existingLinkNode);
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const link = document.createElement('link');
|
|
link.setAttribute('rel', 'stylesheet');
|
|
link.setAttribute('href', src);
|
|
link.classList.add(`${name}-stylesheet`);
|
|
link.crossOrigin = 'true';
|
|
link.addEventListener('load', () => {
|
|
link.classList.add('loaded');
|
|
resolve();
|
|
});
|
|
link.addEventListener('error', (event) => {
|
|
link.classList.add('loaded'); // not really loaded, but let's stop other calls from waiting forever, see !493
|
|
reject(new LoadScriptError(name, src, typeof event === 'string' ? event : event.type));
|
|
});
|
|
document.body.appendChild(link);
|
|
});
|
|
};
|
|
|
|
const datetime = (timestamp: number): string => {
|
|
const dt = DateTime.fromSeconds(timestamp);
|
|
return dt.toFormat('y-MM-dd HH:mm');
|
|
};
|
|
|
|
const date = (timestamp: number): string => {
|
|
const dt = DateTime.fromSeconds(timestamp);
|
|
return dt.toFormat('y-MM-dd');
|
|
};
|
|
|
|
const ulidTime = (ulid: string): number => {
|
|
return decodeTime(ulid) / 1000;
|
|
};
|
|
|
|
const router = useRouter();
|
|
router.afterEach(() => {
|
|
if (typeof window !== 'undefined' && window.fusetag && window.fusetag.pageInit) {
|
|
window.fusetag.pageInit();
|
|
}
|
|
});
|
|
|
|
return {
|
|
provide: {
|
|
loadScript,
|
|
loadStylesheet,
|
|
datetime,
|
|
date,
|
|
ulidTime,
|
|
},
|
|
};
|
|
});
|