From 94609f96304ad0d086fc95cb5bead9730ad8d30a Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Mon, 8 Apr 2024 14:23:56 +0100 Subject: [PATCH 01/17] WIP --- .../css/components/fieldtypes/replicator.css | 2 +- resources/js/app.js | 1 + resources/js/components/Sortables.js | 28 +++++++++++++++++++ resources/js/components/Statamic.js | 6 ++++ .../fieldtypes/replicator/Replicator.vue | 9 ++++-- .../js/components/sortable/SortableList.vue | 10 +++++-- src/Fieldtypes/Replicator.php | 1 + 7 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 resources/js/components/Sortables.js diff --git a/resources/css/components/fieldtypes/replicator.css b/resources/css/components/fieldtypes/replicator.css index 55b54cc677..1d0ae05cd5 100644 --- a/resources/css/components/fieldtypes/replicator.css +++ b/resources/css/components/fieldtypes/replicator.css @@ -3,7 +3,7 @@ ========================================================================== */ .replicator-set-container { - @apply outline-none; + @apply outline-none min-h-[10px]; } .replicator-set { diff --git a/resources/js/app.js b/resources/js/app.js index 968c30a852..47595f5c9a 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -67,6 +67,7 @@ Vue.prototype.$echo = Statamic.$echo; Vue.prototype.$bard = Statamic.$bard; Vue.prototype.$keys = Statamic.$keys; Vue.prototype.$reveal = Statamic.$reveal; +Vue.prototype.$sortables = Statamic.$sortables; import Moment from 'moment'; window.moment = Vue.moment = Vue.prototype.$moment = Moment; diff --git a/resources/js/components/Sortables.js b/resources/js/components/Sortables.js new file mode 100644 index 0000000000..d1e3f7abce --- /dev/null +++ b/resources/js/components/Sortables.js @@ -0,0 +1,28 @@ +import { Sortable } from '@shopify/draggable' + +class Sortables { + constructor() { + this.instances = {}; + } + + connect(id, container, options) { + if (!this.instances[id]) { + this.instances[id] = new Sortable(container, options); + } else { + this.instances[id].addContainer(container); + } + return this.instances[id]; + } + + disconnect(id, container) { + if (this.instances[id]) { + this.instances[id].removeContainer(container); + if (this.instances[id].containers.length === 0) { + this.instances[id].destroy(); + delete this.instances[id]; + } + } + } +} + +export default Sortables; diff --git a/resources/js/components/Statamic.js b/resources/js/components/Statamic.js index 75d6d71404..0ec2e9bdc0 100644 --- a/resources/js/components/Statamic.js +++ b/resources/js/components/Statamic.js @@ -4,6 +4,7 @@ import Bard from './Bard'; import Keys from './keys/Keys'; import Hooks from './Hooks'; import Reveal from './Reveal'; +import Sortables from './Sortables'; import Components from './Components'; import FieldConditions from './FieldConditions'; import Callbacks from './Callbacks'; @@ -12,6 +13,7 @@ const bard = new Bard; const keys = new Keys; const hooks = new Hooks; const reveal = new Reveal; +const sortables = new Sortables; const components = new Components; const conditions = new FieldConditions; const callbacks = new Callbacks; @@ -55,6 +57,10 @@ export default new Vue({ return reveal; }, + $sortables() { + return sortables; + }, + $conditions() { return conditions; }, diff --git a/resources/js/components/fieldtypes/replicator/Replicator.vue b/resources/js/components/fieldtypes/replicator/Replicator.vue index 3f7d4cb216..6c3c8ac664 100644 --- a/resources/js/components/fieldtypes/replicator/Replicator.vue +++ b/resources/js/components/fieldtypes/replicator/Replicator.vue @@ -43,6 +43,7 @@ -import { Sortable, Plugins } from '@shopify/draggable' +import { Plugins } from '@shopify/draggable' function move(items, oldIndex, newIndex) { const itemRemovedArray = [ @@ -20,6 +20,9 @@ export default { value: { required: true, }, + group: { + default: null, + }, itemClass: { default: 'sortable-item', }, @@ -63,6 +66,7 @@ export default { data() { return { sortable: null, + sortableId: this.group || uniqid(), } }, @@ -120,7 +124,7 @@ export default { methods: { setupSortableList() { - this.sortable = new Sortable(this.$el, this.computedOptions); + this.sortable = this.$sortables.connect(this.sortableId, this.$el, this.computedOptions); this.sortable.on('drag:start', () => this.$emit('dragstart')); this.sortable.on('drag:stop', () => this.$emit('dragend')); @@ -139,7 +143,7 @@ export default { }, destroySortableList() { - this.sortable.destroy() + this.$sortables.disconnect(this.sortableId, this.$el, this.computedOptions); }, }, diff --git a/src/Fieldtypes/Replicator.php b/src/Fieldtypes/Replicator.php index a437022e07..1e5ca7bb8d 100644 --- a/src/Fieldtypes/Replicator.php +++ b/src/Fieldtypes/Replicator.php @@ -224,6 +224,7 @@ public function preload() 'defaults' => $defaults, 'collapsed' => [], 'previews' => $previews, + 'sortableGroup' => implode('-', $this->field->handlePath()), ]; } From caa85bab1c880405fa46f6f595b95d5f999a8316 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Mon, 24 Jun 2024 20:13:43 +0100 Subject: [PATCH 02/17] WIP --- .../js/components/fieldtypes/replicator/Replicator.vue | 10 +++++----- src/Fieldtypes/Replicator.php | 8 +++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/resources/js/components/fieldtypes/replicator/Replicator.vue b/resources/js/components/fieldtypes/replicator/Replicator.vue index 78ab350b11..17eda3f40d 100644 --- a/resources/js/components/fieldtypes/replicator/Replicator.vue +++ b/resources/js/components/fieldtypes/replicator/Replicator.vue @@ -43,7 +43,7 @@ $defaults, 'collapsed' => [], 'previews' => $previews, - 'sortableGroup' => implode('-', $this->field->handlePath()), + 'groupKey' => $this->groupKey(), ]; } @@ -330,4 +330,10 @@ public function toQueryableValue($value) { return empty($value) ? null : $value; } + + protected function groupKey() + { + // @todo This should be refactored into a list of allowed set config hashes, if possible. + return md5(serialize($this->field->config('sets'))); + } } From 8071ee21530939bb5f23df459025bbcd1c0a273f Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Mon, 24 Jun 2024 21:21:14 +0100 Subject: [PATCH 03/17] WIP --- .../js/components/sortable/SortableList.vue | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/resources/js/components/sortable/SortableList.vue b/resources/js/components/sortable/SortableList.vue index 60648e4e71..6968152897 100644 --- a/resources/js/components/sortable/SortableList.vue +++ b/resources/js/components/sortable/SortableList.vue @@ -1,19 +1,25 @@