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

Widget editor: adds tabs #4514

Merged
merged 10 commits into from Apr 30, 2024
5 changes: 3 additions & 2 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,7 @@
### Adds

* Allows to disable page refresh on content changed for page types.
* Widget editor can now have tabs.

## 4.2.0 (2024-04-18)

Expand Down Expand Up @@ -53,7 +54,7 @@ watching behavior by Vue 3.

* Don't crash if a document of a type no longer corresponding to any module is present
together with the advanced permission module.
* AposLoginForm.js now pulls its schema from the user module rather than hardcoding it. Includes the
* AposLoginForm.js now pulls its schema from the user module rather than hardcoding it. Includes the
addition of `enterUsername` and `enterPassword` i18n fields for front end customization and localization.
* Simulated Express requests returned by `apos.task.getReq` now include a `req.headers` property, for
greater accuracy and to prevent unexpected bugs in other code.
Expand All @@ -62,7 +63,7 @@ actually exists before calling `attachment.url` still lies with the developer.

### Adds

* Add new `getChanges` method to the schema module to get an array of document changed field names instead of just a boolean like does the `isEqual` method.
* Add new `getChanges` method to the schema module to get an array of document changed field names instead of just a boolean like does the `isEqual` method.
* Add highlight class in UI when comparing documents.

## 4.0.0 (2024-03-12)
Expand Down
116 changes: 113 additions & 3 deletions modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue
@@ -1,8 +1,8 @@
<template>
<div class="apos-modal-tabs">
<div class="apos-modal-tabs" :class="{ 'apos-modal-tabs--horizontal': orientation === 'horizontal' }">
falkodev marked this conversation as resolved.
Show resolved Hide resolved
<ul class="apos-modal-tabs__tabs">
<li
v-for="tab in tabs"
v-for="tab in visibleTabs"
v-show="tab.isVisible !== false"
:key="tab.name"
class="apos-modal-tabs__tab"
Expand All @@ -14,12 +14,27 @@
@click="selectTab"
>
{{ $t(tab.label) }}
<span v-if="tabErrors[tab.name] && tabErrors[tab.name].length" class="apos-modal-tabs__label apos-modal-tabs__label--error">
<span
v-if="tabErrors[tab.name] && tabErrors[tab.name].length"
class="apos-modal-tabs__label apos-modal-tabs__label--error"
>
{{ tabErrors[tab.name].length }} {{ generateErrorLabel(tabErrors[tab.name].length) }}
</span>
</button>
</li>
<li
v-if="hiddenTabs.length"
key="placeholder-for-hidden-tabs"
class="apos-modal-tabs__tab apos-modal-tabs__tab--small"
/>
</ul>
<AposContextMenu
v-if="hiddenTabs.length"
:menu="hiddenTabs"
menu-placement="bottom-end"
:button="moreMenuButton"
@item-clicked="moreMenuHandler($event)"
/>
</div>
</template>

Expand All @@ -40,9 +55,36 @@
default() {
return {};
}
},
orientation: {
type: String,
default: 'vertical'
}
},
emits: [ 'select-tab' ],
data() {
const visibleTabs = [];
const hiddenTabs = [];

for (let i = 0; i < this.tabs.length; i++) {
this.tabs[i].action = this.tabs[i].name;

Check failure on line 70 in modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue

View workflow job for this annotation

GitHub Actions / build (18, 4.4)

Unexpected mutation of "tabs" prop

Check failure on line 70 in modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue

View workflow job for this annotation

GitHub Actions / build (18, 5)

Unexpected mutation of "tabs" prop

Check failure on line 70 in modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue

View workflow job for this annotation

GitHub Actions / build (18, 6)

Unexpected mutation of "tabs" prop

Check failure on line 70 in modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue

View workflow job for this annotation

GitHub Actions / build (18, 7)

Unexpected mutation of "tabs" prop

Check failure on line 70 in modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue

View workflow job for this annotation

GitHub Actions / build (20, 4.4)

Unexpected mutation of "tabs" prop

Check failure on line 70 in modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue

View workflow job for this annotation

GitHub Actions / build (20, 5)

Unexpected mutation of "tabs" prop

Check failure on line 70 in modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue

View workflow job for this annotation

GitHub Actions / build (20, 6)

Unexpected mutation of "tabs" prop

Check failure on line 70 in modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue

View workflow job for this annotation

GitHub Actions / build (20, 7)

Unexpected mutation of "tabs" prop
if (i < 5) {
visibleTabs.push(this.tabs[i]);
} else {
hiddenTabs.push(this.tabs[i]);
}
}

return {
visibleTabs,
hiddenTabs,
moreMenuButton: {
icon: 'dots-vertical-icon',
iconOnly: true,
type: 'subtle'
}
};
},
computed: {
tabErrors() {
const errors = {};
Expand All @@ -69,6 +111,15 @@
const tab = e.target;
const id = tab.id;
this.$emit('select-tab', id);
},
moreMenuHandler(item) {
const lastVisibleTab = this.visibleTabs[this.visibleTabs.length - 1];
const selectedItem = this.hiddenTabs.find((tab) => tab.name === item);

this.hiddenTabs.splice(this.hiddenTabs.indexOf(selectedItem), 1, lastVisibleTab);
this.visibleTabs.splice(this.visibleTabs.length - 1, 1, selectedItem);

this.$emit('select-tab', item);
}
}
};
Expand All @@ -80,6 +131,65 @@
height: 100%;
}

:deep(.apos-context-menu) {
position: absolute;
right: 0;
top: 10px;

svg {
height: 20px;
width: 20px;
color: var(--a-base-1);
}

.apos-button--subtle:hover {
background-color: initial;
}
}

.apos-modal-tabs--horizontal {
position: relative;

.apos-modal-tabs__tabs {
flex-direction: row;
border-top: 1px solid var(--a-base-7);
border-bottom: 1px solid var(--a-base-7);
}

.apos-modal-tabs__tab {
display: flex;
width: 100%;
}

.apos-modal-tabs__tab--small {
width: 50%;
color: var(--a-base-1);
background-color: var(--a-base-10);
border-bottom: 1px solid var(--a-base-7);
}

.apos-modal-tabs__btn {
justify-content: center;
color: var(--a-base-1);
background-color: var(--a-base-10);

&:hover, &:focus {
color: var(--a-primary-light-40);
background-color: var(--a-base-10);
}

&[aria-selected="true"], &[aria-selected="true"]:hover, &[aria-selected="true"]:focus {
color: var(--a-primary);
background-color: var(--a-base-10);
border-bottom: 3px solid var(--a-primary);
}
}

.apos-modal-tabs__btn::before {
content: none;
}
}

.apos-modal-tabs__tabs {
display: flex;
flex-direction: column;
Expand Down
Expand Up @@ -9,19 +9,29 @@
@no-modal="$emit('safe-close')"
>
<template #breadcrumbs>
<AposModalBreadcrumbs
v-if="breadcrumbs && breadcrumbs.length"
:items="breadcrumbs"
<AposModalBreadcrumbs v-if="breadcrumbs && breadcrumbs.length" :items="breadcrumbs" />
<AposModalTabs
v-if="tabs.length"
:key="tabKey"
:current="currentTab"
:tabs="tabs"
orientation="horizontal"
:errors="fieldErrors"
@select-tab="switchPane"
/>
</template>
<template #main>
<AposModalBody>
<template #bodyMain>
<div class="apos-widget-editor__body">
<AposSchema
ref="schema"
v-for="tab in tabs"
v-show="tab.name === currentTab"
:key="tab.name"
:ref="tab.name"
:trigger-validation="triggerValidation"
:schema="schema"
:current-fields="groups[tab.name].fields"
:schema="groups[tab.name].schema"
:model-value="docFields"
:meta="meta"
:following-values="followingValues()"
Expand Down Expand Up @@ -52,13 +62,14 @@
<script>
import AposModifiedMixin from 'Modules/@apostrophecms/ui/mixins/AposModifiedMixin';
import AposEditorMixin from 'Modules/@apostrophecms/modal/mixins/AposEditorMixin';
import AposModalTabsMixin from 'Modules/@apostrophecms/modal/mixins/AposModalTabsMixin';
import { detectDocChange } from 'Modules/@apostrophecms/schema/lib/detectChange';
import cuid from 'cuid';
import { klona } from 'klona';

export default {
name: 'AposWidgetEditor',
mixins: [ AposModifiedMixin, AposEditorMixin ],
mixins: [ AposModifiedMixin, AposEditorMixin, AposModalTabsMixin ],
props: {
type: {
required: true,
Expand Down Expand Up @@ -107,6 +118,7 @@ export default {
data: {},
hasErrors: false
},
fieldErrors: {},
modal: {
title: this.editLabel,
active: false,
Expand Down Expand Up @@ -181,10 +193,14 @@ export default {
},
methods: {
updateDocFields(value) {
this.docFields = value;
this.docFields.data = {
...this.docFields.data,
...value.data
};
this.evaluateConditions();
},
async save() {
const widget = klona(this.docFields.data);
this.triggerValidation = true;
this.$nextTick(async () => {
if (this.docFields.hasErrors) {
Expand All @@ -199,7 +215,6 @@ export default {
});
return;
}
const widget = this.docFields.data;
if (!widget.type) {
widget.type = this.type;
}
Expand Down