diff --git a/README.md b/README.md index 4f92347..25a4126 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This package provides a *DataTables-like* experience for [Inertia.js](https://inertiajs.com/) with support for searching, filtering, sorting, toggling columns, and pagination. It generates URLs that can be consumed by Spatie's excellent [Laravel Query Builder](https://github.com/spatie/laravel-query-builder) package, with no additional logic needed. The components are styled with [Tailwind CSS 3.0](https://tailwindcss.com/), but it's fully customizable with slots. The data refresh logic is based on Inertia's [Ping CRM demo](https://github.com/inertiajs/pingcrm). - +[](https://user-images.githubusercontent.com/8403149/177773377-86c32d69-8f86-47e4-8063-ea227e480d10.mp4) ## Support this package! diff --git a/app/resources/js/Layouts/Guest.vue b/app/resources/js/Layouts/Guest.vue index 16600e8..580a2da 100644 --- a/app/resources/js/Layouts/Guest.vue +++ b/app/resources/js/Layouts/Guest.vue @@ -1,6 +1,6 @@ <template> <div class="min-h-screen flex flex-col items-center bg-gray-100"> - <div class="w-full max-w-7xl mt-6 sm:px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg"> + <div class="w-full max-w-7xl mt-6 sm:px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg dark:bg-gray-800"> <slot /> </div> </div> diff --git a/js/Components/ButtonWithDropdown.vue b/js/Components/ButtonWithDropdown.vue index 46d84dc..ce68811 100644 --- a/js/Components/ButtonWithDropdown.vue +++ b/js/Components/ButtonWithDropdown.vue @@ -6,7 +6,7 @@ type="button" :dusk="dusk" :disabled="disabled" - class="w-full bg-white border rounded-md shadow-sm px-4 py-2 inline-flex justify-center text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" + class="w-full bg-white border rounded-md shadow-sm px-4 py-2 inline-flex justify-center text-sm font-medium text-gray-700 hover:bg-gray-50 focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:hover:bg-gray-600 dark:border-gray-500" :class="{'border-green-300': active, 'border-gray-300': !active, 'cursor-not-allowed': disabled }" aria-haspopup="true" @click.prevent="toggle" @@ -19,7 +19,7 @@ ref="tooltip" class="absolute z-10" > - <div class="mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5"> + <div class="mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 dark:bg-gray-700"> <slot /> </div> </div> diff --git a/js/Components/Pagination.vue b/js/Components/Pagination.vue index 5e4d9c4..08b030d 100644 --- a/js/Components/Pagination.vue +++ b/js/Components/Pagination.vue @@ -1,7 +1,7 @@ <template> <nav v-if="hasPagination" - class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6" + class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6 dark:bg-gray-500 dark:border-gray-400 dark:text-gray-100" > <p v-if="!hasData || pagination.total < 1"> {{ translations.no_results_found }} @@ -88,7 +88,7 @@ :on-change="onPerPageChange" /> - <p class="hidden lg:block text-sm text-gray-700 flex-grow"> + <p class="hidden lg:block text-sm text-gray-700 flex-grow dark:text-gray-100"> <span class="font-medium">{{ pagination.from }}</span> {{ translations.to }} <span class="font-medium">{{ pagination.to }}</span> @@ -105,12 +105,12 @@ <component :is="previousPageUrl ? 'a' : 'div'" :class="{ - 'cursor-not-allowed text-gray-400': !previousPageUrl, - 'text-gray-500 hover:bg-gray-50': previousPageUrl + 'cursor-not-allowed text-gray-400 dark:bg-gray-700 dark:text-gray-500': !previousPageUrl, + 'text-gray-500 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-400 dark:hover:bg-gray-600': previousPageUrl }" :href="previousPageUrl" :dusk="previousPageUrl ? 'pagination-previous' : null" - class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium" + class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium dark:border-gray-500" @click.prevent="onClick(previousPageUrl)" > <span class="sr-only">{{ translations.previous }}</span> @@ -140,11 +140,11 @@ " :href="link.url" :dusk="link.url ? `pagination-${link.label}` : null" - class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700" + class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 dark:bg-gray-700 dark:text-gray-100 dark:border-gray-500 dark:hover:bg-gray-500" :class="{ 'cursor-not-allowed': !link.url, 'hover:bg-gray-50': link.url, - 'bg-gray-100': link.active, + 'bg-gray-100 dark:bg-blue-500 dark:hover:bg-blue-400': link.active, }" @click.prevent="onClick(link.url)" > @@ -156,12 +156,12 @@ <component :is="nextPageUrl ? 'a' : 'div'" :class="{ - 'cursor-not-allowed text-gray-400': !nextPageUrl, - 'text-gray-500 hover:bg-gray-50': nextPageUrl + 'cursor-not-allowed text-gray-400 dark:bg-gray-700 dark:text-gray-500': !nextPageUrl, + 'text-gray-500 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-400 dark:hover:bg-gray-600': nextPageUrl }" :href="nextPageUrl" :dusk="nextPageUrl ? 'pagination-next' : null" - class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium" + class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium dark:border-gray-500" @click.prevent="onClick(nextPageUrl)" > <span class="sr-only">{{ translations.next }}</span> diff --git a/js/Components/PerPageSelector.vue b/js/Components/PerPageSelector.vue index 4bbfb66..483da1a 100644 --- a/js/Components/PerPageSelector.vue +++ b/js/Components/PerPageSelector.vue @@ -3,7 +3,7 @@ name="per_page" :dusk="dusk" :value="value" - class="block focus:ring-indigo-500 focus:border-indigo-500 min-w-max shadow-sm text-sm border-gray-300 rounded-md" + class="block focus:ring-indigo-500 focus:border-indigo-500 min-w-max shadow-sm text-sm border-gray-300 rounded-md dark:bg-gray-700 dark:text-gray-100 dark:border-gray-500" @change="onChange($event.target.value)" > <option diff --git a/js/Components/Table.vue b/js/Components/Table.vue index 456dd65..bd6c6a3 100644 --- a/js/Components/Table.vue +++ b/js/Components/Table.vue @@ -8,7 +8,7 @@ :class="{'opacity-75': isVisiting}" > <div class="flex flex-row flex-wrap sm:flex-nowrap justify-start px-4 sm:px-0"> - <div class="order-2 sm:order-1 mr-2 sm:mr-4"> + <div v-if="queryBuilderProps.hasFilters" class="order-2 sm:order-1 mr-2 sm:mr-4"> <slot name="tableFilter" :has-filters="queryBuilderProps.hasFilters" @@ -46,19 +46,14 @@ </slot> </div> - - <slot - name="tableReset" - can-be-reset="canBeReset" - :on-click="resetQuery" + <div + v-if="canBeReset" + class="order-5 sm:order-3 sm:mr-4 ml-auto" > - <div - v-if="canBeReset" - class="order-5 sm:order-3 sm:mr-4 ml-auto" - > + <slot name="tableReset" :on-click="resetQuery"> <TableReset :on-click="resetQuery" /> - </div> - </slot> + </slot> + </div> <slot name="tableAddSearchRow" @@ -115,7 +110,7 @@ > <TableWrapper :class="{ 'mt-3': !hasOnlyData }"> <slot name="table"> - <table class="min-w-full divide-y divide-gray-200 bg-white"> + <table class="min-w-full divide-y divide-gray-200 bg-white dark:divide-gray-400"> <thead class="bg-gray-50"> <slot name="head" @@ -123,7 +118,7 @@ :sort-by="sortBy" :header="header" > - <tr class="font-medium text-xs uppercase text-left tracking-wider text-gray-500 py-3 px-6"> + <tr class="font-medium text-xs uppercase text-left tracking-wider text-gray-500 py-3 px-6 dark:bg-gray-500 dark:text-gray-100"> <HeaderCell v-for="column in queryBuilderProps.columns" :key="`table-${name}-header-${column.key}`" @@ -133,7 +128,7 @@ </slot> </thead> - <tbody class="bg-white divide-y divide-gray-200"> + <tbody class="bg-white divide-y divide-gray-200 dark:bg-gray-600 dark:divide-gray-400"> <slot name="body" :show="show" @@ -143,16 +138,16 @@ :key="`table-${name}-row-${key}`" class="" :class="{ - 'bg-gray-50': striped && key % 2, - 'hover:bg-gray-100': striped, - 'hover:bg-gray-50': !striped + 'bg-gray-50 dark:bg-gray-500': striped && key % 2, + 'hover:bg-gray-100 dark:hover:bg-gray-400': striped, + 'hover:bg-gray-50 dark:hover:bg-gray-500': !striped }" > <td v-for="column in queryBuilderProps.columns" v-show="show(column.key)" :key="`table-${name}-row-${key}-column-${column.key}`" - class="text-sm py-4 px-6 text-gray-500 whitespace-nowrap" + class="text-sm py-4 px-6 text-gray-500 whitespace-nowrap dark:text-gray-100" > <slot :name="`cell(${column.key})`" diff --git a/js/Components/TableAddSearchRow.vue b/js/Components/TableAddSearchRow.vue index fc3ebd5..2e0718c 100644 --- a/js/Components/TableAddSearchRow.vue +++ b/js/Components/TableAddSearchRow.vue @@ -31,7 +31,7 @@ v-for="(searchInput, key) in searchInputs" :key="key" :dusk="`add-search-row-${searchInput.key}`" - class="text-left w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900" + class="text-left w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:bg-gray-600 dark:hover:text-gray-100 rounded-md" role="menuitem" @click.prevent="enableSearch(searchInput.key)" > diff --git a/js/Components/TableColumns.vue b/js/Components/TableColumns.vue index f762e1d..71f5c6a 100644 --- a/js/Components/TableColumns.vue +++ b/js/Components/TableColumns.vue @@ -31,7 +31,7 @@ class="min-w-max" > <div class="px-2"> - <ul class="divide-y divide-gray-200"> + <ul class="divide-y divide-gray-200 dark:divide-gray-500"> <li v-for="(column, key) in props.columns" v-show="column.can_be_hidden" @@ -39,14 +39,14 @@ class="py-2 flex items-center justify-between" > <p - class="text-sm text-gray-900" + class="text-sm text-gray-900 dark:text-gray-100" > {{ column.label }} </p> <button type="button" - class="ml-4 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-light-blue-500" + class="ml-4 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-light-blue-500" :class="{ 'bg-green-500': !column.hidden, 'bg-gray-200': column.hidden, diff --git a/js/Components/TableFilter.vue b/js/Components/TableFilter.vue index 8d5c87c..aa5f5d7 100644 --- a/js/Components/TableFilter.vue +++ b/js/Components/TableFilter.vue @@ -32,8 +32,9 @@ <div v-for="(filter, key) in filters" :key="key" + class="rounded-md dark:bg-gray-700" > - <h3 class="text-xs uppercase tracking-wide bg-gray-100 p-3"> + <h3 class="text-xs uppercase tracking-wide bg-gray-100 p-3 dark:text-gray-100 dark:bg-gray-700 dark:rounded-md"> {{ filter.label }} </h3> <div class="p-2"> @@ -41,7 +42,7 @@ v-if="filter.type === 'select'" :name="filter.key" :value="filter.value" - class="block focus:ring-indigo-500 focus:border-indigo-500 w-full shadow-sm text-sm border-gray-300 rounded-md" + class="block focus:ring-indigo-500 focus:border-indigo-500 w-full shadow-sm text-sm border-gray-300 rounded-md dark:bg-gray-600 dark:text-gray-100 dark:border-gray-500" @change="onFilterChange(filter.key, $event.target.value)" > <option diff --git a/js/Components/TableGlobalSearch.vue b/js/Components/TableGlobalSearch.vue index e4753ce..df4297b 100644 --- a/js/Components/TableGlobalSearch.vue +++ b/js/Components/TableGlobalSearch.vue @@ -1,7 +1,7 @@ <template> <div class="relative"> <input - class="block w-full pl-9 text-sm rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 border-gray-300" + class="block w-full pl-9 text-sm rounded-md shadow-sm focus:ring-indigo-500 focus:border-gray-500 border-gray-300 focus:ring-2 dark:bg-gray-700 dark:text-gray-100 dark:border-gray-500" :placeholder="label" :value="value" type="text" diff --git a/js/Components/TableReset.vue b/js/Components/TableReset.vue index 664a34f..ad05aa5 100644 --- a/js/Components/TableReset.vue +++ b/js/Components/TableReset.vue @@ -3,7 +3,7 @@ ref="button" type="button" dusk="reset-table" - class="w-full bg-white border rounded-md shadow-sm px-4 py-2 inline-flex justify-center text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 border-gray-300" + class="w-full bg-white border rounded-md shadow-sm px-4 py-2 inline-flex justify-center text-sm font-medium text-gray-700 hover:bg-gray-50 focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 border-gray-300 dark:bg-gray-700 dark:text-gray-100 dark:border-gray-500 dark:hover:bg-gray-600" aria-haspopup="true" @click.prevent="onClick" > diff --git a/js/Components/TableSearchRows.vue b/js/Components/TableSearchRows.vue index 0967875..db75734 100644 --- a/js/Components/TableSearchRows.vue +++ b/js/Components/TableSearchRows.vue @@ -8,7 +8,7 @@ <div class="flex rounded-md shadow-sm relative mt-3"> <label :for="searchInput.key" - class="inline-flex items-center px-4 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm" + class="inline-flex items-center px-4 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm dark:text-gray-100 dark:bg-gray-600 dark:border-gray-500" > <svg xmlns="http://www.w3.org/2000/svg" @@ -31,7 +31,7 @@ :name="searchInput.key" :value="searchInput.value" type="text" - class="flex-1 min-w-0 block w-full px-3 py-2 rounded-none rounded-r-md focus:ring-indigo-500 focus:border-indigo-500 text-sm border-gray-300" + class="flex-1 min-w-0 block w-full px-3 py-2 rounded-none rounded-r-md focus:ring-indigo-500 focus:border-gray-500 text-sm border-gray-300 focus:ring-2 dark:bg-gray-700 dark:border-gray-500 dark:text-gray-100" @input="onChange(searchInput.key, $event.target.value)" > <div diff --git a/js/Components/TableWrapper.vue b/js/Components/TableWrapper.vue index 55321c0..d7cec43 100644 --- a/js/Components/TableWrapper.vue +++ b/js/Components/TableWrapper.vue @@ -2,7 +2,7 @@ <div class="flex flex-col"> <div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> <div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8"> - <div class="shadow border-b border-gray-200 relative"> + <div class="shadow border-b border-gray-200 relative dark:border-0 dark:shadow-none"> <slot /> </div> </div>