diff --git a/src/app/components/entity-detail/detail-entity/detail-entity.component.html b/src/app/components/entity-detail/detail-entity/detail-entity.component.html index a2b235ee..5f991343 100644 --- a/src/app/components/entity-detail/detail-entity/detail-entity.component.html +++ b/src/app/components/entity-detail/detail-entity/detail-entity.component.html @@ -62,7 +62,9 @@

{{ physicalEntity.title }}

@if (hasPersonsOrInstitutions()) { - {{ 'Persons and Institutions' | translate }} + + {{ 'Persons and Institutions' | translate }} + @if (persons(); as persons) { @@ -134,28 +136,6 @@

{{ physicalEntity.title }}

}
} - @if (hasOtherMetadata()) { - - - {{ 'Other' | translate }} - - - @for (entry of otherMetadata(); track entry) { -
- @if (entry.description) { -

- {{ entry.description }} -

- } - @if (entry.value) { -

- {{ entry.value }} -

- } -
- } -
- } @if (hasMetadataFiles()) { @@ -200,7 +180,9 @@

{{ physicalEntity.title }}

@if (hasPersonsOrInstitutions()) { - {{ 'Persons and Institutions' | translate }} + + {{ 'Persons and Institutions' | translate }} + @if (persons(); as persons) { @@ -272,28 +254,6 @@

{{ physicalEntity.title }}

}
} - @if (hasOtherMetadata()) { - - - {{ 'Other' | translate }} - - - @for (entry of otherMetadata(); track entry) { -
- @if (entry.description) { -

- {{ entry.description }} -

- } - @if (entry.value) { -

- {{ entry.value }} -

- } -
- } -
- } @if (hasMetadataFiles()) { diff --git a/src/app/components/entity-detail/detail-entity/detail-entity.component.ts b/src/app/components/entity-detail/detail-entity/detail-entity.component.ts index b5b42411..56c1fa3a 100644 --- a/src/app/components/entity-detail/detail-entity/detail-entity.component.ts +++ b/src/app/components/entity-detail/detail-entity/detail-entity.component.ts @@ -46,15 +46,6 @@ export class DetailEntityComponent { return this.metadataFiles().length > 0; }); - otherMetadata = computed(() => { - const entity = this.entity(); - return entity.other; - }); - - hasOtherMetadata = computed(() => { - return this.otherMetadata().length > 0; - }); - bibRefs = computed(() => { const entity = this.entity(); return entity.biblioRefs; diff --git a/src/app/components/metadata/address/address.component.html b/src/app/components/metadata/address/address.component.html index ab361e90..34c9da80 100644 --- a/src/app/components/metadata/address/address.component.html +++ b/src/app/components/metadata/address/address.component.html @@ -9,75 +9,58 @@ @if (address) {
- - {{ 'Country' | translate }} - - - - - {{ 'Postal Code' | translate }} - - - - - {{ 'City' | translate }} - - - - - {{ 'Street' | translate }} - - - - - {{ 'Number' | translate }} - - - - - {{ 'Building' | translate }} - - - + + + + + + + + + + + + +
} diff --git a/src/app/components/metadata/address/address.component.ts b/src/app/components/metadata/address/address.component.ts index 7d15a706..e3bc034d 100644 --- a/src/app/components/metadata/address/address.component.ts +++ b/src/app/components/metadata/address/address.component.ts @@ -1,15 +1,14 @@ import { Component, Input } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { MatFormField, MatLabel } from '@angular/material/form-field'; -import { MatInput } from '@angular/material/input'; import { Address } from 'src/app/metadata'; import { TranslatePipe } from '../../../pipes/translate.pipe'; +import { OutlinedInputComponent } from '../../outlined-input/outlined-input.component'; @Component({ selector: 'app-address', templateUrl: './address.component.html', styleUrls: ['./address.component.scss'], - imports: [MatFormField, MatLabel, MatInput, FormsModule, TranslatePipe], + imports: [FormsModule, TranslatePipe, OutlinedInputComponent], }) export class AddressComponent { @Input('address') diff --git a/src/app/components/metadata/agents/agents.component.html b/src/app/components/metadata/agents/agents.component.html index 00e75dbc..90b78399 100644 --- a/src/app/components/metadata/agents/agents.component.html +++ b/src/app/components/metadata/agents/agents.component.html @@ -1,3 +1,4 @@ + {{ 'Related persons and institutions' | translate }} + + + +

{{ 'Optional metadata:' | translate }}

+
+ -

{{ 'Optional metadata:' | translate }}

- - + + - - - - + - - - + - + {{ 'Metadata files' | translate }} + + +
@@ -212,11 +186,7 @@ @if (digitalEntity(); as digitalEntity) { -

- {{ - 'Select a license that fits the way other users are allowed to use it.' | translate - }} -

+
@for (item of availableLicences | keyvalue; track item.key) { @@ -241,23 +211,15 @@
- +
- - - @if (digitalEntity(); as digitalEntity) { - - } - - - @if (digitalEntity(); as digitalEntity) { - + } @@ -267,33 +229,27 @@ @if (digitalEntity(); as digitalEntity) { - + } - + - + - - - - - - @if (digitalEntity(); as digitalEntity) { - + } @@ -301,7 +257,7 @@ @if (digitalEntity(); as digitalEntity) { - + } diff --git a/src/app/components/metadata/entity/entity.component.scss b/src/app/components/metadata/entity/entity.component.scss index 88f41f33..5afdbabc 100644 --- a/src/app/components/metadata/entity/entity.component.scss +++ b/src/app/components/metadata/entity/entity.component.scss @@ -131,10 +131,19 @@ app-agent-card:not(:last-child) { } .mat-expansion-panel { + .mat-expansion-panel-header.mat-expanded { + border-color: transparent; + } + + .mat-expansion-panel-header, + .mat-expansion-panel-header.mat-expanded { + height: 44px; + padding: 0 16px; + } .mat-expansion-panel-body { - margin-top: 1rem; display: flex; flex-direction: column; + padding: 0; } &.single-column .mat-expansion-panel-body { > div.card + div.card { @@ -222,7 +231,7 @@ mat-tab-group.mat-mdc-tab-group.mat-primary.mat-mdc-tab-group-stretch-tabs { } .optional-text { - font-size: 14px; + font-size: 16px; font-weight: bold; } @@ -280,3 +289,7 @@ div.card .actions { .mat-mdc-list-item:focus { background-color: transparent !important; } + +.expansion-divider { + border-top-width: 2px; +} diff --git a/src/app/components/metadata/entity/entity.component.ts b/src/app/components/metadata/entity/entity.component.ts index ea87ea55..48a54bb1 100644 --- a/src/app/components/metadata/entity/entity.component.ts +++ b/src/app/components/metadata/entity/entity.component.ts @@ -36,12 +36,11 @@ import { AgentsComponent } from '../agents/agents.component'; import { GeneralComponent } from '../general/general.component'; import { BiblioRefComponent } from '../optional/biblio-ref/biblio-ref.component'; import { CreationComponent } from '../optional/creation/creation.component'; -import { DimensionComponent } from '../optional/dimension/dimension.component'; import { ExternalIdsComponent } from '../optional/external-ids/external-ids.component'; import { LinksComponent } from '../optional/links/links.component'; import { MetadataFilesComponent } from '../optional/metadata-files/metadata-files.component'; -import { OtherComponent } from '../optional/other/other.component'; import { PhysObjComponent } from '../optional/phys-obj/phys-obj.component'; +import { MatExpansionModule } from '@angular/material/expansion'; type AnyEntity = DigitalEntity | PhysicalEntity; @@ -64,12 +63,11 @@ type AnyEntity = DigitalEntity | PhysicalEntity; LinksComponent, PhysObjComponent, GeneralComponent, - DimensionComponent, ExternalIdsComponent, BiblioRefComponent, MetadataFilesComponent, - OtherComponent, KeyValuePipe, + MatExpansionModule, ], }) export class EntityComponent { @@ -89,12 +87,10 @@ export class EntityComponent { 'General', 'Licence', 'Related', - 'Dimensions', 'Creation', 'Ids', 'Links', 'References', - 'Other', 'Files', 'Physical', ]; @@ -319,11 +315,6 @@ export class EntityComponent { return undefined === entity.biblioRefs.find(c => !DescriptionValueTuple.checkIsValid(c, false)); } - get otherValid() { - const entity = this.entity(); - return undefined === entity.other.find(c => !DescriptionValueTuple.checkIsValid(c)); - } - get metadataFilesValid() { const entity = this.entity(); return undefined === entity.metadata_files.find(c => !FileTuple.checkIsValid(c)); @@ -381,8 +372,6 @@ export class EntityComponent { return entity.externalLink.push(new DescriptionValueTuple()); case 'biblioRefs': return entity.biblioRefs.push(new DescriptionValueTuple()); - case 'other': - return entity.other.push(new DescriptionValueTuple()); case 'metadata_files': const input = document.createElement('input'); input.type = 'file'; diff --git a/src/app/components/metadata/general/general.component.html b/src/app/components/metadata/general/general.component.html index 5a3ab8a8..233293e6 100644 --- a/src/app/components/metadata/general/general.component.html +++ b/src/app/components/metadata/general/general.component.html @@ -1,118 +1,68 @@ @if (entity(); as entity) { - - {{ 'Title' | translate }} - - - - {{ 'Description' | translate }} - - +

+ {{ 'General Information' | translate }} +

+ + + } @if (physicalEntity(); as physicalEntity) { - - {{ 'Collection' | translate }} - - + } @if (digitalEntity(); as digitalEntity) { - - {{ 'Statement' | translate }} - - - - - {{ 'Object type' | translate }} - - - - - {{ 'Tags' | translate }} - - @for (tag of digitalEntity.tags; track tag; let index = $index) { - - {{ tag.value }} - cancel - - } - - + @for (tag of filteredTags$ | async; track tag) { - - {{ tag.value }} - + {{ tag.value }} } - {{ 'Seperate many tags by pressing comma or enter/return' | translate }} - + - - {{ 'Discipline' | translate }} - - @for (discipline of digitalEntity.discipline; track discipline; let index = $index) { - - {{ discipline }} - cancel - - } - - - - {{ 'Seperate many disciplines by pressing comma or enter/return' | translate }} - - +

{{ 'Seperate many tags by pressing comma or enter/return' | translate }}

+ + + @for (tag of digitalEntity.tags; track tag; let index = $index) { + + {{ tag.value }} + cancel + + } + } diff --git a/src/app/components/metadata/general/general.component.scss b/src/app/components/metadata/general/general.component.scss index 862fb592..65eccce4 100644 --- a/src/app/components/metadata/general/general.component.scss +++ b/src/app/components/metadata/general/general.component.scss @@ -1,13 +1,3 @@ -::ng-deep { - .mat-mdc-standard-chip:not(.mdc-evolution-chip--disabled) .mdc-evolution-chip__text-label { - color: var(--mat-chip-label-text-color, var(--mat-app-on-surface-variant)) !important; - } - - .mat-mdc-form-field-hint-wrapper { - padding: 0 !important; - } -} - -mat-form-field { - margin-bottom: 20px; +.tag-hint { + font-size: 12px; } diff --git a/src/app/components/metadata/general/general.component.ts b/src/app/components/metadata/general/general.component.ts index 994df547..7709190a 100644 --- a/src/app/components/metadata/general/general.component.ts +++ b/src/app/components/metadata/general/general.component.ts @@ -1,4 +1,3 @@ -import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { AsyncPipe } from '@angular/common'; import { Component, @@ -27,6 +26,7 @@ import { TranslatePipe } from 'src/app/pipes'; import { ContentProviderService } from 'src/app/services'; import { MetadataCommunicationService } from 'src/app/services/metadata-communication.service'; import { isDigitalEntity, isPhysicalEntity } from '@kompakkt/common'; +import { OutlinedInputComponent } from '../../outlined-input/outlined-input.component'; @Component({ selector: 'app-general', @@ -42,6 +42,7 @@ import { isDigitalEntity, isPhysicalEntity } from '@kompakkt/common'; ReactiveFormsModule, FormsModule, AsyncPipe, + OutlinedInputComponent, ], templateUrl: './general.component.html', styleUrl: './general.component.scss', @@ -61,10 +62,7 @@ export class GeneralComponent { @Output() remove = new EventEmitter(); - @ViewChild('tagInput') tagInput!: ElementRef; - public searchTag = new FormControl(''); - public separatorKeysCodes: number[] = [ENTER, COMMA]; public availableTags = new BehaviorSubject([]); @@ -72,6 +70,8 @@ export class GeneralComponent { private isInSelection: boolean = false; + public displayTag = () => ''; + constructor( public content: ContentProviderService, private metaService: MetadataCommunicationService, @@ -82,7 +82,7 @@ export class GeneralComponent { this.filteredTags$ = this.searchTag.valueChanges.pipe( startWith(''), - map(value => (value as string).toLowerCase()), + map(value => (value ?? '').toLowerCase()), // null-safe machen withLatestFrom(this.digitalEntity$), map(([value, digitalEntity]) => this.availableTags.value @@ -92,31 +92,13 @@ export class GeneralComponent { ); } - public addTag(event: MatChipInputEvent, digitalEntity: DigitalEntity) { - const tagText = event.value; - if (tagText !== '' && !this.isInSelection) { - const tag = new Tag(); - tag.value = tagText; - digitalEntity.addTag(tag); - // this.searchTag.patchValue(''); - // this.searchTag.setValue(''); - event.chipInput.inputElement.value = ''; - } - } - - public addDiscipline(event: MatChipInputEvent, digitalEntity: DigitalEntity) { - const discipline = event.value; - digitalEntity.discipline.push(discipline); - event.chipInput.inputElement.value = ''; - } - public async selectTag(event: MatAutocompleteSelectedEvent, digitalEntity: DigitalEntity) { const tagId = event.option.value; const tag = this.availableTags.value.find(t => t._id === tagId); - if (!tag) return console.warn(`Could not tag with id ${tagId}`); + if (!tag) return console.warn(`Could not find tag with id ${tagId}`); this.isInSelection = true; digitalEntity.addTag(tag); - this.tagInput.nativeElement.value = ''; + this.searchTag.setValue(''); setTimeout(() => (this.isInSelection = false)); } @@ -130,4 +112,20 @@ export class GeneralComponent { public onRemove(property: string, index: number) { this.remove.emit({ property, index }); } + + onChipKeydown(event: KeyboardEvent, entity: DigitalEntity): void { + const separators = ['Enter', ',']; + if (!separators.includes(event.key)) return; + + event.preventDefault(); + + const inputValue = this.searchTag.value?.trim(); + if (!inputValue || this.isInSelection) return; + + const tag = new Tag(); + tag.value = inputValue; + entity.addTag(tag); + + this.searchTag.setValue(''); + } } diff --git a/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.html b/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.html index ab2f039b..a98ef775 100644 --- a/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.html +++ b/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.html @@ -1,38 +1,43 @@
- - {{ 'Description' | translate }} - +

+ {{ 'Bibliographic references' | translate }} +

+ + + @if (dataIsEditable) { - } -
- - {{ 'Reference e.g. Title, Author, Year)' | translate }} - + + + @if (dataIsEditable) { - } - +
+
- +@if (!isPhysical()) { + +} diff --git a/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.scss b/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.scss index ad070749..fa150bdf 100644 --- a/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.scss +++ b/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.scss @@ -2,6 +2,7 @@ margin: 20px 0; display: flex; justify-content: flex-end; + gap: 10px; } .card { @@ -26,8 +27,3 @@ div.card .actions { right: 5px !important; margin-top: auto; } - -.editButton { - border: none; - background-color: transparent; -} diff --git a/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.ts b/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.ts index 3476839f..d8afb365 100644 --- a/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.ts +++ b/src/app/components/metadata/optional/biblio-ref/biblio-ref.component.ts @@ -1,4 +1,4 @@ -import { Component, input } from '@angular/core'; +import { Component, computed, input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; @@ -8,11 +8,12 @@ import { MatInputModule } from '@angular/material/input'; import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; import { Subscription } from 'rxjs'; -import { AnyEntity, DescriptionValueTuple } from 'src/app/metadata'; +import { AnyEntity, DescriptionValueTuple, PhysicalEntity } from 'src/app/metadata'; import { MetadataCommunicationService } from 'src/app/services/metadata-communication.service'; import { DataTuple } from '@kompakkt/common'; import { TranslatePipe } from '../../../../pipes/translate.pipe'; import { OptionalCardListComponent } from '../optional-card-list/optional-card-list.component'; +import { OutlinedInputComponent } from 'src/app/components/outlined-input/outlined-input.component'; @Component({ selector: 'app-biblio-ref', @@ -26,12 +27,14 @@ import { OptionalCardListComponent } from '../optional-card-list/optional-card-l ReactiveFormsModule, TranslatePipe, OptionalCardListComponent, + OutlinedInputComponent, ], templateUrl: './biblio-ref.component.html', styleUrl: './biblio-ref.component.scss', }) export class BiblioRefComponent { public entity = input.required(); + isPhysical = computed(() => this.entity() instanceof PhysicalEntity); public referenceControl = new FormControl('', { nonNullable: true }); public descriptionControl = new FormControl('', { nonNullable: true }); @@ -77,8 +80,6 @@ export class BiblioRefComponent { this.entity().biblioRefs[this.dataIndex].value = this.referenceControl.value ?? ''; this.resetFormFields(); - this.isUpdating = false; - this.dataIsEditable = false; } onEditData(inputElementString: string): void { diff --git a/src/app/components/metadata/optional/creation/creation.component.html b/src/app/components/metadata/optional/creation/creation.component.html index 964bdf27..e1f2f901 100644 --- a/src/app/components/metadata/optional/creation/creation.component.html +++ b/src/app/components/metadata/optional/creation/creation.component.html @@ -1,35 +1,53 @@
- - {{ ' Add technique (e.g. Laserscan or Modelling)' | translate }} - - - - {{ 'Add program' | translate }} - - - - {{ 'Add equipment' | translate }} - - - - {{ 'Add creation date (format: mm/dd/yyyy)' | translate }} - - - - -
-
- -
+ + + + + + + + + + - +
+ + + + +
+ - +
+ +
+ + + + +
diff --git a/src/app/components/metadata/optional/creation/creation.component.scss b/src/app/components/metadata/optional/creation/creation.component.scss index fb9b65e9..62b85a14 100644 --- a/src/app/components/metadata/optional/creation/creation.component.scss +++ b/src/app/components/metadata/optional/creation/creation.component.scss @@ -3,3 +3,9 @@ display: flex; justify-content: flex-end; } + +.material-date-input { + position: absolute; + visibility: hidden; + pointer-events: none; +} diff --git a/src/app/components/metadata/optional/creation/creation.component.ts b/src/app/components/metadata/optional/creation/creation.component.ts index 10825be4..b6880a94 100644 --- a/src/app/components/metadata/optional/creation/creation.component.ts +++ b/src/app/components/metadata/optional/creation/creation.component.ts @@ -1,12 +1,6 @@ import { formatDate } from '@angular/common'; -import { ChangeDetectionStrategy, Component, input } from '@angular/core'; -import { - AbstractControl, - FormControl, - ReactiveFormsModule, - ValidationErrors, - ValidatorFn, -} from '@angular/forms'; +import { ChangeDetectionStrategy, Component, computed, input, OnInit } from '@angular/core'; +import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { provideNativeDateAdapter } from '@angular/material/core'; @@ -19,6 +13,9 @@ import { CreationTuple, DigitalEntity } from 'src/app/metadata'; import { TranslatePipe } from '../../../../pipes/translate.pipe'; import { OptionalCardListComponent } from '../optional-card-list/optional-card-list.component'; +import { OutlinedInputComponent } from 'src/app/components/outlined-input/outlined-input.component'; +import { toSignal } from '@angular/core/rxjs-interop'; + @Component({ selector: 'app-creation', standalone: true, @@ -31,73 +28,97 @@ import { OptionalCardListComponent } from '../optional-card-list/optional-card-l ReactiveFormsModule, TranslatePipe, OptionalCardListComponent, + OutlinedInputComponent, ], templateUrl: './creation.component.html', styleUrl: './creation.component.scss', providers: [provideNativeDateAdapter()], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class CreationComponent { +export class CreationComponent implements OnInit { public entity = input.required(); - public techniqueControl = new FormControl(''); - public softwareControl = new FormControl(''); - public equipmentControl = new FormControl(''); - public dateControl = new FormControl(''); + form = new FormGroup({ + technique: new FormControl(''), + software: new FormControl(''), + equipment: new FormControl(''), + start: new FormControl(null), + end: new FormControl(null), + }); + + dateRangeDisplay = ''; + private readonly _formValues = toSignal(this.form.valueChanges, { + initialValue: this.form.value, + }); private readonly _currentYear = new Date().getFullYear(); readonly minDate = new Date(this._currentYear - 20, 0, 1); addNewCreationData() { - const value = this.dateControl.value; + const value = this.form.value; + + let formattedDate = ''; + if (value.start && value.end) { + const startStr = formatDate(value.start, 'MM/dd/yyyy', 'en-US'); + const endStr = formatDate(value.end, 'MM/dd/yyyy', 'en-US'); + formattedDate = `${startStr} - ${endStr}`; + } const creationInstance = new CreationTuple({ - technique: this.techniqueControl.value ?? '', - program: this.softwareControl.value ?? '', - equipment: this.equipmentControl.value ?? '', - date: value ? formatDate(value, 'yyyy-dd-MM', 'en-US') : '', + technique: value.technique ?? '', + program: value.software ?? '', + equipment: value.equipment ?? '', + date: formattedDate, }); this.resetFormFields(); - - console.log(creationInstance); this.entity().creation.push(creationInstance); } - get dateFormat(): boolean { - return this.dateControl.valid; - } + isFormValid = computed(() => { + const v = this._formValues(); + return !!v.technique || !!v.software || !!v.equipment || (!!v.start && !!v.end); + }); - get isFormValid(): boolean { - return ( - this.techniqueControl.value !== '' || - this.softwareControl.value !== '' || - this.equipmentControl.value !== '' || - this.dateControl.value !== '' - ); + resetFormFields() { + this.form.reset(); + this.dateRangeDisplay = ''; } - dateFormValidator(): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - if (!control.value) { - return null; - } + dateRangeForm = new FormGroup({ + start: new FormControl(null), + end: new FormControl(null), + }); + + onDateInput(event: Event): void { + const value = (event.target as HTMLInputElement).value; + const parts = value.split(/\s*[–-]\s*/).map(s => s.trim()); + if (parts.length !== 2) return; - // const dateRegex = /^\d{4}-\d{2}-\d{2}$/; - const dateRegex = /^\d{2}\/\d{2}\/\d{4}$/; - const isValid = dateRegex.test(control.value); - return isValid ? null : { invalidDateFormat: true }; - }; + const start = this.parseDate(parts[0]); + const end = this.parseDate(parts[1]); + + if (start && end) { + this.form.patchValue({ start, end }); + this.dateRangeDisplay = value; + } } - // get dateAlreadySet(): boolean { - // return this.entity.creation.some(set => !!set.date); - // } + private parseDate(str: string): Date | null { + const [day, month, year] = str.split('.').map(Number); + if (!day || !month || !year) return null; - resetFormFields() { - this.techniqueControl.setValue(''); - this.softwareControl.setValue(''); - this.equipmentControl.setValue(''); - this.dateControl.setValue(''); + const fullYear = year < 100 ? 2000 + year : year; + + const date = new Date(fullYear, month - 1, day); + return isNaN(date.getTime()) ? null : date; + } + + ngOnInit(): void { + this.form.valueChanges.subscribe(({ start, end }) => { + if (start && end) { + this.dateRangeDisplay = `${start.toLocaleDateString()} – ${end.toLocaleDateString()}`; + } + }); } } diff --git a/src/app/components/metadata/optional/dimension/dimension.component.html b/src/app/components/metadata/optional/dimension/dimension.component.html index 0e91a0e8..f312d7cf 100644 --- a/src/app/components/metadata/optional/dimension/dimension.component.html +++ b/src/app/components/metadata/optional/dimension/dimension.component.html @@ -1,35 +1,28 @@
- - {{ 'Unit description (e.g. Width of base)' | translate }} - {{ 'Dimension' | translate }}

+ + +
+ + - -
- - {{ 'Unit value' | translate }} - - - - {{ 'Unit type' | translate }} - -
@@ -44,6 +37,4 @@
- - diff --git a/src/app/components/metadata/optional/dimension/dimension.component.ts b/src/app/components/metadata/optional/dimension/dimension.component.ts index 6c683537..686beff9 100644 --- a/src/app/components/metadata/optional/dimension/dimension.component.ts +++ b/src/app/components/metadata/optional/dimension/dimension.component.ts @@ -4,9 +4,10 @@ import { MatButtonModule } from '@angular/material/button'; import { MatDividerModule } from '@angular/material/divider'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; -import { DigitalEntity, DimensionTuple } from 'src/app/metadata'; +import { DigitalEntity, DimensionTuple, PhysicalEntity } from 'src/app/metadata'; import { TranslatePipe } from 'src/app/pipes'; import { OptionalCardListComponent } from '../optional-card-list/optional-card-list.component'; +import { OutlinedInputComponent } from 'src/app/components/outlined-input/outlined-input.component'; @Component({ selector: 'app-dimension', @@ -19,12 +20,13 @@ import { OptionalCardListComponent } from '../optional-card-list/optional-card-l ReactiveFormsModule, TranslatePipe, OptionalCardListComponent, + OutlinedInputComponent, ], templateUrl: './dimension.component.html', styleUrl: './dimension.component.scss', }) export class DimensionComponent { - public entity = input.required(); + public entity = input.required(); public nameControl = new FormControl('', { nonNullable: true }); public valueControl = new FormControl('', { nonNullable: true }); diff --git a/src/app/components/metadata/optional/external-ids/external-ids.component.html b/src/app/components/metadata/optional/external-ids/external-ids.component.html index 45faa881..2d180698 100644 --- a/src/app/components/metadata/optional/external-ids/external-ids.component.html +++ b/src/app/components/metadata/optional/external-ids/external-ids.component.html @@ -1,23 +1,18 @@ - - {{ 'Type (e.g. DOI) ' | translate }} - - - - {{ 'Value' | translate }} - - +

+ {{ 'External identifiers' | translate }} +

+ +
- +@if (!isPhysical()) { + +} diff --git a/src/app/components/metadata/optional/external-ids/external-ids.component.ts b/src/app/components/metadata/optional/external-ids/external-ids.component.ts index d1342363..8e2a1c4c 100644 --- a/src/app/components/metadata/optional/external-ids/external-ids.component.ts +++ b/src/app/components/metadata/optional/external-ids/external-ids.component.ts @@ -1,14 +1,15 @@ import { AsyncPipe } from '@angular/common'; -import { Component, input } from '@angular/core'; +import { Component, computed, input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatDividerModule } from '@angular/material/divider'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { combineLatest, map, startWith } from 'rxjs'; -import { AnyEntity, TypeValueTuple } from 'src/app/metadata'; +import { AnyEntity, PhysicalEntity, TypeValueTuple } from 'src/app/metadata'; import { TranslatePipe } from 'src/app/pipes'; import { OptionalCardListComponent } from '../optional-card-list/optional-card-list.component'; +import { OutlinedInputComponent } from 'src/app/components/outlined-input/outlined-input.component'; @Component({ selector: 'app-external-ids', @@ -22,6 +23,7 @@ import { OptionalCardListComponent } from '../optional-card-list/optional-card-l ReactiveFormsModule, TranslatePipe, OptionalCardListComponent, + OutlinedInputComponent, ], templateUrl: './external-ids.component.html', styleUrl: './external-ids.component.scss', @@ -32,6 +34,8 @@ export class ExternalIdsComponent { public valueControl = new FormControl('', { nonNullable: true }); public typeControl = new FormControl('', { nonNullable: true }); + isPhysical = computed(() => this.entity() instanceof PhysicalEntity); + public isExternalIdentifiersValid$ = combineLatest([ this.valueControl.valueChanges.pipe(startWith(this.valueControl.value)), this.typeControl.valueChanges.pipe(startWith(this.typeControl.value)), diff --git a/src/app/components/metadata/optional/links/links.component.html b/src/app/components/metadata/optional/links/links.component.html index 2d9d7ae1..e0c76097 100644 --- a/src/app/components/metadata/optional/links/links.component.html +++ b/src/app/components/metadata/optional/links/links.component.html @@ -1,24 +1,19 @@
- - {{ 'Description' | translate }} - - - - {{ 'URL' | translate }} - - +

+ {{ 'External links' | translate }} +

+ +
- +@if (!isPhysical()) { + +} diff --git a/src/app/components/metadata/optional/links/links.component.ts b/src/app/components/metadata/optional/links/links.component.ts index 89c06e24..5883246e 100644 --- a/src/app/components/metadata/optional/links/links.component.ts +++ b/src/app/components/metadata/optional/links/links.component.ts @@ -1,5 +1,5 @@ import { AsyncPipe } from '@angular/common'; -import { Component, input } from '@angular/core'; +import { Component, computed, input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; @@ -8,9 +8,10 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { combineLatest, map, startWith } from 'rxjs'; -import { AnyEntity, DescriptionValueTuple } from 'src/app/metadata'; +import { AnyEntity, DescriptionValueTuple, PhysicalEntity } from 'src/app/metadata'; import { TranslatePipe } from '../../../../pipes/translate.pipe'; import { OptionalCardListComponent } from '../optional-card-list/optional-card-list.component'; +import { OutlinedInputComponent } from 'src/app/components/outlined-input/outlined-input.component'; @Component({ selector: 'app-links', @@ -24,6 +25,7 @@ import { OptionalCardListComponent } from '../optional-card-list/optional-card-l ReactiveFormsModule, TranslatePipe, OptionalCardListComponent, + OutlinedInputComponent, ], templateUrl: './links.component.html', styleUrl: './links.component.scss', @@ -34,6 +36,8 @@ export class LinksComponent { public valueControl = new FormControl('', { nonNullable: true }); public descriptionControl = new FormControl('', { nonNullable: true }); + isPhysical = computed(() => this.entity() instanceof PhysicalEntity); + public isLinkDataValid$ = combineLatest([ this.valueControl.valueChanges.pipe(startWith(this.valueControl.value)), this.descriptionControl.valueChanges.pipe(startWith(this.descriptionControl.value)), diff --git a/src/app/components/metadata/optional/metadata-files/metadata-files.component.html b/src/app/components/metadata/optional/metadata-files/metadata-files.component.html index 7fe52393..2cb19f59 100644 --- a/src/app/components/metadata/optional/metadata-files/metadata-files.component.html +++ b/src/app/components/metadata/optional/metadata-files/metadata-files.component.html @@ -1,4 +1,7 @@
+

+ {{ 'Metadatafiles' | translate }} +

{{ 'Add external meta data files. These files will be available for download.' | translate }}

@@ -8,7 +11,9 @@ {{ 'Add' | translate }}
- + @if (!isPhysical()) { + + }
@for (file of entity().metadata_files; track file; let index = $index) {
diff --git a/src/app/components/metadata/optional/metadata-files/metadata-files.component.ts b/src/app/components/metadata/optional/metadata-files/metadata-files.component.ts index 36e060b7..42a7e4c7 100644 --- a/src/app/components/metadata/optional/metadata-files/metadata-files.component.ts +++ b/src/app/components/metadata/optional/metadata-files/metadata-files.component.ts @@ -1,8 +1,8 @@ -import { Component, input } from '@angular/core'; +import { Component, computed, input } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; -import { AnyEntity, FileTuple } from 'src/app/metadata'; +import { AnyEntity, FileTuple, PhysicalEntity } from 'src/app/metadata'; import { FilesizePipe, TranslatePipe } from 'src/app/pipes'; @Component({ @@ -14,6 +14,7 @@ import { FilesizePipe, TranslatePipe } from 'src/app/pipes'; }) export class MetadataFilesComponent { public entity = input.required(); + isPhysical = computed(() => this.entity() instanceof PhysicalEntity); public removeProperty(property: string, index: number) { if (Array.isArray(this.entity()[property])) { diff --git a/src/app/components/metadata/optional/other/other.component.html b/src/app/components/metadata/optional/other/other.component.html deleted file mode 100644 index 042dd5f1..00000000 --- a/src/app/components/metadata/optional/other/other.component.html +++ /dev/null @@ -1,36 +0,0 @@ -
- - {{ 'Description' | translate }} - - - - {{ 'Value' | translate }} - - -
-
- -
- - - - diff --git a/src/app/components/metadata/optional/other/other.component.scss b/src/app/components/metadata/optional/other/other.component.scss deleted file mode 100644 index e1d29b71..00000000 --- a/src/app/components/metadata/optional/other/other.component.scss +++ /dev/null @@ -1,28 +0,0 @@ -.meta-button { - margin: 20px 0; - display: flex; - justify-content: flex-end; -} - -.card { - margin-top: 10px; - border-radius: 1rem !important; - justify-items: center; - justify-content: center; -} - -div.card .actions { - padding: 0 !important; - transform: none; -} - -.card p { - margin-block-end: 5px; - margin-block-start: 5px; -} - -.actions { - padding: 0 !important; - right: 5px !important; - margin-top: auto; -} diff --git a/src/app/components/metadata/optional/other/other.component.ts b/src/app/components/metadata/optional/other/other.component.ts deleted file mode 100644 index 2b2205d7..00000000 --- a/src/app/components/metadata/optional/other/other.component.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { AsyncPipe } from '@angular/common'; -import { Component, input } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; - -import { MatButtonModule } from '@angular/material/button'; -import { MatDividerModule } from '@angular/material/divider'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; - -import { combineLatest, map, startWith } from 'rxjs'; -import { AnyEntity, DescriptionValueTuple } from 'src/app/metadata'; -import { TranslatePipe } from '../../../../pipes/translate.pipe'; -import { OptionalCardListComponent } from '../optional-card-list/optional-card-list.component'; - -@Component({ - selector: 'app-other', - standalone: true, - imports: [ - ReactiveFormsModule, - MatButtonModule, - MatDividerModule, - MatFormFieldModule, - MatInputModule, - TranslatePipe, - OptionalCardListComponent, - AsyncPipe, - ], - templateUrl: './other.component.html', - styleUrl: './other.component.scss', -}) -export class OtherComponent { - public entity = input.required(); - - public valueControl = new FormControl('', { nonNullable: true }); - public descriptionControl = new FormControl('', { nonNullable: true }); - - public isOtherDataValid$ = combineLatest([ - this.valueControl.valueChanges.pipe(startWith(this.valueControl.value)), - this.descriptionControl.valueChanges.pipe(startWith(this.descriptionControl.value)), - ]).pipe(map(([value, description]) => value !== '' && description !== '')); - - async addNewOtherData() { - const otherInstance = new DescriptionValueTuple({ - value: this.valueControl.value ?? '', - description: this.descriptionControl.value ?? '', - }); - - if (otherInstance.isValid) { - this.entity().other.push(otherInstance); - this.resetFormFields(); - } - } - - resetFormFields() { - this.valueControl.reset(); - this.descriptionControl.reset(); - } -} diff --git a/src/app/components/metadata/optional/phys-obj/phys-obj.component.html b/src/app/components/metadata/optional/phys-obj/phys-obj.component.html index 742259e5..4b186cde 100644 --- a/src/app/components/metadata/optional/phys-obj/phys-obj.component.html +++ b/src/app/components/metadata/optional/phys-obj/phys-obj.component.html @@ -1,87 +1,37 @@ @if (physEntity(); as physEntity) { - - - - {{ 'General information' | translate }} - - - - + + - - - Place - + - - {{ 'Name' | translate }} - - - - {{ 'Geopolicital area' | translate }} - - - - + + + - - - - {{ 'Related persons and institutions' | translate }} - - - - + - - - {{ 'External Identifiers' | translate }} - - - + - - - {{ 'External Links' | translate }} - - - + - - - {{ 'Bibliographic References' | translate }} - - - + - - - {{ 'Other' | translate }} - - - + - - - {{ 'Metadata files' | translate }} - - - + } diff --git a/src/app/components/metadata/optional/phys-obj/phys-obj.component.ts b/src/app/components/metadata/optional/phys-obj/phys-obj.component.ts index 65f28fe7..9d0a1acf 100644 --- a/src/app/components/metadata/optional/phys-obj/phys-obj.component.ts +++ b/src/app/components/metadata/optional/phys-obj/phys-obj.component.ts @@ -14,7 +14,8 @@ import { BiblioRefComponent } from '../biblio-ref/biblio-ref.component'; import { ExternalIdsComponent } from '../external-ids/external-ids.component'; import { LinksComponent } from '../links/links.component'; import { MetadataFilesComponent } from '../metadata-files/metadata-files.component'; -import { OtherComponent } from '../other/other.component'; +import { OutlinedInputComponent } from '../../../outlined-input/outlined-input.component'; +import { DimensionComponent } from '../dimension/dimension.component'; @Component({ selector: 'app-phys-obj', @@ -33,7 +34,8 @@ import { OtherComponent } from '../other/other.component'; AddressComponent, ExternalIdsComponent, MetadataFilesComponent, - OtherComponent, + OutlinedInputComponent, + DimensionComponent, ], templateUrl: './phys-obj.component.html', styleUrl: './phys-obj.component.scss', diff --git a/src/app/components/outlined-input/outlined-input.component.html b/src/app/components/outlined-input/outlined-input.component.html index cc4bf25c..0e95a92f 100644 --- a/src/app/components/outlined-input/outlined-input.component.html +++ b/src/app/components/outlined-input/outlined-input.component.html @@ -1,11 +1,11 @@ @if (label(); as label) { - + } @switch (type()) { @case ('textarea') {