restyling dashboard layout
This commit is contained in:
@@ -7,7 +7,7 @@ import Icon from '@/Components/Icon.vue'
|
||||
import Swal from 'sweetalert2'
|
||||
import { Inertia } from '@inertiajs/inertia'
|
||||
|
||||
const self = getCurrentInstance()
|
||||
const { open } = defineProps(['open'])
|
||||
const menus = ref(usePage().props.value.$menus || [])
|
||||
const { user } = usePage().props.value
|
||||
|
||||
@@ -44,7 +44,7 @@ const f = async () => {
|
||||
<template>
|
||||
<div class="flex flex-col w-full h-full bg-inherit overflow-auto">
|
||||
<transition name="op" mode="in-out">
|
||||
<Builder v-if="menus.length" :menus="menus" />
|
||||
<Builder v-if="menus.length" :menus="menus" :open="open" />
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,12 +5,13 @@ import Links from "./Links.vue"
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
open: Boolean,
|
||||
menus: Array,
|
||||
},
|
||||
|
||||
setup(props, { attrs }) {
|
||||
return props => {
|
||||
const { menus } = props
|
||||
const { menus, open } = props
|
||||
const padding = (menu, initial = 0) => menu && menu.parent_id !== null ? padding(menu.parent, initial + 8) : initial
|
||||
|
||||
const generate = (menu, attrs = {}) => {
|
||||
@@ -20,12 +21,13 @@ export default defineComponent({
|
||||
padding: padding(menu),
|
||||
menu,
|
||||
childs: menu.childs,
|
||||
open,
|
||||
}, menu.childs.map(child => generate(child, {
|
||||
padding: padding(child)
|
||||
})))
|
||||
}
|
||||
|
||||
return h(Link, { ...attrs, padding: padding(menu), menu })
|
||||
return h(Link, { ...attrs, padding: padding(menu), menu, open, })
|
||||
}
|
||||
|
||||
return h('div', { class: 'flex flex-col' }, menus.map(menu => generate(menu)))
|
||||
|
||||
@@ -6,6 +6,7 @@ import axios from 'axios'
|
||||
|
||||
const { menu } = defineProps({
|
||||
menu: Object,
|
||||
open: Boolean,
|
||||
padding: Number,
|
||||
})
|
||||
|
||||
@@ -52,15 +53,16 @@ onUpdated(fetch)
|
||||
<Link
|
||||
:href="link"
|
||||
:class="`${themes().get('sidebar', 'bg-slate-700 text-gray-200')} ${active && 'bg-slate-800'} pl-${padding !== 0 && padding}`"
|
||||
:title="menu.name"
|
||||
class="w-full px-4 py-3"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center" :class="{ 'justify-between': open, 'justify-center': !open }">
|
||||
<div class="flex items-center space-x-2">
|
||||
<Icon :name="menu.icon" />
|
||||
<p class="uppercase font-semibold">{{ __(menu.name) }}</p>
|
||||
<p v-if="open" class="uppercase font-semibold">{{ __(menu.name) }}</p>
|
||||
</div>
|
||||
|
||||
<div v-if="menu.counter_handler && counter !== null" ref="element" class="flex-none flex items-center justify-center min-w-[1.5rem] min-h-[1.5rem] rounded-full bg-red-500 text-white text-xs p-1 transition-all">
|
||||
<div v-if="open && menu.counter_handler && counter !== null" ref="element" class="flex-none flex items-center justify-center min-w-[1.5rem] min-h-[1.5rem] rounded-full bg-red-500 text-white text-xs p-1 transition-all">
|
||||
<p>{{ counter }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
import { getCurrentInstance, onMounted, onUpdated, ref } from 'vue'
|
||||
import Icon from '@/Components/Icon.vue'
|
||||
|
||||
const { menu, childs } = defineProps({
|
||||
const { menu, childs, open } = defineProps({
|
||||
menu: Object,
|
||||
open: Boolean,
|
||||
childs: Array,
|
||||
padding: Number,
|
||||
})
|
||||
@@ -24,7 +25,7 @@ const trace = menu => {
|
||||
|
||||
const active = childs.find(trace)
|
||||
const self = getCurrentInstance()
|
||||
const open = ref(active ? true : false)
|
||||
const show = ref(open ? (active ? true : false) : false)
|
||||
const fetch = async () => {
|
||||
try {
|
||||
const { data } = await axios.get(route(`superuser.menu.counter`, menu.id))
|
||||
@@ -74,27 +75,31 @@ onUpdated(fetch)
|
||||
<template>
|
||||
<div class="w-full flex flex-col">
|
||||
<button
|
||||
@click.prevent="open = ! open"
|
||||
:class="`${themes().get('sidebar', 'bg-slate-700 text-gray-200')} ${open && 'dark:bg-gray-800'} pl-${padding !== 0 && padding}`"
|
||||
@click.prevent="show = ! show"
|
||||
:class="`${themes().get('sidebar', 'bg-slate-700 text-gray-200')} ${show && 'dark:bg-gray-800'} pl-${padding !== 0 && padding}`"
|
||||
:title="menu.name"
|
||||
class="w-full p-4"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="flex items-center justify-center space-x-2">
|
||||
<Icon :name="menu.icon" />
|
||||
<p class="uppercase font-semibold w-full text-left">{{ __(menu.name) }}</p>
|
||||
|
||||
<div class="flex items-center space-x-2">
|
||||
<div v-if="counter > 0" ref="element" class="flex items-center justify-center bg-red-500 text-white text-center rounded-full p-1">
|
||||
<p class="text-xs">
|
||||
{{ counter }}
|
||||
</p>
|
||||
<template v-if="open">
|
||||
<p class="uppercase font-semibold w-full text-left">{{ __(menu.name) }}</p>
|
||||
|
||||
<div class="flex items-center space-x-2">
|
||||
<div v-if="counter > 0" ref="element" class="flex items-center justify-center bg-red-500 text-white text-center rounded-full p-1">
|
||||
<p class="text-xs">
|
||||
{{ counter }}
|
||||
</p>
|
||||
</div>
|
||||
<Icon name="caret-left" class="transition-all ease-in-out duration-150" :class="show && '-rotate-90'" />
|
||||
</div>
|
||||
<Icon name="caret-left" class="transition-all ease-in-out duration-150" :class="open && '-rotate-90'" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<Transition name="slide-fade" mode="in-out">
|
||||
<div v-if="open" class="flex flex-col" ref="container">
|
||||
<div v-if="show && open" class="flex flex-col" ref="container">
|
||||
<slot />
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
@@ -3,8 +3,8 @@ import Icon from '../Icon.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-none w-14 h-14 p-3">
|
||||
<button @click.prevent="$emit('toggle')" type="button" class="w-full h-full rounded-md border border-gray-600 text-gray-700 transition-all p-1">
|
||||
<div class="flex-none w-14 h-14">
|
||||
<button @click.prevent="$emit('toggle')" type="button" class="w-full h-full text-gray-700 transition-all p-1">
|
||||
<Icon name="bars" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -40,20 +40,20 @@ const logout = async () => {
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div ref="container" class="flex-none flex items-center justify-end sm:justify-between space-x-2 sm:w-full sm:max-w-xs h-14 sm:px-3">
|
||||
<img :src="user.profile_photo_url" :alt="user.name" class="hidden sm:block flex-none rounded-full w-10 h-10">
|
||||
<div ref="container" class="flex-none flex items-center justify-end md:justify-between space-x-2 w-14 md:w-full md:max-w-[15rem] h-14">
|
||||
<img :src="user.profile_photo_url" :alt="user.name" class="hidden md:block flex-none rounded-full w-10 h-10">
|
||||
|
||||
<p class="hidden sm:inline font-semibold lowercase first-letter:capitalize truncate w-full">{{ user.name }}</p>
|
||||
<p class="hidden md:inline font-semibold lowercase first-letter:capitalize truncate w-full">{{ user.name }}</p>
|
||||
|
||||
<div class="flex-none w-14 h-14 p-3">
|
||||
<button @click.prevent="open = ! open" class="rounded-md border border-gray-600 w-full h-full text-gray-700 transition-all ease-in-out duration-150 hover:border-gray-700 hover:text-gray-900">
|
||||
<button @click.prevent="open = ! open" class="rounded-md w-full h-full text-gray-700 transition-all ease-in-out duration-150 hover:border-gray-700 hover:text-gray-900">
|
||||
<Icon name="caret-left" class="transition-all ease-linear duration-500" :class="open && '-rotate-90'" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<transition name="slide">
|
||||
<div v-if="open" class="fixed right-0 sm:right-4 top-12 w-full sm:max-w-xl sm:w-48 bg-white dark:bg-gray-700 rounded-md shadow-xl">
|
||||
<div v-if="open" class="fixed right-0 md:right-4 top-12 w-full md:max-w-xl md:w-48 bg-white dark:bg-gray-700 rounded-md shadow-xl">
|
||||
<Link :href="route('profile.show')" as="button" class="w-full border-l-8 border-transparent dark:hover:border-gray-600 px-4 py-2 rounded-t-md transition-all ease-linear duration-150 hover:bg-gray-200 dark:hover:bg-gray-800">
|
||||
<div class="flex items-center space-x-2 dark:text-white font-semibold">
|
||||
<Icon name="user" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { getCurrentInstance, onMounted, ref } from 'vue'
|
||||
import { getCurrentInstance, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { Head, usePage } from '@inertiajs/inertia-vue3'
|
||||
import Toggler from '@/Components/DashboardLayout/SidebarToggler.vue'
|
||||
import TopbarDropdown from '@/Components/DashboardLayout/TopbarDropdown.vue'
|
||||
@@ -9,16 +9,23 @@ const { title } = defineProps({
|
||||
title: String,
|
||||
})
|
||||
|
||||
const self = getCurrentInstance()
|
||||
const open = ref(window.innerWidth > 669)
|
||||
const { $config } = usePage().props.value
|
||||
const open = ref(Boolean(
|
||||
Number(localStorage.getItem('sidebar_open'))
|
||||
))
|
||||
|
||||
onMounted(() => window.addEventListener('resize', () => open.value = window.innerWidth > 640))
|
||||
watch(open, () => {
|
||||
localStorage.setItem('sidebar_open', Number(open.value))
|
||||
})
|
||||
|
||||
const { user } = usePage().props.value
|
||||
Echo.private(`App.Models.User.${user.id}`)
|
||||
.notification(notification => {
|
||||
console.log(notification)
|
||||
})
|
||||
const q = e => {
|
||||
if (e.key === 'q' && ! (e.target instanceof HTMLInputElement)) {
|
||||
open.value = ! open.value
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => document.addEventListener('keyup', q))
|
||||
onUnmounted(() => document.removeEventListener('keyup', q))
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -30,10 +37,56 @@ Echo.private(`App.Models.User.${user.id}`)
|
||||
.fade-enter-from, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.max-h-sidebar {
|
||||
max-height: calc(100vh - 3.5rem);
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="flex bg-gray-300 dark:bg-gray-900 font-sans w-full h-full">
|
||||
<div class="bg-gray-300 dark:bg-gray-900 font-sans w-full h-full min-h-screen">
|
||||
<div class="sticky top-0 left-0 z-20 flex-none flex justify-between w-full h-14" :class="themes().get('topbar', 'bg-cyan-500 text-gray-700 hover:bg-cyan-600 hover:text-gray-800 transition-all ease-in-out duration-150').replace(/hover:(bg|text)-(.*?)-(\d+)/, '')">
|
||||
<div class="flex items-center justify-between w-14 md:w-64 pl-0 md:pl-6">
|
||||
<h1 class="text-2xl font-bold hidden sm:inline">
|
||||
{{ $config.app.name }}
|
||||
</h1>
|
||||
|
||||
<Toggler @toggle="open = ! open" />
|
||||
</div>
|
||||
|
||||
<div class="md:hidden w-full flex items-center justify-center">
|
||||
<h1 class="text-center text-2xl font-semibold">
|
||||
{{ $config.app.name }}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<TopbarDropdown />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="transition-all duration-300"
|
||||
:class="{
|
||||
'pl-14 md:pl-64': open,
|
||||
'pl-14': !open,
|
||||
}"
|
||||
>
|
||||
<main class="p-6">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="fixed top-14 left-0 transition-all duration-300 h-screen max-h-sidebar z-20 flex flex-col bg-gray-700"
|
||||
:class="{
|
||||
'w-64': open,
|
||||
'w-14': !open,
|
||||
}"
|
||||
>
|
||||
<Sidebar :open="open" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden bg-gray-300 dark:bg-gray-900 font-sans w-full h-full">
|
||||
<Head :title="title" />
|
||||
|
||||
<div ref="sidebar" class="fixed sm:static top-0 left-0 flex-none flex flex-col h-full min-h-screen transition-all ease-in-out duration-300 z-20" :class="`${themes().get('sidebar', 'bg-gray-700 text-gray-200 hover:bg-gray-800 hover:text-gray-100 transition-all ease-in-out duration-100').replace(/hover:(bg|text)-(.*?)-(\d+)/)} ${open ? 'w-full sm:w-60' : 'w-0'}`">
|
||||
|
||||
@@ -46,7 +46,7 @@ const sorted = () => Object.keys(translations).sort().map(key => ({
|
||||
</template>
|
||||
|
||||
<template #body>
|
||||
<div class="flex flex-col space-y-2 p-4 h-screen max-h-96 overflow-auto">
|
||||
<div class="flex flex-col space-y-2 min-h-[30rem] p-4">
|
||||
<TransitionGroup
|
||||
enterActiveClass="transition-all duration-300"
|
||||
leaveActiveClass="transition-all duration-300"
|
||||
|
||||
Reference in New Issue
Block a user