mirror of
https://github.com/Drop-OSS/drop.git
synced 2026-07-27 18:24:43 +10:00
refactor(create collection modal): use ModalTemplate & v-model
This commit is contained in:
@@ -1,118 +1,100 @@
|
|||||||
<template>
|
<template>
|
||||||
<TransitionRoot appear :show="show" as="template">
|
<ModalTemplate v-model="open">
|
||||||
<Dialog as="div" @close="$emit('close')" class="relative z-50">
|
<template #default>
|
||||||
<TransitionChild
|
<DialogTitle as="h3" class="text-lg font-medium leading-6 text-white">
|
||||||
as="template"
|
Create Collection
|
||||||
enter="duration-300 ease-out"
|
</DialogTitle>
|
||||||
enter-from="opacity-0"
|
<div class="mt-2">
|
||||||
enter-to="opacity-100"
|
<input
|
||||||
leave="duration-200 ease-in"
|
type="text"
|
||||||
leave-from="opacity-100"
|
v-model="collectionName"
|
||||||
leave-to="opacity-0"
|
placeholder="Collection name"
|
||||||
>
|
class="block w-full rounded-md border-0 bg-zinc-800 py-1.5 text-white shadow-sm ring-1 ring-inset ring-zinc-700 placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
|
||||||
<div class="fixed inset-0 bg-zinc-950/80" aria-hidden="true" />
|
/>
|
||||||
</TransitionChild>
|
|
||||||
|
|
||||||
<div class="fixed inset-0 overflow-y-auto">
|
|
||||||
<div class="flex min-h-full items-center justify-center p-4 text-center">
|
|
||||||
<TransitionChild
|
|
||||||
as="template"
|
|
||||||
enter="duration-300 ease-out"
|
|
||||||
enter-from="opacity-0 scale-95"
|
|
||||||
enter-to="opacity-100 scale-100"
|
|
||||||
leave="duration-200 ease-in"
|
|
||||||
leave-from="opacity-100 scale-100"
|
|
||||||
leave-to="opacity-0 scale-95"
|
|
||||||
>
|
|
||||||
<DialogPanel class="w-full max-w-md transform overflow-hidden rounded-2xl bg-zinc-900 p-6 text-left align-middle shadow-xl transition-all">
|
|
||||||
<DialogTitle as="h3" class="text-lg font-medium leading-6 text-white">
|
|
||||||
Create Collection
|
|
||||||
</DialogTitle>
|
|
||||||
<div class="mt-2">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="collectionName"
|
|
||||||
placeholder="Collection name"
|
|
||||||
class="block w-full rounded-md border-0 bg-zinc-800 py-1.5 text-white shadow-sm ring-1 ring-inset ring-zinc-700 placeholder:text-zinc-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-4 flex justify-end gap-x-2">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
@click="$emit('close')"
|
|
||||||
class="inline-flex justify-center rounded-md border border-transparent px-4 py-2 text-sm font-medium text-zinc-400 hover:text-zinc-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<LoadingButton
|
|
||||||
:loading="isCreating"
|
|
||||||
:disabled="!collectionName"
|
|
||||||
@click="createCollection"
|
|
||||||
class="inline-flex items-center rounded-md bg-white/10 px-3 py-2 text-sm font-semibold font-display text-white hover:bg-white/20 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
||||||
>
|
|
||||||
Create
|
|
||||||
</LoadingButton>
|
|
||||||
</div>
|
|
||||||
</DialogPanel>
|
|
||||||
</TransitionChild>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</template>
|
||||||
</TransitionRoot>
|
|
||||||
|
<template #buttons="{ close }">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="() => close()"
|
||||||
|
class="inline-flex justify-center rounded-md border border-transparent px-4 py-2 text-sm font-medium text-zinc-400 hover:text-zinc-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<LoadingButton
|
||||||
|
:loading="createCollectionLoading"
|
||||||
|
:disabled="!collectionName"
|
||||||
|
@click="() => createCollection()"
|
||||||
|
class="inline-flex items-center rounded-md bg-white/10 px-3 py-2 text-sm font-semibold font-display text-white hover:bg-white/20 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</LoadingButton>
|
||||||
|
</template>
|
||||||
|
</ModalTemplate>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
import {
|
import {
|
||||||
TransitionRoot,
|
TransitionRoot,
|
||||||
TransitionChild,
|
TransitionChild,
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogPanel,
|
DialogPanel,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@headlessui/vue';
|
} from "@headlessui/vue";
|
||||||
|
import ModalTemplate from "~/drop-base/components/ModalTemplate.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
show: boolean
|
gameId?: string;
|
||||||
gameId?: string
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
close: []
|
created: [collectionId: string];
|
||||||
created: [collectionId: string]
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const collectionName = ref('');
|
const open = defineModel<boolean>();
|
||||||
const isCreating = ref(false);
|
|
||||||
|
const collectionName = ref("");
|
||||||
|
const createCollectionLoading = ref(false);
|
||||||
|
|
||||||
|
async function createCollection() {
|
||||||
|
if (!collectionName.value || createCollectionLoading.value) return;
|
||||||
|
|
||||||
const createCollection = async () => {
|
|
||||||
if (!collectionName.value || isCreating.value) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isCreating.value = true;
|
createCollectionLoading.value = true;
|
||||||
|
|
||||||
// Create the collection
|
// Create the collection
|
||||||
const response = await $fetch('/api/v1/collection', {
|
const response = await $fetch("/api/v1/collection", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
body: { name: collectionName.value }
|
body: { name: collectionName.value },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add the game if provided
|
// Add the game if provided
|
||||||
if (props.gameId) {
|
if (props.gameId) {
|
||||||
await $fetch(`/api/v1/collection/${response.id}/entry`, {
|
await $fetch(`/api/v1/collection/${response.id}/entry`, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
body: { id: props.gameId }
|
body: { id: props.gameId },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset and emit
|
// Reset and emit
|
||||||
collectionName.value = '';
|
collectionName.value = "";
|
||||||
emit('created', response.id);
|
open.value = false;
|
||||||
emit('close');
|
|
||||||
|
emit("created", response.id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to create collection:', error);
|
console.error("Failed to create collection:", error);
|
||||||
|
createModal(
|
||||||
|
ModalType.Notification,
|
||||||
|
{
|
||||||
|
title: "Failed to create collection",
|
||||||
|
description: `Drop couldn't create your collection: ${error}`,
|
||||||
|
},
|
||||||
|
(_, c) => c()
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
isCreating.value = false;
|
createCollectionLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user