Skip to content

Commit

Permalink
T345056: dark mode (#186)
Browse files Browse the repository at this point in the history
* Add support for prefers-color-scheme

* Make the spanish demo page default dark view

* Update media query

* Allow detect config option as default

* Fix line max-len warning

* Update storybook

* Updated loading state dark style

* Use CSS custom properties instead of mixins

* Add prefixes to all vars

* Simplify with mixins

* Remove rules from :root

* Update README

* Update README
  • Loading branch information
medied committed Mar 6, 2024
1 parent 9b4d6e2 commit 24586e5
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 60 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ popupContainer | DOM Element | `document.body` | Where to put the popup in the D
detectLinks | Boolean | `false` | Allow Wikipedia hyperlinks to have the popup
events | Object | `{}` | Custom event handlers: `{ onShow: <fn>, onWikiRead: <fn> }`
debug | Boolean | `false` | Shows the debug message when `init()` is called
prefersColorScheme | string | `'detect'` | Sets theme color. Allowed values are 'light', 'dark' and 'detect'. Setting it to 'light' or 'dark' will dictate theme color regardless of [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme); setting to 'detect' will render preview according to [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme).

Example (custom selector)
```html
Expand Down Expand Up @@ -159,6 +160,21 @@ If you prefer to style them in a way that makes more sense for your context, sim
}
```

#### CSS custom properties

If you wish to adjust the styling of the light/dark theme, you can override the following CSS custom properties to your liking as shown below, under the appropriate [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) query.

```CSS
@media (prefers-color-scheme: dark) {
.wikipediapreview {
--wikipediapreview-primary-background-color: #202122;
--wikipediapreview-secondary-background-color: #202122;
--wikipediapreview-primary-color: #eaecf0;
--wikipediapreview-filter-setting: invert(1);
}
}
```

## Acknowledgements/Contributors

This is heavily inspired by [jquery.wikilookup](https://github.com/mooeypoo/jquery.wikilookup) and [Page Previews](https://www.mediawiki.org/wiki/Page_Previews).
15 changes: 14 additions & 1 deletion demo/articles/spanish.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@
<link href="../css/article.css" rel="stylesheet" type="text/css"/>
<link href="../css/link.css" rel="stylesheet" type="text/css"/>
<style>
body {
background-color: #202122;

p {
color: #EAECF0;
}
}

.header {
color: #36c;
}

@media screen and (max-width: 650px) {
.customize-background-position {
background-position-y: -30px !important;
Expand Down Expand Up @@ -67,7 +79,8 @@
<script src="/dist/wikipedia-preview.umd.cjs"></script>
<script>
wikipediaPreview.init({
lang: 'es'
lang: 'es',
prefersColorScheme: 'dark'
});
</script>
<!-- End of Scripts -->
Expand Down
25 changes: 18 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ function init( {
detectLinks = false,
popupContainer = document.body,
events = {},
debug = false
debug = false,
prefersColorScheme = 'detect'
} ) {
const globalLang = lang
const popup = isTouch ?
Expand Down Expand Up @@ -99,7 +100,11 @@ function init( {

popup.loading = true
popup.dir = dir
popup.show( renderLoading( isTouch, localLang, dir ), currentTarget, pointerPosition )
popup.show(
renderLoading( isTouch, localLang, dir, prefersColorScheme ),
currentTarget,
pointerPosition
)

requestPagePreview( localLang, title, ( data ) => {
if ( popupId !== currentPopupId ) {
Expand All @@ -112,16 +117,22 @@ function init( {
popup.title = title
if ( data.type === 'standard' ) {
popup.show(
renderPreview( localLang, data, isTouch ),
renderPreview( localLang, data, isTouch, prefersColorScheme ),
currentTarget,
pointerPosition
)
invokeCallback( events, 'onShow', [ title, localLang, 'standard' ] )
} else if ( data.type === 'disambiguation' ) {
const content = data.extractHtml ?
renderPreview( localLang, data, isTouch ) :
renderPreview( localLang, data, isTouch, prefersColorScheme ) :
// fallback message when no extract is found on disambiguation page
renderDisambiguation( isTouch, localLang, data.title, data.dir )
renderDisambiguation(
isTouch,
localLang,
data.title,
data.dir,
prefersColorScheme
)
popup.show(
content,
currentTarget,
Expand All @@ -132,14 +143,14 @@ function init( {
} else {
if ( isOnline() ) {
popup.show(
renderError( isTouch, localLang, title, dir ),
renderError( isTouch, localLang, title, dir, prefersColorScheme ),
currentTarget,
pointerPosition
)
invokeCallback( events, 'onShow', [ title, localLang, 'error' ] )
} else {
popup.show(
renderOffline( isTouch, localLang, dir ),
renderOffline( isTouch, localLang, dir, prefersColorScheme ),
currentTarget,
pointerPosition
)
Expand Down
40 changes: 24 additions & 16 deletions src/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,21 @@ const getPreviewBody = ( type, message, cta ) => {
`.trim()
}

const render = ( lang, isTouch, dir, headerContent, bodyContent ) => {
const getReadOnWikiCta = ( lang, title, isTouch ) => {
return `<a href="${ buildWikipediaUrl( lang, title, isTouch ) }" target="_blank" class="wikipediapreview-cta-readonwiki">${ msg( lang, 'read-on-wiki' ) }</a>`
}

const render = ( lang, isTouch, dir, headerContent, bodyContent, prefersColorScheme ) => {
const colorScheme = prefersColorScheme === 'detect' ? '' : `wikipediapreview-${ prefersColorScheme }-theme`
return `
<div class="wikipediapreview ${ isTouch ? 'mobile' : '' }" lang="${ lang }" dir="${ dir }">
<div class="wikipediapreview ${ isTouch ? 'mobile' : '' } ${ colorScheme }" lang="${ lang }" dir="${ dir }">
${ headerContent }
${ bodyContent }
</div>
`.trim()
}

const renderPreview = ( lang, data, isTouch ) => {
const renderPreview = ( lang, data, isTouch, prefersColorScheme ) => {
const imageUrl = data.imgUrl,
bodyContent = `
<div class="wikipediapreview-body">
Expand All @@ -49,10 +54,17 @@ const renderPreview = ( lang, data, isTouch ) => {
</div>
`.trim()

return render( lang, isTouch, data.dir, getPreviewHeader( lang, imageUrl ), bodyContent )
return render(
lang,
isTouch,
data.dir,
getPreviewHeader( lang, imageUrl ),
bodyContent,
prefersColorScheme
)
}

const renderLoading = ( isTouch, lang, dir ) => {
const renderLoading = ( isTouch, lang, dir, prefersColorScheme ) => {
const bodyContent = `
<div class="wikipediapreview-body wikipediapreview-body-loading">
<div class="wikipediapreview-body-loading-line larger"></div>
Expand All @@ -69,32 +81,28 @@ const renderLoading = ( isTouch, lang, dir ) => {
<div class="wikipediapreview-footer-loading"></div>
`.trim()

return render( lang, isTouch, dir, getPreviewHeader( lang ), bodyContent )
}

const getReadOnWikiCta = ( lang, title, isTouch ) => {
return `<a href="${ buildWikipediaUrl( lang, title, isTouch ) }" target="_blank" class="wikipediapreview-cta-readonwiki">${ msg( lang, 'read-on-wiki' ) }</a>`
return render( lang, isTouch, dir, getPreviewHeader( lang ), bodyContent, prefersColorScheme )
}

const renderError = ( isTouch, lang, title, dir ) => {
const renderError = ( isTouch, lang, title, dir, prefersColorScheme ) => {
const message = `<span>${ msg( lang, 'preview-error-message' ) }</span>`
const cta = getReadOnWikiCta( lang, title, isTouch )

return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'error', message, cta ) )
return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'error', message, cta ), prefersColorScheme )
}

const renderDisambiguation = ( isTouch, lang, title, dir ) => {
const renderDisambiguation = ( isTouch, lang, title, dir, prefersColorScheme ) => {
const message = `<span>${ msg( lang, 'preview-disambiguation-message', title ) }</span>`
const cta = getReadOnWikiCta( lang, title, isTouch )

return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'disambiguation', message, cta ) )
return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'disambiguation', message, cta ), prefersColorScheme )
}

const renderOffline = ( isTouch, lang, dir ) => {
const renderOffline = ( isTouch, lang, dir, prefersColorScheme ) => {
const message = `<span>${ msg( lang, 'preview-offline-message' ) }</span>`
const cta = `<a>${ msg( lang, 'preview-offline-cta' ) }</a>`

return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'offline', message, cta ) )
return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'offline', message, cta ), prefersColorScheme )
}

export { renderPreview, renderLoading, renderError, renderDisambiguation, renderOffline }
40 changes: 23 additions & 17 deletions src/stories/preview.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ export default {
imgUrl: {
name: 'Thumbnail URL',
control: 'text'
},
prefersColorScheme: {
name: 'Color Scheme',
control: 'inline-radio',
options: [ 'light', 'dark', 'detect' ]
}
},
args: {
Expand All @@ -42,21 +47,22 @@ export default {
title: 'Cat',
pageUrl: 'https://en.wikipedia.org/wiki/Cat',
extractHtml: '<p><strong>Lorem ipsum dolor sit amet,</strong> consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <br/><br/>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>',
imgUrl: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Moons_of_solar_system-he.svg/langhe-320px-Moons_of_solar_system-he.svg.png'
imgUrl: 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Moons_of_solar_system-he.svg/langhe-320px-Moons_of_solar_system-he.svg.png',
prefersColorScheme: 'light'
}
}

export const StandardWithImage = ( { lang, title, extractHtml, dir, pageUrl, imgUrl, touch } ) => {
return renderPreview( lang, { title, extractHtml, dir, pageUrl, imgUrl }, touch )
export const StandardWithImage = ( { lang, title, extractHtml, dir, pageUrl, imgUrl, touch, prefersColorScheme } ) => {

Check warning on line 55 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (17)

This line has a length of 119. Maximum allowed is 100

Check warning on line 55 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (latest)

This line has a length of 119. Maximum allowed is 100
return renderPreview( lang, { title, extractHtml, dir, pageUrl, imgUrl }, touch, prefersColorScheme )

Check warning on line 56 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (17)

This line has a length of 105. Maximum allowed is 100

Check warning on line 56 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (latest)

This line has a length of 105. Maximum allowed is 100
}

export const Standard = ( { lang, title, extractHtml, dir, pageUrl, touch } ) => {
return renderPreview( lang, { title, extractHtml, dir, pageUrl }, touch )
export const Standard = ( { lang, title, extractHtml, dir, pageUrl, touch, prefersColorScheme } ) => {

Check warning on line 59 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (17)

This line has a length of 102. Maximum allowed is 100

Check warning on line 59 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (latest)

This line has a length of 102. Maximum allowed is 100
return renderPreview( lang, { title, extractHtml, dir, pageUrl }, touch, prefersColorScheme )
}

export const Expanded = ( { lang, title, extractHtml, dir, pageUrl, touch } ) => {
export const Expanded = ( { lang, title, extractHtml, dir, pageUrl, touch, prefersColorScheme } ) => {

Check warning on line 63 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (17)

This line has a length of 102. Maximum allowed is 100

Check warning on line 63 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (latest)

This line has a length of 102. Maximum allowed is 100
const template = document.createElement( 'template' )
template.innerHTML = renderPreview( lang, { title, extractHtml, dir, pageUrl }, touch )
template.innerHTML = renderPreview( lang, { title, extractHtml, dir, pageUrl }, touch, prefersColorScheme )

Check warning on line 65 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (17)

This line has a length of 111. Maximum allowed is 100

Check warning on line 65 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (latest)

This line has a length of 111. Maximum allowed is 100
const preview = template.content.firstChild
preview.classList.add( 'expanded' )
const mediaData = [
Expand All @@ -76,22 +82,22 @@ export const Expanded = ( { lang, title, extractHtml, dir, pageUrl, touch } ) =>
return preview
}

export const Loading = ( { touch, lang, dir } ) => {
return renderLoading( touch, lang, dir )
export const Loading = ( { touch, lang, dir, prefersColorScheme } ) => {
return renderLoading( touch, lang, dir, prefersColorScheme )
}

export const Error = ( { touch, lang, title, dir } ) => {
return renderError( touch, lang, title, dir )
export const Error = ( { touch, lang, title, dir, prefersColorScheme } ) => {
return renderError( touch, lang, title, dir, prefersColorScheme )
}

export const Disambiguation = ( { lang, title, extractHtml, dir, pageUrl, touch } ) => {
return renderPreview( lang, { title, extractHtml, dir, pageUrl }, touch )
export const Disambiguation = ( { lang, title, extractHtml, dir, pageUrl, touch, prefersColorScheme } ) => {

Check warning on line 93 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (17)

This line has a length of 108. Maximum allowed is 100

Check warning on line 93 in src/stories/preview.stories.js

View workflow job for this annotation

GitHub Actions / build (latest)

This line has a length of 108. Maximum allowed is 100
return renderPreview( lang, { title, extractHtml, dir, pageUrl }, touch, prefersColorScheme )
}

export const DisambiguationWithNoExtract = ( { touch, lang, title, dir } ) => {
return renderDisambiguation( touch, lang, title, dir )
export const DisambiguationWithNoExtract = ( { touch, lang, title, dir, prefersColorScheme } ) => {
return renderDisambiguation( touch, lang, title, dir, prefersColorScheme )
}

export const Offline = ( { touch, lang, dir } ) => {
return renderOffline( touch, lang, dir )
export const Offline = ( { touch, lang, dir, prefersColorScheme } ) => {
return renderOffline( touch, lang, dir, prefersColorScheme )
}
61 changes: 42 additions & 19 deletions style/preview.less
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
display: flex;
flex-direction: column;
width: 350px;
background-color: var( --wikipediapreview-primary-background-color );
box-shadow: 0 30px 90px -20px rgba( 0, 0, 0, 0.3 ), 0 0 1px 1px rgba( 0, 0, 0, 0.05 );
border-radius: 8px 8px 0 0;
background-color: #fff;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Lato', 'Helvetica', 'Arial', sans-serif;

* {
Expand Down Expand Up @@ -43,6 +43,7 @@
flex-grow: 1;
margin-left: 16px;
margin-right: 16px;
filter: var( --wikipediapreview-filter-setting );

&-with-image {
margin-top: 16px;
Expand Down Expand Up @@ -75,34 +76,20 @@
height: 100%;
text-align: center;
width: 50px;
filter: var( --wikipediapreview-filter-setting );
}
}

&-body {
background-color: #fff;
max-height: 248px;
overflow: hidden;

&:after {
content: ' ';
position: absolute;
width: 100%;
bottom: 35px;
left: 0;
right: 200px;
top: 235px;
background: -moz-linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, #fff 100% );
background: -webkit-linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, #fff 100% );
background: linear-gradient( to bottom, rgba( 255, 255, 255, 0 ) 0%, #fff 100% );
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ffffff', GradientType=0 );
}

p {
margin: 0;
color: #202122;
line-height: 1.6;
font-size: 18px;
padding: 10px 20px;
color: var( --wikipediapreview-primary-color );
}

ul {
Expand All @@ -117,7 +104,7 @@
margin-right: 23px;
font-size: 16px;
line-height: 1.4;
color: #000;
color: var( --wikipediapreview-primary-color );
}

&-icon {
Expand Down Expand Up @@ -272,7 +259,7 @@

&-loading {
height: 30px;
background-color: #eaecf0;
background-color: var( --wikipediapreview-secondary-background-color );
}
}

Expand Down Expand Up @@ -352,3 +339,39 @@
flex-direction: column;
justify-content: center;
}

@media (prefers-color-scheme: dark) {
.wikipediapreview {
.mixin-wikipediapreview-dark-theme();
}
}

@media (prefers-color-scheme: light) {
.wikipediapreview {
.mixin-wikipediapreview-light-theme();
}
}

.wikipediapreview.wikipediapreview-dark-theme {
.mixin-wikipediapreview-dark-theme();

}

.wikipediapreview.wikipediapreview-light-theme {
.mixin-wikipediapreview-light-theme();
}


.mixin-wikipediapreview-dark-theme () {
--wikipediapreview-primary-background-color: #202122;
--wikipediapreview-secondary-background-color: #202122;
--wikipediapreview-primary-color: #eaecf0;
--wikipediapreview-filter-setting: invert(1);
}

.mixin-wikipediapreview-light-theme () {
--wikipediapreview-primary-background-color: #fff;
--wikipediapreview-secondary-background-color: #eaecf0;
--wikipediapreview-primary-color: #202122;
--wikipediapreview-filter-setting: unset;
}

0 comments on commit 24586e5

Please sign in to comment.