dont use [...path] routing since it breaks building statically
This commit is contained in:
128
frontend/components/AppBreadcrumbs.vue
Normal file
128
frontend/components/AppBreadcrumbs.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbList,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from '@/components/ui/breadcrumb';
|
||||
import type { BreadcrumbData } from '~/types';
|
||||
const route = useRoute();
|
||||
const store = useWarrenStore();
|
||||
|
||||
const routeCrumbs = computed<BreadcrumbData[]>(() => {
|
||||
if (route.path === '/') {
|
||||
return [{ name: '/', href: '/' }];
|
||||
}
|
||||
|
||||
const rawCrumbs = route.path.split('/');
|
||||
const crumbs: BreadcrumbData[] = [];
|
||||
|
||||
crumbs[0] = {
|
||||
name: '/',
|
||||
href: '/',
|
||||
};
|
||||
for (let i = 1; i < rawCrumbs.length; i++) {
|
||||
crumbs.push({
|
||||
name: rawCrumbs[i],
|
||||
href: rawCrumbs.slice(0, i + 1).join('/'),
|
||||
});
|
||||
}
|
||||
return crumbs;
|
||||
});
|
||||
|
||||
type WarrenBreadcrumbData = {
|
||||
name: string;
|
||||
action: () => void;
|
||||
};
|
||||
|
||||
const warrenCrumbs = computed<WarrenBreadcrumbData[]>(() => {
|
||||
if (store.current == null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const warren = store.warrens[store.current.warrenId];
|
||||
const rawCrumbs = store.current.path.split('/').filter((c) => c.length > 0);
|
||||
const crumbs: WarrenBreadcrumbData[] = [
|
||||
{
|
||||
name: '/',
|
||||
action: async () => {
|
||||
await navigateTo({
|
||||
path: '/',
|
||||
});
|
||||
store.clearCurrentWarren();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'warrens',
|
||||
action: async () => {
|
||||
await navigateTo({
|
||||
path: '/warrens',
|
||||
});
|
||||
store.clearCurrentWarren();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: warren.name,
|
||||
action: () => store.setCurrentWarren(warren.id, '/'),
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < rawCrumbs.length; i++) {
|
||||
const path = rawCrumbs.slice(0, i + 1).join('/');
|
||||
crumbs.push({
|
||||
name: rawCrumbs[i],
|
||||
action: () => store.setCurrentWarrenPath(path),
|
||||
});
|
||||
}
|
||||
return crumbs;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<template v-if="store.current == null">
|
||||
<template v-for="(crumb, i) in routeCrumbs" :key="i">
|
||||
<BreadcrumbItem>
|
||||
<NuxtLink
|
||||
v-if="i < routeCrumbs.length - 1"
|
||||
:to="crumb.href"
|
||||
as-child
|
||||
>
|
||||
<BreadcrumbLink>
|
||||
{{ crumb.name }}
|
||||
</BreadcrumbLink>
|
||||
</NuxtLink>
|
||||
<BreadcrumbPage v-else>{{ crumb.name }}</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator
|
||||
v-if="i < routeCrumbs.length - 1"
|
||||
class="hidden md:block"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
<template
|
||||
v-for="(crumb, i) in warrenCrumbs"
|
||||
v-else-if="route.path.startsWith('/warrens')"
|
||||
:key="i"
|
||||
>
|
||||
<BreadcrumbItem
|
||||
v-if="i < warrenCrumbs.length - 1"
|
||||
class="cursor-pointer"
|
||||
@click="crumb.action"
|
||||
>
|
||||
<BreadcrumbLink>
|
||||
{{ crumb.name }}
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbPage v-else>{{ crumb.name }}</BreadcrumbPage>
|
||||
<BreadcrumbSeparator
|
||||
v-if="i < warrenCrumbs.length - 1"
|
||||
class="hidden md:block"
|
||||
/>
|
||||
</template>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</template>
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
import { deleteWarrenDirectory, deleteWarrenFile } from '~/lib/api/warrens';
|
||||
import type { DirectoryEntry } from '~/types';
|
||||
|
||||
const route = useRoute();
|
||||
const warrenRoute = useWarrenRoute();
|
||||
const warrenStore = useWarrenStore();
|
||||
const renameDialog = useRenameDirectoryDialog();
|
||||
|
||||
const { entry, disabled } = defineProps<{
|
||||
@@ -21,12 +20,25 @@ const { entry, disabled } = defineProps<{
|
||||
const deleting = ref(false);
|
||||
|
||||
async function submitDelete(force: boolean = false) {
|
||||
if (warrenStore.current == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
deleting.value = true;
|
||||
|
||||
if (entry.fileType === 'directory') {
|
||||
await deleteWarrenDirectory(warrenRoute.value, entry.name, force);
|
||||
await deleteWarrenDirectory(
|
||||
warrenStore.current.warrenId,
|
||||
warrenStore.current.path,
|
||||
entry.name,
|
||||
force
|
||||
);
|
||||
} else {
|
||||
await deleteWarrenFile(warrenRoute.value, entry.name);
|
||||
await deleteWarrenFile(
|
||||
warrenStore.current.warrenId,
|
||||
warrenStore.current.path,
|
||||
entry.name
|
||||
);
|
||||
}
|
||||
|
||||
deleting.value = false;
|
||||
@@ -40,32 +52,32 @@ async function openRenameDialog() {
|
||||
<template>
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger>
|
||||
<NuxtLink
|
||||
:to="joinPaths(route.path, entry.name)"
|
||||
<button
|
||||
:class="[
|
||||
'bg-accent/30 border-border flex w-52 flex-row gap-4 rounded-md border-1 px-4 py-2 select-none',
|
||||
'bg-accent/30 border-border flex w-52 flex-row gap-4 overflow-hidden rounded-md border-1 px-4 py-2 select-none',
|
||||
{
|
||||
'pointer-events-none':
|
||||
disabled || entry.fileType === 'file',
|
||||
},
|
||||
]"
|
||||
@click="() => warrenStore.addToCurrentWarrenPath(entry.name)"
|
||||
>
|
||||
<div class="flex flex-row items-center">
|
||||
<Icon class="size-6" :name="getFileIcon(entry.mimeType)" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col gap-0 truncate overflow-hidden leading-6"
|
||||
class="flex w-full flex-col items-start justify-stretch gap-0 overflow-hidden text-left leading-6"
|
||||
>
|
||||
<span>{{ entry.name }}</span>
|
||||
<span class="w-full truncate">{{ entry.name }}</span>
|
||||
<NuxtTime
|
||||
v-if="entry.createdAt != null"
|
||||
:datetime="entry.createdAt * 1000"
|
||||
class="text-muted-foreground text-sm"
|
||||
class="text-muted-foreground w-full truncate text-sm"
|
||||
relative
|
||||
></NuxtTime>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</button>
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuItem @select="openRenameDialog">
|
||||
|
||||
@@ -10,20 +10,28 @@ import {
|
||||
} from '@/components/ui/dialog';
|
||||
import { createDirectory } from '~/lib/api/warrens';
|
||||
|
||||
const warrenRoute = useWarrenRoute();
|
||||
const warrenStore = useWarrenStore();
|
||||
const dialog = useCreateDirectoryDialog();
|
||||
|
||||
const creating = ref(false);
|
||||
const directoryNameValid = computed(() => dialog.value.trim().length > 0);
|
||||
|
||||
async function submit() {
|
||||
if (!directoryNameValid.value || creating.value) {
|
||||
if (
|
||||
!directoryNameValid.value ||
|
||||
creating.value ||
|
||||
warrenStore.current == null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
creating.value = true;
|
||||
|
||||
const { success } = await createDirectory(warrenRoute.value, dialog.value);
|
||||
const { success } = await createDirectory(
|
||||
warrenStore.current.warrenId,
|
||||
warrenStore.current.path,
|
||||
dialog.value
|
||||
);
|
||||
|
||||
creating.value = false;
|
||||
|
||||
|
||||
@@ -9,21 +9,27 @@ import {
|
||||
} from '@/components/ui/dialog';
|
||||
import { renameWarrenEntry } from '~/lib/api/warrens';
|
||||
|
||||
const warrenRoute = useWarrenRoute();
|
||||
const warrenStore = useWarrenStore();
|
||||
const dialog = useRenameDirectoryDialog();
|
||||
|
||||
const renaming = ref(false);
|
||||
const directoryNameValid = computed(() => dialog.value.trim().length > 0);
|
||||
|
||||
async function submit() {
|
||||
if (dialog.entry == null || !directoryNameValid.value || renaming.value) {
|
||||
if (
|
||||
dialog.entry == null ||
|
||||
!directoryNameValid.value ||
|
||||
renaming.value ||
|
||||
warrenStore.current == null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
renaming.value = true;
|
||||
|
||||
const { success } = await renameWarrenEntry(
|
||||
warrenRoute.value,
|
||||
warrenStore.current.warrenId,
|
||||
warrenStore.current.path,
|
||||
dialog.entry.name,
|
||||
dialog.value
|
||||
);
|
||||
|
||||
@@ -16,9 +16,16 @@ import { uploadToWarren } from '~/lib/api/warrens';
|
||||
import { toast } from 'vue-sonner';
|
||||
import UploadListEntry from './UploadListEntry.vue';
|
||||
|
||||
const warrenStore = useWarrenStore();
|
||||
const uploadStore = useUploadStore();
|
||||
|
||||
const warrenRoute = useWarrenRoute();
|
||||
const currentAndUploadRouteMatch = computed(
|
||||
() =>
|
||||
uploadStore.destination != null &&
|
||||
warrenStore.current != null &&
|
||||
uploadStore.destination.warrenId == warrenStore.current.warrenId &&
|
||||
uploadStore.destination.path == warrenStore.current.path
|
||||
);
|
||||
|
||||
const fileInputElement = ref<HTMLInputElement>(
|
||||
null as unknown as HTMLInputElement
|
||||
@@ -28,7 +35,7 @@ const uploading = ref(false);
|
||||
const presentPaths = new Set<string>();
|
||||
|
||||
function onFilesChanged(event: Event) {
|
||||
if (warrenRoute.value == null) {
|
||||
if (warrenStore.current == null) {
|
||||
toast.warning('Upload', {
|
||||
description: 'Enter a warren before attempting to upload files',
|
||||
});
|
||||
@@ -45,9 +52,9 @@ function onFilesChanged(event: Event) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uploadStore.path == null) {
|
||||
uploadStore.path = warrenRoute.value;
|
||||
} else if (uploadStore.path !== warrenRoute.value) {
|
||||
if (uploadStore.destination == null) {
|
||||
uploadStore.destination = warrenStore.current;
|
||||
} else if (currentAndUploadRouteMatch.value) {
|
||||
toast.warning('Upload', {
|
||||
description:
|
||||
'The unfinished items belong to a different directory. Remove them before attempting to upload to a different directory.',
|
||||
@@ -78,7 +85,7 @@ function removeFile(index: number) {
|
||||
presentPaths.delete(file.data.name);
|
||||
|
||||
if (uploadStore.files.length < 1) {
|
||||
uploadStore.path = null;
|
||||
uploadStore.destination = null;
|
||||
uploadStore.progress = null;
|
||||
}
|
||||
}
|
||||
@@ -94,7 +101,7 @@ function clearCompletedFiles() {
|
||||
});
|
||||
|
||||
if (uploadStore.files.length < 1) {
|
||||
uploadStore.path = null;
|
||||
uploadStore.destination = null;
|
||||
uploadStore.progress = null;
|
||||
}
|
||||
}
|
||||
@@ -126,7 +133,7 @@ function updateFileListStatus(loadedBytes: number, ended: boolean = false) {
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (uploadStore.path == null) {
|
||||
if (uploadStore.destination == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +161,8 @@ async function submit() {
|
||||
};
|
||||
|
||||
const { success } = await uploadToWarren(
|
||||
uploadStore.path,
|
||||
uploadStore.destination.warrenId,
|
||||
uploadStore.destination.path,
|
||||
dt.files,
|
||||
(loaded, total) => {
|
||||
if (uploadStore.progress != null) {
|
||||
@@ -192,10 +200,13 @@ async function submit() {
|
||||
<DialogDescription
|
||||
>Upload files to
|
||||
<span class="text-foreground">{{
|
||||
uploadStore.path == null ||
|
||||
warrenRoute === uploadStore.path
|
||||
currentAndUploadRouteMatch ||
|
||||
uploadStore.destination == null
|
||||
? 'the current directory'
|
||||
: routeWithWarrenName(uploadStore.path)
|
||||
: routeWithWarrenName(
|
||||
uploadStore.destination!.warrenId,
|
||||
uploadStore.destination!.path
|
||||
)
|
||||
}}</span></DialogDescription
|
||||
>
|
||||
</DialogHeader>
|
||||
|
||||
Reference in New Issue
Block a user