From 8e44b55c974ca4769404894fe2f79ca62130d7be Mon Sep 17 00:00:00 2001 From: Jack McDade Date: Thu, 9 Mar 2023 16:44:09 -0500 Subject: [PATCH 1/4] Make Status its own column Co-Authored-By: Jason Varga --- .../CP/Collections/CollectionsController.php | 5 +++++ src/Http/Resources/CP/Entries/Entries.php | 10 ++++++++++ src/Http/Resources/CP/Entries/ListedEntry.php | 13 ++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Http/Controllers/CP/Collections/CollectionsController.php b/src/Http/Controllers/CP/Collections/CollectionsController.php index 041bca2e396..4c94b6a1fa9 100644 --- a/src/Http/Controllers/CP/Collections/CollectionsController.php +++ b/src/Http/Controllers/CP/Collections/CollectionsController.php @@ -75,6 +75,11 @@ public function show(Request $request, $collection) $columns = $blueprint ->columns() + ->prepend(Column::make('status') + ->listable(true) + ->visible(true) + ->defaultVisibility(true) + ->sortable(false), 'status') ->setPreferred("collections.{$collection->handle()}.columns") ->rejectUnlisted() ->values(); diff --git a/src/Http/Resources/CP/Entries/Entries.php b/src/Http/Resources/CP/Entries/Entries.php index c0fd9e4a01e..c2c4141928c 100644 --- a/src/Http/Resources/CP/Entries/Entries.php +++ b/src/Http/Resources/CP/Entries/Entries.php @@ -2,6 +2,8 @@ namespace Statamic\Http\Resources\CP\Entries; +use Statamic\CP\Column; +use Statamic\Http\Resources\CP\Entries\ListedEntry; use Illuminate\Http\Resources\Json\ResourceCollection; use Statamic\Http\Resources\CP\Concerns\HasRequestedColumns; @@ -31,6 +33,14 @@ private function setColumns() { $columns = $this->blueprint->columns(); + $status = Column::make('status') + ->listable(true) + ->visible(true) + ->defaultVisibility(true) + ->sortable(false); + + $columns->prepend($status, 'status'); + if ($key = $this->columnPreferenceKey) { $columns->setPreferred($key); } diff --git a/src/Http/Resources/CP/Entries/ListedEntry.php b/src/Http/Resources/CP/Entries/ListedEntry.php index a63f83e2549..505047b9bec 100644 --- a/src/Http/Resources/CP/Entries/ListedEntry.php +++ b/src/Http/Resources/CP/Entries/ListedEntry.php @@ -33,6 +33,7 @@ public function toArray($request) return [ 'id' => $entry->id(), 'published' => $entry->published(), + 'status' => $entry->status(), 'private' => $entry->private(), 'date' => $this->when($collection->dated(), function () { return $this->resource->date()->inPreferredFormat(); @@ -60,13 +61,19 @@ protected function values($extra = []) $value = $extra[$key] ?? $this->resource->value($key); } - $value = $this->blueprint - ->field($key) - ->setValue($value) + $field = $this->blueprint->field($key); + + if (! $field) { + return [$key => $value]; + } + + $value = $field->setValue($value) ->setParent($this->resource) ->preProcessIndex() ->value(); + + return [$key => $value]; }); } From 2cdb1de5ffc92e7d1ccc17fc287455fc660bd0a4 Mon Sep 17 00:00:00 2001 From: Jack McDade Date: Thu, 9 Mar 2023 16:46:25 -0500 Subject: [PATCH 2/4] Greatly improve the data-tables UI in every way - titles will wrap to 2 lines max, will show the status dot if there's no status field shown - relationship fields have a new little badge style and will truncate to each on one line - content fields get smaller text and wrap to 2 lines max - new status column - title fields have a reasonable min-width set because they're important - title fields will still show the status dot if the status column isn't visible - date fields will no longer wrap to two lines - wide tables will scroll horizontally instead of overflow, keeping the checkbox and actions columns in view at all times --- package-lock.json | 10 ++ package.json | 1 + resources/css/components/popover.css | 35 ++-- resources/css/elements/tables.css | 155 ++++++++++++++---- resources/js/components/DropdownList.vue | 9 +- resources/js/components/Popover.vue | 21 ++- .../js/components/collections/Listing.vue | 4 +- resources/js/components/data-list/Filters.vue | 4 +- resources/js/components/data-list/Table.vue | 23 ++- .../js/components/data-list/ToggleAll.vue | 2 +- resources/js/components/entries/Listing.vue | 109 +++++++----- .../RelationshipIndexFieldtype.vue | 14 +- .../js/components/taxonomies/Listing.vue | 2 +- resources/js/components/terms/Listing.vue | 4 +- resources/js/components/users/Listing.vue | 2 +- resources/lang/en/messages.php | 3 + tailwind.config.js | 5 + 17 files changed, 285 insertions(+), 118 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88ec712a068..53e5993d735 100644 --- a/package-lock.json +++ b/package-lock.json @@ -85,6 +85,7 @@ "@babel/preset-env": "^7.20.2", "@rollup/plugin-inject": "^5.0.3", "@tailwindcss/container-queries": "^0.1.0", + "@tailwindcss/line-clamp": "^0.4.2", "@tailwindcss/typography": "^0.5.9", "@vitejs/plugin-vue2": "^2.2.0", "autoprefixer": "^10.4.0", @@ -4053,6 +4054,15 @@ "tailwindcss": ">=3.2.0" } }, + "node_modules/@tailwindcss/line-clamp": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.4.2.tgz", + "integrity": "sha512-HFzAQuqYCjyy/SX9sLGB1lroPzmcnWv1FHkIpmypte10hptf4oPUfucryMKovZh2u0uiS9U5Ty3GghWfEJGwVw==", + "dev": true, + "peerDependencies": { + "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" + } + }, "node_modules/@tailwindcss/typography": { "version": "0.5.9", "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.9.tgz", diff --git a/package.json b/package.json index 8cec9155431..5ba57538251 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "@babel/preset-env": "^7.20.2", "@rollup/plugin-inject": "^5.0.3", "@tailwindcss/container-queries": "^0.1.0", + "@tailwindcss/line-clamp": "^0.4.2", "@tailwindcss/typography": "^0.5.9", "@vitejs/plugin-vue2": "^2.2.0", "autoprefixer": "^10.4.0", diff --git a/resources/css/components/popover.css b/resources/css/components/popover.css index d17c12772f0..9fb3c471052 100644 --- a/resources/css/components/popover.css +++ b/resources/css/components/popover.css @@ -34,11 +34,27 @@ position: relative; } +/* When open */ +.popover-open { + .popover { + pointer-events: auto; + visibility: visible; + } + + .popover-content { + transform: scale(1); + opacity: 1; + } + + .rotating-dots { + transform: rotate(90deg); + } +} + /* Supporting elements */ .rotating-dots { @apply relative cursor-pointer; transition: .12s ease-out; - /* top: 1px; */ } .rotating-dots-button { @@ -54,20 +70,3 @@ @apply focus-outline; } } - -/* When open */ -.popover-open { - .popover { - pointer-events: auto; - visibility: visible; - } - - .popover-content { - transform: scale(1); - opacity: 1; - } - - .rotating-dots { - transform: rotate(90deg); - } -} diff --git a/resources/css/elements/tables.css b/resources/css/elements/tables.css index 721e009095b..a625df7aa78 100644 --- a/resources/css/elements/tables.css +++ b/resources/css/elements/tables.css @@ -44,49 +44,49 @@ } th { - @apply font-medium px-4 py-2; + @apply font-medium px-4 py-3 whitespace-nowrap; &:first-child { @apply rounded-tl-lg; } &:last-child { @apply rounded-tr-lg; } &:hover { @apply text-gray-900; } } + th.handle-column { + @apply p-0 w-4; + } .type-column { text-align: right; } - .actions-column { - @apply p-0 pr-4 text-right; - width: 24px; - } } tbody { outline: none; tr { - @apply border-b text-sm; + @apply border-b border-gray-400 text-sm; &.row-selected { @apply bg-gray-200; } &:first-child { - td:first-child { - @apply rounded-tl; + td:first-child, th:first-child { + @apply rounded-tl-md; } - td:last-child { - @apply rounded-tr; + td:last-child, th:last-child { + @apply rounded-tr-md; } } &:last-child { @apply border-none; - td:first-child { - @apply rounded-bl; + + td:first-child, th:first-child { + @apply rounded-bl-md; } - td:last-child { - @apply rounded-br; + td:last-child, th:last-child { + @apply rounded-br-md; } } @@ -99,25 +99,19 @@ } td { - @apply py-2 px-4 break-words; + @apply py-2 px-4 break-words ; + } + + td.table-drag-handle { + @apply w-1 border-r h-full py-2 px-0; } } - .type-column { + + .type-column { text-align: right; } - .actions-column { - @apply p-0 text-right; - width: 24px; - .rotating-dots-button { - margin-right: 18px; - } - } } - .checkbox-column { - @apply w-4 pr-0 relative z-10; - padding-left: 20px; - } .sortable-column { @apply cursor-pointer select-none; @@ -148,11 +142,67 @@ } } -@screen md { +/* Sticky Meta Columns */ +.data-table { + thead th.checkbox-column { + @apply p-0 pr-2 z-10 sticky -left-px; + background-image: linear-gradient(to right, theme(colors.gray.100) 70%, theme(colors.gray.100 / 0%) 100%); + width: 45px; + min-width: 45px; + } + + thead th.actions-column { + @apply p-0 pl-2 text-right sticky z-1 -right-px; + background-image: linear-gradient(to left, theme(colors.gray.100) 70%, theme(colors.gray.100 / 0%) 100%); + width: 45px; + min-width: 45px; + } + + tbody th.checkbox-column { + @apply z-1 px-3 sticky -left-px; + background-image: linear-gradient(to right, rgba(255,255,255,1) 70%, rgba(255,255,255,0) 100%); + } + + tbody th.actions-column { + @apply p-0 pl-4 text-right sticky -right-px z-1; + background-image: linear-gradient(to left, rgba(255,255,255,1) 70%, rgba(255,255,255,0) 100%); + min-width: 45px; + width: 45px; + } + + tbody tr.row-selected .checkbox-column { + background-image: linear-gradient(to left, theme(colors.gray.200) 70%, theme(colors.gray.200 / 0%) 100%); + } + + tbody tr.row-selected .actions-column { + background-image: linear-gradient(to right, theme(colors.gray.200) 70%, theme(colors.gray.200 / 0%) 100%); + } + + tbody tr:hover .checkbox-column { + background-image: linear-gradient(to right, theme(colors.gray.100) 70%, theme(colors.gray.100 / 0%) 100%); + } + + tbody tr:hover .actions-column { + background-image: linear-gradient(to left, theme(colors.gray.100) 70%, theme(colors.gray.100 / 0%) 100%); + } +} + +/* .data-table[data-size="sm"] { + thead th.checkbox-column, + thead th.actions-column, + tbody th.checkbox-column, + tbody th.actions-column { + position: static !important; + background: none !important; + } +} */ + + +/* @screen md { .data-table { @apply w-full table; } -} +} */ .data-list-header ~ .data-table { thead th { @@ -259,3 +309,50 @@ table.control { padding-left: 30px; } } + + +/* Index Fields + ========================================================================== */ + +.bard-index-field, +.code-index-field, +.markdown-index-field, +.text-index-field, +.textarea-index-field { + @apply line-clamp-2 text-xs; +} + +.title-index-field { + @apply line-clamp-2; + min-width: 10vw; +} + +.relationship-index-field { + min-width: 10vw; + .relationship-index-field-item { + @apply rounded bg-gray-100 border px-1 flex items-center text-2xs; + a { + @apply line-clamp-1; + } + } +} + +.date-index-field { + @apply whitespace-nowrap text-gray-800; +} + +.slug-index-field { + @apply line-clamp-2 font-mono text-2xs; +} + +.status-index-field { + @apply inline-block text-xs bg-gray-300 text-gray-800 shrink rounded-full px-2 py-0.5 text-center justify-center; + + &.status-published:not(.status-private) { + @apply text-lime-900 bg-lime-200 ; + } + + &.status-scheduled { + @apply text-amber-900 bg-amber-200; + } +} diff --git a/resources/js/components/DropdownList.vue b/resources/js/components/DropdownList.vue index 576061d93f6..6fd4b0e2786 100644 --- a/resources/js/components/DropdownList.vue +++ b/resources/js/components/DropdownList.vue @@ -1,5 +1,5 @@