├── .editorconfig ├── .gitignore ├── .prettierrc ├── LICENSE.md ├── README.md ├── composer.json ├── index.css ├── index.js ├── index.php └── src └── BlocksField.php /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = tab 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | 11 | [*.php] 12 | indent_size = 4 13 | insert_final_newline = true 14 | 15 | [*.md,*.txt] 16 | indent_style = space 17 | trim_trailing_whitespace = false 18 | insert_final_newline = false 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS files 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "singleQuote": true, 6 | "trailingComma": "none", 7 | "bracketSpacing": true, 8 | "semi": true, 9 | "proseWrap": "preserve", 10 | "arrowParens": "avoid", 11 | "htmlWhitespaceSensitivity": "css" 12 | } 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 JUNO 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 Visual Block Selector 2 | 3 | This plugin for **Kirby 5** replaces the block selector with a customized version that displays a preview image for each block. 4 | 5 | ![Visual block selector](https://github.com/junohamburg/kirby-visual-block-selector/assets/77532479/5f742752-85ac-44f0-8fd2-7c9031df1387) 6 | 7 | Please note: If you are using **Kirby 4**, please install [v2.1.0](https://github.com/junohamburg/kirby-visual-block-selector/releases/tag/2.1.0). If you are using **Kirby 3**, please install [v1.1.2](https://github.com/junohamburg/kirby-visual-block-selector/releases/tag/1.1.2). 8 | 9 | ## Installation 10 | 11 | ### Download 12 | 13 | Download and copy this repository to `/site/plugins/kirby-visual-block-selector`. 14 | 15 | ### Composer 16 | 17 | ``` 18 | composer require junohamburg/kirby-visual-block-selector 19 | ``` 20 | 21 | ### Git submodule 22 | 23 | ``` 24 | git submodule add https://github.com/junohamburg/kirby-visual-block-selector.git site/plugins/kirby-visual-block-selector 25 | ``` 26 | 27 | ## Setup 28 | 29 | 1. Create the block preview images in 480×270 pixel. The images are displayed in a fixed aspect ratio of 16/9. 30 | 2. Create the folder `assets/block-previews`. 31 | 3. Save the images in the `assets/block-previews` folder with the same name as the block. For example, the preview image of `heading.yml` is `heading.png`. Any image format (png, jpg, gif, svg) should work. 32 | 33 | Tip: You can define fieldset groups for the `blocks` field: [Kirby docs](https://getkirby.com/docs/reference/panel/fields/blocks#defining-fieldsets__groups) 34 | 35 | **:warning: Please note:** If there are no preview images for a `blocks` field, the default Kirby block selector will be displayed. 36 | 37 | ## License 38 | 39 | MIT 40 | 41 | ## Credits 42 | 43 | - [JUNO](https://juno-hamburg.com) 44 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "junohamburg/kirby-visual-block-selector", 3 | "description": "Kirby Visual Block Selector", 4 | "license": "MIT", 5 | "type": "kirby-plugin", 6 | "version": "3.0.0", 7 | "authors": [ 8 | { 9 | "name": "JUNO", 10 | "email": "github@juno-hamburg.com" 11 | } 12 | ], 13 | "require": { 14 | "getkirby/composer-installer": "^1.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | /* Dialog layout */ 2 | .k-block-selector[data-size='visual'] { 3 | max-width: 70rem; 4 | width: 100%; 5 | } 6 | 7 | .k-block-selector[data-size='visual'] .k-block-types { 8 | grid-template-columns: repeat(auto-fill, minmax(7.375rem, 1fr)); 9 | grid-gap: 1rem 0.75rem; 10 | } 11 | 12 | @media (min-width: 30em) { 13 | .k-block-selector[data-size='visual'] .k-block-types { 14 | grid-template-columns: repeat(auto-fill, minmax(11.25rem, 1fr)); 15 | } 16 | } 17 | 18 | /* Button */ 19 | .k-block-selector-button { 20 | --icon-color: var(--color-text); 21 | background: var(--item-color-back); 22 | border-radius: var(--button-rounded); 23 | font-variant-numeric: tabular-nums; 24 | box-shadow: var(--shadow); 25 | align-self: start; 26 | } 27 | 28 | @media (max-width: 29.9375em) { 29 | .k-block-selector-button { 30 | font-size: var(--text-xs); 31 | } 32 | } 33 | 34 | /* Disabled button */ 35 | .k-block-selector-button:where([aria-disabled]) { 36 | cursor: not-allowed; 37 | } 38 | .k-block-selector-button:where([aria-disabled]) > * { 39 | opacity: var(--opacity-disabled); 40 | } 41 | 42 | /* Image */ 43 | .k-block-selector-button-preview { 44 | aspect-ratio: 16 / 9; 45 | display: flex; 46 | align-items: center; 47 | justify-content: center; 48 | box-sizing: content-box; 49 | padding: 0.5em; 50 | } 51 | 52 | .k-block-selector-button-preview img { 53 | object-fit: cover; 54 | aspect-ratio: 16 / 9; 55 | border-radius: var(--rounded-sm); 56 | } 57 | 58 | /* Fallback icon */ 59 | .k-block-selector-button-preview .k-icon { 60 | height: calc(var(--icon-size) * 1.25); 61 | width: calc(var(--icon-size) * 1.25); 62 | } 63 | 64 | @media (min-width: 30em) { 65 | .k-block-selector-button-preview .k-icon { 66 | height: calc(var(--icon-size) * 2); 67 | width: calc(var(--icon-size) * 2); 68 | } 69 | } 70 | 71 | /* Text */ 72 | .k-block-selector-button-text { 73 | display: block; 74 | text-align: left; 75 | word-wrap: break-word; 76 | overflow-wrap: break-word; 77 | padding: 0.625em 0.625em 0.6875em; 78 | border-top: 1px solid var(--color-border); 79 | } 80 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | panel.plugin('junohamburg/visual-block-selector', { 2 | components: { 3 | 'k-block-selector': { 4 | extends: 'k-block-selector', 5 | template: ` 6 | 15 | 16 | {{ headline }} 17 | 18 | 19 |
24 | {{ group.label }} 25 | 29 | 44 | 45 | 46 | 50 | 60 | 61 |
62 | 63 |

67 | 68 | 69 | `, 70 | computed: { 71 | showVisualBlockSelector() { 72 | for (const group of Object.values(this.groups)) { 73 | for (const fieldset of group.fieldsets) { 74 | if (fieldset.previewImage !== null) { 75 | return true; 76 | } 77 | } 78 | } 79 | 80 | return false; 81 | } 82 | } 83 | } 84 | } 85 | }); -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | __DIR__ . '/src/BlocksField.php', 14 | ]); 15 | 16 | Kirby::plugin('junohamburg/visual-block-selector', [ 17 | 'fields' => [ 18 | 'blocks' => 'JunoHamburg\VisualBlockSelector\BlocksField' 19 | ], 20 | ]); 21 | -------------------------------------------------------------------------------- /src/BlocksField.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | protected function previewImages(): array 21 | { 22 | $kirby = $this->kirby(); 23 | $previews = []; 24 | $dir = 'block-previews'; 25 | $path = $kirby->root('assets') . '/' . $dir; 26 | $images = Dir::files($path); 27 | 28 | $relativePath = str_replace($kirby->root('index') . '/', '', $kirby->root('assets')); 29 | 30 | foreach ($images as $image) { 31 | $asset = asset($relativePath . '/' . $dir . '/' . $image); 32 | $previews[$asset->name()] = $asset->url(); 33 | } 34 | 35 | return $previews; 36 | } 37 | 38 | /** 39 | * Adds the preview images to the fieldsets 40 | * if they exist 41 | */ 42 | public function props(): array 43 | { 44 | $props = parent::props(); 45 | $previewsImages = $this->previewImages(); 46 | 47 | return [ 48 | ...$props, 49 | 'fieldsets' => array_map(fn (array $fieldset) => [ 50 | ...$fieldset, 51 | 'previewImage' => $previewsImages[$fieldset['type']] ?? null 52 | ], $props['fieldsets']) 53 | ]; 54 | } 55 | } 56 | --------------------------------------------------------------------------------