Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Card Components . #25

Open
naser09 opened this issue Sep 14, 2024 · 1 comment
Open

add Card Components . #25

naser09 opened this issue Sep 14, 2024 · 1 comment

Comments

@naser09
Copy link

naser09 commented Sep 14, 2024

as an android developer i was missing Card component while using this library . so made my own . i was going to do a pull request but as a solo (self taught) developer i am bad at collaboration . so here is the code . please add the component if you think its necessary or usable . or modify it to your liking . maybe its need some more effect like hover effect . but in my case I am using simple card to show my data .

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.stevdza.san.kotlinbs.util.UniqueIdGenerator
import com.varabyte.kobweb.compose.css.AlignItems
import com.varabyte.kobweb.compose.css.JustifyContent
import com.varabyte.kobweb.compose.ui.*
import com.varabyte.kobweb.compose.ui.modifiers.*
import org.jetbrains.compose.web.css.*
import org.jetbrains.compose.web.dom.Div

@Composable
fun BSCard(
    modifier: Modifier = Modifier,
    id: String? = null,
    alignment: Alignment = Alignment.TopStart,
    shadow: Boolean = true,
    borderRadius: BSBorderRadius? = null,
    customization: CardCustomization? = null,
    content: @Composable () -> Unit
) {
    val randomId = remember {
        id ?: UniqueIdGenerator.generateUniqueId("card")
    }

    Div(
        attrs = Modifier
            .then(modifier)
            .id(randomId)
            .classNames("card")
            .thenIf(
                condition = shadow,
                other = Modifier.classNames("shadow")
            )
            .thenIf(
                condition = customization == null && borderRadius != null,
                other = borderRadius?.let {
                    Modifier.borderRadius(
                        topLeft = it.topLeft,
                        topRight = it.topRight,
                        bottomRight = it.bottomRight,
                        bottomLeft = it.bottomLeft
                    )
                } ?: Modifier
            )
            .styleModifier {
                if (customization != null) {
                    customization.backgroundColor?.let { property("background-color", it) }
                    customization.borderColor?.let { property("border-color", it) }
                    customization.borderWidth?.let { property("border-width", it) }
                    property("border-radius", customization.borderRadius)
                    customization.padding?.let { property("padding", it) }
                    customization.margin?.let { property("margin", it) }
                    customization.width?.let { property("width", it) }
                    customization.height?.let { property("height", it) }
                }
            }
            .display(DisplayStyle.Flex)
            .flexDirection(FlexDirection.Column)
            .justifyContent(alignment.toJustifyContent())
            .alignItems(alignment.toAlignItems())
            .toAttrs()
    ) {
        content()
    }
}

// Helper functions to convert Alignment to Justify Content and Align Items
private fun Alignment.toJustifyContent(): JustifyContent = when (this) {
    Alignment.TopStart, Alignment.CenterStart, Alignment.BottomStart -> JustifyContent.FlexStart
    Alignment.TopCenter, Alignment.Center, Alignment.BottomCenter -> JustifyContent.Center
    Alignment.TopEnd, Alignment.CenterEnd, Alignment.BottomEnd -> JustifyContent.FlexEnd
    Alignment.FromStyle -> JustifyContent.SpaceBetween
}

private fun Alignment.toAlignItems(): AlignItems = when (this) {
    Alignment.TopStart, Alignment.TopCenter, Alignment.TopEnd -> AlignItems.FlexStart
    Alignment.CenterStart, Alignment.Center, Alignment.CenterEnd -> AlignItems.Center
    Alignment.BottomStart, Alignment.BottomCenter, Alignment.BottomEnd -> AlignItems.FlexEnd
    Alignment.FromStyle -> AlignItems.Normal
}

// Data class for custom card styling
data class CardCustomization(
    val backgroundColor: String? = null,
    val borderColor: String? = null,
    val borderWidth: String? = null,
    val borderRadius: String = "0.25rem",
    val padding: String? = null,
    val margin: String? = null,
    val width: String? = null,
    val height: String? = null
)

// Reusing BSBorderRadius from your example
data class BSBorderRadius(
    val topLeft: CSSLengthOrPercentageValue,
    val topRight: CSSLengthOrPercentageValue,
    val bottomRight: CSSLengthOrPercentageValue,
    val bottomLeft: CSSLengthOrPercentageValue
){
    constructor(all:CSSLengthOrPercentageValue) : this(all,all,all,all)
}
@naser09
Copy link
Author

naser09 commented Sep 17, 2024

one more thing . with the default file picker I wasn't able to do what I wanted because the file is plain text and it got encoded to base64 . so for picking different file I modified BSFilePicker to
changed the on click function for file pick . . document.loadTextFromDisk( accept = accept, onLoad = { onFileSelected(filename, it) placeholderText = filename } )

here is the complete code for text picker .

@Composable
fun BSTextFilePicker(
    modifier: Modifier = Modifier,
    id: String? = null,
    label: String? = null,
    placeholder: String = "No file selected.",
    size: InputSize = InputSize.Default,
    disabled: Boolean = false,
    accept: String = "plain/text, .txt",
    onFileSelected: (String, String) -> Unit
) {
    val randomId = remember {
        id ?: UniqueIdGenerator.generateUniqueId("fileinput")
    }
    var placeholderText by remember { mutableStateOf(placeholder) }
    Div(attrs = modifier.toAttrs()) {
        if(label != null) {
            Label(
                attrs = Modifier
                    .classNames("form-label")
                    .toAttrs(),
                forId = randomId
            )
            {
                Text(value = label)
            }
        }
        Row(
            modifier = Modifier
                .id(randomId)
                .thenIf(
                    condition = disabled,
                    // TODO: Will this color get used anywhere? Should we extract it into a constant?
                    other = Modifier.backgroundColor(Color.rgb(0xFAFAFA))
                )
                .border(
                    width = 1.px,
                    style = LineStyle.Solid,
                    color = rgba(r = 206, g = 212, b = 218, a = 1)
                )
                .padding(all = 0.px)
                .onClick {
                    if (!disabled) {
                        document.loadTextFromDisk(
                            accept = accept,
                            onLoad = {
                                onFileSelected(filename, it)
                                placeholderText = filename
                            }
                        )
                    }
                }
                .overflow(Overflow.Hidden)
                .textOverflow(TextOverflow.Ellipsis)
                .thenIf(
                    condition = size != InputSize.Default,
                    other = Modifier.classNames(size.value)
                )
                .borderRadius(0.375.cssRem),
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.Start
        ) {
            BSButton(
                modifier = Modifier
                    .margin(all = 0.px)
                    .borderRadius(topRight = 0.px, bottomRight = 0.px),
                text = "Browse...",
                variant = ButtonVariant.Light,
                size = when (size) {
                    InputSize.Default -> {
                        ButtonSize.Default
                    }

                    InputSize.Small -> {
                        ButtonSize.Small
                    }

                    InputSize.Large -> {
                        ButtonSize.Large
                    }
                },
                disabled = disabled,
                onClick = {}
            )
            SpanText(
                modifier = Modifier
                    .thenIf(
                        condition = disabled,
                        other = Modifier.classNames("text-muted")
                    )
                    .margin(leftRight = 12.px),
                text = placeholderText
            )
        }
    }
}```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant