summaryrefslogtreecommitdiffstatshomepage
path: root/frontend/src/lib/Utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/lib/Utils.ts')
-rw-r--r--frontend/src/lib/Utils.ts108
1 files changed, 108 insertions, 0 deletions
diff --git a/frontend/src/lib/Utils.ts b/frontend/src/lib/Utils.ts
new file mode 100644
index 0000000..1a07be1
--- /dev/null
+++ b/frontend/src/lib/Utils.ts
@@ -0,0 +1,108 @@
+import { isError } from '$gql/Utils';
+import type { ImageFragment } from '$gql/graphql';
+import type { BeforeNavigate } from '@sveltejs/kit';
+import type { OperationResultState } from '@urql/svelte';
+import { openModal } from 'svelte-modals';
+import ConfirmDeletion from './dialogs/ConfirmDeletion.svelte';
+
+export function range(from: number, to: number) {
+ return Array.from({ length: to - from + 1 }, (_, k) => k + from);
+}
+
+export function getRandomInt(min: number, max: number) {
+ const minCeiled = Math.ceil(min);
+ const maxFloored = Math.floor(max);
+
+ return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
+}
+
+export interface ListItem {
+ id: number | string;
+ name: string;
+}
+
+export interface ResultState {
+ fetching: boolean;
+ message?: string;
+}
+
+export function getResultState(state: OperationResultState): ResultState {
+ let message: string | undefined;
+
+ if (state.error) {
+ message = `${state.error.name}: ${state.error.message}`;
+ } else if (state.data) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
+ const obj = Object.values(state.data)[0];
+ if (isError(obj)) {
+ message = obj.message;
+ }
+ }
+
+ return { fetching: state.fetching, message: message };
+}
+
+export function src(image: ImageFragment, type: 'full' | 'thumb' = 'thumb') {
+ const dir = image.hash.slice(0, 2);
+ const file = image.hash.slice(2);
+
+ return `/objects/${dir}/${file}_${type}.webp`;
+}
+
+export function numKeys(obj?: object | null, ignore: string[] = []) {
+ if (!obj) return 0;
+
+ const len = Object.keys(obj).length;
+ let ignored = 0;
+
+ for (const i of ignore) {
+ if (Object.hasOwn(obj, i)) ignored++;
+ }
+
+ return len - ignored;
+}
+
+export function confirmDeletion(
+ typename: string,
+ names: string | string[],
+ callback: () => void,
+ warning?: string
+) {
+ openModal(
+ ConfirmDeletion,
+ { names: Array.isArray(names) ? names : [names], typename, callback: callback, warning },
+ { replace: true }
+ );
+}
+
+export function idFromLabel(label: string) {
+ return label.toLowerCase().replaceAll(' ', '-');
+}
+
+export function pluralize(singular: string, size: number) {
+ return `${singular}${size > 1 ? 's' : ''}`;
+}
+
+export function formatListSize(word: string, size: number) {
+ return `${size} ${pluralize(word, size)}`;
+}
+
+export function joinText(items: string[], separator = ', ') {
+ return items.filter((i) => i).join(separator);
+}
+
+export function confirmPending() {
+ return confirm('There are pending changes. Click Cancel to keep editing or OK to dismiss them.');
+}
+
+export function preventOnPending({ to, cancel }: BeforeNavigate, pending: boolean) {
+ if (!pending) return;
+
+ if (to) {
+ if (confirmPending()) {
+ return;
+ }
+ }
+
+ cancel();
+}