mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
feat: add input color (#2257)
* feat: add input color * patterns will always be there --------- Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
committed by
Aiden McClelland
parent
833c1f22a3
commit
e0ee89bdd9
22
frontend/package-lock.json
generated
22
frontend/package-lock.json
generated
@@ -19,6 +19,8 @@
|
|||||||
"@angular/router": "^14.1.0",
|
"@angular/router": "^14.1.0",
|
||||||
"@angular/service-worker": "^14.2.2",
|
"@angular/service-worker": "^14.2.2",
|
||||||
"@ionic/angular": "^6.1.15",
|
"@ionic/angular": "^6.1.15",
|
||||||
|
"@maskito/angular": "^0.10.0",
|
||||||
|
"@maskito/core": "^0.10.0",
|
||||||
"@materia-ui/ngx-monaco-editor": "^6.0.0",
|
"@materia-ui/ngx-monaco-editor": "^6.0.0",
|
||||||
"@ng-web-apis/common": "^2.0.0",
|
"@ng-web-apis/common": "^2.0.0",
|
||||||
"@ng-web-apis/mutation-observer": "^2.0.0",
|
"@ng-web-apis/mutation-observer": "^2.0.0",
|
||||||
@@ -3498,6 +3500,26 @@
|
|||||||
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
|
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@maskito/angular": {
|
||||||
|
"version": "0.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@maskito/angular/-/angular-0.10.0.tgz",
|
||||||
|
"integrity": "sha512-RpwN4zj//IV1Lnm1kkDlxej7XuhSlkr3VfkG+dAkl7gJsqdnLnrSFesnId564vwI6oxXZHEGzSpujXdQwje7Kg==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": ">=12.0.0",
|
||||||
|
"@angular/core": ">=12.0.0",
|
||||||
|
"@angular/forms": ">=12.0.0",
|
||||||
|
"@maskito/core": "^0.10.0",
|
||||||
|
"rxjs": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@maskito/core": {
|
||||||
|
"version": "0.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@maskito/core/-/core-0.10.0.tgz",
|
||||||
|
"integrity": "sha512-ChCGFiA5uIOVetctbFaWjv1EDj4WdHW2cWtOFuqGbTB4+NcIn//ubccjuTEV41Pb/gR4pyO0Fkv2RRzV+cLOmA=="
|
||||||
|
},
|
||||||
"node_modules/@materia-ui/ngx-monaco-editor": {
|
"node_modules/@materia-ui/ngx-monaco-editor": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@materia-ui/ngx-monaco-editor/-/ngx-monaco-editor-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@materia-ui/ngx-monaco-editor/-/ngx-monaco-editor-6.0.0.tgz",
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
"@angular/router": "^14.1.0",
|
"@angular/router": "^14.1.0",
|
||||||
"@angular/service-worker": "^14.2.2",
|
"@angular/service-worker": "^14.2.2",
|
||||||
"@ionic/angular": "^6.1.15",
|
"@ionic/angular": "^6.1.15",
|
||||||
|
"@maskito/angular": "^0.10.0",
|
||||||
|
"@maskito/core": "^0.10.0",
|
||||||
"@materia-ui/ngx-monaco-editor": "^6.0.0",
|
"@materia-ui/ngx-monaco-editor": "^6.0.0",
|
||||||
"@ng-web-apis/common": "^2.0.0",
|
"@ng-web-apis/common": "^2.0.0",
|
||||||
"@ng-web-apis/mutation-observer": "^2.0.0",
|
"@ng-web-apis/mutation-observer": "^2.0.0",
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ export abstract class Control<Spec extends ValueSpec, Value> {
|
|||||||
private readonly control: FormControlComponent<Spec, Value> =
|
private readonly control: FormControlComponent<Spec, Value> =
|
||||||
inject(FormControlComponent)
|
inject(FormControlComponent)
|
||||||
|
|
||||||
|
get invalid(): boolean {
|
||||||
|
return this.control.touched && this.control.invalid
|
||||||
|
}
|
||||||
|
|
||||||
get spec(): Spec {
|
get spec(): Spec {
|
||||||
return this.control.spec
|
return this.control.spec
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<tui-input
|
||||||
|
[maskito]="mask"
|
||||||
|
[tuiTextfieldCustomContent]="color"
|
||||||
|
[tuiTextfieldCleaner]="false"
|
||||||
|
[tuiHintContent]="spec.description"
|
||||||
|
[pseudoInvalid]="invalid"
|
||||||
|
[(ngModel)]="value"
|
||||||
|
(focusedChange)="onFocus($event)"
|
||||||
|
>
|
||||||
|
{{ spec.name }}
|
||||||
|
<span *ngIf="spec.required">*</span>
|
||||||
|
</tui-input>
|
||||||
|
<ng-template #color>
|
||||||
|
<div class="wrapper" [style.color]="value">
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
class="color"
|
||||||
|
tabindex="-1"
|
||||||
|
[(ngModel)]="value"
|
||||||
|
(click.stop)="(0)"
|
||||||
|
/>
|
||||||
|
<tui-svg
|
||||||
|
src="tuiIconPaintLarge"
|
||||||
|
tuiWrapper
|
||||||
|
appearance="icon"
|
||||||
|
class="icon"
|
||||||
|
></tui-svg>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
@import '@taiga-ui/core/styles/taiga-ui-local';
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: 0.3rem;
|
||||||
|
width: 1.4rem;
|
||||||
|
bottom: 0.125rem;
|
||||||
|
background: currentColor;
|
||||||
|
border-radius: 0.125rem;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.color {
|
||||||
|
@include fullsize();
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@include fullsize();
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
input:hover + & {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { Component } from '@angular/core'
|
||||||
|
import { ValueSpecColor } from 'start-sdk/lib/config/configTypes'
|
||||||
|
import { Control } from '../control'
|
||||||
|
import { MaskitoOptions } from '@maskito/core'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'form-color',
|
||||||
|
templateUrl: './form-color.component.html',
|
||||||
|
styleUrls: ['./form-color.component.scss'],
|
||||||
|
})
|
||||||
|
export class FormColorComponent extends Control<ValueSpecColor, string> {
|
||||||
|
readonly mask: MaskitoOptions = {
|
||||||
|
mask: ['#', ...Array(6).fill(/[0-9a-f]/i)],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
<ng-container [ngSwitch]="spec.type">
|
<ng-container [ngSwitch]="spec.type">
|
||||||
<form-text *ngSwitchCase="'text'"></form-text>
|
<form-color *ngSwitchCase="'color'"></form-color>
|
||||||
|
<form-file *ngSwitchCase="'file'"></form-file>
|
||||||
|
<form-multiselect *ngSwitchCase="'multiselect'"></form-multiselect>
|
||||||
<form-number *ngSwitchCase="'number'"></form-number>
|
<form-number *ngSwitchCase="'number'"></form-number>
|
||||||
|
<form-select *ngSwitchCase="'select'"></form-select>
|
||||||
|
<form-text *ngSwitchCase="'text'"></form-text>
|
||||||
<form-textarea *ngSwitchCase="'textarea'"></form-textarea>
|
<form-textarea *ngSwitchCase="'textarea'"></form-textarea>
|
||||||
<form-toggle *ngSwitchCase="'toggle'"></form-toggle>
|
<form-toggle *ngSwitchCase="'toggle'"></form-toggle>
|
||||||
<form-select *ngSwitchCase="'select'"></form-select>
|
|
||||||
<form-multiselect *ngSwitchCase="'multiselect'"></form-multiselect>
|
|
||||||
<form-file *ngSwitchCase="'file'"></form-file>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<tui-error [error]="order | tuiFieldError | async"></tui-error>
|
<tui-error [error]="order | tuiFieldError | async"></tui-error>
|
||||||
<ng-template *ngIf="spec.warning" #warning let-completeWith="completeWith">
|
<ng-template *ngIf="spec.warning" #warning let-completeWith="completeWith">
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ interface ValidatorsPatternError {
|
|||||||
pattern: ({ requiredPattern }: ValidatorsPatternError) =>
|
pattern: ({ requiredPattern }: ValidatorsPatternError) =>
|
||||||
control.spec.patterns.find(
|
control.spec.patterns.find(
|
||||||
({ regex }) => String(regex) === String(requiredPattern),
|
({ regex }) => String(regex) === String(requiredPattern),
|
||||||
)?.description || 'Invalid pattern',
|
)?.description || 'Invalid format',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<tui-input-files
|
<tui-input-files
|
||||||
[pseudoInvalid]="true"
|
[pseudoInvalid]="invalid"
|
||||||
[(ngModel)]="value"
|
[(ngModel)]="value"
|
||||||
(focusedChange)="onFocus($event)"
|
(focusedChange)="onFocus($event)"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<tui-multi-select
|
<tui-multi-select
|
||||||
[tuiHintContent]="spec.description"
|
[tuiHintContent]="spec.description"
|
||||||
|
[pseudoInvalid]="invalid"
|
||||||
[editable]="false"
|
[editable]="false"
|
||||||
[disabledItemHandler]="disabledItemHandler"
|
[disabledItemHandler]="disabledItemHandler"
|
||||||
[(ngModel)]="selected"
|
[(ngModel)]="selected"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<tui-input-number
|
<tui-input-number
|
||||||
[tuiHintContent]="spec.description"
|
[tuiHintContent]="spec.description"
|
||||||
[tuiTextfieldPostfix]="spec.units || ''"
|
[tuiTextfieldPostfix]="spec.units || ''"
|
||||||
|
[pseudoInvalid]="invalid"
|
||||||
[precision]="Infinity"
|
[precision]="Infinity"
|
||||||
[decimal]="spec.integer ? 'never' : 'not-zero'"
|
[decimal]="spec.integer ? 'never' : 'not-zero'"
|
||||||
[min]="spec.min ?? -Infinity"
|
[min]="spec.min ?? -Infinity"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<tui-select
|
<tui-select
|
||||||
[tuiHintContent]="spec.description"
|
[tuiHintContent]="spec.description"
|
||||||
[tuiTextfieldCleaner]="!spec.required"
|
[tuiTextfieldCleaner]="!spec.required"
|
||||||
|
[pseudoInvalid]="invalid"
|
||||||
[(ngModel)]="selected"
|
[(ngModel)]="selected"
|
||||||
(focusedChange)="onFocus($event)"
|
(focusedChange)="onFocus($event)"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<tui-input
|
<tui-input
|
||||||
[tuiTextfieldCustomContent]="spec.masked ? toggle : ''"
|
[tuiTextfieldCustomContent]="spec.masked ? toggle : ''"
|
||||||
[tuiHintContent]="spec.description"
|
[tuiHintContent]="spec.description"
|
||||||
|
[pseudoInvalid]="invalid"
|
||||||
[(ngModel)]="value"
|
[(ngModel)]="value"
|
||||||
(focusedChange)="onFocus($event)"
|
(focusedChange)="onFocus($event)"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<tui-text-area
|
<tui-text-area
|
||||||
[tuiHintContent]="spec.description"
|
[tuiHintContent]="spec.description"
|
||||||
|
[pseudoInvalid]="invalid"
|
||||||
[expandable]="true"
|
[expandable]="true"
|
||||||
[rows]="6"
|
[rows]="6"
|
||||||
[maxLength]="spec.maxLength"
|
[maxLength]="spec.maxLength"
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ import {
|
|||||||
TuiHintModule,
|
TuiHintModule,
|
||||||
TuiLinkModule,
|
TuiLinkModule,
|
||||||
TuiModeModule,
|
TuiModeModule,
|
||||||
|
TuiSvgModule,
|
||||||
TuiTextfieldControllerModule,
|
TuiTextfieldControllerModule,
|
||||||
TuiTooltipModule,
|
TuiTooltipModule,
|
||||||
|
TuiWrapperModule,
|
||||||
} from '@taiga-ui/core'
|
} from '@taiga-ui/core'
|
||||||
import {
|
import {
|
||||||
TuiElasticContainerModule,
|
TuiElasticContainerModule,
|
||||||
@@ -40,6 +42,8 @@ import { FormArrayComponent } from './form-array/form-array.component'
|
|||||||
import { FormControlComponent } from './form-control/form-control.component'
|
import { FormControlComponent } from './form-control/form-control.component'
|
||||||
import { MustachePipe } from './mustache.pipe'
|
import { MustachePipe } from './mustache.pipe'
|
||||||
import { ControlDirective } from './control.directive'
|
import { ControlDirective } from './control.directive'
|
||||||
|
import { FormColorComponent } from './form-color/form-color.component'
|
||||||
|
import { MaskitoModule } from '@maskito/angular'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -66,10 +70,14 @@ import { ControlDirective } from './control.directive'
|
|||||||
TuiFieldErrorPipeModule,
|
TuiFieldErrorPipeModule,
|
||||||
TuiValueChangesModule,
|
TuiValueChangesModule,
|
||||||
TuiElasticContainerModule,
|
TuiElasticContainerModule,
|
||||||
|
MaskitoModule,
|
||||||
|
TuiSvgModule,
|
||||||
|
TuiWrapperModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
FormGroupComponent,
|
FormGroupComponent,
|
||||||
FormControlComponent,
|
FormControlComponent,
|
||||||
|
FormColorComponent,
|
||||||
FormTextComponent,
|
FormTextComponent,
|
||||||
FormToggleComponent,
|
FormToggleComponent,
|
||||||
FormTextareaComponent,
|
FormTextareaComponent,
|
||||||
|
|||||||
@@ -766,6 +766,14 @@ export module Mock {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
background: {
|
||||||
|
name: 'Background',
|
||||||
|
type: 'color',
|
||||||
|
description: 'Background color for the service',
|
||||||
|
warning: null,
|
||||||
|
required: false,
|
||||||
|
default: '#000000',
|
||||||
|
},
|
||||||
advanced: {
|
advanced: {
|
||||||
name: 'Advanced',
|
name: 'Advanced',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
unionSelectKey,
|
unionSelectKey,
|
||||||
ValueSpecTextarea,
|
ValueSpecTextarea,
|
||||||
unionValueKey,
|
unionValueKey,
|
||||||
|
ValueSpecColor,
|
||||||
} from 'start-sdk/lib/config/configTypes'
|
} from 'start-sdk/lib/config/configTypes'
|
||||||
const Mustache = require('mustache')
|
const Mustache = require('mustache')
|
||||||
|
|
||||||
@@ -123,6 +124,13 @@ export class FormService {
|
|||||||
value = spec.default || null
|
value = spec.default || null
|
||||||
}
|
}
|
||||||
return this.formBuilder.control(value, numberValidators(spec))
|
return this.formBuilder.control(value, numberValidators(spec))
|
||||||
|
case 'color':
|
||||||
|
if (currentValue !== undefined) {
|
||||||
|
value = currentValue
|
||||||
|
} else {
|
||||||
|
value = spec.default || null
|
||||||
|
}
|
||||||
|
return this.formBuilder.control(value, colorValidators(spec))
|
||||||
case 'object':
|
case 'object':
|
||||||
return this.getFormGroup(spec.spec, [], currentValue)
|
return this.getFormGroup(spec.spec, [], currentValue)
|
||||||
case 'list':
|
case 'list':
|
||||||
@@ -198,6 +206,16 @@ function textareaValidators(spec: ValueSpecTextarea): ValidatorFn[] {
|
|||||||
return validators
|
return validators
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function colorValidators({ required }: ValueSpecColor): ValidatorFn[] {
|
||||||
|
const validators: ValidatorFn[] = [Validators.pattern(/^#[0-9a-f]{6}$/i)]
|
||||||
|
|
||||||
|
if (required) {
|
||||||
|
validators.push(Validators.required)
|
||||||
|
}
|
||||||
|
|
||||||
|
return validators
|
||||||
|
}
|
||||||
|
|
||||||
function numberValidators(
|
function numberValidators(
|
||||||
spec: ValueSpecNumber | ListValueSpecNumber,
|
spec: ValueSpecNumber | ListValueSpecNumber,
|
||||||
): ValidatorFn[] {
|
): ValidatorFn[] {
|
||||||
|
|||||||
Reference in New Issue
Block a user