Initial commit

This commit is contained in:
2024-03-17 14:07:38 +01:00
commit 22ea1930c4
133 changed files with 24036 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
const links = [{
label: 'Documentation',
icon: 'i-heroicons-book-open',
to: 'https://ui.nuxt.com/getting-started',
}, {
label: 'Pro',
icon: 'i-heroicons-square-3-stack-3d',
to: 'https://ui.nuxt.com/pro',
}, {
label: 'Releases',
icon: 'i-heroicons-rocket-launch',
to: 'https://github.com/nuxt/ui/releases',
target: '_blank',
}]
</script>
<template>
<UHeader :links="links">
<template #logo>
<Logo class="h-6 w-auto" />
</template>
<template #right>
<UColorModeButton />
<UserDropdown />
</template>
<template #panel>
<UNavigationTree :links="links" />
</template>
</UHeader>
</template>

5
nuxt/components/Logo.vue Normal file
View File

@@ -0,0 +1,5 @@
<template>
<div>
<span class="text-primary">Nuxt</span> Breeze
</div>
</template>

View File

@@ -0,0 +1,31 @@
<script setup lang="ts">
const links = [
{
label: 'Company',
icon: 'i-heroicons-building-office-2',
children: [
{
label: 'Overview',
to: '/login',
icon: 'i-heroicons-eye',
},
{
label: 'Add Company',
to: '/login',
icon: 'i-heroicons-plus-circle',
},
],
},
{
label: 'People',
to: '/login',
icon: 'i-heroicons-user-group',
},
]
</script>
<template>
<UContainer>
<UNavigationTree :links="links" />
</UContainer>
</template>

View File

@@ -0,0 +1,28 @@
<script setup lang="ts">
const links = [
{
label: 'Account',
to: '/account',
icon: 'i-heroicons-user-solid',
},
{
label: 'Logout',
to: '/logout',
icon: 'i-heroicons-arrow-left-on-rectangle',
}]
</script>
<template>
<UPopover>
<UButton icon="i-heroicons-user-solid" color="gray" variant="ghost" />
<template #panel>
<div class="p-4">
<UNavigationLinks :links="links" />
</div>
</template>
</UPopover>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,102 @@
<script lang="ts" setup>
const form = ref();
const auth = useAuthStore();
const state = reactive({
current_password: "",
password: "",
password_confirmation: "",
});
const { refresh: onSubmit, status: accountPasswordStatus } = useFetch<any>("account/password", {
method: "POST",
body: state,
immediate: false,
watch: false,
async onResponse({ response }) {
if (response?.status === 422) {
form.value.setErrors(response._data?.errors);
} else if (response._data?.ok) {
useToast().add({
icon: "i-heroicons-check-circle-20-solid",
title: "The password was successfully updated.",
color: "emerald",
});
state.current_password = "";
state.password = "";
state.password_confirmation = "";
}
}
});
const { refresh: sendResetPasswordEmail, status: resetPasswordEmailStatus } = useFetch<any>("verification-notification", {
method: "POST",
body: { email: auth.user.email },
immediate: false,
watch: false,
onResponse({ response }) {
if (response._data?.ok) {
useToast().add({
icon: "i-heroicons-check-circle-20-solid",
title: "A link to reset your password has been sent to your email.",
color: "emerald",
});
}
}
});
</script>
<template>
<div>
<UForm
v-if="auth.user.has_password"
ref="form"
:state="state"
@submit="onSubmit"
class="space-y-4"
>
<UFormGroup label="Current Password" name="current_password" required>
<UInput v-model="state.current_password" type="password" autocomplete="off" />
</UFormGroup>
<UFormGroup
label="New Password"
name="password"
hint="min 8 characters"
:ui="{ hint: 'text-xs text-gray-500 dark:text-gray-400' }"
required
>
<UInput v-model="state.password" type="password" autocomplete="off" />
</UFormGroup>
<UFormGroup label="Repeat Password" name="password_confirmation" required>
<UInput
v-model="state.password_confirmation"
type="password"
autocomplete="off"
/>
</UFormGroup>
<div class="pt-2">
<UButton type="submit" label="Save" :loading="accountPasswordStatus === 'pending'" />
</div>
</UForm>
<UAlert
v-else
icon="i-heroicons-information-circle-20-solid"
title="Send a link to your email to reset your password."
description="To create a password for your account, you must go through the password recovery process."
:actions="[
{
label: 'Send link to Email',
variant: 'solid',
color: 'gray',
loading: resetPasswordEmailStatus === 'pending',
click: sendResetPasswordEmail,
},
]"
/>
</div>
</template>

View File

@@ -0,0 +1,99 @@
<script lang="ts" setup>
const form = ref();
const auth = useAuthStore();
const state = reactive({
...{
email: auth.user.email,
name: auth.user.name,
avatar: auth.user.avatar,
},
});
const { refresh: sendEmailVerification, status: resendEmailStatus } = useFetch<any>("verification-notification", {
method: "POST",
body: { email: state.email },
immediate: false,
watch: false,
onResponse({ response }) {
if (response._data?.ok) {
useToast().add({
icon: "i-heroicons-check-circle-20-solid",
title: response._data.message,
color: "emerald",
});
}
}
});
const { refresh: onSubmit, status: accountUpdateStatus } = useFetch<any>("account/update", {
method: "POST",
body: state,
immediate: false,
watch: false,
async onResponse({ response }) {
if (response?.status === 422) {
form.value.setErrors(response._data?.errors);
} else if (response._data?.ok) {
useToast().add({
icon: "i-heroicons-check-circle-20-solid",
title: "Account details have been successfully updated.",
color: "emerald",
});
await auth.fetchUser();
state.name = auth.user.name;
state.email = auth.user.email;
state.avatar = auth.user.avatar;
}
}
});
</script>
<template>
<UForm ref="form" :state="state" @submit="onSubmit" class="space-y-4">
<UFormGroup label="" name="avatar" class="flex">
<InputUploadAvatar
v-model="state.avatar"
accept=".png, .jpg, .jpeg, .webp"
entity="avatars"
max-size="2"
/>
</UFormGroup>
<UFormGroup label="Name" name="name" required>
<UInput v-model="state.name" type="text" />
</UFormGroup>
<UFormGroup label="Email" name="email" required>
<UInput
v-model="state.email"
placeholder="you@example.com"
icon="i-heroicons-envelope"
trailing
type="email"
/>
</UFormGroup>
<UAlert
v-if="auth.user.must_verify_email"
icon="i-heroicons-information-circle-20-solid"
title="Please confirm your email address."
description="A confirmation email has been sent to your email address. Please click on the confirmation link in the email to verify your email address."
:actions="[
{
label: 'Resend verification email',
variant: 'solid',
color: 'gray',
loading: resendEmailStatus === 'pending',
click: sendEmailVerification,
},
]"
/>
<div class="pt-2">
<UButton type="submit" label="Save" :loading="accountUpdateStatus === 'pending'" />
</div>
</UForm>
</template>

View File

@@ -0,0 +1,115 @@
<script lang="ts" setup>
const props = defineProps(["modelValue", "entity", "accept", "maxSize"]);
const emit = defineEmits(["update:modelValue"]);
const { $storage } = useNuxtApp();
const value = computed({
get() {
return props.modelValue;
},
set(value) {
emit("update:modelValue", value);
},
});
const inputRef = ref();
const loading = ref(false);
const onSelect = async (e: any) => {
const file = e.target.files[0];
e.target.value = null;
if (file.size > props.maxSize * 1024 * 1024) {
return useToast().add({
title: "File is too large.",
color: "red",
icon: "i-heroicons-exclamation-circle-solid",
});
}
loading.value = true;
const formData = new FormData();
formData.append("image", file);
await $fetch<any>("upload", {
method: "POST",
body: formData,
params: {
entity: props.entity,
width: 300,
height: 300,
},
ignoreResponseError: true,
onResponse({ response }) {
if (response.status !== 200) {
useToast().add({
icon: 'i-heroicons-exclamation-circle-solid',
color: 'red',
title: response._data?.message ?? response.statusText ?? 'Something went wrong',
});
} else if (response._data?.ok) {
value.value = response._data?.path;
}
loading.value = false;
},
});
};
</script>
<template>
<div class="flex gap-6">
<div class="relative flex">
<UAvatar
:src="$storage(value)"
size="3xl"
img-class="object-cover"
:ui="{ rounded: 'rounded-lg' }"
/>
<UTooltip
text="Upload avatar"
class="absolute top-0 end-0 -m-2"
:popper="{ placement: 'right' }"
>
<UButton
type="button"
color="gray"
icon="i-heroicons-cloud-arrow-up"
size="2xs"
:ui="{ rounded: 'rounded-full' }"
:loading="loading"
@click="inputRef.click()"
/>
</UTooltip>
<UTooltip
text="Delete avatar"
class="absolute bottom-0 end-0 -m-2"
:popper="{ placement: 'right' }"
>
<UButton
type="button"
color="gray"
icon="i-heroicons-x-mark-20-solid"
size="2xs"
:ui="{ rounded: 'rounded-full' }"
:disabled="loading"
@click="value = ''"
/>
</UTooltip>
<input
ref="inputRef"
type="file"
class="hidden"
:accept="accept"
@change="onSelect"
/>
</div>
<div class="text-sm opacity-80">
<div>Max upload size: {{ maxSize }}Mb</div>
<div>Accepted formats: {{ accept }}</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,18 @@
<script lang="ts" setup>
const modal = useModal()
</script>
<template>
<UModal>
<UCard>
<template #header>
<div class="text-2xl leading-tight font-black">Welcome to LaravelNuxt</div>
</template>
<USkeleton class="w-full h-60" />
<template #footer>
<UButton label="Close" @click="modal.close" color="gray" />
</template>
</UCard>
</UModal>
</template>