summaryrefslogtreecommitdiff
path: root/web/src/components.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'web/src/components.tsx')
-rw-r--r--web/src/components.tsx259
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">&gt;</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>
+}