Skip to content
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

[5.x] Add field actions modals #10833

Draft
wants to merge 22 commits into
base: 5.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion resources/css/components/fieldtypes/bard.css
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@
========================================================================== */

.bard-fullscreen {
@apply fixed bg-gray-200 dark:bg-dark-700 inset-0 min-h-screen overflow-scroll rounded-none pt-16;
@apply fixed bg-gray-200 dark:bg-dark-700 inset-0 min-h-screen overflow-scroll rounded-none pt-14;

& > .bard-editor {
@apply bg-white dark:bg-dark-800 shadow dark:shadow-dark max-w-xl mx-auto rounded relative my-6 px-8;
Expand Down
5 changes: 3 additions & 2 deletions resources/css/components/fieldtypes/code.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
}
}

.code-fieldtype-toolbar select {
.code-fieldtype-toolbar select,
.code-fieldtype-toolbar-fullscreen select {
@apply h-8 text-sm leading-none;
}


.code-fieldtype-container.code-fullscreen {
@apply fixed bg-gray-200 dark:bg-dark-600 inset-0 min-h-screen overflow-scroll rounded-none pt-12;
@apply fixed bg-gray-200 dark:bg-dark-600 inset-0 min-h-screen overflow-scroll rounded-none pt-14;

.code-fieldtype-toolbar {
@apply fixed z-2 top-0 w-full px-6 py-2 h-12 shadow dark:shadow-dark text-base rounded-none bg-gradient-to-b from-white to-gray-100 dark:from-dark-550 dark:to-dark-600;
Expand Down
5 changes: 2 additions & 3 deletions resources/css/components/fieldtypes/markdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -212,13 +212,12 @@
}

.markdown-fieldtype-wrapper.markdown-fullscreen {
@apply fixed bg-gray-200 inset-0 min-h-screen overflow-scroll rounded-none pt-16;
@apply fixed bg-gray-200 inset-0 min-h-screen overflow-scroll rounded-none pt-14 border-0;
/* padding-top: 52px; offset the nav */
will-change: transform;

.markdown-toolbar {
@apply fixed top-0 w-full px-6 py-2 h-12 shadow text-base flex items-center justify-between;
@apply bg-gradient-to-b from-white to-gray-100;
@apply border-0;
}

.mode-wrap {
Expand Down
12 changes: 12 additions & 0 deletions resources/css/components/publish.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ code.parent-url {
@apply absolute inset-0 cursor-not-allowed bg-white/25;
z-index: 100;
}

.field-dropdown {
@apply hidden;
}
.has-dropdown {
.field-inner {
@apply pr-6;
}
.field-dropdown {
@apply block absolute bottom-0 right-0;
}
}
}

.publish-field {
Expand Down
13 changes: 13 additions & 0 deletions resources/css/elements/buttons.css
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,19 @@ td .btn-icon {
}
}

.btn-quick-action {
@apply text-center p-0 text-xl text-gray-600 dark:text-dark-150 rounded-full w-8 h-8 outline-none shrink-0 leading-none inline-flex items-center justify-center;

&:hover {
@apply bg-gray-400 dark:bg-dark-700;
}

&:active, &:focus:hover {
outline: none;
@apply bg-gray-500 dark:bg-dark-750;
}
}

.super-btn {
@apply p-4 flex items-start hover:bg-gray-200 border border-transparent rounded-md space-x-4 rtl:space-x-reverse;
@apply dark:hover:bg-dark-575 dark:hover:border-dark-400;
Expand Down
40 changes: 40 additions & 0 deletions resources/css/elements/dropdowns.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,44 @@
.align-left & {
right: auto ; [dir="rtl"] & { right: auto ; left: auto ; }
}

}

.quick-list {

@apply relative;

.quick-list-content {
@apply absolute top-1/2 right-full mr-[8px] -translate-y-1/2 min-w-max transition origin-right flex bg-white shadow-quick rounded-full p-0.5;
&::before {
content: '';
position: absolute;
inset: -8px -8px -8px -20px;
z-index: -1;
}
button, a {
@apply rounded-full p-1.5 text-gray-800 flex shrink-0;
&:hover {
@apply bg-blue text-white;
}
}
&:empty {
@apply hidden;
}
}

button.warning, a.warning {
@apply text-red-500;

&:hover {
@apply bg-red-500 text-white;
}
}

&:not(:hover) {
.quick-list-content {
@apply opacity-0 pointer-events-none scale-[0.85];
}
}

}
2 changes: 1 addition & 1 deletion resources/css/vendors/codemirror.css
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@


.CodeMirror-fullscreen {
@apply fixed h-auto inset-0 top-12 rounded-none;
@apply fixed h-auto inset-0 pt-14 rounded-none;
}

.CodeMirror-rulers {
Expand Down
1 change: 1 addition & 0 deletions resources/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.$actions = Statamic.$actions;
Vue.prototype.$slug = Statamic.$slug;

import Moment from 'moment';
Expand Down
10 changes: 10 additions & 0 deletions resources/js/bootstrap/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import PublishForm from '../components/publish/PublishForm.vue';
import Fields from '../components/publish/Fields.vue';
import FieldsContainer from '../components/publish/FieldsContainer.vue'; // deprecated
import Field from '../components/publish/Field.vue';
import FieldHeader from '../components/publish/FieldHeader.vue';
import FieldMeta from '../components/publish/FieldMeta.vue';
import ConfigureTabs from '../components/configure/Tabs.vue';
import PublishTabs from '../components/publish/Tabs.vue';
Expand Down Expand Up @@ -42,6 +43,9 @@ import FileIcon from '../components/FileIcon.vue';
import LoadingGraphic from '../components/LoadingGraphic.vue';
import DropdownList from '../components/DropdownList.vue';
import DropdownItem from '../components/DropdownItem.vue';
import DropdownActions from '../components/DropdownActions.vue';
import QuickDropdownList from '../components/QuickDropdownList.vue';
import QuickDropdownItem from '../components/QuickDropdownItem.vue';
import ValidationErrors from '../components/ValidationErrors.vue';
import Slugify from '../components/slugs/Slugify.vue';
import ElementContainer from '../components/ElementContainer.vue';
Expand All @@ -54,6 +58,7 @@ import Portal from '../components/portals/Portal.vue';
import PermissionTree from '../components/roles/PermissionTree.vue';
import Modal from '../components/Modal.vue';
import ConfirmationModal from '../components/modals/ConfirmationModal.vue';
import ActionModal from '../components/modals/ActionModal.vue';
import FavoriteCreator from '../components/FavoriteCreator.vue';
import KeyboardShortcutsModal from '../components/modals/KeyboardShortcutsModal.vue';
import ResourceDeleter from '../components/ResourceDeleter.vue';
Expand All @@ -77,6 +82,7 @@ Vue.component('publish-fields', Fields);
Vue.component('publish-fields-container', FieldsContainer);
Vue.component('publish-field', Field);
Vue.component('publish-field-meta', FieldMeta);
Vue.component('publish-field-header', FieldHeader);
Vue.component('configure-tabs', ConfigureTabs);
Vue.component('publish-tabs', PublishTabs);
Vue.component('publish-sections', PublishSections);
Expand Down Expand Up @@ -120,6 +126,9 @@ Vue.component('file-icon', FileIcon);
Vue.component('loading-graphic', LoadingGraphic);
Vue.component('dropdown-list', DropdownList);
Vue.component('dropdown-item', DropdownItem);
Vue.component('dropdown-actions', DropdownActions);
Vue.component('quick-dropdown-list', QuickDropdownList);
Vue.component('quick-dropdown-item', QuickDropdownItem);
Vue.component('validation-errors', ValidationErrors);
Vue.component('slugify', Slugify);
Vue.component('element-container', ElementContainer);
Expand All @@ -137,6 +146,7 @@ Vue.component('role-permission-tree', PermissionTree);
// Modals
Vue.component('modal', Modal);
Vue.component('confirmation-modal', ConfirmationModal);
Vue.component('action-modal', ActionModal);
Vue.component('favorite-creator', FavoriteCreator);
Vue.component('keyboard-shortcuts-modal', KeyboardShortcutsModal);
Vue.component('resource-deleter', ResourceDeleter);
Expand Down
46 changes: 46 additions & 0 deletions resources/js/components/Actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import uid from 'uniqid';

class Actions {
constructor() {
this.actions = {};
}

add(name, action) {
if (this.actions[name] === undefined) {
this.actions[name] = [];
}

this.actions[name].push(action);
}

get(name) {
return this.actions[name] || [];
}

async run(action, payload) {
action.run(payload);
}

modal(props) {
return new Promise((resolve) => {
const component = Statamic.$components.append('action-modal', { props });
component.on('confirm', (data) => {
if (props.keepOpen) {
resolve({
...data,
close: () => Statamic.$components.destroy(component.id),
});
} else {
resolve(data);
Statamic.$components.destroy(component.id);
}
});
component.on('cancel', () => {
resolve(false);
Statamic.$components.destroy(component.id);
});
});
}
}

export default Actions;
30 changes: 30 additions & 0 deletions resources/js/components/DropdownActions.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<template>
<div>
<button
v-for="action in actions"
@click="run(action)"
>
{{ action.display || action.title }}
</button>
</div>
</template>

<script>
export default {

props: ['actions'],

inject: ['popover'],

methods: {

run(action) {
this.$emit('run', action);

this.popover.vm.close();
},

}

}
</script>
10 changes: 7 additions & 3 deletions resources/js/components/DropdownList.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<popover class="dropdown-list" :disabled="disabled" :placement="placement" :autoclose="autoclose" @opened="$emit('opened')" @closed="$emit('closed')">
<popover class="dropdown-list" :disabled="disabled" :placement="placement" :autoclose="autoclose" :offset="offset" @opened="$emit('opened')" @closed="$emit('closed')">
<template #trigger>
<slot name="trigger">
<button class="rotating-dots-button" :aria-label="__('Open Dropdown')">
<button class="rotating-dots-button" :aria-label="__('Open Dropdown')" type="button">
<svg class="rotating-dots fill-current" width="12" viewBox="0 0 24 24"><circle cx="3" cy="12" r="3"/><circle cx="12" cy="12" r="3"/><circle cx="21" cy="12" r="3"/></svg>
</button>
</slot>
Expand All @@ -25,7 +25,11 @@ export default {
autoclose: {
type: Boolean,
default: false
}
},
offset: {
type: Array,
default: () => [10, 0]
},
},
computed: {
strategy() {
Expand Down
52 changes: 52 additions & 0 deletions resources/js/components/HasActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export default {

computed: {

actions() {
return this.$actions.get(this.$options.name);
},

internalActions() {
return [];
},

visibleActions() {
return this.actions
.filter(action => {
if (typeof action.visible === 'function') return action.visible();
if (typeof action.visible !== 'undefined') return action.visible;
return true;
});
},

visibleInternalActions() {
return this.internalActions
.filter(action => {
if (typeof action.visible === 'function') return action.visible();
if (typeof action.visible !== 'undefined') return action.visible;
return true;
});
},

visibleQuickActions() {
return [
...this.visibleActions,
...this.visibleInternalActions
].filter(item => item.quick);
},

actionPayload() {
return {};
},

},

methods: {

runAction(action) {
Statamic.$actions.run(action, this.actionPayload);
},

}

}
37 changes: 37 additions & 0 deletions resources/js/components/QuickDropdownItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template>
<a :href="href" :target="target" @click="selectAndClose" v-tooltip="text">
<svg-icon :name="icon" class="h-3 w-3" />
</a>
</template>

<script>
export default {

props: ['text', 'icon', 'redirect', 'externalLink'],

computed: {

href() {
return this.redirect || this.externalLink;
},

target() {
return this.externalLink ? '_blank' : null;
},

},

methods: {

selectAndClose($event) {
if (this.href) {
return;
}

this.$emit('click', $event);
},

}

}
</script>
Loading
Loading