diff --git a/.docs/images/netlify_plugin.png b/.docs/images/netlify_plugin.png index 64e212a..d3f9230 100644 Binary files a/.docs/images/netlify_plugin.png and b/.docs/images/netlify_plugin.png differ diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..18d2a96 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + "recommendations": [ + // code quality plugins + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + + // plugin that helps with html strings in js files + "tobermory.es6-string-html" + ] +} diff --git a/common/plugin-element-cache.js b/common/plugin-element-cache.js index 8c66934..eb43a2c 100644 --- a/common/plugin-element-cache.js +++ b/common/plugin-element-cache.js @@ -6,13 +6,11 @@ export const addElementToCache = (element, key, data = {}) => { data, }; - setTimeout( - () => - element.addEventListener('flotiq.detached', () => { - delete appRoots[key]; - }), - 50, - ); + element.addEventListener('flotiq.detached', () => { + setTimeout(() => { + return delete appRoots[key]; + }, 50); + }); }; export const getCachedElement = (key) => { diff --git a/common/plugin-helpers.js b/common/plugin-helpers.js new file mode 100644 index 0000000..7e512e8 --- /dev/null +++ b/common/plugin-helpers.js @@ -0,0 +1,28 @@ +/** + * Read key value deep inside object + * @param {string} key + * @param {object} object + * @returns {*} example: read 'object[0].key' from 'object: [{key: value}] + */ +export const deepReadKeyValue = (key, object) => { + return key + .split(/[[.\]]/) + .filter((kp) => !!kp) + .reduce((nestedOptions, keyPart) => { + return nestedOptions?.[keyPart]; + }, object); +}; + +/** + * Generate string based on tempalte and object with values + * + * @param {string} value - template string with keys in {{}} + * @param {*} object - object with values + * @returns {string} + */ +export const getKeyPattern = (value, object) => { + return value.replace(/{(?[^{}]+)}/g, (...params) => { + const { key } = params[4]; + return deepReadKeyValue(key, object) || ''; + }); +}; diff --git a/package.json b/package.json index 9556ae4..2249383 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "chalk": "^5.3.0", - "esbuild-plugin-copy": "^2.1.1" + "esbuild-plugin-copy": "^2.1.1", + "semver": "^7.6.2" } } diff --git a/plugin-manifest.json b/plugin-manifest.json index d06b765..1cbb9fb 100644 --- a/plugin-manifest.json +++ b/plugin-manifest.json @@ -2,7 +2,7 @@ "id": "flotiq.deploy-netlify", "name": "Deploy Netlify", "description": "Integration with Netlify deploy. With this plugin, you can easily trigger Netlify builds within Content Object changes on form submission. You will also be able to quickly navigate to your Netlify pages from the Flotiq content editor.", - "version": "1.1.2", + "version": "1.1.3", "repository": "https://github.com/flotiq/flotiq-ui-plugin-deploy-netlify", "url": "https://localhost:3053/index.js", "permissions": [] diff --git a/plugins/build-handler.js b/plugins/build-handler.js new file mode 100644 index 0000000..e6ed9ea --- /dev/null +++ b/plugins/build-handler.js @@ -0,0 +1,67 @@ +import { getKeyPattern } from '../common/plugin-helpers'; + +/** + * + * @param {object} buttonSettings + * @param {*} contentObject + * @param {string} id + * @returns + */ +export const onBuildHandler = (buttonSettings, contentObject, id) => { + const buildWebhookURL = getKeyPattern( + buttonSettings?.build_webhook_url, + contentObject, + ); + const buildInstance = getKeyPattern( + buttonSettings?.build_instance_url, + contentObject, + ); + const buttonId = `${id}-button`; + const statusBoxId = `${id}-status`; + + const statusMessageContainer = document.getElementById(statusBoxId); + const buttonElement = document.getElementById(buttonId); + + const updateStatus = (message) => { + statusMessageContainer.innerHTML = message; + }; + + const pluginLink = /* html */ ` + + Go to page: ${buildInstance} + + `; + + if (!buildWebhookURL) { + updateStatus(pluginLink); + return; + } else { + updateStatus('Updating preview link...'); + } + + buttonElement.disabled = true; + buttonElement.classList.add('plugin-deploy-netlify__button--loading'); + return fetch(buildWebhookURL, { + mode: 'no-cors', + method: 'POST', + body: JSON.stringify(contentObject), + headers: { + 'content-type': 'application/json;charset=UTF-8', + }, + }) + .then(() => updateStatus(pluginLink)) + .catch((error) => { + if (error.message) { + updateStatus(error.message); + } else { + updateStatus('Failed to fetch'); + } + }) + .finally(() => { + buttonElement.disabled = false; + buttonElement.classList.remove('plugin-deploy-netlify__button--loading'); + }); +}; diff --git a/plugins/form-submit/index.js b/plugins/form-submit/index.js index 3ed2f88..c7f0596 100644 --- a/plugins/form-submit/index.js +++ b/plugins/form-submit/index.js @@ -1,44 +1,29 @@ -export const handleAfterSubmitPlugin = ( - { success, contentObject }, - toast, - getPluginSettings, -) => { +import { onBuildHandler } from '../build-handler'; + +export const handleAfterSubmitPlugin = (data, getPluginSettings) => { + const { success, contentObject } = data; const ctdName = contentObject?.internal?.contentType; - const settings = getPluginSettings(); + const netlifySettings = getPluginSettings(); + + if (!success || !ctdName || !netlifySettings) return; - if (!success || !ctdName || !settings) return; + const settings = JSON.parse(netlifySettings); - const settingsForCtd = JSON.parse(settings)?.builds?.filter( - (plugin) => - plugin.content_types.length === 0 || - plugin.content_types.find((ctd) => ctd === ctdName), - ); + const settingsForCtd = settings?.builds + ?.filter( + (buttonSettings) => + buttonSettings.content_types.length === 0 || + buttonSettings.content_types.find((ctd) => ctd === ctdName), + ) + .filter((buttonSettings) => buttonSettings.build_on_save); - if (!settingsForCtd.length) return null; + if (!settingsForCtd.length) return; - settingsForCtd.map((item) => - fetch(item.build_webhook_url, { - method: `POST`, - body: '{}', - headers: { - 'content-type': 'application/json;charset=UTF-8', - }, - }) - .then(async ({ ok, status }) => { - if (!ok) - throw Error( - `Failed to fetch Netlify build URL: ${item.build_instance_url}. Status: ${status}`, - ); - }) - .catch((error) => { - console.log(error); - if (error.message) { - toast.error(error.message); - } else { - toast.error( - `Failed to fetch Netlify build URL: ${item.build_instance_url}`, - ); - } - }), - ); + settingsForCtd.forEach((buttonSettings, index) => { + onBuildHandler( + buttonSettings, + contentObject, + `netlify-item-child-${index}`, + ); + }); }; diff --git a/plugins/img/netlify-logo-black.png b/plugins/img/netlify-logo-black.png new file mode 100644 index 0000000..b24c2ef Binary files /dev/null and b/plugins/img/netlify-logo-black.png differ diff --git a/plugins/img/netlify-logo-white.png b/plugins/img/netlify-logo-white.png new file mode 100644 index 0000000..0acf3e5 Binary files /dev/null and b/plugins/img/netlify-logo-white.png differ diff --git a/plugins/index.js b/plugins/index.js index a88e054..14e4698 100644 --- a/plugins/index.js +++ b/plugins/index.js @@ -4,22 +4,26 @@ import cssString from 'inline:./sidebar-panel/style/style.css'; import { handlePanelPlugin } from './sidebar-panel'; import { handleManagePlugin } from './manage'; import { handleAfterSubmitPlugin } from './form-submit'; +import { handleMigrate } from './migrations'; -registerFn(pluginInfo, (handler, _, { toast, getPluginSettings }) => { - if (!document.getElementById(`${pluginInfo.id}-styles`)) { - const style = document.createElement('style'); +registerFn(pluginInfo, (handler, _, { getPluginSettings }) => { + let style = document.getElementById(`${pluginInfo.id}-styles`); + if (!style) { + style = document.createElement('style'); style.id = `${pluginInfo.id}-styles`; - style.textContent = cssString; document.head.appendChild(style); } + style.textContent = cssString; handler.on('flotiq.plugins.manage::form-schema', (data) => handleManagePlugin(data, pluginInfo), ); handler.on('flotiq.form.sidebar-panel::add', (data) => - handlePanelPlugin(data, pluginInfo), + handlePanelPlugin(data, getPluginSettings, pluginInfo), ); handler.on('flotiq.form::after-submit', (data) => - handleAfterSubmitPlugin(data, toast, getPluginSettings), + handleAfterSubmitPlugin(data, getPluginSettings, pluginInfo), ); + + handler.on('flotiq.plugin::migrate', handleMigrate); }); diff --git a/plugins/manage/index.js b/plugins/manage/index.js index 3d5bcaa..9feb324 100644 --- a/plugins/manage/index.js +++ b/plugins/manage/index.js @@ -1,3 +1,5 @@ +import { getSettingsSchema } from './settings-schema'; + let configCache = null; export const handleManagePlugin = ( @@ -10,103 +12,11 @@ export const handleManagePlugin = ( const ctds = (contentTypes || []) .filter((ctd) => !ctd.internal || ctd.name === '_media') - .map(({ name }) => name); + .map(({ name, label }) => ({ value: name, label })); configCache = {}; - configCache.schema = { - id: pluginInfo.id, - name: 'netlify_build', - label: 'Netlify build', - workflowId: 'generic', - internal: false, - schemaDefinition: { - type: 'object', - allOf: [ - { - $ref: '#/components/schemas/AbstractContentTypeSchemaDefinition', - }, - { - type: 'object', - properties: { - builds: { - type: 'array', - items: { - type: 'object', - required: ['build_instance_url'], - properties: { - build_instance_url: { - type: 'string', - minLength: 1, - }, - build_webhook_url: { - type: 'string', - }, - content_types: { - type: 'array', - minLength: 1, - }, - displayName: { - type: 'string', - default: 'Build site', - }, - }, - }, - }, - }, - }, - ], - required: [], - additionalProperties: false, - }, - metaDefinition: { - order: ['builds'], - propertiesConfig: { - builds: { - items: { - order: [ - 'build_instance_url', - 'build_webhook_url', - 'displayName', - 'content_types', - ], - propertiesConfig: { - build_instance_url: { - label: 'Build Instance URL', - unique: false, - helpText: '', - inputType: 'text', - }, - build_webhook_url: { - label: 'Build Webhook URL', - unique: false, - helpText: '', - inputType: 'text', - }, - content_types: { - label: 'Content types', - unique: false, - options: ctds, - helpText: '', - inputType: 'select', - isMultiple: true, - }, - displayName: { - label: 'Display name', - unique: false, - helpText: '', - inputType: 'text', - }, - }, - }, - label: 'Builds', - unique: false, - helpText: '', - inputType: 'object', - }, - }, - }, - }; + configCache.schema = getSettingsSchema(pluginInfo, ctds); modalInstance.promise.then(() => (configCache = null)); diff --git a/plugins/manage/settings-schema.js b/plugins/manage/settings-schema.js new file mode 100644 index 0000000..45f1070 --- /dev/null +++ b/plugins/manage/settings-schema.js @@ -0,0 +1,107 @@ +export function getSettingsSchema(pluginInfo, ctds) { + return { + id: pluginInfo.id, + name: 'netlify_build', + label: 'Netlify build', + workflowId: 'generic', + internal: false, + schemaDefinition: { + type: 'object', + allOf: [ + { + $ref: '#/components/schemas/AbstractContentTypeSchemaDefinition', + }, + { + type: 'object', + properties: { + builds: { + type: 'array', + items: { + type: 'object', + required: ['build_instance_url'], + properties: { + build_instance_url: { + type: 'string', + minLength: 1, + }, + build_webhook_url: { + type: 'string', + }, + content_types: { + type: 'array', + }, + displayName: { + type: 'string', + default: 'Build site', + }, + build_on_save: { + type: 'boolean', + default: true, + }, + }, + }, + }, + }, + }, + ], + required: [], + additionalProperties: false, + }, + metaDefinition: { + order: ['builds'], + propertiesConfig: { + builds: { + items: { + order: [ + 'build_instance_url', + 'build_webhook_url', + 'displayName', + 'content_types', + 'build_on_save', + ], + propertiesConfig: { + build_instance_url: { + label: 'Site url', + unique: false, + helpText: '', + inputType: 'text', + }, + build_webhook_url: { + label: 'Build Webhook URL', + unique: false, + helpText: '', + inputType: 'text', + }, + content_types: { + label: 'Content types', + unique: false, + helpText: + 'If the content types are not selected, the button will be shown when editing each content object.', + inputType: 'select', + isMultiple: true, + useOptionsWithLabels: true, + optionsWithLabels: ctds, + }, + displayName: { + label: 'Display name', + unique: false, + helpText: '', + inputType: 'text', + }, + build_on_save: { + label: 'Build automatically on save', + unique: false, + helpText: '', + inputType: 'checkbox', + }, + }, + }, + label: 'Builds', + unique: false, + helpText: '', + inputType: 'object', + }, + }, + }, + }; +} diff --git a/plugins/migrations/index.js b/plugins/migrations/index.js new file mode 100644 index 0000000..9b7531b --- /dev/null +++ b/plugins/migrations/index.js @@ -0,0 +1,36 @@ +import semver from 'semver'; + +const settingsMigrations = [ + { + from: '1.1.2', + to: '1.1.3', + migration: async (settings) => { + settings.builds.forEach((itemSettings) => { + if (typeof itemSettings.build_on_save === 'undefined') { + itemSettings.build_on_save = true; + } + }); + + return settings; + }, + }, +]; + +export const handleMigrate = async ({ previousVersion }) => { + let settings = previousVersion.settings + ? JSON.parse(previousVersion.settings) + : []; + + let versionNumber = previousVersion.version; + let migration; + + const isNext = (m) => + semver.gte(m.from, versionNumber) && semver.lt(versionNumber, m.to); + + while ((migration = settingsMigrations.find(isNext))) { + settings = await migration.migration(settings); + versionNumber = migration.to; + } + + return JSON.stringify(settings); +}; diff --git a/plugins/sidebar-panel/index.js b/plugins/sidebar-panel/index.js index 8d72aa2..7c62230 100644 --- a/plugins/sidebar-panel/index.js +++ b/plugins/sidebar-panel/index.js @@ -2,127 +2,92 @@ import { addElementToCache, getCachedElement, } from '../../common/plugin-element-cache'; - -const onBuildHandler = (data, statusMessageContainer) => { - const buildWebhookURL = data?.build_webhook_url; - const buildInstance = data?.build_instance_url; - - writeMessage('Updating preview link...', statusMessageContainer); - - if (!buildWebhookURL) { - writeMessage( - `Open page (build may be still pending)`, - statusMessageContainer, - ); - return; - } - - return fetch(buildWebhookURL, { - method: `POST`, - body: '{}', - headers: { - 'content-type': 'application/json;charset=UTF-8', - }, - }) - .then(() => { - writeMessage( - `Open page (build may be still pending)`, - statusMessageContainer, - ); - }) - .catch((error) => { - if (error.message) { - writeMessage(error.message, statusMessageContainer); - } else { - writeMessage('Failed to fetch', statusMessageContainer); - } - }); +import { createNetlifyItem, updateNetlifyItem } from './panel-button'; + +const createPanelElement = (cacheKey) => { + const panelElement = document.createElement('div'); + panelElement.classList.add('plugin-deploy-netlify'); + panelElement.id = cacheKey; + panelElement.innerHTML = /*html*/ ` + + Netlify builds + +
+ + `; + + addElementToCache(panelElement, cacheKey); + + return panelElement; }; -const writeMessage = (message, statusMessageContainer) => { - statusMessageContainer.innerHTML = message || ''; - statusMessageContainer.style.display = 'block'; -}; - -const itemNetlify = (data) => { - const pluginContainerItem = document.createElement('div'); - pluginContainerItem.classList.add('plugin-dn-container-item'); - - // :: Status - const statusMessageContainer = document.createElement('div'); - statusMessageContainer.classList.add('plugin-dn-status-message'); - - // :: Button - const pluginButton = document.createElement('button'); - pluginButton.classList.add('plugin-dn-button'); - pluginButton.innerText = data?.displayName || 'Build site'; - pluginButton.onclick = () => onBuildHandler(data, statusMessageContainer); - - // :: Images - const imgLogo = document.createElement('img'); - imgLogo.classList.add('plugin-dn-logo'); - - imgLogo.alt = 'Logo Netlify'; - - // :: Append new elements - pluginContainerItem.appendChild(pluginButton); - pluginContainerItem.appendChild(statusMessageContainer); - pluginContainerItem.appendChild(imgLogo); - - // :: Checking if build instante - const buildInstance = data?.build_instance_url; +const updatePanelElement = ( + pluginContainer, + settingsForCtd, + contentObject, + isCreating, +) => { + const buttonList = pluginContainer.querySelector( + '.plugin-deploy-netlify__button-list', + ); + settingsForCtd.forEach((buttonSettings, index) => { + const itemUniqueID = `netlify-item-child-${index}`; + let htmlItem = buttonList.children[index]; + if (!htmlItem) { + htmlItem = createNetlifyItem(itemUniqueID); + buttonList.appendChild(htmlItem); + } + updateNetlifyItem( + htmlItem, + buttonSettings, + contentObject, + itemUniqueID, + isCreating, + ); + return htmlItem; + }); - if (!buildInstance) { - pluginButton.classList.add('disabled'); - pluginButton.disabled = true; - statusMessageContainer.classList.add('active'); - statusMessageContainer.innerText = - "Can't find build instance url. Check the plugin settings."; + // Remove unnecessary items + while (settingsForCtd.length < buttonList.children.length) { + buttonList.children[buttonList.children.length - 1].remove(); } - - return pluginContainerItem; }; export const handlePanelPlugin = ( - { contentType, contentObject, userPlugins }, + { contentType, contentObject, create, duplicate }, + getPluginSettings, pluginInfo, ) => { - const netlifySettings = userPlugins?.find( - ({ id }) => id === pluginInfo.id, - )?.settings; + const netlifySettings = getPluginSettings(); if (!netlifySettings) return null; + const settings = JSON.parse(netlifySettings); - const settingsForCtd = JSON.parse(netlifySettings)?.builds?.filter( + const settingsForCtd = settings?.builds?.filter( (plugin) => plugin.content_types.length === 0 || plugin.content_types.find((ctd) => ctd === contentType?.name), ); if (!settingsForCtd.length) return null; + const isCreating = duplicate || create; const cacheKey = `${pluginInfo.id}-${contentType?.name}-${ - contentObject?.id || 'new' + isCreating ? contentObject?.id : 'new' }`; let pluginContainer = getCachedElement(cacheKey)?.element; if (!pluginContainer) { - pluginContainer = document.createElement('div'); - pluginContainer.classList.add('plugin-dn-container'); - - const headerElement = document.createElement('span'); - headerElement.classList.add('plugin-dn-header'); - headerElement.id = 'plugin-dn-header'; - headerElement.innerText = 'Netlify Builds'; - - pluginContainer.appendChild(headerElement); - - const items = settingsForCtd.map((item) => itemNetlify(item)); - pluginContainer.append(...items); - - addElementToCache(pluginContainer, cacheKey); + pluginContainer = createPanelElement(cacheKey); } + updatePanelElement( + pluginContainer, + settingsForCtd, + contentObject, + isCreating, + ); + return pluginContainer; }; diff --git a/plugins/sidebar-panel/panel-button.js b/plugins/sidebar-panel/panel-button.js new file mode 100644 index 0000000..7e98993 --- /dev/null +++ b/plugins/sidebar-panel/panel-button.js @@ -0,0 +1,76 @@ +import { getKeyPattern } from '../../common/plugin-helpers'; +import { onBuildHandler } from '../build-handler'; + +export const updateNetlifyItem = ( + htmlElement, + buttonSettings, + contentObject, + id, + isCreating, +) => { + const buildInstance = getKeyPattern( + buttonSettings?.build_instance_url, + contentObject, + ); + const buttonLabel = getKeyPattern( + buttonSettings?.displayName || 'Build site', + contentObject, + ); + const buildWebhookURL = getKeyPattern( + buttonSettings?.build_webhook_url, + contentObject, + ); + + const pluginButton = htmlElement.querySelector( + '.plugin-deploy-netlify__button', + ); + const statusMessageContainer = htmlElement.querySelector( + '.plugin-deploy-netlify__status-message', + ); + + // :: Update button label and onclick handler + pluginButton.innerText = buttonLabel; + pluginButton.onclick = () => + onBuildHandler(buttonSettings, contentObject, id); + + // :: Disable button if object is not yet saved + pluginButton.disabled = isCreating || !buildWebhookURL; + + const updateInProgress = pluginButton.classList.contains( + 'plugin-deploy-netlify__button--loading', + ); + + // do not update status message if update is in progress + if (updateInProgress) { + return; + } + // :: Message + if (buildInstance && !isCreating) { + statusMessageContainer.innerHTML = /*html*/ ` + + Go to page: ${buildInstance} + + `; + } else if (isCreating) { + statusMessageContainer.innerText = buildWebhookURL + ? 'Save the object to build site' + : ''; + } +}; + +export const createNetlifyItem = (id) => { + const pluginContainerItem = document.createElement('div'); + pluginContainerItem.classList.add('plugin-deploy-netlify__item'); + + pluginContainerItem.innerHTML = /* html */ ` + +
+ `; + + return pluginContainerItem; +}; diff --git a/plugins/sidebar-panel/style/style.css b/plugins/sidebar-panel/style/style.css index b367df8..50b5fea 100644 --- a/plugins/sidebar-panel/style/style.css +++ b/plugins/sidebar-panel/style/style.css @@ -1,6 +1,5 @@ -/* Section Container */ - -.plugin-dn-container { +/* Panel Container */ +.plugin-deploy-netlify { background: white; display: flex; flex-direction: column; @@ -8,103 +7,103 @@ border-radius: 0.5rem; } -.plugin-dn-container-item { +.plugin-deploy-netlify__item { display: flex; flex-direction: column; padding: 0 20px; } -/* Section Header */ - -.plugin-dn-header { +/* Panel Header */ +.plugin-deploy-netlify__header { font-weight: 700; font-size: 16px; + margin-bottom: 1rem; } -/* Section Button */ - -.plugin-dn-button { +/* Panel Button */ +.plugin-deploy-netlify__button { text-align: center; border: 2px solid rgb(0, 199, 183); - margin: 20px 0px 10px 0px; + border-radius: 0.5rem; + margin: 5px 0px 10px 0px; cursor: pointer; padding: 5px 20px; + position: relative; } -.plugin-dn-button.disabled { - border-color: silver; - opacity: 0.6; - cursor: auto; -} - -.plugin-dn-button:hover { +.plugin-deploy-netlify__button:hover { opacity: 0.8; } -.plugin-dn-button.disabled { +.plugin-deploy-netlify__button[disabled] { border-color: silver; - opacity: 0.6; + opacity: 0.3; cursor: auto; + pointer-events: none; + position: relative; } -/* Section Logo */ +.plugin-deploy-netlify__button.plugin-deploy-netlify__button--loading:after { + content: ' '; + border: 2px solid #f3f3f3; + -webkit-animation: spin 1s linear infinite; + animation: spin 1s linear infinite; + border-top: 2px solid #0083fc; + border-radius: 50%; + width: 20px; + height: 20px; + position: absolute; + right: 10px; +} -.plugin-dn-logo { +/* Panel Logo */ +.plugin-deploy-netlify__logo { width: 90px; + margin-top: 5px; margin-left: auto; pointer-events: none; - content: url('https://api.flotiq.com/image/0x0/_media-84001101-c254-4879-b77f-cc47ff9b0051.png'); + content: url('../../img/netlify-logo-black.png'); } -/* Section Status Message */ - -.plugin-dn-status-message { +/* Panel Button Status Message */ +.plugin-deploy-netlify__status-message { font-size: 12px; color: rgb(134, 134, 134); margin-bottom: 10px; - display: none; -} - -.plugin-dn-status-message.active { - display: block; } -/* Section Link Preview */ -.plugin-dn-link { +/* Panel Button Link Preview */ +.plugin-deploy-netlify__link { color: -webkit-link; cursor: pointer; text-decoration: underline; } -.plugin-dn-link:hover { +.plugin-deploy-netlify__link:hover { opacity: 0.8; } /* Theme: dark */ -.mode-dark .plugin-dn-container { +.mode-dark .plugin-deploy-netlify { background: #020617; } -.mode-dark .plugin-dn-header { - color: white; -} - -.mode-dark plugin-dn-button { +.mode-dark .plugin-deploy-netlify__header { color: white; } -.mode-dark .plugin-dn-button { +.mode-dark .plugin-deploy-netlify__button { color: white; } -.mode-dark .plugin-dn-link { +.mode-dark .plugin-deploy-netlify__link { color: #0083fc; } -.mode-dark .plugin-dn-status-message { +.mode-dark .plugin-deploy-netlify__status-message { color: #e3e3e3; } -.mode-dark .plugin-dn-logo { - content: url('https://api.flotiq.com/image/0x0/_media-087ddee7-4769-495a-89e0-43d539206922.png'); +.mode-dark .plugin-deploy-netlify__logo { + content: url('../../img/netlify-logo-white.png'); } diff --git a/yarn.lock b/yarn.lock index 042cc78..76be494 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1022,6 +1022,11 @@ semver@^6.0.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.6.2: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"