2022-05-26 06:47:26 +00:00
|
|
|
import {colors, isNarrowScreenObs} from 'app/client/ui2018/cssVars';
|
|
|
|
import {icon} from 'app/client/ui2018/icons';
|
|
|
|
import {Disposable, dom, DomArg, DomElementArg, makeTestId, Observable, styled} from 'grainjs';
|
|
|
|
|
|
|
|
const testId = makeTestId('test-banner-');
|
|
|
|
|
|
|
|
export interface BannerOptions {
|
|
|
|
/**
|
|
|
|
* Content to display in the banner.
|
|
|
|
*/
|
|
|
|
content: DomArg;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The banner style.
|
|
|
|
*
|
|
|
|
* Warning banners have a yellow background. Error banners have a red
|
|
|
|
* background.
|
|
|
|
*/
|
2023-01-03 10:52:25 +00:00
|
|
|
style: 'warning' | 'error' | 'info';
|
2022-05-26 06:47:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Optional variant of `content` to display when screen width becomes narrow.
|
|
|
|
*/
|
|
|
|
contentSmall?: DomArg;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether a button to close the banner should be shown.
|
|
|
|
*
|
|
|
|
* If true, `onClose` should also be specified; it will be called when the close
|
|
|
|
* button is clicked.
|
|
|
|
*
|
|
|
|
* Defaults to false.
|
|
|
|
*/
|
|
|
|
showCloseButton?: boolean;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether a button to collapse/expand the banner should be shown on narrow screens.
|
|
|
|
*
|
|
|
|
* Defaults to false.
|
|
|
|
*/
|
|
|
|
showExpandButton?: boolean;
|
|
|
|
|
2023-01-03 10:52:25 +00:00
|
|
|
/**
|
|
|
|
* If provided, applies the css class to the banner container.
|
|
|
|
*/
|
|
|
|
bannerCssClass?: string;
|
|
|
|
|
2022-05-26 06:47:26 +00:00
|
|
|
/**
|
|
|
|
* Function that is called when the banner close button is clicked.
|
|
|
|
*
|
|
|
|
* Should be used to handle disposal of the Banner.
|
|
|
|
*/
|
|
|
|
onClose?(): void;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A customizable banner for displaying at the top of a page.
|
|
|
|
*/
|
|
|
|
export class Banner extends Disposable {
|
|
|
|
private readonly _isExpanded = Observable.create(this, true);
|
|
|
|
|
|
|
|
constructor(private _options: BannerOptions) {
|
|
|
|
super();
|
|
|
|
}
|
|
|
|
|
|
|
|
public buildDom() {
|
2023-01-03 10:52:25 +00:00
|
|
|
return cssBanner({class: this._options.bannerCssClass || ''},
|
2022-05-26 06:47:26 +00:00
|
|
|
cssBanner.cls(`-${this._options.style}`),
|
|
|
|
this._buildContent(),
|
|
|
|
this._buildButtons(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private _buildContent() {
|
|
|
|
const {content, contentSmall} = this._options;
|
|
|
|
return dom.domComputed(use => {
|
|
|
|
if (contentSmall === undefined) { return [content]; }
|
|
|
|
|
|
|
|
const isExpanded = use(this._isExpanded);
|
|
|
|
const isNarrowScreen = use(isNarrowScreenObs());
|
|
|
|
return [isNarrowScreen && !isExpanded ? contentSmall : content];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private _buildButtons() {
|
|
|
|
return cssButtons(
|
|
|
|
this._options.showExpandButton ? this._buildExpandButton() : null,
|
|
|
|
this._options.showCloseButton ? this._buildCloseButton() : null,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private _buildCloseButton() {
|
|
|
|
return cssButton('CrossBig',
|
|
|
|
dom.on('click', () => this._options.onClose?.()),
|
|
|
|
testId('close'),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private _buildExpandButton() {
|
|
|
|
return dom.maybe(isNarrowScreenObs(), () => {
|
|
|
|
return cssExpandButton('Dropdown',
|
|
|
|
cssExpandButton.cls('-expanded', this._isExpanded),
|
|
|
|
dom.on('click', () => this._isExpanded.set(!this._isExpanded.get())),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function buildBannerMessage(...domArgs: DomElementArg[]) {
|
|
|
|
return cssBannerMessage(
|
|
|
|
cssIcon('Idea'),
|
|
|
|
cssLightlyBoldedText(domArgs),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const cssBanner = styled('div', `
|
|
|
|
display: flex;
|
|
|
|
padding: 10px;
|
|
|
|
gap: 16px;
|
|
|
|
color: white;
|
|
|
|
|
2023-01-03 10:52:25 +00:00
|
|
|
&-info {
|
|
|
|
color: black;
|
|
|
|
background: #FFFACD;
|
|
|
|
}
|
|
|
|
|
2022-05-26 06:47:26 +00:00
|
|
|
&-warning {
|
|
|
|
background: #E6A117;
|
|
|
|
}
|
|
|
|
|
|
|
|
&-error {
|
|
|
|
background: ${colors.error};
|
|
|
|
}
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssButtons = styled('div', `
|
|
|
|
display: flex;
|
|
|
|
gap: 16px;
|
|
|
|
flex-shrink: 0;
|
|
|
|
margin-left: auto;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssButton = styled(icon, `
|
|
|
|
width: 16px;
|
|
|
|
height: 16px;
|
|
|
|
cursor: pointer;
|
|
|
|
background-color: white;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssExpandButton = styled(cssButton, `
|
|
|
|
&-expanded {
|
2022-07-26 17:49:35 +00:00
|
|
|
-webkit-mask-image: var(--icon-DropdownUp) !important;
|
2022-05-26 06:47:26 +00:00
|
|
|
}
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssLightlyBoldedText = styled('div', `
|
|
|
|
font-weight: 500;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssIconAndText = styled('div', `
|
|
|
|
display: flex;
|
|
|
|
gap: 16px;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssBannerMessage = styled(cssIconAndText, `
|
|
|
|
flex-grow: 1;
|
|
|
|
justify-content: center;
|
|
|
|
`);
|
|
|
|
|
|
|
|
const cssIcon = styled(icon, `
|
|
|
|
flex-shrink: 0;
|
|
|
|
width: 16px;
|
|
|
|
height: 16px;
|
|
|
|
background-color: white;
|
|
|
|
`);
|