Introduce family of Panel components
parent
34b9f720a0
commit
a420e8439c
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
Panels
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@import 'src/style/modules/influx-colors';
|
||||
@import 'src/style/modules/variables';
|
||||
@import 'src/style/modules/mixins';
|
||||
|
||||
$panel-gutter: 30px;
|
||||
$panel-background: $g3-castle;
|
||||
|
||||
.panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
margin-bottom: $panel-gutter;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: $panel-gutter 0;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-weight: 400;
|
||||
font-size: 19px;
|
||||
color: $g12-forge;
|
||||
letter-spacing: 0.015em;
|
||||
margin: 0;
|
||||
line-height: 1em;
|
||||
@extend %no-user-select;
|
||||
}
|
||||
|
||||
.panel-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:nth-child(1) {
|
||||
justify-content: flex-start;
|
||||
> * {
|
||||
margin-right: $ix-marg-b;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
justify-content: flex-end;
|
||||
> * {
|
||||
margin-left: $ix-marg-b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
background-color: $panel-background;
|
||||
padding: $panel-gutter;
|
||||
|
||||
.panel-header + &,
|
||||
&:first-child {
|
||||
border-top-left-radius: $ix-radius;
|
||||
border-top-right-radius: $ix-radius;
|
||||
}
|
||||
&:last-child {
|
||||
border-bottom-left-radius: $ix-radius;
|
||||
border-bottom-right-radius: $ix-radius;
|
||||
}
|
||||
|
||||
> *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
> *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: $ix-marg-c $panel-gutter;
|
||||
border-radius: 0 0 $ix-radius $ix-radius;
|
||||
@include gradient-v($g2-kevlar, $panel-background);
|
||||
color: $g9-mountain;
|
||||
}
|
||||
|
||||
// Tables directly inside Panels
|
||||
// ----------------------------------------------------------------------------
|
||||
.panel > .table {
|
||||
border-top: $ix-border;
|
||||
* {
|
||||
border-color: $g19-ghost;
|
||||
}
|
||||
}
|
||||
.panel-header + .table {
|
||||
border: none;
|
||||
}
|
||||
.panel > .table td:first-child,
|
||||
.panel > .table th:first-child {
|
||||
padding-left: $panel-gutter;
|
||||
}
|
||||
.panel > .table td:last-child,
|
||||
.panel > .table th:last-child {
|
||||
padding-right: $panel-gutter;
|
||||
}
|
||||
|
||||
// Solid Panels
|
||||
// ----------------------------------------------------------------------------
|
||||
.panel.panel-solid {
|
||||
background-color: $panel-background;
|
||||
border-radius: $ix-radius;
|
||||
|
||||
.panel-header {
|
||||
padding: $panel-gutter;
|
||||
}
|
||||
.panel-body {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// Horizontal Rules directly inside Panels
|
||||
// ----------------------------------------------------------------------------
|
||||
.panel-body hr {
|
||||
margin: $ix-marg-c 0;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
// Libraries
|
||||
import React, {Component, Children} from 'react'
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Components
|
||||
import PanelHeader from 'src/reusable_ui/components/panel/PanelHeader'
|
||||
import PanelBody from 'src/reusable_ui/components/panel/PanelBody'
|
||||
import PanelFooter from 'src/reusable_ui/components/panel/PanelFooter'
|
||||
|
||||
// Styles
|
||||
import 'src/reusable_ui/components/panel/Panel.scss'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
export enum PanelType {
|
||||
Default = '',
|
||||
Solid = 'solid',
|
||||
}
|
||||
|
||||
interface Props {
|
||||
children: JSX.Element[]
|
||||
type?: PanelType
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class Panel extends Component<Props> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
type: PanelType.Default,
|
||||
}
|
||||
|
||||
public static Header = PanelHeader
|
||||
public static Body = PanelBody
|
||||
public static Footer = PanelFooter
|
||||
|
||||
public render() {
|
||||
const {children} = this.props
|
||||
|
||||
this.validateChildren()
|
||||
|
||||
return <div className={this.className}>{children}</div>
|
||||
}
|
||||
|
||||
private get className(): string {
|
||||
const {type} = this.props
|
||||
|
||||
return classnames('panel', {'panel-solid': type === PanelType.Solid})
|
||||
}
|
||||
|
||||
private validateChildren = (): void => {
|
||||
const {children} = this.props
|
||||
|
||||
let invalidCount = 0
|
||||
|
||||
Children.forEach(children, (child: JSX.Element) => {
|
||||
if (
|
||||
child.type === PanelHeader ||
|
||||
child.type === PanelBody ||
|
||||
child.type === PanelFooter
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
invalidCount += 1
|
||||
return
|
||||
})
|
||||
|
||||
if (invalidCount > 0) {
|
||||
throw new Error(
|
||||
'Panel expected children of type <Panel.Header>, <Panel.Body>, or <Panel.Footer>'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Panel
|
|
@ -0,0 +1,19 @@
|
|||
// Libraries
|
||||
import React, {Component} from 'react'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
children: JSX.Element[] | JSX.Element
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class PanelBody extends Component<Props> {
|
||||
public render() {
|
||||
const {children} = this.props
|
||||
|
||||
return <div className="panel-body">{children}</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default PanelBody
|
|
@ -0,0 +1,19 @@
|
|||
// Libraries
|
||||
import React, {Component} from 'react'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
children: JSX.Element[]
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class PanelFooter extends Component<Props> {
|
||||
public render() {
|
||||
const {children} = this.props
|
||||
|
||||
return <div className="panel-footer">{children}</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default PanelFooter
|
|
@ -0,0 +1,25 @@
|
|||
// Libraries
|
||||
import React, {Component} from 'react'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
children?: JSX.Element[]
|
||||
title: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class PanelHeader extends Component<Props> {
|
||||
public render() {
|
||||
const {children, title} = this.props
|
||||
|
||||
return (
|
||||
<div className="panel-header">
|
||||
<div className="panel-title">{title}</div>
|
||||
<div className="panel-controls">{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default PanelHeader
|
Loading…
Reference in New Issue