Skip to content

Instantly share code, notes, and snippets.

@dmjio
Last active April 5, 2025 19:57
Show Gist options
  • Save dmjio/0851afa4898253cfa9d67fe323bd0f3a to your computer and use it in GitHub Desktop.
Save dmjio/0851afa4898253cfa9d67fe323bd0f3a to your computer and use it in GitHub Desktop.
Tailwind Components DaisyUI Library and Miso integration, thanks to DeepSeek R1
{-# LANGUAGE OverloadedStrings #-}
module DaisyUI where
import Miso
import Miso.String (MisoString, ms)
-- Action type for all component interactions
data Action
= ButtonClicked MisoString
| AccordionToggled Int
| AlertDismissed
| DropdownToggled
| ModalToggled Bool
| TabSelected Int
| NoOp
deriving (Show, Eq)
-- Model to track component states
data Model = Model
{ activeAccordionItem :: Maybe Int
, isDropdownOpen :: Bool
, isModalOpen :: Bool
, activeTab :: Int
} deriving (Show, Eq)
initialModel :: Model
initialModel = Model
{ activeAccordionItem = Nothing
, isDropdownOpen = False
, isModalOpen = False
, activeTab = 0
}
-- Update function
update :: Action -> Model -> Effect Action Model
update action model = case action of
ButtonClicked btnId ->
noEff $ model { activeAccordionItem = Nothing } -- Example: reset accordion on button click
AccordionToggled idx ->
noEff $ model { activeAccordionItem =
if Just idx == activeAccordionItem model
then Nothing
else Just idx
}
AlertDismissed ->
noEff model -- Could add alert visibility to model
DropdownToggled ->
noEff $ model { isDropdownOpen = not (isDropdownOpen model) }
ModalToggled state ->
noEff $ model { isModalOpen = state }
TabSelected idx ->
noEff $ model { activeTab = idx }
NoOp ->
noEff model
-- Enhanced Button Component with click handler
button :: ButtonType -> ButtonSize -> ButtonShape -> Maybe ButtonState -> MisoString -> Action -> View Action
button btnType size shape state content onClick =
button_
[ class_ $ ms $ "btn " <> buttonTypeClass btnType <> " " <> sizeClass size <> " " <> shapeClass shape <> " " <> stateClass state
, onClick onClick
]
[ text content ]
where
buttonTypeClass BtnPrimary = "btn-primary"
-- ... rest of buttonTypeClass as before
sizeClass BtnXs = "btn-xs"
-- ... rest of sizeClass as before
shapeClass BtnSquare = "btn-square"
-- ... rest of shapeClass as before
stateClass (Just BtnActive) = "btn-active"
-- ... rest of stateClass as before
-- Enhanced Accordion with toggling
accordion :: Model -> [AccordionItem] -> View Action
accordion model items =
div_ [ class_ "join join-vertical w-full" ] $
map (\(i, item) ->
let isActive = activeAccordionItem model == Just i
in div_ [ class_ "collapse collapse-arrow join-item border border-base-300" ] [
input_
[ type_ "radio"
, name_ "my-accordion"
, checked_ isActive
, onClick (AccordionToggled i)
],
div_ [ class_ "collapse-title text-xl font-medium" ] [
text (accordionTitle item)
],
div_ [ class_ "collapse-content" ] [
accordionContent item
]
]
) (zip [0..] items)
-- Alert with dismiss button
alert :: AlertType -> View Action -> View Action
alert alertType content =
div_ [ class_ $ "alert " <> alertTypeClass alertType ] [
content,
button_
[ class_ "btn btn-sm"
, onClick AlertDismissed
]
[ text "×" ]
]
where
alertTypeClass AlertInfo = "alert-info"
-- ... rest of alertTypeClass as before
-- Dropdown with toggle action
dropdown :: Model -> MisoString -> [View Action] -> View Action
dropdown model title items =
div_ [ class_ "dropdown" ] [
div_
[ tabIndex_ "0"
, role_ "button"
, class_ "btn m-1"
, onClick DropdownToggled
]
[ text title ],
if isDropdownOpen model
then ul_
[ tabIndex_ "0"
, class_ "dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52"
]
items
else noHtml
]
-- Modal with open/close controls
modal :: Model -> View Action -> View Action -> View Action
modal model title content =
div_ [ class_ $ if isModalOpen model then "modal modal-open" else "modal" ] [
div_ [ class_ "modal-box" ] [
h3_ [ class_ "font-bold text-lg" ] [ title ],
p_ [ class_ "py-4" ] [ content ],
div_ [ class_ "modal-action" ] [
button BtnPrimary BtnMd BtnSquare Nothing "Close" (ModalToggled False)
]
]
]
-- Tabs with selection action
tabs :: Model -> [Tab] -> View Action
tabs model tabItems =
div_ [] [
div_ [ class_ "tabs" ] $
map (\(i, tab) ->
a_
[ class_ $ "tab " <> if i == activeTab model then "tab-active" else ""
, onClick (TabSelected i)
]
[ text (tabName tab) ]
) (zip [0..] tabItems),
div_ [ class_ "tab-content" ] [
tabContent (tabItems !! activeTab model)
]
]
-- Example view using all components
exampleView :: Model -> View Action
exampleView model =
div_ [ class_ "p-4" ] [
h1_ [ class_ "text-2xl font-bold mb-4" ] [ text "DaisyUI Components in Miso" ],
-- Button example
div_ [ class_ "mb-8" ] [
h2_ [ class_ "text-xl mb-2" ] [ text "Buttons" ],
button BtnPrimary BtnMd BtnSquare Nothing "Primary Button" (ButtonClicked "primary"),
button BtnSecondary BtnSm BtnCircle Nothing "Secondary" (ButtonClicked "secondary")
],
-- Accordion example
div_ [ class_ "mb-8" ] [
h2_ [ class_ "text-xl mb-2" ] [ text "Accordion" ],
accordion model [
AccordionItem "First Item" (text "Content for first item"),
AccordionItem "Second Item" (text "Content for second item")
]
],
-- Alert example
div_ [ class_ "mb-8" ] [
h2_ [ class_ "text-xl mb-2" ] [ text "Alert" ],
alert AlertInfo (text "This is an info alert with dismiss button")
],
-- Dropdown example
div_ [ class_ "mb-8" ] [
h2_ [ class_ "text-xl mb-2" ] [ text "Dropdown" ],
dropdown model "Dropdown Menu" [
li_ [] [ a_ [] [ text "Item 1" ] ],
li_ [] [ a_ [] [ text "Item 2" ] ]
]
],
-- Modal example
div_ [ class_ "mb-8" ] [
h2_ [ class_ "text-xl mb-2" ] [ text "Modal" ],
button BtnPrimary BtnMd BtnSquare Nothing "Open Modal" (ModalToggled True),
modal model (text "Modal Title") (text "Modal content goes here")
],
-- Tabs example
div_ [ class_ "mb-8" ] [
h2_ [ class_ "text-xl mb-2" ] [ text "Tabs" ],
tabs model [
Tab "Tab 1" (text "Content for Tab 1") True,
Tab "Tab 2" (text "Content for Tab 2") False
]
]
]
-- App setup
app :: App Model Action
app = App
{ initialAction = NoOp
, model = initialModel
, update = update
, view = exampleView
, subs = []
, events = defaultEvents
, mountPoint = Nothing
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment