|
76 | 76 | /> |
77 | 77 | </li> |
78 | 78 | </ol> |
79 | | - <!-- FIXME Bring widget controls data from the widget config --> |
80 | 79 | <ol |
| 80 | + v-if="widgetBreadcrumbActions.length > 0" |
81 | 81 | class="apos-area-widget__breadcrumbs apos-area-widget__breadcrumbs--switch" |
82 | 82 | style="margin-left: 10px;" |
83 | 83 | > |
84 | 84 | <li class="apos-area-widget__breadcrumb"> |
85 | | - <AposBreadcrumbSwitch |
86 | | - :choices="[ |
87 | | - { label: 'Content', value: 'content' }, |
88 | | - { label: 'Layout', value: 'layout' } |
89 | | - ]" |
90 | | - name="switch" |
91 | | - value="layout" |
92 | | - @update="foo" |
| 85 | + <component |
| 86 | + :is="operation.component" |
| 87 | + v-for="operation in widgetBreadcrumbActions" |
| 88 | + :key="operation.key" |
| 89 | + v-bind="operation.props" |
| 90 | + v-on="operation.listeners" |
| 91 | + /> |
| 92 | + </li> |
| 93 | + </ol> |
| 94 | + <ol |
| 95 | + v-if="widgetBreadcrumbInfos.length > 0" |
| 96 | + class="apos-area-widget__breadcrumbs apos-area-widget__breadcrumbs--info" |
| 97 | + > |
| 98 | + <li> |
| 99 | + <component |
| 100 | + :is="operation.component" |
| 101 | + v-for="operation in widgetBreadcrumbInfos" |
| 102 | + :key="`info-${operation.key}`" |
| 103 | + v-bind="operation.props" |
| 104 | + v-on="operation.listeners" |
93 | 105 | /> |
94 | 106 | </li> |
95 | | - <AposIndicator |
96 | | - icon="information-outline-icon" |
97 | | - fill-color="var(--a-primary)" |
98 | | - tooltip="Use Content mode to edit your widgets and Layout mode to modify your columns" |
99 | | - class="apos-area-widget__breadcrumbs-switch__info" |
100 | | - /> |
101 | 107 | </ol> |
102 | 108 | </div> |
103 | 109 | <div |
@@ -345,6 +351,18 @@ export default { |
345 | 351 | }; |
346 | 352 | }, |
347 | 353 | computed: { |
| 354 | + operationButtonDefault() { |
| 355 | + return { |
| 356 | + iconOnly: true, |
| 357 | + icon: 'plus-icon', |
| 358 | + type: 'group', |
| 359 | + modifiers: [ 'small', 'inline' ], |
| 360 | + role: 'menuitem', |
| 361 | + class: 'apos-area-modify-controls__button', |
| 362 | + iconSize: 16, |
| 363 | + disableFocus: !this.isFocused |
| 364 | + }; |
| 365 | + }, |
348 | 366 | // Passed only to the preview layer (custom preview components). |
349 | 367 | followingValuesWithParent() { |
350 | 368 | return Object.entries(this.followingValues || {}) |
@@ -383,12 +401,32 @@ export default { |
383 | 401 | moduleOptions() { |
384 | 402 | return window.apos.area; |
385 | 403 | }, |
| 404 | + widgetModuleOptions() { |
| 405 | + return apos.modules[this.moduleOptions?.widgetManagers[this.widget?.type]] ?? {}; |
| 406 | + }, |
| 407 | + widgetBreadcrumbOperations() { |
| 408 | + return (this.widgetModuleOptions.widgetBreadcrumbOperations || []) |
| 409 | + .map((operation) => ({ |
| 410 | + component: this.getOperationComponent(operation), |
| 411 | + props: this.getOperationProps(operation), |
| 412 | + listeners: this.getOperationListeners(operation), |
| 413 | + key: operation.action || operation.name, |
| 414 | + type: operation.type |
| 415 | + })); |
| 416 | + }, |
| 417 | + widgetBreadcrumbActions() { |
| 418 | + return this.widgetBreadcrumbOperations.filter(op => op.type !== 'info'); |
| 419 | + }, |
| 420 | + widgetBreadcrumbInfos() { |
| 421 | + return this.widgetBreadcrumbOperations.filter(op => op.type === 'info'); |
| 422 | + }, |
386 | 423 | isFocused() { |
387 | 424 | if (this.isSuppressed) { |
388 | 425 | return false; |
389 | 426 | } |
390 | 427 |
|
391 | 428 | const isWidgetFocused = this.widgetFocused === this.widget._id; |
| 429 | + // FIXME: move to the watcher? |
392 | 430 | if (isWidgetFocused) { |
393 | 431 | document.addEventListener('click', this.unfocus); |
394 | 432 | } |
@@ -481,8 +519,86 @@ export default { |
481 | 519 | apos.bus.$off('widget-focus-parent', this.focusParent); |
482 | 520 | }, |
483 | 521 | methods: { |
484 | | - foo(update) { |
485 | | - console.log(`name: ${update.name}, value: ${update.value}`); |
| 522 | + getOperationComponent(operation) { |
| 523 | + if (operation.type === 'info') { |
| 524 | + return 'AposIndicator'; |
| 525 | + } |
| 526 | + if (operation.type === 'switch') { |
| 527 | + return 'AposBreadcrumbSwitch'; |
| 528 | + } |
| 529 | + return 'AposButton'; |
| 530 | + }, |
| 531 | + getOperationProps(operation) { |
| 532 | + if (operation.type === 'info') { |
| 533 | + return { |
| 534 | + // class: 'apos-area-widget__breadcrumbs-switch__info', |
| 535 | + fillColor: 'var(--a-primary)', |
| 536 | + icon: operation.icon, |
| 537 | + tooltip: operation.tooltip |
| 538 | + }; |
| 539 | + } |
| 540 | +
|
| 541 | + if (operation.type === 'switch') { |
| 542 | + return { |
| 543 | + name: operation.name, |
| 544 | + choices: operation.choices, |
| 545 | + value: operation.def, |
| 546 | + class: 'apos-area-modify-controls__button--switch' |
| 547 | + }; |
| 548 | + } |
| 549 | +
|
| 550 | + // Button by default |
| 551 | + return { |
| 552 | + ...this.operationButtonDefault, |
| 553 | + icon: operation.icon, |
| 554 | + action: operation.action, |
| 555 | + tooltip: operation.tooltip || null |
| 556 | + }; |
| 557 | + }, |
| 558 | + getOperationListeners(operation) { |
| 559 | + const listeners = {}; |
| 560 | + if (operation.type === 'info') { |
| 561 | + return listeners; |
| 562 | + } |
| 563 | + if (operation.type === 'switch') { |
| 564 | + listeners.update = (payload) => { |
| 565 | + this.emitOperation(operation, payload); |
| 566 | + }; |
| 567 | + } else { |
| 568 | + listeners.click = () => { |
| 569 | + this.handleOperationClick(operation); |
| 570 | + }; |
| 571 | + } |
| 572 | + return listeners; |
| 573 | + }, |
| 574 | + async handleOperationClick(operation) { |
| 575 | + const { modal } = operation; |
| 576 | + if (modal) { |
| 577 | + const result = await apos.modal.execute(modal, { |
| 578 | + widget: this.widget, |
| 579 | + widgetSchema: this.widgetModuleOptions.schema |
| 580 | + }); |
| 581 | + if (result) { |
| 582 | + // TODO: make sure the update method from |
| 583 | + // modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue |
| 584 | + // does the job and does not mess with the widget type and _id: |
| 585 | + this.$emit('update', result); |
| 586 | + } |
| 587 | + return; |
| 588 | + } |
| 589 | +
|
| 590 | + this.emitOperation(operation); |
| 591 | + }, |
| 592 | + emitOperation(operation, payload = {}) { |
| 593 | + if (operation.action) { |
| 594 | + this.$emit(operation.action, this.i); |
| 595 | + } else { |
| 596 | + apos.bus.$emit('widget-breadcrumb-operation', { |
| 597 | + ...payload, |
| 598 | + ...operation, |
| 599 | + _id: this.widget._id |
| 600 | + }); |
| 601 | + } |
486 | 602 | }, |
487 | 603 | getFocusForMenu({ menuId, isOpen }) { |
488 | 604 | if ( |
@@ -639,12 +755,28 @@ export default { |
639 | 755 | padding: 0; |
640 | 756 | } |
641 | 757 |
|
| 758 | + > li { |
| 759 | + display: flex; |
| 760 | + align-items: center; |
| 761 | + margin: 0; |
| 762 | + padding: 0; |
| 763 | +
|
| 764 | + } |
642 | 765 | } |
643 | 766 |
|
644 | | -.apos-area-widget__breadcrumbs-switch__info { |
645 | | - position: absolute; |
646 | | - transform: translateX(50%); |
647 | | - right: -10px; |
| 767 | +.apos-area-widget__breadcrumbs.apos-area-widget__breadcrumbs--info { |
| 768 | + display: flex; |
| 769 | + border: none; |
| 770 | + background-color: transparent; |
| 771 | +
|
| 772 | + > li { |
| 773 | + display: flex; |
| 774 | + align-items: center; |
| 775 | + gap: 5px; |
| 776 | + margin: 0; |
| 777 | + padding: 0; |
| 778 | +
|
| 779 | + } |
648 | 780 | } |
649 | 781 |
|
650 | 782 | @mixin showButton() { |
@@ -901,13 +1033,13 @@ export default { |
901 | 1033 |
|
902 | 1034 | & { |
903 | 1035 | display: flex; |
904 | | - height: 32px; |
905 | 1036 | box-sizing: border-box; |
906 | 1037 | align-items: center; |
| 1038 | + height: 32px; |
907 | 1039 | margin: 0 0 8px; |
908 | 1040 | padding: 4px 6px; |
909 | | - background-color: var(--a-background-primary); |
910 | 1041 | border: 1px solid var(--a-primary-transparent-50); |
| 1042 | + background-color: var(--a-background-primary); |
911 | 1043 | border-radius: 8px; |
912 | 1044 | } |
913 | 1045 | } |
|
0 commit comments