digitallyinduced / ihp

🔥 The fastest way to build type safe web apps. IHP is a new batteries-included web framework optimized for longterm productivity and programmer happiness
https://ihp.digitallyinduced.com/
MIT License
4.92k stars 195 forks source link

Custom css framework #365

Closed themmes closed 3 years ago

themmes commented 4 years ago

Hey!

In my tiny test project I was trying to make IHP work with tailwindcss (https://github.com/themmes/ihp-todo). I thought I'd simply go the easy route first, so added the CDN to the Layout.hs and started styling the hsx. This works well until I want to style flashMessages or form related items. The documentation is still WIP on this, so I thought I might ask you folks for advice and then attempt to write it.

The docs point me to:

  1. https://ihp.digitallyinduced.com/Guide/form.html#working-with-other-css-frameworks
  2. https://ihp.digitallyinduced.com/api-docs/IHP-View-Form.html#v:horizontalFormFor
  3. https://ihp.digitallyinduced.com/api-docs/src/IHP.View.Form.html#renderHorizontalBootstrapFormField

Brings up the following questions:

Would love to hear your thoughts!

themmes commented 4 years ago

To clarify, this relates to https://github.com/digitallyinduced/ihp/issues/72 but isn't necessarily limited to forms.

mpscholten commented 4 years ago

Hey Tom,

thanks for opening an issue on this 👍

What I dont really understand is why there exist custom functions specific to Bootstrap?

IHP is optimized to be used with bootstrap because that was what we needed at di for building our apps. We've basically optimized it for ourselves.

Why bootstrap classes on e.g. the button are default, why can't I just customise from scratch?

I think we should make it possible to completely customize the default classes used. It would be cool to later have something like a ihp-tailwindcss package which one could use to have everything default to e.g. tailwindcss instead of bootstrap.

Is there a way to add children elements? e.g. an SVG icon to the button

Currently not supported, we should add that 👍

Maybe the CSS section should get a more appropriate location in the docs, instead of being under Forms?

Agree, we could add a new Styling section below the Frontend headline

image

themmes commented 4 years ago

Thanks for your response @mpscholten, after my holidays (2 weeks) I'll pick this up!

mpscholten commented 4 years ago

Perfect thanks, enjoy the holidays :)

ruhatch commented 4 years ago

I'm imaging something along the lines of:

class HtmlComponents cssFramework where
    renderButton :: _ -> _
    renderFormField :: _ -> _

{- In an 'ihp-boostrap' library -}

data Bootstrap

instance HtmlComponents Boostrap where
    renderButton = _ -- Implementation with bootstrap stuff
    ...

{- In an 'ihp-tailwind' library -}

data Tailwind

instance HtmlComponents Tailwind where
    renderButton = _ -- Implementation with tailwind stuff
    ...

Or something similar to get building blocks from different frameworks. Could even have combinators to connect multiple form fields into a form, or other such building blocks.

Would love to hear your thoughts, @themmes

mpscholten commented 4 years ago

👍

we should also add renderFlashMessages to the interface

themmes commented 4 years ago

@ruhatch that's an interesting perspective!

As an alternative, I think you always end up (or actually in my case it was almost the first thing I did) wanting to customise the looks (html and classes). For that, you would want the predefined html to be as minimal as possible, because removing predefined is much harder than adding afterwards e.g. by a parameter for additional classes like its done now.

So maybe it would be an idea to have the most minimal html for IHP to function in the library and e.g. different boilerplates ihp-bootstrap-boilerplate with overrides that add the html (if it isn't already the most minimal) and classes that are currently in the IHP codebase?

mpscholten commented 4 years ago

I really the above approach by @ruhatch. This way we can still have basic boilerplate built-in (for quickly hacking something together). And we can also support custom cases e.g. as a IHP user you could add your own instance HtmlComponents MyCustomCSS. We could also have an instance HtmlComponents Minimal to only generate the minimal html.

We should also think about how to be able to customize only smalll parts of the layout (e.g. you might want to use bootstrap rendering, but want to customize the form controls a bit). Maybe it might be better to have something like:

data HtmlComponents = HtmlComponents { renderButton :: Html, renderFlashMessage :: Html }

bootstrap = HtmlComponents { renderButton = .., renderFlashMessage = .. }
tailwind = HtmlComponents { renderButton = .., renderFlashMessage = .. }

myCustomAppFrontend = bootstrap |> set #renderButton renderMyCustomButton
themmes commented 4 years ago

Cool, I think that would work well too! For my understanding, where exactly would I put the custom defined styling?

myCustomAppFrontend = bootstrap |> set #renderButton renderMyCustomButton
mpscholten commented 4 years ago

I'd put it into Application.Helper.View for now 👍

mpscholten commented 4 years ago

Any updates on this? :)

mpscholten commented 3 years ago

I think this can be closed now, see https://ihp.digitallyinduced.com/Guide/tailwindcss.html :) In case there's still something to do here, let me know so we can reopen this