diff options
Diffstat (limited to 'web/src/components.tsx')
| -rw-r--r-- | web/src/components.tsx | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/web/src/components.tsx b/web/src/components.tsx new file mode 100644 index 0000000..ccd8da8 --- /dev/null +++ b/web/src/components.tsx @@ -0,0 +1,259 @@ +import $ from "jquery"; +import * as JSX from "./jsx"; +import { Header } from "./header"; +import { Sidebar } from "./sidebar"; + +const popup_stack = []; +window.onclick = ( e: Event ) => { + if( !e.target ) return; + + if( popup_stack.length > 0 ) { + const last = popup_stack[popup_stack.length - 1]; + if( last.el[0] == e.target || last.el.find( e.target ).length != 0 ) return; + e.preventDefault(); + e.stopPropagation(); + if( last.fn ) + last.fn(); + + popup_stack.pop(); + last.el.remove(); + } +} + +/** + * appends an element to the DOM and saves it in the popup stack to be removed. +**/ +export function addPopup( element: JQuery ) { + document.body.appendChild( element[0] ); + setTimeout( () => popup_stack.push( { el: element, fn: null } ) ); +} + +/** + * closes the topmost popup +**/ +export function closePopup() { + if( popup_stack.length > 0 ) { + const last = popup_stack[popup_stack.length - 1]; + if( last.fn ) + last.fn(); + + popup_stack.pop(); + setTimeout( () => last.el.remove() ); + } +} + +/** + * sets a callback that will get executed once the current popup is closed + **/ +export function onPopupClosed( fn: Function ) { + setTimeout( () => { + if( popup_stack.length > 0 ) { + popup_stack[popup_stack.length - 1].fn = fn; + } + } ); +} + +/* + * accepts "folded" prop +**/ +export function RolldownListItem( props: any ) { + const ret = <div class="rolldown"> + <div class="rolldown-collapsed-container"> + <div class="rolldown-icon-container">></div> + <div class="rolldown-collapsed">{props.folded}</div> + </div> + <div class="rolldown-expanded-container"> + <div class="rolldown-expanded">{props.children}</div> + </div> + </div>; + + ret.onclick = () => { + $( ret ).toggleClass( "active" ); + $( ret ).find( ".rolldown-expanded-container" ).toggleClass( 'active' ); + }; + + return ret; +} + +export function Spinner( props: any ) { + let spinner_steps = [ + '/', + '-', + '\\', + '|', + '/', + '-', + '\\', + '|' + ]; + + const id = props.id || ''; + + let el = $( <div class="spinner" id={ id } style={ props.style || '' } /> ); + let i = 0; + let loop = () => { + el.text( spinner_steps[i++] ); + if( i > spinner_steps.length ) + i = 0; + + if( el[0].isConnected ) + setTimeout( loop, 100 ); + }; + + setTimeout( loop, 100 ); + return el[0]; +} + +/* + * accepts title prop +**/ +export function RolldownList( props: any ) { + return <GroupBox title={props.title} style={props.style} innerStyle="margin: 0px; width: 100%"> + <div class="rolldownlist"> + { props.children } + </div> + </GroupBox> +} + +/* + * accepts title prop and optional innerStyle +**/ +export function GroupBox( props: any ) { + return <div class="groupbox" id={props.id || ''} style={props.style || ''}> + <span class="grouptitle"> + {props.title} + </span> + <span class="groupbody" style={props.innerStyle || ''}> + {props.children} + </span> + </div> +} + +export function Page( props: any ) { + return <> + <Header /> + <div id="page-main"> + <Sidebar /> + <div id="page-main-content"> + {props.children} + </div> + </div> + + <BackgroundToggle /> + </> +} + +export function DropdownItem( props: any ) { + return <div class="dropdown-inner" style={ props.style || "" } onclick={ props.onclick || null }> + {props.children} + </div> +} + +/** + * supports innerStyle for styling the actual dropdown picker + **/ +export function Dropdown( props: any ) { + const children = props.children; + let title = props.title; + let inline = props.inline; + let onchange = props.onchange; + let classes = props.class || ''; + let style = props.style || ""; + let id = props.id || ''; + let innerStyle = props.innerStyle || ""; + + const showItems = ( e: Event ) => { + e.preventDefault(); + const target = $( e.target as HTMLElement ); + + const newDropdown = $( <div class="dropdown-wrapper" style={ innerStyle }> + { children.map( ( child: HTMLElement ) => { + if( !child.onclick ) child.onclick = onchange; return child; + } ) } + </div> ); + target.parent().append( newDropdown[0] ); + setTimeout( () => popup_stack.push( { el: newDropdown, fn: null } ) ); + } + + if( inline ) { + return <button class={ 'dropdown' + ' ' + classes } style={ style } onclick={ showItems } id={ id }> + { title } + </button> + } + else { + return <> + <label>{ title }</label> + <button class={ 'dropdown' + ' ' + classes } style={ style } onclick={ showItems } id={ id }> + </button> + </> + } +} + +export function OkPopup( props: any ) { + const children = props.children; + const classes = props.class || ''; + const style = props.style || ''; + const id = props.id || ''; + + const onclick = ( e: Event ) => { + e.preventDefault(); + e.stopPropagation(); + if( props.onclick ) + props.onclick(); + + closePopup(); + } + + return <div class={ "popup-msg " + classes } id={ id } style={ style }> + { children } + <div style="display: flex; justify-content: center"> + <button onclick={ onclick }>Ok</button> + </div> + </div> +} + +export function OkCancelPopup( props: any ) { + const children = props.children; + const classes = props.class || ''; + const style = props.style || ''; + const id = props.id || ''; + + const onclick = ( e: Event ) => { + e.preventDefault(); + e.stopPropagation(); + if( props.onclick ) + props.onclick(); + + closePopup(); + } + + const oncancel = ( e: Event ) => { + e.preventDefault(); + e.stopPropagation(); + + closePopup(); + } + + return <div class={ "popup-msg " + classes } id={ id } style={ style }> + { children } + <div style="display: flex; justify-content: center"> + <button onclick={ onclick } style="margin-right: 10px">Ok</button> + <button onclick={ oncancel }>Cancel</button> + </div> + </div> +} + +export function BackgroundToggle() { + const toggleBackground = () => { + const main = $( "#page-main" ); + if( main.css( "display" ) == "none" ) { + main.css( "display", "" ); + } else { + main.css( "display", "none" ); + } + } + + return <div id="background-toggle" onclick={ toggleBackground }> + show background + </div> +} |
