Browse Source

Feature/focus point (#482)

* Improved image editor and focus point.

* added missing files.

* Folder renamed

* Focus point improvement.

* Focus point in API.

* Tags improved.

* Another style fix.
pull/483/head
Sebastian Stehle 6 years ago
committed by GitHub
parent
commit
d5d1285419
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetMetadata.cs
  2. 2
      backend/src/Squidex.Infrastructure/Assets/IAssetThumbnailGenerator.cs
  3. 46
      backend/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs
  4. 20
      backend/src/Squidex.Infrastructure/Assets/ResizeMode.cs
  5. 57
      backend/src/Squidex.Infrastructure/Assets/ResizeOptions.cs
  6. 2
      backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj
  7. 3
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs
  8. 15
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs
  9. 65
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetQuery.cs
  10. 3
      backend/src/Squidex/Areas/IdentityServer/Controllers/Profile/ProfileController.cs
  11. 32
      backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetMetadataTests.cs
  12. 16
      backend/tests/Squidex.Infrastructure.Tests/Assets/ImageSharpAssetThumbnailGeneratorTests.cs
  13. 4
      frontend/app/features/assets/pages/assets-page.component.html
  14. 2
      frontend/app/features/content/shared/references/content-selector.component.scss
  15. 2
      frontend/app/features/rules/pages/rules/rule-icon.component.scss
  16. 2
      frontend/app/features/schemas/pages/schema/export/schema-export-form.component.scss
  17. 2
      frontend/app/features/schemas/pages/schema/scripts/schema-scripts-form.component.scss
  18. 3
      frontend/app/features/schemas/pages/schema/ui/field-list.component.scss
  19. 2
      frontend/app/features/schemas/pages/schema/ui/schema-ui-form.component.scss
  20. 2
      frontend/app/features/settings/pages/contributors/contributor-add-form.component.scss
  21. 3
      frontend/app/features/settings/pages/workflows/workflow.component.html
  22. 1
      frontend/app/framework/angular/forms/editors/tag-editor.component.html
  23. 15
      frontend/app/framework/angular/forms/editors/tag-editor.component.scss
  24. 3
      frontend/app/framework/angular/forms/editors/tag-editor.component.ts
  25. 2
      frontend/app/framework/angular/forms/progress-bar.component.ts
  26. 10
      frontend/app/framework/angular/image-source.directive.ts
  27. 21
      frontend/app/framework/angular/list-view.component.scss
  28. 10
      frontend/app/framework/angular/modals/modal-dialog.component.html
  29. 4
      frontend/app/framework/angular/modals/modal-dialog.component.scss
  30. 3
      frontend/app/framework/angular/modals/modal-dialog.component.ts
  31. 41
      frontend/app/shared/components/assets/asset-dialog.component.html
  32. 4
      frontend/app/shared/components/assets/asset-dialog.component.scss
  33. 86
      frontend/app/shared/components/assets/asset-dialog.component.ts
  34. 0
      frontend/app/shared/components/assets/asset-folder-dialog.component.html
  35. 0
      frontend/app/shared/components/assets/asset-folder-dialog.component.scss
  36. 8
      frontend/app/shared/components/assets/asset-folder-dialog.component.ts
  37. 4
      frontend/app/shared/components/assets/asset-folder.component.html
  38. 2
      frontend/app/shared/components/assets/asset-folder.component.scss
  39. 14
      frontend/app/shared/components/assets/asset.component.html
  40. 43
      frontend/app/shared/components/assets/asset.component.scss
  41. 2
      frontend/app/shared/components/assets/asset.component.ts
  42. 29
      frontend/app/shared/components/assets/image-cropper.component.html
  43. 46
      frontend/app/shared/components/assets/image-cropper.component.scss
  44. 134
      frontend/app/shared/components/assets/image-cropper.component.ts
  45. 1
      frontend/app/shared/components/assets/image-editor.component.html
  46. 29
      frontend/app/shared/components/assets/image-editor.component.scss
  47. 199
      frontend/app/shared/components/assets/image-editor.component.ts
  48. 29
      frontend/app/shared/components/assets/image-focus-point.component.html
  49. 41
      frontend/app/shared/components/assets/image-focus-point.component.scss
  50. 108
      frontend/app/shared/components/assets/image-focus-point.component.ts
  51. 6
      frontend/app/shared/components/assets/pipes.ts
  52. 5
      frontend/app/shared/declarations.ts
  53. 12
      frontend/app/shared/module.ts
  54. 11
      frontend/app/shared/services/assets.service.ts
  55. 2
      frontend/app/theme/_bootstrap-vars.scss
  56. 3
      frontend/app/theme/_bootstrap.scss
  57. 11
      frontend/app/theme/_lists.scss
  58. 4
      frontend/app/theme/_vars.scss
  59. 4
      frontend/app/theme/icomoon/demo-files/demo.css
  60. 490
      frontend/app/theme/icomoon/demo.html
  61. BIN
      frontend/app/theme/icomoon/fonts/icomoon.eot
  62. 5
      frontend/app/theme/icomoon/fonts/icomoon.svg
  63. BIN
      frontend/app/theme/icomoon/fonts/icomoon.ttf
  64. BIN
      frontend/app/theme/icomoon/fonts/icomoon.woff
  65. 2
      frontend/app/theme/icomoon/selection.json
  66. 177
      frontend/app/theme/icomoon/style.css
  67. 10
      frontend/package-lock.json
  68. 2
      frontend/package.json

34
backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetMetadata.cs

@ -17,6 +17,20 @@ namespace Squidex.Domain.Apps.Core.Assets
{
private static readonly char[] PathSeparators = { '.', '[', ']' };
public AssetMetadata SetFocusX(float value)
{
this["focusX"] = JsonValue.Create(value);
return this;
}
public AssetMetadata SetFocusY(float value)
{
this["focusY"] = JsonValue.Create(value);
return this;
}
public AssetMetadata SetPixelWidth(int value)
{
this["pixelWidth"] = JsonValue.Create(value);
@ -31,6 +45,26 @@ namespace Squidex.Domain.Apps.Core.Assets
return this;
}
public float? GetFocusX()
{
if (TryGetValue("focusX", out var n) && n is JsonNumber number)
{
return (float)number.Value;
}
return null;
}
public float? GetFocusY()
{
if (TryGetValue("focusY", out var n) && n is JsonNumber number)
{
return (float)number.Value;
}
return null;
}
public int? GetPixelWidth()
{
if (TryGetValue("pixelWidth", out var n) && n is JsonNumber number)

2
backend/src/Squidex.Infrastructure/Assets/IAssetThumbnailGenerator.cs

@ -14,6 +14,6 @@ namespace Squidex.Infrastructure.Assets
{
Task<ImageInfo?> GetImageInfoAsync(Stream source);
Task CreateThumbnailAsync(Stream source, Stream destination, int? width = null, int? height = null, string? mode = null, int? quality = null);
Task CreateThumbnailAsync(Stream source, Stream destination, ResizeOptions options);
}
}

46
backend/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs

@ -11,18 +11,24 @@ using System.Threading.Tasks;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Transforms;
using SixLabors.Primitives;
using ISResizeMode = SixLabors.ImageSharp.Processing.ResizeMode;
using ISResizeOptions = SixLabors.ImageSharp.Processing.ResizeOptions;
namespace Squidex.Infrastructure.Assets.ImageSharp
{
public sealed class ImageSharpAssetThumbnailGenerator : IAssetThumbnailGenerator
{
public Task CreateThumbnailAsync(Stream source, Stream destination, int? width = null, int? height = null, string? mode = null, int? quality = null)
public Task CreateThumbnailAsync(Stream source, Stream destination, ResizeOptions options)
{
Guard.NotNull(options);
return Task.Run(() =>
{
if (!width.HasValue && !height.HasValue && !quality.HasValue)
var w = options.Width ?? 0;
var h = options.Height ?? 0;
if (w <= 0 && h <= 0 && !options.Quality.HasValue)
{
source.CopyTo(destination);
@ -33,9 +39,9 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
{
var encoder = Configuration.Default.ImageFormatsManager.FindEncoder(format);
if (quality.HasValue)
if (options.Quality.HasValue)
{
encoder = new JpegEncoder { Quality = quality.Value };
encoder = new JpegEncoder { Quality = options.Quality.Value };
}
if (encoder == null)
@ -43,31 +49,37 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
throw new NotSupportedException();
}
if (width.HasValue || height.HasValue)
if (w > 0 && h > 0)
{
var isCropUpsize = string.Equals("CropUpsize", mode, StringComparison.OrdinalIgnoreCase);
var isCropUpsize = options.Mode == ResizeMode.CropUpsize;
if (!Enum.TryParse<ResizeMode>(mode, true, out var resizeMode))
if (!Enum.TryParse<ISResizeMode>(options.Mode.ToString(), true, out var resizeMode))
{
resizeMode = ResizeMode.Max;
resizeMode = ISResizeMode.Max;
}
if (isCropUpsize)
{
resizeMode = ResizeMode.Crop;
resizeMode = ISResizeMode.Crop;
}
var resizeWidth = width ?? 0;
var resizeHeight = height ?? 0;
if (resizeWidth >= sourceImage.Width && resizeHeight >= sourceImage.Height && resizeMode == ResizeMode.Crop && !isCropUpsize)
if (w >= sourceImage.Width && h >= sourceImage.Height && resizeMode == ISResizeMode.Crop && !isCropUpsize)
{
resizeMode = ResizeMode.BoxPad;
resizeMode = ISResizeMode.BoxPad;
}
var options = new ResizeOptions { Size = new Size(resizeWidth, resizeHeight), Mode = resizeMode };
var resizeOptions = new ISResizeOptions { Size = new Size(w, h), Mode = resizeMode };
if (options.FocusX.HasValue && options.FocusY.HasValue)
{
resizeOptions.CenterCoordinates = new float[]
{
+(options.FocusX.Value / 2f) + 0.5f,
-(options.FocusX.Value / 2f) + 0.5f
};
}
sourceImage.Mutate(x => x.Resize(options));
sourceImage.Mutate(x => x.Resize(resizeOptions));
}
sourceImage.Save(destination, encoder);

20
backend/src/Squidex.Infrastructure/Assets/ResizeMode.cs

@ -0,0 +1,20 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Infrastructure.Assets
{
public enum ResizeMode
{
Crop,
CropUpsize,
Pad,
BoxPad,
Max,
Min,
Stretch
}
}

57
backend/src/Squidex.Infrastructure/Assets/ResizeOptions.cs

@ -0,0 +1,57 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Text;
namespace Squidex.Infrastructure.Assets
{
public sealed class ResizeOptions
{
public int? Width { get; set; }
public int? Height { get; set; }
public int? Quality { get; set; }
public float? FocusX { get; set; }
public float? FocusY { get; set; }
public ResizeMode Mode { get; set; }
public override string ToString()
{
var sb = new StringBuilder();
sb.Append(Width);
sb.Append("_");
sb.Append(Height);
sb.Append("_");
sb.Append(Mode);
if (Quality.HasValue)
{
sb.Append("_");
sb.Append(Quality);
}
if (FocusX.HasValue)
{
sb.Append("_focusX_");
sb.Append(FocusX);
}
if (FocusY.HasValue)
{
sb.Append("_focusY_");
sb.Append(FocusY);
}
return sb.ToString();
}
}
}

2
backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj

@ -30,7 +30,7 @@
<PackageReference Include="NJsonSchema" Version="10.1.5" />
<PackageReference Include="NodaTime" Version="2.4.7" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0004" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0007" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="1.7.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />

3
backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs

@ -34,6 +34,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
[ApiExplorerSettings(GroupName = nameof(Apps))]
public sealed class AppsController : ApiController
{
private static readonly ResizeOptions ResizeOptions = new ResizeOptions { Width = 50, Height = 50, Mode = ResizeMode.Crop };
private readonly IAppImageStore appImageStore;
private readonly IAssetStore assetStore;
private readonly IAssetThumbnailGenerator assetThumbnailGenerator;
@ -232,7 +233,7 @@ namespace Squidex.Areas.Api.Controllers.Apps
using (Profiler.Trace("ResizeImage"))
{
await assetThumbnailGenerator.CreateThumbnailAsync(sourceStream, destinationStream, 150, 150, "Crop");
await assetThumbnailGenerator.CreateThumbnailAsync(sourceStream, destinationStream, ResizeOptions);
destinationStream.Position = 0;
}

15
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs

@ -136,14 +136,11 @@ namespace Squidex.Areas.Api.Controllers.Assets
var handler = new Func<Stream, Task>(async bodyStream =>
{
if (asset.Type == AssetType.Image && query.ShouldResize())
{
var resizedAsset = $"{asset.Id}_{asset.FileVersion}_{query.Width}_{query.Height}_{query.Mode}";
var resizeOptions = query.ToResizeOptions(asset);
if (query.Quality.HasValue)
{
resizedAsset += $"_{query.Quality}";
}
if (asset.Type == AssetType.Image && resizeOptions != null)
{
var resizedAsset = $"{asset.Id}_{asset.FileVersion}_{resizeOptions}";
try
{
@ -165,7 +162,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
using (Profiler.Trace("ResizeImage"))
{
await assetThumbnailGenerator.CreateThumbnailAsync(sourceStream, destinationStream, query.Width, query.Height, query.Mode, query.Quality);
await assetThumbnailGenerator.CreateThumbnailAsync(sourceStream, destinationStream, resizeOptions);
destinationStream.Position = 0;
}
@ -187,7 +184,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
}
});
if (query.Download == 1)
if (query.Download == 1 || asset.Type != AssetType.Image)
{
return new FileCallbackResult(asset.MimeType, asset.FileName, true, handler);
}

65
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetQuery.cs

@ -5,8 +5,12 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Areas.Api.Controllers.Assets.Models
{
@ -28,7 +32,7 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models
/// Set it to 0 to prevent download.
/// </summary>
[FromQuery(Name = "download")]
public int Download { get; set; } = 1;
public int Download { get; set; } = 0;
/// <summary>
/// The target width of the asset, if it is an image.
@ -52,11 +56,64 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models
/// The resize mode when the width and height is defined.
/// </summary>
[FromQuery(Name = "mode")]
public string? Mode { get; set; }
public ResizeMode? Mode { get; set; }
public bool ShouldResize()
/// <summary>
/// Override the y focus point.
/// </summary>
[FromQuery(Name = "focusX")]
public float? FocusX { get; set; }
/// <summary>
/// Override the x focus point.
/// </summary>
[FromQuery(Name = "focusY")]
public float? FocusY { get; set; }
/// <summary>
/// True to ignore the asset focus point if any.
/// </summary>
[FromQuery(Name = "nofocus")]
public bool IgnoreFocus { get; set; }
public ResizeOptions? ToResizeOptions(IAssetEntity asset)
{
Guard.NotNull(asset);
if (!Width.HasValue && !Height.HasValue && !Quality.HasValue)
{
return null;
}
var result = SimpleMapper.Map(this, new ResizeOptions());
var (x, y) = GetFocusPoint(asset);
result.FocusX = x;
result.FocusY = y;
return result;
}
private (float?, float?) GetFocusPoint(IAssetEntity asset)
{
return Width.HasValue || Height.HasValue || Quality.HasValue;
if (!IgnoreFocus)
{
if (FocusX.HasValue && FocusY.HasValue)
{
return (FocusX.Value, FocusY.Value);
}
var focusX = asset.Metadata.GetFocusX();
var focusY = asset.Metadata.GetFocusY();
if (focusX.HasValue && focusY.HasValue)
{
return (focusX.Value, focusY.Value);
}
}
return (null, null);
}
}
}

3
backend/src/Squidex/Areas/IdentityServer/Controllers/Profile/ProfileController.cs

@ -29,6 +29,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Profile
[Authorize]
public sealed class ProfileController : IdentityServerController
{
private static readonly ResizeOptions ResizeOptions = new ResizeOptions { Width = 128, Height = 128, Mode = ResizeMode.Crop };
private readonly SignInManager<IdentityUser> signInManager;
private readonly UserManager<IdentityUser> userManager;
private readonly IUserPictureStore userPictureStore;
@ -145,7 +146,7 @@ namespace Squidex.Areas.IdentityServer.Controllers.Profile
{
try
{
await assetThumbnailGenerator.CreateThumbnailAsync(file[0].OpenReadStream(), thumbnailStream, 128, 128, "Crop");
await assetThumbnailGenerator.CreateThumbnailAsync(file[0].OpenReadStream(), thumbnailStream, ResizeOptions);
thumbnailStream.Position = 0;
}

32
backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetMetadataTests.cs

@ -13,6 +13,27 @@ namespace Squidex.Domain.Apps.Core.Model.Assets
{
public class AssetMetadataTests
{
[Fact]
public void Should_return_focus_infos_if_found()
{
var sut =
new AssetMetadata()
.SetFocusX(.5f)
.SetFocusY(.2f);
Assert.Equal(.5f, sut.GetFocusX());
Assert.Equal(.2f, sut.GetFocusY());
}
[Fact]
public void Should_return_null_if_focus_infos_not_found()
{
var sut = new AssetMetadata();
Assert.Null(sut.GetFocusX());
Assert.Null(sut.GetFocusY());
}
[Fact]
public void Should_return_pixel_infos_if_found()
{
@ -48,9 +69,12 @@ namespace Squidex.Domain.Apps.Core.Model.Assets
[Fact]
public void Should_return_plain_value_if_found()
{
var sut = new AssetMetadata().SetPixelWidth(800);
var sut = new AssetMetadata
{
["someValue"] = JsonValue.Create(800)
};
var found = sut.TryGetByPath("pixelWidth", out var result);
var found = sut.TryGetByPath("someValue", out var result);
Assert.True(found);
Assert.Equal(JsonValue.Create(800), result);
@ -59,9 +83,9 @@ namespace Squidex.Domain.Apps.Core.Model.Assets
[Fact]
public void Should_return_null_if_not_found()
{
var sut = new AssetMetadata().SetPixelWidth(800);
var sut = new AssetMetadata();
var found = sut.TryGetByPath("pixelHeight", out var result);
var found = sut.TryGetByPath("notFound", out var result);
Assert.False(found);
Assert.Null(result);

16
backend/tests/Squidex.Infrastructure.Tests/Assets/ImageSharpAssetThumbnailGeneratorTests.cs

@ -19,11 +19,11 @@ namespace Squidex.Infrastructure.Assets
private readonly MemoryStream target = new MemoryStream();
[Fact]
public async Task Should_return_same_image_if_no_size_is_passed_for_thumbnail()
public async Task Should_return_same_image_if_no_size_and_quality_is_passed_for_thumbnail()
{
var source = GetPng();
await sut.CreateThumbnailAsync(source, target);
await sut.CreateThumbnailAsync(source, target, new ResizeOptions());
Assert.Equal(target.Length, source.Length);
}
@ -33,7 +33,9 @@ namespace Squidex.Infrastructure.Assets
{
var source = GetPng();
await sut.CreateThumbnailAsync(source, target, 1000, 1000, "resize");
var options = new ResizeOptions { Width = 1000, Height = 1000, Mode = ResizeMode.BoxPad };
await sut.CreateThumbnailAsync(source, target, options);
Assert.True(target.Length > source.Length);
}
@ -43,7 +45,9 @@ namespace Squidex.Infrastructure.Assets
{
var source = GetJpeg();
await sut.CreateThumbnailAsync(source, target, quality: 10);
var options = new ResizeOptions { Quality = 10 };
await sut.CreateThumbnailAsync(source, target, options);
Assert.True(target.Length < source.Length);
}
@ -53,7 +57,9 @@ namespace Squidex.Infrastructure.Assets
{
var source = GetPng();
await sut.CreateThumbnailAsync(source, target, quality: 10);
var options = new ResizeOptions { Quality = 10 };
await sut.CreateThumbnailAsync(source, target, options);
Assert.True(target.Length < source.Length);
}

4
frontend/app/features/assets/pages/assets-page.component.html

@ -82,9 +82,9 @@
</sqx-panel>
<ng-container *sqxModal="addAssetFolderDialog">
<sqx-asset-folder-form
<sqx-asset-folder-dialog
(complete)="addAssetFolderDialog.hide()">
</sqx-asset-folder-form>
</sqx-asset-folder-dialog>
</ng-container>
<router-outlet></router-outlet>

2
frontend/app/features/content/shared/references/content-selector.component.scss

@ -12,7 +12,7 @@
position: relative;
.form-control {
@include absolute(-.4rem, auto, auto, 0);
@include absolute(-.125rem, auto, auto, 0);
@include force-width(300px);
color: $color-dark-foreground;
}

2
frontend/app/features/rules/pages/rules/rule-icon.component.scss

@ -1,4 +1,4 @@
:ng-deep {
:host ::ng-deep {
svg {
display: block;

2
frontend/app/features/schemas/pages/schema/export/schema-export-form.component.scss

@ -13,7 +13,7 @@
.inner-header {
background: $color-theme-secondary;
border: 0;
border-bottom: 1px solid $color-border-darker;
padding: 1rem $panel-padding;
}

2
frontend/app/features/schemas/pages/schema/scripts/schema-scripts-form.component.scss

@ -13,7 +13,7 @@
.inner-header {
background: $color-theme-secondary;
border: 0;
border-bottom: 1px solid $color-border-darker;
padding: 1rem $panel-padding;
}

3
frontend/app/features/schemas/pages/schema/ui/field-list.component.scss

@ -8,11 +8,12 @@
&-assigned {
@include absolute(0, 50%, 0, 0);
border-right: 1px solid $color-border;
border-right: 1px solid darken($color-input, 2%);
}
&-available {
@include absolute(0, 0, 0, 50%);
border: 0;
}
}

2
frontend/app/features/schemas/pages/schema/ui/schema-ui-form.component.scss

@ -13,6 +13,6 @@
.inner-header {
background: $color-theme-secondary;
border-bottom: 1px solid $color-border;
border-bottom: 1px solid $color-border-darker;
padding: 1rem $panel-padding;
}

2
frontend/app/features/settings/pages/contributors/contributor-add-form.component.scss

@ -9,7 +9,5 @@
}
.table-items-header {
border: 0;
border-bottom: 2px solid $color-border;
margin: 0;
}

3
frontend/app/features/settings/pages/workflows/workflow.component.html

@ -6,11 +6,10 @@
</div>
<div class="col col-tags">
<sqx-tag-editor [converter]="schemasSource.converter | async" [ngModel]="workflow.schemaIds"
placeholder=""
styleGray="true"
styleBlank="true"
singleLine="true"
disabled="true">
readonly="true">
</sqx-tag-editor>
</div>
<div class="col-options">

1
frontend/app/framework/angular/forms/editors/tag-editor.component.html

@ -3,6 +3,7 @@
[class.blank]="styleBlank"
[class.gray]="styleGray"
[class.singleline]="singleLine"
[class.readonly]="readonly"
[class.multiline]="!singleLine"
[class.focus]="snapshot.hasFocus"
[class.disabled]="addInput.disabled"

15
frontend/app/framework/angular/forms/editors/tag-editor.component.scss

@ -47,6 +47,18 @@ $inner-height: 1.75rem;
&.dashed {
border-style: dashed;
}
&.readonly {
pointer-events: none;
input {
display: none !important;
}
.icon-close {
display: none !important;
}
}
}
.multiline {
@ -74,7 +86,8 @@ div {
}
&.disabled,
&:disabled {
&:disabled,
&.readonly {
background: transparent;
}

3
frontend/app/framework/angular/forms/editors/tag-editor.component.ts

@ -176,6 +176,9 @@ export class TagEditorComponent extends StatefulControlComponent<State, Readonly
@Input()
public singleLine = false;
@Input()
public readonly = false;
@Input()
public styleBlank = false;

2
frontend/app/framework/angular/forms/progress-bar.component.ts

@ -12,7 +12,7 @@ import * as ProgressBar from 'progressbar.js';
@Component({
selector: 'sqx-progress-bar',
styles: [`
:host /deep/ svg {
:host ::ng-deep svg {
vertical-align: top
}`
],

10
frontend/app/framework/angular/image-source.directive.ts

@ -25,10 +25,6 @@ export class ImageSourceDirective extends ResourceOwner implements OnChanges, On
@Input()
public retryCount = 10;
@Input()
public accessToken: string;
@Input()
public layoutKey: string;
@ -126,16 +122,12 @@ export class ImageSourceDirective extends ResourceOwner implements OnChanges, On
const h = Math.round(this.size.height);
if (w > 0 && h > 0) {
let source = `${this.imageSource}&width=${w}&height=${h}&mode=Pad`;
let source = `${this.imageSource}&width=${w}&height=${h}&mode=Pad&nofocus`;
if (this.loadQuery) {
source += `&q=${this.loadQuery}`;
}
if (this.accessToken) {
source += `&access_token=${this.accessToken}`;
}
this.renderer.setProperty(this.element.nativeElement, 'src', source);
}
}

21
frontend/app/framework/angular/list-view.component.scss

@ -20,6 +20,7 @@
}
&-content {
flex-direction: column;
flex-grow: 1;
padding: $panel-padding;
@ -52,16 +53,18 @@
display: table-cell;
}
/deep/ th {
padding: .75rem;
}
::ng-deep {
th {
padding: .75rem;
}
/deep/ table {
margin: 0;
}
table {
margin: 0;
}
/deep/ .table-items {
margin: 0;
.table-items {
margin: 0;
}
}
}
@ -72,7 +75,7 @@
flex-shrink: 0;
}
/deep/ .pagination {
::ng-deep .pagination {
margin: .25rem 0;
}
}

10
frontend/app/framework/angular/modals/modal-dialog.component.html

@ -6,15 +6,13 @@
<ng-content select="[title]"></ng-content>
</h4>
<button type="button" class="close" (click)="close.emit()">
<ng-content select="[plainTitle]"></ng-content>
<button type="button" class="btn btn-close" (click)="close.emit()">
<i class="icon-close"></i>
</button>
</div>
<div class="modal-tabs clearfix" #tabsElement *ngIf="showTabs">
<ng-content select="[tabs]"></ng-content>
</div>
<div class="modal-body" [class.flexed]="flexBody">
<ng-content select="[content]"></ng-content>
</div>

4
frontend/app/framework/angular/modals/modal-dialog.component.scss

@ -2,6 +2,10 @@
display: block;
}
.modal-header {
position: relative;
}
.flexed {
display: flex;
flex-direction: column;

3
frontend/app/framework/angular/modals/modal-dialog.component.ts

@ -31,9 +31,6 @@ export class ModalDialogComponent implements AfterViewInit {
@Input()
public showFooter = true;
@Input()
public showTabs = true;
@Input()
public size: 'sm' | 'md' | 'lg' | 'xl' = 'md';

41
frontend/app/shared/components/assets/asset-dialog.component.html

@ -1,31 +1,44 @@
<form [formGroup]="annotateForm.form" (ngSubmit)="annotateAsset()">
<sqx-modal-dialog (close)="emitComplete()" size="xl" fullHeight="true" [showHeader]="true" [showFooter]="false">
<ng-container title>
Update Asset
</ng-container>
<ng-container tabs>
<sqx-modal-dialog (close)="emitComplete()" size="xl" fullHeight="true" [title]="false" [showFooter]="false">
<ng-container plainTitle>
<ul class="nav nav-tabs2">
<li class="nav-item" *ngFor="let tab of selectableTabs">
<a class="nav-link" [class.active]="tab === selectedTab" (click)="selectTab(tab)">{{tab}}</a>
</li>
</ul>
<ng-container [ngSwitch]="selectedTab">
<ng-container *ngSwitchCase="'Image'">
<button type="submit" class="float-right btn btn-primary" [class.invisible]="!isUploadable" [disabled]="progress > 0">Save</button>
<ng-container [ngSwitch]="selectedTab">
<ng-container *ngSwitchCase="'Image'">
<button type="button" class="btn btn-primary ml-auto mr-4" (click)="cropImage()" [class.invisible]="!isUploadable" [disabled]="progress > 0">Save</button>
</ng-container>
<ng-container *ngSwitchCase="'Focus Point'">
<button type="button" class="btn btn-primary ml-auto mr-4" (click)="setFocusPoint()" [class.invisible]="!isEditable">Save</button>
</ng-container>
<ng-container *ngSwitchCase="'Metadata'">
<button type="submit" class="btn btn-primary ml-auto mr-4" [class.invisible]="!isEditable">Save</button>
</ng-container>
</ng-container>
<ng-container *ngSwitchCase="'Metadata'">
<button type="submit" class="float-right btn btn-primary" [class.invisible]="!isEditable">Save</button>
</ng-container>
</ng-container>
</ng-container>
<ng-container content>
<ng-container [ngSwitch]="selectedTab">
<ng-container *ngSwitchCase="'Image'">
<div class="image">
<sqx-image-editor [accessToken]="accessToken" [imageUrl]="asset.contentUrl"></sqx-image-editor>
<sqx-image-editor [imageSource]="asset | sqxAssetPreviewUrl"></sqx-image-editor>
<div class="image-progress" *ngIf="progress > 0">
<sqx-progress-bar
[strokeWidth]="2"
[trailColor]="'transparent'"
[trailWidth]="0"
[value]="progress">
</sqx-progress-bar>
</div>
</div>
</ng-container>
<ng-container *ngSwitchCase="'Focus Point'">
<div>
<sqx-image-focus-point [imageSource]="asset | sqxAssetPreviewUrl" [focusPoint]="asset.metadata"></sqx-image-focus-point>
<div class="image-progress" *ngIf="progress > 0">
<sqx-progress-bar

4
frontend/app/shared/components/assets/asset-dialog.component.scss

@ -12,6 +12,10 @@
}
}
.nav-link {
padding-bottom: 1.25rem;
}
.invisible {
visibility: hidden;
}

86
frontend/app/shared/components/assets/asset-dialog.component.ts

@ -5,10 +5,11 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, QueryList, ViewChildren } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, QueryList, ViewChildren } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import {
AnnotateAssetDto,
AnnotateAssetForm,
AssetDto,
AssetsState,
@ -19,7 +20,8 @@ import {
UploadCanceled
} from '@app/shared/internal';
import { ImageEditorComponent } from './image-editor.component';
import { ImageCropperComponent } from './image-cropper.component';
import { ImageFocusPointComponent } from './image-focus-point.component';
@Component({
selector: 'sqx-asset-dialog',
@ -27,24 +29,24 @@ import { ImageEditorComponent } from './image-editor.component';
templateUrl: './asset-dialog.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AssetDialogComponent implements OnInit {
export class AssetDialogComponent implements OnChanges {
@Output()
public complete = new EventEmitter();
@Output()
public changed = new EventEmitter<AssetDto>();
@Input()
public accessToken: string;
@Input()
public asset: AssetDto;
@Input()
public allTags: ReadonlyArray<string>;
@ViewChildren(ImageEditorComponent)
public imageEditor: QueryList<ImageEditorComponent>;
@ViewChildren(ImageCropperComponent)
public imageCropper: QueryList<ImageCropperComponent>;
@ViewChildren(ImageFocusPointComponent)
public imageFocus: QueryList<ImageFocusPointComponent>;
public isEditable = false;
public isEditableAny = false;
@ -67,7 +69,7 @@ export class AssetDialogComponent implements OnInit {
) {
}
public ngOnInit() {
public ngOnChanges() {
this.isEditable = this.asset.canUpdate;
this.isUploadable = this.asset.canUpload;
@ -75,12 +77,14 @@ export class AssetDialogComponent implements OnInit {
this.annotateForm.setEnabled(this.isEditable);
if (this.asset.type === 'Image') {
this.selectableTabs = ['Metadata', 'Image'];
this.selectableTabs = ['Metadata', 'Image', 'Focus Point'];
} else {
this.selectableTabs = ['Metadata'];
}
this.selectTab(this.selectableTabs[0]);
if (this.selectableTabs.indexOf(this.selectedTab) < 0) {
this.selectTab(this.selectableTabs[0]);
}
}
public selectTab(tab: string) {
@ -95,14 +99,12 @@ export class AssetDialogComponent implements OnInit {
this.complete.emit();
}
public annotateAsset() {
if (this.selectedTab === 'Image') {
if (!this.isUploadable) {
return;
}
const file = this.imageEditor.first.toFile();
public cropImage() {
if (!this.isUploadable) {
return;
}
this.imageCropper.first.toFile().then(file => {
if (file) {
this.setProgress(0);
@ -112,9 +114,9 @@ export class AssetDialogComponent implements OnInit {
this.setProgress(dto);
} else {
this.changed.emit(dto);
}
this.dialogs.notifyInfo('Asset has been updated.');
this.dialogs.notifyInfo('Asset has been updated.');
}
}, error => {
if (!Types.is(error, UploadCanceled)) {
this.dialogs.notifyError(error);
@ -125,25 +127,37 @@ export class AssetDialogComponent implements OnInit {
} else {
this.dialogs.notifyInfo('Nothing has changed.');
}
} else {
if (!this.isEditable) {
return;
}
});
}
const value = this.annotateForm.submit(this.asset);
public setFocusPoint() {
if (!this.isEditable) {
return;
}
if (value) {
this.assetsState.updateAsset(this.asset, value)
.subscribe(() => {
this.annotateForm.submitCompleted({ noReset: true });
this.annoateAssetInternal(this.imageFocus.first.submit(this.asset));
}
this.dialogs.notifyInfo('Asset has been updated.');
}, error => {
this.annotateForm.submitFailed(error);
});
} else {
this.dialogs.notifyInfo('Nothing has changed.');
}
public annotateAsset() {
if (!this.isEditable) {
return;
}
this.annoateAssetInternal(this.annotateForm.submit(this.asset));
}
private annoateAssetInternal(value: AnnotateAssetDto | null) {
if (value) {
this.assetsState.updateAsset(this.asset, value)
.subscribe(() => {
this.annotateForm.submitCompleted({ noReset: true });
this.dialogs.notifyInfo('Asset has been updated.');
}, error => {
this.annotateForm.submitFailed(error);
});
} else {
this.dialogs.notifyInfo('Nothing has changed.');
}
}

0
frontend/app/shared/components/assets/asset-folder-form.component.html → frontend/app/shared/components/assets/asset-folder-dialog.component.html

0
frontend/app/shared/components/assets/asset-folder-form.component.scss → frontend/app/shared/components/assets/asset-folder-dialog.component.scss

8
frontend/app/shared/components/assets/asset-folder-form.component.ts → frontend/app/shared/components/assets/asset-folder-dialog.component.ts

@ -15,12 +15,12 @@ import {
} from '@app/shared/internal';
@Component({
selector: 'sqx-asset-folder-form',
styleUrls: ['./asset-folder-form.component.scss'],
templateUrl: './asset-folder-form.component.html',
selector: 'sqx-asset-folder-dialog',
styleUrls: ['./asset-folder-dialog.component.scss'],
templateUrl: './asset-folder-dialog.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AssetFolderFormComponent implements OnInit {
export class AssetFolderDialogComponent implements OnInit {
@Output()
public complete = new EventEmitter();

4
frontend/app/shared/components/assets/asset-folder.component.html

@ -40,7 +40,7 @@
<ng-container *sqxModal="editDialog">
<sqx-asset-folder-form [assetFolder]="assetFolder"
<sqx-asset-folder-dialog [assetFolder]="assetFolder"
(complete)="editDialog.hide()">
</sqx-asset-folder-form>
</sqx-asset-folder-dialog>
</ng-container>

2
frontend/app/shared/components/assets/asset-folder.component.scss

@ -1,4 +1,4 @@
:host /deep/ {
:host ::ng-deep {
.cdk-drag-placeholder {
display: none;
}

14
frontend/app/shared/components/assets/asset.component.html

@ -11,7 +11,7 @@
<ng-container *ngIf="asset.canPreview; else noPreview">
<div class="file-image">
<img [sqxImageSource]="asset | sqxAssetPreviewUrl" [accessToken]="authService.user?.accessToken" class="bg" layoutKey="asset-large">
<img [sqxImageSource]="asset | sqxAssetPreviewUrl" layoutKey="asset-large">
</div>
</ng-container>
<ng-template #noPreview>
@ -68,12 +68,16 @@
<div class="card-footer" (dblclick)="edit()">
<ng-container *ngIf="asset">
<div>
<div class="file-name editable" (click)="edit()">
<div class="file-name truncate editable" (click)="edit()">
{{asset.fileName}}
</div>
</div>
<div class="file-tags tags">
<sqx-tag-editor [ngModel]="asset.tags" disabled="true" styleBlank="true" placeholder="+Tag"></sqx-tag-editor>
<sqx-tag-editor [ngModel]="asset.tags"
styleBlank="true"
styleGray="true"
readonly="true">
</sqx-tag-editor>
</div>
<div class="file-info">
{{asset.metadataText}}
@ -112,7 +116,7 @@
<ng-container *ngIf="!isCompact">
<td class="col-info">
{{asset.metadataText}}
<div class="truncate">{{asset.metadataText}}</div>
</td>
<td class="col-user">
<img class="user-picture" title="{{asset.lastModifiedBy | sqxUserNameRef}}" [src]="asset.lastModifiedBy | sqxUserPictureRef" />
@ -152,7 +156,7 @@
<ng-container *ngIf="asset">
<ng-container *sqxModal="editDialog">
<sqx-asset-dialog [allTags]="allTags" [asset]="asset" [accessToken]="authService.user?.accessToken"
<sqx-asset-dialog [allTags]="allTags" [asset]="asset"
(changed)="setAsset($event)"
(complete)="editDialog.hide()">
</sqx-asset-dialog>

43
frontend/app/shared/components/assets/asset.component.scss

@ -101,13 +101,12 @@ $list-height: 2.25rem;
transition: opacity .4s ease;
}
&-name,
&-info {
@include truncate;
}
&-image {
height: $asset-image;
img {
background-image: $asset-background;
}
}
&-name {
@ -200,18 +199,20 @@ $list-height: 2.25rem;
}
.image {
@include absolute(0, auto, 0, 4px);
background: $color-asset-bg;
border: 0;
width: $list-height + 2rem;
}
& {
@include absolute(0, auto, 0, 4px);
background: $color-asset-bg;
border: 0;
width: $list-height + 2rem;
}
.image-padded {
padding: 1rem;
}
&-padded {
padding: 1rem;
}
.image-left {
left: 0;
&-left {
left: 0;
}
}
.icon {
@ -223,6 +224,10 @@ $list-height: 2.25rem;
height: $list-height;
}
&-name, &-info {
width: 50% !important;
}
&-name {
padding-right: .5rem;
}
@ -283,14 +288,6 @@ img {
cursor: pointer;
}
.bg {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAIAAAC1nk4lAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjEuMWMqnEsAAACbSURBVGhD7c6hDQAxAMPA33+m7vYlJh7AoFKOBMbfyfyZRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4E3o9kA7YFFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgQejz7nPYYKl8IqSfgAAAABJRU5ErkJggg==');
}
.bg2 {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjEuMWMqnEsAAAAsSURBVDhPY9iDF/zHC0Y1YwCoKhxgRGqG0jgA1AwcYFQzBoCqwgFGnuY9ewCdSg6FRg4gMAAAAABJRU5ErkJggg==');
}
.tags {
min-height: 26px;
}

2
frontend/app/shared/components/assets/asset.component.ts

@ -11,7 +11,6 @@ import {
AssetDto,
AssetsState,
AssetUploaderState,
AuthService,
DialogModel,
DialogService,
Types,
@ -75,7 +74,6 @@ export class AssetComponent implements OnInit {
public editDialog = new DialogModel();
constructor(
public readonly authService: AuthService,
private readonly assetUploader: AssetUploaderState,
private readonly changeDetector: ChangeDetectorRef,
private readonly dialogs: DialogService

29
frontend/app/shared/components/assets/image-cropper.component.html

@ -0,0 +1,29 @@
<div class="menu">
<button type="button" class="btn" (click)="rotate(-90)" title="Rotate Left">
<i class="icon-rotate_left"></i>
</button>
<button type="button" class="btn" (click)="rotate(90)" title="Rotate Right">
<i class="icon-rotate_right"></i>
</button>
<span class="separator"></span>
<button type="button" class="btn" (click)="flip(false)" title="Flip Vertically">
<i class="icon-flip"></i>
</button>
<button type="button" class="btn rotate 90" (click)="flip(true)" title="Flip Horizontally">
<i class="icon-flip"></i>
</button>
<span class="separator"></span>
<button type="button" class="btn" (click)="reset()" title="Reset">
<i class="icon-close"></i>
</button>
</div>
<div class="editor">
<canvas #editor></canvas>
</div>

46
frontend/app/shared/components/assets/image-cropper.component.scss

@ -0,0 +1,46 @@
:host ::ng-deep {
@import '~cropperjs/dist/cropper';
img {
background-image: $asset-background;
}
}
:host {
background: $color-dark-black;
display: flex;
flex-direction: column;
flex-grow: 1;
height: 100%;
overflow-x: hidden;
overflow-y: hidden;
}
.editor {
flex-grow: 1;
overflow-x: hidden;
overflow-y: hidden;
}
.menu {
flex-shrink: 0;
padding: 1rem;
text-align: center;
text-decoration: none;
.btn {
color: $color-dark-foreground;
}
}
.rotate {
transform: rotate(90deg);
}
.separator {
border-left: 1px solid $color-dark-foreground;
display: inline-block;
height: .75rem;
margin-left: 1rem;
margin-right: 1rem;
}

134
frontend/app/shared/components/assets/image-cropper.component.ts

@ -0,0 +1,134 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, OnDestroy, ViewChild } from '@angular/core';
import Cropper from 'cropperjs';
import { Types } from '@app/framework';
@Component({
selector: 'sqx-image-editor',
styleUrls: ['./image-cropper.component.scss'],
templateUrl: './image-cropper.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ImageCropperComponent implements AfterViewInit, OnDestroy, OnChanges {
private cropper: Cropper | null = null;
private data: Cropper.Data;
@Input()
public imageSource: string;
@ViewChild('editor', { static: false })
public editor: ElementRef<HTMLCanvasElement>;
public ngOnDestroy() {
if (this.cropper) {
this.cropper.destroy();
}
}
public ngOnChanges() {
if (this.cropper) {
this.cropper.replace(this.imageSource);
}
}
public ngAfterViewInit() {
this.cropper = new Cropper(this.editor.nativeElement, {
ready: () => {
if (this.cropper) {
this.data = this.cropper.getData();
}
},
autoCrop: false,
background: false,
minContainerHeight: 0,
minContainerWidth: 0,
movable: false,
zoomOnTouch: false,
zoomOnWheel: false,
viewMode: 0
});
this.cropper.replace(this.imageSource);
}
public rotate(value: number) {
if (this.cropper) {
this.cropper.rotate(-90);
const canvasData = this.cropper.getCanvasData();
const containerData = this.cropper.getContainerData();
const dx = containerData.width / canvasData.naturalWidth;
const dy = containerData.height / canvasData.naturalHeight;
this.cropper.zoomTo(Math.min(dx, dy), {
x: containerData.width / 2,
y: containerData.height / 2
});
}
}
public flip(vertically: boolean) {
if (this.cropper) {
const { rotate, scaleX, scaleY } = this.cropper.getData();
if (rotate === 90 || rotate === 270) {
vertically = !vertically;
}
if (vertically) {
this.cropper.scale(scaleX, -1 * scaleY);
} else {
this.cropper.scale(-1 * scaleX, scaleY);
}
}
}
public zoomIn() {
if (this.cropper) {
this.cropper.zoom(.1);
}
}
public zoomOut() {
if (this.cropper) {
this.cropper.zoom(-.1);
}
}
public reset() {
if (this.cropper) {
this.cropper.reset();
this.cropper.clear();
this.data = this.cropper.getData();
}
}
public toFile(): Promise<Blob | null> {
return new Promise<Blob | null>(resolve => {
if (!this.cropper) {
return resolve(null);
} else {
const data = this.cropper.getData();
if (Types.equals(data, this.data)) {
resolve(null);
} else {
this.data = data;
this.cropper.getCroppedCanvas().toBlob(blob => {
resolve(blob);
});
}
}
});
}
}

1
frontend/app/shared/components/assets/image-editor.component.html

@ -1 +0,0 @@
<div #editor></div>

29
frontend/app/shared/components/assets/image-editor.component.scss

@ -1,29 +0,0 @@
:host {
height: 100%;
}
:host /deep/ {
.tui-image-editor-header {
display: none;
}
* {
box-sizing: content-box;
}
.tie-btn-delete {
display: none !important;
}
.tie-btn-delete-all {
display: none !important;
& + li {
display: none !important;
}
}
svg {
vertical-align: baseline;
}
}

199
frontend/app/shared/components/assets/image-editor.component.ts

@ -1,199 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, ViewChild } from '@angular/core';
import { ResourceLoaderService } from '@app/shared/internal';
declare var tui: any;
const blackTheme = {
'common.bi.image': 'https://uicdn.toast.com/toastui/img/tui-image-editor-bi.png',
'common.bisize.width': '251px',
'common.bisize.height': '21px',
'common.backgroundImage': 'none',
'common.backgroundColor': '#000',
'common.border': '0px',
// header
'header.backgroundImage': 'none',
'header.backgroundColor': 'transparent',
'header.border': '0px',
// load button
'loadButton.backgroundColor': '#fff',
'loadButton.border': '1px solid #ddd',
'loadButton.color': '#222',
'loadButton.fontFamily': '\'Noto Sans\', sans-serif',
'loadButton.fontSize': '12px',
// download button
'downloadButton.backgroundColor': '#fdba3b',
'downloadButton.border': '1px solid #fdba3b',
'downloadButton.color': '#fff',
'downloadButton.fontFamily': '\'Noto Sans\', sans-serif',
'downloadButton.fontSize': '12px',
// main icons
'menu.normalIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-d.svg',
'menu.normalIcon.name': 'icon-d',
'menu.activeIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-b.svg',
'menu.activeIcon.name': 'icon-b',
'menu.disabledIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-a.svg',
'menu.disabledIcon.name': 'icon-a',
'menu.hoverIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-c.svg',
'menu.hoverIcon.name': 'icon-c',
'menu.iconSize.width': '24px',
'menu.iconSize.height': '24px',
// submenu primary color
'submenu.backgroundColor': '#000',
'submenu.partition.color': '#3c3c3c',
// submenu icons
'submenu.normalIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-d.svg',
'submenu.normalIcon.name': 'icon-d',
'submenu.activeIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-c.svg',
'submenu.activeIcon.name': 'icon-c',
'submenu.iconSize.width': '32px',
'submenu.iconSize.height': '32px',
// submenu labels
'submenu.normalLabel.color': '#8a8a8a',
'submenu.normalLabel.fontWeight': 'normal',
'submenu.activeLabel.color': '#fff',
'submenu.activeLabel.fontWeight': 'normal',
// checkbox style
'checkbox.border': '0px',
'checkbox.backgroundColor': '#fff',
// range style
'range.pointer.color': '#fff',
'range.bar.color': '#666',
'range.subbar.color': '#d1d1d1',
'range.disabledPointer.color': '#414141',
'range.disabledBar.color': '#282828',
'range.disabledSubbar.color': '#414141',
'range.value.color': '#fff',
'range.value.fontWeight': 'normal',
'range.value.fontSize': '11px',
'range.value.border': '1px solid #353535',
'range.value.backgroundColor': '#151515',
'range.title.color': '#fff',
'range.title.fontWeight': 'normal',
// colorpicker style
'colorpicker.button.border': '1px solid #1e1e1e',
'colorpicker.title.color': '#fff'
};
@Component({
selector: 'sqx-image-editor',
styleUrls: ['./image-editor.component.scss'],
templateUrl: './image-editor.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ImageEditorComponent implements AfterViewInit, OnChanges {
private imageEditor: any;
private isChanged = false;
private isChangedBefore = false;
@Input()
public accessToken: string;
@Input()
public imageUrl: string;
@ViewChild('editor', { static: false })
public editor: ElementRef;
constructor(
private readonly resourceLoader: ResourceLoaderService
) {
}
public ngOnChanges() {
if (this.imageEditor && this.imageUrl) {
this.imageEditor.loadImageFromURL(this.imageUrl);
}
}
public toFile(): Blob | null {
if (!this.isChanged) {
return null;
}
this.isChanged = false;
const dataURI = this.imageEditor.toDataURL();
const byteString = atob(dataURI.split(',')[1]);
const byteBuffer = new ArrayBuffer(byteString.length);
const type = dataURI.split(',')[0].split(':')[1].split(';')[0];
const array = new Uint8Array(byteBuffer);
for (let i = 0; i < byteString.length; i++) {
array[i] = byteString.charCodeAt(i);
}
return new Blob([array], { type });
}
public ngAfterViewInit() {
const styles = [
'https://uicdn.toast.com/tui-color-picker/latest/tui-color-picker.css',
'https://uicdn.toast.com/tui-image-editor/latest/tui-image-editor.css'
];
const scripts = [
'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.3.2/fabric.js',
'https://uicdn.toast.com/tui.code-snippet/latest/tui-code-snippet.min.js',
'https://uicdn.toast.com/tui-color-picker/latest/tui-color-picker.js',
'https://uicdn.toast.com/tui-image-editor/latest/tui-image-editor.js'
];
let path = this.imageUrl;
if (this.accessToken) {
path += `&access_token=${this.accessToken}`;
}
styles.forEach(style => this.resourceLoader.loadStyle(style));
Promise.all(scripts.map(script => this.resourceLoader.loadScript(script))).then(() => {
this.imageEditor = new tui.ImageEditor(this.editor.nativeElement, {
includeUI: {
loadImage: {
path, name: 'image'
},
menu: [
'crop',
'flip',
'mask',
'filter'
],
theme: blackTheme
},
cssMaxWidth: 700,
cssMaxHeight: 500
});
this.imageEditor.on('undoStackChanged', () => {
if (this.isChangedBefore) {
this.isChanged = true;
} else {
this.isChangedBefore = true;
}
});
});
}
}

29
frontend/app/shared/components/assets/image-focus-point.component.html

@ -0,0 +1,29 @@
<div class="row">
<div class="col-5">
<Label>Select position of focus point</Label>
<div class="image">
<div class="image-container absolute align-items-center">
<div>
<img #image [src]="imageSource" />
</div>
</div>
</div>
</div>
<div class="col-7">
<Label>Preview for different sizes</Label>
<div class="preview-wide">
<img #previewWide [src]="imageSource" />
</div>
<div class="preview-line2">
<div class="preview-small absolute">
<img #previewSmall [src]="imageSource" />
</div>
<div class="preview-normal absolute">
<img #previewNormal [src]="imageSource" />
</div>
</div>
</div>
</div>

41
frontend/app/shared/components/assets/image-focus-point.component.scss

@ -0,0 +1,41 @@
.image {
background: $color-dark-black;
padding: 0;
padding-top: 100%;
position: relative;
&-container {
@include absolute(0, 0, 0, 0);
display: flex;
}
}
.preview {
&-wide {
padding-top: 20%;
}
&-line2 {
margin-top: 1rem;
max-height: 20rem;
min-height: 20rem;
position: relative;
}
&-normal {
@include absolute(0, 9rem, 0, 0);
}
&-small {
@include absolute(0, 0, 0, null);
width: 8rem;
}
}
.absolute {
position: absolute !important;
}
img {
background-image: $asset-background;
}

108
frontend/app/shared/components/assets/image-focus-point.component.ts

@ -0,0 +1,108 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
// tslint:disable: readonly-array
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, OnDestroy, ViewChild } from '@angular/core';
import { FocusedImage, FocusPicker } from 'image-focus';
import { Types } from '@app/framework';
import { AnnotateAssetDto, AssetDto } from '@app/shared/services/assets.service';
@Component({
selector: 'sqx-image-focus-point',
styleUrls: ['./image-focus-point.component.scss'],
templateUrl: './image-focus-point.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ImageFocusPointComponent implements AfterViewInit, OnDestroy, OnChanges {
private readonly previewImages: FocusedImage[] = [];
private focusPicker: FocusPicker | null = null;
private x = 0;
private y = 0;
@Input()
public imageSource: string;
@Input()
public focusPoint: any;
@ViewChild('image', { static: false })
public image: ElementRef<HTMLImageElement>;
@ViewChild('previewWide', { static: false })
public previewWide: ElementRef<HTMLImageElement>;
@ViewChild('previewSmall', { static: false })
public previewSmall: ElementRef<HTMLImageElement>;
@ViewChild('previewNormal', { static: false })
public previewNormal: ElementRef<HTMLImageElement>;
public ngOnDestroy() {
if (this.focusPicker) {
this.focusPicker.stopListening();
}
}
public ngOnChanges() {
const { x, y } = getFocusPoint(this.focusPoint);
this.x = x;
this.y = y;
}
public ngAfterViewInit() {
const focus = { x: this.x, y: this.y };
const properties = { focus, debounceTime: 50 };
this.previewImages.push(new FocusedImage(this.previewWide.nativeElement, properties));
this.previewImages.push(new FocusedImage(this.previewSmall.nativeElement, properties));
this.previewImages.push(new FocusedImage(this.previewNormal.nativeElement, properties));
this.focusPicker = new FocusPicker(this.image.nativeElement, {
focus,
onChange: newFocus => {
this.x = newFocus.x;
this.y = newFocus.y;
for (let preview of this.previewImages) {
preview.setFocus(newFocus);
}
}
});
}
public submit(asset: AssetDto): AnnotateAssetDto | null {
const previous = getFocusPoint(asset.metadata);
if (previous.x === this.x && previous.y === this.y) {
return null;
}
const metadata = { ...asset.metadata, focusX: this.x, focusY: this.y };
return { metadata };
}
}
function getFocusPoint(value: any): { x: number, y: number } {
let x = 0;
let y = 0;
if (value && Types.isNumber(value.focusX)) {
x = value.focusX;
}
if (value && Types.isNumber(value.focusY)) {
y = value.focusY;
}
return { x, y };
}

6
frontend/app/shared/components/assets/pipes.ts

@ -10,6 +10,7 @@ import { Pipe, PipeTransform } from '@angular/core';
import {
ApiUrlConfig,
AssetDto,
AuthService,
MathHelper
} from '@app/shared/internal';
@ -34,12 +35,13 @@ export class AssetUrlPipe implements PipeTransform {
})
export class AssetPreviewUrlPipe implements PipeTransform {
constructor(
private readonly apiUrl: ApiUrlConfig
private readonly apiUrl: ApiUrlConfig,
private readonly authService: AuthService
) {
}
public transform(asset: AssetDto): string {
return asset.fullUrl(this.apiUrl);
return asset.fullUrl(this.apiUrl, this.authService);
}
}

5
frontend/app/shared/declarations.ts

@ -11,14 +11,15 @@ export * from './components/schema-category.component';
export * from './components/table-header.component';
export * from './components/assets/asset-dialog.component';
export * from './components/assets/asset-folder-form.component';
export * from './components/assets/asset-folder-dialog.component';
export * from './components/assets/asset-folder.component';
export * from './components/assets/asset-path.component';
export * from './components/assets/asset-uploader.component';
export * from './components/assets/asset.component';
export * from './components/assets/assets-list.component';
export * from './components/assets/assets-selector.component';
export * from './components/assets/image-editor.component';
export * from './components/assets/image-cropper.component';
export * from './components/assets/image-focus-point.component';
export * from './components/assets/pipes';
export * from './components/comments/comment.component';

12
frontend/app/shared/module.ts

@ -22,7 +22,7 @@ import {
AssetComponent,
AssetDialogComponent,
AssetFolderComponent,
AssetFolderFormComponent,
AssetFolderDialogComponent,
AssetPathComponent,
AssetPreviewUrlPipe,
AssetsDialogState,
@ -61,7 +61,8 @@ import {
HistoryListComponent,
HistoryMessagePipe,
HistoryService,
ImageEditorComponent,
ImageCropperComponent,
ImageFocusPointComponent,
LanguageSelectorComponent,
LanguagesService,
LanguagesState,
@ -128,7 +129,7 @@ import {
AssetComponent,
AssetDialogComponent,
AssetFolderComponent,
AssetFolderFormComponent,
AssetFolderDialogComponent,
AssetPathComponent,
AssetPreviewUrlPipe,
AssetsListComponent,
@ -147,7 +148,8 @@ import {
HistoryComponent,
HistoryListComponent,
HistoryMessagePipe,
ImageEditorComponent,
ImageCropperComponent,
ImageFocusPointComponent,
LanguageSelectorComponent,
MarkdownEditorComponent,
QueryComponent,
@ -173,7 +175,7 @@ import {
AssetComponent,
AssetDialogComponent,
AssetFolderComponent,
AssetFolderFormComponent,
AssetFolderDialogComponent,
AssetPathComponent,
AssetPreviewUrlPipe,
AssetsListComponent,

11
frontend/app/shared/services/assets.service.ts

@ -30,6 +30,7 @@ import {
const SVG_PREVIEW_LIMIT = 10 * 1024;
import { encodeQuery, Query } from './../state/query';
import { AuthService } from './auth.service';
export class AssetsDto extends ResultSet<AssetDto> {
public get canCreate() {
@ -89,8 +90,14 @@ export class AssetDto {
this._meta = meta;
}
public fullUrl(apiUrl: ApiUrlConfig) {
return apiUrl.buildUrl(this.contentUrl);
public fullUrl(apiUrl: ApiUrlConfig, authService?: AuthService) {
let url = apiUrl.buildUrl(this.contentUrl);
if (this.isProtected && authService && authService.user) {
url += `&access_token=${authService.user.accessToken}`;
}
return url;
}
}

2
frontend/app/theme/_bootstrap-vars.scss

@ -44,7 +44,7 @@ $paragraph-margin-bottom: .5rem;
$modal-backdrop-opacity: .35;
$modal-footer-border-width: 1px;
$modal-header-border-width: 0;
$modal-header-padding: 1.25rem 1.75rem;
$modal-header-padding: 1rem 1.75rem;
$modal-inner-padding: 1.5rem 1.75rem;
$modal-md: 560px;
$modal-title-line-height: 1.8rem;

3
frontend/app/theme/_bootstrap.scss

@ -661,9 +661,10 @@ $icon-size: 4.5rem;
h4 {
font-size: 1rem;
font-weight: normal;
line-height: 2.25rem;
}
.close {
.btn-close {
& {
color: $color-modal-header-foreground;
}

11
frontend/app/theme/_lists.scss

@ -141,20 +141,19 @@
}
// Footer that typically contains an add-item-form.
&-header,
&-footer {
background: $color-table-footer;
border: 1px solid $color-input;
border-bottom-width: 2px;
margin-top: .75rem;
padding: .75rem 1.25rem;
}
&-header {
margin-bottom: .8rem;
}
&-footer {
margin-top: .8rem;
background: $color-table-footer;
border-bottom: 1px solid $color-border-darker;
margin-bottom: .75rem;
padding: .75rem 1.25rem;
}
// Edit or expand button.

4
frontend/app/theme/_vars.scss

@ -2,6 +2,7 @@ $color-background: #eef1f4;
$color-border: #e4e7e9;
$color-border-dark: #b3bbbf;
$color-border-darker: darken($color-border, 3%);
$color-title: #000;
$color-text: #373a3c;
@ -110,4 +111,5 @@ $asset-folder-height: 4rem;
$asset-height: 19rem;
$asset-header: 12rem;
$asset-image: 12rem;
$asset-footer: 7rem;
$asset-footer: 7rem;
$asset-background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAIAAAC1nk4lAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjEuMWMqnEsAAACbSURBVGhD7c6hDQAxAMPA33+m7vYlJh7AoFKOBMbfyfyZRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4E3o9kA7YFFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgQejz7nPYYKl8IqSfgAAAABJRU5ErkJggg==');

4
frontend/app/theme/icomoon/demo-files/demo.css

@ -147,10 +147,10 @@ p {
font-size: 16px;
}
.fs1 {
font-size: 28px;
font-size: 24px;
}
.fs2 {
font-size: 24px;
font-size: 28px;
}
.fs3 {
font-size: 24px;

490
frontend/app/theme/icomoon/demo.html

@ -9,144 +9,18 @@
<link rel="stylesheet" href="style.css"></head>
<body>
<div class="bgc1 clearfix">
<h1 class="mhmm mvm"><span class="fgc1">Font Name:</span> icomoon <small class="fgc1">(Glyphs:&nbsp;130)</small></h1>
<h1 class="mhmm mvm"><span class="fgc1">Font Name:</span> icomoon <small class="fgc1">(Glyphs:&nbsp;135)</small></h1>
</div>
<div class="clearfix mhl ptl">
<h1 class="mvm mtn fgc1">Grid Size: 14</h1>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-angle-double-right"></span>
<span class="mls"> icon-angle-double-right</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e97d" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97d;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-angle-double-left"></span>
<span class="mls"> icon-angle-double-left</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e97e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97e;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-filter-filled"></span>
<span class="mls"> icon-filter-filled</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e978" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe978;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-clone"></span>
<span class="mls"> icon-clone</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e96a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe96a;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-control-Tags"></span>
<span class="mls"> icon-control-Tags</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e963" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe963;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-control-Checkboxes"></span>
<span class="mls"> icon-control-Checkboxes</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e962" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe962;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-control-Html"></span>
<span class="mls"> icon-control-Html</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e960" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe960;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-single-content"></span>
<span class="mls"> icon-single-content</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e958" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe958;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-multiple-content"></span>
<span class="mls"> icon-multiple-content</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e957" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe957;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<h1 class="mvm mtn fgc1">Grid Size: 24</h1>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-type-Array"></span>
<span class="mls"> icon-type-Array</span>
<span class="icon-zoom_out"></span>
<span class="mls"> icon-zoom_out</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e956" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe956;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e982" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe982;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -155,12 +29,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-exclamation"></span>
<span class="mls"> icon-exclamation</span>
<span class="icon-zoom_in"></span>
<span class="mls"> icon-zoom_in</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e955" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe955;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e983" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe983;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -169,12 +43,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-orleans"></span>
<span class="mls"> icon-orleans</span>
<span class="icon-flip"></span>
<span class="mls"> icon-flip</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e94b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe94b;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e97f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97f;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -183,12 +57,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-document-lock"></span>
<span class="mls"> icon-document-lock</span>
<span class="icon-rotate_right"></span>
<span class="mls"> icon-rotate_right</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e949" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe949;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e980" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe980;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -197,12 +71,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-document-unpublish"></span>
<span class="mls"> icon-document-unpublish</span>
<span class="icon-rotate_left"></span>
<span class="mls"> icon-rotate_left</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e93f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe93f;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e981" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe981;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -211,12 +85,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-angle-down"></span>
<span class="mls"> icon-angle-down</span>
<span class="icon-create_new_folder"></span>
<span class="mls"> icon-create_new_folder</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e900" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe900;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e97b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97b;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -225,12 +99,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-angle-left"></span>
<span class="mls"> icon-angle-left</span>
<span class="icon-folder"></span>
<span class="mls"> icon-folder</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e901" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe901;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e97c" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97c;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -239,12 +113,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-angle-right"></span>
<span class="mls"> icon-angle-right</span>
<span class="icon-help2"></span>
<span class="mls"> icon-help2</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e931" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe931;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e97a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97a;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -253,12 +127,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-angle-up"></span>
<span class="mls"> icon-angle-up</span>
<span class="icon-trigger-Manual"></span>
<span class="mls"> icon-trigger-Manual</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e903" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe903;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e979" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe979;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -267,12 +141,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-api"></span>
<span class="mls"> icon-api</span>
<span class="icon-play-line"></span>
<span class="mls"> icon-play-line</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e945" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe945;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e979" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe979;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -281,12 +155,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-assets"></span>
<span class="mls"> icon-assets</span>
<span class="icon-corner-down-right"></span>
<span class="mls"> icon-corner-down-right</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e948" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe948;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e977" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe977;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -295,12 +169,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-bug"></span>
<span class="mls"> icon-bug</span>
<span class="icon-info-outline"></span>
<span class="mls"> icon-info-outline</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e93d" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe93d;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e974" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe974;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -309,12 +183,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-caret-down"></span>
<span class="mls"> icon-caret-down</span>
<span class="icon-upload-2"></span>
<span class="mls"> icon-upload-2</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e92c" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe92c;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e972" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe972;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -323,12 +197,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-caret-left"></span>
<span class="mls"> icon-caret-left</span>
<span class="icon-translate"></span>
<span class="mls"> icon-translate</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e92a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe92a;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e96f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe96f;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -337,12 +211,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-caret-right"></span>
<span class="mls"> icon-caret-right</span>
<span class="icon-arrow_back"></span>
<span class="mls"> icon-arrow_back</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e929" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe929;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e96e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe96e;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -351,12 +225,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-caret-up"></span>
<span class="mls"> icon-caret-up</span>
<span class="icon-external-link"></span>
<span class="mls"> icon-external-link</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e92b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe92b;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e96d" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe96d;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -365,12 +239,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-contents"></span>
<span class="mls"> icon-contents</span>
<span class="icon-minus-square"></span>
<span class="mls"> icon-minus-square</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e946" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe946;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e969" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe969;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -379,12 +253,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-trigger-ContentChanged"></span>
<span class="mls"> icon-trigger-ContentChanged</span>
<span class="icon-plus-square"></span>
<span class="mls"> icon-plus-square</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e946" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe946;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e968" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe968;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -393,12 +267,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-control-Date"></span>
<span class="mls"> icon-control-Date</span>
<span class="icon-drag2"></span>
<span class="mls"> icon-drag2</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e936" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe936;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e961" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe961;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -407,12 +281,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-control-DateTime"></span>
<span class="mls"> icon-control-DateTime</span>
<span class="icon-comments"></span>
<span class="mls"> icon-comments</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e937" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe937;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e95f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe95f;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -421,12 +295,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-control-Markdown"></span>
<span class="mls"> icon-control-Markdown</span>
<span class="icon-backup"></span>
<span class="mls"> icon-backup</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e938" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe938;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e95b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe95b;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -435,12 +309,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-grid"></span>
<span class="mls"> icon-grid</span>
<span class="icon-support"></span>
<span class="mls"> icon-support</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="f00a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xf00a;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e95a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe95a;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -449,12 +323,12 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-list1"></span>
<span class="mls"> icon-list1</span>
<span class="icon-control-RichText"></span>
<span class="mls"> icon-control-RichText</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="f0c9" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xf0c9;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e939" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe939;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -463,43 +337,43 @@
</div>
<div class="glyph fs1">
<div class="clearfix bshadow0 pbs">
<span class="icon-user-o"></span>
<span class="mls"> icon-user-o</span>
<span class="icon-download"></span>
<span class="mls"> icon-download</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e932" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe932;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e93e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe93e;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
<div class="glyph fs1">
</div>
<div class="clearfix mhl ptl">
<h1 class="mvm mtn fgc1">Grid Size: 14</h1>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-rules"></span>
<span class="mls"> icon-rules</span>
<span class="icon-angle-double-right"></span>
<span class="mls"> icon-angle-double-right</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e947" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe947;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e97d" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97d;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
<input type="text" readonly value="" class="liga unitRight" />
</div>
</div>
</div>
<div class="clearfix mhl ptl">
<h1 class="mvm mtn fgc1">Grid Size: 24</h1>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-create_new_folder"></span>
<span class="mls"> icon-create_new_folder</span>
<span class="icon-angle-double-left"></span>
<span class="mls"> icon-angle-double-left</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e97b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97b;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e97e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97e;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -508,12 +382,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-folder"></span>
<span class="mls"> icon-folder</span>
<span class="icon-filter-filled"></span>
<span class="mls"> icon-filter-filled</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e97c" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97c;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e978" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe978;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -522,12 +396,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-help2"></span>
<span class="mls"> icon-help2</span>
<span class="icon-clone"></span>
<span class="mls"> icon-clone</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e97a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe97a;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e96a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe96a;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -536,12 +410,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-trigger-Manual"></span>
<span class="mls"> icon-trigger-Manual</span>
<span class="icon-control-Tags"></span>
<span class="mls"> icon-control-Tags</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e979" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe979;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e963" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe963;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -550,12 +424,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-play-line"></span>
<span class="mls"> icon-play-line</span>
<span class="icon-control-Checkboxes"></span>
<span class="mls"> icon-control-Checkboxes</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e979" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe979;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e962" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe962;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -564,12 +438,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-corner-down-right"></span>
<span class="mls"> icon-corner-down-right</span>
<span class="icon-control-Html"></span>
<span class="mls"> icon-control-Html</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e977" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe977;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e960" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe960;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -578,12 +452,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-info-outline"></span>
<span class="mls"> icon-info-outline</span>
<span class="icon-single-content"></span>
<span class="mls"> icon-single-content</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e974" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe974;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e958" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe958;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -592,12 +466,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-upload-2"></span>
<span class="mls"> icon-upload-2</span>
<span class="icon-multiple-content"></span>
<span class="mls"> icon-multiple-content</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e972" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe972;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e957" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe957;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -606,12 +480,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-translate"></span>
<span class="mls"> icon-translate</span>
<span class="icon-type-Array"></span>
<span class="mls"> icon-type-Array</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e96f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe96f;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e956" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe956;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -620,12 +494,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-arrow_back"></span>
<span class="mls"> icon-arrow_back</span>
<span class="icon-exclamation"></span>
<span class="mls"> icon-exclamation</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e96e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe96e;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e955" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe955;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -634,12 +508,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-external-link"></span>
<span class="mls"> icon-external-link</span>
<span class="icon-orleans"></span>
<span class="mls"> icon-orleans</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e96d" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe96d;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e94b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe94b;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -648,12 +522,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-minus-square"></span>
<span class="mls"> icon-minus-square</span>
<span class="icon-document-lock"></span>
<span class="mls"> icon-document-lock</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e969" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe969;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e949" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe949;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -662,12 +536,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-plus-square"></span>
<span class="mls"> icon-plus-square</span>
<span class="icon-document-unpublish"></span>
<span class="mls"> icon-document-unpublish</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e968" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe968;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e93f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe93f;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -676,12 +550,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-drag2"></span>
<span class="mls"> icon-drag2</span>
<span class="icon-angle-down"></span>
<span class="mls"> icon-angle-down</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e961" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe961;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e900" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe900;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -690,12 +564,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-comments"></span>
<span class="mls"> icon-comments</span>
<span class="icon-angle-left"></span>
<span class="mls"> icon-angle-left</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e95f" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe95f;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e901" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe901;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -704,12 +578,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-backup"></span>
<span class="mls"> icon-backup</span>
<span class="icon-angle-right"></span>
<span class="mls"> icon-angle-right</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e95b" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe95b;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e931" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe931;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -718,12 +592,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-support"></span>
<span class="mls"> icon-support</span>
<span class="icon-angle-up"></span>
<span class="mls"> icon-angle-up</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e95a" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe95a;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e903" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe903;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -732,12 +606,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-control-RichText"></span>
<span class="mls"> icon-control-RichText</span>
<span class="icon-api"></span>
<span class="mls"> icon-api</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e939" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe939;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e945" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe945;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>
@ -746,12 +620,12 @@
</div>
<div class="glyph fs2">
<div class="clearfix bshadow0 pbs">
<span class="icon-download"></span>
<span class="mls"> icon-download</span>
<span class="icon-assets"></span>
<span class="mls"> icon-assets</span>
</div>
<fieldset class="fs0 size1of1 clearfix hidden-false">
<input type="text" readonly value="e93e" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe93e;" class="unitRight size1of2 talign-right" />
<input type="text" readonly value="e948" class="unit size1of2" />
<input type="text" maxlength="1" readonly value="&#xe948;" class="unitRight size1of2 talign-right" />
</fieldset>
<div class="fs0 bshadow0 clearfix hidden-true">
<span class="unit pvs fgc1">liga: </span>

BIN
frontend/app/theme/icomoon/fonts/icomoon.eot

Binary file not shown.

5
frontend/app/theme/icomoon/fonts/icomoon.svg

@ -134,6 +134,11 @@
<glyph unicode="&#xe97c;" glyph-name="folder" d="M426 768.667l86-86h342q34 0 59-26t25-60v-426q0-34-25-60t-59-26h-684q-34 0-59 26t-25 60v512q0 34 25 60t59 26h256z" />
<glyph unicode="&#xe97d;" glyph-name="angle-double-right" horiz-adv-x="567" d="M340 402.286c0-4.571-2.286-9.714-5.714-13.143l-266.286-266.286c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-28.571 28.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l224.571 224.571-224.571 224.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l28.571 28.571c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l266.286-266.286c3.429-3.429 5.714-8.571 5.714-13.143zM559.429 402.286c0-4.571-2.286-9.714-5.714-13.143l-266.286-266.286c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-28.571 28.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l224.571 224.571-224.571 224.571c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l28.571 28.571c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l266.286-266.286c3.429-3.429 5.714-8.571 5.714-13.143z" />
<glyph unicode="&#xe97e;" glyph-name="angle-double-left" horiz-adv-x="603" d="M358.286 164.571c0-4.571-2.286-9.714-5.714-13.143l-28.571-28.571c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-266.286 266.286c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l266.286 266.286c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l28.571-28.571c3.429-3.429 5.714-8.571 5.714-13.143s-2.286-9.714-5.714-13.143l-224.571-224.571 224.571-224.571c3.429-3.429 5.714-8.571 5.714-13.143zM577.714 164.571c0-4.571-2.286-9.714-5.714-13.143l-28.571-28.571c-3.429-3.429-8.571-5.714-13.143-5.714s-9.714 2.286-13.143 5.714l-266.286 266.286c-3.429 3.429-5.714 8.571-5.714 13.143s2.286 9.714 5.714 13.143l266.286 266.286c3.429 3.429 8.571 5.714 13.143 5.714s9.714-2.286 13.143-5.714l28.571-28.571c3.429-3.429 5.714-8.571 5.714-13.143s-2.286-9.714-5.714-13.143l-224.571-224.571 224.571-224.571c3.429-3.429 5.714-8.571 5.714-13.143z" />
<glyph unicode="&#xe97f;" glyph-name="flip" d="M810 42.667v86h86q0-34-26-60t-60-26zM810 384.667v84h86v-84h-86zM640 724.667v86h86v-86h-86zM810 212.667v86h86v-86h-86zM470-43.333v940h84v-940h-84zM810 810.667q34 0 60-26t26-60h-86v86zM128 724.667q0 34 26 60t60 26h170v-86h-170v-596h170v-86h-170q-34 0-60 26t-26 60v596zM810 554.667v86h86v-86h-86zM640 42.667v86h86v-86h-86z" />
<glyph unicode="&#xe980;" glyph-name="rotate_right" d="M720 278.667q34 46 44 106h86q-12-92-68-166zM554 174.667q60 10 106 44l62-62q-72-56-168-68v86zM850 468.667h-86q-10 60-44 106l62 60q58-72 68-166zM664 702.667l-194-190v166q-92-16-153-87t-61-165 61-165 153-87v-86q-126 16-213 112t-87 226 87 226 213 112v132z" />
<glyph unicode="&#xe981;" glyph-name="rotate_left" d="M554 764.667q126-16 213-112t87-226-87-226-213-112v86q92 16 153 87t61 165-61 165-153 87v-166l-194 190 194 194v-132zM302 156.667l62 62q46-34 106-44v-86q-96 12-168 68zM260 384.667q10-58 42-106l-60-60q-56 74-68 166h86zM304 574.667q-36-52-44-106h-86q12 90 70 166z" />
<glyph unicode="&#xe982;" glyph-name="zoom_out" d="M298 554.667h214v-42h-214v42zM406 340.667q80 0 136 56t56 136-56 136-136 56-136-56-56-136 56-136 136-56zM662 340.667l212-212-64-64-212 212v34l-12 12q-76-66-180-66-116 0-197 80t-81 196 81 197 197 81 196-81 80-197q0-42-20-95t-46-85l12-12h34z" />
<glyph unicode="&#xe983;" glyph-name="zoom_in" d="M512 512.667h-86v-86h-42v86h-86v42h86v86h42v-86h86v-42zM406 340.667q80 0 136 56t56 136-56 136-136 56-136-56-56-136 56-136 136-56zM662 340.667l212-212-64-64-212 212v34l-12 12q-76-66-180-66-116 0-197 80t-81 196 81 197 197 81 196-81 80-197q0-42-20-95t-46-85l12-12h34z" />
<glyph unicode="&#xe9ca;" glyph-name="earth" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512-0.002c-62.958 0-122.872 13.012-177.23 36.452l233.148 262.29c5.206 5.858 8.082 13.422 8.082 21.26v96c0 17.674-14.326 32-32 32-112.99 0-232.204 117.462-233.374 118.626-6 6.002-14.14 9.374-22.626 9.374h-128c-17.672 0-32-14.328-32-32v-192c0-12.122 6.848-23.202 17.69-28.622l110.31-55.156v-187.886c-116.052 80.956-192 215.432-192 367.664 0 68.714 15.49 133.806 43.138 192h116.862c8.488 0 16.626 3.372 22.628 9.372l128 128c6 6.002 9.372 14.14 9.372 22.628v77.412c40.562 12.074 83.518 18.588 128 18.588 70.406 0 137.004-16.26 196.282-45.2-4.144-3.502-8.176-7.164-12.046-11.036-36.266-36.264-56.236-84.478-56.236-135.764s19.97-99.5 56.236-135.764c36.434-36.432 85.218-56.264 135.634-56.26 3.166 0 6.342 0.080 9.518 0.236 13.814-51.802 38.752-186.656-8.404-372.334-0.444-1.744-0.696-3.488-0.842-5.224-81.324-83.080-194.7-134.656-320.142-134.656z" />
<glyph unicode="&#xf00a;" glyph-name="grid" d="M292.571 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM292.571 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 237.714v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM658.286 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 530.286v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857zM1024 822.857v-109.714c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v109.714c0 30.286 24.571 54.857 54.857 54.857h182.857c30.286 0 54.857-24.571 54.857-54.857z" />
<glyph unicode="&#xf0c9;" glyph-name="list1" horiz-adv-x="878" d="M877.714 182.857v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 475.428v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571zM877.714 768v-73.143c0-20-16.571-36.571-36.571-36.571h-804.571c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h804.571c20 0 36.571-16.571 36.571-36.571z" />

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 100 KiB

BIN
frontend/app/theme/icomoon/fonts/icomoon.ttf

Binary file not shown.

BIN
frontend/app/theme/icomoon/fonts/icomoon.woff

Binary file not shown.

2
frontend/app/theme/icomoon/selection.json

File diff suppressed because one or more lines are too long

177
frontend/app/theme/icomoon/style.css

@ -1,10 +1,10 @@
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?4bb69f');
src: url('fonts/icomoon.eot?4bb69f#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?4bb69f') format('truetype'),
url('fonts/icomoon.woff?4bb69f') format('woff'),
url('fonts/icomoon.svg?4bb69f#icomoon') format('svg');
src: url('fonts/icomoon.eot?ipz2o6');
src: url('fonts/icomoon.eot?ipz2o6#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?ipz2o6') format('truetype'),
url('fonts/icomoon.woff?ipz2o6') format('woff'),
url('fonts/icomoon.svg?ipz2o6#icomoon') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
@ -25,107 +25,20 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-angle-double-right:before {
content: "\e97d";
}
.icon-angle-double-left:before {
content: "\e97e";
}
.icon-filter-filled:before {
content: "\e978";
}
.icon-clone:before {
content: "\e96a";
}
.icon-control-Tags:before {
content: "\e963";
}
.icon-control-Checkboxes:before {
content: "\e962";
}
.icon-control-Html:before {
content: "\e960";
.icon-zoom_out:before {
content: "\e982";
}
.icon-single-content:before {
content: "\e958";
}
.icon-multiple-content:before {
content: "\e957";
}
.icon-type-Array:before {
content: "\e956";
}
.icon-exclamation:before {
content: "\e955";
.icon-zoom_in:before {
content: "\e983";
}
.icon-orleans:before {
content: "\e94b";
}
.icon-document-lock:before {
content: "\e949";
.icon-flip:before {
content: "\e97f";
}
.icon-document-unpublish:before {
content: "\e93f";
.icon-rotate_right:before {
content: "\e980";
}
.icon-angle-down:before {
content: "\e900";
}
.icon-angle-left:before {
content: "\e901";
}
.icon-angle-right:before {
content: "\e931";
}
.icon-angle-up:before {
content: "\e903";
}
.icon-api:before {
content: "\e945";
}
.icon-assets:before {
content: "\e948";
}
.icon-bug:before {
content: "\e93d";
}
.icon-caret-down:before {
content: "\e92c";
}
.icon-caret-left:before {
content: "\e92a";
}
.icon-caret-right:before {
content: "\e929";
}
.icon-caret-up:before {
content: "\e92b";
}
.icon-contents:before {
content: "\e946";
}
.icon-trigger-ContentChanged:before {
content: "\e946";
}
.icon-control-Date:before {
content: "\e936";
}
.icon-control-DateTime:before {
content: "\e937";
}
.icon-control-Markdown:before {
content: "\e938";
}
.icon-grid:before {
content: "\f00a";
}
.icon-list1:before {
content: "\f0c9";
}
.icon-user-o:before {
content: "\e932";
}
.icon-rules:before {
content: "\e947";
.icon-rotate_left:before {
content: "\e981";
}
.icon-create_new_folder:before {
content: "\e97b";
@ -184,6 +97,66 @@
.icon-download:before {
content: "\e93e";
}
.icon-angle-double-right:before {
content: "\e97d";
}
.icon-angle-double-left:before {
content: "\e97e";
}
.icon-filter-filled:before {
content: "\e978";
}
.icon-clone:before {
content: "\e96a";
}
.icon-control-Tags:before {
content: "\e963";
}
.icon-control-Checkboxes:before {
content: "\e962";
}
.icon-control-Html:before {
content: "\e960";
}
.icon-single-content:before {
content: "\e958";
}
.icon-multiple-content:before {
content: "\e957";
}
.icon-type-Array:before {
content: "\e956";
}
.icon-exclamation:before {
content: "\e955";
}
.icon-orleans:before {
content: "\e94b";
}
.icon-document-lock:before {
content: "\e949";
}
.icon-document-unpublish:before {
content: "\e93f";
}
.icon-angle-down:before {
content: "\e900";
}
.icon-angle-left:before {
content: "\e901";
}
.icon-angle-right:before {
content: "\e931";
}
.icon-angle-up:before {
content: "\e903";
}
.icon-api:before {
content: "\e945";
}
.icon-assets:before {
content: "\e948";
}
.icon-bug:before {
content: "\e93d";
}

10
frontend/package-lock.json

@ -3511,6 +3511,11 @@
"sha.js": "^2.4.8"
}
},
"cropperjs": {
"version": "2.0.0-alpha.1",
"resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-2.0.0-alpha.1.tgz",
"integrity": "sha512-dcru3l4IwfswR0SDpegJa9GBFTcGLpuTwPlkbe8Y3chg8IxumGo+JNY19H6Y7jT5JVCdQubVMwM8gE2vUitzug=="
},
"cross-fetch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.2.tgz",
@ -6760,6 +6765,11 @@
"integrity": "sha1-2B8kA3bQuk8Nd4lyw60lh0EXpGM=",
"dev": true
},
"image-focus": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/image-focus/-/image-focus-1.1.0.tgz",
"integrity": "sha512-pAMWcA0+rJIGUYBULexM50yf/RRO8DBuqwnOzmv+q7kIdJYcf5skwRkE1UzokTIgrPe7BwyxEa8L4HAXC8WWeg=="
},
"import-cwd": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",

2
frontend/package.json

@ -28,8 +28,10 @@
"babel-polyfill": "6.26.0",
"bootstrap": "4.3.1",
"core-js": "3.2.1",
"cropperjs": "2.0.0-alpha.1",
"graphiql": "0.13.2",
"graphql": "14.4.2",
"image-focus": "^1.1.0",
"marked": "0.7.0",
"mersenne-twister": "1.1.0",
"moment": "2.24.0",

Loading…
Cancel
Save