Add logo preview to creator settings form (#15363)

This commit is contained in:
Nick Taylor 2021-11-18 12:23:24 -05:00 committed by GitHub
parent ef83f0b07b
commit ca0db28fc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 121 additions and 14 deletions

View file

@ -18,6 +18,11 @@ body.default-header {
background: white;
}
[data-creator-settings-target='previewLogo'] {
max-height: 80px;
height: 80px;
}
// This ID is tied the global "Setup not complete" banner
// and is necessary for the removal of the banner on the
// Creator Settings page

View file

@ -28,6 +28,7 @@ module.exports = {
'@crayons': path.join(__dirname, './crayons'),
'@utilities': path.join(__dirname, './utilities'),
'@components': path.join(__dirname, './shared/components'),
'@admin-controllers': path.join(__dirname, './admin/controllers'),
},
extensions: ['.js', '.jsx'],
},

View file

@ -0,0 +1,70 @@
import { Controller } from '@hotwired/stimulus';
const MAX_LOGO_PREVIEW_HEIGHT = 80;
const MAX_LOGO_PREVIEW_WIDTH = 220;
/**
* Manages interactions on the Creator Settings page.
*/
export class CreatorSettingsController extends Controller {
static targets = ['previewLogo'];
/**
* Displays a preview of the image selected by the user.
*
* @param {Event} event
*/
previewLogo(event) {
const {
target: {
files: [firstFile],
},
} = event;
if (!firstFile) {
// Most likely the user cancelled the file selection.
return;
}
const reader = new FileReader();
reader.onload = () => {
const imageURL = reader.result;
const image = document.createElement('img');
image.src = imageURL;
// The logo preview image is purely visual so no need to communicate this to assistive technology.
image.alt = 'preview of logo selected';
image.addEventListener(
'load',
(event) => {
let {
target: { width, height },
} = event;
if (height > MAX_LOGO_PREVIEW_HEIGHT) {
width = (width / height) * MAX_LOGO_PREVIEW_HEIGHT;
height = MAX_LOGO_PREVIEW_HEIGHT;
}
if (width > MAX_LOGO_PREVIEW_WIDTH) {
width = MAX_LOGO_PREVIEW_WIDTH;
height = (height / width) * MAX_LOGO_PREVIEW_WIDTH;
}
image.style.width = `${width}px`;
image.style.height = `${height}px`;
this.previewLogoTarget.replaceChild(
image,
this.previewLogoTarget.firstChild,
);
},
{ once: true },
);
};
reader.readAsDataURL(firstFile);
}
}

View file

@ -143,3 +143,23 @@ getInstantClick().then((spa) => {
});
initializeNav();
async function loadCreatorSettings() {
try {
const [{ CreatorSettingsController }, { Application }] = await Promise.all([
import('@admin-controllers/creator_settings_controller'),
import('@hotwired/stimulus'),
]);
const application = Application.start();
application.register('creator-settings', CreatorSettingsController);
} catch (error) {
Honeybadger.notify(
`Error loading the creator settings controller: ${error.message}`,
);
}
}
if (document.location.pathname === '/admin/creator_settings/new') {
loadCreatorSettings();
}

View file

@ -11,17 +11,16 @@
<%= label_tag :logo_svg, class: "crayons-field__label" do %>
Logo
<span class="crayons-field__required crayons-tooltip" data-tooltip="This will set the logo for your Forem" aria-describedby="logo-subtitle"></span>
<p id="logo-subtitle" class="crayons-field__description">Ideally SVG, but PNG will work, too. Min size: 300x300px.</p>
<p id="logo-subtitle" class="crayons-field__description">Ideally SVG, but PNG or JPEG will work, too.</p>
<% end %>
<span class="block border-none">
<%= file_field_tag :logo_svg, class: "crayons-btn crayons-btn--secondary w-100 ", role: "button", required: true %>
</span>
<% if ::Settings::General.logo_svg.present? %>
<div class="site-logo">
<%= ::Settings::General.logo_svg.html_safe %>
<div class="flex flex-1 gap-4">
<%= file_field_tag :logo_svg, required: true, accept: ".svg,.png,.jpg,image/svg+xml,image/png,image/jpg", data: { "max-file-size-mb": "25", action: "change->creator-settings#previewLogo" }, aria: { describedby: "logo-subtitle" } %>
<div data-creator-settings-target="previewLogo">
<% if ::Settings::General.logo_svg.present? %>
<%= ::Settings::General.logo_svg.html_safe %>
<% end %>
</div>
<% end %>
</div>
</div>
<div class="crayons-field mt-6 align-left">

View file

@ -3,7 +3,7 @@
<%= Rails.application.assets["setup-mode.css"].to_s.html_safe %>
</style>
<main id="main-content" class="flex flex-1 justify-center flex-col crayons-layout crayons-layout--limited-xs">
<main id="main-content" class="flex flex-1 justify-center flex-col crayons-layout crayons-layout--limited-xs" data-controller="creator-settings">
<div aria-live="assertive">
<% if flash[:error] %>
<div class="crayons-notice crayons-notice--danger mb-6" role="alert">

View file

@ -22,6 +22,10 @@ environment.splitChunks((config) => {
...(config.resolve ? config.resolve.alias : {}),
'@crayons': path.resolve(__dirname, '../../app/javascript/crayons'),
'@utilities': path.resolve(__dirname, '../../app/javascript/utilities'),
'@admin-controllers': path.resolve(
__dirname,
'../../app/javascript/admin/controllers',
),
'@components': path.resolve(
__dirname,
'../../app/javascript/shared/components',

View file

@ -29,10 +29,12 @@ describe('Creator Settings Page', () => {
cy.get('@communityName').type('Climbing Life');
// should contain a logo upload field and upload a logo upon click
cy.findByText(/^Logo/).should('be.visible');
cy.findByRole('button', { name: /logo/i }).attachFile(
cy.findByLabelText(/logo/i, { selector: 'input' }).attachFile(
'/images/admin-image.png',
);
cy.findByRole('img', { name: /preview of logo selected/i }).should(
'be.visible',
);
// should contain a brand color field
cy.findByText(/^Brand color/).should('be.visible');
@ -63,7 +65,12 @@ describe('Creator Settings Page', () => {
'have.attr',
'required',
);
cy.findByRole('button', { name: /logo/i }).should('have.attr', 'required');
cy.findByLabelText(/logo/i, { selector: 'input' }).should(
'have.attr',
'required',
);
// should not redirect the creator to the home page when the form is not completely filled out and 'Finish' is clicked
cy.findByRole('button', { name: 'Finish' }).click();
cy.url().should('equal', `${baseUrl}admin/creator_settings/new`);

View file

@ -4,7 +4,8 @@
"paths": {
"@crayons/*": ["app/javascript/crayons/*"],
"@utilities/*": ["app/javascript/utilities/*"],
"@components/*": ["app/javascript/shared/components/*"]
"@components/*": ["app/javascript/shared/components/*"],
"@admin-controllers/*": ["app/javascript/admin/controllers/*"]
}
},
"exclude": ["node_modules", "**/node_modules/*"]