Add a basic HTML interface

This commit is contained in:
Emi Simpson 2022-11-08 22:42:02 -05:00
parent 257712bfae
commit 831b361eda
Signed by: Emi
GPG Key ID: A12F2C2FFDC3D847
5 changed files with 151 additions and 3 deletions

128
index.html Normal file
View File

@ -0,0 +1,128 @@
<!Doctype HTML>
<html>
<head>
<style>
body {
margin: 0;
padding: 0;
background: #201b27;
color: white;
font-family: sans-serif;
}
#thumbnails {
display: flex;
flex-wrap: wrap;
gap: 30px;
justify-content: center;
}
.thumbnail-card {
height: 400px;
}
#focused-panel {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: rgba(0, 0, 0, 60%);
display: grid;
justify-items: center;
align-items: center;
box-sizing: border-box;
overflow: auto;
}
#focused-panel > img {
max-height: 80vh;
max-width: 60vw;
padding: 50px;
}
#spinner {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
#loader-text {
position: absolute;
width: fit-content;
height: fit-content;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto auto;
text-align: center;
font-size: 31px;
}
/* Yoinked from https://codepen.io/AdamDipinto/pen/eYOaGvY
with modifications */
.loader {
position: relative;
width: 350px;
height: 350px;
border-radius: 50%;
background: linear-gradient(#ff52bf, #f1f1f1, #1ed3ec);
animation: animate 1.2s linear infinite;
}
@keyframes animate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.loader span {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
background: linear-gradient(#ff52bf, #f1f1f1, #1ed3ec);
}
.loader span:nth-child(1) {
filter: blur(5px);
}
.loader span:nth-child(2) {
filter: blur(10px);
}
.loader span:nth-child(3) {
filter: blur(25px);
}
.loader span:nth-child(4) {
filter: blur(50px);
}
.loader:after {
content: '';
position: absolute;
top: 10px;
left: 10px;
right: 10px;
bottom: 10px;
background: #201b27;
border-radius: 50%;
}
</style>
<script src="/index.js"></script>
<script src="https://unpkg.com/rescript-blurhash@0.4.0/dist/production.min.js"></script>
</head>
<body>
<div id="spinner">
<div class="loader">
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div id="loader-text">Downloading<br/>Gallery...</div>
</div>
</body>
</html>

View File

@ -1,6 +1,7 @@
module Main where module Main where
import Prelude import Prelude
import Aviary.FFI (removeSpinner)
import Aviary.UI (component) import Aviary.UI (component)
import Aviary.Logic (fetch_and_decrypt_gallery, get_parameters) import Aviary.Logic (fetch_and_decrypt_gallery, get_parameters)
import Aviary.Model (Model(..)) import Aviary.Model (Model(..))
@ -8,6 +9,7 @@ import Aviary.Model (Model(..))
import Data.Either (Either(..)) import Data.Either (Either(..))
import Effect (Effect) import Effect (Effect)
import Effect.Aff (Aff, launchAff) import Effect.Aff (Aff, launchAff)
import Effect.Class (liftEffect)
import Halogen.Aff (awaitBody) import Halogen.Aff (awaitBody)
import Halogen.VDom.Driver (runUI) import Halogen.VDom.Driver (runUI)
@ -18,6 +20,7 @@ main_aff = do
gallery <- case parameters of gallery <- case parameters of
Left e -> pure $ GError e Left e -> pure $ GError e
Right parameters' -> fetch_and_decrypt_gallery parameters' Right parameters' -> fetch_and_decrypt_gallery parameters'
_ <- liftEffect $ removeSpinner
_ <- runUI (component gallery) unit body _ <- runUI (component gallery) unit body
pure unit pure unit

View File

@ -25,6 +25,7 @@ data Event = LoadThumbs
| ThumbLoaded Int ImageData | ThumbLoaded Int ImageData
| FullLoaded Int ImageData | FullLoaded Int ImageData
| Focus Int | Focus Int
| Unfocus
component :: forall query input. Model -> H.Component query input Event Aff component :: forall query input. Model -> H.Component query input Event Aff
component initialState = H.mkComponent component initialState = H.mkComponent
@ -52,8 +53,8 @@ renderThumbnail pos image =
renderFocused :: forall m. Image -> H.ComponentHTML Event () m renderFocused :: forall m. Image -> H.ComponentHTML Event () m
renderFocused image = renderFocused image =
HH.div HH.div
[ HP.class_ $ ClassName "focused-panel" [ HP.id $ "focused-panel"
, HP.class_ $ ClassName "visible" , HE.onClick \_ -> Unfocus
] ]
( [ HH.img $ ( [ HH.img $
maybe [] (HP.src >>> pure) (fullOrBlurhash image) maybe [] (HP.src >>> pure) (fullOrBlurhash image)
@ -107,11 +108,18 @@ update (Focus newFocus) = do
Just focusedImage' -> fetchFullAction newFocus focusedImage' Just focusedImage' -> fetchFullAction newFocus focusedImage'
Nothing -> Nothing ->
H.put $ GError $ UnexpectedError "Focus event raised with an out of bounds index!" H.put $ GError $ UnexpectedError "Focus event raised with an out of bounds index!"
update Unfocus = H.modify_ \model -> case model of
GError e -> GError e
GLoaded gal -> GLoaded gal { focus = Nothing }
render :: forall m. Model -> H.ComponentHTML Event () m render :: forall m. Model -> H.ComponentHTML Event () m
render (GError e) = HH.p_ [ HH.text $ show e ] render (GError e) = HH.p_ [ HH.text $ show e ]
render (GLoaded {title, desc, images, focus}) = HH.div_ render (GLoaded {title, desc, images, focus}) = HH.div_
((maybe [] (HH.text >>> pure >>> HH.h1_ >>> pure) title) <> ((maybe [] (HH.text >>> pure >>> HH.h1_ >>> pure) title) <>
(maybe [] (HH.text >>> pure >>> HH.p_ >>> pure) desc) <> (maybe [] (HH.text >>> pure >>> HH.p_ >>> pure) desc) <>
(mapWithIndex renderThumbnail images) <> [ HH.div
[ HP.id "thumbnails"
]
(mapWithIndex renderThumbnail images)
] <>
(maybe [] (renderFocused >>> pure) (index images =<< focus))) (maybe [] (renderFocused >>> pure) (index images =<< focus)))

View File

@ -21,3 +21,7 @@ export function decodeBlurhashImpl(just) {
} }
} }
} }
export function removeSpinner() {
document.getElementById("spinner").remove()
}

View File

@ -1,7 +1,10 @@
module Aviary.FFI where module Aviary.FFI where
import Prelude
import Data.ArrayBuffer.Types (ArrayBuffer) import Data.ArrayBuffer.Types (ArrayBuffer)
import Data.Maybe (Maybe(..)) import Data.Maybe (Maybe(..))
import Effect (Effect)
import Web.File.Blob (Blob) import Web.File.Blob (Blob)
-- mimeType :: String -- mimeType :: String
@ -15,3 +18,5 @@ decodeBlurhash :: Int -> Int -> String -> Maybe String
decodeBlurhash = decodeBlurhashImpl Just Nothing decodeBlurhash = decodeBlurhashImpl Just Nothing
decodeBlurhash32 :: String -> Maybe String decodeBlurhash32 :: String -> Maybe String
decodeBlurhash32 = decodeBlurhash 32 32 decodeBlurhash32 = decodeBlurhash 32 32
foreign import removeSpinner :: Effect Unit