diff options
| -rw-r--r-- | Module.md | 4 | ||||
| -rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt | 47 | ||||
| -rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/navbar/Nav.kt | 55 | ||||
| -rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/navbar/NavForm.kt | 56 | ||||
| -rw-r--r-- | src/main/kotlin/pl/treksoft/kvision/navbar/Navbar.kt | 171 | ||||
| -rw-r--r-- | src/main/resources/css/style.css | 7 | 
6 files changed, 330 insertions, 10 deletions
| @@ -52,6 +52,10 @@ Components supporting complete set of HTML tags, with dedicated classes for butt  Classes supporting general purpose Bootstrap modals with convenient helpers for alert and confirm popup dialogs. +# Package pl.treksoft.kvision.navbar + +Bootstrap navbar components. +  # Package pl.treksoft.kvision.panel  Rich set of container classes, supporting both simple use cases and sophisticated layouts (including CSS flexbox, diff --git a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt index 44396951..9a349707 100644 --- a/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt +++ b/src/main/kotlin/pl/treksoft/kvision/dropdown/DropDown.kt @@ -22,16 +22,17 @@  package pl.treksoft.kvision.dropdown  import com.github.snabbdom.VNode +import pl.treksoft.kvision.KVManager  import pl.treksoft.kvision.core.Component  import pl.treksoft.kvision.core.Container  import pl.treksoft.kvision.core.CssSize  import pl.treksoft.kvision.core.StringBoolPair  import pl.treksoft.kvision.core.StringPair -import pl.treksoft.kvision.html.ButtonStyle  import pl.treksoft.kvision.html.Button -import pl.treksoft.kvision.html.ListType +import pl.treksoft.kvision.html.ButtonStyle  import pl.treksoft.kvision.html.Link  import pl.treksoft.kvision.html.ListTag +import pl.treksoft.kvision.html.ListType  import pl.treksoft.kvision.html.TAG  import pl.treksoft.kvision.html.Tag  import pl.treksoft.kvision.panel.SimplePanel @@ -55,11 +56,12 @@ enum class DD(val option: String) {   * @param icon the icon of the dropdown button   * @param style the style of the dropdown button   * @param disabled determines if the component is disabled on start + * @param forNavbar determines if the component will be used in a navbar   * @param classes a set of CSS class names   */  open class DropDown(      text: String, elements: List<StringPair>? = null, icon: String? = null, -    style: ButtonStyle = ButtonStyle.DEFAULT, disabled: Boolean = false, +    style: ButtonStyle = ButtonStyle.DEFAULT, disabled: Boolean = false, val forNavbar: Boolean = false,      classes: Set<String> = setOf()  ) : SimplePanel(classes) {      /** @@ -136,7 +138,7 @@ open class DropDown(      private val idc = "kv_dropdown_$counter"      internal val button: DropDownButton = DropDownButton(          idc, text, icon, style, -        disabled, setOf("dropdown") +        disabled, forNavbar, setOf("dropdown")      )      internal val list: DropDownListTag = DropDownListTag(idc, setOf("dropdown-menu")) @@ -147,6 +149,14 @@ open class DropDown(          counter++      } +    override fun render(): VNode { +        return if (forNavbar) { +            render("li", childrenVNodes()) +        } else { +            render("div", childrenVNodes()) +        } +    } +      override fun add(child: Component): SimplePanel {          list.add(child)          return this @@ -171,7 +181,6 @@ open class DropDown(          return list.getChildren()      } -      private fun setChildrenFromElements() {          list.removeAll()          elements?.let { elems -> @@ -237,10 +246,10 @@ open class DropDown(           */          fun Container.dropDown(              text: String, elements: List<StringPair>? = null, icon: String? = null, -            style: ButtonStyle = ButtonStyle.DEFAULT, disabled: Boolean = false, +            style: ButtonStyle = ButtonStyle.DEFAULT, disabled: Boolean = false, navbar: Boolean = false,              classes: Set<String> = setOf(), init: (DropDown.() -> Unit)? = null          ): DropDown { -            val dropDown = DropDown(text, elements, icon, style, disabled, classes).apply { init?.invoke(this) } +            val dropDown = DropDown(text, elements, icon, style, disabled, navbar, classes).apply { init?.invoke(this) }              this.add(dropDown)              return dropDown          } @@ -249,7 +258,7 @@ open class DropDown(  internal class DropDownButton(      id: String, text: String, icon: String? = null, style: ButtonStyle = ButtonStyle.DEFAULT, -    disabled: Boolean = false, classes: Set<String> = setOf() +    disabled: Boolean = false, val forNavbar: Boolean = false, classes: Set<String> = setOf()  ) :      Button(text, icon, style, disabled, classes) { @@ -257,10 +266,30 @@ internal class DropDownButton(          this.id = id      } +    override fun render(): VNode { +        val text = createLabelWithIcon(text, icon, image) +        return if (forNavbar) { +            val textWithCarret = text.toMutableList() +            textWithCarret.add(" ") +            textWithCarret.add(KVManager.virtualize("<span class='caret'></span>")) +            render("a", textWithCarret.toTypedArray()) +        } else { +            render("button", text) +        } +    } + +    override fun getSnClass(): List<StringBoolPair> { +        return if (forNavbar) { +            listOf("dropdown" to true) +        } else { +            super.getSnClass() +        } +    } +      override fun getSnAttrs(): List<StringPair> {          return super.getSnAttrs() + listOf(              "data-toggle" to "dropdown", "aria-haspopup" to "true", -            "aria-expanded" to "false" +            "aria-expanded" to "false", "role" to "button", "href" to "#"          )      }  } diff --git a/src/main/kotlin/pl/treksoft/kvision/navbar/Nav.kt b/src/main/kotlin/pl/treksoft/kvision/navbar/Nav.kt new file mode 100644 index 00000000..79b69290 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/navbar/Nav.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018. Robert Jaros + */ +package pl.treksoft.kvision.navbar + +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag + +/** + * The Bootstrap Nav container. + * + * @constructor + * @param rightAlign determines if the nav is aligned to the right + * @param classes a set of CSS class names + * @param init an initializer extension function + */ +open class Nav(rightAlign: Boolean = false, classes: Set<String> = setOf(), init: (Nav.() -> Unit)? = null) : +    Tag(TAG.UL, classes = classes) { + +    /** +     * Determines if the nav is aligned to the right. +     */ +    var rightAlign by refreshOnUpdate(rightAlign) + +    init { +        @Suppress("LeakingThis") +        init?.invoke(this) +    } + +    override fun getSnClass(): List<StringBoolPair> { +        val cl = super.getSnClass().toMutableList() +        cl.add("nav" to true) +        cl.add("navbar-nav" to true) +        if (rightAlign) { +            cl.add("navbar-right" to true) +        } +        return cl +    } + +    companion object { +        /** +         * DSL builder extension function. +         * +         * It takes the same parameters as the constructor of the built component. +         */ +        fun Navbar.nav( +            rightAlign: Boolean = false, classes: Set<String> = setOf(), init: (Nav.() -> Unit)? = null +        ): Nav { +            val nav = Nav(rightAlign, classes).apply { init?.invoke(this) } +            this.add(nav) +            return nav +        } +    } +} diff --git a/src/main/kotlin/pl/treksoft/kvision/navbar/NavForm.kt b/src/main/kotlin/pl/treksoft/kvision/navbar/NavForm.kt new file mode 100644 index 00000000..69755155 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/navbar/NavForm.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018. Robert Jaros + */ +package pl.treksoft.kvision.navbar + +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag + +/** + * The Bootstrap Nav form container. + * + * @constructor + * @param rightAlign determines if the nav form is aligned to the right + * @param classes a set of CSS class names + * @param init an initializer extension function + */ +open class NavForm(rightAlign: Boolean = false, classes: Set<String> = setOf(), init: (NavForm.() -> Unit)? = null) : +    Tag(TAG.FORM, classes = classes) { + +    /** +     * Determines if the nav form is aligned to the right. +     */ +    var rightAlign by refreshOnUpdate(rightAlign) + +    init { +        @Suppress("LeakingThis") +        init?.invoke(this) +    } + +    override fun getSnClass(): List<StringBoolPair> { +        val cl = super.getSnClass().toMutableList() +        cl.add("navbar-form" to true) +        if (rightAlign) { +            cl.add("navbar-right" to true) +        } else { +            cl.add("navbar-left" to true) +        } +        return cl +    } + +    companion object { +        /** +         * DSL builder extension function. +         * +         * It takes the same parameters as the constructor of the built component. +         */ +        fun Navbar.navForm( +            rightAlign: Boolean = false, classes: Set<String> = setOf(), init: (NavForm.() -> Unit)? = null +        ): NavForm { +            val navForm = NavForm(rightAlign, classes).apply { init?.invoke(this) } +            this.add(navForm) +            return navForm +        } +    } +} diff --git a/src/main/kotlin/pl/treksoft/kvision/navbar/Navbar.kt b/src/main/kotlin/pl/treksoft/kvision/navbar/Navbar.kt new file mode 100644 index 00000000..ee131731 --- /dev/null +++ b/src/main/kotlin/pl/treksoft/kvision/navbar/Navbar.kt @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2018. Robert Jaros + */ +package pl.treksoft.kvision.navbar + +import com.github.snabbdom.VNode +import pl.treksoft.kvision.core.Component +import pl.treksoft.kvision.core.Container +import pl.treksoft.kvision.core.StringBoolPair +import pl.treksoft.kvision.core.StringPair +import pl.treksoft.kvision.html.Link +import pl.treksoft.kvision.html.TAG +import pl.treksoft.kvision.html.Tag.Companion.tag +import pl.treksoft.kvision.panel.SimplePanel + +/** + * Navbar types. + */ +enum class NavbarType(internal val navbarType: String) { +    FIXEDTOP("navbar-fixed-top"), +    FIXEDBOTTOM("navbar-fixed-bottom"), +    STATICTOP("navbar-static-top") +} + +/** + * The Bootstrap Navbar container. + * + * @constructor + * @param label the navbar label + * @param type the navbar type + * @param inverted determines if the navbar is inverted + * @param classes a set of CSS class names + * @param init an initializer extension function + */ +open class Navbar( +    label: String = "", +    type: NavbarType? = null, +    inverted: Boolean = false, +    classes: Set<String> = setOf(), init: (Navbar.() -> Unit)? = null +) : SimplePanel(classes) { + +    /** +     * The navbar header label. +     */ +    var label +        get() = brandLink.label +        set(value) { +            brandLink.label = value +        } + +    /** +     * The navbar type. +     */ +    var type by refreshOnUpdate(type) +    /** +     * Determines if the navbar is inverted. +     */ +    var inverted by refreshOnUpdate(inverted) + +    private val idc = "kv_navbar_$counter" + +    private val brandLink = Link(label, "#", classes = setOf("navbar-brand")) +    protected val container = SimplePanel(setOf("collapse", "navbar-collapse")) { +        id = idc +    } + +    init { +        val c = SimplePanel(setOf("container-fluid")) { +            simplePanel(setOf("navbar-header")) { +                add(NavbarButton(idc)) +                add(brandLink) +            } +            add(container) +        } +        addInternal(c) +        counter++ +        @Suppress("LeakingThis") +        init?.invoke(this) +    } + +    override fun render(): VNode { +        return render("nav", childrenVNodes()) +    } + +    override fun add(child: Component): Navbar { +        container.add(child) +        return this +    } + +    override fun addAll(children: List<Component>): Navbar { +        container.addAll(children) +        return this +    } + +    override fun remove(child: Component): Navbar { +        container.remove(child) +        return this +    } + +    override fun removeAll(): Navbar { +        container.removeAll() +        return this +    } + +    override fun getChildren(): List<Component> { +        return container.getChildren() +    } + +    override fun getSnClass(): List<StringBoolPair> { +        val cl = super.getSnClass().toMutableList() +        cl.add("navbar" to true) +        type?.let { +            cl.add(it.navbarType to true) +        } +        if (inverted) { +            cl.add("navbar-inverse" to true) +        } else { +            cl.add("navbar-default" to true) +        } +        return cl +    } + +    companion object { +        internal var counter = 0 + +        /** +         * DSL builder extension function. +         * +         * It takes the same parameters as the constructor of the built component. +         */ +        fun Container.navbarPanel( +            text: String = "", +            type: NavbarType? = null, +            inverted: Boolean = false, +            classes: Set<String> = setOf(), init: (Navbar.() -> Unit)? = null +        ): Navbar { +            val navbarPanel = Navbar(text, type, inverted, classes, init) +            this.add(navbarPanel) +            return navbarPanel +        } +    } +} + +/** + * @suppress + * Internal component. + * The Bootstrap Navbar header button. + */ +internal class NavbarButton(private val idc: String, toggle: String = "Toggle navigation") : +    SimplePanel(setOf("navbar-toggle", "collapsed")) { + +    init { +        tag(TAG.SPAN, toggle, classes = setOf("sr-only")) +        tag(TAG.SPAN, classes = setOf("icon-bar")) +        tag(TAG.SPAN, classes = setOf("icon-bar")) +        tag(TAG.SPAN, classes = setOf("icon-bar")) +    } + +    override fun render(): VNode { +        return render("button", childrenVNodes()) +    } + +    override fun getSnAttrs(): List<StringPair> { +        return super.getSnAttrs() + listOf( +            "type" to "button", +            "data-toggle" to "collapse", +            "data-target" to "#$idc", +            "aria-expanded" to "false" +        ) +    } +} diff --git a/src/main/resources/css/style.css b/src/main/resources/css/style.css index 444bf5c2..82747e59 100644 --- a/src/main/resources/css/style.css +++ b/src/main/resources/css/style.css @@ -2,6 +2,11 @@    padding: 0px;  } +.navbar .container-fluid { +  padding-left: 15px; +  padding-right: 15px; +} +  .splitpanel-vertical {    display: flex;    flex-direction: row; @@ -73,7 +78,7 @@ trix-toolbar .trix-button-group {    margin-right:6px;  } -.form-inline .form-group .form-control { +.form-inline .form-group .form-control, .navbar-form .form-group .form-control {    margin-left:6px;  } | 
