Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IMP] website: improve configurator logo upload #145047

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { delay } from "@web/core/utils/concurrency";
import { getDataURLFromFile } from "@web/core/utils/urls";
Guillaume-gdi marked this conversation as resolved.
Show resolved Hide resolved
import weUtils from '@web_editor/js/common/utils';
import { _t } from "@web/core/l10n/translation";
import {svgToPNG} from '@website/js/utils';
import { svgToPNG, webpToPNG } from "@website/js/utils";
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { mixCssColors } from '@web/core/utils/colors';
Expand Down Expand Up @@ -235,9 +235,27 @@ class PaletteSelectionScreen extends Component {
this.logoInputRef.el.click();
}

/**
* Removes the previously uploaded logo.
*
* @param {Event} ev
*/
async removeLogo(ev) {
ev.stopPropagation();
// Permit to trigger onChange even with the same file.
this.logoInputRef.el.value = "";
if (this.state.logoAttachmentId) {
await this._removeAttachments([this.state.logoAttachmentId]);
}
this.state.changeLogo();
// Remove recommended palette.
this.state.setRecommendedPalette();
}

async changeLogo() {
Guillaume-gdi marked this conversation as resolved.
Show resolved Hide resolved
Guillaume-gdi marked this conversation as resolved.
Show resolved Hide resolved
const logoSelectInput = this.logoInputRef.el;
if (logoSelectInput.files.length === 1) {
const previousLogoAttachmentId = this.state.logoAttachmentId;
const file = logoSelectInput.files[0];
const data = await getDataURLFromFile(file);
const attachment = await this.rpc('/web_editor/attachment/add_data', {
Expand All @@ -246,6 +264,9 @@ class PaletteSelectionScreen extends Component {
'is_image': true,
});
if (!attachment.error) {
if (previousLogoAttachmentId) {
await this._removeAttachments([previousLogoAttachmentId]);
}
this.state.changeLogo(data, attachment.id);
this.updatePalettes();
} else {
Expand All @@ -264,6 +285,9 @@ class PaletteSelectionScreen extends Component {
if (img.startsWith('data:image/svg+xml')) {
img = await svgToPNG(img);
}
if (img.startsWith('data:image/webp')) {
img = await webpToPNG(img);
}
img = img.split(',')[1];
const [color1, color2] = await this.orm.call('base.document.layout',
'extract_image_primary_secondary_colors',
Expand All @@ -277,6 +301,16 @@ class PaletteSelectionScreen extends Component {
this.state.selectPalette(paletteName);
this.props.navigate(ROUTES.featuresSelectionScreen);
}

/**
* Removes the attachments from the DB.
*
* @private
* @param {Array<number>} ids the attachment ids to remove
*/
async _removeAttachments(ids) {
this.rpc("/web_editor/attachment/remove", { ids: ids });
}
}

Object.assign(PaletteSelectionScreen, {
Expand Down Expand Up @@ -556,6 +590,7 @@ class Store {
} else {
this.recommendedPalette = undefined;
}
this.selectedPalette = this.recommendedPalette;
}

updateRecommendedThemes(themes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
<div t-if="state.logo" class="o_configurator_logo_wrapper position-absolute d-flex justify-content-center align-items-center bg-white w-100 h-100">
<img style="height: 120px" t-attf-src="{{state.logo}}"/>
</div>
<i t-if="state.logo" class="fa fa-2x fa-times-circle text-danger position-absolute top-0 end-0 pe-2 pt-2" t-on-click="removeLogo"/>
Guillaume-gdi marked this conversation as resolved.
Show resolved Hide resolved
</div>
<div t-if="state.recommendedPalette" class="w-75 mx-auto px-2 pt-3" style="max-width: 184px;">
<div t-attf-class="palette_card rounded-pill overflow-hidden d-flex {{state.getSelectedPaletteName() == 'recommendedPalette' ? 'selected' : ''}}"
Expand Down
29 changes: 28 additions & 1 deletion addons/website/static/src/js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,32 @@ function sendRequest(route, params) {
* @returns {Promise<string>} a base64 PNG (as result of a Promise)
*/
export async function svgToPNG(src) {
return _exportToPNG(src, "svg+xml");
}

/**
* Converts a base64 WEBP into a base64 PNG.
*
* @param {string|HTMLImageElement} src - an URL to a WEBP or a *loaded* image
* with such an URL. This allows the call to potentially be a bit more
* efficient in that second case.
* @returns {Promise<string>} a base64 PNG (as result of a Promise)
*/
export async function webpToPNG(src) {
return _exportToPNG(src, "webp");
}

/**
* Converts a formatted base64 image into a base64 PNG.
*
* @private
* @param {string|HTMLImageElement} src - an URL to a image or a *loaded* image
* with such an URL. This allows the call to potentially be a bit more
* efficient in that second case.
* @param {string} format - the format of the image
* @returns {Promise<string>} a base64 PNG (as result of a Promise)
*/
async function _exportToPNG(src, format) {
Guillaume-gdi marked this conversation as resolved.
Show resolved Hide resolved
function checkImg(imgEl) {
// Firefox does not support drawing SVG to canvas unless it has width
// and height attributes set on the root <svg>.
Expand Down Expand Up @@ -301,7 +327,7 @@ export async function svgToPNG(src) {
return new Promise(resolve => {
const imgEl = new Image();
imgEl.onload = () => {
if (checkImg(imgEl)) {
if (format !== "svg+xml" || checkImg(imgEl)) {
resolve(imgEl);
return;
}
Expand Down Expand Up @@ -397,6 +423,7 @@ export default {
websiteDomain: websiteDomain,
isHTTPSorNakedDomainRedirection: isHTTPSorNakedDomainRedirection,
svgToPNG: svgToPNG,
webpToPNG: webpToPNG,
generateGMapIframe: generateGMapIframe,
generateGMapLink: generateGMapLink,
isMobile: isMobile,
Expand Down