From cc68c5554d7ac61c39d9e516e82fabf24298be67 Mon Sep 17 00:00:00 2001
From: "Hahn Axel (hahn)" <axel.hahn@iml.unibe.ch>
Date: Wed, 14 Dec 2022 16:17:56 +0100
Subject: [PATCH] big restructure of widget and value handling

---
 public_html/classes/render-adminlte.class.php | 947 +++++++++---------
 public_html/index.php                         |   9 +
 public_html/pages/component.php               | 234 +----
 public_html/ui/main.css                       |   2 +-
 4 files changed, 504 insertions(+), 688 deletions(-)

diff --git a/public_html/classes/render-adminlte.class.php b/public_html/classes/render-adminlte.class.php
index 7567e7c..35e62ca 100755
--- a/public_html/classes/render-adminlte.class.php
+++ b/public_html/classes/render-adminlte.class.php
@@ -13,75 +13,113 @@ require_once 'htmlelements.class.php';
  */
 class renderadminlte {
 
-    /**
-     * valid items for colors, boxes ....
-     * @var array
-     */
-    var $_aValidItems=[
-        
-        'bgcolor'=>[
-            // for colors see https://adminlte.io/docs/3.2/layout.html
-            // https://adminlte.io/themes/v3/pages/UI/general.html
-            '', // none
-
-            'black', 
-            'dark', 
-            'gray-dark', 
-            'gray', 
-            'light',
-
-            'indigo',
-            'lightblue',
-            'navy',
-            'purple',
-            'fuchsia',
-            'pink',
-            'maroon',
-            'orange',
-            'lime',
-            'teal',
-            'olive',
+    var $aPresets=[
 
+        'bgcolor'=>[
+            'description'=>'background colors',
+            'group'=>'styling',
+            'values'=>[
+                // https://adminlte.io/themes/v3/pages/UI/general.html
+                ''=>'no value',
+                'indigo'=>'indigo',
+                'lightblue'=>'',
+                'navy'=>'',
+                'purple'=>'',
+                'fuchsia'=>'',
+                'pink'=>'',
+                'maroon'=>'',
+                'orange'=>'',
+                'lime'=>'',
+                'teal'=>'',
+                'olive'=>'',
+        
+                'black'=>'black',
+                'dark'=>'dark gray',
+                'gray'=>'gray', 
+                'light'=>'light gray', 
+            ]
         ],
-        'color'=>[
-            'indigo',
-            'navy',
-            'purple',
-            'fuchsia',
-            'pink',
-            'maroon',
-            'orange',
-            'lime',
-            'teal',
-            'olive',
-        ],
+    
         'type'=>[
-            'danger',   // red
-            'dark',     // dark gray
-            'gray',     // gray
-            'info',     // aqua
-            'primary',  // blue
-            'secondary', // gray
-            'success',  // green
-            'warning',  // yellow
+            'description'=>'type or status like info/ warning/ danger to define a color',
+            'group'=>'styling',
+            'values'=>[
+                ''=>'no value',
+                'danger'=>'red',
+                'info'=>'aqua',
+                'primary'=>'blue',
+                'secondary'=>'gray',
+                'success'=>'green',
+                'warning'=>'yellow',
+                'dark'=>'dark gray',
+                'gray'=>'gray', 
+            ]
+        ],
+        'shadow'=>[
+            'description'=>'use a shadow',
+            'group'=>'styling',
+            'values'=>[
+                ''=>'no value', 
+                'none'=>'none',
+                'small'=>'small', 
+                'regular'=>'regular',
+                'large'=>'large'
+            ]
         ],
         'size'=>[
-            'lg',
-            'sm',
-            'xs',
-            'flat',
+            'description'=>'set a size',
+            'group'=>'styling',
+            'values'=>[
+                ''=>'no value',
+                'lg'=>'',
+                'sm'=>'',
+                'xs'=>'',
+                'flat'=>'',
+            ]
+        ],
+        'variant'=>[
+            'description'=>'coloring style',
+            'group'=>'styling',
+            'values'=>[
+                ''=>'no value',
+                'outline'=>'small stripe on top',
+                'solid'=>'',
+                'gradient'=>'',
+            ]
+        ],
+        'visibility'=>[
+            'description'=>'',
+            'group'=>'customizing',
+            'values'=>[
+                ''=>'no value', 
+                '0'=>'hide', 
+                '1'=>'show',
+            ]
+        ],
+        // for keys: state
+        'windowstate'=>[
+            'description'=>'state of a resizable widget',
+            'group'=>'customizing',
+            'values'=>[
+                ''=>'no value', 
+                'collapsed'=>'header only', 
+                'maximized'=>'full window',
+            ]
+        ],
+        // for keys: dismissable
+        'yesno'=>[
+            'description'=>'',
+            'group'=>'customizing',
+            'values'=>[
+                ''=>'no value', 
+                '0'=>'no', 
+                '1'=>'yes',
+            ]
         ],
     ];
+
+    var $_aElements=[];
     
-    var $_aValueMappings=[
-        'shadow'=>[
-        'default'  => '',
-        'none'     => 'shadow-none',
-        'small'    => 'shadow-small',
-        'regular'  => 'shadow',
-        'large'    => 'shadow-lg',
-    ],
-];
     /**
      * instance of htmlelements
      * @var object
@@ -91,11 +129,12 @@ class renderadminlte {
     
     // ----------------------------------------------------------------------
     // 
-    // PRIVATE FUNCTIONS 
+    // CONSTRUCTOR
     // 
     // ----------------------------------------------------------------------
     public function __construct() {
         $this->_oHtml=new htmlelements();
+        $this->_initElements();
         return true;
     }
 
@@ -115,7 +154,7 @@ class renderadminlte {
      * @param string  $sValue     value to check
      * @param string  $sReferrer  optional: method that called this function
      */
-    protected function _checkValue($sType, $sValue, $sReferrer=false){
+    protected function _DELETE_ME___checkValue($sType, $sValue, $sReferrer=false){
         if (!$sValue || !array_key_exists($sType, $this->_aValidItems)){
             return false;
         }
@@ -125,6 +164,211 @@ class renderadminlte {
         return true;
     }
 
+    /**
+     * used in cosntructor
+     * initialize all element definitions
+     */
+    protected function _initElements(){
+        $this->_aElements=[
+
+            // ------------------------------------------------------------
+            'alert'=>[
+                'label'=>'Alert',
+                'description'=>'Colored box with title and a text',
+                'method'=>'getAlert',
+        
+                'params'=>[
+                    'type'        => ['select'=>$this->aPresets['type'],     'example_value'=>'warning'],
+                    'dismissible' => ['select'=>$this->aPresets['yesno'],    'example_value'=>''],
+                    'title'       => [
+                        'description'=>'Title in a bit bigger font', 
+                        'group'=>'content',
+                        'example_value'=>'Alert title'
+                    ],
+                    'text'        => [
+                        'description'=>'Message text', 
+                        'group'=>'content',
+                        'example_value'=>'I am a message. Read me, please.'
+                    ],
+                ]
+            ],
+            // ------------------------------------------------------------
+            'badge'=>[
+                'label'=>'Badge',
+                'description'=>'Tiny additional info; mostly as counter',
+                'method'=>'getBadge',
+        
+                'params'=>[
+                    'type'        => ['select'=>$this->aPresets['type'],     'example_value'=>'danger'],
+                    'bgcolor'     => ['select'=>$this->aPresets['bgcolor'],  'example_value'=>''],
+                    'class'       => [
+                        'group'=>'styling', 
+                        'description'=>'optional: css classes', 
+                        'example_value'=>''
+                    ],
+                    'id'          => [
+                        'group'=>'customizing', 
+                        'description'=>'optional: id attribute', 
+                        'example_value'=>''
+                    ],
+                    'title'       => [
+                        'group'=>'content', 
+                        'description'=>'optional: title attribute for mouseover', 
+                        'example_value'=>'Errors: 5'
+                    ],
+                    'text'        => [
+                        'group'=>'content', 
+                        'description'=>'Text or value in the badge', 
+                        'example_value'=>'5'
+                    ],
+                ]
+            ],
+            // ------------------------------------------------------------
+            'button'=>[
+                'label'=>'Button',
+                'description'=>'Buttons<br>In this component you can add other parmeter keys too - these will be added as attributes in the button tag.',
+                'method'=>'getButton',
+        
+                'params'=>[
+                    'type'        => ['select'=>$this->aPresets['type'],     'example_value'=>'primary'],
+                    'size'        => ['select'=>$this->aPresets['size'],     'example_value'=>''],
+                    'text'        => [
+                        'group'=>'content', 
+                        'description'=>'Text/ html code on the button', 
+                        'example_value'=>'Click me'
+                    ],
+                ]
+            ],
+            // ------------------------------------------------------------
+            'callout'=>[
+                'label'=>'Callout',
+                'description'=>'Kind of infobox',
+                'method'=>'getCallout',
+        
+                'params'=>[
+                    'type'        => ['select'=>$this->aPresets['type'],     'example_value'=>'danger'],
+                    'class'       => [
+                        'group'=>'styling', 
+                        'description'=>'optional: css classes', 
+                        'example_value'=>''
+                    ],
+                    'title'       => [
+                        'group'=>'content', 
+                        'description'=>'Title in a bit bigger font', 
+                        'example_value'=>'I am a callout'
+                    ],
+                    'text'        => [
+                        'group'=>'content',
+                        'description'=>'Message text', 
+                        'example_value'=>'Here is some description to whatever.'
+                    ],
+                ]
+            ],
+            // ------------------------------------------------------------
+            'card'=>[
+                'label'=>'Card',
+                'description'=>'Content box with header, text, footer',
+                'method'=>'getCard',
+        
+                'params'=>[
+                    'type'        => ['select'=>$this->aPresets['type'],     'example_value'=>''],
+                    'variant'     => ['select'=>$this->aPresets['variant'],  'example_value'=>''],
+                    'class'       => [
+                        'group'=>'styling', 
+                        'description'=>'optional: css classes', 
+                        'example_value'=>''
+                    ],
+                    'state'       => [
+                        'group'=>'customizing', 
+                        'select'=>$this->aPresets['windowstate'], 
+                        'example_value'=>''
+                    ],
+        
+                    'tb-collapse' => ['description'=>'show minus symbol as collapse button', 'select'=>$this->aPresets['visibility'], 'example_value'=>''],
+                    'tb-expand'   => ['description'=>'show plus symbol to expand card', 'select'=>$this->aPresets['visibility'], 'example_value'=>''],
+                    'tb-maximize' => ['description'=>'show maximize button for fullscreen', 'select'=>$this->aPresets['visibility'], 'example_value'=>''],
+                    'tb-minimize' => ['description'=>'show minimize button to minimize', 'select'=>$this->aPresets['visibility'], 'example_value'=>''],
+                    'tb-remove'   => ['description'=>'show cross symbol to remove card', 'select'=>$this->aPresets['visibility'], 'example_value'=>''],
+        
+                    'title'       => [
+                        'group'=>'content', 
+                        'description'=>'Title in the top row', 
+                        'example_value'=>'I am a card'
+                    ],
+                    'tools'       => [
+                        'group'=>'content', 
+                        'description'=>'Html code for the top right', 
+                        'example_value'=>'Tools'
+                    ],
+                    'text'        => [
+                        'group'=>'content', 
+                        'description'=>'Main content', 
+                        'example_value'=>'Here is some beautiful content.'
+                    ],
+                    'footer'      => [
+                        'group'=>'content', 
+                        'description'=>'optional: footer content', 
+                        'example_value'=>'Footer'
+                    ],
+                ]
+            ],
+            // ------------------------------------------------------------
+            'infobox'=>[
+                'label'=>'Info box',
+                'description'=>'Box with icon to highlight a single value; optional with a progress bar',
+                'method'=>'getInfobox',
+        
+                'params'=>[
+                    'type'=>['select'=>$this->aPresets['type'],     'example_value'=>''],
+                    'iconbg'=>['select'=>$this->aPresets['type'],   'example_value'=>'info'],
+                    'shadow'=>['select'=>$this->aPresets['shadow'], 'example_value'=>''],
+                    'icon'=>[
+                        'group'=>'content', 
+                        'description'=>'css class for an icon', 
+                        'example_value'=>'far fa-thumbs-up'
+                    ],
+                    'text'=>[
+                        'group'=>'content', 
+                        'description'=>'short information text', 
+                        'example_value'=>'Likes'
+                    ],
+                    'number'=>[
+                        'group'=>'content', 
+                        'description'=>'a number to highlight', 
+                        'example_value'=>"41,410"
+                    ],
+                    'progressvalue'=>[
+                        'group'=>'content', 
+                        'description'=>'optional: progress value 0..100 to draw a progress bar', 
+                        'example_value'=>70
+                    ],
+                    'progresstext'=>[
+                        'group'=>'content', 
+                        'description'=>'optional: text below progress bar', 
+                        'example_value'=>'70% Increase in 30 Days'
+                    ]
+                ]
+            ],
+            // ------------------------------------------------------------
+            'smallbox'=>[
+                'label'=>'Small box',
+                'description'=>'Solid colored box to highlight a single value; optional with a link',
+                'method'=>'getSmallbox',
+        
+                'params'=>[
+                    'type'=>['select'=>$this->aPresets['type'],     'example_value'=>'info'],
+                    'shadow'=>['select'=>$this->aPresets['shadow'], 'example_value'=>''],
+        
+                    'icon'=>['group'=>'content', 'description'=>'css class for an icon', 'example_value'=>'fas fa-shopping-cart'],
+        
+                    'text'=>['group'=>'content', 'description'=>'short information text', 'example_value'=>'New orders'],
+                    'number'=>['group'=>'content', 'description'=>'a number to highlight', 'example_value'=>"150"],
+                    'url'=>['group'=>'content', 'description'=>'optional: url to set a link on the bottom', 'example_value'=>'#'],
+                    'linktext'=>['group'=>'content', 'optional: description'=>'linktext', 'example_value'=>'More info']
+                ]
+            ],
+        ];
+    }
     /**
      * helper function: a shortcut for $this->_oHtml->getTag
      * @param  string  $sTag         name of html tag
@@ -168,6 +412,10 @@ class renderadminlte {
     }
 
     // ----------------------------------------------------------------------
+    // 
+    // PUBLIC FUNCTIONS :: NAVIGATION
+    // 
+    // ----------------------------------------------------------------------
 
 
     /** 
@@ -323,6 +571,10 @@ class renderadminlte {
             )."\n";
     }
 
+    // ----------------------------------------------------------------------
+    // 
+    // PUBLIC FUNCTIONS :: CONTENT - BASIC FUNCTIONS
+    // 
     // ----------------------------------------------------------------------
     
     /**
@@ -347,50 +599,137 @@ class renderadminlte {
         return $this->addWrapper('div', ['class'=>'col-md-'.$iCols, 'style'=>'float:'.$sFloat], $sContent);
     }
 
+    // ----------------------------------------------------------------------
+    // 
+    // PUBLIC FUNCTIONS :: CONTENT - WIDGET HELPERS
+    // 
+    // ----------------------------------------------------------------------
+
 
     /**
-     * show help of standard key in a component key
-     * @param string  $skey  name of a options key
+     * get a list of all defined components that can be rendered
+     * @param  {bool}  $bSendData  flag: send including subkeys of the hash; default: false (keys only)
+     * @return {array}
      */
-    public function showKeyHelp($sKey){
-        $aDescription=[
-            'bgcolor' => 'background color (without prefix "bg")',
-            'class'   => 'css class',
-            'color'   => 'foreground color',
-            'id'      => 'optional: id attribute',
-            'text'    => 'visible text',
-            'title'   => 'optional: title attribute',
-            'type'    => 'one of [none]|danger|info|primary|success|warning',
-        ];
-        return [
-            'key'=>$sKey,
-            'description'=>isset($aDescription[$sKey]) ? $aDescription[$sKey] : '-',
-            'valid_values'=>isset($this->_aValidItems[$sKey]) ? implode("|", $this->_aValidItems[$sKey]) : '',
-        ];
+    public function getComponents($bSendData=false){
+        return $bSendData
+            ? $this->_aElements
+            : array_keys($this->_aElements)
+        ;
+    }
+    /**
+     * get data of a component
+     * @param  {string}  $sComponent  id of the component
+     * @return {array}
+     */
+    public function getComponent($sComponent){
+        if(!isset($this->_aElements[$sComponent])){
+            return false;
+        }
+        $aReturn=array_merge(['id'=>$sComponent], $this->_aElements[$sComponent]);
+        unset($aReturn['params']);
+        return $aReturn;
     }
 
+    /**
+     * get parameter keys of a component
+     * @param  {string}  $sComponent  id of the component
+     * @param  {bool}    $bSendData  flag: send including subkeys of the hash; default: false (keys only)
+     * @return {array}
+     */
+    public function getComponentParamkeys($sComponent, $bSendData=false){
+        if(!isset($this->_aElements[$sComponent])){
+            return false;
+        }
+        $aKeys=array_keys($this->_aElements[$sComponent]['params']);
+        if(!$bSendData){
+            return $aKeys;
+        }
+        $aReturn=[];
+        foreach($aKeys as $sKey){
+            $aReturn[$sKey]=$this->getComponentParamkey($sComponent, $sKey);
+        }
+        // $aReturn=$this->_aElements[$sComponent]['params'];
+        return $aReturn;
+    }
+
+    /**
+     * get information a parameter keys of a component
+     * @param  {string}  $sComponent  id of the component
+     * @param  {string}  $sKey        key in the options array
+     * @return {array}
+     */
+    public function getComponentParamkey($sComponent, $sKey){
+        if(!isset($this->_aElements[$sComponent]['params'][$sKey])){
+            return false;
+        }
+        $aReturn=$this->_aElements[$sComponent]['params'][$sKey];
+        // get description from a preset
+        if(!isset($aReturn['description']) && isset($aReturn['select']['description'])){
+            $aReturn['description']=$aReturn['select']['description'];
+        }
+        if(!isset($aReturn['group']) && isset($aReturn['select']['group'])){
+            $aReturn['group']=$aReturn['select']['group'];
+        }
+        return $aReturn;
+    }
+
+    /**
+     * get a flat list of valid parameters for a key in a component
+     * @param  {string}  $sComponent  id of the component
+     * @param  {string}  $sKey        key in the options array
+     * @return {array}
+     */
+    public function getValidParamValues($sComponent, $sKey){
+        $aOptionkey=$this->getComponentParamkey($sComponent, $sKey);
+        if(!$aOptionkey || !isset($aOptionkey['select']['values'])){
+            return false;
+        }
+        return array_keys($aOptionkey['select']['values']);
+    }
+
+
     // ----------------------------------------------------------------------
 
     /**
      * helper function for get[COMPONENTNAME] methods:
      * ensure that all wanted keys exist in an array. Non existing keys will be added with value false
-     * @param  array  $aOptions  options array of the method
-     * @param  array  $aKeys     required keys
      * @return array
      */
-    protected function _ensureOptions($aOptions, $aKeys){
-        foreach ($aKeys as $sKey){
-            if(!isset($aOptions[$sKey])){
+    protected function _ensureOptions($sComponent, $aOptions=[]){
+
+        $aParams=$this->getComponentParamkeys($sComponent, 0);
+        if(!$aParams){
+            $aOptions['_infos'][]="Warning: no definition was found for component $sComponent.";
+            return $aOptions;
+        }
+        foreach ($aParams as $sKey){
+            if(!isset($aOptions) || !isset($aOptions[$sKey])){
                 $aOptions[$sKey]=false;
                 if(!isset($aOptions['_infos'])){
                     $aOptions['_infos']=[];
                 }
                 $aOptions['_infos'][]="added missing key: $sKey";
             }
-            $this->_checkValue($sKey, $aOptions[$sKey], __METHOD__);
+
+            // $aParamdata
+            $aValidvalues=$this->getValidParamValues($sComponent, $sKey);
+            if($aValidvalues){
+                if(array_search($aOptions[$sKey], $aValidvalues)===false){
+                    echo "ERROR: [".$sComponent."] value &quot;".$aOptions[$sKey]."&quot; is not a valid for param key [".$sKey."]; it must be one of ".implode("|", $aValidvalues).'<br>';
+                }
+            }
+    
+            // $this->_checkValue($sKey, $aOptions[$sKey], __METHOD__);
         }
+        // echo '<pre>' . print_r($aOptions, 1) . '</pre>';
         return $aOptions;
     }
+    // ----------------------------------------------------------------------
+    // 
+    // PUBLIC FUNCTIONS :: CONTENT - WIDGETS
+    // 
+    // ----------------------------------------------------------------------
 
     /**
      * return a alert box      
@@ -404,7 +743,7 @@ class renderadminlte {
      * @return string
      */
     public function getAlert($aOptions){
-        $aOptions=$this->_ensureOptions($aOptions, ['type','dismissible', 'title', 'text']);
+        $aOptions=$this->_ensureOptions('alert', $aOptions);
         $aAlertIcons=[
             'danger'=>'icon fas fa-ban',
             'info'=>'icon fas fa-info',
@@ -448,7 +787,7 @@ class renderadminlte {
      *                          - type    - one of [none]|danger|dark|info|primary|secondary|success|warning
      */
     public function getBadge($aOptions){
-        $aOptions=$this->_ensureOptions($aOptions, ['bgcolor', 'class', 'id', 'text', 'title', 'type']);
+        $aOptions=$this->_ensureOptions('badge', $aOptions);
         $aElement=[];
         $aElement['class']='badge'
             . ($aOptions['class']   ? ' badge-'.$aOptions['class'] : '')
@@ -480,7 +819,7 @@ class renderadminlte {
      * @return string
      */
     public function getButton($aOptions){
-        $aOptions=$this->_ensureOptions($aOptions, ['type', 'size', 'class', 'text', 'icon']);
+        $aOptions=$this->_ensureOptions('button', $aOptions);
         $aElement=$aOptions;
         $aElement['class']='btn'
                 .($aOptions['class'] ? ' '.$aOptions['class'] : '')
@@ -509,7 +848,7 @@ class renderadminlte {
      * @return string
      */
     public function getCallout($aOptions){
-        $aOptions=$this->_ensureOptions($aOptions, ['type', 'class', 'title', 'text']);
+        $aOptions=$this->_ensureOptions('callout', $aOptions);
         $sClass='callout'
                 .($aOptions['class'] ? ' '.$aOptions['class'] : '')
                 .($aOptions['type']  ? ' callout-'.$aOptions['type'] : '')
@@ -552,7 +891,7 @@ class renderadminlte {
      * @return string
      */
     public function getCard($aOptions){
-        $aOptions=$this->_ensureOptions($aOptions, ['variant', 'type', 'class', 'collapsable', 'title', 'tools', 'text', 'footer']);
+        $aOptions=$this->_ensureOptions('card', $aOptions);
         // css class prefixes based on "variant" value
         $aVariants=[
             'default'  => 'card-',
@@ -630,7 +969,7 @@ class renderadminlte {
      * @return string
      */
     public function getInfobox($aOptions){
-        $aOptions=$this->_ensureOptions($aOptions, ['type', 'bgcolor', 'shadow', 'icon', 'text', 'number', 'progressvalue', 'progresstext']);
+        $aOptions=$this->_ensureOptions('infobox', $aOptions);
 
         // print_r($aOptions);
         $sClass='info-box'
@@ -669,6 +1008,7 @@ class renderadminlte {
      * return an info-box:
      * A colored box with large icon, text and a value.
      * https://adminlte.io/docs/3.2/components/boxes.html
+     * https://adminlte.io/themes/v3/pages/widgets.html
      * 
      * @param type $aOptions  hash with keys for all options
      *                        styling:
@@ -683,7 +1023,7 @@ class renderadminlte {
      * @return string
      */
     public function getSmallbox($aOptions){
-        $aOptions=$this->_ensureOptions($aOptions, ['type', 'bgcolor', 'shadow', 'icon', 'text', 'number', 'progressvalue', 'progresstext']);
+        $aOptions=$this->_ensureOptions('smallbox', $aOptions);
         $aShadows=[
             'default'  => '',
             'none'     => 'shadow-none',
@@ -692,34 +1032,38 @@ class renderadminlte {
             'large'    => 'shadow-lg',
         ];
         // print_r($aOptions);
-        $sClass='info-box'
+        $sClass='small-box'
                 .($aOptions['class'] ? ' '.$aOptions['class'] : '')
                 .($aOptions['type']  ? ' bg-'.$aOptions['type'] : '')
                 .($aOptions['shadow'] && isset($aShadows) && $aShadows[$aOptions['shadow']] ? ' '.$aShadows[$aOptions['shadow']] : '')
                 ;
         
         // build parts
+        $sContent=$this->addWrapper("div", ['class'=>'inner'],
+            ''
+            . ($aOptions['number'] ? $this->_tag('h3', ['label'=>$aOptions['number']]) : '')
+            . ($aOptions['text']   ? $this->_tag('p', ['class'=>'info-box-text',   'label'=>$aOptions['text']])   : '')
+        );
         $sIcon=$aOptions['icon'] 
-            ? $this->addWrapper("span", [
-                    'class'=>'info-box-icon'.($aOptions['iconbg'] ? ' bg-'.$aOptions['iconbg'] : '')
-                ], $this->_tag('i',['class'=>$aOptions['icon']])) 
+            ? $this->addWrapper("div", ['class'=>'icon'], 
+                $this->_tag('i',['class'=>$aOptions['icon']])) 
             : ''
             ;
-        $sContent=$this->addWrapper("div", ['class'=>'info-box-content'],
-            ''
-            . ($aOptions['text']   ? $this->_tag('span', ['class'=>'info-box-text',   'label'=>$aOptions['text']])   : '')
-            . ($aOptions['number'] ? $this->_tag('span', ['class'=>'info-box-number', 'label'=>$aOptions['number']]) : '')
-            . ($aOptions['progressvalue']!==false 
-                ? $this->addWrapper('div', ['class'=>'progress'],
-                        $this->_tag('div', ['class'=>'progress-bar', 'style'=>'width: '.(int)$aOptions['progressvalue'].'%' ]) 
-                    )
-                : ''    
-                )
-            . ($aOptions['progresstext'] ? $this->_tag('span', ['class'=>'progress-description', 'label'=>$aOptions['progresstext']]) : '' )
+        $sFooter=($aOptions['url']
+            ? $this->addWrapper("a", [
+                'class'=>'small-box-footer',
+                'href'=>$aOptions['url'],
+                ],
+                ''
+                . ($aOptions['linktext'] ? $aOptions['linktext'] : $aOptions['url'])
+                . ' '
+                . $this->_tag('i',['class'=>'fas fa-arrow-circle-right'])
+            )
+            : ''
         );
 
         // merge all
-        return $this->_tag('div', ['class'=>$sClass], $sIcon.$sContent);
+        return $this->_tag('div', ['class'=>$sClass], $sContent.$sIcon.$sFooter);
     }
 
 
@@ -764,389 +1108,4 @@ class renderadminlte {
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-    // ----------------------------------------------------------------------
-    // v2.x methods
-    // ----------------------------------------------------------------------
-
-    
-    // ----------------------------------------------------------------------
-    // 
-    // PUBLIC FUNCTIONS
-    // SIMPLE HTML ELEMENTS
-    // 
-    // ----------------------------------------------------------------------
-
-    /**
-     * return a alert box      
-     * https://adminlte.io/themes/AdminLTE/pages/UI/general.html
-     * @param type $aOptions  hash with keys for all options
-     *                          - type - one of [none]|danger|info|primary|success|warning
-     *                          - dismissible - if dismissible - one of true|false; default: false
-     *                          - title
-     *                          - text
-     * @return string
-     */
-    public function MIGRATED__getAlert($aOptions){
-        foreach (array('type','dismissible', 'title', 'text') as $sKey){
-            if(!isset($aOptions[$sKey])){
-                $aOptions[$sKey]=false;
-            }
-            $this->_checkValue($sKey, $aOptions[$sKey], __METHOD__);
-        }
-        return '<div class="alert'
-                    .($aOptions['type'] ? ' alert-'.$aOptions['type'] : '')
-                    . ($aOptions['dismissible'] ? ' alert-dismissible' : '')
-                .'">'
-                
-                // div content
-                . ($aOptions['dismissible'] ? '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' : '')
-                . ($aOptions['title'] ? '<h4>'.$aOptions['title'].'</h4>' : '')
-                . $aOptions['text']
-            . '</div>'
-            ;
-        
-        /*
-            <div class="alert alert-danger alert-dismissible">
-                <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
-                <h4><i class="icon fa fa-ban"></i> Alert!</h4>
-                Danger alert preview. This alert is dismissable. A wonderful serenity has taken possession of my entire
-                soul, like these sweet mornings of spring which I enjoy with my whole heart.
-            </div>         
-         */
-    }
-
-    /**
-     * get html code for a badge
-     * @param type $aOptions  hash with keys for all options
-     *                          - type    - one of [none]|danger|info|primary|success|warning
-     *                          - bgcolor - background color (without prefix "bg")
-     *                          - class   - css class
-     *                          - text    - visible text
-     *                          - title   - optional: title attribute
-     *                          - id      - optional: id attribute
-     */
-    public function MIGRATED__getBadge($aOptions){
-        foreach (array('bgcolor', 'title', 'text', 'type', 'id') as $sKey){
-            if(!isset($aOptions[$sKey])){
-                $aOptions[$sKey]=false;
-            }
-            $this->_checkValue($sKey, $aOptions[$sKey], __METHOD__);
-        }
-        return '<small class="label'
-                    . ($aOptions['type']  ? ' label-'.$aOptions['type'] : '')
-                    . ($aOptions['bgcolor'] ? ' bg-'.$aOptions['bgcolor']   : '')
-                .'"'
-                . ($aOptions['id']  ? ' id="'.$aOptions['id'].'"' : '')
-                . (isset($aOptions['title'])  ? ' title="'.$aOptions['title'].'"' : '')
-                . '>'
-                . $aOptions['text']
-            . '</small>'
-            ;
-        /*
-         <small class="label pull-right bg-yellow">12</small>
-         <span class="label label-danger">Delivered</span>
-         */
-    }
-    /**
-     * return a callout box      
-     * https://adminlte.io/themes/AdminLTE/pages/UI/general.html
-     * @param type $aOptions  hash with keys for all options
-     *                          - type - one of [none]|danger|info|primary|success|warning
-     *                          - title
-     *                          - text
-     * @return string
-     */
-    public function MIGRATED__getCallout($aOptions){
-        foreach (array('type', 'title', 'text') as $sKey){
-            if(!isset($aOptions[$sKey])){
-                $aOptions[$sKey]=false;
-            }
-            $this->_checkValue($sKey, $aOptions[$sKey], __METHOD__);
-        }
-        return '<div class="callout'
-                    .($aOptions['type'] ? ' callout-'.$aOptions['type'] : '')
-                .'">'
-                
-                // div content
-                . ($aOptions['title'] ? '<h4>'.$aOptions['title'].'</h4>' : '')
-                . ($aOptions['text'] ? '<p>'.$aOptions['text'].'</p>' : '')
-            . '</div>'
-            ;
-        
-        /*
-            <div class="callout callout-info">
-                <h4>I am an info callout!</h4>
-                <p>Follow the steps to continue to payment.</p>
-            </div>
-         */
-    }
-    
-    /**
-     * return a content Box
-     * @param type $aOptions  hash with keys for all options
-     *                          - type - one of [none]|danger|info|primary|success|warning
-     *                          - solid - one of true|false; default: false
-     *                          - collapsable - one of true|false; default: false
-     *                          - removable - one of true|false; default: false
-     *                          - collapsed - if collapsable - one of true|false; default: false
-     *                          - title
-     *                          - label
-     *                          - text
-     *                          - footer
-     * @return string
-     */
-    public function getBox($aOptions) {
-        foreach (array('type','solid', 'collapsable', 'collapsed', 'removable', 'title','label', 'text', 'footer') as $sKey){
-            if(!isset($aOptions[$sKey])){
-                $aOptions[$sKey]=false;
-            }
-            $this->_checkValue($sKey, $aOptions[$sKey], __METHOD__);
-        }
-        
-        // system icons on top right
-        $sToolbox='';
-        if($aOptions['label']){
-            $sToolbox.='<span class="label label-primary">'.$aOptions['label'].'</span>';
-        }
-        if($aOptions['collapsable']){
-            $sToolbox.='<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
-                <button type="button" class="btn btn-box-tool" data-widget="remove"><i class="fa fa-times"></i></button>
-            ';
-        }
-        if($aOptions['removable']){
-            $sToolbox.='<button type="button" class="btn btn-box-tool" data-widget="remove"><i class="fa fa-times"></i></button>';
-        }
-        if($sToolbox){
-            $sToolbox='<div class="box-tools pull-right">'.$sToolbox.'</div>';
-        }
-                
-        // return box
-        return '
-        <div class="box'
-            .($aOptions['type'] ? ' box-'.$aOptions['type'] : '')
-            .($aOptions['solid'] ? ' box-solid' : '')
-            .($aOptions['collapsed'] ? ' collapsed-box' : '')
-            .'">
-            <div class="box-header with-border">
-              '.($aOptions['title'] ? '<h3 class="box-title">'.$aOptions['title'].'</h3>' : '').'
-              '.$sToolbox.'
-            </div>
-            <div class="box-body">
-              '.$aOptions['text'] .'
-            </div>
-            <!-- /.box-body -->
-              '.($aOptions['footer'] ? '<div class="box-footer">'.$aOptions['footer'].'</div>' : '') .'
-            <!-- /.box-footer-->
-        </div>
-        ';
-    }
-    
-    
-    public function getMenuItem($aOptions, $aLinkOptions){
-        $sLabel=$this->_tag('a', $aLinkOptions);
-        
-        // TODO
-        // if subelements then add them to $sLabel with recursion
-        
-        return $this->_tag('li', array(
-            'class'=>'treeview',
-            'label'=>$sLabel,
-        ));
-        /*
-        return '<li class="treeview">
-          <a href="#">
-            <i class="fa fa-laptop"></i>
-            <span>UI Elements</span>
-            <span class="pull-right-container">
-              <i class="fa fa-angle-left pull-right"></i>
-            </span>
-          </a>
-          <!--
-          <ul class="treeview-menu" style="display: none;">
-            <li><a href="general.html"><i class="fa fa-circle-o"></i> General</a></li>
-            <li class="active"><a href="icons.html"><i class="fa fa-circle-o"></i> Icons</a></li>
-            <li><a href="buttons.html"><i class="fa fa-circle-o"></i> Buttons</a></li>
-            <li><a href="sliders.html"><i class="fa fa-circle-o"></i> Sliders</a></li>
-            <li><a href="timeline.html"><i class="fa fa-circle-o"></i> Timeline</a></li>
-            <li><a href="modals.html"><i class="fa fa-circle-o"></i> Modals</a></li>
-          </ul>
-          -->
-        </li>
-        ';
-         */
-    }
-    
-    /**
-     * return a small Box
-     * @param type $aOptions  hash with keys for all options
-     *                          - type - icon color one of [none]|aqua|green|yellow|red
-     *                          - bgcolor - background color one of [none]|aqua|green|yellow|red
-     *                          - color - icon color one of [none]|aqua|black|gray|green|orange|maroon|navy|purple|red|teal|yellow
-     *                          - title
-     *                          - text
-     *                          - icon - icon on the right
-     *                          - footer - footer text
-     *                          - url
-     * @return string
-     */
-    public function MIGRATED__getSmallBox($aOptions) {
-        foreach (array('bgcolor','color', 'title', 'text', 'icon', 'footer') as $sKey){
-            if(!isset($aOptions[$sKey])){
-                $aOptions[$sKey]=false;
-            }
-            $this->_checkValue($sKey, $aOptions[$sKey], __METHOD__);
-        }
-        if(!$aOptions['url']){
-            $aOptions['url']='#';
-        }
-        return '<div class="small-box'.($aOptions['bgcolor'] ? ' bg-'.$aOptions['bgcolor'] : '').'">
-            <div class="inner">
-                '.($aOptions['title'] ? '<h3>'.$aOptions['title'].'</h3>' : '').'
-                '.($aOptions['text'] ? '<p>'.$aOptions['text'].'</p>' : '').'
-            </div>
-            '.($aOptions['icon'] ? '<div class="icon">'.$this->_oHtml->getIcon($aOptions['icon']).'</div>' : '').'
-            '.($aOptions['footer'] 
-                    ? '<a href="'.$aOptions['url'].'" class="small-box-footer"'
-                        . '>'.$aOptions['footer'].' <i class="fa fa-arrow-circle-right"></i>'
-                    . '</a>' : '').'
-        </div>';
-        
-    }
-    /**
-     * return a widget
-     * @param type $aOptions  hash with keys for all options
-     *                          - bgcolor - icon color one of aqua|green|yellow|red
-     *                          - color - color one of aqua|black|gray|green|orange|maroon|navy|purple|red|teal|yellow
-     *                          - onclick
-     *                          - icon
-     *                          - text
-     *                          - number
-     *                          - progressvalue - 0..100
-     *                          - progresstext  - text for progress
-     * @return string
-     */
-    public function getWidget($aOptions=array()){
-        foreach (array('bgcolor','color', 'text', 'number','icon') as $sKey){
-            if(!isset($aOptions[$sKey])){
-                $aOptions[$sKey]=false;
-            }
-            $this->_checkValue($sKey, $aOptions[$sKey], __METHOD__);
-        }
-        
-        // if onclick is available then add a a-tag to all labels that do not contain a link yet
-        $sApre=isset($aOptions['onclick']) && $aOptions['onclick'] ? '<a href="#" onclick="'.$aOptions['onclick'].'">' : '';
-        $sAsuf=$sApre ? '</a>' : '';
-        
-        $aOptions['icon']=$this->_oHtml->getIcon($aOptions['icon']);
-        // foreach(array('icon', 'text', 'number', 'progresstext') as $sKey){
-        foreach(array('icon') as $sKey){
-            $aOptions[$sKey]=strstr($aOptions[$sKey], '<a')===false ? $sApre.$aOptions[$sKey].$sAsuf : $aOptions[$sKey];
-        }
-        
-        return '<div class="info-box bg-'.$aOptions['bgcolor'].'">
-            <span class="info-box-icon bg-'.$aOptions['color'].'">'.$aOptions['icon'].'</span>
-
-            <div class="info-box-content">
-              <span class="info-box-text">'.$aOptions['text'].'</span>
-              <span class="info-box-number">'.$aOptions['number'].'</span>
-            </div>
-            '.
-                (is_int($aOptions['progressvalue'])
-                    ? '<div class="progress">
-                            <div class="progress-bar" style="width: '.$aOptions['progressvalue'].'%"></div>
-                        </div>
-                        '
-                    :'')
-                .(isset($aOptions['progresstext']) 
-                    ? '<span class="progress-description">'.$aOptions['progresstext'].'</span>'
-                    : ''
-                )
-            .'
-            <!-- /.info-box-content -->
-        </div>';
-    }
-    
-    /**
-     * get html content for a column div element inside a row
-     * 
-     * @param string   $sContent  html content to show
-     * @param integer  $iColums   optional: count of columns; defauklt is 12 (full width)
-     * @param string   $sFloat    style value for float; 
-     * @return string
-     */
-    public function getSectionColumn($sContent=false, $iColums=12, $sFloat=false){
-        return '<div class="col-md-'.$iColums.'"'
-                .($sFloat ? ' style="float: '.$sFloat.';"' : '')
-                .'>DEPRECATED: use addCol() method<br>'.$sContent.'</div>';
-    }
-    
-    /**
-     * get html code for a new content row
-     * 
-     * @param string   $sContent  html content to show
-     * @return string
-     */
-    public function getSectionRow($sContent=false){
-        return '<div class="row">DEPRECATED: use addRow() method<br>'.$sContent.'</div>';
-    }
-
-    /**
-     * get html code for headline of page content
-     * 
-     * @param string  $sHeadline  headline as html
-     * @return type
-     */
-    public function getSectionHead($sHeadline){
-        return '
-            <section class="content-header">
-              <h1>
-                '.$sHeadline.'
-              </h1>
-              <!--
-
-              BREADCRUMB TOP RIGHT
-
-              <ol class="breadcrumb">
-                <li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
-                <li class="active">Here</li>
-              </ol>
-              -->
-            </section>
-        ';
-    }
-
-    /**
-     * get html code to init content section 
-     * 
-     * @param string   $sContent  html content to show
-     * @return string
-     */
-    public function getSectionContent($sContent){
-        return '
-            <!-- Main content -->
-            <section class="content container-fluid">
-
-              <!--------------------------
-                | Your Page Content Here |
-                -------------------------->
-
-                '.$sContent.'
-
-            </section>
-            <!-- /.content -->
-        ';
-    }
 }
diff --git a/public_html/index.php b/public_html/index.php
index 308c85d..cc6aac5 100755
--- a/public_html/index.php
+++ b/public_html/index.php
@@ -41,6 +41,15 @@ $aReplace['{{NAVI_TOP}}']=''
 
 // ---------- LEFT BAR
 $aSidebarNav=include("./config/navi_left.php");
+
+foreach($renderAdminLTE->getComponents(1) as $sId=>$aComponent){
+    $aSidebarNav[1]['children'][]=[
+        'href'=>'/component?id='.$sId,   
+        'label'=>$aComponent['label'], 
+        'icon'=>'fas fa-square-full'
+    ];
+}
+
 $aReplace['{{NAVI_LEFT}}']=''
     . $renderAdminLTE->addWrapper(
         'nav', ['class'=>'mt-2'],
diff --git a/public_html/pages/component.php b/public_html/pages/component.php
index 0043e2b..5bd0e39 100644
--- a/public_html/pages/component.php
+++ b/public_html/pages/component.php
@@ -2,194 +2,38 @@
 
 $sComponent=(isset($_GET['id']) ? preg_replace('/[^a-z]/', '', $_GET['id']) : '');
 
-// ----------------------------------------------------------------------
-// pre defined values - used for dropdowns
-// ----------------------------------------------------------------------
-
-$aPresets=[
-
-    'colors'=>[
-        // https://adminlte.io/themes/v3/pages/UI/general.html
-        ''=>'no value',
-        'indigo'=>'indigo',
-        'lightblue'=>'',
-        'navy'=>'',
-        'purple'=>'',
-        'fuchsia'=>'',
-        'pink'=>'',
-        'maroon'=>'',
-        'orange'=>'',
-        'lime'=>'',
-        'teal'=>'',
-        'olive'=>'',
-
-        'black'=>'black',
-        'dark'=>'dark gray',
-        'gray'=>'gray', 
-        'light'=>'light gray', 
-    ],
-
-    'type'=>[
-        ''=>'no value',
-        'danger'=>'red',
-        'info'=>'aqua',
-        'primary'=>'blue',
-        'secondary'=>'gray',
-        'success'=>'green',
-        'warning'=>'yellow',
-        'dark'=>'dark gray',
-        'gray'=>'gray', 
-    ],
-    'shadow'=>[
-        ''=>'no value', 
-        'none'=>'none',
-        'small'=>'small', 
-        'regular'=>'regular',
-        'large'=>'large'
-    ],
-    'size'=>[
-        ''=>'no value',
-        'lg'=>'',
-        'sm'=>'',
-        'xs'=>'',
-        'flat'=>'',
-    ],
-    'variant'=>[
-        ''=>'no value',
-        'outline'=>'small stripe on top',
-        'solid'=>'',
-        'gradient'=>'',
-    ],
-    'visibility'=>[
-        ''=>'no value', 
-        '0'=>'hide', 
-        '1'=>'show',
-    ],
-    // for keys: state
-    'windowstate'=>[
-        ''=>'no value', 
-        'collapsed'=>'header only', 
-        'maximized'=>'full window',
-    ],
-    // for keys: dismissable
-    'yesno'=>[
-        ''=>'no value', 
-        '0'=>'no', 
-        '1'=>'yes',
-    ],
-];
-
-// ----------------------------------------------------------------------
-// definition of a component
-// ----------------------------------------------------------------------
-$aComponents=[
+/**
+ * @var options array for example widget to display
+ */
+$aWidgetOptions=[];
 
-    // ------------------------------------------------------------
-    'alert'=>[
-        'label'=>'Alert',
-        'description'=>'',
-        'method'=>'getAlert',
+// get all components ... as key or all items
+// print_r($renderAdminLTE->getComponents({true|false}));
 
-        'params'=>[
-            'type'        => ['select'=>$aPresets['type'],     'default'=>'warning'],
-            'dismissible' => ['select'=>$aPresets['yesno'],    'default'=>''],
-            'title'       => ['default'=>'Alert title'],
-            'text'        => ['default'=>'I am a message. Read me, please.'],
-        ]
-    ],
-    // ------------------------------------------------------------
-    'badge'=>[
-        'label'=>'Badge',
-        'description'=>'Tiny additional info; mostly as counter',
-        'method'=>'getBadge',
+// get array of a component
+// print_r($renderAdminLTE->getComponent($sComponent));
 
-        'params'=>[
-            'type'        => ['select'=>$aPresets['type'],     'default'=>'danger'],
-            'bgcolor'     => ['select'=>$aPresets['colors'],   'default'=>''],
-            'class'       => ['default'=>''],
-            'id'          => ['default'=>''],
-            'title'       => ['default'=>'Errors: 5'],
-            'text'        => ['default'=>'5'],
-        ]
-    ],
-    // ------------------------------------------------------------
-    'button'=>[
-        'label'=>'Button',
-        'description'=>'Buttons',
-        'method'=>'getButton',
 
-        'params'=>[
-            'type'        => ['select'=>$aPresets['type'],     'default'=>'primary'],
-            'size'        => ['select'=>$aPresets['size'],     'default'=>''],
-            'text'        => ['default'=>'Click me'],
-        ]
-    ],
-    // ------------------------------------------------------------
-    'callout'=>[
-        'label'=>'Callout',
-        'description'=>'Kind of infobox',
-        'method'=>'getCallout',
+// echo '<pre>';
+// print_r($renderAdminLTE->getComponent($sComponent));
+// echo '</pre>';
 
-        'params'=>[
-            'type'        => ['select'=>$aPresets['type'],     'default'=>'danger'],
-            'class'       => ['default'=>''],
-            'title'       => ['default'=>'I am a callout'],
-            'text'        => ['default'=>'Here is some description to whatever.'],
-        ]
-    ],
-    // ------------------------------------------------------------
-    'card'=>[
-        'label'=>'Callout',
-        'description'=>'Content box with header, text, footer',
-        'method'=>'getCard',
 
-        'params'=>[
-            'variant'     => ['select'=>$aPresets['variant'],  'default'=>''],
-            'type'        => ['select'=>$aPresets['type'],     'default'=>'danger'],
-            'class'       => ['default'=>''],
-            'state'       => ['select'=>$aPresets['windowstate'], 'default'=>''],
+// echo '<pre>';
+// print_r($renderAdminLTE->getComponentParamkey($sComponent, 'type'));
+// echo '</pre>';
 
-            'tb-collapse' => ['select'=>$aPresets['visibility'], 'default'=>''],
-            'tb-expand'   => ['select'=>$aPresets['visibility'], 'default'=>''],
-            'tb-maximize' => ['select'=>$aPresets['visibility'], 'default'=>''],
-            'tb-minimize' => ['select'=>$aPresets['visibility'], 'default'=>''],
-            'tb-remove'   => ['select'=>$aPresets['visibility'], 'default'=>''],
 
-            'title'       => ['default'=>'I am a card'],
-            'tools'       => ['default'=>'Tools'],
-            'text'        => ['default'=>'Here is some beautiful content.'],
-            'footer'      => ['default'=>'Footer'],
-        ]
-    ],
-    // ------------------------------------------------------------
-    'infobox'=>[
-        'label'=>'Infobox',
-        'description'=>'',
-        'method'=>'getInfobox',
-
-        'params'=>[
-            'type'=>['select'=>$aPresets['type'],     'default'=>''],
-            'iconbg'=>['select'=>$aPresets['type'],   'default'=>'info'],
-            'shadow'=>['select'=>$aPresets['shadow'], 'default'=>''],
-            'icon'=>['default'=>'far fa-thumbs-up'],
-            'text'=>['default'=>'Likes'],
-            'number'=>['default'=>"41,410"],
-            'progressvalue'=>['default'=>70],
-            'progresstext'=>['default'=>'70% Increase in 30 Days']
-        ]
-    ],
-];
+// ----------------------------------------------------------------------
 
-if(!isset($aComponents[$sComponent])){
+if(!$renderAdminLTE->getComponent($sComponent)) {
     echo '
     <h2>Ooops</h2>
     <p>Maybe there is a typo ... the component <strong>&quot;'.$sComponent.'&quot;</strong> was not found.</p>
     ';
 } else {
 
-
-    $aComp=$aComponents[$sComponent];
-
+    $aComp=$renderAdminLTE->getComponent($sComponent);
 
     // --------- prepare output for parameter Testing
     $sTester='<form
@@ -202,19 +46,21 @@ if(!isset($aComponents[$sComponent])){
         <tbody>
     ';
 
-    $aWidgetOptions=[];
-    foreach($aComp['params'] as $sOptionkey=>$aParam){
+
+
+    $renderAdminLTE->getComponentParamkeys($sComponent, 1);
+    foreach($renderAdminLTE->getComponentParamkeys($sComponent, true) as $sOptionkey=>$aParam){
         $sInput='';
         $sValue=(isset($_GET[$sOptionkey]) ? $_GET[$sOptionkey] : (
-                isset($aParam['default'])
-                    ? $aParam['default']
+                isset($aParam['example_value'])
+                    ? $aParam['example_value']
                     : ''
         ));
         if($sValue!==''){
             $aWidgetOptions[$sOptionkey]=$sValue;
         }
         if (isset($aParam['select'])){
-            foreach($aParam['select'] as $sSelectItem=>$sLabel){
+            foreach($aParam['select']['values'] as $sSelectItem=>$sLabel){
                 // $sInput.='<option value="'.$sSelectItem.'">'.($sSelectItem ? $sSelectItem : '-- none --').'</option>';
                 $sInput.='<option value="'.$sSelectItem.'"'
                 .($sValue==$sSelectItem ? ' selected="selected"' : '')
@@ -223,11 +69,14 @@ if(!isset($aComponents[$sComponent])){
             $sInput='<nobr><select size="1" name="'.$sOptionkey.'" onchange="form.submit();">'.$sInput.'</select>'
                 .' <button name="doloop" value="'.$sOptionkey.'">Loop</button><nobr>';
 
-           
         } else {
             $sInput.='<input type="text" name="'.$sOptionkey.'" value="'.$sValue.'"/>';
         }
-        $sTester.='<tr><td>'.$sOptionkey .'</td><td colspan="2">'. $sInput.'</td></tr>';
+        // testing - table row
+        $sTester.='<tr>
+            <td><code>'.$sOptionkey.'</code><br>('.$aParam['group'] .')</td>
+            <td>'. $aParam['description'] .'<br>'.$sInput.'</td>
+        </tr>';
     }
     $sTester.='
     
@@ -238,17 +87,13 @@ if(!isset($aComponents[$sComponent])){
 
     // --------- loop over a single var
     $sLooper='';
-    if(isset($_GET['doloop']) && isset($aComp['params'][$_GET['doloop']])){
+    if(
+        isset($_GET['doloop']) 
+        && $renderAdminLTE->getComponentParamkey($sComponent, $_GET['doloop'])
+    ){
         $sLoopvar=$_GET['doloop'];
         
-        /*
-        $sLooper.=$renderAdminLTE->addRow(
-            '<h3 id="#loops">Loop over option key ['.$sLoopvar.']</h3>'
-            . implode(" | ", array_keys($aComp['params'][$sLoopvar]['select']))
-        );
-        */
-        
-        foreach(array_keys($aComp['params'][$sLoopvar]['select']) as $sLoopValue){
+        foreach($renderAdminLTE->getValidParamValues($sComponent, $sLoopvar) as $sLoopValue){
             $aLoopoptions=$aWidgetOptions;
             $aLoopoptions[$sLoopvar]=$sLoopValue;
 
@@ -264,21 +109,24 @@ if(!isset($aComponents[$sComponent])){
     echo $renderAdminLTE->addRow(
         '<h2>'.$aComp['label'].'</h2>'
     )
-
     .$renderAdminLTE->addRow(
-        $renderAdminLTE->getCard(['title'=>'Syntax', 'text'=>'<pre>echo $renderAdminLTE-><strong>'.$aComp['method'].'</strong>($aOptions)</pre>'])
+        '<p>'.$aComp['description'].'</p>'
     )
 
+    // .$renderAdminLTE->addRow(
+    //     $renderAdminLTE->getCard(['title'=>'Syntax', 'text'=>'<pre>echo $renderAdminLTE-><strong>'.$aComp['method'].'</strong>($aOptions)</pre>'])
+    // )
+
     .$renderAdminLTE->addRow(
         '<h3>Testing section</h3>'
     )
     .$renderAdminLTE->addRow(
         $renderAdminLTE->addCol(
             $renderAdminLTE->getCard(['title'=>'Parameter keys for '.$sComponent, 'text'=>$sTester]), 
-            3
+            4
         ).$renderAdminLTE->addCol(
             showExample('$renderAdminLTE->'.$aComp['method'].'('.var_export($aWidgetOptions, 1).')') ,
-            9
+            8
         )
     )
     .(
diff --git a/public_html/ui/main.css b/public_html/ui/main.css
index 6f105f0..90148d7 100644
--- a/public_html/ui/main.css
+++ b/public_html/ui/main.css
@@ -1,4 +1,4 @@
 
-pre{background-color: #445; color: #f8f8f8}
+pre{background-color: #445; color: #aaa}
 pre .params{color: #acc}
 pre .output{color: #aaf}
\ No newline at end of file
-- 
GitLab