Skip to content

Commit

Permalink
feat(module:upload): add picture preview
Browse files Browse the repository at this point in the history
close #9
  • Loading branch information
ng-nest-moon committed Feb 28, 2021
1 parent b8a03fd commit 7c7e40d
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 29 deletions.
5 changes: 4 additions & 1 deletion lib/ng-nest/ui/core/interfaces/data.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,8 @@ export const XIsEmpty = (object: any) => typeof object === 'undefined' || object
export const XIsValueArray = (object: any) => XIsArray(object) && object.length > 0 && !XIsObject(object[0]);
export const XIsObjectArray = (object: any) => XIsArray(object) && object.length > 0 && XIsObject(object[0]);
export const XIsObservable = (object: any) => isObservable(object);
export const XIsTemplateRef = (object: any) => !XIsEmpty(object) && object.elementRef;
export const XIsTemplateRef = (object: any) => {
if (!XIsEmpty(object) && object.elementRef) return true;
else return false;
};
export const XIsXTemplate = (object: any) => XIsString(object) || XIsNumber(object) || XIsDate(object) || XIsTemplateRef(object);
2 changes: 1 addition & 1 deletion lib/ng-nest/ui/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ declare const require: {
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
const files = ['./table/table.component.spec.ts'];
const files = ['./upload/upload.component.spec.ts'];
// And load the modules.
context
.keys()
Expand Down
85 changes: 85 additions & 0 deletions lib/ng-nest/ui/upload/style/mixin.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
color: $--x-text;
font-size: $--x-font-size;
&-buttons {
display: inline-flex;
> .x-button:not(:first-child) {
margin-left: 0.4rem;
}
&-template {
cursor: pointer;
}
}
&-files {
margin-top: 0.4rem;
Expand Down Expand Up @@ -78,6 +82,87 @@
}
&.x-disabled {
}
&-img {
display: flex;
flex-wrap: wrap;
.#{$--x-upload-prefix} {
&-buttons {
&-template {
display: inline-flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: 6.25rem;
height: 6.25rem;
margin-right: 0.5rem;
margin-bottom: 0.5rem;
border: $--x-border-width dashed $--x-border;
background: $--x-background;
border-radius: $--x-border-radius;
transition: border-color $--x-animation-duration-base;
&:hover {
border-color: $--x-primary;
}
}
}
}
&-item {
height: 6.25rem;
width: 6.25rem;
padding: 0.325rem;
border: $--x-border-width $--x-border-style $--x-border;
border-radius: $--x-border-radius;
transition: border-color $--x-animation-duration-base;
margin-right: 0.5rem;
margin-bottom: 0.5rem;
position: relative;
display: flex;
align-items: center;
justify-content: center;
.x-upload-img-inner {
height: 100%;
width: 100%;
overflow: hidden;
display: flex;
align-items: center;
> img {
width: 100%;
border-radius: $--x-border-radius;
}
}
&:hover {
.x-upload-img-btns {
background-color: rgba(0, 0, 0, 0.45);
&-inner {
display: initial;
}
}
}
}
&-btns {
position: absolute;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
border-radius: $--x-border-radius;
background-color: rgba(0, 0, 0, 0);
transition: all $--x-animation-duration-base;
x-icon {
cursor: pointer;
font-size: 1rem;
padding: 0.25rem;
color: rgba(255, 255, 255, 0.7);
&:hover {
color: white;
}
}
&-inner {
display: none;
}
}
}
}

@mixin disabled {
Expand Down
75 changes: 56 additions & 19 deletions lib/ng-nest/ui/upload/upload.component.html
Original file line number Diff line number Diff line change
@@ -1,21 +1,58 @@
<div #upload class="x-upload" [class.x-disabled]="disabled">
<div class="x-upload-buttons">
<x-button icon="fto-upload" [disabled]="disabled" (click)="uploadClick()" type="primary">{{ 'upload.uploadText' | xI18n }}</x-button>
<div #upload class="x-upload x-upload-{{ type }}" [class.x-disabled]="disabled">
<input type="file" #file (change)="change($event)" [attr.accept]="accept" [multiple]="multiple" style="display: none" />
<div class="x-upload-buttons" [class.x-upload-buttons-template]="isTemplateLabel" (click)="uploadClick()">
<ng-container *xOutlet="getLabel">
<x-button icon="fto-upload" [disabled]="disabled" type="primary">{{ getLabel }}</x-button>
</ng-container>
</div>
<input type="file" #file (change)="change($event)" [attr.accept]="accept" [multiple]="multiple" style="display: none;" />
<ul class="x-upload-files">
<li *ngFor="let file of files; index as i; trackBy: trackByItem">
<a [href]="file.url" target="_blank" [title]="file.name">
<x-icon type="fto-file-text"></x-icon>
<span class="x-upload-filename">{{ file.name }}</span>
</a>
<ng-container [ngSwitch]="file.state">
<x-icon class="x-upload-state" *ngSwitchCase="'ready'" type="fto-clock"></x-icon>
<span class="x-upload-percent" *ngSwitchCase="'uploading'">{{ file.percent }}%</span>
<x-icon class="x-upload-state success" *ngSwitchCase="'success'" type="fto-check"></x-icon>
<x-icon class="x-upload-state error" *ngSwitchCase="'error'" type="fto-info"></x-icon>
</ng-container>
<x-button *ngIf="file.state !== 'uploading'" icon="fto-x" (click)="remove(file, i)" onlyIcon closable></x-button>
</li>
</ul>
<ng-container [ngSwitch]="type">
<ng-container *ngSwitchCase="'list'">
<ul class="x-upload-files">
<li *ngFor="let file of files; index as i; trackBy: trackByItem">
<a [href]="file.url" target="_blank" [title]="file.name">
<x-icon type="fto-file-text"></x-icon>
<span class="x-upload-filename">{{ file.name }}</span>
</a>
<ng-container [ngSwitch]="file.state">
<x-icon class="x-upload-state" *ngSwitchCase="'ready'" type="fto-clock"></x-icon>
<span class="x-upload-percent" *ngSwitchCase="'uploading'">{{ file.percent }}%</span>
<x-icon class="x-upload-state success" *ngSwitchCase="'success'" type="fto-check"></x-icon>
<x-icon class="x-upload-state error" *ngSwitchCase="'error'" type="fto-info"></x-icon>
</ng-container>
<x-button *ngIf="file.state !== 'uploading'" icon="fto-x" (click)="remove(file, i)" onlyIcon closable></x-button>
</li>
</ul>
</ng-container>
<ng-container *ngSwitchCase="'img'">
<div class="x-upload-img-item" *ngFor="let file of files; index as i; trackBy: trackByItem" [title]="file.name">
<div class="x-upload-img-inner">
<img [src]="file.url" />
</div>
<div class="x-upload-img-btns">
<div class="x-upload-img-btns-inner">
<ng-container [ngSwitch]="file.state">
<x-icon class="x-upload-state" *ngSwitchCase="'ready'" type="fto-clock"></x-icon>
<span class="x-upload-percent" *ngSwitchCase="'uploading'">{{ file.percent }}%</span>
<x-icon class="x-upload-state error" *ngSwitchCase="'error'" type="fto-info"></x-icon>
<a [href]="file.url" target="_blank" *ngSwitchCase="'success'">
<x-icon type="fto-eye"></x-icon>
</a>
</ng-container>
<x-icon *ngIf="file.state !== 'uploading'" type="fto-trash-2" (click)="remove(file, i)"></x-icon>
</div>
</div>
<!-- <a [href]="file.url" target="_blank" [title]="file.name">
<x-icon type="fto-file-text"></x-icon>
<span class="x-upload-filename">{{ file.name }}</span>
</a>
<ng-container [ngSwitch]="file.state">
<x-icon class="x-upload-state" *ngSwitchCase="'ready'" type="fto-clock"></x-icon>
<span class="x-upload-percent" *ngSwitchCase="'uploading'">{{ file.percent }}%</span>
<x-icon class="x-upload-state success" *ngSwitchCase="'success'" type="fto-check"></x-icon>
<x-icon class="x-upload-state error" *ngSwitchCase="'error'" type="fto-info"></x-icon>
</ng-container>
<x-button *ngIf="file.state !== 'uploading'" icon="fto-x" (click)="remove(file, i)" onlyIcon closable></x-button> -->
</div>
</ng-container>
</ng-container>
</div>
63 changes: 59 additions & 4 deletions lib/ng-nest/ui/upload/upload.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import { XUploadModule } from '@ng-nest/ui/upload';
import { FormsModule } from '@angular/forms';
import { XUploadPrefix } from './upload.property';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { XIconModule } from '@ng-nest/ui/icon';

describe(XUploadPrefix, () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [BrowserAnimationsModule, FormsModule, XUploadModule, XButtonModule, XLayoutModule],
declarations: [TestXUploadComponent, TestXUploadDisabledComponent]
imports: [BrowserAnimationsModule, FormsModule, XIconModule, XUploadModule, XButtonModule, XLayoutModule],
declarations: [TestXUploadComponent, TestXUploadDisabledComponent, TestXUploadImgComponent]
}).compileComponents();
}));
fdescribe(`default.`, () => {
describe(`default.`, () => {
let fixture: ComponentFixture<TestXUploadComponent>;
let upload: DebugElement;
let testComponent: TestXUploadComponent;
Expand All @@ -33,6 +34,22 @@ describe(XUploadPrefix, () => {
expect(upload).toBeDefined();
});
});
fdescribe(`img.`, () => {
let fixture: ComponentFixture<TestXUploadImgComponent>;
let upload: DebugElement;
let testComponent: TestXUploadImgComponent;
let element: HTMLElement;
beforeEach(() => {
fixture = TestBed.createComponent(TestXUploadImgComponent);
fixture.detectChanges();
testComponent = fixture.debugElement.componentInstance;
upload = fixture.debugElement.query(By.directive(XUploadComponent));
element = upload.nativeElement;
});
it('should create.', () => {
expect(upload).toBeDefined();
});
});
describe(`disabled.`, () => {
let fixture: ComponentFixture<TestXUploadDisabledComponent>;
let upload: DebugElement;
Expand Down Expand Up @@ -81,7 +98,6 @@ class TestXUploadComponent {

@Component({
template: `
<x-theme showDark></x-theme>
<x-row>
<x-col span="24">
<x-upload disabled></x-upload>
Expand All @@ -104,3 +120,42 @@ class TestXUploadComponent {
class TestXUploadDisabledComponent {
model: any;
}

@Component({
template: `
<x-row>
<x-col span="24">
<x-upload action="http://localhost:3000/upload" label="shangchuan" multiple></x-upload>
</x-col>
<x-col span="24">
<x-upload action="http://localhost:3000/upload" [label]="labelTpl" type="img" multiple></x-upload>
<ng-template #labelTpl>
<x-icon class="upload-icon" type="fto-upload"></x-icon>
<span>选择图片</span>
</ng-template>
</x-col>
</x-row>
`,
styles: [
`
:host {
background-color: var(--x-background);
padding: 1rem;
border: 0.0625rem solid var(--x-border);
}
.upload-icon {
font-size: 1.325rem;
}
x-row > x-col:not(:first-child) {
margin-top: 1rem;
}
x-row > x-col {
width: 14rem;
}
`
]
})
class TestXUploadImgComponent {
model = [];
}
23 changes: 20 additions & 3 deletions lib/ng-nest/ui/upload/upload.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { HttpClient, HttpEventType, HttpRequest, HttpEvent } from '@angular/common/http';
import { Component, ViewEncapsulation, ChangeDetectionStrategy, Renderer2, ElementRef, ChangeDetectorRef, ViewChild } from '@angular/core';
import { XUploadPrefix, XUploadNode, XUploadProperty } from './upload.property';
import { XValueAccessor } from '@ng-nest/ui/core';
import { XIsTemplateRef, XValueAccessor } from '@ng-nest/ui/core';
import { map, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { XI18nService } from '@ng-nest/ui/i18n';
import { XI18nService, XI18nUpload } from '@ng-nest/ui/i18n';

@Component({
selector: `${XUploadPrefix}`,
Expand All @@ -19,6 +19,15 @@ export class XUploadComponent extends XUploadProperty {
files: XUploadNode[] = [];
showUpload = false;
uploadNodes: XUploadNode[] = [];
locale: XI18nUpload = {};

get getLabel() {
return this.label || this.locale.uploadText;
}

get isTemplateLabel() {
return XIsTemplateRef(this.getLabel);
}

private _unSubject = new Subject<void>();

Expand All @@ -38,7 +47,15 @@ export class XUploadComponent extends XUploadProperty {
}

ngOnInit() {
this.i18n.localeChange.pipe(takeUntil(this._unSubject)).subscribe(() => this.cdr.markForCheck());
this.i18n.localeChange
.pipe(
map((x) => x.upload as XI18nUpload),
takeUntil(this._unSubject)
)
.subscribe((x) => {
this.locale = x;
this.cdr.markForCheck();
});
}

ngOnDestory() {
Expand Down
3 changes: 2 additions & 1 deletion lib/ng-nest/ui/upload/upload.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { XButtonModule } from '@ng-nest/ui/button';
import { XIconModule } from '@ng-nest/ui/icon';
import { XUploadProperty } from './upload.property';
import { XI18nModule } from '@ng-nest/ui/i18n';
import { XOutletModule } from '@ng-nest/ui/outlet';

@NgModule({
declarations: [XUploadComponent, XUploadProperty],
exports: [XUploadComponent],
imports: [CommonModule, FormsModule, XButtonModule, XIconModule, XI18nModule]
imports: [CommonModule, FormsModule, XOutletModule, XButtonModule, XIconModule, XI18nModule]
})
export class XUploadModule {}
5 changes: 5 additions & 0 deletions lib/ng-nest/ui/upload/upload.property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export const XUploadPrefix = 'x-upload';
*/
@Component({ template: '' })
export class XUploadProperty extends XControlValueAccessor<any> {
/**
* @zh_CN 显示文字
* @en_US Display text
*/
@Input() label: string;
/**
* @zh_CN 请求地址
* @en_US Request address
Expand Down

0 comments on commit 7c7e40d

Please sign in to comment.