Bar.purs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. module PureTabs.Sidebar.Bar where
  2. import Browser.Tabs (Tab(..), TabId)
  3. import Control.Alternative (pure)
  4. import Control.Bind (bind, discard, void, (<#>))
  5. import Data.Array ((:))
  6. import Data.Function (($))
  7. import Data.Map as M
  8. import Data.Maybe (Maybe(..))
  9. import Data.Set (toUnfoldable, Set) as S
  10. import Data.Set.NonEmpty (cons, max) as NES
  11. import Data.Symbol (SProxy(..))
  12. import Data.Tuple (Tuple(..))
  13. import Data.Unit (Unit, unit)
  14. import Effect.Aff.Class (class MonadAff)
  15. import Effect.Class (class MonadEffect)
  16. import Halogen as H
  17. import Halogen.HTML as HH
  18. import Halogen.HTML.Events as HE
  19. import Halogen.HTML.Properties as HP
  20. import Prelude (class Eq, class Ord, class Show, show, (+), (<<<), (<>), (==))
  21. import PureTabs.Model.Events (SidebarEvent)
  22. import PureTabs.Sidebar.Tabs (Output(..))
  23. import PureTabs.Sidebar.Tabs as Tabs
  24. import Sidebar.Component.GroupName as GroupName
  25. import Sidebar.Utils (whenC)
  26. newtype GroupId
  27. = GroupId Int
  28. derive instance eqGroupId :: Eq GroupId
  29. derive instance ordGroupId :: Ord GroupId
  30. instance showGroupId :: Show GroupId where
  31. show (GroupId gid) = "GroupId(" <> (show gid) <> ")"
  32. type Group
  33. = { name :: String
  34. , pos :: Int
  35. }
  36. type State
  37. = { groups :: M.Map GroupId Group
  38. , tabsToGroup :: M.Map TabId GroupId
  39. , currentGroup :: GroupId
  40. }
  41. data Action
  42. = UserSelectedGroup GroupId
  43. | UserRenameGroup GroupId String
  44. | UserCreatedGroup
  45. | UserDeletedGroup GroupId
  46. | HandleTabsOutput GroupId Tabs.Output
  47. initialState :: forall i. i -> State
  48. initialState _ =
  49. let
  50. firstGroupId = GroupId 0
  51. in
  52. {
  53. groups: M.fromFoldable [ Tuple firstGroupId { name: "main", pos: 0 } ]
  54. , tabsToGroup: M.empty
  55. , currentGroup: firstGroupId
  56. }
  57. type Slots
  58. = ( tab :: H.Slot Tabs.Query Tabs.Output GroupId, groupName :: forall unusedQuery. H.Slot unusedQuery GroupName.NewName GroupId)
  59. _tab :: SProxy "tab"
  60. _tab = (SProxy :: _ "tab")
  61. _groupName :: SProxy "groupName"
  62. _groupName = (SProxy :: _ "groupName")
  63. component :: forall i m. MonadEffect m => MonadAff m => H.Component HH.HTML Tabs.Query i SidebarEvent m
  64. component =
  65. H.mkComponent
  66. { initialState
  67. , render: render
  68. , eval:
  69. H.mkEval
  70. $ H.defaultEval
  71. { handleQuery = handleQuery
  72. , handleAction = handleAction
  73. }
  74. }
  75. where
  76. render :: State -> H.ComponentHTML Action Slots m
  77. render state =
  78. let
  79. menuElem attrs text = HH.li attrs [ HH.text text]
  80. topMenu = HH.div [ HP.id_ "bar-menu" ] [
  81. HH.ul [] [menuElem [HE.onClick \_ -> Just UserCreatedGroup] "+", menuElem [] "-"]
  82. ]
  83. barListGroup = HH.div [ HP.id_ "bar-list" ] [HH.ul [ HP.id_ "bar-list-group"] $
  84. (M.toUnfoldable state.groups) <#> \(Tuple gid g) -> renderGroup gid (gid == state.currentGroup) g
  85. ]
  86. tabsDivs = (S.toUnfoldable $ (M.keys state.groups)) <#>
  87. (\gid -> HH.div [
  88. HP.classes [(H.ClassName "bar-tabs"), whenC (gid == state.currentGroup) (H.ClassName "bar-tabs-active")]
  89. ] [renderGroupTabs gid])
  90. in
  91. HH.div [ HP.id_ "bar" ] $ topMenu : barListGroup : tabsDivs
  92. renderGroupTabs :: GroupId -> H.ComponentHTML Action Slots m
  93. renderGroupTabs groupId = HH.slot _tab groupId Tabs.component unit (Just <<< (HandleTabsOutput groupId))
  94. renderGroup :: GroupId -> Boolean -> Group -> H.ComponentHTML Action Slots m
  95. renderGroup groupId isActive group =
  96. HH.li [
  97. HP.classes [(H.ClassName "group-name"), whenC isActive (H.ClassName "active-group")]
  98. , HE.onClick (\_ -> Just (UserSelectedGroup groupId))
  99. ] [ HH.slot _groupName groupId GroupName.component group.name (\newName -> Just (UserRenameGroup groupId newName))]
  100. handleAction :: Action -> H.HalogenM State Action Slots SidebarEvent m Unit
  101. handleAction =
  102. case _ of
  103. UserSelectedGroup gid -> H.modify_ _ { currentGroup = gid }
  104. UserRenameGroup gid newName ->
  105. H.modify_ \s -> s { groups = M.update (\g -> Just $ g { name = newName }) gid s.groups }
  106. UserCreatedGroup -> do
  107. H.modify_ \s -> s { groups = M.insert (findNextGroupId $ M.keys s.groups) { name: "new group", pos: M.size s.groups } s.groups }
  108. UserDeletedGroup gid -> pure unit
  109. HandleTabsOutput gid (TabsSidebarAction sbEvent) -> H.raise sbEvent
  110. where
  111. findNextGroupId :: S.Set GroupId -> GroupId
  112. findNextGroupId values =
  113. let GroupId(maxValue) = NES.max (NES.cons (GroupId 0) values)
  114. in GroupId(maxValue + 1)
  115. -- TODO: don't use the current group, but use the group associated with the TabId
  116. handleQuery :: forall act o a. Tabs.Query a -> H.HalogenM State act Slots o m (Maybe a)
  117. handleQuery = case _ of
  118. Tabs.InitialTabList tabs a -> do
  119. s <- H.modify (\s ->
  120. s { tabsToGroup = M.fromFoldable $ tabs <#> \(Tab t) -> Tuple t.id s.currentGroup }
  121. )
  122. void $ tellChild s.currentGroup $ Tabs.InitialTabList tabs
  123. pure (Just a)
  124. Tabs.TabCreated (Tab t) a -> do
  125. s <- H.modify (\s -> s { tabsToGroup = M.insert t.id s.currentGroup s.tabsToGroup })
  126. void $ tellChild s.currentGroup $ Tabs.TabCreated (Tab t)
  127. pure (Just a)
  128. Tabs.TabDeleted tid a -> do
  129. s <- H.modify (\s -> s { tabsToGroup = M.delete tid s.tabsToGroup })
  130. void $ tellChild s.currentGroup $ Tabs.TabDeleted tid
  131. pure (Just a)
  132. Tabs.TabActivated oldTid tid a -> do
  133. s <- H.get
  134. void $ tellChild s.currentGroup $ Tabs.TabActivated oldTid tid
  135. pure (Just a)
  136. Tabs.TabMoved tid prev next a -> do
  137. s <- H.get
  138. void $ tellChild s.currentGroup $ Tabs.TabMoved tid prev next
  139. pure (Just a)
  140. Tabs.TabInfoChanged tid cinfo a -> do
  141. s <- H.get
  142. void $ tellChild s.currentGroup $ Tabs.TabInfoChanged tid cinfo
  143. pure (Just a)
  144. Tabs.TabDetached tid a -> do
  145. s <- H.get
  146. void $ tellChild s.currentGroup $ Tabs.TabDetached tid
  147. pure (Just a)
  148. where
  149. tellChild :: GroupId -> (H.Tell Tabs.Query) -> H.HalogenM State act Slots o m (Maybe Unit)
  150. tellChild gid q = H.query _tab gid $ H.tell q