diff --git a/projects/common/id.service.ts b/projects/common/id.service.ts index 8acc04e0e65dffafc451cda8198fd673661ca525..e45dca5a69879085ca56838a601b54bae8754edd 100644 --- a/projects/common/id.service.ts +++ b/projects/common/id.service.ts @@ -21,6 +21,7 @@ export class IdService { 'radio-group-images': 0, 'drop-list': 0, cloze: 0, + frame: 0, value: 0 }; diff --git a/projects/common/models/uI-element.ts b/projects/common/models/uI-element.ts index 0ddd0d2a49a5d74115d6ec22d67f8de49a94964a..66ba3718a9c77bda516158b79fe9aaf9694b854b 100644 --- a/projects/common/models/uI-element.ts +++ b/projects/common/models/uI-element.ts @@ -3,7 +3,7 @@ import { IdService } from '../id.service'; export type UIElementType = 'text' | 'button' | 'text-field' | 'text-area' | 'checkbox' | 'dropdown' | 'radio' | 'image' | 'audio' | 'video' | 'likert' | 'likert_row' | 'radio-group-images' -| 'drop-list' | 'cloze' | 'spell-correct' | 'slider'; +| 'drop-list' | 'cloze' | 'spell-correct' | 'slider' | 'frame'; export type InputElementValue = string[] | string | number | boolean | DragNDropValueObject[] | null; export type DragNDropValueObject = { id: string; diff --git a/projects/common/shared.module.ts b/projects/common/shared.module.ts index cbd0a066106a21d4c5549af8c1fa04e6a726fdbb..199ea52dede95e034e18e2a3b50dff9b549f08af 100644 --- a/projects/common/shared.module.ts +++ b/projects/common/shared.module.ts @@ -46,6 +46,7 @@ import { TextFieldSimpleComponent } from './ui-elements/textfield-simple/text-fi import { SliderComponent } from './ui-elements/slider/slider.component'; import { SpellCorrectComponent } from './ui-elements/spell-correct/spell-correct.component'; import { DropListSimpleComponent } from './ui-elements/drop-list-simple/drop-list-simple.component'; +import { FrameComponent } from './ui-elements/frame/frame.component'; @NgModule({ imports: [ @@ -93,7 +94,8 @@ import { DropListSimpleComponent } from './ui-elements/drop-list-simple/drop-lis DropListSimpleComponent, SliderComponent, SpellCorrectComponent, - TextFieldSimpleComponent + TextFieldSimpleComponent, + FrameComponent ], exports: [ CommonModule, diff --git a/projects/common/ui-elements/frame/frame-element.ts b/projects/common/ui-elements/frame/frame-element.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c1efb115d46722e5e19e0128ec7881ef0a32ca6 --- /dev/null +++ b/projects/common/ui-elements/frame/frame-element.ts @@ -0,0 +1,29 @@ +import { + UIElement, + PositionedElement, + SurfaceElement, + SurfaceProperties, + PositionProperties +} from '../../models/uI-element'; +import { initPositionedElement, initSurfaceElement } from '../../util/unit-interface-initializer'; + +export class FrameElement extends UIElement implements PositionedElement, SurfaceElement { + borderWidth: number = 1; + borderColor: string = 'black'; + borderStyle: 'hidden' | 'solid' | 'dotted' | 'dashed' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset' = 'solid'; + borderRadius: number = 0; + + positionProps: PositionProperties; + surfaceProps: SurfaceProperties; + + constructor(serializedElement: UIElement) { + super(serializedElement); + Object.assign(this, serializedElement); + this.positionProps = initPositionedElement(serializedElement); + this.surfaceProps = initSurfaceElement(serializedElement); + + this.surfaceProps.backgroundColor = + serializedElement.surfaceProps?.backgroundColor as string || + 'transparent'; + } +} diff --git a/projects/common/ui-elements/frame/frame.component.ts b/projects/common/ui-elements/frame/frame.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..dde15dea64eedcf4bf3a9d27161c7ddfe918254c --- /dev/null +++ b/projects/common/ui-elements/frame/frame.component.ts @@ -0,0 +1,23 @@ +import { Component, Input } from '@angular/core'; +import { FrameElement } from './frame-element'; + +@Component({ + selector: 'app-frame', + template: ` + <div [style.width]="elementModel.borderStyle !== 'hidden' ? + 'calc(100% - ' + (elementModel.borderWidth * 2) + 'px)' : + '100%'" + [style.height]="elementModel.borderStyle !== 'hidden' ? + 'calc(100% - ' + (elementModel.borderWidth * 2) + 'px)' : + '100%'" + [style.border-style]="elementModel.borderStyle" + [style.border-width.px]="elementModel.borderStyle !== 'hidden' ? elementModel.borderWidth : ''" + [style.border-color]="elementModel.borderColor" + [style.border-radius.px]="elementModel.borderRadius" + [style.background-color]="elementModel.surfaceProps.backgroundColor"> + </div> + ` +}) +export class FrameComponent { + @Input() elementModel!: FrameElement; +} diff --git a/projects/common/util/element.factory.ts b/projects/common/util/element.factory.ts index deddd7dcdb3b24e1278aed20f88dfcf8b91de897..4ad43d1b0cb2ab35efdf341b6254f4b6834886cf 100644 --- a/projects/common/util/element.factory.ts +++ b/projects/common/util/element.factory.ts @@ -32,6 +32,8 @@ import { SliderElement } from '../ui-elements/slider/slider-element'; import { SpellCorrectElement } from '../ui-elements/spell-correct/spell-correct-element'; import { SliderComponent } from '../ui-elements/slider/slider.component'; import { SpellCorrectComponent } from '../ui-elements/spell-correct/spell-correct.component'; +import { FrameComponent } from '../ui-elements/frame/frame.component'; +import { FrameElement } from '../ui-elements/frame/frame-element'; export function createElement(elementModel: UIElement): UIElement { let newElement: UIElement; @@ -84,6 +86,9 @@ export function createElement(elementModel: UIElement): UIElement { case 'spell-correct': newElement = new SpellCorrectElement(elementModel); break; + case 'frame': + newElement = new FrameElement(elementModel); + break; default: throw new Error(`ElementType ${elementModel.type} not found!`); } @@ -128,6 +133,8 @@ export function getComponentFactory( return componentFactoryResolver.resolveComponentFactory(SliderComponent); case 'spell-correct': return componentFactoryResolver.resolveComponentFactory(SpellCorrectComponent); + case 'frame': + return componentFactoryResolver.resolveComponentFactory(FrameComponent); default: throw new Error('unknown element'); } diff --git a/projects/editor/src/app/components/unit-view/page-view/new-ui-element-panel/ui-element-toolbox.component.html b/projects/editor/src/app/components/unit-view/page-view/new-ui-element-panel/ui-element-toolbox.component.html index 5b5deeb3f8577b403e1150d39dae9dc3a6448772..2ff12016b9ee0ad5d102870cb319c44f92416ba4 100644 --- a/projects/editor/src/app/components/unit-view/page-view/new-ui-element-panel/ui-element-toolbox.component.html +++ b/projects/editor/src/app/components/unit-view/page-view/new-ui-element-panel/ui-element-toolbox.component.html @@ -14,6 +14,11 @@ <mat-icon>smart_button</mat-icon> Knopf </button> + <button mat-raised-button (click)="addUIElement('frame')" + draggable="true" (dragstart)="$event.dataTransfer?.setData('elementType','frame')"> + <mat-icon>crop_square</mat-icon> + Rahmen + </button> <button mat-raised-button (click)="addUIElement('text-field')" draggable="true" (dragstart)="$event.dataTransfer?.setData('elementType','text-field')"> <mat-icon>text_fields</mat-icon> diff --git a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties.component.html b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties.component.html index d3a5fc8a487309e6efdc3d510dd534708966c8bb..4c23420e517dae7b0944e6e7084a4216d252434f 100644 --- a/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties.component.html +++ b/projects/editor/src/app/components/unit-view/page-view/properties-panel/element-model-properties.component.html @@ -539,4 +539,42 @@ <input matInput type="number" [value]="combinedProperties.firstColumnSizeRatio" (input)="updateModel.emit({ property: 'firstColumnSizeRatio', value: $any($event.target).value })"> </mat-form-field> + + + + <mat-form-field *ngIf="combinedProperties.borderStyle !== undefined" + appearance="fill"> + <mat-label>{{'propertiesPanel.borderStyle' | translate }}</mat-label> + <mat-select [value]="combinedProperties.borderStyle" + (selectionChange)="updateModel.emit({ property: 'borderStyle', value: $event.value })"> + <mat-option *ngFor="let option of ['hidden', 'solid', 'dotted', 'dashed', + 'double', 'groove', 'ridge', 'inset', 'outset']" + [value]="option"> + {{ 'propertiesPanel.' + option | translate }} + </mat-option> + </mat-select> + </mat-form-field> + + <mat-form-field *ngIf="combinedProperties.borderColor !== undefined" + appearance="fill" class="mdInput textsingleline"> + <mat-label>{{'propertiesPanel.borderColor' | translate }}</mat-label> + <input matInput type="color" [value]="combinedProperties.borderColor" + (input)="updateModel.emit({ property: 'borderColor', value: $any($event.target).value })"> + </mat-form-field> + <mat-form-field *ngIf="combinedProperties.borderColor !== undefined" + appearance="fill" class="mdInput textsingleline"> + <mat-label>{{'propertiesPanel.borderColor' | translate }}</mat-label> + <input matInput type="text" [value]="combinedProperties.borderColor" + (input)="updateModel.emit({ property: 'borderColor', value: $any($event.target).value })"> + </mat-form-field> + + <mat-form-field *ngIf="combinedProperties.borderWidth !== undefined" + appearance="fill" class="mdInput textsingleline"> + <mat-label>{{'propertiesPanel.borderWidth' | translate }}</mat-label> + <input matInput type="number" #borderWidth="ngModel" min="0" + [ngModel]="combinedProperties.borderWidth" + (ngModelChange)="updateModel.emit({ property: 'borderWidth', + value: $event, + isInputValid: borderWidth.valid && $event !== null })"> + </mat-form-field> </div>