nuxt rewrite

This commit is contained in:
2025-09-25 22:19:06 +02:00
parent ee56a59aef
commit 7cdf77cb52
63 changed files with 395 additions and 11065 deletions

View File

@@ -0,0 +1,37 @@
<template>
<UModal v-bind="$props" title="Add Library">
<template #body>
<div class="flex flex-col gap-2">
<UFormField label="Library Name" required>
<UInput v-model="name" placeholder="Name for the library" class="w-full" :disabled="busy" />
</UFormField>
<UFormField label="Directory Path" required>
<UInput v-model="path" placeholder="Path for the library" class="w-full" :disabled="busy" />
</UFormField>
<UButton icon="i-lucide-plus" @click="onAddClick" :loading="busy">Add</UButton>
</div>
</template>
</UModal>
</template>
<script setup lang="ts">
import type { components } from '#open-fetch-schemas/api';
const name = ref('');
const path = ref('');
const model = computed((): components['schemas']['CreateLibraryRecord'] => {
return { basePath: path.value, libraryName: name.value };
});
const config = useRuntimeConfig();
const busy = ref(false);
const onAddClick = () => {
busy.value = true;
$fetch(new Request(`${config.public.openFetch.api.baseURL}v2/FileLibrary`), { method: 'PUT', body: model.value })
.then(() => emit('change'))
.finally(() => (busy.value = false));
};
const emit = defineEmits(['change']);
</script>

View File

@@ -0,0 +1,31 @@
<template>
<UPageList divide>
<UPageCard
v-for="l in fileLibraries"
variant="ghost"
icon="i-lucide-library-big"
:title="l.libraryName"
:description="l.basePath"
orientation="horizontal">
<UButton color="warning" @click="deleteLibrary(l)" :loading="busy">Delete</UButton>
</UPageCard>
</UPageList>
</template>
<script setup lang="ts">
import type { components } from '#open-fetch-schemas/api';
type FileLibrary = components['schemas']['FileLibrary'];
const { data: fileLibraries, refresh } = useApi('/v2/FileLibrary');
const config = useRuntimeConfig();
const busy = ref(false);
const deleteLibrary = (l: FileLibrary) => {
busy.value = true;
$fetch(new Request(`${config.public.openFetch.api.baseURL}v2/FileLibrary/${l.key}`), { method: 'DELETE' }).finally(
() => {
refresh();
busy.value = false;
}
);
};
</script>

View File

@@ -0,0 +1,48 @@
<template>
<UCard
v-if="!expanded"
:ui="{ body: 'p-0 sm:p-0', root: 'overflow-visible' }"
class="relative h-[350px] mt-2"
@click="$emit('click')">
<MangaCover :manga="manga" blur />
<div class="absolute -top-4 -right-4 flex flex-col bg-pink rounded-full">
<MangaconnectorIcon v-for="m in manga.mangaConnectorIds" v-bind="m" />
</div>
</UCard>
<UCard
v-else
orientation="horizontal"
reverse
class="relative max-w-[600px] w-full h-[350px] mt-2"
:ui="{ body: 'p-0 sm:p-0', root: 'overflow-visible' }"
@click="$emit('click')">
<div class="flex flex-row w-full h-full basis-auto">
<MangaCover :manga="manga" class="shrink-0" />
<div class="absolute -top-4 -right-4 flex flex-col bg-pink rounded-full">
<MangaconnectorIcon v-for="m in manga.mangaConnectorIds" v-bind="m" />
</div>
<div class="flex flex-col h-[350px] shrink mx-2">
<p class="font-semibold text-xl">{{ manga.name }}</p>
<p class="max-h-30 overflow-y-hidden grow">{{ manga.description }}</p>
</div>
</div>
<div class="absolute bottom-0 w-full p-2 flex flex-row justify-end">
<slot name="actions" v-bind="manga" />
</div>
</UCard>
</template>
<script setup lang="ts">
import type { components } from '#open-fetch-schemas/api';
import type { PageCardProps } from '#ui/components/PageCard.vue';
type Manga = components['schemas']['Manga'];
type MinimalManga = components['schemas']['MinimalManga'];
defineProps<MangaCardProps>();
defineEmits(['click']);
export interface MangaCardProps extends PageCardProps {
manga: Manga | MinimalManga;
expanded?: boolean;
}
</script>

View File

@@ -0,0 +1,28 @@
<template>
<div class="relative w-[240px] h-[350px] rounded-lg overflow-clip">
<div
v-if="blur"
class="absolute l-0 t-0 w-full h-full rounded-lg overflow-clip"
style="
background: linear-gradient(150deg, rgba(245, 169, 184, 0.3) 50%, rgba(91, 206, 250, 0.2));
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(2px) brightness(70%);
-webkit-backdrop-filter: blur(2px) brightness(70%);
">
<p class="p-3 text-xl font-semibold max-h-full overflow-clip">{{ manga?.name }}</p>
</div>
<LazyNuxtImg
v-if="manga || mangaId"
:src="`${$config.public.openFetch.api.baseURL}v2/Manga/${manga ? manga.key : mangaId}/Cover/Medium`"
class="w-full h-full object-cover" />
<USkeleton v-else class="w-full h-full object-cover" />
</div>
</template>
<script setup lang="ts">
import type { components } from '#open-fetch-schemas/api';
type Manga = components['schemas']['Manga'];
type MinimalManga = components['schemas']['MinimalManga'];
defineProps<{ manga?: Manga | MinimalManga; mangaId?: string; blur?: boolean }>();
</script>

View File

@@ -0,0 +1,46 @@
<template>
<UPage class="p-4 h-full">
<template #left>
<div class="flex flex-col gap-2 border-r-2 pr-4">
<MangaCover :manga="manga" class="self-center" />
<p v-if="manga" class="font-semibold text-xl">
{{ manga.name }}
<MangaconnectorIcon v-for="m in manga.mangaConnectorIds" v-bind="m" />
</p>
<USkeleton v-else class="text-xl h-20 w-full" />
<div v-if="manga" class="flex flex-row gap-1 flex-wrap">
<UBadge variant="outline" v-for="author in manga.authors" color="neutral">{{ author.name }}</UBadge>
<UBadge variant="outline" v-for="tag in manga.tags">{{ tag }}</UBadge>
<NuxtLink v-for="link in manga.links" :to="link.url">
<UBadge variant="outline" color="warning">{{ link.provider }}</UBadge>
</NuxtLink>
</div>
<USkeleton v-else class="w-full h-lh" />
<p v-if="manga" class="max-h-30 overflow-y-hidden grow">
{{ manga.description }}
</p>
<USkeleton v-else class="w-full h-30" />
</div>
</template>
<UPageBody class="mt-0 relative">
<div>
<UButton variant="soft" to="/" icon="i-lucide-arrow-left">Back</UButton>
<p v-if="title" class="text-3xl">{{ title }}</p>
</div>
<slot />
</UPageBody>
</UPage>
</template>
<script setup lang="ts">
import type { components } from '#open-fetch-schemas/api';
type Manga = components['schemas']['Manga'];
export interface MangaDetailPageProps {
manga?: Manga;
title?: string;
}
defineProps<MangaDetailPageProps>();
</script>

View File

@@ -0,0 +1,25 @@
<template>
<div class="w-6 h-6 inline-block align-middle m-1">
<NuxtLink :href="$props.websiteUrl ?? ''">
<NuxtImg
v-if="mangaConnector"
:src="mangaConnector?.iconUrl"
:class="[
'w-full rounded-full outline-2 -outline-offset-1',
props.useForDownload ? 'outline-green-500' : 'outline-red-500',
]" />
<p v-else>{{ mangaConnectorName }}</p>
</NuxtLink>
</div>
</template>
<script setup lang="ts">
import type { components } from '#open-fetch-schemas/api';
type MangaConnectorId = components['schemas']['MangaConnectorId'];
const props = defineProps<MangaConnectorId>();
const { data: mangaConnector } = useApi('/v2/MangaConnector/{MangaConnectorName}', {
path: { MangaConnectorName: props.mangaConnectorName },
});
</script>