From 651065f46fbc03c58148ebe4e5d4ba2254ccc176 Mon Sep 17 00:00:00 2001 From: Harald Pehl Date: Wed, 25 May 2022 18:27:04 +0200 Subject: [PATCH] Refactor card and card view examples --- .../patternfly/showcase/component/Badge.kt | 4 - .../org/patternfly/showcase/component/Card.kt | 143 ++++++++++-------- .../patternfly/showcase/component/CardView.kt | 133 ++++++++++++++++ .../showcase/component/Component.kt | 1 + .../patternfly/showcase/component/DataList.kt | 40 ++--- .../org/patternfly/showcase/demo/User.kt | 11 +- 6 files changed, 242 insertions(+), 90 deletions(-) create mode 100644 src/main/kotlin/org/patternfly/showcase/component/CardView.kt diff --git a/src/main/kotlin/org/patternfly/showcase/component/Badge.kt b/src/main/kotlin/org/patternfly/showcase/component/Badge.kt index 26a50f3..a29962e 100644 --- a/src/main/kotlin/org/patternfly/showcase/component/Badge.kt +++ b/src/main/kotlin/org/patternfly/showcase/component/Badge.kt @@ -2,10 +2,6 @@ package org.patternfly.showcase.component import dev.fritz2.binding.storeOf import dev.fritz2.dom.html.RenderContext -import dev.fritz2.dom.values -import dev.fritz2.dom.valuesAsNumber -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.map import org.patternfly.badge import org.patternfly.classes import org.patternfly.layout diff --git a/src/main/kotlin/org/patternfly/showcase/component/Card.kt b/src/main/kotlin/org/patternfly/showcase/component/Card.kt index 011671b..18e2d0e 100644 --- a/src/main/kotlin/org/patternfly/showcase/component/Card.kt +++ b/src/main/kotlin/org/patternfly/showcase/component/Card.kt @@ -2,13 +2,13 @@ package org.patternfly.showcase.component -import dev.fritz2.binding.RootStore +import dev.fritz2.binding.storeOf import dev.fritz2.dom.html.RenderContext +import dev.fritz2.lenses.IdProvider import kotlinx.coroutines.flow.map import org.patternfly.ButtonVariant.inline import org.patternfly.ButtonVariant.link import org.patternfly.CardVariant.compact -import org.patternfly.CardVariant.expandable import org.patternfly.CardVariant.flat import org.patternfly.CardVariant.hoverable import org.patternfly.CardVariant.selectable @@ -16,8 +16,9 @@ import org.patternfly.Color.BLUE import org.patternfly.Color.GREEN import org.patternfly.Color.ORANGE import org.patternfly.Color.PURPLE +import org.patternfly.SelectionMode import org.patternfly.card -import org.patternfly.checkbox +import org.patternfly.cardView import org.patternfly.classes import org.patternfly.component import org.patternfly.dom.Id @@ -28,6 +29,7 @@ import org.patternfly.label import org.patternfly.labelGroup import org.patternfly.layout import org.patternfly.linkButton +import org.patternfly.list import org.patternfly.modifier import org.patternfly.pageSection import org.patternfly.showcase.fixture.DropdownFixture.defaultDropdown @@ -51,7 +53,7 @@ object CardComponent { snippet("With image and action", CardCode.IMAGE_ACTION) { card { header { - main { + content { img { src(require("pf-logo.svg") as String) inlineStyle("width: 300px") @@ -59,8 +61,8 @@ object CardComponent { } actions { defaultDropdown() - checkbox(Id.unique("card-check"), standalone = true) } + check() } title { +"Title" } body { +"Body" } @@ -72,11 +74,11 @@ object CardComponent { header { actions { defaultDropdown() - checkbox(Id.unique("card-check"), standalone = true) } title { +"This is a really really really really really really really really really really long title" } + check() } body { +"Body" } footer { +"Footer" } @@ -87,8 +89,8 @@ object CardComponent { header { actions { defaultDropdown() - checkbox(Id.unique("card-check"), standalone = true) } + check() } body { +"This is the card body, there are only actions in the card head." @@ -98,7 +100,7 @@ object CardComponent { snippet("Only image in the card header", CardCode.ONLY_IMAGE) { card { header { - main { + content { img { src(require("pf-logo.svg") as String) inlineStyle("width: 300px") @@ -163,16 +165,11 @@ object CardComponent { } } snippet("Selectable and selected", CardCode.SELECTABLE) { - class OnOff : RootStore(false) { - val toggle = handle { !it } - } + val selection0 = storeOf(false) + val selection1 = storeOf(false) + val selection2 = storeOf(false) - card(selectable) { - val onOff = OnOff() - selected(onOff.data) - events { - clicks handledBy onOff.toggle - } + card(selectable, selection = selection0) { header { actions { defaultDropdown() @@ -182,31 +179,14 @@ object CardComponent { body { +"This is a selectable card. Click me to select me. Click again to deselect me." } } br {} - card(selectable) { - val onOff = OnOff() - selected(onOff.data) - events { - clicks handledBy onOff.toggle - } + card(selectable, selection = selection1) { title { +"Second card" } body { +"This is a selectable card. Click me to select me. Click again to deselect me." } } br {} - card(selectable) { - val onOff = OnOff() - selected(onOff.data) - events { - clicks handledBy onOff.toggle - } + card(selectable, selection = selection2) { header { - actions { - checkbox("card-check", standalone = true) { - checked(onOff.data) - events { - changes handledBy onOff.toggle - } - } - } + check() title { +"Third card" } } body { +"This is a selectable card. Click the card or the checkbox to select me." } @@ -220,11 +200,11 @@ object CardComponent { } } snippet("Expandable", CardCode.EXPANDABLE) { - card(expandable) { + card { header { + toggle() actions { defaultDropdown() - checkbox(Id.unique("card-check"), standalone = true) } title { expandedStore.data.map { "Expanded state: $it" }.renderText(into = this) @@ -246,12 +226,13 @@ object CardComponent { } } snippet("Horizontal card grid", "n/a") { - card(expandable) { + card { header { + toggle() actions { defaultDropdown() } - content { + custom { div(baseClass = classes("level".layout(), "gutter".modifier())) { expandedStore.data.render(into = this) { expanded -> div(baseClass = "card".component("title")) { +"Getting started" } @@ -294,15 +275,14 @@ object CardComponent { ) { label(BLUE, "Setup your cluster") p { +"Continue setting up your cluster to access all you cain in the Console" } - // TODO use list component - ul(baseClass = classes("list".component(), "plain".modifier())) { - li(baseClass = "list".component("item")) { + list { + item { a { href("#"); +"Add identity provider" } } - li(baseClass = "list".component("item")) { + item { a { href("#"); +"Configure alert receivers" } } - li(baseClass = "list".component("item")) { + item { a { href("#"); +"Configure default ingress certificate" } } } @@ -331,12 +311,11 @@ object CardComponent { ) { label(PURPLE, "Guided tours") p { +"Tour some of the key features around the console" } - // TODO use list component - ul(baseClass = classes("list".component(), "plain".modifier())) { - li(baseClass = "list".component("item")) { + list { + item { a { href("#"); +"Tour the console" } } - li(baseClass = "list".component("item")) { + item { a { href("#"); +"Explore the Developer perspective" } } } @@ -365,15 +344,14 @@ object CardComponent { ) { label(GREEN, "Quick starts") p { +"Get started with features using our step-by-step documentation" } - // TODO use list component - ul(baseClass = classes("list".component(), "plain".modifier())) { - li(baseClass = "list".component("item")) { + list { + item { a { href("#"); +"Getting started with Serverless" } } - li(baseClass = "list".component("item")) { + item { a { href("#"); +"Explore virtualization" } } - li(baseClass = "list".component("item")) { + item { a { href("#"); +"Build pipelines" } } } @@ -402,19 +380,18 @@ object CardComponent { ) { label(ORANGE, "Learning resources") p { +"Learn about new features within the Console and get started with demo apps" } - // TODO use list component - ul(baseClass = classes("list".component(), "plain".modifier())) { - li(baseClass = "list".component("item")) { + list { + item { a { href("#"); +"See what's possible with the Explore page" } } - li(baseClass = "list".component("item")) { + item { a { href("#") +"OpenShift 4.5: Top Tasks " icon("external-link-alt".fas()) } } - li(baseClass = "list".component("item")) { + item { a { href("#"); +"Try a demo app" } } } @@ -428,6 +405,52 @@ object CardComponent { } } } + snippet("Card view (single select)", "n/a") { + data class Demo(val id: String, val title: String) + + val foo = Demo("foo", "Foo") + val bar = Demo("bar", "Bar") + val values = storeOf(listOf(foo, bar)) + val selection = storeOf(foo) + val idProvider: IdProvider = { Id.build(it.id, "single", "select", "demo") } + + cardView(SelectionMode.SINGLE) { + items(values, idProvider, singleSelection = selection) { demo -> + card(selectable) { + title { +demo.title } + body { +loremIpsum(3) } + } + } + } + } + snippet("Card view (multi select)", "n/a") { + data class Demo(val id: String, val title: String) + + val foo = Demo("foo", "Foo") + val bar = Demo("bar", "Bar") + val values = storeOf(listOf(foo, bar)) + val selection = storeOf(listOf(foo)) + val idProvider: IdProvider = { Id.build(it.id, "multi", "select", "demo") } + + cardView(SelectionMode.MULTI) { + card { + title { +"Static Card" } + body { +loremIpsum(3) } + } + items(values, idProvider, multiSelection = selection) { demo -> + card(selectable) { + header { + title { +demo.title } + actions { + defaultDropdown() + } + check() + } + body { +loremIpsum(3) } + } + } + } + } } } } diff --git a/src/main/kotlin/org/patternfly/showcase/component/CardView.kt b/src/main/kotlin/org/patternfly/showcase/component/CardView.kt new file mode 100644 index 0000000..122e483 --- /dev/null +++ b/src/main/kotlin/org/patternfly/showcase/component/CardView.kt @@ -0,0 +1,133 @@ +@file:Suppress("DuplicatedCode") + +package org.patternfly.showcase.component + +import dev.fritz2.binding.storeOf +import dev.fritz2.dom.html.RenderContext +import dev.fritz2.lenses.IdProvider +import kotlinx.coroutines.flow.map +import org.patternfly.ButtonVariant.link +import org.patternfly.CardVariant.selectable +import org.patternfly.SelectionMode +import org.patternfly.actionList +import org.patternfly.cardView +import org.patternfly.classes +import org.patternfly.clickButton +import org.patternfly.dom.Id +import org.patternfly.layout +import org.patternfly.modifier +import org.patternfly.pageSection +import org.patternfly.showcase.fixture.DropdownFixture.defaultDropdown +import org.patternfly.util + +object CardViewComponent { + val content: RenderContext.() -> Unit = { + intro( + title = "Card view", + text = "A card view is a grid of cards in a gallery to facilitate browsing.", + designGuidelines = "https://www.patternfly.org/v4/demos/card-view/design-guidelines" + ) + pageSection { + snippet("Single select", CardViewCode.SINGLE_SELECT) { + data class Demo(val id: String, val title: String) + + val foo = Demo("foo", "Foo") + val bar = Demo("bar", "Bar") + val demos = listOf(foo, bar) + val values = storeOf(demos) + val selection = storeOf(foo) + val idProvider: IdProvider = { Id.build(it.id, "single", "select", "demo") } + + cardView(SelectionMode.SINGLE) { + items(values, idProvider, singleSelection = selection) { demo -> + card(selectable) { + title { +demo.title } + body { +loremIpsum(3) } + } + } + } + section(baseClass = classes("flex".layout(), "mt-lg".util())) { + actionList { + for (demo in demos) { + item { + clickButton(link) { +"Select ${demo.title}" }.map { demo } handledBy selection.update + } + } + item { + clickButton(link) { +"Select none" }.map { null } handledBy selection.update + } + } + div(baseClass = "align-right".modifier()) { + +"Selected item: " + selection.data.map { it?.title ?: "Nothing" }.renderText() + } + } + } + snippet("Multi select", CardViewCode.MULTI_SELECT) { + data class Demo(val id: String, val title: String) + + val foo = Demo("foo", "Foo") + val bar = Demo("bar", "Bar") + val demos = listOf(foo, bar) + val values = storeOf(demos) + val selection = storeOf(listOf(foo)) + val idProvider: IdProvider = { Id.build(it.id, "multi", "select", "demo") } + + cardView(SelectionMode.MULTI) { + card { + title { +"Static Card" } + body { +loremIpsum(3) } + } + items(values, idProvider, multiSelection = selection) { demo -> + card(selectable) { + header { + title { +demo.title } + actions { + defaultDropdown() + } + check() + } + body { +loremIpsum(3) } + } + } + } + section(baseClass = classes("flex".layout(), "mt-lg".util())) { + actionList { + for (demo in demos) { + item { + clickButton(link) { +"Select ${demo.title}" }.map { selection.current + demo } handledBy selection.update + } + } + item { + clickButton(link) { +"Select all" }.map { demos } handledBy selection.update + } + item { + clickButton(link) { +"Select none" }.map { emptyList() } handledBy selection.update + } + } + div(baseClass = "align-right".modifier()) { + +"Selected items: " + selection.data.map { demos -> demos.joinToString { it.title }.ifEmpty { "None" } }.renderText() + } + } + } + } + } +} + +object CardViewCode { + + //language=kotlin + const val SINGLE_SELECT: String = """fun main() { + render { + } +} +""" + + //language=kotlin + const val MULTI_SELECT: String = """fun main() { + render { + } +} +""" +} diff --git a/src/main/kotlin/org/patternfly/showcase/component/Component.kt b/src/main/kotlin/org/patternfly/showcase/component/Component.kt index 8ea1aa9..c86923e 100644 --- a/src/main/kotlin/org/patternfly/showcase/component/Component.kt +++ b/src/main/kotlin/org/patternfly/showcase/component/Component.kt @@ -16,6 +16,7 @@ val components = listOf( Component("badge", "Badge", BadgeComponent.content), Component("button", "Button", ButtonComponent.content), Component("card", "Card", CardComponent.content), + Component("card-view", "Card view", CardViewComponent.content), Component("chip", "Chip", ChipComponent.content), Component("chip-group", "Chip group", ChipGroupComponent.content), Component("data-list", "Data list", DataListComponent.content), diff --git a/src/main/kotlin/org/patternfly/showcase/component/DataList.kt b/src/main/kotlin/org/patternfly/showcase/component/DataList.kt index 482851f..487d5e0 100644 --- a/src/main/kotlin/org/patternfly/showcase/component/DataList.kt +++ b/src/main/kotlin/org/patternfly/showcase/component/DataList.kt @@ -6,6 +6,8 @@ import dev.fritz2.binding.storeOf import dev.fritz2.dom.html.RenderContext import kotlinx.coroutines.flow.map import org.patternfly.ButtonVariant.link +import org.patternfly.ButtonVariant.primary +import org.patternfly.ButtonVariant.secondary import org.patternfly.actionList import org.patternfly.classes import org.patternfly.clickButton @@ -87,8 +89,8 @@ object DataListComponent { defaultDropdown() } action(baseClass = classes("hidden".modifier(), "visible-on-lg".modifier())) { - pushButton(baseClass = "primary".modifier()) { +"Primary" } - pushButton(baseClass = "secondary".modifier()) { +"Secondary" } + pushButton(primary) { +"Primary" } + pushButton(secondary) { +"Secondary" } } } item { @@ -99,16 +101,16 @@ object DataListComponent { defaultDropdown() } action(baseClass = classes("hidden".modifier(), "visible-on-xl".modifier())) { - pushButton(baseClass = "primary".modifier()) { +"Primary" } - pushButton(baseClass = "secondary".modifier()) { +"Secondary" } - pushButton(baseClass = "secondary".modifier()) { +"Secondary" } - pushButton(baseClass = "secondary".modifier()) { +"Secondary" } + pushButton(primary) { +"Primary" } + pushButton(secondary) { +"Secondary" } + pushButton(secondary) { +"Secondary" } + pushButton(secondary) { +"Secondary" } } } } section(baseClass = "mt-lg".util()) { p { - +"Selected ids: " + +"Selected IDs: " dl.selectedIds.renderText() } } @@ -119,7 +121,7 @@ object DataListComponent { cell { span(id = this@item.id) { +"Single actionable - primary content" } } cell { +"Single actionable - secondary content" } action { - pushButton(baseClass = "primary".modifier()) { +"Delete" } + pushButton(primary) { +"Delete" } } } item { @@ -161,7 +163,7 @@ object DataListComponent { cell { span(id = this@item.id) { +"Single actionable - primary content" } } cell { +"Single actionable - secondary content" } action { - pushButton(baseClass = "primary".modifier()) { +"Delete" } + pushButton(primary) { +"Delete" } } } item { @@ -176,12 +178,11 @@ object DataListComponent { snippet("Store (single selection)", "n/a") { data class Demo(val id: String, val name: String) - val demos = listOf( - Demo("foo", "Foo"), - Demo("bar", "Bar") - ) + val foo = Demo("foo", "Foo") + val bar = Demo("bar", "Bar") + val demos = listOf(foo, bar) val store = storeOf(demos) - val selection = storeOf(null) + val selection = storeOf(foo) dataList(selectable = true) { items(store, { it.id }, selection) { demo -> @@ -216,15 +217,14 @@ object DataListComponent { snippet("Store (multiple selections)", "n/a") { data class Demo(val id: String, val name: String) - val demos = listOf( - Demo("foo", "Foo"), - Demo("bar", "Bar") - ) + val foo = Demo("foo", "Foo") + val bar = Demo("bar", "Bar") + val demos = listOf(foo, bar) val store = storeOf(demos) - val selection = storeOf>(emptyList()) + val selection = storeOf(listOf(foo)) dataList { - items(store, { it.id }, selection) { demo -> + items(values = store, idProvider = { it.id }, multiSelection = selection) { demo -> item { check() cell { diff --git a/src/main/kotlin/org/patternfly/showcase/demo/User.kt b/src/main/kotlin/org/patternfly/showcase/demo/User.kt index 00ed2ec..5c52a1e 100644 --- a/src/main/kotlin/org/patternfly/showcase/demo/User.kt +++ b/src/main/kotlin/org/patternfly/showcase/demo/User.kt @@ -19,8 +19,6 @@ import org.patternfly.ButtonVariant.plain import org.patternfly.ItemsStore import org.patternfly.SortInfo import org.patternfly.aria -import org.patternfly.bulkSelect -import org.patternfly.cardView import org.patternfly.classes import org.patternfly.clickButton import org.patternfly.dataTable @@ -43,6 +41,7 @@ import org.patternfly.legacyCardBody import org.patternfly.legacyCardCheckbox import org.patternfly.legacyCardFooter import org.patternfly.legacyCardHeader +import org.patternfly.legacyCardView import org.patternfly.modifier import org.patternfly.mvp.Presenter import org.patternfly.mvp.View @@ -118,9 +117,9 @@ class UserDemoView(override val presenter: UserDemoPresenter) : View, WithPresen toolbar { toolbarContent { toolbarContentSection { - toolbarItem { - bulkSelect(presenter.userStore) - } +// toolbarItem { +// bulkSelect(presenter.userStore) +// } toolbarItem { inputGroup { inputFormControl(id = Id.unique("usr", "flt")) { @@ -166,7 +165,7 @@ class UserDemoView(override val presenter: UserDemoPresenter) : View, WithPresen } } } - cardView(presenter.userStore) { + legacyCardView(presenter.userStore) { classMap(activeComponent.data.map { mapOf("display-none".util() to (it != CARD)) }) display { user -> legacyCard(user, baseClass = classes {