adding some form vue components

This commit is contained in:
Brian 2022-11-28 12:28:41 -07:00
parent e78324e92a
commit 433ad39a08
Signed by: brian
GPG Key ID: DE1A5390A3B84CD8
8 changed files with 292 additions and 0 deletions

View 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">&nbsp;</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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>