diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index b5e032f9fb..78a10da78d 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -195,6 +195,10 @@ @import "components/contextdialogs/umb-dialog-datatype-delete.less"; +// Property Editors +@import "../views/propertyeditors/blocklist/blocklist.component.less"; + + // Utilities @import "utilities/layout/_display.less"; @import "utilities/theme/_opacity.less"; @@ -218,6 +222,11 @@ // Used for prevalue editors @import "components/prevalues/multivalues.less"; +// Block Elements +@import "../views/blockelements/labelblock/labelblock.editor.less"; +@import "../views/blockelements/textareablock/textareablock.editor.less"; +@import "../views/blockelements/imageblock/imageblock.editor.less"; + // Dashboards @import "dashboards/getstarted.less"; @import "dashboards/umbraco-forms.less"; diff --git a/src/Umbraco.Web.UI.Client/src/views/blockelements/imageblock/imageblock.editor.html b/src/Umbraco.Web.UI.Client/src/views/blockelements/imageblock/imageblock.editor.html new file mode 100644 index 0000000000..c77f19ba67 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/blockelements/imageblock/imageblock.editor.html @@ -0,0 +1,3 @@ + diff --git a/src/Umbraco.Web.UI.Client/src/views/blockelements/imageblock/imageblock.editor.less b/src/Umbraco.Web.UI.Client/src/views/blockelements/imageblock/imageblock.editor.less new file mode 100644 index 0000000000..99b1bb53f2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/blockelements/imageblock/imageblock.editor.less @@ -0,0 +1,12 @@ +.blockelement-imageblock-editor { + + padding-top: 2px; + padding-bottom: 2px; + + img { + width: 100%; + border: none; + resize: none; + border-radius: @baseBorderRadius; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/views/blockelements/labelblock/labelblock.editor.html b/src/Umbraco.Web.UI.Client/src/views/blockelements/labelblock/labelblock.editor.html new file mode 100644 index 0000000000..f0678c76e9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/blockelements/labelblock/labelblock.editor.html @@ -0,0 +1,4 @@ + diff --git a/src/Umbraco.Web.UI.Client/src/views/blockelements/labelblock/labelblock.editor.less b/src/Umbraco.Web.UI.Client/src/views/blockelements/labelblock/labelblock.editor.less new file mode 100644 index 0000000000..610773528b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/blockelements/labelblock/labelblock.editor.less @@ -0,0 +1,34 @@ +.blockelement-labelblock-editor { + + width: 100%; + min-height: 48px; + border: 1px solid @gray-9; + border-radius: @baseBorderRadius; + + color: @ui-action-discreet-type; + + text-align: left; + padding-left: 20px; + padding-bottom: 2px; + margin-bottom: 2px; + margin-top: 2px; + + user-select: none; + + transition: border-color 120ms; + + i { + font-size: 22px; + display: inline-block; + vertical-align: middle; + } + span { + display: inline-block; + vertical-align: middle; + } + + &:hover { + color: @ui-action-discreet-type-hover; + border-color: @gray-8; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/views/blockelements/textareablock/textareablock.editor.controller.js b/src/Umbraco.Web.UI.Client/src/views/blockelements/textareablock/textareablock.editor.controller.js new file mode 100644 index 0000000000..761fc57e03 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/blockelements/textareablock/textareablock.editor.controller.js @@ -0,0 +1,29 @@ +//used for the media picker dialog +angular.module("umbraco") +.controller("Umbraco.Editors.TextAreaBlockElementEditorController", + function ($scope) { + + var vm = this; + + vm.firstProperty = $scope.block.content.tabs[0].properties[0]; +/* + vm.submitOnEnter = function($event) { + if($event && $event.keyCode === 13 && !$event.shiftKey && !$event.ctrlKey) { + var target = $event.target; + if(target.selectionStart === target.selectionEnd && target.selectionEnd === target.textLength) { + //&& (target.textLength === 0 || /\r|\n/.test(target.value.charAt(target.textLength - 1))) + $scope.$emit("showFocusOutline"); + $scope.blockApi.showCreateOptionsFor($scope.block, $event); + } + } + } +*/ + vm.onBlur = function() { + if (vm.firstProperty.value === null || vm.firstProperty.value === "") { + $scope.blockApi.deleteBlock($scope.block); + } + } + + } + +); diff --git a/src/Umbraco.Web.UI.Client/src/views/blockelements/textareablock/textareablock.editor.html b/src/Umbraco.Web.UI.Client/src/views/blockelements/textareablock/textareablock.editor.html new file mode 100644 index 0000000000..405c8634b4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/blockelements/textareablock/textareablock.editor.html @@ -0,0 +1,15 @@ + +
+ + + + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/blockelements/textareablock/textareablock.editor.less b/src/Umbraco.Web.UI.Client/src/views/blockelements/textareablock/textareablock.editor.less new file mode 100644 index 0000000000..492025274a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/blockelements/textareablock/textareablock.editor.less @@ -0,0 +1,27 @@ +.blockelement-textareablock-editor { + + width: 100%; + padding-bottom: 24px; + padding-top: 24px; + + padding-left: 24px; + padding-right: 24px; + + min-height: 64px; + box-sizing: border-box; + + textarea { + display: block; + width: 100%; + max-width: 640px; + margin-left: auto; + margin-right: auto; + border: none; + resize: none; + overflow: auto; + + font-size: 18px; + font-family: Georgia,Cambria,"Times New Roman",Times,serif; + line-height: 1.25; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/elementeditor/elementeditor.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/elementeditor/elementeditor.controller.js new file mode 100644 index 0000000000..d421418297 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/elementeditor/elementeditor.controller.js @@ -0,0 +1,23 @@ +//used for the media picker dialog +angular.module("umbraco") +.controller("Umbraco.Editors.ElementEditorController", + function ($scope) { + + var vm = this; + + vm.content = $scope.model.block.content; + + vm.saveAndClose = function() { + if ($scope.model && $scope.model.submit) { + $scope.model.submit($scope.model); + } + } + + vm.close = function() { + if ($scope.model && $scope.model.close) { + $scope.model.close($scope.model); + } + } + + } +); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/elementeditor/elementeditor.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/elementeditor/elementeditor.html new file mode 100644 index 0000000000..71aab124e6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/elementeditor/elementeditor.html @@ -0,0 +1,84 @@ +
+ + + + + + +
+ + + +
+ +
+
+ +
+ +
+
{{ group.label }}
+
+ +
+ + +
+ + +
+ +
+
+ +
+ + + + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + +
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.component.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.component.html new file mode 100644 index 0000000000..e38858c8b7 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.component.html @@ -0,0 +1,104 @@ +
+ + +
+ +
+ +
+ + + + +
+ +
+
+
+ +

No editor

+
+ +
+ + +
+ +
+ +
+
+ + + + + +
+ + + + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.component.js new file mode 100644 index 0000000000..6283bd1026 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.component.js @@ -0,0 +1,553 @@ +(function () { + 'use strict'; + + angular + .module('umbraco') + .component('blockListPropertyEditor', { + templateUrl: 'views/propertyeditors/blocklist/blocklist.component.html', + controller: BlockListController, + controllerAs: 'vm', + bindings: { + + }, + require: { + umbProperty: '?^umbProperty', + propertyForm: '?^propertyForm' + } + }); + + function BlockListController($scope, $interpolate, editorService, clipboardService, localizationService, overlayService) { + + var vm = this; + var model = $scope.$parent.$parent.model; + + $scope.moveFocusToBlock = null; + + vm.quickMenuVisible = false; + vm.quickMenuIndex = 0; + + vm.quickMenuAddNewBlock = function(type) { + addNewBlock(vm.quickMenuIndex, type); + vm.quickMenuVisible = false; + } + + vm.availableBlockTypes = [ + { + alias: "pageModule", + name: "Module", + icon: "icon-document", + prototype_paste_data: { + + elementType: { + alias: 'contentTypeAlias', + icon: "icon-document", + label: "Text" + }, + label: "{{pageTitle | truncate:true:36}}", + labelInterpolate: $interpolate("{{pageTitle | truncate:true:36}}"), + editor: "views/blockelements/labelblock/labelblock.editor.html", + content: { + variants: [ + { + language: { + isDefault: true + } + } + ], + tabs: [ + { + id: 1234, + label: "Group 1", + properties: [ + { + label: "Page Title", + description: "The title of the page", + view: "textbox", + config: {maxChars: 500}, + hideLabel: false, + validation: {mandatory: true, mandatoryMessage: "", pattern: null, patternMessage: ""}, + readonly: false, + id: 441, + dataTypeKey: "0cc0eba1-9960-42c9-bf9b-60e150b429ae", + value: "Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + alias: "pageTitle", + editor: "Umbraco.TextBox", + isSensitive: false, + culture: null, + segment: null + } + ] + } + ] + } + } + }, + { + alias: "contentTypeAlias", + name: "contentTypeName", + icon: "icon-text", + prototype_paste_data: { + elementType: { + alias: 'contentTypeAlias', + icon: "icon-document", + label: "Text" + }, + label: "Label", + editor: "views/blockelements/textareablock/textareablock.editor.html", + content: { + variants: [ + { + language: { + isDefault: true + } + } + ], + tabs: [ + { + id: 1234, + label: "Group 1", + properties: [ + { + label: "Page Title", + description: "The title of the page", + view: "textbox", + config: {maxChars: 500}, + hideLabel: false, + validation: {mandatory: true, mandatoryMessage: "", pattern: null, patternMessage: ""}, + readonly: false, + id: 441, + dataTypeKey: "0cc0eba1-9960-42c9-bf9b-60e150b429ae", + value: "", + alias: "pageTitle", + editor: "Umbraco.TextBox", + isSensitive: false, + culture: null, + segment: null + } + ] + } + ] + } + } + }, + { + alias: "contentTypeAlias", + name: "contentTypeName", + icon: "icon-picture", + prototype_paste_data: { + elementType: { + alias: 'contentTypeAlias', + icon: "icon-document", + label: "Text" + }, + label: "Label", + editor: "views/blockelements/imageblock/imageblock.editor.html", + content: { + variants: [ + { + language: { + isDefault: true + } + } + ], + tabs: [ + { + id: 1234, + label: "Group 1", + properties: [ + { + label: "Page Title", + description: "The title of the page", + view: "textbox", + config: {maxChars: 500}, + hideLabel: false, + validation: {mandatory: true, mandatoryMessage: "", pattern: null, patternMessage: ""}, + readonly: false, + id: 441, + dataTypeKey: "0cc0eba1-9960-42c9-bf9b-60e150b429ae", + value: "Let's have a chat", + alias: "pageTitle", + editor: "Umbraco.TextBox", + isSensitive: false, + culture: null, + segment: null + } + ] + } + ], + temp_image: "/umbraco/assets/img/login.jpg" + } + } + } + ]; + + // var defaultBlockType... + + // TODO: get icon, properties etc. from available types? + vm.blocks = [ + { + elementType: { + alias: 'contentTypeAlias', + icon: "icon-document", + label: "Text" + }, + label: "{{pageTitle | truncate:true:36}}", + labelInterpolate: $interpolate("{{pageTitle | truncate:true:36}}"), + key: 1, + editor: "views/blockelements/labelblock/labelblock.editor.html", + content: { + variants: [ + { + language: { + isDefault: true + } + } + ], + tabs: [ + { + id: 1234, + label: "Group 1", + properties: [ + { + label: "Page Title", + description: "The title of the page", + view: "textbox", + config: {maxChars: 500}, + hideLabel: false, + validation: {mandatory: true, mandatoryMessage: "", pattern: null, patternMessage: ""}, + readonly: false, + id: 441, + dataTypeKey: "0cc0eba1-9960-42c9-bf9b-60e150b429ae", + value: "The purpose of lorem ipsum is to create a natural looking block of text (sentence, paragraph, page, etc.) that doesn't distract from the layout. A practice not without controversy, laying out pages with meaningless filler text can be very useful when the focus is meant to be on design, not content.", + alias: "pageTitle", + editor: "Umbraco.TextBox", + isSensitive: false, + culture: null, + segment: null + } + ] + } + ] + } + }, + { + elementType: { + alias: 'contentTypeAlias', + icon: "icon-document", + label: "Text" + }, + label: "{{pageTitle | truncate:true:36}}", + labelInterpolate: $interpolate("{{pageTitle | truncate:true:36}}"), + key: 2, + editor: "views/blockelements/labelblock/labelblock.editor.html", + content: { + variants: [ + { + language: { + isDefault: true + } + } + ], + tabs: [ + { + id: 1234, + label: "Group 1", + properties: [ + { + label: "Page Title", + description: "The title of the page", + view: "textbox", + config: {maxChars: 500}, + hideLabel: false, + validation: {mandatory: true, mandatoryMessage: "", pattern: null, patternMessage: ""}, + readonly: false, + id: 441, + dataTypeKey: "0cc0eba1-9960-42c9-bf9b-60e150b429ae", + value: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + alias: "pageTitle", + editor: "Umbraco.TextBox", + isSensitive: false, + culture: null, + segment: null + } + ] + } + ] + } + }, + { + + elementType: { + alias: 'contentTypeAlias', + icon: "icon-document", + label: "Text" + }, + label: "{{pageTitle | truncate:true:36}}", + labelInterpolate: $interpolate("{{pageTitle | truncate:true:36}}"), + key: 3, + editor: "views/blockelements/labelblock/labelblock.editor.html", + content: { + variants: [ + { + language: { + isDefault: true + } + } + ], + tabs: [ + { + id: 1234, + label: "Group 1", + properties: [ + { + label: "Page Title", + description: "The title of the page", + view: "textbox", + config: {maxChars: 500}, + hideLabel: false, + validation: {mandatory: true, mandatoryMessage: "", pattern: null, patternMessage: ""}, + readonly: false, + id: 441, + dataTypeKey: "0cc0eba1-9960-42c9-bf9b-60e150b429ae", + value: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + alias: "pageTitle", + editor: "Umbraco.TextBox", + isSensitive: false, + culture: null, + segment: null + } + ] + } + ] + } + } + ]; + + function setDirty() { + if (vm.propertyForm) { + vm.propertyForm.$setDirty(); + } + }; + + function addNewBlock(index, type) { + + var block = angular.copy(type.prototype_paste_data); + + vm.blocks.splice(index, 0, block); + $scope.moveFocusToBlock = block; + + } + /* + function moveFocusToNextBlock(blockModel, $event) { + var index = vm.blocks.indexOf(blockModel); + if(index < vm.blocks.length) { + var nextBlock = vm.blocks[index+1]; + $scope.moveFocusToBlock = nextBlock; + } else { + showCreateOptions(blockModel, $event); + } + } + */ + + vm.showCreateOptionsFor = function(blockModel, $event) { + var index = vm.blocks.indexOf(blockModel); + $event.preventDefault(); + showCreateOptionsAt(index); + } + function showCreateOptionsAt(index) { + vm.quickMenuIndex = index; + vm.quickMenuVisible = true; + window.addEventListener("keydown", handleTypingInCreateOptions); + } + + function handleTypingInCreateOptions(event) { + if (event.ctrlKey || event.metaKey || event.altKey) + return; + + if ( + (event.keyCode === 13) // enter + || + (event.keyCode >= 48 && event.keyCode <= 90)// 0 to z + || + (event.keyCode >= 96 && event.keyCode <= 111)// numpads + || + (event.keyCode >= 186 && event.keyCode <= 222)// semi-colon and a lot of other special characters + ) { + // Continue writting... needs to know default text-element. if we have one. + } + } + + function hideCreateOptions() { + vm.quickMenuVisible = false; + window.removeEventListener("keydown", handleTypingInCreateOptions); + } + + vm.onCreateOptionsBlur = function($event) { + + if(!$($event.relatedTarget).is(".umb-block-list__block--create-bar > button")) { + hideCreateOptions(); + } + + } + + vm.getBlockLabel = function(block) { + + var name = ""; + + var props = new Object(); + + var tab = block.content.tabs[0]; + // TODO: need to look up all tabs... + for(const property of tab.properties) { + props[property.alias] = property.value; + } + + if(block.labelInterpolate) { + return block.labelInterpolate(props); + } + + return "block.label"; + } + + vm.deleteBlock = function(block) { + var index = vm.blocks.indexOf(block); + if(index !== -1) { + vm.blocks.splice(index, 1); + } + if(vm.quickMenuIndex > index) { + vm.quickMenuIndex--; + } + } + + vm.editBlock = function(blockModel) { + + var elementEditor = { + block: blockModel, + view: "views/common/infiniteeditors/elementeditor/elementeditor.html", + size: "large", + submit: function(model) { + blockModel.content = model.block.content; + editorService.close(); + }, + close: function() { + editorService.close(); + } + }; + + // open property settings editor + editorService.open(elementEditor); + } + + vm.showCreateDialog = function (createIndex, $event) { + + if (vm.blockTypePicker) { + return; + } + + if (vm.availableBlockTypes.length === 0) { + return; + } + + vm.blockTypePicker = { + show: true, + size: vm.availableBlockTypes.length > 6 ? "medium" : "small", + filter: vm.availableBlockTypes.length > 12 ? true : false, + orderBy: "$index", + view: "itempicker", + event: $event, + availableItems: vm.availableBlockTypes, + submit: function (model) { + if (model && model.selectedItem) { + addNewBlock(createIndex, model.selectedItem); + } + vm.blockTypePicker.close(); + }, + close: function () { + vm.blockTypePicker.show = false; + vm.blockTypePicker = null; + } + }; + + }; + + vm.requestCopyBlock = function(block) { + console.log("copy") + } + vm.requestDeleteBlock = function(block) { + localizationService.localizeMany(["content_nestedContentDeleteItem", "general_delete", "general_cancel", "contentTypeEditor_yesDelete"]).then(function (data) { + const overlay = { + title: data[1], + content: data[0], + closeButtonLabel: data[2], + submitButtonLabel: data[3], + submitButtonStyle: "danger", + close: function () { + overlayService.close(); + }, + submit: function () { + vm.deleteBlock(block); + overlayService.close(); + } + }; + + overlayService.open(overlay); + }); + } + + vm.showCopy = clipboardService.isSupported(); + + + + vm.sorting = false; + vm.sortableOptions = { + axis: "y", + cursor: "grabbing", + handle: '.umb-block-list__block', + cancel: 'input,textarea,select,option', + classes: '.blockelement--dragging', + distance: 5, + tolerance: "pointer", + scroll: true, + start: function (ev, ui) { + $scope.$apply(function () { + vm.sorting = true; + }); + }, + update: function (ev, ui) { + setDirty(); + }, + stop: function (ev, ui) { + $scope.$apply(function () { + vm.sorting = false; + }); + } + }; + + $scope.blockApi = { + showCreateOptionsFor: vm.showCreateOptionsFor, + removeBlock: vm.removeBlock + } + + + var copyAllEntriesAction = { + labelKey: 'clipboard_labelForCopyAllEntries', + labelTokens: [model.label], + icon: 'documents', + method: function () {}, + isDisabled: true + } + + var propertyActions = [ + copyAllEntriesAction + ]; + + this.$onInit = function () { + if (this.umbProperty) { + this.umbProperty.setPropertyActions(propertyActions); + } + }; + + + } + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.component.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.component.less new file mode 100644 index 0000000000..a26dda4202 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.component.less @@ -0,0 +1,217 @@ +@umb-block-list__item_minimum_height: 48px; + +.umb-block-list { + padding-bottom:10px; +} + +.umb-block-list__wrapper { + position: relative; + max-width: 1024px; + > .ui-sortable > .ui-sortable-helper > .umb-block-list__block > .umb-block-list__block--content > * { + box-shadow: 0px 5px 10px 0 rgba(0,0,0,.2); + } +} + +.umb-block-list__block { + position: relative; + width: 100%; + cursor: grab; + + .umb-block-list__block--head { + opacity: 0; + transition: opacity 120ms; + } + .umb-block-list__block--actions { + opacity: 0; + transition: opacity 120ms; + } + + &:hover, &:focus, &:focus-within { + .umb-block-list__block--head { + opacity: 1; + } + + .umb-block-list__block--actions { + opacity: 1; + } + } + + &:focus, &:focus-within { + .umb-block-list__block--head { + &::before { + background-color: @blueMid; + } + } + } +} + +.umb-block-list__block--head { + position: absolute; + top: 0; + left: -180px;// 160px from control-header + 20px from spacing. + bottom: 0; + width: 180px;// 160px from control-header + 20px from spacing. + user-select: none; + padding-top: 6px; + padding-right: 14px; + box-sizing: border-box; + color: @gray-5; + background-color: rgba(255, 255, 255, .96); + box-shadow: 0 0 6px 6px rgba(255, 255, 255, .96); + text-align: right; + &::before { + content: ''; + position: absolute; + top: 6px; + bottom: 6px; + right: 4px; + width: 1px; + background-color: @gray-10; + } + + small { + text-align: left; + margin-left: 4px; + margin-bottom: 4px; + } +} +label.umb-block-list__block--head { + cursor: grab; +} + +.umb-block-list__block--actions { + position: absolute; + top: 10px; + right: 10px; + font-size: 0; + background-color: rgba(255, 255, 255, .96); + border-radius: 14px; + padding-left: 5px; + padding-right: 5px; + .action { + display: inline-block; + color: @ui-action-discreet-type; + font-size: 18px; + padding: 5px; + &:hover { + color: @ui-action-discreet-type-hover; + } + } +} + +.umb-block-list__block--content { + position: relative; + width: 100%; + min-height: @umb-block-list__item_minimum_height; + background-color: @white; + border-radius: @baseBorderRadius; +} + + +.umb-block-list__block--create-button { + position: absolute; + width: 100%; + z-index:1; + opacity: 0; + outline: none; + height: 20px; + margin-top: -10px; + padding-top: 10px; + margin-bottom: -10px; + transition: opacity 240ms; + + &::before { + content: ''; + position: absolute; + background-color: @ui-outline; + border-radius: 2px; + top:9px; + right: 0; + left: 0; + height: 2px; + animation: umb-block-list__block--create-button 800ms ease-in-out infinite; + @keyframes umb-block-list__block--create-button { + 0% { opacity: 0.5; } + 50% { opacity: 1; } + 100% { opacity: 0.5; } + } + } + &::after { + content: "+"; + margin-left: auto; + margin-right: auto; + margin-top: -16px; + width: 28px; + height: 25px; + padding-bottom: 3px; + border-radius: 3em; + border: 2px solid @ui-outline; + display: flex; + justify-content: center; + align-items: center; + color: @ui-outline; + font-size: 20px; + font-weight: 800; + background-color: rgba(255, 255, 255, .96); + box-shadow: 0 0 0 2px rgba(255, 255, 255, .96); + transform: scale(0); + transition: transform 240ms ease-in; + } + &:focus { + &::after { + border: 2px solid @ui-outline; + } + } + &:hover, &:focus { + opacity: 1; + transition-duration: 120ms; + &::after { + transform: scale(1); + transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275); + } + } +} +/* +.umb-block-list__block--create-bar { + button { + display: inline-block; + width: 120px; + height: 120px; + border-radius: @baseBorderRadius; + text-align: center; + font-size: 12px; + i { + font-size: 30px; + line-height: 20px; + margin-bottom: 10px; + display: block; + } + } +} +*/ +.umb-block-list__create-button { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + border: 1px dashed @ui-action-discreet-border; + color: @ui-action-discreet-type; + font-weight: bold; + margin: 2px 0; + padding: 5px 15px; + box-sizing: border-box; + border-radius: @baseBorderRadius; +} + +.umb-block-list__create-button:hover { + color: @ui-action-discreet-type-hover; + border-color: @ui-action-discreet-border-hover; + text-decoration: none; +} + +.umb-block-list__create-button.--disabled, +.umb-block-list__create-button.--disabled:hover { + color: @gray-7; + border-color: @gray-7; + cursor: default; +} diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.html new file mode 100644 index 0000000000..198dab4f5f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.html @@ -0,0 +1 @@ +