-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: Sidebar Menu Items Search Functionality #11
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi!
Thanks for your time and effort in this PR. Please check the comments in the Review.
<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('user.index'))" | ||
v-if="can('Acl')" | ||
> | ||
<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="ri-user-fill text-2xl"></i> | ||
</div> | ||
<div> | ||
<p class="mb-2 text-sm font-medium">Users</p> | ||
<p class="text-lg font-semibold"> | ||
{{ props.count['users'] }} | ||
</p> | ||
</div> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please extract to a dedicated DashboardCard.vue Component. Save it in stubs/resources/js/Pages/Dashboard/Components/DashboardCard.vue
. Use this same component for all the 3 cards...
const searchTerm = ref('') | ||
|
||
// Computed property to filter items based on search term | ||
const filteredItems = computed(() => { | ||
if (!searchTerm.value) return props.items | ||
const searchFilter = (item) => { | ||
// Convert search term to lowercase for case-insensitive matching | ||
const term = searchTerm.value.toLowerCase() | ||
|
||
// Check if the label or any child item contains the search term | ||
const matches = (i) => | ||
i.label?.toLowerCase().includes(term) || | ||
(i.children && i.children.some(matches)) // Recursively check children | ||
|
||
return matches(item) | ||
} | ||
|
||
// Filter items recursively | ||
return props.items.filter(searchFilter) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea of a search can be useful. I made some tests and updated it to cover other scenarios so for tests purposes:
resources/js/Configs/menu.js
export default {
// main navigation - side menu
items: [
{
label: 'Dashboard',
permission: 'Dashboard',
icon: 'ri-dashboard-line',
link: route('dashboard.index')
},
{
label: 'Banners',
permission: 'Main Menu: Banners',
children: [
{
label: 'Sections',
permission: 'Main Menu: Banners: Sections - List',
icon: 'ri-landscape-line',
link: route('dashboard.index')
}
]
},
{
label: 'Page',
permission: 'Page',
children: [
{
label: 'Pages',
permission: 'Page: Page - List',
icon: 'ri-draft-line',
link: route('dashboard.index')
}
]
},
{
label: 'Blog',
permission: 'Blog',
children: [
{
label: 'Posts',
permission: 'Blog: Post - List',
icon: 'ri-draft-line',
link: route('dashboard.index')
},
{
label: 'Categories',
permission: 'Blog: Category - List',
icon: 'ri-folders-line',
link: route('dashboard.index')
},
{
label: 'Tags',
permission: 'Blog: Tag - List',
icon: 'ri-price-tag-3-line',
link: route('dashboard.index')
},
{
label: 'Authors',
permission: 'Blog: Author - List',
icon: 'ri-team-line',
link: route('dashboard.index')
}
]
},
{
label: 'Newsletter',
permission: 'Newsletter',
children: [
{
label: 'Newsletter List',
permission: 'Newsletter: List',
icon: 'ri-mail-line',
link: route('dashboard.index')
}
]
},
{
label: 'Access Control List',
permission: 'Acl',
children: [
{
label: 'Users',
permission: 'Acl: User - List',
icon: 'ri-user-line',
link: route('user.index')
},
{
label: 'Permissions',
permission: 'Acl: Permission - List',
icon: 'ri-shield-keyhole-line',
link: route('aclPermission.index')
},
{
label: 'Roles',
permission: 'Acl: Role - List',
icon: 'ri-account-box-line',
link: route('aclRole.index')
}
]
}
]
}
Updated search:
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)
})
Now it will return the expected values for a larger amount of scenarios like:
"Access Control List" => It's a parent node. Return the parent and all childs.
"Posts" => It's a child node. Returns the parent label "Blog" and the searched term "Posts".
Please update to use this concept...
Fix: Created dedicated component for dashboard card
Hello, Thank you for your time to review my PR. I have updated code according to suggestions given above. Please check out. Thanks. |
Thank you @mehedijaman ! |
Implemented a search feature within the sidebar menu to enhance user experience.
Added count cards for Users, Roles, and Permissions in the Dashboard.
Finally the dashboard looks like this -