Browse Source

Many style improvements.

pull/308/head
Sebastian 8 years ago
parent
commit
dc3ddaad75
  1. 4
      src/Squidex/app/features/assets/pages/assets-page.component.html
  2. 8
      src/Squidex/app/features/assets/pages/assets-page.component.ts
  3. 8
      src/Squidex/app/features/content/shared/assets-editor.component.html
  4. 6
      src/Squidex/app/features/content/shared/assets-editor.component.scss
  5. 4
      src/Squidex/app/framework/angular/forms/tag-editor.component.html
  6. 17
      src/Squidex/app/framework/angular/forms/tag-editor.component.scss
  7. 12
      src/Squidex/app/framework/angular/forms/tag-editor.component.ts
  8. 2
      src/Squidex/app/shared/components/asset.component.html
  9. 17
      src/Squidex/app/shared/components/asset.component.scss
  10. 10
      src/Squidex/app/shared/components/asset.component.ts
  11. 2
      src/Squidex/app/shared/components/assets-list.component.html
  12. 5
      src/Squidex/app/shared/components/assets-list.component.scss
  13. 4
      src/Squidex/app/shared/services/assets.service.spec.ts
  14. 10
      src/Squidex/app/shared/services/assets.service.ts
  15. 35
      src/Squidex/app/shared/state/assets.state.spec.ts
  16. 50
      src/Squidex/app/shared/state/assets.state.ts
  17. 3
      src/Squidex/app/theme/_vars.scss

4
src/Squidex/app/features/assets/pages/assets-page.component.html

@ -24,7 +24,7 @@
<ng-container sidebar>
<div class="section">
<a class="row tag" (click)="selectTag(undefined)" [class.active]="!assetsState.snapshot.tag">
<a class="row tag" (click)="resetTags()" [class.active]="assetsState.isTagSelectionEmpty()">
<div class="col">
All Assets
</div>
@ -35,7 +35,7 @@
<h3>Tags</h3>
<ng-container *ngIf="assetsState.tags | async; let tags">
<a class="row tag" *ngFor="let tag of tags | sqxKeys" (click)="selectTag(tag)" [class.active]="tag === assetsState.snapshot.tag">
<a class="row tag" *ngFor="let tag of tags | sqxKeys" (click)="toggleTag(tag)" [class.active]="assetsState.isTagSelected(tag)">
<div class="col">
{{tag}}
</div>

8
src/Squidex/app/features/assets/pages/assets-page.component.ts

@ -39,8 +39,12 @@ export class AssetsPageComponent implements OnInit {
this.assetsState.search(this.assetsFilter.value).pipe(onErrorResumeNext()).subscribe();
}
public selectTag(tag: string) {
this.assetsState.selectTag(tag).pipe(onErrorResumeNext()).subscribe();
public resetTags() {
this.assetsState.resetTags().pipe(onErrorResumeNext()).subscribe();
}
public toggleTag(tag: string) {
this.assetsState.toggleTag(tag).pipe(onErrorResumeNext()).subscribe();
}
public goNext() {

8
src/Squidex/app/features/content/shared/assets-editor.component.html

@ -1,11 +1,9 @@
<div class="assets-container" [class.disabled]="isDisabled">
<div class="row">
<div class="drop-area-container">
<div class="drop-area" (sqxFileDrop)="addFiles($event)" (click)="assetsDialog.show()">
Drop files here to add them.
</div>
<div class="drop-area align-items-center" (sqxFileDrop)="addFiles($event)" (click)="assetsDialog.show()">
Drop files here to add them.
</div>
<sqx-asset *ngFor="let file of newAssets" [initFile]="file"
(failed)="onAssetFailed(file)"
(loaded)="onAssetLoaded(file, $event)">

6
src/Squidex/app/features/content/shared/assets-editor.component.scss

@ -22,13 +22,15 @@
& {
@include transition(border-color .4s ease);
@include border-radius;
@include flex-box;
border: 2px dashed $color-border;
height: $asset-height;
height: $asset-height + 1.5rem;
width: $asset-height;
margin-left: 8px;
font-size: 1.2rem;
font-weight: normal;
text-align: center;
padding: 3.5rem 2rem;
padding: 0 2rem;
cursor: pointer;
color: darken($color-border, 30%);
}

4
src/Squidex/app/framework/angular/forms/tag-editor.component.html

@ -1,9 +1,9 @@
<div class="form-control {{class}}" (click)="input.focus()" [class.focus]="hasFocus">
<div class="form-control {{class}}" (click)="input.focus()" [class.focus]="hasFocus" [class.disabled]="addInput.disabled">
<span class="item" *ngFor="let item of items; let i = index" [class.disabled]="addInput.disabled">
{{item}} <i class="icon-close" (click)="remove(i)"></i>
</span>
<input type="text" class="blank" [attr.name]="inputName" (keydown)="onKeyDown($event)" #input
<input type="text" class="blank" [attr.name]="inputName" (keydown)="onKeyDown($event)" [class.hidden]="addInput.disabled" #input
(focus)="focus()"
(blur)="markTouched()"
(input)="adjustSize($event.target)"

17
src/Squidex/app/framework/angular/forms/tag-editor.component.scss

@ -5,6 +5,10 @@
& {
cursor: text;
}
&.disabled {
cursor: inherit;
}
&.focus {
@include box-shadow-raw(0 0 0 0.2rem rgba(51, 137, 255, 0.25));
@ -26,6 +30,10 @@
@include box-shadow-none;
outline: none;
}
&:hover {
background: transparent;
}
}
.icon-close {
@ -62,14 +70,7 @@
}
&.disabled {
& {
pointer-events: none;
}
&,
&:hover {
background: $color-theme-blue-light;
}
pointer-events: none;
}
&:hover {

12
src/Squidex/app/framework/angular/forms/tag-editor.component.ts

@ -123,12 +123,10 @@ export class TagEditorComponent implements ControlValueAccessor {
this.callTouched = fn;
}
public remove(index: number) {
this.updateItems([...this.items.slice(0, index), ...this.items.splice(index + 1)]);
}
public focus() {
this.hasFocus = true;
if (this.addInput.enabled) {
this.hasFocus = true;
}
}
private resetForm() {
@ -143,6 +141,10 @@ export class TagEditorComponent implements ControlValueAccessor {
this.hasFocus = false;
}
public remove(index: number) {
this.updateItems([...this.items.slice(0, index), ...this.items.splice(index + 1)]);
}
public adjustSize() {
const style = window.getComputedStyle(this.inputElement.nativeElement);

2
src/Squidex/app/shared/components/asset.component.html

@ -53,7 +53,7 @@
</form>
</div>
</div>
<div>
<div class="tags">
<sqx-tag-editor [useDefaultValue]="false" [formControl]="tagInput" class="blank"></sqx-tag-editor>
</div>
<div class="file-info">

17
src/Squidex/app/shared/components/asset.component.scss

@ -49,13 +49,6 @@
}
}
:host {
width: $asset-height;
padding-bottom: 1rem;
padding-left: 8px;
padding-right: 8px;
}
.drop-overlay {
& {
@include overlay;
@ -73,7 +66,11 @@
.card {
& {
@include overlay-container;
min-height: $asset-height + 1.5rem;
width: $asset-width;
margin-bottom: 1rem;
margin-left: 8px;
margin-right: 8px;
min-height: $asset-height;
}
&.selectable {
@ -188,4 +185,8 @@
.editable {
height: 2rem;
}
.tags {
min-height: 26px;
}

10
src/Squidex/app/shared/components/asset.component.ts

@ -110,6 +110,10 @@ export class AssetComponent implements OnDestroy, OnInit {
this.updateAsset(this.asset, false);
}
if (this.isDisabled) {
this.tagInput.disable();
}
this.tagSubscription =
this.tagInput.valueChanges.pipe(
distinctUntilChanged(),
@ -184,12 +188,6 @@ export class AssetComponent implements OnDestroy, OnInit {
this.renaming = false;
}
public startTagging() {
if (!this.isDisabled) {
this.isTagging = true;
}
}
private setProgress(progress = 0) {
this.progress = progress;
}

2
src/Squidex/app/shared/components/assets-list.component.html

@ -14,7 +14,7 @@
<div class="file-drop-info">Drop file on existing item to replace the asset with a newer version.</div>
</div>
<div class="row">
<div class="row assets">
<sqx-asset *ngFor="let file of newFiles" [initFile]="file"
(failed)="remove(file)"
(loaded)="add(file, $event)">

5
src/Squidex/app/shared/components/assets-list.component.scss

@ -35,6 +35,11 @@
}
}
.assets {
margin-left: -8px;
margin-right: -8px;
}
.btn {
cursor: default;
}

4
src/Squidex/app/shared/services/assets.service.spec.ts

@ -272,9 +272,9 @@ describe('AssetsService', () => {
it('should append query to find by name and tag',
inject([AssetsService, HttpTestingController], (assetsService: AssetsService, httpMock: HttpTestingController) => {
assetsService.getAssets('my-app', 17, 13, 'my-query', 'tag1').subscribe();
assetsService.getAssets('my-app', 17, 13, 'my-query', ['tag1', 'tag2']).subscribe();
const req = httpMock.expectOne(`http://service/p/api/apps/my-app/assets?$filter=contains(fileName,'my-query') and tags eq 'tag1'&$top=17&$skip=13`);
const req = httpMock.expectOne(`http://service/p/api/apps/my-app/assets?$filter=contains(fileName,'my-query') and tags eq 'tag1' and tags eq 'tag2'&$top=17&$skip=13`);
expect(req.request.method).toEqual('GET');
expect(req.request.headers.get('If-Match')).toBeNull();

10
src/Squidex/app/shared/services/assets.service.ts

@ -131,7 +131,7 @@ export class AssetsService {
map(response => <any>response));
}
public getAssets(appName: string, take: number, skip: number, query?: string, tag?: string, ids?: string[]): Observable<AssetsDto> {
public getAssets(appName: string, take: number, skip: number, query?: string, tags?: string[], ids?: string[]): Observable<AssetsDto> {
let fullQuery = '';
if (ids) {
@ -145,8 +145,12 @@ export class AssetsService {
filters.push(`contains(fileName,'${encodeURIComponent(query)}')`);
}
if (tag && tag.length > 0) {
filters.push(`tags eq '${encodeURIComponent(tag)}'`);
if (tags) {
for (let tag of tags) {
if (tag && tag.length > 0) {
filters.push(`tags eq '${encodeURIComponent(tag)}'`);
}
}
}
if (filters.length > 0) {

35
src/Squidex/app/shared/state/assets.state.spec.ts

@ -49,7 +49,7 @@ describe('AssetsState', () => {
assetsService = Mock.ofType<AssetsService>();
assetsService.setup(x => x.getAssets(app, 30, 0, undefined, undefined))
assetsService.setup(x => x.getAssets(app, 30, 0, undefined, []))
.returns(() => of(new AssetsDto(200, oldAssets)));
assetsService.setup(x => x.getTags(app))
@ -66,7 +66,7 @@ describe('AssetsState', () => {
expect(assetsState.snapshot.assetsPager.numberOfItems).toEqual(200);
expect(assetsState.snapshot.isLoaded).toBeTruthy();
assetsService.verify(x => x.getAssets(app, 30, 0, undefined, undefined), Times.exactly(2));
assetsService.verify(x => x.getAssets(app, 30, 0, undefined, []), Times.exactly(2));
assetsService.verify(x => x.getTags(app), Times.exactly(2));
dialogs.verify(x => x.notifyInfo(It.isAnyString()), Times.never());
@ -112,7 +112,7 @@ describe('AssetsState', () => {
});
it('should load next page and prev page when paging', () => {
assetsService.setup(x => x.getAssets(app, 30, 30, undefined, undefined))
assetsService.setup(x => x.getAssets(app, 30, 30, undefined, []))
.returns(() => of(new AssetsDto(200, [])));
assetsState.goNext().subscribe();
@ -120,29 +120,40 @@ describe('AssetsState', () => {
expect().nothing();
assetsService.verify(x => x.getAssets(app, 30, 30, undefined, undefined), Times.once());
assetsService.verify(x => x.getAssets(app, 30, 0, undefined, undefined), Times.exactly(2));
assetsService.verify(x => x.getAssets(app, 30, 30, undefined, []), Times.once());
assetsService.verify(x => x.getAssets(app, 30, 0, undefined, []), Times.exactly(2));
});
it('should load with query when searching', () => {
assetsService.setup(x => x.getAssets(app, 30, 0, 'my-query', undefined))
assetsService.setup(x => x.getAssets(app, 30, 0, 'my-query', []))
.returns(() => of(new AssetsDto(0, [])));
assetsState.search('my-query').subscribe();
expect(assetsState.snapshot.assetsQuery).toEqual('my-query');
assetsService.verify(x => x.getAssets(app, 30, 0, 'my-query', undefined), Times.once());
assetsService.verify(x => x.getAssets(app, 30, 0, 'my-query', []), Times.once());
});
it('should load with tag when tag changed', () => {
assetsService.setup(x => x.getAssets(app, 30, 0, undefined, 'tag1'))
it('should load with tags when tag toggled', () => {
assetsService.setup(x => x.getAssets(app, 30, 0, undefined, ['tag1']))
.returns(() => of(new AssetsDto(0, [])));
assetsState.selectTag('tag1').subscribe();
assetsState.toggleTag('tag1').subscribe();
expect(assetsState.snapshot.tag).toEqual('tag1');
expect(assetsState.isTagSelected('tag1')).toBeTruthy();
assetsService.verify(x => x.getAssets(app, 30, 0, undefined, 'tag1'), Times.once());
assetsService.verify(x => x.getAssets(app, 30, 0, undefined, ['tag1']), Times.once());
});
it('should load without tags when tags reset', () => {
assetsService.setup(x => x.getAssets(app, 30, 0, undefined, []))
.returns(() => of(new AssetsDto(0, [])));
assetsState.resetTags().subscribe();
expect(assetsState.isTagSelectionEmpty()).toBeTruthy();
assetsService.verify(x => x.getAssets(app, 30, 0, undefined, []), Times.exactly(2));
});
});

50
src/Squidex/app/shared/state/assets.state.ts

@ -22,7 +22,7 @@ import { AppsState } from './apps.state';
interface Snapshot {
tags: { [name: string]: number };
tag?: string;
tagsSelected: { [name: string]: boolean };
assets: ImmutableArray<AssetDto>;
assetsPager: Pager;
@ -37,10 +37,6 @@ export class AssetsState extends State<Snapshot> {
this.changes.pipe(map(x => x.tags),
distinctUntilChanged());
public tag =
this.changes.pipe(map(x => x.tag),
distinctUntilChanged());
public assets =
this.changes.pipe(map(x => x.assets),
distinctUntilChanged());
@ -58,7 +54,7 @@ export class AssetsState extends State<Snapshot> {
private readonly assetsService: AssetsService,
private readonly dialogs: DialogService
) {
super({ assets: ImmutableArray.empty(), assetsPager: new Pager(0, 0, 30), tags: {} });
super({ assets: ImmutableArray.empty(), assetsPager: new Pager(0, 0, 30), tags: {}, tagsSelected: {} });
}
public load(isReload = false): Observable<any> {
@ -71,7 +67,11 @@ export class AssetsState extends State<Snapshot> {
private loadInternal(isReload = false): Observable<any> {
return combineLatest(
this.assetsService.getAssets(this.appName, this.snapshot.assetsPager.pageSize, this.snapshot.assetsPager.skip, this.snapshot.assetsQuery, this.snapshot.tag),
this.assetsService.getAssets(this.appName,
this.snapshot.assetsPager.pageSize,
this.snapshot.assetsPager.skip,
this.snapshot.assetsQuery,
Object.keys(this.snapshot.tagsSelected)),
this.assetsService.getTags(this.appName)
).pipe(
tap(dtos => {
@ -106,16 +106,18 @@ export class AssetsState extends State<Snapshot> {
const assetsPager = s.assetsPager.decrementCount();
const tags = { ...s.tags };
const tagsSelected = { ...s.tagsSelected };
for (let tag of asset.tags) {
if (tags[tag] === 1) {
delete tags[tag];
delete tagsSelected[tag];
} else {
tags[tag]--;
}
}
return { ...s, assets, assetsPager, tags };
return { ...s, assets, assetsPager, tags, tagsSelected };
});
}),
notify(this.dialogs));
@ -126,11 +128,13 @@ export class AssetsState extends State<Snapshot> {
const previous = s.assets.find(x => x.id === asset.id);
const tags = { ...s.tags };
const tagsSelected = { ...s.tagsSelected };
if (previous) {
for (let tag of previous.tags) {
if (tags[tag] === 1) {
delete tags[tag];
delete tagsSelected[tag];
} else {
tags[tag]--;
}
@ -149,12 +153,28 @@ export class AssetsState extends State<Snapshot> {
const assets = s.assets.replaceBy('id', asset);
return { ...s, assets, tags };
return { ...s, assets, tags, tagsSelected };
});
}
public selectTag(tag: string): Observable<any> {
this.next(s => ({ ...s, assetsPager: new Pager(0, 0, 30), tag }));
public toggleTag(tag: string): Observable<any> {
this.next(s => {
const tagsSelected = { ...s.tagsSelected };
if (tagsSelected[tag]) {
delete tagsSelected[tag];
} else {
tagsSelected[tag] = true;
}
return { ...s, assetsPager: new Pager(0, 0, 30), tagsSelected };
});
return this.loadInternal();
}
public resetTags(): Observable<any> {
this.next(s => ({ ...s, assetsPager: new Pager(0, 0, 30), tagsSelected: {} }));
return this.loadInternal();
}
@ -177,6 +197,14 @@ export class AssetsState extends State<Snapshot> {
return this.loadInternal();
}
public isTagSelected(tag: string) {
return this.snapshot.tagsSelected[tag] === true;
}
public isTagSelectionEmpty() {
return Object.keys(this.snapshot.tagsSelected).length === 0;
}
private get appName() {
return this.appsState.appName;
}

3
src/Squidex/app/theme/_vars.scss

@ -97,4 +97,5 @@ $panel-header: 5.4rem;
$panel-sidebar: 3.75rem;
$panel-light-background: #fff;
$asset-height: 16rem;
$asset-width: 16rem;
$asset-height: 18rem;
Loading…
Cancel
Save