Skip to content

feat: add custom branding with icon, brand name and color #1657

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

Open
wants to merge 8 commits into
base: alpha
Choose a base branch
from
Open
13 changes: 12 additions & 1 deletion Parse-Dashboard/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,20 +171,27 @@ module.exports = function(config, options) {
if (!users || (req.user && req.user.isAuthenticated)) {
return res.redirect(`${mountPath}apps`);
}

let errors = req.flash('error');
if (errors && errors.length) {
errors = `<div id="login_errors" style="display: none;">
${errors.join(' ')}
</div>`
}
const customBrandIcon = config.customBrandIcon;
const customBrandColorPrimary = config.customBrandColorPrimary;
res.send(`<!DOCTYPE html>
<head>
<link rel="shortcut icon" type="image/x-icon" href="${mountPath}favicon.ico" />
<base href="${mountPath}"/>
<script>
PARSE_DASHBOARD_PATH = "${mountPath}";
${customBrandIcon && 'CUSTOM_BRAND_ICON = "' + customBrandIcon + '";'}
</script>
<style>
body {
${customBrandColorPrimary && `background-color: ${customBrandColorPrimary} !important;`}
}
</style>
</head>
<html>
<title>Parse Dashboard</title>
Expand All @@ -206,12 +213,16 @@ module.exports = function(config, options) {
if (users && req.user && req.user.matchingUsername ) {
res.append('username', req.user.matchingUsername);
}
const customBrandIcon = config.customBrandIcon;
const customBrandTitle = config.customBrandTitle;
res.send(`<!DOCTYPE html>
<head>
<link rel="shortcut icon" type="image/x-icon" href="${mountPath}favicon.ico" />
<base href="${mountPath}"/>
<script>
PARSE_DASHBOARD_PATH = "${mountPath}";
${customBrandIcon && 'CUSTOM_BRAND_ICON = "' + customBrandIcon + '";'}
${customBrandTitle && 'CUSTOM_BRAND_TITLE = "' + customBrandTitle + '";'}
</script>
</head>
<html>
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,12 @@ Parse Dashboard supports adding an optional background color for each app, so yo
}
```

## Custom branding

- You can set `customBrandIcon` with a relative path from `iconsFolder`. This could be your custom logo which will appear on the login screen and on the top of the sidebar. Icon should be square (same width and height), SVG or PNG with transparent background.
- You can set `customBrandTitle` which will be visible on top of the sidebar instead of `Parse Dashboard`.
- You can set `customBrandColorPrimary` which will be the background color at the login screen.

## Other Configuration Options

You can set `appNameForURL` in the config file for each app to control the url of your app within the dashboard. This can make it easier to use bookmarks or share links on your dashboard.
Expand Down
5 changes: 4 additions & 1 deletion src/components/LoginForm/LoginForm.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ import { verticalCenter } from 'stylesheets/base.scss';
// Class-style component, because we need refs
export default class LoginForm extends React.Component {
render() {
const customBrandIcon = window.CUSTOM_BRAND_ICON;
const customBrandTitle = window.CUSTOM_BRAND_TITLE;
return (
<div className={styles.login} style={{ marginTop: this.props.marginTop || '-220px' }}>
<Icon width={80} height={80} name='infinity' fill='#093A59' />
{!customBrandIcon && <Icon width={80} height={80} name='infinity' fill='#093A59' />}
{customBrandIcon && <img src={'appicons/' + customBrandIcon} width={80} height={80} alt={customBrandTitle || 'Brand Logo'} />}
<form method='post' ref='form' action={this.props.endpoint} className={styles.form}>
<CSRFInput />
<div className={styles.header}>{this.props.header}</div>
Expand Down
31 changes: 19 additions & 12 deletions src/components/Sidebar/SidebarHeader.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export default class SidebarHeader extends React.Component {
});
}
render() {
const customBrandIcon = window.CUSTOM_BRAND_ICON;
const customBrandTitle = window.CUSTOM_BRAND_TITLE;

const { isCollapsed = false } = this.props;
const headerContent = isCollapsed
? (
Expand All @@ -33,25 +36,29 @@ export default class SidebarHeader extends React.Component {
)
: (
<>
<Link className={styles.logo} to={{ pathname: '/apps' }}>
<Icon width={28} height={28} name='infinity' fill={'#ffffff'} />
</Link>
<Link to='/apps'>
<div className={styles.version}>
<div>
Parse Dashboard {version}
<div className={styles.header}>
<Link className={styles.logo} to={{ pathname: '/apps' }}>
{!customBrandIcon && <Icon width={28} height={28} name='infinity' fill={'#ffffff'} />}
{customBrandIcon && <img src={'appicons/' + customBrandIcon} width={28} height={28} alt={customBrandTitle || 'Brand Logo'} />}
</Link>
<Link to='/apps'>
<div className={styles.version}>
<div>
{this.state.dashboardUser}
{customBrandTitle || 'Parse Dashboard'} {version}
<div>
{this.state.dashboardUser}
</div>
</div>
</div>
</div>
</Link>
</div>
</Link>
</div>
</>
)

return (
<div className={styles.header}>
{headerContent}
</div>
);
);
}
}