├── .gitignore ├── LICENSE.md ├── README.md ├── composer.json ├── index.css ├── index.js ├── index.php ├── package.json ├── postcss.config.js └── src ├── FieldsBlock.vue └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # OS files 2 | .DS_Store 3 | 4 | # npm modules 5 | /node_modules 6 | 7 | # Composer files 8 | /vendor 9 | 10 | # Lock Files 11 | yarn.lock 12 | package-lock.json -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jon Gacnik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kirby Fields Block 2 | 3 | Kirby [block preview](https://getkirby.com/docs/reference/plugins/extensions/blocks) plugin to directly render block fields, allowing for inline editing. 4 | 5 | 6 | 7 | ## Usage 8 | 9 | ### Block definition 10 | 11 | When creating a custom block in your blueprints, pass `preview: fields` to utilize this plugin 12 | 13 | ```yaml 14 | blockname: 15 | name: Block Name 16 | preview: fields # required 17 | wysiwyg: true # recommended 18 | fields: 19 | text: 20 | label: Text 21 | type: text 22 | ``` 23 | 24 | Setting `wysiwyg: true` prevents drawer from automatically opening when creating a new block. 25 | 26 | ### Disable block title 27 | 28 | You can disable the block title bar by passing `label: false` 29 | 30 | ```yaml 31 | blockname: 32 | name: Block Name 33 | preview: fields 34 | wysiwyg: true 35 | label: false # disables block title bar 36 | fields: 37 | text: 38 | label: Text 39 | type: text 40 | ``` 41 | 42 |
43 | Example 44 | 45 |
46 | 47 | ### Collapse/Expand block 48 | 49 | You can collapse or expand the block preview by clicking on the arrow icon or double clicking the block title bar. 50 | 51 | ## Notes 52 | 53 | - The block `icon` will appear in the title bar. 54 | - Currently does not support blocks with tabs. 55 | 56 | ## Installation 57 | 58 | ``` 59 | composer require jg/kirby-fields-block 60 | ``` 61 | 62 |
63 | Other installation methods 64 | 65 | ### Download 66 | 67 | Download and copy this repository to `/site/plugins/kirby-fields-block`. 68 | 69 | ### Git submodule 70 | 71 | ``` 72 | git submodule add https://github.com/jongacnik/kirby-fields-block.git site/plugins/kirby-fields-block 73 | ``` 74 |
-------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jg/kirby-fields-block", 3 | "description": "Kirby Fields Block", 4 | "type": "kirby-plugin", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Jon Gacnik", 9 | "email": "jon@folderstudio.com" 10 | } 11 | ], 12 | "require": { 13 | "getkirby/composer-installer": "^1.1" 14 | } 15 | } -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | 2 | .k-block-fields-preview { 3 | margin: -0.75rem; 4 | overflow: hidden; 5 | border-radius: var(--rounded); 6 | } 7 | .k-block-fields-preview .k-block-title { 8 | padding: 0.75rem; 9 | background: #f7f7f7; 10 | } 11 | .k-block-fields-preview:not([data-hidden="true"]) .k-block-title { 12 | border-bottom: 1px solid rgba(0,0,0,.1); 13 | } 14 | .k-block-fields-preview .k-fields-block-toggle { 15 | margin-left: auto; 16 | cursor: pointer; 17 | } 18 | .k-block-fields-preview[data-hidden="true"] .k-fields-block-toggle { 19 | transform: scaleY(-1); 20 | } 21 | .k-block-fields-preview .k-form { 22 | padding: 1.25rem 1.5rem 1.5rem 1.5rem; 23 | } 24 | 25 | /** 26 | * Reset `.k-layout-column .k-empty` overrides 27 | */ 28 | .k-block-fields-preview .k-empty { 29 | position: static !important; 30 | opacity: 1 !important; 31 | align-items: stretch !important; 32 | justify-content: flex-start !important; 33 | color: #777 !important; 34 | border: 1px dashed #ccc !important; 35 | border-radius: 1px !important; 36 | } 37 | .k-block-fields-preview .k-empty[data-layout="cards"] { 38 | justify-content: center !important; 39 | } 40 | .k-block-fields-preview .k-empty[data-layout="list"] .k-icon { 41 | border-right: 1px solid rgba(0,0,0,.05) !important; 42 | } 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | const FieldsBlock_vue_vue_type_style_index_0_lang = ""; 4 | function normalizeComponent(scriptExports, render, staticRenderFns, functionalTemplate, injectStyles, scopeId, moduleIdentifier, shadowMode) { 5 | var options = typeof scriptExports === "function" ? scriptExports.options : scriptExports; 6 | if (render) { 7 | options.render = render; 8 | options.staticRenderFns = staticRenderFns; 9 | options._compiled = true; 10 | } 11 | if (functionalTemplate) { 12 | options.functional = true; 13 | } 14 | if (scopeId) { 15 | options._scopeId = "data-v-" + scopeId; 16 | } 17 | var hook; 18 | if (moduleIdentifier) { 19 | hook = function(context) { 20 | context = context || this.$vnode && this.$vnode.ssrContext || this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext; 21 | if (!context && typeof __VUE_SSR_CONTEXT__ !== "undefined") { 22 | context = __VUE_SSR_CONTEXT__; 23 | } 24 | if (injectStyles) { 25 | injectStyles.call(this, context); 26 | } 27 | if (context && context._registeredComponents) { 28 | context._registeredComponents.add(moduleIdentifier); 29 | } 30 | }; 31 | options._ssrRegister = hook; 32 | } else if (injectStyles) { 33 | hook = shadowMode ? function() { 34 | injectStyles.call( 35 | this, 36 | (options.functional ? this.parent : this).$root.$options.shadowRoot 37 | ); 38 | } : injectStyles; 39 | } 40 | if (hook) { 41 | if (options.functional) { 42 | options._injectStyles = hook; 43 | var originalRender = options.render; 44 | options.render = function renderWithStyleInjection(h, context) { 45 | hook.call(context); 46 | return originalRender(h, context); 47 | }; 48 | } else { 49 | var existing = options.beforeCreate; 50 | options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; 51 | } 52 | } 53 | return { 54 | exports: scriptExports, 55 | options 56 | }; 57 | } 58 | const _sfc_main = { 59 | data() { 60 | return { 61 | isHidden: JSON.parse(sessionStorage.getItem(`kirby.fieldsBlock.${this.$attrs.endpoints.field}.${this.$attrs.id}`)) 62 | }; 63 | }, 64 | methods: { 65 | toggle() { 66 | this.isHidden = !this.isHidden; 67 | sessionStorage.setItem(`kirby.fieldsBlock.${this.$attrs.endpoints.field}.${this.$attrs.id}`, this.isHidden); 68 | }, 69 | preventSelect(event) { 70 | if (event.detail > 1) { 71 | if (!event.target.closest(".k-input")) { 72 | event.preventDefault(); 73 | } 74 | } 75 | } 76 | } 77 | }; 78 | var _sfc_render = function render() { 79 | var _vm = this, _c = _vm._self._c; 80 | return _c("div", { staticClass: "k-block-fields-preview", attrs: { "data-hidden": _vm.isHidden }, on: { "mousedown": _vm.preventSelect } }, [_vm.fieldset.label === null || _vm.fieldset.label ? _c("k-fields-block-title", { attrs: { "content": _vm.content, "fieldset": _vm.fieldset }, on: { "dblclick": _vm.toggle, "toggle": _vm.toggle } }) : _vm._e(), !_vm.isHidden ? _c("k-form", { ref: "form", attrs: { "autofocus": true, "fields": _vm.fieldset.tabs.content.fields, "value": _vm.$helper.clone(_vm.content) }, on: { "input": function($event) { 81 | return _vm.$emit("update", $event); 82 | } } }) : _vm._e()], 1); 83 | }; 84 | var _sfc_staticRenderFns = []; 85 | _sfc_render._withStripped = true; 86 | var __component__ = /* @__PURE__ */ normalizeComponent( 87 | _sfc_main, 88 | _sfc_render, 89 | _sfc_staticRenderFns, 90 | false, 91 | null, 92 | null, 93 | null, 94 | null 95 | ); 96 | __component__.options.__file = "/Users/jongacnik/Sites/_kirby/kirby-fields-block/src/FieldsBlock.vue"; 97 | const FieldsBlock = __component__.exports; 98 | panel.plugin("jg/fields-block", { 99 | components: { 100 | "k-fields-block-title": { 101 | extends: "k-block-title", 102 | template: ` 103 |
104 | 105 | 106 | {{ name }} 107 | 108 | 109 | {{ label }} 110 | 111 | 112 | 113 | 114 |
115 | ` 116 | } 117 | }, 118 | blocks: { 119 | fields: FieldsBlock 120 | } 121 | }); 122 | })(); 123 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | ", 7 | "license": "MIT", 8 | "devDependencies": { 9 | "kirbyup": "latest" 10 | }, 11 | "scripts": { 12 | "dev": "kirbyup src/index.js --watch", 13 | "build": "kirbyup src/index.js" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { } 3 | } -------------------------------------------------------------------------------- /src/FieldsBlock.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 43 | 44 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import FieldsBlock from "./FieldsBlock.vue" 2 | 3 | panel.plugin("jg/fields-block", { 4 | components: { 5 | 'k-fields-block-title': { 6 | extends: 'k-block-title', 7 | template: ` 8 |
9 | 10 | 11 | {{ name }} 12 | 13 | 14 | {{ label }} 15 | 16 | 17 | 18 | 19 |
20 | ` 21 | } 22 | }, 23 | blocks: { 24 | fields: FieldsBlock 25 | } 26 | }) --------------------------------------------------------------------------------