From f58b258fabfe31c454669c3ba8ac41a10e97e33e Mon Sep 17 00:00:00 2001 From: Thomas Schulze Date: Sat, 6 Apr 2019 16:37:46 +0200 Subject: [PATCH] update for initial release --- .gitignore | 1 + CHANGELOG.md | 5 + LICENSE.md | 16 +++ README.md | 60 ++++++++++++ composer.json | 38 ++++---- examples/README.md | 27 ++++++ examples/colorset/buttons.php | 2 +- examples/positions/buttons.php | 56 +++++++++++ .../positions}/images/center-bottom.svg | 0 .../positions}/images/center-middle.svg | 0 .../positions}/images/center-top.svg | 0 .../positions}/images/left-bottom.svg | 0 .../positions}/images/left-middle.svg | 0 .../positions}/images/left-top.svg | 0 .../positions}/images/right-bottom.svg | 0 .../positions}/images/right-middle.svg | 0 .../positions}/images/right-top.svg | 0 examples/{icons => transport}/buttons.php | 4 +- resources/colorset.png | Bin 0 -> 7662 bytes resources/positions.png | Bin 0 -> 10012 bytes resources/transport.png | Bin 0 -> 9395 bytes src/config.php | 91 ++++++++---------- src/fields/Buttons.php | 52 +++++----- src/models/Settings.php | 13 ++- src/resources/ButtonsAssets.php | 2 - src/resources/CustomAssets.php | 5 +- src/translations/de/buttons.php | 10 +- 27 files changed, 266 insertions(+), 116 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 examples/README.md create mode 100644 examples/positions/buttons.php rename {src/resources => examples/positions}/images/center-bottom.svg (100%) rename {src/resources => examples/positions}/images/center-middle.svg (100%) rename {src/resources => examples/positions}/images/center-top.svg (100%) rename {src/resources => examples/positions}/images/left-bottom.svg (100%) rename {src/resources => examples/positions}/images/left-middle.svg (100%) rename {src/resources => examples/positions}/images/left-top.svg (100%) rename {src/resources => examples/positions}/images/right-bottom.svg (100%) rename {src/resources => examples/positions}/images/right-middle.svg (100%) rename {src/resources => examples/positions}/images/right-top.svg (100%) rename examples/{icons => transport}/buttons.php (90%) create mode 100644 resources/colorset.png create mode 100644 resources/positions.png create mode 100644 resources/transport.png diff --git a/.gitignore b/.gitignore index e43b0f9..90ac674 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +/.idea .DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..84d5483 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Customizable Radio Buttons Field Changelog + +## 1.0.0 - 2019-04-06 +### Added +- Initial release diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..08fcfe4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,16 @@ +The MIT License (MIT) + +Copyright (c) 2018 Codemonauts + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b50085a --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# Customizable Radio Buttons Field for Craft CMS 3.x + +![Icon](resources/buttons.png) + +A field type that add customizable radio buttons to Craft CMS. + +## Background + +Pictures say more than many words. With this plugin you can add radio buttons as fields, which can be images, icons, CSS classes, texts or a combination of them. + +## Requirements + + * Craft CMS >= 3.0.0 + +## Installation + +Open your terminal and go to your Craft project: + +``` shell +cd /path/to/project +composer require codemonauts/craft-customizable-radio-buttons-field +``` + +In the control panel, go to Settings → Plugins and click the “install” button for *Customizable radio buttons field*. + +## Configuration + +Copy the ```config.php``` to your config folder as ```buttons.php```. Then add button groups like this: + +``` php + '@config/path/to/my.css', // optional path to a local CSS file. This will be automatically published. + 'cssUrl' => 'https://example.com/awesome.css' // Optional URL to an external CSS. + 'buttonGroups' => [ + 'myhandle' => [ + 'name' => 'My awesome buttons', // The name in the field's configuration dialog. + 'buttons' => [ + 'handle-button-1' => [ + 'image' => '@buttonsAssets/myimage.jpg', // Optional Image, overwrites 'label'. + 'title' => 'My button 1', // Title and Alt Attributes. + 'value' => 'myvalue', // The value to store (string) + 'class' => 'myclass', // Optional class(es) to add to the button. + 'label' => 'abc', // The button's text, will be overwritten when an image is set. + ], + 'handle-button-2' => [ + // ... + ], + // ... + ], + // ... + ], + ], +]; +``` + +You can have multiple button groups. They all share the same CSS file or CSS URL you can configure. See the [examples](examples/README.md). + +With ❤ by [codemonauts](https://codemonauts.com) diff --git a/composer.json b/composer.json index 6f68a9e..65b1ea2 100644 --- a/composer.json +++ b/composer.json @@ -1,42 +1,42 @@ { "name": "codemonauts/craft-customizable-radio-buttons-field", - "description": "Radio buttons field customizable with CSS classes, icons, images and text", + "description": "Craft CMS plugin to add a radio buttons field, customizable with CSS classes, icons, images and text.", "version": "1.0.0", "type": "craft-plugin", - "minimum-stability": "dev", "keywords": [ "craft", "cms", "craftcms", - "craft-plugin" + "craft-plugin", + "field", + "buttons" ], - "autoload": { - "psr-4": { - "codemonauts\\buttons\\": "src/" - } - }, + "license": "MIT", "authors": [ { "name": "codemonauts", - "homepage": "https://www.codemonauts.com" + "homepage": "https://codemonauts.com" } ], - "require": { - "craftcms/cms": "^3.0.0" - }, "support": { + "source": "https://github.com/codemonauts/craft-customizable-radio-buttons-field", "docs": "https://github.com/codemonauts/craft-customizable-radio-buttons-field/blob/master/README.md", "issues": "https://github.com/codemonauts/craft-customizable-radio-buttons-field/issues" }, - "license": "MIT", + "require": { + "craftcms/cms": "^3.0.0" + }, + "autoload": { + "psr-4": { + "codemonauts\\buttons\\": "src/" + } + }, "extra": { "handle": "buttons", - "name": "Customizable radio buttons field", - "developer": "codemonauts", - "developerUrl": "https://www.codemonauts.com", - "schemaVersion": "1.0.0", + "class": "codemonauts\\buttons\\Buttons", + "name": "Customizable Radio Buttons Field", + "description": "Radio buttons field, customizable with CSS classes, icons, images and text.", "hasCpSection": false, - "hasSettings": false, - "class": "codemonauts\\buttons\\Buttons" + "hasSettings": false } } diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..155dc6a --- /dev/null +++ b/examples/README.md @@ -0,0 +1,27 @@ +# Examples + +## Colorset + +![Screenshot Colorset](../resources/colorset.png) + +This example shows the usage of CSS classes and labels to let the user switch between preconfigured back- and foreground colors. So the user can see, how the color will look like. + +To run this example, copy the [```colorset/buttons.php```](colorset/buttons.php) to your Craft config folder and the [```colorset/colorset.css```](colorset/colorset.css) to a subfolder called ```buttons```. + +## Positions + +![Screenshot Positions](../resources/positions.png) + +This example uses images as buttons to switch between different positions. + +To run this example, copy the [```positions/buttons.php```](positions/buttons.php) to your Craft config folder and the folder [```positions/images```](positions/images) to a subfolder called ```buttons```. + +## Transport + +![Screenshot Transport](../resources/transport.png) + +In this example we use the Font Awesome Icons with our radio buttons. We add the Font Awesome CSS URL and the corresponding CSS classes to the buttons. + +To run this example, just copy the [```transport/buttons.php```](transport/buttons.php) to your Craft config folder. + + diff --git a/examples/colorset/buttons.php b/examples/colorset/buttons.php index b0cd252..5ec3555 100644 --- a/examples/colorset/buttons.php +++ b/examples/colorset/buttons.php @@ -1,10 +1,10 @@ '@config/buttons/colorset.css', 'buttonGroups' => [ 'colorset' => [ 'name' => 'Colorset', - 'cssFile' => '@config/buttons/colorset.css', 'buttons' => [ 'white' => [ 'label' => 'T', diff --git a/examples/positions/buttons.php b/examples/positions/buttons.php new file mode 100644 index 0000000..aebff0e --- /dev/null +++ b/examples/positions/buttons.php @@ -0,0 +1,56 @@ + [ + 'position' => [ + 'name' => 'Position', + 'buttons' => [ + 'left-top' => [ + 'image' => '@config/buttons/images/left-top.svg', + 'title' => 'Top left', + 'value' => 'left-top', + ], + 'center-top' => [ + 'image' => '@config/buttons/images/center-top.svg', + 'title' => 'Top center', + 'value' => 'center-top', + ], + 'right-top' => [ + 'image' => '@config/buttons/images/right-top.svg', + 'title' => 'Top right', + 'value' => 'right-top', + ], + 'left-middle' => [ + 'image' => '@config/buttons/images/left-middle.svg', + 'title' => 'Middle left', + 'value' => 'left-middle', + ], + 'center-middle' => [ + 'image' => '@config/buttons/images/center-middle.svg', + 'title' => 'Middle center', + 'value' => 'center-middle', + ], + 'right-middle' => [ + 'image' => '@config/buttons/images/right-middle.svg', + 'title' => 'Middle right', + 'value' => 'right-middle', + ], + 'left-bottom' => [ + 'image' => '@config/buttons/images/left-bottom.svg', + 'title' => 'Bottom left', + 'value' => 'left-bottom', + ], + 'center-bottom' => [ + 'image' => '@config/buttons/images/center-bottom.svg', + 'title' => 'Bottom center', + 'value' => 'center-bottom', + ], + 'right-bottom' => [ + 'image' => '@config/buttons/images/right-bottom.svg', + 'title' => 'Bottom right', + 'value' => 'right-bottom', + ], + ], + ], + ], +]; diff --git a/src/resources/images/center-bottom.svg b/examples/positions/images/center-bottom.svg similarity index 100% rename from src/resources/images/center-bottom.svg rename to examples/positions/images/center-bottom.svg diff --git a/src/resources/images/center-middle.svg b/examples/positions/images/center-middle.svg similarity index 100% rename from src/resources/images/center-middle.svg rename to examples/positions/images/center-middle.svg diff --git a/src/resources/images/center-top.svg b/examples/positions/images/center-top.svg similarity index 100% rename from src/resources/images/center-top.svg rename to examples/positions/images/center-top.svg diff --git a/src/resources/images/left-bottom.svg b/examples/positions/images/left-bottom.svg similarity index 100% rename from src/resources/images/left-bottom.svg rename to examples/positions/images/left-bottom.svg diff --git a/src/resources/images/left-middle.svg b/examples/positions/images/left-middle.svg similarity index 100% rename from src/resources/images/left-middle.svg rename to examples/positions/images/left-middle.svg diff --git a/src/resources/images/left-top.svg b/examples/positions/images/left-top.svg similarity index 100% rename from src/resources/images/left-top.svg rename to examples/positions/images/left-top.svg diff --git a/src/resources/images/right-bottom.svg b/examples/positions/images/right-bottom.svg similarity index 100% rename from src/resources/images/right-bottom.svg rename to examples/positions/images/right-bottom.svg diff --git a/src/resources/images/right-middle.svg b/examples/positions/images/right-middle.svg similarity index 100% rename from src/resources/images/right-middle.svg rename to examples/positions/images/right-middle.svg diff --git a/src/resources/images/right-top.svg b/examples/positions/images/right-top.svg similarity index 100% rename from src/resources/images/right-top.svg rename to examples/positions/images/right-top.svg diff --git a/examples/icons/buttons.php b/examples/transport/buttons.php similarity index 90% rename from examples/icons/buttons.php rename to examples/transport/buttons.php index 896ab8e..4ec9634 100644 --- a/examples/icons/buttons.php +++ b/examples/transport/buttons.php @@ -1,9 +1,9 @@ '@config/buttons/fontawesome.css', + 'cssUrl' => 'https://use.fontawesome.com/releases/v5.8.1/css/all.css', 'buttonGroups' => [ - 'icons' => [ + 'transport' => [ 'name' => 'Transport', 'buttons' => [ 'bicycle' => [ diff --git a/resources/colorset.png b/resources/colorset.png new file mode 100644 index 0000000000000000000000000000000000000000..629ecd8b265b022b93bc9c94d0f17e80d5c64e04 GIT binary patch literal 7662 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 literal 0 HcmV?d00001 diff --git a/resources/transport.png b/resources/transport.png new file mode 100644 index 0000000000000000000000000000000000000000..65067d71a687c169a5de7f05ad23edcfa3b14f1b GIT binary patch literal 9395 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 literal 0 HcmV?d00001 diff --git a/src/config.php b/src/config.php index c9dd5e1..dda703c 100644 --- a/src/config.php +++ b/src/config.php @@ -1,56 +1,43 @@ [ - 'position' => [ - 'name' => 'Position', - 'buttons' => [ - 'left-top' => [ - 'image' => '@codemonauts/buttons/resources/images/left-top.svg', - 'title' => 'Top left', - 'value' => 'left-top', - ], - 'center-top' => [ - 'image' => '@codemonauts/buttons/resources/images/center-top.svg', - 'title' => 'Top center', - 'value' => 'center-top', - ], - 'right-top' => [ - 'image' => '@codemonauts/buttons/resources/images/right-top.svg', - 'title' => 'Top right', - 'value' => 'right-top', - ], - 'left-middle' => [ - 'image' => '@codemonauts/buttons/resources/images/left-middle.svg', - 'title' => 'Middle left', - 'value' => 'left-middle', - ], - 'center-middle' => [ - 'image' => '@codemonauts/buttons/resources/images/center-middle.svg', - 'title' => 'Middle center', - 'value' => 'center-middle', - ], - 'right-middle' => [ - 'image' => '@codemonauts/buttons/resources/images/right-middle.svg', - 'title' => 'Middle right', - 'value' => 'right-middle', - ], - 'left-bottom' => [ - 'image' => '@codemonauts/buttons/resources/images/left-bottom.svg', - 'title' => 'Bottom left', - 'value' => 'left-bottom', - ], - 'center-bottom' => [ - 'image' => '@codemonauts/buttons/resources/images/center-bottom.svg', - 'title' => 'Bottom center', - 'value' => 'center-bottom', - ], - 'right-bottom' => [ - 'image' => '@codemonauts/buttons/resources/images/right-bottom.svg', - 'title' => 'Bottom right', - 'value' => 'right-bottom', - ], - ], - ], - ], + /* + * An optional CSS file, that will be bundled and published for the control panel, when a button group is used. + * There can only be one CSS file for all button groups. + * + * You would normaly use something like '@config/buttons/style.css'. + */ + 'cssFile' => '', + + /* + * In addition to a local file, you can set an URL for an external CSS (e.g. Fontawesome) + */ + 'cssUrl' => '', + + /* + * This array sets the config for all button groups. The array key is the button group's handle. + * See the examples in the repository. + * + * E.g.: + * + * 'buttonGroups' => [ + * 'myhandle' => [ + * 'name' => 'My awesome buttons', // The name in the field's configuration dialog + * 'buttons' => [ + * 'handle-button-1' => [ + * 'image' => '@buttonsAssets/myimage.jpg', // Optional Image, overwrites 'label' + * 'title' => 'My button 1', // Title and Alt Attributes + * 'value' => 'myvalue', // The value to store (string) + * 'class' => 'myclass', // Optional class to add to the button + * 'label' => 'Abc', // The button's text, will be overwritten when an image is set + * ], + * 'handle-button-2' => [ + * ... + * ], + * ... + * ], + * ], + * ], + */ + 'buttonGroups' => [], ]; diff --git a/src/fields/Buttons.php b/src/fields/Buttons.php index cc54ed5..efbc2c6 100644 --- a/src/fields/Buttons.php +++ b/src/fields/Buttons.php @@ -9,13 +9,12 @@ use craft\base\Field; use craft\base\PreviewableFieldInterface; use LitEmoji\LitEmoji; -use yii\db\Schema; use codemonauts\buttons\Buttons as Plugin; class Buttons extends Field implements PreviewableFieldInterface { - /* - * @var string[] Default values for buttons + /** + * @var array Default values for buttons */ protected $defaultButton = [ 'image' => '', @@ -46,14 +45,6 @@ public function __construct(array $config = []) parent::__construct($config); } - /** - * @inheritdoc - */ - public function getContentColumnType(): string - { - return Schema::TYPE_STRING; - } - /** * @inheritdoc */ @@ -68,16 +59,15 @@ public function getSettingsHtml() ]; } - return Craft::$app->getView()->renderTemplateMacro('_includes/forms', 'selectField', + return Craft::$app->getView()->renderTemplateMacro('_includes/forms', 'selectField', [ [ - [ - 'label' => Craft::t('buttons', 'Button group'), - 'id' => 'configHandle', - 'name' => 'configHandle', - 'options' => $options, - 'value' => $this->configHandle, - ], - ]); + 'label' => Craft::t('buttons', 'Button group'), + 'id' => 'configHandle', + 'name' => 'configHandle', + 'options' => $options, + 'value' => $this->configHandle, + ], + ]); } /** @@ -85,26 +75,30 @@ public function getSettingsHtml() */ public function getInputHtml($value, ElementInterface $element = null): string { + $settings = Plugin::getInstance()->getSettings(); $group = Plugin::getInstance()->getSettings()->buttonGroups[$this->configHandle]; + if ($settings->cssUrl !== '') { + Craft::$app->getView()->registerCssFile($settings->cssUrl); + } + $buttons = []; foreach ($group['buttons'] as $handle => $button) { $buttons[$handle] = array_merge($this->defaultButton, $button); - if ($buttons[$handle]['image'] != '') { - $buttons[$handle]['image'] = Craft::$app->assetManager->getPublishedUrl($buttons[$handle]['image'], true); + if ($buttons[$handle]['image'] !== '') { + $buttons[$handle]['image'] = Craft::$app->assetManager->getPublishedUrl($buttons[$handle]['image'], false); } } Craft::$app->getView()->registerAssetBundle(ButtonsAssets::class); Craft::$app->getView()->registerAssetBundle(CustomAssets::class); - return Craft::$app->getView()->renderTemplate('buttons/input', - [ - 'name' => $this->handle, - 'value' => $value, - 'field' => $this, - 'buttons' => $buttons, - ]); + return Craft::$app->getView()->renderTemplate('buttons/input', [ + 'name' => $this->handle, + 'value' => $value, + 'field' => $this, + 'buttons' => $buttons, + ]); } /** diff --git a/src/models/Settings.php b/src/models/Settings.php index ae5832a..8621ba7 100644 --- a/src/models/Settings.php +++ b/src/models/Settings.php @@ -6,7 +6,18 @@ class Settings extends Model { + /** + * @var array The config for all button groups + */ public $buttonGroups = []; - public $cssFile = null; + /** + * @var string Optional CSS file to bundle + */ + public $cssFile = ''; + + /** + * @var string Optional URL to an external CSS + */ + public $cssUrl = ''; } diff --git a/src/resources/ButtonsAssets.php b/src/resources/ButtonsAssets.php index ea7270a..cae3f3e 100644 --- a/src/resources/ButtonsAssets.php +++ b/src/resources/ButtonsAssets.php @@ -2,10 +2,8 @@ namespace codemonauts\buttons\resources; -use codemonauts\buttons\Buttons; use craft\web\AssetBundle; use craft\web\assets\cp\CpAsset; -use Craft; class ButtonsAssets extends AssetBundle { diff --git a/src/resources/CustomAssets.php b/src/resources/CustomAssets.php index 6ad44f4..883309d 100644 --- a/src/resources/CustomAssets.php +++ b/src/resources/CustomAssets.php @@ -9,11 +9,14 @@ class CustomAssets extends AssetBundle { + /** + * @inheritDoc + */ public function init() { $cssFile = Buttons::getInstance()->getSettings()->cssFile; - if ($cssFile != '') { + if ($cssFile !== '') { $file = Craft::getAlias($cssFile); $this->sourcePath = pathinfo($file, PATHINFO_DIRNAME); diff --git a/src/translations/de/buttons.php b/src/translations/de/buttons.php index 52fe85f..2bc7b9b 100644 --- a/src/translations/de/buttons.php +++ b/src/translations/de/buttons.php @@ -2,13 +2,5 @@ return [ 'Customizable Radio Buttons' => 'Individuelle Radio-Buttons', - 'Top left' => 'Oben links', - 'Top center' => 'Oben zentriert', - 'Top right' => 'Oben rechts', - 'Middle left' => 'Links', - 'Middle center' => 'Zentriert', - 'Middle right' => 'Rechts', - 'Bottom left' => 'Unten links', - 'Bottom center' => 'Unten zentriert', - 'Bottom right' => 'Unten rechts', + 'Button group' => 'Schalterkonfiguration', ];