Add support for dark mode

This commit is contained in:
Thomas Forgione 2021-04-03 23:33:01 +02:00
parent 28f6c05acb
commit df821e07af
6 changed files with 181 additions and 59 deletions

View File

@ -13,14 +13,34 @@
<script src="js/vd.js"></script>
<script src="js/main.js"></script>
<script>
function isDarkMode(e) {
var darkMode = JSON.parse(localStorage.getItem('darkMode'));
if (darkMode === null) {
if (e === undefined) {
e = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)');
}
darkMode = e.matches === true;
}
return darkMode;
}
var app = Elm.Main.init({
node: document.getElementById('container'),
flags: { width: window.innerWidth, height: window.innerHeight }
flags: {
width: window.innerWidth,
height: window.innerHeight,
darkMode: isDarkMode(),
darkSetting: JSON.parse(localStorage.getItem('darkMode'))
}
});
var lastId, player;
if (app.ports !== undefined && app.ports.registerVideo !== undefined) {
if (app.ports !== undefined) {
if (app.ports.registerVideo !== undefined) {
app.ports.registerVideo.subscribe(function(args) {
window.scrollTo(0, 0);
var time = vd.parseTime(args[2]) || undefined;
@ -41,12 +61,31 @@
});
}
if (app.ports !== undefined && app.ports.eraseVideo !== undefined) {
if (app.ports.setDarkMode !== undefined) {
app.ports.setDarkMode.subscribe(function(arg) {
if (arg === null) {
localStorage.removeItem('darkMode');
} else {
localStorage.setItem('darkMode', arg);
}
app.ports.darkMode.send(isDarkMode());
});
}
}
if (app.ports !== undefined) {
if (app.ports.eraseVideo !== undefined) {
app.ports.eraseVideo.subscribe(function() {
window.scrollTo(0, 0);
lastId = undefined;
});
}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) {
app.ports.darkMode.send(isDarkMode(e));
});
}
</script>
</body>
</html>

View File

@ -1,4 +1,4 @@
module Colors exposing (blackFont, greyBackground, greyFont, primary, primaryOver, red, selected, white)
module Colors exposing (..)
import Element
@ -28,16 +28,37 @@ greyBackground =
Element.rgba255 0 0 0 0.7
blackFont : Element.Color
blackFont =
Element.rgb255 54 54 54
background : Bool -> Element.Color
background darkMode =
if darkMode then
Element.rgb255 47 49 54
else
Element.rgb255 245 245 245
greyFont : Element.Color
greyFont =
font : Bool -> Element.Color
font darkMode =
if darkMode then
Element.rgb255 245 245 245
else
Element.rgb255 54 57 63
detailFont : Bool -> Element.Color
detailFont darkMode =
if darkMode then
Element.rgb255 160 160 160
else
Element.rgb255 128 128 128
selected : Element.Color
selected =
selected : Bool -> Element.Color
selected darkMode =
if darkMode then
Element.rgb255 64 68 75
else
Element.rgb255 223 233 250

View File

@ -24,6 +24,8 @@ type alias Model =
, time : Time.Posix
, currentDate : Time.Posix
, url : Url.Url
, darkMode : Bool
, darkSetting : Maybe Bool
}
@ -49,10 +51,12 @@ type Msg
| Unhover
| TimeReceived Time.Posix
| CurrentDateReceived Time.Posix
| DarkMode Bool
| DarkModeClicked
init : { width : Int, height : Int } -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
init { width, height } url key =
init : { width : Int, height : Int, darkMode : Bool, darkSetting : Maybe Bool } -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
init { width, height, darkMode, darkSetting } url key =
( Model
[]
Time.utc
@ -62,6 +66,8 @@ init { width, height } url key =
(Time.millisToPosix 0)
(Time.millisToPosix 0)
url
darkMode
darkSetting
, Cmd.batch
[ Task.attempt TimeZoneReceivedResult TimeZone.getZone
, Task.perform CurrentDateReceived Time.now
@ -85,6 +91,7 @@ subscriptions _ =
Sub.batch
[ Events.onResize (\w h -> SizeReceived w h)
, Time.every 200 TimeReceived
, Ports.darkMode DarkMode
]
@ -154,6 +161,13 @@ update msg model =
, Nav.pushUrl model.key "#"
)
DarkModeClicked ->
let
next =
nextDarkSetting model.darkSetting
in
( { model | darkSetting = next }, Ports.setDarkMode next )
PlaylistClicked playlist ->
( model
, Nav.pushUrl model.key ("#" ++ playlist.url)
@ -248,6 +262,9 @@ update msg model =
Browser.External s ->
( model, Nav.load s )
DarkMode dark ->
( { model | darkMode = dark }, Cmd.none )
splitter : String -> Maybe ( String, String )
splitter input =
@ -262,3 +279,16 @@ splitter input =
parseQueryString : String -> Dict String String
parseQueryString input =
Dict.fromList (List.filterMap splitter (String.split "&" input))
nextDarkSetting : Maybe Bool -> Maybe Bool
nextDarkSetting current =
case current of
Nothing ->
Just True
Just True ->
Just False
Just False ->
Nothing

View File

@ -5,7 +5,7 @@ import Core
import Views
main : Program { width : Int, height : Int } Core.Model Core.Msg
main : Program { width : Int, height : Int, darkMode : Bool, darkSetting : Maybe Bool } Core.Model Core.Msg
main =
Browser.application
{ init = Core.init

View File

@ -1,7 +1,13 @@
port module Ports exposing (eraseVideo, registerVideo)
port module Ports exposing (darkMode, eraseVideo, registerVideo, setDarkMode)
port registerVideo : ( String, String, Maybe String ) -> Cmd msg
port eraseVideo : () -> Cmd msg
port setDarkMode : Maybe Bool -> Cmd msg
port darkMode : (Bool -> msg) -> Sub msg

View File

@ -35,13 +35,14 @@ view model =
{ title = title model
, body =
[ Element.layout
[ Font.color Colors.blackFont
[ Font.color (Colors.font model.darkMode)
, Background.color (Colors.background model.darkMode)
, Font.size Consts.normalFontSize
, Font.family [ Font.typeface "Cantarell" ]
]
(Element.column
[ Element.width Element.fill, Element.height Element.fill ]
[ topBar, element ]
[ topBar model.darkSetting, element ]
)
]
}
@ -67,21 +68,46 @@ viewContent model =
playlistsView model.device model.playlists model.currentDate model.time hover
Core.Playlist playlist hover ->
videoMiniaturesView model.device model.zone model.currentDate model.time hover playlist
videoMiniaturesView model.darkMode model.device model.zone model.currentDate model.time hover playlist
Core.Video playlist video hover ->
videoView model.device model.zone model.currentDate model.time hover playlist video
videoView model.darkMode model.device model.zone model.currentDate model.time hover playlist video
topBar : Element Core.Msg
topBar =
topBar : Maybe Bool -> Element Core.Msg
topBar darkSetting =
Element.row
[ Element.width Element.fill
, Background.color Colors.primary
, Font.color Colors.white
, Font.size Consts.homeFontSize
]
[ homeButton ]
[ homeButton, mode darkSetting ]
mode : Maybe Bool -> Element Core.Msg
mode current =
let
( label, icon ) =
case current of
Nothing ->
( "Par défaut", "🌓" )
Just True ->
( "Mode nuit", "🌑" )
Just False ->
( "Mode jour", "🌕" )
in
Input.button
[ Element.height Element.fill, Element.alignRight, Element.padding 10 ]
{ label =
Element.row [ Element.spacing 5 ]
[ Element.el [ Font.size Consts.titleFontSize ] (Element.text label)
, Element.el [ Font.size Consts.homeFontSize ] (Element.text icon)
]
, onPress = Just Core.DarkModeClicked
}
homeButton : Element Core.Msg
@ -203,14 +229,14 @@ playlistView currentDate time hover playlist =
button
videoMiniaturesView : Element.Device -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Element Core.Msg
videoMiniaturesView device zone currentDate time hover playlist =
videoMiniaturesView : Bool -> Element.Device -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Element Core.Msg
videoMiniaturesView darkMode device zone currentDate time hover playlist =
let
empty =
Element.el [ Element.width Element.fill ] Element.none
views =
List.map (videoMiniatureView zone currentDate time hover playlist) playlist.videos
List.map (videoMiniatureView darkMode zone currentDate time hover playlist) playlist.videos
grouped =
group (numberOfVideosPerRow device) views
@ -288,13 +314,13 @@ videoMiniature currentDate time hover playlist video =
image
videoMiniatureView : Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoMiniatureView zone currentDate time hover playlist video =
videoMiniatureView : Bool -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoMiniatureView darkMode zone currentDate time hover playlist video =
let
display =
Element.column [ Element.width Element.fill, Element.spacing 10 ]
[ videoMiniature currentDate time hover playlist video
, videoDescription zone video
, videoDescription darkMode zone video
]
button =
@ -306,21 +332,21 @@ videoMiniatureView zone currentDate time hover playlist video =
button
videoInList : Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Twitch.Video -> Element Core.Msg
videoInList zone currentDate time hover playlist activeVideo video =
videoInList : Bool -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Twitch.Video -> Element Core.Msg
videoInList darkMode zone currentDate time hover playlist activeVideo video =
let
label =
Element.row [ Element.width Element.fill, Element.spacing 10 ]
[ Element.el [ Element.width (Element.fillPortion 2) ]
(videoMiniature currentDate time hover playlist video)
, Element.el [ Element.width (Element.fillPortion 3), Element.paddingXY 0 10, Element.alignTop ]
(videoDescription zone video)
(videoDescription darkMode zone video)
]
in
if video == activeVideo then
Element.el
[ Element.width Element.fill
, Background.color Colors.selected
, Background.color (Colors.selected darkMode)
, Border.color Colors.primary
, Border.width 2
]
@ -333,8 +359,8 @@ videoInList zone currentDate time hover playlist activeVideo video =
}
videoView : Element.Device -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoView device zone currentDate time hover playlist video =
videoView : Bool -> Element.Device -> Time.Zone -> Time.Posix -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoView darkMode device zone currentDate time hover playlist video =
let
( builder, contentPadding ) =
case device.class of
@ -401,12 +427,12 @@ videoView device zone currentDate time hover playlist video =
, Element.height Element.fill
, Element.scrollbarY
]
(List.map (videoInList zone currentDate time hover playlist video) playlist.videos)
(List.map (videoInList darkMode zone currentDate time hover playlist video) playlist.videos)
]
videoDescription : Time.Zone -> Twitch.Video -> Element Core.Msg
videoDescription zone video =
videoDescription : Bool -> Time.Zone -> Twitch.Video -> Element Core.Msg
videoDescription darkMode zone video =
Element.column [ Element.spacing 10 ]
[ Element.paragraph
[ Font.bold
@ -416,7 +442,7 @@ videoDescription zone video =
, case video.date of
Just date ->
Element.paragraph
[ Font.color Colors.greyFont
[ Font.color (Colors.detailFont darkMode)
]
[ Element.text ("Diffusé le " ++ formatDate zone date) ]