diff options
author | Robert Jaros <rjaros@finn.pl> | 2018-03-11 23:47:07 +0100 |
---|---|---|
committer | Robert Jaros <rjaros@finn.pl> | 2018-03-12 00:03:27 +0100 |
commit | 567a42eb216381b951fe5c6bcc199bcba835ffa6 (patch) | |
tree | ec49858d37556ff37cd156f401cb680c26558482 | |
parent | 0c9f1189a40f361484cf29fd89e74d9b83aba321 (diff) | |
download | kvision-567a42eb216381b951fe5c6bcc199bcba835ffa6.tar.gz kvision-567a42eb216381b951fe5c6bcc199bcba835ffa6.tar.bz2 kvision-567a42eb216381b951fe5c6bcc199bcba835ffa6.zip |
Bootstrap Navbar component.
-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; } |