Skip to content

Commit 5f38ef3

Browse files
committed
feat(image-editor): UI/UX polish for the Angular image editor
- Accordion: design-aligned header (13px title, 11px subtitle, primary icon chip when open), collapsed by default, open sections persisted to localStorage - Adjust values are editable number fields synced with the sliders (clamped) - Undo/redo keyboard shortcuts on the dialog (Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z, Ctrl+Y); ignored while a text field is focused - Crop: Shift-drag a corner locks the starting aspect ratio - Address bar text/icon use the design's 78%-white dark-chrome tone - Canvas/footer layout + padding, gradient adjust sliders, taller dialog - Store: split panel events into Adjust/Transform/File-info groups, one withReducer per group, and move async effects to withEventHandlers - Remove unused Storybook wiring (story + .storybook glob) and the unused legacy Dojo and noop launchers Refs #36063
1 parent 2c623b3 commit 5f38ef3

53 files changed

Lines changed: 1356 additions & 774 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

core-web/apps/dotcms-ui/.storybook/main.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ module.exports = {
1414
'../../../libs/template-builder/**/*.stories.@(js|jsx|ts|tsx|mdx)',
1515
'../../../libs/block-editor/**/*.stories.@(js|jsx|ts|tsx|mdx)',
1616
'../../../libs/edit-content/**/*.stories.@(js|jsx|ts|tsx|mdx)',
17-
'../../../libs/image-editor/**/*.stories.@(js|jsx|ts|tsx|mdx)',
1817
'../../../libs/ui/**/*.stories.@(js|jsx|ts|tsx|mdx)',
1918
'../../../libs/portlets/**/*.stories.@(js|jsx|ts|tsx|mdx)'
2019
],

core-web/libs/edit-content/src/lib/edit-content.shell.component.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,25 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
22
import { RouterModule } from '@angular/router';
33

44
import { MessageService } from 'primeng/api';
5+
import { DialogService } from 'primeng/dynamicdialog';
56
import { ToastModule } from 'primeng/toast';
67

8+
import {
9+
AngularImageEditorLauncher,
10+
IMAGE_EDITOR_LAUNCHER
11+
} from './fields/shared/image-editor-launcher';
12+
713
@Component({
814
selector: 'dot-edit-content',
915
imports: [RouterModule, ToastModule],
10-
providers: [MessageService],
16+
providers: [
17+
MessageService,
18+
// Scope the new Angular image editor to the edit-content shell so it only
19+
// activates here and never leaks into the legacy/web-component path. DialogService
20+
// is required by AngularImageEditorLauncher to open the modal.
21+
DialogService,
22+
{ provide: IMAGE_EDITOR_LAUNCHER, useClass: AngularImageEditorLauncher }
23+
],
1124
template: '<p-toast /> <router-outlet />',
1225
styleUrls: ['./edit-content.shell.component.scss'],
1326
changeDetection: ChangeDetectionStrategy.OnPush

core-web/libs/edit-content/src/lib/fields/dot-edit-content-binary-field/dot-edit-content-binary-field.component.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ import { getFileMetadata, getUiMessage } from './utils/binary-field-utils';
6363

6464
import { DEFAULT_MONACO_CONFIG } from '../../models/dot-edit-content-field.constant';
6565
import { getFieldVariablesParsed, stringToJson } from '../../utils/functions.util';
66-
import { AngularImageEditorLauncher, IMAGE_EDITOR_LAUNCHER } from '../shared/image-editor-launcher';
66+
import { IMAGE_EDITOR_LAUNCHER } from '../shared/image-editor-launcher';
6767

6868
export const DEFAULT_BINARY_FIELD_MONACO_CONFIG: MonacoEditorConstructionOptions = {
6969
...DEFAULT_MONACO_CONFIG,
@@ -99,7 +99,6 @@ type SystemOptionsType = {
9999
DotBinaryFieldStore,
100100
DotLicenseService,
101101
DotBinaryFieldValidatorService,
102-
{ provide: IMAGE_EDITOR_LAUNCHER, useClass: AngularImageEditorLauncher },
103102
{
104103
multi: true,
105104
provide: NG_VALUE_ACCESSOR,
@@ -121,7 +120,10 @@ export class DotEditContentBinaryFieldComponent
121120
readonly #dotAiService = inject(DotAiService);
122121
readonly #dialogService = inject(DialogService);
123122
readonly #destroyRef = inject(DestroyRef);
124-
readonly #imageEditorLauncher = inject(IMAGE_EDITOR_LAUNCHER);
123+
// Optional: the launcher is provided by the Angular edit-content shell, so the new
124+
// image editor only activates there. When absent (e.g. a non-Angular host), or when
125+
// isAvailable() is false, `onEditImage()` safely no-ops.
126+
readonly #imageEditorLauncher = inject(IMAGE_EDITOR_LAUNCHER, { optional: true });
125127

126128
$isAIPluginInstalled = toSignal(this.#dotAiService.checkPluginInstallation(), {
127129
initialValue: false
@@ -399,12 +401,18 @@ export class DotEditContentBinaryFieldComponent
399401
* @memberof DotEditContentBinaryFieldComponent
400402
*/
401403
onEditImage() {
404+
const launcher = this.#imageEditorLauncher;
405+
406+
if (!launcher?.isAvailable()) {
407+
return;
408+
}
409+
402410
const inode = this.contentlet?.inode;
403411
const metadata = this.contentlet
404412
? (getFileMetadata(this.contentlet) as Partial<DotFileMetadata>)
405413
: null;
406414

407-
this.#imageEditorLauncher
415+
launcher
408416
.open({
409417
inode,
410418
tempId: this.tempId,

core-web/libs/edit-content/src/lib/fields/shared/image-editor-launcher/angular-image-editor.launcher.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,16 @@ describe('AngularImageEditorLauncher', () => {
3636
expect(spectator.service.isAvailable()).toBe(true);
3737
});
3838

39-
it('should open the DotImageEditorComponent with a closable, escapable dialog', () => {
39+
it('should open the DotImageEditorComponent with a headerless, closable, escapable dialog', () => {
4040
spectator.service.open(params).subscribe();
4141

4242
expect(spectator.inject(DialogService).open).toHaveBeenCalledWith(
4343
DotImageEditorComponent,
4444
expect.objectContaining({
4545
data: params,
4646
modal: true,
47+
// The editor renders its own header; PrimeNG's chrome header is hidden.
48+
showHeader: false,
4749
closable: true,
4850
closeOnEscape: true
4951
})

core-web/libs/edit-content/src/lib/fields/shared/image-editor-launcher/angular-image-editor.launcher.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,15 @@ export class AngularImageEditorLauncher implements DotImageEditorLauncher {
3232
*/
3333
open(params: ImageEditorOpenParams): Observable<DotCMSTempFile | null> {
3434
const ref = this.#dialogService.open(DotImageEditorComponent, {
35-
header: undefined,
35+
// The editor renders its own header (title + close ✕), so hide PrimeNG's
36+
// chrome header to avoid a duplicate. Closing is handled by the internal ✕
37+
// (DotImageEditorHeaderComponent) and the Esc key (closeOnEscape).
38+
showHeader: false,
3639
data: params,
37-
width: 'min(92vw, 75rem)',
38-
height: '90%',
40+
// Large landscape dialog: wider than tall. Generous caps keep it big on wide
41+
// screens while staying within the viewport on smaller ones.
42+
width: 'min(96vw, 90rem)',
43+
height: 'min(96vh, 60rem)',
3944
modal: true,
4045
draggable: false,
4146
resizable: false,

core-web/libs/edit-content/src/lib/fields/shared/image-editor-launcher/image-editor-launcher.token.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ export type { DotImageEditorLauncher, ImageEditorOpenParams } from '@dotcms/imag
77
/**
88
* DI seam for launching the image editor from the binary field.
99
*
10-
* Providers swap implementations (Angular dialog, legacy Dojo bridge, or noop)
11-
* without the consuming field knowing which editor surfaces the result.
10+
* The Angular edit-content shell provides the dialog-based launcher. When the
11+
* token is left unprovided, the binary field injects it as optional and hides
12+
* the "edit image" action, so no fallback implementation is needed.
1213
*/
1314
export const IMAGE_EDITOR_LAUNCHER = new InjectionToken<DotImageEditorLauncher>(
1415
'IMAGE_EDITOR_LAUNCHER'

core-web/libs/edit-content/src/lib/fields/shared/image-editor-launcher/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,3 @@ export {
44
ImageEditorOpenParams
55
} from './image-editor-launcher.token';
66
export { AngularImageEditorLauncher } from './angular-image-editor.launcher';
7-
export { LegacyDojoImageEditorLauncher } from './legacy-dojo-image-editor.launcher';
8-
export { NoopImageEditorLauncher } from './noop-image-editor.launcher';

core-web/libs/edit-content/src/lib/fields/shared/image-editor-launcher/legacy-dojo-image-editor.launcher.spec.ts

Lines changed: 0 additions & 96 deletions
This file was deleted.

core-web/libs/edit-content/src/lib/fields/shared/image-editor-launcher/legacy-dojo-image-editor.launcher.ts

Lines changed: 0 additions & 65 deletions
This file was deleted.

core-web/libs/edit-content/src/lib/fields/shared/image-editor-launcher/noop-image-editor.launcher.spec.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)