Banano one step ahead

How interested are you in developing WebApps?

  • Not at all

    Votes: 0 0.0%
  • Little

    Votes: 6 20.7%
  • Lot

    Votes: 12 41.4%
  • I am interested in additional libraries

    Votes: 2 6.9%
  • I would pay for new libraries

    Votes: 3 10.3%
  • I would donate a kidney to learn more

    Votes: 2 6.9%
  • What is banano?

    Votes: 4 13.8%

  • Total voters
    29

Star-Dust

Expert
Licensed User
Longtime User
I would title this post like this: I was on the edge of the precipice now I've taken a step forward

Premise

I have recently worked with WebApps, customers prefer them and above all the stores (Apple and mostly Google) are making life difficult for developers.
For a few years I have been using Banano (by @alwaysbusy ) with Vuetify (by @Mashiane ). The last project was large and took too long to compile. Once the project was finished I thought I'd take a step forward.

Questions
I asked myself why I have always used Banano with Vuetify (excellent library) and never without, perhaps using skeleton. Would he have been as attractive? It certainly would have been much lighter
I downloaded and studied some examples and the result seemed satisfactory to me. But it was missing some fancier components that I find with Vuetify.
What if I had created them myself? I downloaded other examples and read some tutorials.
I tried other frameworks (Alpine.JS, Bootstrap, svelte ...) creating test components.

One step forward
In the end I concluded that I didn't need frameworks to manage data, rotation, etc.. but only graphics... which you can get with CSS or other free js sources you find around...
I decided to create my own Banano library with the views I need and which is light.
In fact I went from 5/7 minutes of compilation to less than 40 seconds.... I have to add many components, little by little I will get there

The result? Here is a small example ... A WebApp for pizza delivery

1731865483713.png


1731865492368.png
 

Mashiane

Expert
Licensed User
Longtime User
In the end I concluded that I didn't need frameworks to manage data, rotation, etc..
Awesome news. Glad you worked something out. I love the UI, amazing work, congrats, and thanks for this feedback.

One of the best thing you can always do for your app is tree-shaking it with remove dead code transpiler options before production in BANano. With BVAD3, because its a VueJS based library unlike Skeleton or any simple library, this can only be done via the BVAD3 Package Manager. That is what I've used with client apps to speed them up as this ensures that only the components used in your app are available and not the whole b4xlib.

BVAD4 is coming in 2025 using Vue3 which will have a lot of improvements and whilst BANano was never built around VueJS, it has been kicking a punch, thanks to Alain.

I am still interested though, whether when it comes to more speed, what is much better between writing code or use layouts for the UI.

Enjoy!
 

alwaysbusy

Expert
Licensed User
Longtime User
In the end I concluded that I didn't need frameworks to manage data, rotation, etc.. but only graphics... which you can get with CSS or other free js sources you find around...
I 100% agree and in many of our projects we also move away from standard UI frameworks and just write the extra CSS/BANano code for components specific for that project.

And your WebApp looks great!
 

Star-Dust

Expert
Licensed User
Longtime User
To give a small example of how you can easily build a component, I will show you My Numeric Stepper.
You see in the image the result and also how it looks in the design, a single object.
Below you will find the code. Obviously this is just one of the components I'm creating. I hope it is useful for others to create components on their own

1731949500908.png


B4X:
#Event: Click (event As BANanoEvent)

#DesignerProperty: Key: Value, DisplayName: Start value, FieldType: Int, DefaultValue: 0, Description: Starter value
#DesignerProperty: Key: minValue, DisplayName: Min value, FieldType: Int, DefaultValue: 0, Description: Minimum value
#DesignerProperty: Key: maxValue, DisplayName: Max value, FieldType: Int, DefaultValue: 10, Description: Maximum value
#DesignerProperty: Key: TextColor, DisplayName: Number Color, FieldType: Color, DefaultValue: 0xFF000000, Description: Text Color
#DesignerProperty: Key: Background, DisplayName: Background Color, FieldType: Color, DefaultValue: 0x00FFFFFF, Description: Background Color
#DesignerProperty: Key: btnTextColor, DisplayName: Button text Color, FieldType: Color, DefaultValue: 0xFFFFFFFF, Description: Button Text Color
#DesignerProperty: Key: btnBackground, DisplayName: Button Background Color, FieldType: Color, DefaultValue: 0xFFA52A2A, Description: Button  Background Color
#DesignerProperty: Key: Classes, DisplayName: Classes, FieldType: String, DefaultValue: sd-stepper, Description: Classes added to the HTML tag.
#DesignerProperty: Key: Style, DisplayName: Style, FieldType: String, DefaultValue: , Description: Styles added to the HTML tag. Must be a json String.
#DesignerProperty: Key: MarginLeft, DisplayName: Margin Left, FieldType: String, DefaultValue: , Description: Margin Left
#DesignerProperty: Key: MarginRight, DisplayName: Margin Right, FieldType: String, DefaultValue: , Description: Margin Right
#DesignerProperty: Key: MarginTop, DisplayName: Margin Top, FieldType: String, DefaultValue: , Description: Margin Top
#DesignerProperty: Key: MarginBottom, DisplayName: Margin Bottom, FieldType: String, DefaultValue: , Description: Margin Bottom
#DesignerProperty: Key: PaddingLeft, DisplayName: Padding Left, FieldType: String, DefaultValue: , Description: Padding Left
#DesignerProperty: Key: PaddingRight, DisplayName: Padding Right, FieldType: String, DefaultValue: , Description: Padding Right
#DesignerProperty: Key: PaddingTop, DisplayName: Padding Top, FieldType: String, DefaultValue: , Description: Padding Top
#DesignerProperty: Key: PaddingBottom, DisplayName: Padding Bottom, FieldType: String, DefaultValue: , Description: Padding Bottom
#DesignerProperty: Key: Enabled, DisplayName: Enabled, FieldType: Boolean, DefaultValue: True, Description: If enabled.
#DesignerProperty: Key: Visible, DisplayName: Visible, FieldType: Boolean, DefaultValue: True, Description: If visible.
#DesignerProperty: Key: Type, DisplayName: Type, FieldType: String, DefaultValue: p, List: p|div|span|h1|h2|h3|h4|h5|h6, Description: Type of label
#DesignerProperty: Key: StringWithListExample, DisplayName: String With List, FieldType: String, DefaultValue: Sunday, List: Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday

Sub Class_Globals
    Private BANano As BANano 'ignore
    Private mName As String 'ignore
    Private mEventName As String 'ignore
    Private mCallBack As Object 'ignore
    Private mTarget As BANanoElement 'ignore
    Private mElement As BANanoElement 'ignore
    Private btnMeno As BANanoElement 'ignore
    Private btnPiu As BANanoElement 'ignore
    
    Private mValue As String = ""
    Private minValue As Int = 0
    Private maxValue As Int = 10
    Private mTextColor As String = ""
    Private mBackground As String = ""
    Private mbtnTextColor As String = ""
    Private mbtnBackground As String = ""
    Private mClasses As String = ""
    Private mStyle As String = ""
    Private mMarginLeft As String = ""
    Private mMarginRight As String = ""
    Private mMarginTop As String = ""
    Private mMarginBottom As String = ""
    Private mPaddingLeft As String = ""
    Private mPaddingRight As String = ""
    Private mPaddingTop As String = ""
    Private mPaddingBottom As String = ""
    Private mVisible As Boolean = True
    Private mEnabled As Boolean = True
    Private mType As String = "p"
    
    Private mTag As Object
End Sub

' initializes the component
Public Sub Initialize (CallBack As Object, Name As String, EventName As String)
    mName = Name
    mEventName = EventName.ToLowerCase
    mCallBack = CallBack
End Sub

' returns the BANanoElement
public Sub getElement() As BANanoElement
    Return mElement
End Sub

' returns the tag id
public Sub getID() As String
    Return mName
End Sub

' this is the place where you create the view in html and run initialize javascript
Public Sub DesignerCreateView (Target As BANanoElement, Props As Map)
    mTarget = Target

    If Props <> Null Then
        mValue = Props.Get("Value")
        minValue = 1 * Props.Get("minValue")
        maxValue = 1 * Props.Get("maxValue")
        mTextColor = Props.Get("TextColor")
        mBackground = Props.Get("Background")
        mbtnTextColor = Props.Get("btnTextColor")
        mbtnBackground = Props.Get("btnBackground")
        mClasses = Props.Get("Classes")
        mStyle = Props.Get("Style")
        mMarginLeft = Props.Get("MarginLeft")
        mMarginRight = Props.Get("MarginRight")
        mMarginTop = Props.Get("MarginTop")
        mMarginBottom = Props.Get("MarginBottom")
        mPaddingLeft = Props.Get("PaddingLeft")
        mPaddingRight = Props.Get("PaddingRight")
        mPaddingTop = Props.Get("PaddingTop")
        mPaddingBottom = Props.Get("PaddingBottom")
        mVisible = Props.Get("Visible")
        mEnabled = Props.Get("Enabled")
        mType = Props.Get("Type")
    End If
    
    Dim exStyle As String = BuildExStyle
    
    mElement = mTarget.Append($"<div id="div${mName}" class="sd-label" style="width: 100%; ${exStyle}${mStyle}">
        <div style="width: 33%; height: 50px; text-align: center; line-height: 50px; ">
            <button id="meno-${mName}" Type="button" class="${mClasses}" style="border-radius: 50%;padding: 10px 15px;">-</button>
        </div>
        <div style="width: 33%; height: 50px; text-align: center; line-height: 50px; ">
            <${mType} id="${mName}">${mValue}</${mType}>
        </div>
        <div style="width: 33%; height: 50px; text-align: center; line-height: 50px; ">
            <button id="plus-${mName}" Type="button" class="${mClasses}" style="border-radius: 50%;padding: 10px 15px;">+</button>
        </div>
    </div>"$)
                
    btnMeno = mElement.Get($"#meno-${mName}"$)
    btnPiu = mElement.Get($"#plus-${mName}"$)
    btnMeno.HandleEvents("click", Me, "meno_click")
    btnPiu.HandleEvents("click", Me, "piu_click")
    
    setBackgroundColor(mBackground)
    setTextColor(mTextColor)
    setbtnBackgroundColor(mbtnBackground)
    setbtnTextColor(mbtnTextColor)
End Sub

' add the component to a parent tag
public Sub AddToParent(targetID As String)
    mTarget = BANano.GetElement("#" & targetID.ToLowerCase)
    DesignerCreateView(mTarget, Null)
End Sub

' removes the component from the parent tag
public Sub Remove()
    mTarget.Empty
    BANano.SetMeToNull
End Sub

#Region common shared properties and methods
' trigger an event
public Sub Trigger(event As String, params() As String)
    If mElement <> Null Then
        mElement.Trigger(event, params)
    End If
End Sub

' internal method to build the style
public Sub BuildExStyle() As String
    Dim sb As StringBuilder
    sb.Initialize
    If mMarginLeft <> "" Then sb.Append("margin-left: " & mMarginLeft & ";")
    If mMarginRight <> "" Then sb.Append("margin-right: " & mMarginRight & ";")
    If mMarginTop <> "" Then sb.Append("margin-top: " & mMarginTop & ";")
    If mMarginBottom <> "" Then sb.Append("margin-bottom: " & mMarginBottom & ";")
    If mPaddingLeft <> "" Then sb.Append("padding-left: " & mPaddingLeft & ";")
    If mPaddingRight <> "" Then sb.Append("padding-right: " & mPaddingRight & ";")
    If mPaddingTop <> "" Then sb.Append("padding-top: " & mPaddingTop & ";")
    If mPaddingBottom <> "" Then sb.Append("padding-bottom: " & mPaddingBottom & ";")
    Return sb.ToString
End Sub

' set css classes to the main tag
public Sub setClasses(Classes As String)
    If mElement <> Null Then
        mElement.AddClass(Classes)
    End If
    mClasses = Classes
End Sub

public Sub getClasses() As String
    Return mClasses
End Sub

' get/set the style of the main tag
public Sub setStyle(Style As String)
    Dim tmpStyle As String = Style
    If tmpStyle.StartsWith("{") = False Then
        Dim spl() As String = BANano.Split(";", Style)
        Dim m As Map
        m.Initialize
        For i = 0 To spl.Length - 1
            Dim spl2() As String = BANano.Split(":", spl(0))
            Dim key As String = spl2(0).Replace(Chr(34), "").trim
            Dim val As String = spl2(1).Replace(Chr(34), "").trim
            m.Put(key, val)
        Next
        Dim jsonG As BANanoJSONGenerator
        jsonG.Initialize(m)
        tmpStyle = jsonG.ToString
    End If
    If mElement <> Null Then
        mElement.SetStyle(Style)
    End If
    mStyle = Style
End Sub

public Sub getStyle() As String
    Return mStyle
End Sub

' get/set if the component is visible
public Sub setVisible(Visible As Boolean)
    If mElement <> Null Then
        If Visible Then
            mElement.RemoveClass("u-hide")
        Else
            mElement.AddClass("u-hide")
        End If
    End If
    mVisible=Visible
End Sub

public Sub getVisible() As Boolean
    mVisible = Not(mElement.HasClass("u-hide"))
    Return mVisible
End Sub

' get/set if the component is enabled
public Sub setEnabled(Enabled As Boolean)
    If mElement <> Null Then
        If Enabled Then
            mElement.RemoveAttr("disabled")
        Else
            mElement.SetAttr("disabled", True)
        End If
    End If
    mEnabled = Enabled
End Sub

public Sub getEnabled() As Boolean
    mEnabled = Not(mElement.hasAttr("disabled"))
    Return mEnabled
End Sub

' get/set the margin left of the main tag
public Sub setMarginLeft(mar As String)
    mMarginLeft = mar
End Sub

public Sub getMarginLeft() As String
    Return mMarginLeft
End Sub

' get/set the margin right of the main tag
public Sub setMarginRight(mar As String)
    mMarginRight = mar
End Sub

public Sub getMarginRight() As String
    Return mMarginRight
End Sub

' get/set the margin top of the main tag
public Sub setMarginTop(mar As String)
    mMarginTop = mar
End Sub

public Sub getMarginTop() As String
    Return mMarginTop
End Sub

' get/set the margin bottom of the main tag
public Sub setMarginBottom(mar As String)
    mMarginBottom = mar
End Sub

public Sub getMarginBottom() As String
    Return mMarginBottom
End Sub

' get/set the Padding left of the main tag
public Sub setPaddingLeft(pad As String)
    mPaddingLeft = pad
End Sub

public Sub getPaddingLeft() As String
    Return mPaddingLeft
End Sub

' get/set the Padding right of the main tag
public Sub setPaddingRight(pad As String)
    mPaddingRight = pad
End Sub

public Sub getPaddingRight() As String
    Return mPaddingRight
End Sub

' get/set the Padding top of the main tag
public Sub setPaddingTop(pad As String)
    mPaddingTop = pad
End Sub

public Sub getPaddingTop() As String
    Return mPaddingTop
End Sub

' get/set the Padding bottom of the main tag
public Sub setPaddingBottom(pad As String)
    mPaddingBottom = pad
End Sub

public Sub getPaddingBottom() As String
    Return mPaddingBottom
End Sub

' get/set attach any object to the component
public Sub setTag(t As Object)
    mTag = t
End Sub

public Sub getTag() As Object
    Return mTag
End Sub

public Sub setValue(t As String)
    If BANano.IsNumber(t) Then
        mValue = t
        Dim be As BANanoElement = BANano.GetElement("#" & mName)
        be.SetText(t)
    End If
End Sub

public Sub getValue() As String
    Return mValue
End Sub

Public Sub setBackgroundColor(Color As String)
    mBackground=Color
    BANano.GetElement("#" & mName).SetStyle($"{"background-color":"${Color}"}"$)
    BANano.GetElement("#div" & mName).SetStyle($"{"background-color":"${Color}"}"$)
End Sub

Public Sub getBackgroundColor As String
    Return mBackground
End Sub

Public Sub setTextColor(Color As String)
    mTextColor=Color
    Dim be As BANanoElement = BANano.GetElement("#" & mName)
    be.SetStyle($"{"color":"${Color}"}"$)
End Sub

Public Sub getTextgroundColor As String
    Return mTextColor
End Sub

Public Sub setbtnBackgroundColor(Color As String)
    mbtnBackground=Color
    btnMeno.SetStyle($"{"background-color":"${Color}"}"$)
    btnPiu.SetStyle($"{"background-color":"${Color}"}"$)
End Sub

Public Sub getbtnBackgroundColor As String
    Return mbtnBackground
End Sub

Public Sub setbtnTextColor(Color As String)
    mbtnTextColor=Color
    btnMeno.SetStyle($"{"color":"plus-${Color}"}"$)
    btnPiu.SetStyle($"{"color":"meno-${Color}"}"$)
End Sub

Public Sub getbtnTextgroundColor As String
    Return mbtnTextColor
End Sub

#End Region

#Region Internal Events

Private Sub meno_click
    mValue=Max(mValue-1,minValue)
    Dim be As BANanoElement = BANano.GetElement("#" & mName)
    be.SetText(mValue)
End Sub

private Sub piu_click
    mValue=Min(mValue+1,maxValue)
    Dim be As BANanoElement = BANano.GetElement("#" & mName)
    be.SetText(mValue)
End Sub

#End Region



#IF CSS
 /* -----------------------------  Stili per label */
    .sd-label {
      background-color: white;
      border: none;
      color: black;
      padding: 15px 32px;
      text-align: center;
      text-decoration: none;
      display: inline-flex; /* Utilizzo di flexbox per l'allineamento */
      justify-content: center; /* Centra il testo orizzontalmente */
      align-items: center; /* Centra il testo verticalmente */
      font-size: 16px;
      border-radius: 8px; /* Angoli arrotondati */
      cursor: pointer;
      transition: background-color 0.3s ease, transform 0.2s ease;
    }

    /* Effetto di focus (quando il bottone è selezionato) */
    .sd-label:focus {
      outline: none;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
    }

 /* -----------------------------  Stili per stepper */
    .sd-stepper {
      background-color: #AAAAAA; /* Colore di sfondo grigio */
      border: none;
      color: white;
      padding: 15px 32px;
      text-align: center;
      text-decoration: none;
      display: inline-flex; /* Utilizzo di flexbox per l'allineamento */
      justify-content: center; /* Centra il testo orizzontalmente */
      align-items: center; /* Centra il testo verticalmente */
      font-size: 18px;
      border-radius: 10px; /* Angoli arrotondati */
      cursor: pointer;
      transition: background-color 0.3s ease, transform 0.2s ease;
    }

    /* Effetto hover */
    .sd-stepper:hover {
      background-color: #FF45A049; /* Colore di sfondo quando si passa sopra */
      color: black;
      transform: scale(1.1); /* Aumento dimensione al passaggio del mouse */
    }

    /* Effetto di focus (quando il bottone è selezionato) */
    .sd-stepper:focus {
      outline: none;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
    }
#End If
 

Star-Dust

Expert
Licensed User
Longtime User
I have to be honest, I hit a wall for a couple of days until I understood some of the problems generated by DIVs and now these are some of the components created

1732016637319.png
 

Star-Dust

Expert
Licensed User
Longtime User
Interesting, mind to share...
Using SKColumn on some components did not respect the width, even if set to 1/12 it always went full screen. after days I realized it was the DIV. So I created my own Column and will also create my own Rows
 
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
I'm sure you will create very nice components for BANano, your creativity is incredible.
Thanks, but they don't believe they have creativity, the b4x tool makes it very easy to create views and components
 
  • Like
Reactions: byz

rabbitBUSH

Well-Known Member
Licensed User
until I understood some of the problems generated by DIVs
such is life - as is said in france i believe.
i've struggled with all these ABMs and BANANOs and whatnot . . . . .myself.....Oi!
 

alwaysbusy

Expert
Licensed User
Longtime User
That is the fun part with BANano: you can make whatever you want, it just provides the language Transpiler and the B4J Abstract Designer support and you can create whatever web component you want. The code will be transpiled to JavaScript, you can use inline CSS (and JavaScript) like Star-Dust does here to make new components. The grid (row/columns) of the BANanoSkeleton library does indeed have some quirks (it may be over simplified by the Skeleton library it is based on) and for some projects we don't use them either and just make our own 'Grid' system as it really is not that hard to do once you get the grip on how such a responsive system works.

Looking forward to see some original components because that is exactly why BANano was developed/shared to the community by us!
 
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
These are some developed components. The Grid is basic but functional, I will probably create a second more complex grid similar to SD_FlexGrid later.

What I have created so far I will most likely share the sources. I will not share future changes and components that I will add from today onwards, but I will continue to update the progress on this thread

Nuovovideo-ezgif.com-optimize.gif



Developed componentsIn planning
  • Button
  • Col
  • Combo
  • Container
  • Grdi
  • Icon
  • Image
  • Label
  • List
  • Row
  • ScrollHorizzontale
  • Select
  • Stepper
  • Switch
  • ToastMessage
  • Modal Dialog Box
  • FlexGrid
  • Calendar
  • Card
  • Date boxes
  • Time boxes
  • Plaining
  • Chips
  • Stats (maybe)
 
Last edited:

Star-Dust

Expert
Licensed User
Longtime User
Find a smaller version of the library here

 

yiankos1

Well-Known Member
Licensed User
Longtime User
Great work SD!

It would be usefull for community to create a tutorial: How to create custom components in BANano.

Lets say i find a JS component in github, how to make it working in BANano.
 

alwaysbusy

Expert
Licensed User
Longtime User
@yiankos1 Chapter 11 in the booklet talks about creating custom components. It is hard to write a 'general tutorial' on how to create one as every component found on the internet has its own rules and syntax. You can always unzip e.g. the BANanoSkeleton.b4xlib file and see how I wrapped some JS components as there is a variety of components in there.
 

Star-Dust

Expert
Licensed User
Longtime User
I'm slow going but I'm working on it.
Now I'm working on a planner with activity panels that can be simple text or customizable panels. Each panel can be loaded with LoadLayout

1733519552185.png


B4X:
SDplanning1.AddItem(0,"0",DateTime.TimeParse("08:00"),60,"Test 1")
SDplanning1.AddItem(2,"1",DateTime.TimeParse("10:00"),60,"test 2")
SDplanning1.AddItem(2,"2",DateTime.TimeParse("11:10"),60,"Test 3")
SDplanning1.AddElement(4,"3",DateTime.TimeParse("11:10"),60).LoadLayout("item")
SDplanning1.AddElement(6,"4",DateTime.TimeParse("12:00"),60).SetText("Text 4")
SDplanning1.SetHeaderStyle("lightgray","black")
SDplanning1.SetHeader(Array As String("15 feb","16 feb","17 feb","18 feb","19 feb","20 feb","21 feb"))
 

Star-Dust

Expert
Licensed User
Longtime User
Using LoadLayout in a component that loads the same layout in multiple places creates the problem that they all have the same ID and identifying and modifying them becomes a problem. Various conflicts arise.

But I found a solution, now I have to refine it.
 
Top