Files
acms/frontend/app/Main.hs

233 lines
4.9 KiB
Haskell
Raw Normal View History

2024-05-31 10:42:26 +02:00
module Main where
#ifndef ghcjs_HOST_OS
import Language.Javascript.JSaddle.Warp as JSaddle
#endif
2024-06-05 22:47:49 +02:00
import Api
2024-06-04 14:36:26 +02:00
import Data.Bifunctor
2024-06-03 11:22:10 +02:00
import Data.Default
import Data.Function
import Miso
import Miso.String (toMisoString)
2024-06-04 12:32:59 +02:00
import NeatInterpolation qualified as Q
2024-06-04 14:36:26 +02:00
import Page (Page, initialPage, updatePage, viewPage)
import Page qualified as Page
import Route (parseURI)
2024-06-05 22:47:49 +02:00
import Version
2024-06-03 11:22:10 +02:00
2024-06-05 22:47:49 +02:00
data Model
= Loading
| Failed String
| Loaded LoadedState
deriving (Show, Eq)
data LoadedState = LoadedState
2024-06-06 22:52:33 +02:00
{ collections :: [String],
schemaVersion :: Version,
page :: Maybe (Either String Page)
2024-06-03 11:22:10 +02:00
}
2024-06-05 22:47:49 +02:00
deriving (Show, Eq)
instance Default Model where
def = Loading
2024-06-03 11:22:10 +02:00
2024-05-31 10:42:26 +02:00
data Action
2024-06-05 22:47:49 +02:00
= -- Loading
SetLoaded (Either String LoadedState)
| -- Loaded
NoOp
2024-06-04 14:36:26 +02:00
| Init URI
| HandleURI URI
| HandlePage Page.Action
| SetPage (Either String Page)
2024-05-31 10:42:26 +02:00
deriving (Show, Eq)
#ifndef ghcjs_HOST_OS
runApp :: JSM () -> IO ()
runApp f = JSaddle.debugOr 8080 (f >> syncPoint) JSaddle.jsaddleApp
#else
runApp :: IO () -> IO ()
runApp app = app
#endif
main :: IO ()
2024-06-04 14:36:26 +02:00
main = runApp $ do
uri <- getCurrentURI
startApp App {initialAction = Init uri, ..}
2024-05-31 10:42:26 +02:00
where
2024-06-03 11:22:10 +02:00
model = def
2024-05-31 10:42:26 +02:00
update = updateModel
view = viewModel
events = defaultEvents
2024-06-04 14:36:26 +02:00
subs = [uriSub HandleURI]
2024-05-31 10:42:26 +02:00
mountPoint = Nothing
logLevel = Off
updateModel :: Action -> Model -> Effect Action Model
2024-06-05 22:47:49 +02:00
updateModel _ (Failed err) = noEff (Failed err)
updateModel (Init uri) Loading =
Loading <# do
page <- Just <$> initialPage (parseURI uri)
schemaVersion' <- fetchSchemaVersion
2024-06-06 22:52:33 +02:00
collections' <- fetchCollections
2024-06-05 22:47:49 +02:00
pure $ SetLoaded do
schemaVersion <- schemaVersion'
2024-06-06 22:52:33 +02:00
collections <- collections'
2024-06-05 22:47:49 +02:00
pure LoadedState {..}
updateModel (Init _) m = noEff m
updateModel (SetLoaded (Left err)) Loading = noEff (Failed err)
updateModel (SetLoaded (Right state)) Loading = noEff (Loaded state)
updateModel (SetLoaded _) m = noEff m
updateModel _ Loading = noEff Loading
updateModel NoOp (Loaded s) = noEff (Loaded s)
updateModel (HandleURI uri) (Loaded s) =
Loaded s <# do
2024-06-04 14:36:26 +02:00
let route = parseURI uri
SetPage <$> initialPage route
2024-06-05 22:47:49 +02:00
updateModel (SetPage page) (Loaded s) = noEff (Loaded s {page = Just page})
updateModel (HandlePage action) (Loaded s) =
case s.page of
2024-06-04 14:36:26 +02:00
Just (Right page) ->
2024-06-05 22:47:49 +02:00
fmap Loaded $
updatePage action page
& bimap HandlePage (\page -> s {page = Just (Right page)})
_ -> noEff (Loaded s)
2024-05-31 10:42:26 +02:00
viewModel :: Model -> View Action
2024-06-05 22:47:49 +02:00
viewModel Loading = text ".."
viewModel (Failed s) = err s
viewModel (Loaded s) =
2024-06-04 14:36:26 +02:00
div_ [] $
[ viewCss,
2024-06-05 22:47:49 +02:00
viewHeader s,
2024-06-06 22:52:33 +02:00
nav_ [] [viewCollections s],
2024-06-04 14:36:26 +02:00
main_ [] $
2024-06-05 22:47:49 +02:00
[ HandlePage <$> maybe (text "..") (either err viewPage) s.page
2024-06-04 09:59:10 +02:00
]
2024-06-04 14:36:26 +02:00
]
2024-06-03 11:22:10 +02:00
2024-06-04 12:32:59 +02:00
viewCss :: View Action
viewCss =
node
HTML
"style"
Nothing
[type_ "text/css"]
[ text
( toMisoString
[Q.text|
/* normalize */
* {
box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh; }
/* typography */
html {
font: Iosevka; }
/* layout */
body > div {
display: flex;
flex-flow: row nowrap;
min-height: 100vh;
padding-top: 64px;
align-items: stretch; }
header {
position: fixed;
top: 0; left: 0;
width: 100%;
height: 64px; }
nav, main {
min-height: 100%; }
nav {
flex: 0 0 200px; }
main {
flex: 1 1 auto; }
/* borders */
header {
border-bottom: 1px solid gray; }
nav {
border-right: 1px solid gray; }
/* padding */
nav, header, main {
padding: 16px; }
/* scrolling */
body > div {
overflow: visible; }
header {
overflow: visible; }
nav, main {
overflow: auto; }
/* header */
header {
display: flex;
align-items: center; }
header section {
margin-left: auto; }
header section:first-child {
margin-left: 0; }
2024-06-04 15:42:33 +02:00
/* table layout */
th, td {
text-align: left;
padding: 0 16px;
line-height: 52px;
text-overflow: ellipsis;
}
/* table borders */
table {
border-collapse: collapse;
border-left: 1px solid gray;
border-right: 1px solid gray; }
th, td {
border-top: 1px solid gray;
border-bottom: 1px solid gray; }
2024-06-04 12:32:59 +02:00
|]
)
]
2024-06-04 14:36:26 +02:00
err :: String -> View action
2024-06-03 11:22:10 +02:00
err = text . toMisoString . ("err! " <>)
2024-06-05 22:47:49 +02:00
viewHeader :: LoadedState -> View Action
viewHeader s =
2024-06-04 12:32:59 +02:00
header_ [] $
2024-06-04 14:36:26 +02:00
[ section_ [] [h1_ [] [a_ [href_ "#"] [text "acms"]]],
2024-06-05 22:47:49 +02:00
section_ [] (viewBranch s)
2024-06-04 12:32:59 +02:00
]
2024-06-05 22:47:49 +02:00
viewBranch :: LoadedState -> [View Action]
viewBranch s =
[ text (toMisoString (versionToString s.schemaVersion)),
text " ",
select_ [] [option_ [] [text "main"]]
]
2024-06-04 12:32:59 +02:00
2024-06-06 22:52:33 +02:00
viewCollections :: LoadedState -> View Action
viewCollections s =
2024-06-04 12:32:59 +02:00
section_ [] $
2024-06-06 23:05:41 +02:00
[ span_
[]
[ text "collections",
text " ",
a_ [href_ "#collection/new"] [text "+new"]
],
2024-06-03 11:22:10 +02:00
ol_ [] $
2024-06-06 22:52:33 +02:00
[ li_
[]
[ a_
[href_ (toMisoString ("#collection/" <> collection))]
[text (toMisoString collection)]
]
| collection <- s.collections
2024-06-04 14:36:26 +02:00
]
]