diff --git a/CHANGELOG.md b/CHANGELOG.md index 3742d31..080f80b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ -# Changelog +### Changelog -## 0.1.0 +All notable changes to this project will be documented in this file. Dates are displayed in UTC. -- Initial release +Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). + +#### [0.2.0](https://github.com/eea/volto-call-to-action-block/compare/0.1.0...0.2.0) + +- Release 0.2.0 [`ae6c18d`](https://github.com/eea/volto-call-to-action-block/commit/ae6c18d84f502829f254ac62d0792040a9854418) +- Add cypress basic tests [`fd5b04b`](https://github.com/eea/volto-call-to-action-block/commit/fd5b04b43cfcd01e6ddd32b7c16e5db4a8cadb22) +- Cleanup: style defaults [`f682eca`](https://github.com/eea/volto-call-to-action-block/commit/f682eca484fe3aab0ab7ab774115df6548290f41) +- Update docs [`7f8d80b`](https://github.com/eea/volto-call-to-action-block/commit/7f8d80bb7b18ec989ab47dbf2f62fc966a022e50) +- i18n [`63b55e1`](https://github.com/eea/volto-call-to-action-block/commit/63b55e17d2136f01d4c7e6bb8d9886d751d0cbc4) +- Fix style [`6a35058`](https://github.com/eea/volto-call-to-action-block/commit/6a35058703fd5b67401562ed1f1c3fc4f855b61b) +- Add labeled icon and some cleanup [`88a331f`](https://github.com/eea/volto-call-to-action-block/commit/88a331ffb1d8814c2e2b4abfd09b7e69e2895014) +- i18n [`0f965c0`](https://github.com/eea/volto-call-to-action-block/commit/0f965c0d8f16b1e8354c60631463f2d57c40fe23) +- Cleanup and use enableStyling / custom stylesSchema: [`1453f98`](https://github.com/eea/volto-call-to-action-block/commit/1453f98109626760271cdbff519ef9f831345ce9) +- Add button [`8e1a17f`](https://github.com/eea/volto-call-to-action-block/commit/8e1a17f2f622e501348697b1d80216d1219c3c4e) + +#### 0.1.0 + +> 31 May 2022 + +- Initial commit [`00f39c8`](https://github.com/eea/volto-call-to-action-block/commit/00f39c8a36327a821cc613a772bf228451a71e67) diff --git a/Jenkinsfile b/Jenkinsfile index b622053..8a4c878 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -184,10 +184,10 @@ pipeline { unstash "xunit-reports" unstash "cypress-coverage" def scannerHome = tool 'SonarQubeScanner'; - def nodeJS = tool 'NodeJS11'; + def nodeJS = tool 'NodeJS'; withSonarQubeEnv('Sonarqube') { sh '''sed -i "s#/opt/frontend/my-volto-project/src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info''' - sh "export PATH=$PATH:${scannerHome}/bin:${nodeJS}/bin; sonar-scanner -Dsonar.javascript.lcov.reportPaths=./xunit-reports/coverage/lcov.info,./cypress-coverage/coverage/lcov.info -Dsonar.sources=./src -Dsonar.projectKey=$GIT_NAME-$BRANCH_NAME -Dsonar.projectVersion=$BRANCH_NAME-$BUILD_NUMBER" + sh "export PATH=${scannerHome}/bin:${nodeJS}/bin:$PATH; sonar-scanner -Dsonar.javascript.lcov.reportPaths=./xunit-reports/coverage/lcov.info,./cypress-coverage/coverage/lcov.info -Dsonar.sources=./src -Dsonar.projectKey=$GIT_NAME-$BRANCH_NAME -Dsonar.projectVersion=$BRANCH_NAME-$BUILD_NUMBER" sh '''try=2; while [ \$try -gt 0 ]; do curl -s -XPOST -u "${SONAR_AUTH_TOKEN}:" "${SONAR_HOST_URL}api/project_tags/set?project=${GIT_NAME}-${BRANCH_NAME}&tags=${SONARQUBE_TAGS},${BRANCH_NAME}" > set_tags_result; if [ \$(grep -ic error set_tags_result ) -eq 0 ]; then try=0; else cat set_tags_result; echo "... Will retry"; sleep 60; try=\$(( \$try - 1 )); fi; done''' } } @@ -238,8 +238,4 @@ pipeline { } } } -} - } - } - } } diff --git a/README.md b/README.md index 2c110de..d1f83eb 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,11 @@ [![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-call-to-action-block-develop&metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-call-to-action-block-develop) -[Volto](https://github.com/plone/volto) add-on +[Volto](https://github.com/plone/volto) Call to Action Block ## Features -Demo GIF +![Call to Action](https://github.com/eea/volto-call-to-action-block/raw/develop/docs/call-to-action.gif) ## Getting started diff --git a/cypress/integration/block-basics.js b/cypress/integration/block-basics.js index 2b90366..00ad09b 100644 --- a/cypress/integration/block-basics.js +++ b/cypress/integration/block-basics.js @@ -16,8 +16,8 @@ describe('Blocks Tests', () => { // Add block cy.get('.ui.basic.icon.button.block-add-button').first().click(); - cy.get('.blocks-chooser .title').contains('Media').click(); - cy.get('.content.active.media .button.image').contains('Image').click(); + cy.get('.blocks-chooser .title').contains('Common').click(); + cy.get('.content.active.common .button.callToActionBlock').contains('Call to Action').click(); // Save cy.get('#toolbar-save').click(); @@ -25,6 +25,6 @@ describe('Blocks Tests', () => { // then the page view should contain our changes cy.contains('My Add-on Page'); - cy.get('.block.image'); + cy.get('.block.call-to-action'); }); }); diff --git a/docs/call-to-action.gif b/docs/call-to-action.gif new file mode 100644 index 0000000..3ee286c Binary files /dev/null and b/docs/call-to-action.gif differ diff --git a/locales/volto.pot b/locales/volto.pot index e69de29..2b4d00b 100644 --- a/locales/volto.pot +++ b/locales/volto.pot @@ -0,0 +1,95 @@ +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"POT-Creation-Date: 2022-05-31T18:04:15.692Z\n" +"Last-Translator: Plone i18n \n" +"Language-Team: Plone i18n \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"Language-Code: en\n" +"Language-Name: English\n" +"Preferred-Encodings: utf-8\n" +"Domain: volto\n" + +#: components/Schema +# defaultMessage: Alignment +msgid "Alignment" +msgstr "" + +#: components/Edit +#: components/Schema +# defaultMessage: Call to Action +msgid "Call to Action" +msgstr "" + +#: components/Schema +# defaultMessage: Click here +msgid "Click here" +msgstr "" + +#: components/Schema +# defaultMessage: Icon +msgid "Icon" +msgstr "" + +#: components/Schema +# defaultMessage: Icon on the right +msgid "Icon on the right" +msgstr "" + +#: components/Schema +# defaultMessage: Inverted +msgid "Inverted" +msgstr "" + +#: components/Schema +# defaultMessage: Link +msgid "Link" +msgstr "" + +#: components/Schema +# defaultMessage: Open in new window +msgid "Open in new window" +msgstr "" + +#: components/Schema +# defaultMessage: undefined +msgid "Open in parent window / frame" +msgstr "" + +#: components/Schema +# defaultMessage: Open in this window / frame +msgid "Open in this window / frame" +msgstr "" + +#: components/Schema +# defaultMessage: Open in top frame (replaces all frames) +msgid "Open in top frame (replaces all frames)" +msgstr "" + +#: components/Schema +# defaultMessage: Primary +msgid "Primary" +msgstr "" + +#: components/Schema +# defaultMessage: Secondary +msgid "Secondary" +msgstr "" + +#: components/Schema +# defaultMessage: Target +msgid "Target" +msgstr "" + +#: components/Schema +# defaultMessage: Text +msgid "Text" +msgstr "" + +#: components/Schema +# defaultMessage: Theme +msgid "Theme" +msgstr "" diff --git a/package.json b/package.json index ddd5fb8..6a4fb00 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eeacms/volto-call-to-action-block", - "version": "0.1.0", + "version": "0.2.0", "description": "@eeacms/volto-call-to-action-block: Volto add-on", "main": "src/index.js", "author": "European Environment Agency: IDM2 A-Team", @@ -16,10 +16,9 @@ "type": "git", "url": "git@github.com:eea/volto-call-to-action-block.git" }, - "dependencies": { - "@plone/scripts": "*" - }, + "dependencies": {}, "devDependencies": { + "@plone/scripts": "*", "@cypress/code-coverage": "^3.9.5", "babel-plugin-transform-class-properties": "^6.24.1" }, diff --git a/src/components/Edit.jsx b/src/components/Edit.jsx new file mode 100644 index 0000000..f2aa091 --- /dev/null +++ b/src/components/Edit.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { SidebarPortal, BlockDataForm } from '@plone/volto/components'; +import { defineMessages } from 'react-intl'; +import { EditSchema } from './Schema'; +import View from './View'; + +const messages = defineMessages({ + Type: { + id: 'Call to Action', + defaultMessage: 'Call to Action', + }, +}); + +const Edit = (props) => { + const { data, block, onChangeBlock, selected, intl } = props; + const schema = EditSchema({ intl }); + return ( + <> + + + { + onChangeBlock(block, { + ...data, + [id]: value, + }); + }} + formData={data} + fieldIndex={data.index} + block={block} + /> + + + ); +}; + +export default Edit; diff --git a/src/components/Schema.js b/src/components/Schema.js new file mode 100644 index 0000000..b1ca670 --- /dev/null +++ b/src/components/Schema.js @@ -0,0 +1,146 @@ +import { defineMessages } from 'react-intl'; + +const messages = defineMessages({ + Type: { + id: 'Call to Action', + defaultMessage: 'Call to Action', + }, + Label: { + id: 'Label', + defaultMessage: 'Label', + }, + Link: { + id: 'Link', + defaultMessage: 'Link', + }, + Icon: { + id: 'Icon', + defaultMessage: 'Icon', + }, + IconRight: { + id: 'Icon on the right', + defaultMessage: 'Icon on the right', + }, + Align: { + id: 'Alignment', + defaultMessage: 'Alignment', + }, + Theme: { + id: 'Theme', + defaultMessage: 'Theme', + }, + ThemePrimary: { + id: 'Primary', + defaultMessage: 'Primary', + }, + ThemeSecondary: { + id: 'Secondary', + defaultMessage: 'Secondary', + }, + ThemeLink: { + id: 'Link', + defaultMessage: 'Link', + }, + Inverted: { + id: 'Inverted', + defaultMessage: 'Inverted', + }, + DefaultLabel: { + id: 'Click here', + defaultMessage: 'Click here', + }, + Target: { + id: 'Target', + defaultMessage: 'Target', + }, + TargetEmpty: { + id: 'Open in this window / frame', + defaultMessage: 'Open in this window / frame', + }, + TargetBlank: { + id: 'Open in new window', + defaultMessage: 'Open in new window', + }, + TargetParent: { + id: 'Open in parent window / frame', + defineMessages: 'Open in parent window / frame', + }, + TargetTop: { + id: 'Open in top frame (replaces all frames)', + defaultMessage: 'Open in top frame (replaces all frames)', + }, +}); + +export const EditSchema = ({ intl }) => ({ + title: intl.formatMessage(messages.Type), + block: 'callToAction', + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['text', 'href', 'target'], + }, + ], + + properties: { + text: { + title: intl.formatMessage(messages.Label), + default: intl.formatMessage(messages.DefaultLabel), + }, + href: { + title: intl.formatMessage(messages.Link), + widget: 'object_browser', + mode: 'link', + selectedItemAttrs: ['Title', 'Description', 'hasPreviewImage'], + allowExternals: true, + }, + target: { + title: intl.formatMessage(messages.Target), + choices: [ + ['_self', intl.formatMessage(messages.TargetEmpty)], + ['_blank', intl.formatMessage(messages.TargetBlank)], + ['_parent', intl.formatMessage(messages.TargetParent)], + ['_top', intl.formatMessage(messages.TargetTop)], + ], + }, + }, + required: [], +}); + +export const StylingSchema = ({ intl }) => ({ + title: intl.formatMessage(messages.Type), + block: 'callToAction', + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['align', 'theme', 'inverted', 'icon', 'rightIcon'], + }, + ], + properties: { + align: { + title: intl.formatMessage(messages.Align), + widget: 'align', + }, + theme: { + title: intl.formatMessage(messages.Theme), + choices: [ + ['primary', intl.formatMessage(messages.ThemePrimary)], + ['secondary', intl.formatMessage(messages.ThemeSecondary)], + ['link', intl.formatMessage(messages.ThemeLink)], + ], + }, + inverted: { + title: intl.formatMessage(messages.Inverted), + type: 'boolean', + }, + icon: { + title: intl.formatMessage(messages.Icon), + }, + rightIcon: { + title: intl.formatMessage(messages.IconRight), + type: 'boolean', + }, + }, + required: [], +}); diff --git a/src/components/View.jsx b/src/components/View.jsx new file mode 100644 index 0000000..0361dde --- /dev/null +++ b/src/components/View.jsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { Icon } from 'semantic-ui-react'; +import cx from 'classnames'; +import { Link } from 'react-router-dom'; +import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers'; + +const View = ({ data, isEditMode }) => { + const [hasLink, setHasLink] = React.useState(false); + + React.useEffect(() => { + if (isEditMode) { + setHasLink(false); + } else { + if (data.href) { + if (data.href && data.href.length > 0) { + setHasLink(true); + } + if (data.href.length === 0) { + setHasLink(false); + } + } + } + }, [isEditMode, data.href]); + + const As = hasLink && isInternalURL(data.href[0]['@id']) ? Link : 'a'; + + return ( +
+ + {data.styles?.icon && } + {data.text} + +
+ ); +}; + +export default View; diff --git a/src/index.js b/src/index.js index cb042f0..c639d7c 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,29 @@ +import callToActionSVG from '@plone/volto/icons/circle-right.svg'; +import Edit from './components/Edit'; +import View from './components/View'; +import { StylingSchema, EditSchema } from './components/Schema'; + +import './theme/main.less'; + const applyConfig = (config) => { + config.blocks.blocksConfig.callToActionBlock = { + id: 'callToActionBlock', + title: 'Call to Action', + icon: callToActionSVG, + group: 'common', + view: View, + edit: Edit, + editSchema: EditSchema, + stylesSchema: StylingSchema, + restricted: false, + mostUsed: false, + sidebarTab: 1, + enableStyling: true, + security: { + addPermission: [], + view: [], + }, + }; return config; }; diff --git a/src/theme/main.less b/src/theme/main.less new file mode 100644 index 0000000..70d4938 --- /dev/null +++ b/src/theme/main.less @@ -0,0 +1,23 @@ +.block.call-to-action { + text-align: center; + + &.align { + &.right { + text-align: right; + } + + &.left { + text-align: left; + } + + &.center { + text-align: center; + } + + &.full { + a { + width: 100%; + } + } + } +}