Skip to content

Commit dd19770

Browse files
authored
fix: Remove flash of unstyled content from theme preferences (#936)
* Fix light theme flashing when dark theme is on; respect system theme * Style * Removed unrelated change
1 parent ef32c3d commit dd19770

11 files changed

Lines changed: 119 additions & 36 deletions

File tree

assets/css/1-core/3-variables.css

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,55 @@
106106
--focused-background: var(--pale-blue);
107107
}
108108

109+
@media(prefers-color-scheme: dark) {
110+
html:not([data-theme="light"]) {
111+
--background-color: var(--blue-20);
112+
--brand-border: var(--purple-30);
113+
--category-card-name-color: var(--purple-60);
114+
--category-card-synopsis-color: var(--gray-90);
115+
--category-card-background-hover: var(--blue-15);
116+
--error-button: var(--purple-30);
117+
--error-code: var(--gray-90);
118+
--link-color: var(--purple-60);
119+
--link-hover-color: var(--blue-15);
120+
--navbar-background-color: var(--blue-15);
121+
--navbar-border-color: transparent;
122+
--navbar-search-color: var(--gray-90);
123+
--navbar-search-background-color: var(--blue-20);
124+
--navbar-search-border-color: var(--blue-20);
125+
--package-list-item-background-hover-color: var(--blue-15);
126+
--package-list-item-name-color: var(--purple-60);
127+
--package-list-item-metadata-color: var(--gray-90);
128+
--package-list-item-synopsis-color: var(--gray-90);
129+
--package-list-item-version-color: var(--green-40);
130+
--search-bar-color: var(--gray-90);
131+
--search-bar-background-color: var(--blue-20);
132+
--search-bar-background-hover-color: var(--blue-20);
133+
--search-bar-background-focus-color: var(--blue-20);
134+
--search-bar-focus-border-color: var(--purple-30);
135+
--readme-pre-background-color: var(--blue-30);
136+
--readme-code-background-color: var(--blue-30);
137+
--changelog-pre-background-color: var(--blue-30);
138+
--changelog-code-background-color: var(--blue-30);
139+
140+
/* --install-string-border: hsl(215 28% 17%); */
141+
--compiler-badge-background: var(--blue-30);
142+
--text-color: var(--gray-80);
143+
--main-page-button-background: var(--blue-20);
144+
--main-page-button-focus-border-color: var(--purple-30);
145+
--main-page-button-divider: var(--blue-15);
146+
--deprecated-version: var(--red-60);
147+
--breadcrumb-color: hsl(221 9% 60%);
148+
--severity-critical: var(--red-60);
149+
--severity-high: orange;
150+
--severity-medium: gold;
151+
--severity-low: var(--pale-blue);
152+
--severity-none: hsl(156 100% 99%);
153+
--severity-rating-colour: black;
154+
--focused-background: var(--blue-80);
155+
}
156+
}
157+
109158
html[data-theme="dark"] {
110159
--background-color: var(--blue-20);
111160
--brand-border: var(--purple-30);

assets/css/2-components/1-navbar.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
}
103103

104104
.navbar-themeBtn {
105+
display: inline-flex;
105106
flex-shrink: 0;
106107
}
107108
}

assets/css/2-components/15-theme-switch.css

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
1-
[data-theme] .theme-button--light {
2-
display: none;
3-
}
4-
5-
[data-theme="dark"] .theme-button--light {
1+
.theme-button--light {
62
display: inline-flex;
73
background-color: hsl(294 40% 30%);
84
}
95

106
.theme-button--dark {
117
display: inline-flex;
8+
background-color: hsl(226 232 240);
129
}
1310

14-
[data-theme="dark"] .theme-button--dark {
15-
display: none;
11+
@media (prefers-color-scheme: light) {
12+
.top-navbar .theme-button--light { display: none; }
1613
}
1714

15+
@media (prefers-color-scheme: dark) {
16+
.top-navbar .theme-button--dark { display: none; }
17+
}
18+
19+
html[data-theme="light"] .theme-button--light { display: none; }
20+
html[data-theme="light"] .theme-button--dark { display: inline-flex; }
21+
html[data-theme="dark"] .theme-button--dark { display: none; }
22+
html[data-theme="dark"] .theme-button--light { display: inline-flex; }
23+
1824
/* Dark mode-specific rules */
1925
.dark {
2026
.social-button:hover {

assets/css/4-helpers/1-globals.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,6 @@
114114
border-color: rgb(229 231 235 / 100%);
115115
}
116116

117-
.bg-slate-200 {
118-
background-color: rgb(226 232 240 / 100%);
119-
}
120-
121117
@media (--viewport-sm) {
122118
.sm\:rounded-lg {
123119
border-radius: var(--space-lg);

assets/css/4-helpers/2-colors.css

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
/* stylelint-disable selector-class-pattern */
22

3-
/* Background */
4-
.bg-slate-200 { background-color: rgb(226 232 240 / 100%); }
5-
63
/* Text */
74

85
.text-black { color: rgb(0 0 0 / 100%); }

src/core/Flora/Environment.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Flora.Environment
22
( getFloraEnv
3-
) where
3+
)
4+
where
45

56
import Data.ByteString (ByteString)
67
import Data.Pool (Pool)
@@ -62,6 +63,7 @@ configToEnv floraConfig = do
6263
, assets = assets
6364
, config = floraConfig
6465
, metrics = metrics
66+
, theme = Nothing
6567
}
6668

6769
getFloraEnv :: (Fail :> es, FileSystem :> es, IOE :> es) => Eff es FloraEnv

src/core/Flora/Environment/Env.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ module Flora.Environment.Env
55
, MLTP (..)
66
, FeatureEnv (..)
77
, BlobStoreImpl (..)
8-
) where
8+
)
9+
where
910

1011
import Data.Aeson
1112
import Data.Pool (Pool)
@@ -30,6 +31,7 @@ data FloraEnv = FloraEnv
3031
, config :: FloraConfig
3132
, assets :: Assets
3233
, metrics :: AppMetrics
34+
, theme :: Maybe Text
3335
}
3436
deriving stock (Generic)
3537

src/web/FloraWeb/Common/Auth.hs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ handler
9898
-> Eff es (Headers '[Header "Set-Cookie" SetCookie] (Session (Maybe User)))
9999
handler floraEnv req = do
100100
let cookies = getCookies req
101+
let theme = getTheme cookies
101102
mbPersistentSessionId <- handlerToEff $ getSessionId cookies
102103
mbPersistentSession <- getInTheFuckingSessionShinji mbPersistentSessionId
103104
mUserInfo <- fetchUser mbPersistentSession
@@ -108,7 +109,7 @@ handler floraEnv req = do
108109
nSessionId <- liftIO newPersistentSessionId
109110
pure (Nothing, nSessionId)
110111
Just (user, userSession) -> pure (Just user, userSession.persistentSessionId)
111-
webEnvStore <- liftIO $ newWebEnvStore (WebEnv floraEnv)
112+
webEnvStore <- liftIO $ newWebEnvStore (WebEnv $ floraEnv{theme = theme})
112113
let sessionCookie = craftSessionCookie sessionId False
113114
pure $ addCookie sessionCookie $ Session sessionId user webEnvStore requestID
114115

@@ -147,6 +148,12 @@ getRequestID req = do
147148
Nothing -> fmap UUID.toText UUID.nextRandom
148149
Just requestID -> pure $ Text.decodeUtf8 requestID
149150

151+
getTheme :: Cookies -> Maybe Text
152+
getTheme cookies =
153+
case List.lookup "theme" cookies of
154+
Nothing -> Nothing
155+
Just theme -> pure $ Text.decodeUtf8 theme
156+
150157
getSessionId :: Cookies -> Handler (Maybe PersistentSessionId)
151158
getSessionId cookies =
152159
case List.lookup "flora_server_session" cookies of

src/web/FloraWeb/Components/Header.hs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,39 @@ import FloraWeb.Pages.Templates.Types (FloraHTML, TemplateEnv (..))
1616

1717
header :: FloraHTML
1818
header = do
19-
TemplateEnv{environment, title, indexPage} <- ask
19+
TemplateEnv{environment, title, indexPage, theme} <- ask
2020
doctype_
21+
let theme' = case theme of
22+
Nothing -> []
23+
Just a -> [data_ "theme" a]
2124
html_
22-
[ lang_ "en"
23-
, class_ "no-js"
24-
, xData_
25-
"{ theme: \
26-
\ localStorage.getItem('theme') \
27-
\ || (window.matchMedia('(prefers-color-scheme: dark)').matches \
28-
\ ? 'dark' : 'light') \
29-
\ }"
30-
, xBind_ "data-theme" "(theme === 'dark') ? 'dark' : 'light'"
31-
, xInit_ "$watch('theme', val => localStorage.setItem('theme', val))"
32-
]
25+
( [ lang_ "en"
26+
, class_ "no-js"
27+
, xData_
28+
"{ updateTheme() { \
29+
\ const customTheme = document.documentElement.getAttribute('data-theme'); \
30+
\ const isSystemDark = window.matchMedia('(prefers-color-scheme: dark)').matches; \
31+
\ const applyTheme = (theme) => { \
32+
\ document.documentElement.setAttribute('data-theme', theme); \
33+
\ console.log(\"theme switch\"); \
34+
\ (async () => { await cookieStore.set('theme', theme) })(); \
35+
\ }; \
36+
\ switch (customTheme) { \
37+
\ case 'light': \
38+
\ applyTheme('dark'); \
39+
\ break; \
40+
\ case 'dark': \
41+
\ applyTheme('light'); \
42+
\ break; \
43+
\ default: \
44+
\ isSystemDark ? applyTheme('light') : applyTheme('dark'); \
45+
\ break; \
46+
\ } \
47+
\ } \
48+
\}"
49+
]
50+
<> theme'
51+
)
3352
$ do
3453
head_ $ do
3554
meta_ [charset_ "UTF-8"]
@@ -64,7 +83,7 @@ header = do
6483
]
6584
meta_ [name_ "description", content_ "A package repository for the Haskell ecosystem"]
6685
ogTags
67-
theme
86+
themeHtml
6887
-- link_ [rel_ "canonical", href_ $ getCanonicalURL assigns]
6988
meta_ [name_ "twitter:dnt", content_ "on"]
7089

@@ -108,7 +127,7 @@ ogTags = do
108127
meta_ [property_ "og:locale", content_ "en_GB"]
109128
meta_ [property_ "og:type", content_ "website"]
110129

111-
theme :: FloraHTML
112-
theme = do
130+
themeHtml :: FloraHTML
131+
themeHtml = do
113132
meta_ [name_ "theme-color", content_ "#000", media_ "(prefers-color-scheme: dark)"]
114133
meta_ [name_ "theme-color", content_ "#FFF", media_ "(prefers-color-scheme: light)"]

src/web/FloraWeb/Components/Navbar.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,23 +138,23 @@ themeToggle = do
138138
let moonIcon = do
139139
img_ [src_ "/static/icons/moon.svg", class_ "h-6 w-6", alt_ ""]
140140

141-
let buttonBaseClasses = "navbar-themeBtn p-2 m-4 md:m-0 rounded-md inline-flex items-center bg-slate-200"
141+
let buttonBaseClasses = "navbar-themeBtn p-2 m-4 md:m-0 rounded-md items-center"
142142

143143
button_
144-
[ xOn_ "click" "theme = 'light'; menuOpen = false"
144+
[ xOn_ "click" "updateTheme()"
145145
, class_ $ "theme-button--light " <> buttonBaseClasses
146146
, ariaLabel_ "Switch to light theme"
147147
]
148148
sunIcon
149149

150150
button_
151-
[ xOn_ "click" "theme = 'dark'; menuOpen = false"
151+
[ xOn_ "click" "updateTheme()"
152152
, class_ $ "theme-button--dark " <> buttonBaseClasses
153153
, ariaLabel_ "Switch to dark theme"
154154
]
155155
moonIcon
156156

157-
input_ [type_ "checkbox", name_ "", id_ "darkmode-toggle", class_ "hidden", xModel_ [] "theme"]
157+
input_ [type_ "checkbox", name_ "", id_ "darkmode-toggle", class_ "hidden"]
158158

159159
getUsernameOrLogin :: Maybe User -> FloraHTML
160160
getUsernameOrLogin Nothing = navBarLink' "/sessions/new" "Login" False

0 commit comments

Comments
 (0)