little styling

master
Boris Voropaev 2024-09-05 10:04:52 +03:00
parent f588583f73
commit 98e225a015
7 changed files with 319 additions and 362 deletions

View File

@ -0,0 +1,13 @@
<div class="input-img">
<div class="input-img-area">
<input #fileInput type="file" id="file-input" (change)="onFileInput($event)" [style.background-image]="backGround"/>
</div>
<label class="btn primary" for="file-input">Файл изображения</label>
<button type="button" class="btn icon remove" *ngIf="value" (click)="clear()">Удалить</button>
<!-- <p>Перетащите сюда или <span (click)="fileInput.click()">выберите файл</span> в формате JPEG или PNG общим объемом не более 10 Мбайт.</p> -->
<!-- *ngIf="upload.file" -->
<div class="indicator" *ngIf="upload.file">
<div class="label">Загружается файл {{upload.file?.name}}</div>
<!-- <div class="progress"><div class="fill" [style.width]="upload.progress + '%'"></div></div> -->
</div>
</div>

View File

@ -0,0 +1,31 @@
.input-img{
display: flex;
gap: 24px;
align-items: end;
.input-img-area{
display: inline-flex;
border: 1px solid var(--clr-gr);
border-radius: 12px;
padding: 12px;
}
}
input[type="file"]{
width: 240px;
height: 100px;
overflow: hidden ;
background: center no-repeat;
background-size: contain;
display: block;
&::file-selector-button {
width: 240px;
height: 100px;
color: transparent;
background-color: transparent;
padding: 10px 20px;
border: none;
cursor: pointer;
}
}

View File

@ -0,0 +1,50 @@
import { NgIf } from '@angular/common';
import { Component, EventEmitter, Output} from '@angular/core';
import { AssetsService } from '../../_services/assets.service';
import {HttpEventType, HttpResponse} from "@angular/common/http";
@Component({
selector: 'img-input',
standalone: true,
imports: [NgIf],
templateUrl: './img-input.component.html',
styleUrl: './img-input.component.scss'
})
export class ImgInputComponent {
public upload: any = {file: null, progress: 0};
public asset: any;
public value: any;
@Output() change = new EventEmitter()
constructor(private assetsService: AssetsService){}
get backGround(){
return this.value?.links?'url('+this.value.links.thumb+')':'url(assets/img/nir_logo_top.svg)'
}
clear() {
this.value = null;
this.setValue();
}
onFileInput(event: any) {
let file = event.target.files[0];
this.upload.file = file;
this.assetsService.upload(file).subscribe((result) => {
if (result.type === HttpEventType.UploadProgress) {
this.upload.progress = Math.round(100 * result.loaded / result.total);
} else if (result instanceof HttpResponse) {
this.upload = {file: null, progress: 0};
this.value = result.body.data;
this.setValue();
}
})
event.target.value = null;
}
setValue(){
this.change.emit(this.value)
}
}

View File

@ -1,200 +1,106 @@
<div class="block">
<div class="container-fluid">
<div class="row inner">
<div class="col-md-7 col-lg-8 block-options">
<div class="accordion" [formGroup]="QrCodeForm">
<div class="pane" ng-class="{'active':editView==='content'}" style>
<div class="pane-header" ng-click="setEditView('content')">
<div class="icon"></div>
<h3 class="title">Введите текст или загрузите изображение</h3>
<div class="plus">
<i class="fa" aria-hidden="true"></i>
</div>
<div class="minus">
<i class="fa" aria-hidden="true"></i>
</div>
<div class="row">
<div class="col-9 block-options" *ngIf="QrCodeForm">
<div [formGroup]="QrCodeForm" class="form-group">
<h3>Данные</h3>
<div>
<textarea name="text" rows="3" class="form-control" formControlName="text" #text></textarea>
</div>
<h3>Изображения</h3>
<img-input (change)="setImgFile($event)"></img-input>
<h3>Цвета</h3>
<div class="colors">
<div class="color-element">
<h4>Фон</h4>
<div class="input-color">
<input type="color" id="bg-color" formControlName="background-color">
<label for="bg-color">Цвет фона</label>
</div>
</div>
<div class="color-element">
<h4>Данные</h4>
<div class="input-color-stroke">
<div class="input-color-stroke-type">
<label for="color-type-solid">
<input class="" id="color-type-solid" type="radio" name="color-type" value="solid"
formControlName="color-type">
Сплошной
</label>
<label for="color-type-gradient">
<input class="" id="color-type-gradient" type="radio" name="color-type" value="gradient"
formControlName="color-type">
Градиент
</label>
</div>
<div class="pane-content">
<div class="tab-content">
<div class="">
<div class="form-group">
<label for="qrcodeUrl">Ваш текст или картинка</label>
<textarea name="text" rows="3" class="form-control" formControlName="text" #text></textarea>
<small class="form-text text-mutted">Line breaks are allowed</small>
</div>
<div class="input-color-stroke-value">
<div class="input-color" *ngIf="colorType=='solid'">
<input type="color" id="foreground-color" formControlName="foreground-color">
<label for="foreground-color">Цвет кода</label>
</div>
<div class="gradient-type" *ngIf="colorType=='gradient'">
<select class="btn" formControlName="gradient-type" id="gradient-type">
<option class="option" value="vertical">Вертикальный</option>
<option value="horizontal">Горизонтальный</option>
<option value="diagonal">Диагональ сверху вниз</option>
<option value="inverse_diagonal">Диагональ снизу вверх</option>
<option value="radial">Крулый</option>
</select>
</div>
<div class="area" [class.hover]="dragOver">
<input #fileInput type="file" [id]="field.name" (change)="onFileInput($event)" />
<p>Перетащите сюда или <span (click)="fileInput.click()">выберите файл</span> в формате JPEG или PNG общим объемом не более 10 Мбайт.</p>
<div class="indicator" *ngIf="upload.file">
<div class="label">Загружается файл {{upload.file?.name}}</div>
<div class="progress"><div class="fill" [style.width]="upload.progress + '%'"></div></div>
</div>
</div>
<div class="values" *ngIf="asset">
<div class="item">
<div class="preview"><img [src]="asset.links?.thumb" alt="" /></div>
<button type="button" class="btn icon remove" (click)="clear()"></button>
</div>
</div>
</div>
<div class="values" *ngIf="asset">
<div class="item">
<div class="preview"><img [src]="asset.links?.thumb" alt="" /></div>
<button type="button" class="btn icon remove" (click)="clear()"></button>
</div>
</div>
<div class="input-color" *ngIf="colorType=='gradient'">
<input type="color" id="gradient-start" formControlName="gradient-start">
<label for="gradient-start">Начало</label>
</div>
<div class="input-color" *ngIf="colorType=='gradient'">
<input type="color" id="gradient-end" formControlName="gradient-end">
<label for="gradient-end">Конец</label>
</div>
</div>
</div>
<div class="pane" ng-class="{'active':editView==='colors'}" style>
<div class="pane-header" ng-click="setEditView('colors')">
<div class="icon"></div>
<h3 class="title">Выберите цвет</h3>
<div class="plus">
<i class="fa" aria-hidden="true"></i>
</div>
<div class="minus">
<i class="fa" aria-hidden="true"></i>
</div>
</div>
<div class="pane-content overflow-visible color-panel">
<label>Основной цвет</label>
<div class="color-group color-group-body">
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input ng-valid ng-not-empty ng dirty ng-valid-parse ng-touched" type="radio" name="color-type" value="solid" formControlName="color-type" checked>
Сплошной
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input ng-valid ng-not-empty ng dirty ng-valid-parse ng-touched" type="radio" name="color-type" value="gradient" formControlName="color-type">
Градиент
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input ng-valid ng-not-empty ng dirty ng-valid-parse ng-touched" type="checkbox" name="eyeMode" value=true style formControlName="custom-eye-color" [defaultValue]=false>
Цвет глаз
</label>
</div>
<div class="row">
<div class="col-sm-6 col-lg-4 form-group">
<input type="color" formControlName="foreground-color">
</div>
</div>
<div class="row">
<div class="col-sm-6 col-lg-4 form-group">
<input type="color" formControlName="gradient-start">
</div>
<div class="col-sm-6 col-lg-4 form-group">
<input type="color" formControlName="gradient-end">
</div>
<div class="col-sm-6 col-lg-4 form-group">
<div class="input-group">
<span>
<button>Цвета местами</button>
</span>
<select formControlName="gradient-type" id="gradient-type">
<option value="vertical">Вертикальный</option>
<option value="horizontal">Горизонтальный</option>
<option value="diagonal">Диагональ сверху вниз</option>
<option value="inverse_diagonal">Диагональ снизу вверх</option>
<option value="radial">Крулый</option>
</select>
</div>
</div>
</div>
<div>
<label>Цвет глаз</label>
<div class="row">
<div class="col-sm-6 col-lg-4 form-group">
<input type="color" formControlName="inner-eye-color">
</div>
<div class="col-sm-6 col-lg-4 form-group">
<input type="color" formControlName="outside-eye-color">
</div>
<div class="col-sm-6 col-lg-4 form-group">
<span>
<button>Цвета местами</button>
</span>
<span>
<button>Копировать основной цвет</button>
</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6 col-lg-4">
<label>Цвет фона</label>
<div class="form-group color-group">
<input type="color" formControlName="background-color">
</div>
</div>
</div>
</div>
</div>
<div class="color-element">
<h4>Метки</h4>
<label for="custom-eye-color">
<input class="" id="custom-eye-color" type="checkbox" name="custom-eye-color" formControlName="custom-eye-color">
Изменить цвет
</label>
<div class="input-color" *ngIf="EyeType">
<input type="color" id="outside-eye-color" formControlName="outside-eye-color">
<label for="outside-eye-color">Внешняя часть</label>
</div>
<div class="pane">
<div class="pane-header">
<div class="icon"></div>
<h3 class="title">Добавить изображение</h3>
<div class="plus">
<i class="fa" aria-hidden="true"></i>
</div>
<div class="minus">
<i class="fa" aria-hidden="true"></i>
</div>
</div>
<div class="pane-content">
<div class="area" [class.hover]="dragOver">
<input #fileInput type="file" [id]="field.name" (change)="onFileInput($event)" />
<p>Перетащите сюда или <span (click)="fileInput.click()">выберите файл</span> в формате JPEG или PNG общим объемом не более 10 Мбайт.</p>
<div class="indicator" *ngIf="upload.file">
<div class="label">Загружается файл {{upload.file?.name}}</div>
<div class="progress"><div class="fill" [style.width]="upload.progress + '%'"></div></div>
</div>
</div>
<div class="values" *ngIf="asset">
<div class="item">
<div class="preview"><img [src]="asset.links?.thumb" alt="" /></div>
<button type="button" class="btn icon remove" (click)="clear()"></button>
</div>
</div>
</div>
<div class="input-color" *ngIf="EyeType">
<input type="color" id="inner-eye-color" formControlName="inner-eye-color">
<label for="inner-eye-color">Внутреняя часть</label>
</div>
<div class="pane">
<div class="pane-header">
<div class="icon"></div>
<h3 class="title">Ручной дизайн</h3>
<div class="plus">
<i class="fa" aria-hidden="true"></i>
</div>
<div class="minus">
<i class="fa" aria-hidden="true"></i>
</div>
</div>
<div class="pane-content">
<input type="radio"/>Обычный
<input type="radio"/>Скругленные края
</div>
</div>
</div>
</div>
<div class="col-md-5 col-lg-4 block-download">
<div class="preview">
<p>Созданный QR-CODE</p>
</div>
<button class="btn primary submit" (click)="onSubmit()" [disabled]="QrCodeForm.invalid" >
отправить
</button>
<h3>Битовый элемент</h3>
<div class="bits">
<label for="bit-type-normal">
<input class="" id="bit-type-normal" type="radio" name="bit-type" formControlName="bit-type" value="normal">
Обычный
</label>
<label for="bit-type-round">
<input class="" id="bit-type-round" type="radio" name="bit-type" formControlName="bit-type" value="round">
Скругленные края
</label>
<label for="bit-type-radio">
<input class="" id="bit-type-radio" type="radio" name="bit-type" formControlName="bit-type" value="custom">
Изображение
</label>
<img-input *ngIf="bitType=='custom'" (change)="setImgFile($event)"></img-input>
</div>
</div>
</div>
<div class="col-3 block-download">
<div class="preview">
<p>Созданный QR-CODE</p>
</div>
<button class="btn primary submit" (click)="onSubmit()" [disabled]="QrCodeForm.invalid" >
отправить
</button>
</div>
</div>

View File

@ -2,6 +2,113 @@
box-sizing: border-box
}
.form-group{
display: flex;
flex-direction: column;
gap: 48px;
}
input[type="file"]{
width: 240px;
height: 100px;
overflow: hidden ;
background: center no-repeat;
background-size: contain;
display: block;
&::file-selector-button {
width: 240px;
height: 100px;
color: transparent;
background-color: transparent;
padding: 10px 20px;
border: none;
cursor: pointer;
}
}
h3{
margin-bottom: -24px;
border-bottom: 1px solid var(--clr-gr);
}
label, input, select{
cursor: pointer;
}
.input-color{
display: flex;
align-items: end;
[type=color]{
width: 48px;
height: 48px;
}
gap:24px;
}
.input-color-stroke, .bits{
display: flex;
flex-direction: column;
gap: 24px;
.input-color-stroke-type{
display: flex;
flex-direction: column;
gap: 8px;
}
.input-color-stroke-value{
display: flex;
flex-direction: column;
gap: 8px;
}
}
.input-img{
display: flex;
gap: 24px;
align-items: end;
.input-img-area{
display: inline-flex;
border: 1px solid var(--clr-gr);
border-radius: 12px;
padding: 12px;
}
}
.colors{
display: flex;
flex-direction: row;
gap: 24px;
.color-element{
flex-grow: 1;
flex-shrink: 0;
flex-basis: 33%;
display: flex;
flex-direction: column;
gap: 16px;
} ;
}
select{
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
option{
font-family: Montserrat;
}
.option{
font-family: Montserrat;
}
}
.fill{
height: 10px;
background-color: #495057;
}
input[type="file"]::file-se {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
textarea {
overflow: auto;
resize: vertical
@ -28,89 +135,13 @@ textarea {
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: -15px;
margin-left: -15px
}
.block .block-options {
padding: 32px
}
.block .accordion .pane {
margin-bottom: 4px
}
.block .accordion .pane .pane-header {
cursor: pointer;
-webkit-transition: all .3s;
transition: all .3s;
background: #fff;
font-size: 1.1rem;
position: relative;
font-weight: 500;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
height: 48px;
box-shadow: 0 0 6px rgba(0,0,0,.05)
}
.block .accordion .pane .pane-header .title {
padding: 0 16px;
text-transform: uppercase;
font-size: 1rem;
margin: 0;
-webkit-flex-shrink: 1;
-webkit-flex-grow: 1;
flex-grow: 1;
flex-shrink: 1;
overflow: hidden;
white-space: nowrap;
line-height: 48px;
text-align: initial
}
.block .accordion .pane .pane-header .icon {
width: 48px;
text-align: center;
-webkit-flex-shrink: 0;
-webkit-flex-grow: 0;
flex-grow: 0;
flex-shrink: 0;
background: #f2f8fc;
line-height: 48px
}
.block .accordion .pane .pane-header .minus, .block .accordion .pane .pane-header .plus {
padding: 0 16px;
-webkit-flex-shrink: 0;
-webkit-flex-grow: 0;
flex-grow: 0;
flex-shrink: 0;
line-height: 48px;
color: rgba(111,120,127,.5);
font-size: .9rem
}
.block .accordion .pane .pane-header .minus {
display: none
}
.block .accordion .pane .pane-header:hover {
background-color: #f2f8fc;
box-shadow: none
}
.block.accordion .pane.active .pane-content {
padding: 1rem 0;
display: block;
opacity: 1;
visibility: visible;
max-height: 1400px;
overflow: visible;
-webkit-transition: all .5s ease-in-out 0s,opacity .25s ease-in-out .2s;
transition: all .5s ease-in-out 0s,opacity .25s ease-in-out .2s
}
.form-control {
display: block;
@ -126,25 +157,6 @@ textarea {
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out
}
.block .accordion .pane.active .pane-content {
padding: 1rem 0;
display: block;
opacity: 1;
visibility: visible;
max-height: 1400px;
overflow: visible;
-webkit-transition: all .5s ease-in-out 0s,opacity .25s ease-in-out .2s;
transition: all .5s ease-in-out 0s,opacity .25s ease-in-out .2s
}
.body .accordion .pane .pane-content .color-group label {
font-weight: 400
}
.block .accordion .pane .pane-content .color-group-body {
padding-bottom: 0
}
.form-check {
position: relative;
display: block;

View File

@ -1,23 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { QrCodeComponent } from './qr-code.component';
describe('QrCodeComponent', () => {
let component: QrCodeComponent;
let fixture: ComponentFixture<QrCodeComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [QrCodeComponent]
})
.compileComponents();
fixture = TestBed.createComponent(QrCodeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,10 +1,8 @@
import {Component, Input, OnInit} from '@angular/core';
import {Router} from "@angular/router";
import {Component, Input, OnInit, HostListener} from '@angular/core';
import {FormBuilder, FormGroup, FormsModule, ReactiveFormsModule} from "@angular/forms";
import {NgIf} from "@angular/common";
import {JsonPipe, NgIf} from "@angular/common";
import {FormsService} from "../_services/forms.service";
import {HttpEventType, HttpResponse} from "@angular/common/http";
import {AssetsService} from "../_services/assets.service";
import { ImgInputComponent } from './img-input/img-input.component';
@Component({
selector: 'qr-code',
@ -12,19 +10,21 @@ import {AssetsService} from "../_services/assets.service";
imports: [
FormsModule,
NgIf,
ReactiveFormsModule
ReactiveFormsModule,
JsonPipe,
ImgInputComponent
],
templateUrl: './qr-code.component.html',
styleUrl: './qr-code.component.scss'
})
export class QrCodeComponent implements OnInit{
@Input() field!: any;
public asset: any;
public QrCodeForm: FormGroup;
public dragOver = false;
public upload: any = {file: null, progress: 0};
constructor(private formBuilder:FormBuilder, private formsService: FormsService, private assetsService: AssetsService){}
constructor(private formBuilder:FormBuilder, private formsService: FormsService){}
ngOnInit() {
this.QrCodeForm = this.formBuilder.group({
@ -40,7 +40,8 @@ export class QrCodeComponent implements OnInit{
'custom-eye-color' : [false],
'outside-eye-color' : ['#000000'],
'inner-eye-color' : ['#000000'],
'image' : []
'image' : [],
'bit-type' : ['normal']
});
}
@ -54,56 +55,23 @@ export class QrCodeComponent implements OnInit{
});
}
get initialValue() {
return this.field.value?.data[0];
get colorType(){
return this.QrCodeForm.value['color-type']
}
get control() {
return this.QrCodeForm.controls[this.field.name];
get bitType(){
return this.QrCodeForm.value['bit-type']
}
get value() {
return this.control?.value || [];
get EyeType(){
return this.QrCodeForm.value['custom-eye-color']
}
set value(asset: any) {
this.asset = asset;
this.control?.setValue(asset?.id);
setImgFile(value){
console.log(value)
}
setValue(value: any) {
this.control.setValue(value);
this.control.markAsTouched();
}
clear() {
this.control.markAsTouched();
this.value = null;
}
onFileInput(event: any) {
this.uploadFiles(event.target.files);
event.target.value = null;
}
uploadFiles(files: any) {
for (let file of files) {
this.uploadFile(file);
}
}
uploadFile(file: File) {
this.upload.file = file;
this.assetsService.upload(file).subscribe((result) => {
if (result.type === HttpEventType.UploadProgress) {
this.upload.progress = Math.round(100 * result.loaded / result.total);
} else if (result instanceof HttpResponse) {
this.upload = {file: null, progress: 0};
this.value = result.body.data;
this.control.markAsTouched();
}
}, error => {
this.upload = {file: null, progress: 0};
alert(error.error.message);
});
}
}