Skip to content

Commit

Permalink
Merge pull request #11 from mehedijaman/main
Browse files Browse the repository at this point in the history
Feature: Sidebar Menu Items Search Functionality
  • Loading branch information
daniel-cintra authored Nov 4, 2024
2 parents de2a691 + 7b3f6fe commit ee17911
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 4 deletions.
13 changes: 12 additions & 1 deletion stubs/modules/Dashboard/Http/Controllers/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace Modules\Dashboard\Http\Controllers;

use App\Models\User;
use Inertia\Inertia;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Modules\Support\Http\Controllers\BackendController;

class DashboardController extends BackendController
Expand All @@ -14,6 +17,14 @@ class DashboardController extends BackendController
*/
public function index()
{
return Inertia::render('Dashboard/DashboardIndex');
$count = [
'users' => User::count(),
'permissions' => Permission::count(),
'roles' => Role::count(),
];

return Inertia::render('Dashboard/DashboardIndex', [
'count' => $count
]);
}
}
75 changes: 73 additions & 2 deletions stubs/resources/js/Components/Menu/AppMenu.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,87 @@
<template>
<div>
<ul v-for="(item, index) in items" :key="index">
<li class="mb-2 block">
<div class="rounded-tl rounded-tr">
<label for="search" class="sr-only">Search</label>
<div class="flex items-center align-middle">
<div
class="pointer-events-none absolute flex items-center pl-3"
>
<i class="ri-search-line"></i>
</div>
<AppInputText
id="search"
v-model="searchTerm"
:placeholder="__('Search...')"
class="w-full pl-9"
></AppInputText>

<AppButton
v-if="searchTerm"
class="btn ml-1 border border-skin-neutral-8 bg-skin-neutral-5 hover:bg-skin-neutral-8"
@click="searchTerm = ''"
>
<i class="ri-close-line"></i>
</AppButton>
</div>
</div>
</li>

<ul v-for="(item, index) in filteredItems" :key="index">
<AppMenuSection :item="item" />
</ul>
</div>
</template>

<script setup>
defineProps({
import { ref, computed } from 'vue'
const props = defineProps({
items: {
type: Array,
default: () => []
}
})
const searchTerm = ref('')
// Computed property to filter items based on search term
const filteredItems = computed(() => {
if (!searchTerm.value) return props.items
const term = searchTerm.value.toLowerCase()
// Recursive function to filter items and their children
const filterItems = (items) => {
return items.reduce((acc, item) => {
const isParentMatch = item.label.toLowerCase().includes(term)
let filteredChildren = []
if (item.children) {
if (isParentMatch) {
// If parent matches, include all children
filteredChildren = item.children
} else {
// Else, filter children based on search term
filteredChildren = filterItems(item.children)
}
}
// Include the item if the parent matches or any of its children match
if (
isParentMatch ||
(filteredChildren && filteredChildren.length)
) {
acc.push({
...item,
// If parent matches, include all children; else, include filtered children
children: isParentMatch ? item.children : filteredChildren
})
}
return acc
}, [])
}
return filterItems(props.items)
})
</script>
45 changes: 45 additions & 0 deletions stubs/resources/js/Pages/Dashboard/Components/DashboardCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<template>
<div
class="shadow-xs flex items-center rounded-lg border border-skin-neutral-4 bg-skin-neutral-2 p-4 hover:cursor-pointer hover:bg-skin-neutral-1"
@click="$inertia.visit(route(link))"
>
<div
class="mr-4 rounded-full bg-green-100 px-3 py-2 text-green-500 dark:bg-green-500 dark:text-green-100"
>
<i :class="icon" class="text-2xl"></i>
</div>
<div>
<p class="mb-2 text-sm font-medium">
{{ label }}
</p>
<p class="text-lg font-semibold">
{{ count }}
</p>
</div>
</div>
</template>

<script setup>
import useAuthCan from '@/Composables/useAuthCan'
defineProps({
link: {
type: String,
default: null
},
count: {
type: String,
default: null
},
label: {
type: String,
default: null
},
icon: {
type: String,
default: null
}
})
const { can } = useAuthCan()
</script>
41 changes: 40 additions & 1 deletion stubs/resources/js/Pages/Dashboard/DashboardIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,47 @@
<span class="font-bold">{{ $page.props.auth.user.name }}</span> !
</div>
</div>
</template>

<div class="my-6 grid grid-cols-1 gap-6 md:grid-cols-3">
<!-- User Count Card -->
<DashboardCard
v-if="can('Acl')"
link="user.index"
label="Users"
:count="props.count['users']"
icon="ri-user-fill"
></DashboardCard>

<!-- Role Count Card -->
<DashboardCard
v-if="can('Acl')"
link="aclRole.index"
label="Roles"
:count="props.count['roles']"
icon="ri-user-settings-line"
></DashboardCard>

<!-- Permission Count Card -->
<DashboardCard
v-if="can('Acl')"
link="aclPermission.index"
label="Permissions"
:count="props.count['permissions']"
icon="ri-key-fill"
></DashboardCard>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Head } from '@inertiajs/vue3'
import useAuthCan from '@/Composables/useAuthCan'
import DashboardCard from '@/Pages/Dashboard/Components/DashboardCard.vue'
const { can } = useAuthCan()
const props = defineProps({
count: {
type: Object
}
})
</script>

0 comments on commit ee17911

Please sign in to comment.