adding some form vue components
This commit is contained in:
parent
e78324e92a
commit
433ad39a08
93
src/resources/js/Components/BellNotifications.vue
Normal file
93
src/resources/js/Components/BellNotifications.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { usePage } from '@inertiajs/inertia-vue3'
|
||||
import Dropdown from './Dropdown.vue'
|
||||
import GhostButton from '@/Components/Buttons/GhostButton.vue'
|
||||
import IconBell from '@/Icons/Bell.vue'
|
||||
import Modal from '@/Components/Modals/Modal.vue'
|
||||
|
||||
// variables
|
||||
const notifications = ref(usePage().props.value.notifications)
|
||||
const hasUnreadNotifications = ref(usePage().props.value.unreadNotifications)
|
||||
const showNotification = ref(false)
|
||||
const activeNotification = ref({})
|
||||
|
||||
// methods
|
||||
const openNotification = (notification) => {
|
||||
activeNotification.value = notification
|
||||
showNotification.value = true
|
||||
markActiveAsRead()
|
||||
}
|
||||
|
||||
const closeModal = () => {
|
||||
showNotification.value = false
|
||||
activeNotification.value = {}
|
||||
}
|
||||
|
||||
const markActiveAsRead = () => {
|
||||
axios.post(route('api.notifications.mark-read', activeNotification.value.id))
|
||||
.then(resp => {
|
||||
activeNotification.value.read_at = resp.data.read_at
|
||||
})
|
||||
.catch(erro => {
|
||||
//console.error(erro)
|
||||
})
|
||||
}
|
||||
|
||||
const markAllRead = () => {
|
||||
axios.post(route('api.notifications.mark-all-read'))
|
||||
.then(resp => {
|
||||
let nowDt = new Date()
|
||||
notifications.value.forEach(notification => {
|
||||
if (notification.read_at === null) {
|
||||
notification.read_at = nowDt
|
||||
}
|
||||
})
|
||||
hasUnreadNotifications.value = false
|
||||
})
|
||||
.catch(erro => {
|
||||
//console.error(erro)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dropdown align="right" width="80">
|
||||
<template #trigger>
|
||||
<GhostButton>
|
||||
<IconBell></IconBell>
|
||||
<div v-show="hasUnreadNotifications" class="absolute top-2 right-4 w-3 h-3 z-10 border-2 border-stone-100 bg-red-800 rounded-full"> </div>
|
||||
</GhostButton>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div class="w-full">
|
||||
<div class="grid auto-rows-max gap-y-px bg-stone-400">
|
||||
<template v-for="notification in notifications" :key="notification.id">
|
||||
<div class="px-4 py-2 grid auto-rows-max gap-3 cursor-pointer" :class="{'bg-stone-200': notification.read_at !== null, 'bg-white': notification.read_at === null}" @click="openNotification(notification)">
|
||||
<div>{{ notification.data.title }}</div>
|
||||
<div class="text-xs text-zinc-600">{{ notification.data.created_at_date }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="border-t border-gray-100"></div>
|
||||
|
||||
<div class="px-2">
|
||||
<button class="btn btn-ghost text-xs" @click="markAllRead">Mark All Read</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Dropdown>
|
||||
|
||||
<Modal :show="showNotification" @close="closeModal">
|
||||
<div class="grid auto-rows-max">
|
||||
<header class="bg-sky-800 text-white p-4">{{ activeNotification.data.title }}</header>
|
||||
<div class="p-4 bg-white text-zinc-900">
|
||||
<p class="mb-4">{{ activeNotification.data.body }}</p>
|
||||
|
||||
<p class="text-sm">{{ activeNotification.data.type }} | {{ activeNotification.data.created_at_date }} at {{ activeNotification.data.created_at_time }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
32
src/resources/js/Components/Forms/CheckboxInput.vue
Normal file
32
src/resources/js/Components/Forms/CheckboxInput.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
// variables
|
||||
const emit = defineEmits(['update:checked'])
|
||||
|
||||
const props = defineProps({
|
||||
checked: {
|
||||
type: [Array, Boolean],
|
||||
default: false,
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
})
|
||||
|
||||
// computed properties
|
||||
const proxyChecked = computed({
|
||||
get() {
|
||||
return props.checked
|
||||
},
|
||||
|
||||
set(val) {
|
||||
emit('update:checked', val)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<input type="checkbox" class="checkbox" :value="value" v-model="proxyChecked">
|
||||
</template>
|
9
src/resources/js/Components/Forms/InputError.vue
Normal file
9
src/resources/js/Components/Forms/InputError.vue
Normal file
@ -0,0 +1,9 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
message: String,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p v-show="message" class="px-2 py-1 text-sm text-red-600">{{ message }}</p>
|
||||
</template>
|
20
src/resources/js/Components/Forms/InputLabel.vue
Normal file
20
src/resources/js/Components/Forms/InputLabel.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<script setup>
|
||||
import { useSlots, computed } from 'vue'
|
||||
|
||||
// defines
|
||||
defineProps({
|
||||
value: String,
|
||||
})
|
||||
|
||||
// computed properties
|
||||
const hasActions = computed(() => !! useSlots().actions)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label class="label">
|
||||
<span class="label-text"><slot></slot></span>
|
||||
<span v-show="hasActions" class="flex items-center">
|
||||
<slot name="actions"></slot>
|
||||
</span>
|
||||
</label>
|
||||
</template>
|
28
src/resources/js/Components/Forms/RadioInput.vue
Normal file
28
src/resources/js/Components/Forms/RadioInput.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
// variables
|
||||
const emit = defineEmits(['update:checked'])
|
||||
|
||||
const props = defineProps({
|
||||
checked: {
|
||||
type: [Array, Boolean],
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
// computed properties
|
||||
const proxyChecked = computed({
|
||||
get() {
|
||||
return props.checked
|
||||
},
|
||||
|
||||
set(val) {
|
||||
emit('update:checked', val)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<input type="radio" class="radio" v-model="proxyChecked">
|
||||
</template>
|
28
src/resources/js/Components/Forms/TextInput.vue
Normal file
28
src/resources/js/Components/Forms/TextInput.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
// defines
|
||||
defineEmits(['update:modelValue'])
|
||||
|
||||
defineProps({
|
||||
modelValue: String,
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
focus: () => input.value.focus()
|
||||
})
|
||||
|
||||
// variables
|
||||
const input = ref(null)
|
||||
|
||||
// lifecycle hooks
|
||||
onMounted(() => {
|
||||
if (input.value.hasAttribute('autofocus')) {
|
||||
input.value.focus()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<input ref="input" class="input" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
|
||||
</template>
|
30
src/resources/js/Components/Forms/Textarea.vue
Normal file
30
src/resources/js/Components/Forms/Textarea.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
// defines
|
||||
defineEmits(['update:modelValue'])
|
||||
|
||||
defineProps({
|
||||
modelValue: String,
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
focus: () => input.value.focus()
|
||||
})
|
||||
|
||||
// variables
|
||||
const input = ref(null)
|
||||
|
||||
// lifecycle hooks
|
||||
onMounted(() => {
|
||||
if (input.value.hasAttribute('autofocus')) {
|
||||
input.value.focus()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<textarea ref="input" class="textarea" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
|
||||
<slot></slot>
|
||||
</textarea>
|
||||
</template>
|
52
src/resources/js/Components/LanguageSwitcher.vue
Normal file
52
src/resources/js/Components/LanguageSwitcher.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Inertia } from '@inertiajs/inertia'
|
||||
import { usePage } from '@inertiajs/inertia-vue3'
|
||||
import Dropdown from './DropdownMenu.vue'
|
||||
|
||||
// variables
|
||||
const currentLocale = ref(usePage().props.value.currentLocale)
|
||||
|
||||
// methods
|
||||
const isCurrent = (language) => {
|
||||
return language.iso_code === currentLocale.value.iso_code
|
||||
}
|
||||
|
||||
const changeLocale = (language) => {
|
||||
if (language.iso_code !== currentLocale.value.iso_code) {
|
||||
Inertia.post(route('locale.set'), language, {
|
||||
replace: true,
|
||||
onSuccess: page => {
|
||||
currentLocale.value = page.props.currentLocale
|
||||
},
|
||||
onError: errors => {
|
||||
console.log(errors)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dropdown align="right" width="60">
|
||||
<template #trigger>
|
||||
<div class="py-2 px-4 inline-grid grid-flow-col auto-cols-max gap-x-2 items-center bg-white hover:bg-gray-50 text-sm leading-4 font-medium rounded-md cursor-pointer">
|
||||
<svg class="h-4 w-8">
|
||||
<use :href="`#flag-${currentLocale.iso_code}`"></use>
|
||||
</svg>
|
||||
<span class="ml-2">{{ currentLocale.localized_name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div class="w-60">
|
||||
<button type="button" v-for="(lang, langIdx) in $page.props.availableLocales" :key="langIdx" @click="changeLocale(lang)" class="py-2 px-4 inline-grid grid-flow-col auto-cols-max gap-x-2 items-center w-full" :class="{ 'text-white bg-sky-600 cursor-default': isCurrent(lang), 'hover:bg-sky-600/50': !isCurrent(lang) }">
|
||||
<svg class="h-4 w-8">
|
||||
<use :href="`#flag-${lang.iso_code}`"></use>
|
||||
</svg>
|
||||
<span class="ml-2">{{ lang.localized_name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</Dropdown>
|
||||
</template>
|
Loading…
x
Reference in New Issue
Block a user