浏览代码

Dark mode for the popup and the options page

simov 2 年之前
父节点
当前提交
b5290ed579
共有 11 个文件被更改,包括 173 次插入50 次删除
  1. 2 3
      background/icon.js
  2. 1 1
      background/inject.js
  3. 7 4
      background/messages.js
  4. 10 1
      background/storage.js
  5. 1 1
      content/index.js
  6. 55 0
      options/index.css
  7. 1 0
      options/index.js
  8. 1 1
      options/origins.js
  9. 56 26
      options/settings.js
  10. 34 12
      popup/index.css
  11. 5 1
      popup/index.js

+ 2 - 3
background/icon.js

@@ -1,11 +1,10 @@
 
 md.icon = ({storage: {state}}) => () => {
 
-  setTimeout((color) =>
+  setTimeout(() =>
     chrome.action.setIcon({
       path: [16, 19, 38, 48, 128].reduce((all, size) => (
-        color = state.icon ? 'light' : 'dark',
-        all[size] = `/icons/${color}/${size}x${size}.png`,
+        all[size] = `/icons/${state.settings.icon}/${size}x${size}.png`,
         all
       ), {})
     })

+ 1 - 1
background/inject.js

@@ -9,7 +9,7 @@ md.inject = ({storage: {state}}) => (id) => {
       themes: state.themes,
       content: state.content,
       compiler: state.compiler,
-      icon: state.icon,
+      icon: state.settings.icon,
     }],
     func: (_args) => {
       document.querySelector('pre').style.visibility = 'hidden'

+ 7 - 4
background/messages.js

@@ -42,6 +42,7 @@ md.messages = ({storage: {defaults, state, set}, compilers, mathjax, xhr, webreq
         description: compilers[state.compiler].description,
         compilers: Object.keys(compilers),
         themes: state.themes,
+        settings: {theme: state.settings.theme}
       }))
     }
     else if (req.message === 'popup.theme') {
@@ -127,16 +128,18 @@ md.messages = ({storage: {defaults, state, set}, compilers, mathjax, xhr, webreq
 
     // settings view
     else if (req.message === 'options.settings') {
-      sendResponse({
-        icon: state.icon,
-      })
+      sendResponse(state.settings)
     }
     // settings options
     else if (req.message === 'options.icon') {
-      set({icon: req.icon})
+      set({settings: req.settings})
       icon()
       sendResponse()
     }
+    else if (req.message === 'options.theme') {
+      set({settings: req.settings})
+      sendResponse()
+    }
 
     return true
   }

+ 10 - 1
background/storage.js

@@ -61,7 +61,10 @@ md.storage.defaults = (compilers) => {
         match,
       }
     },
-    icon: false,
+    settings: {
+      icon: 'dark',
+      theme: 'light',
+    }
   }
 
   Object.keys(compilers).forEach((compiler) => {
@@ -151,4 +154,10 @@ md.storage.migrations = (state) => {
   if (state.content.scroll !== undefined) {
     delete state.content.scroll
   }
+  if (state.settings === undefined) {
+    state.settings = {
+      icon: state.icon === true ? 'light' : 'dark',
+      theme: 'light'
+    }
+  }
 }

+ 1 - 1
content/index.js

@@ -235,7 +235,7 @@ var frontmatter = (md) => {
 var favicon = () => {
   var favicon = document.createElement('link')
   favicon.rel = 'icon'
-  favicon.href = chrome.runtime.getURL(`/icons/${state.icon ? 'light' : 'dark'}/16x16.png`)
+  favicon.href = chrome.runtime.getURL(`/icons/${state.icon}/16x16.png`)
   $('head').appendChild(favicon)
 }
 

+ 55 - 0
options/index.css

@@ -26,6 +26,42 @@ main {
   min-height: 52px;
 }
 
+.mdc-elevation--z2 {
+  box-shadow:
+    0 3px 1px -2px rgba(0,0,0,.2),
+    0 2px 2px 0 rgba(0,0,0,.14),
+    0 1px 5px 0 rgba(0,0,0,.12);
+}
+
+/*---------------------------------------------------------------------------*/
+/*color modes*/
+
+body.dark {
+  filter: invert(100%) hue-rotate(180deg);
+  background-color: rgb(25, 25, 25);
+}
+body.dark .navbar {
+  filter: invert(90%) hue-rotate(180deg);
+  background-color: transparent;
+}
+body.dark .navbar #menu > div {
+  filter: invert(100%) hue-rotate(180deg);
+}
+
+@media (prefers-color-scheme: dark) {
+  body.auto {
+    filter: invert(100%) hue-rotate(180deg);
+    background-color: rgb(25, 25, 25);
+  }
+  body.auto .navbar {
+    filter: invert(90%) hue-rotate(180deg);
+    background-color: transparent;
+  }
+  body.auto .navbar #menu > div {
+    filter: invert(100%) hue-rotate(180deg);
+  }
+}
+
 /*---------------------------------------------------------------------------*/
 /*sticky footer*/
 
@@ -166,6 +202,25 @@ footer, #footer-push {
   padding-top: 3px;
 }
 
+/*---------------------------------------------------------------------------*/
+/*select*/
+
+.m-select {
+  font-size: 14px;
+  line-height: 17px;
+  color: #000;
+  text-transform: uppercase;
+  background-color: #ececec;
+  border: none;
+  border-radius: 2px;
+  cursor: pointer;
+  padding: 9px 12px;
+}
+
+.bs-callout .m-select {
+  margin: 2px 20px 3px 10px;
+}
+
 /*---------------------------------------------------------------------------*/
 /*misc*/
 

+ 1 - 0
options/index.js

@@ -15,6 +15,7 @@ document.querySelector('#menu span').addEventListener('click', (e) => {
   document.querySelector('#menu div').classList.toggle('hidden')
 })
 document.querySelector('#menu div').addEventListener('click', (e) => {
+  e.preventDefault()
   Array.from(document.querySelectorAll('#menu em')).forEach((link) => {
     link.classList.remove('active')
   })

+ 1 - 1
options/origins.js

@@ -187,7 +187,7 @@ var Origins = () => {
                 type: 'text',
                 value: state.host,
                 onchange: events.host,
-                placeholder: 'Copy URL address and paste it here'
+                placeholder: 'Copy/paste URL address here'
               }),
               m('.mdc-line-ripple')
             ),

+ 56 - 26
options/settings.js

@@ -1,60 +1,90 @@
 
 var Settings = () => {
   var defaults = {
-    icons: false
+    icon: false,
+    theme: 'light',
+    _icons: ['light', 'dark'],
+    _themes: ['light', 'dark', 'auto'],
   }
 
   var state = Object.assign({}, defaults)
 
   chrome.runtime.sendMessage({message: 'options.settings'}, (res) => {
     Object.assign(state, res)
+    document.querySelector('body').classList.add(state.theme)
     m.redraw()
   })
 
   var events = {
-    icon: () => (e) => {
-      state.icon = !state.icon
+    icon: (e) => {
+      state.icon = state._icons[e.target.selectedIndex]
       chrome.runtime.sendMessage({
         message: 'options.icon',
-        icon: state.icon,
+        settings: {
+          icon: state.icon,
+          theme: state.theme,
+        },
       })
+    },
+    theme: (e) => {
+      state.theme = state._themes[e.target.selectedIndex]
+      chrome.runtime.sendMessage({
+        message: 'options.theme',
+        settings: {
+          icon: state.icon,
+          theme: state.theme,
+        },
+      })
+      document.querySelector('body').classList.remove(...state._themes)
+      document.querySelector('body').classList.add(state.theme)
     }
   }
 
-  var oncreate = {
-    ripple: (vnode) => {
-      mdc.ripple.MDCRipple.attachTo(vnode.dom)
-    }
-  }
+  var oncreate = {}
 
-  var onupdate = {
-    icon: () => (vnode) => {
-      if (vnode.dom.classList.contains('is-checked') !== state.icon) {
-        vnode.dom.classList.toggle('is-checked')
-      }
-    }
-  }
+  var onupdate = {}
 
   var render = () =>
     m('.m-settings hidden',
       m('.row',
         m('h3', 'Settings')
       ),
+      // icon
+      m('.bs-callout',
+        m('.row',
+          m('.col-sm-12',
+            m('.overflow',
+              m('label.mdc-switch',
+                m('select.mdc-elevation--z2 m-select', {
+                  onchange: events.icon
+                  },
+                  state._icons.map((icon) =>
+                    m('option', {selected: state.icon === icon}, icon)
+                  )
+                ),
+                m('span.mdc-switch-label',
+                  'Extension Icon and Content Favicon Color'
+                )
+              )
+            )
+          )
+        )
+      ),
+      // theme
       m('.bs-callout',
         m('.row',
           m('.col-sm-12',
             m('.overflow',
-              m('label.mdc-switch m-switch', {
-                onupdate: onupdate.icon(),
-                },
-                m('input.mdc-switch__native-control', {
-                  type: 'checkbox',
-                  checked: state.icon,
-                  onchange: events.icon()
-                }),
-                m('.mdc-switch__background', m('.mdc-switch__knob')),
+              m('label.mdc-switch',
+                m('select.mdc-elevation--z2 m-select', {
+                  onchange: events.theme
+                  },
+                  state._themes.map((theme) =>
+                    m('option', {selected: state.theme === theme}, theme)
+                  )
+                ),
                 m('span.mdc-switch-label',
-                  'Light Extension Icon for Dark Browser Theme'
+                  'Popup and Options Page Color Mode'
                 )
               )
             )

+ 34 - 12
popup/index.css

@@ -1,4 +1,7 @@
 
+/*---------------------------------------------------------------------------*/
+/*global*/
+
 html, body {
   height: auto;
   min-height: auto;
@@ -8,7 +11,6 @@ html, body {
   margin: 0;
 }
 
-/*font family*/
 body,
 body label,
 body input {
@@ -34,8 +36,29 @@ body a.mdc-tab {
 }
 #popup:after { content: ''; display: block; clear: both; }
 
+/*---------------------------------------------------------------------------*/
+/*color modes*/
+
+body.dark {
+  filter: invert(100%) hue-rotate(180deg);
+  background-color: #e4e4e4;
+}
 
+@media (prefers-color-scheme: dark) {
+  body.auto {
+    filter: invert(100%) hue-rotate(180deg);
+    background-color: #e4e4e4;
+  }
+}
+
+/*---------------------------------------------------------------------------*/
 /*button*/
+
+/*defaults button*/
+#popup button:nth-child(2) { float: right; }
+/*advanced options button*/
+#popup button:nth-child(2n+3) { float: right; margin-top: 20px; }
+
 .m-button {
   background-color: #ececec !important;
   color: #000 !important;
@@ -47,8 +70,9 @@ body a.mdc-tab {
   background-color: rgba(96, 125, 139, 0.56) !important;
 }
 
-
+/*---------------------------------------------------------------------------*/
 /*select*/
+
 .m-select {
   font-size: 14px;
   line-height: 17px;
@@ -66,8 +90,9 @@ body a.mdc-tab {
   margin: 20px 0 0 0;
 }
 
-
+/*---------------------------------------------------------------------------*/
 /*switch*/
+
 .m-switch {
   cursor: pointer;
   margin: 7px 0;
@@ -95,14 +120,9 @@ body a.mdc-tab {
 
 #popup .m-switch .mdc-switch-label { width: 276px; }
 
-
-/*defaults button*/
-#popup button:nth-child(2) { float: right; }
-/*advanced options button*/
-#popup button:nth-child(2n+3) { float: right; margin-top: 20px; }
-
-
+/*---------------------------------------------------------------------------*/
 /*tabs*/
+
 .m-tabs {
   border: 0;
   height: 36px;
@@ -128,8 +148,9 @@ body a.mdc-tab {
 .m-panel { display: none; }
 .m-panel.is-active { display: block; }
 
-
+/*---------------------------------------------------------------------------*/
 /*options scroll*/
+
 .scroll {
   margin-top: 10px;
   overflow-y: auto;
@@ -139,8 +160,9 @@ body a.mdc-tab {
   height: 324px;
 }
 
+/*---------------------------------------------------------------------------*/
+/*scrollbar*/
 
-/*custom scrollbars in WebKit*/
 ::-webkit-scrollbar {
   width: 10px;
   height: 10px;

+ 5 - 1
popup/index.js

@@ -63,7 +63,8 @@ var state = {
       mermaid: 'Mermaid diagrams',
       syntax: 'Syntax highlighting for fenced code blocks',
     }
-  }
+  },
+  settings: {}
 }
 
 var events = {
@@ -152,6 +153,9 @@ var init = (res) => {
   state.compilers = res.compilers
   state.description.compiler = res.description
 
+  state.settings = res.settings
+  document.querySelector('body').classList.add(state.settings.theme)
+
   m.redraw()
 }