Creating Inital Layout Element

This commit is contained in:
Martin Karkowski 2020-09-02 17:00:03 +02:00
parent a13f85c18f
commit b90f39f00c
4 changed files with 315 additions and 132 deletions

File diff suppressed because one or more lines are too long

View File

@ -7,8 +7,9 @@
*/
import React from 'react';
import { Col, Container, Row } from 'react-bootstrap';
import LocalNavbar from '../navbar';
import { ListGroup, Container, Row, Col, InputGroup, FormControl } from 'react-bootstrap';
import Selection, { SelecitonProps } from './selection';
const mainStyle = {
minHeight: '90vh',
@ -20,32 +21,70 @@ const sidebarStyle = {
}
const contentStyle = {
padding: '10px',
padding: '10px',
}
export default () => (
<>
<LocalNavbar></LocalNavbar>
<Container fluid style={mainStyle}>
<Row style={mainStyle}>
<Col className="col-md-2 d-none d-md-block bg-light sidebar-sticky" style={sidebarStyle}>
{/* A Search Field. */}
<InputGroup size="sm" className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="inputGroup-sizing-sm">Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl aria-label="Small" aria-describedby="inputGroup-sizing-sm" />
</InputGroup>
<ListGroup>
<ListGroup.Item>Cras justo odio</ListGroup.Item>
<ListGroup.Item>Dapibus ac facilisis in</ListGroup.Item>
<ListGroup.Item>Morbi leo risus</ListGroup.Item>
<ListGroup.Item>Porta ac consectetur ac</ListGroup.Item>
<ListGroup.Item>Vestibulum at eros</ListGroup.Item>
</ListGroup>
</Col>
<Col role="main" style={contentStyle}>Content</Col>
</Row>
</Container>
</>
);
export interface LayoutProps<T> extends SelecitonProps<T> {
onResize?: () => void;
onMount?: (_ref: React.RefObject<any>) => void;
onUnmount?: () => void;
}
export interface LayoutState<T> {
}
class Layout<T> extends React.Component<LayoutProps<T>, LayoutState<T>> {
protected _ref: React.RefObject<any>;
protected _handleResize: () => void;
componentDidMount() {
const _this = this;
function handleResize() {
if (typeof _this.props.onResize === 'function') {
_this.props.onResize();
}
}
if (typeof this.props.onMount === 'function') {
this.props.onMount(this._ref);
}
this._handleResize = handleResize;
window.addEventListener('resize', this._handleResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this._handleResize);
// Call the unmount
if (typeof this.props.onUnmount === 'function') {
this.props.onUnmount();
}
}
constructor(props) {
super(props);
this._ref = React.createRef();
}
public render() {
return (<>
<LocalNavbar></LocalNavbar>
<Container fluid style={mainStyle}>
<Row style={mainStyle}>
<Col className="col-md-2 d-none d-md-block bg-light sidebar-sticky" style={sidebarStyle}>
<Selection selection={this.props.selection} ></Selection>
</Col>
<Col role="main" style={contentStyle}>
{/* style={{height: '100%'}} */}
<div ref={this._ref}></div>
</Col>
</Row>
</Container>
</>);
}
}
export default Layout;

View File

@ -0,0 +1,135 @@
import React from 'react';
import { FormControl, InputGroup, ListGroup } from 'react-bootstrap';
import { deepClone } from '../../../lib/helpers/objectMethods';
export interface SelecitonProps<T> {
selection: {
groupName: string,
items: SelectionItem<T>[]
}[],
onSelect?: (item: T) => void;
}
export interface SelectionItem<T> {
label: string,
keywords: string,
item: T,
id: string | number,
}
export interface LayoutState<T> {
selected: string | number;
search: string;
}
class Selection<T> extends React.Component<SelecitonProps<T>, LayoutState<T>> {
constructor(props) {
super(props);
this.state = {
search: '',
selected: null
}
}
/**
* Function to Filter the Selection.
* @param search The Search Term.
*/
protected _filter(search: string) {
this.setState({
search: search.toLocaleLowerCase(),
selected: this.state.selected
});
}
/**
* Function used to Select an item
* @param item which will be selected
*/
protected _select(item: SelectionItem<T>) {
this.setState({
search: this.state.search,
selected: item.id
});
if (typeof this.props.onSelect === "function") {
this.props.onSelect(item.item);
}
}
public render() {
const _this = this;
// Filter only Valid items.
// Therefore iterate over the Groups and
// Filter the Items with the Search String
// and there Labels / Keywords.
// Afterwards filter the groups and remove
// Empty Groups
const items = deepClone(this.props).selection.map(item => {
// Filter the Items, that match the Selection
item.items = item.items.filter(value =>
// Filter the Keywords
value.keywords.toLowerCase().includes(_this.state.search) ||
// Filter the Lable.
value.label.toLowerCase().includes(_this.state.search)
);
// Return the Item
return item;
}).filter(
item =>
// Filter the Element by the lenght of the contained elements.
item.items.length > 0
);
let idx = 0;
return (<>
{/* A Search Field. */}
<InputGroup size="sm" className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="inputGroup-sizing-sm" >Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl aria-label="Small" aria-describedby="inputGroup-sizing-sm" onChange={(event) => {
_this._filter(event.currentTarget.value);
}} />
</InputGroup>
{
items.length > 0 ?
items.map(item => {
idx++;
return (
<div key={idx}>
<hr />
<h4>{item.groupName}</h4>
<hr />
<ListGroup>
{item.items.map(template => {
// Raise the ID
idx++;
// Store the Item Index
const idxOfItem = idx;
// Based on the selected Item assign the Color
// dark = selected
// light = unselected
const variant = template.id === _this.state.selected ? "dark" : "light";
// Return the Template variant={variant}
return (
<ListGroup.Item key={idxOfItem} action variant={variant} onClick={e => {
_this._select(template)
}}>{template.label}</ListGroup.Item>
);
})}
</ListGroup>
</div>
);
}) :
<code>Nothing Found</code>
}
</>);
}
}
export default Selection;

View File

@ -0,0 +1,18 @@
import * as React from 'react';
export interface ToolbarProps {
}
export interface ToolbarState {
}
class Toolbar extends React.Component<ToolbarProps, ToolbarState> {
render() {
return ( );
}
}
export default Toolbar;