refactor(themes): use CSS specificity order for themes (#684)
The point of this PR is to make it easier to implement scrollbars (#683). With this PR, the themes move from a body tag-based system (e.g. `body.theme-scarlet`) to a system where they simply declare global CSS and we use CSS specificity order to give us the right theme.
This commit is contained in:
		
							parent
							
								
									f0b3115be1
								
							
						
					
					
						commit
						48a1bd47b3
					
				
					 26 changed files with 120 additions and 141 deletions
				
			
		| 
						 | 
				
			
			@ -34,18 +34,21 @@ function doWatch () {
 | 
			
		|||
  chokidar.watch()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function compileGlobalSass () {
 | 
			
		||||
  let results = await Promise.all([
 | 
			
		||||
    render({ file: defaultThemeScss, outputStyle: 'compressed' }),
 | 
			
		||||
    render({ file: globalScss, outputStyle: 'compressed' }),
 | 
			
		||||
    render({ file: offlineThemeScss, outputStyle: 'compressed' })
 | 
			
		||||
  ])
 | 
			
		||||
async function renderCss (file) {
 | 
			
		||||
  return (await render({ file, outputStyle: 'compressed' })).css
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  let css = results.map(_ => _.css).join('')
 | 
			
		||||
async function compileGlobalSass () {
 | 
			
		||||
  let mainStyle = (await Promise.all([defaultThemeScss, globalScss].map(renderCss))).join('')
 | 
			
		||||
  let offlineStyle = (await renderCss(offlineThemeScss))
 | 
			
		||||
 | 
			
		||||
  let html = await readFile(html2xxFile, 'utf8')
 | 
			
		||||
  html = html.replace(/<style>[\s\S]+?<\/style>/,
 | 
			
		||||
    `<style>\n/* auto-generated w/ build-sass.js */\n${css}\n</style>`)
 | 
			
		||||
  html = html.replace(/<!-- begin inline CSS -->[\s\S]+<!-- end inline CSS -->/,
 | 
			
		||||
    `<!-- begin inline CSS -->\n` +
 | 
			
		||||
    `<style>\n${mainStyle}</style>\n` +
 | 
			
		||||
    `<style media="only x" id="theOfflineStyle">\n${offlineStyle}</style>\n` +
 | 
			
		||||
    `<!-- end inline CSS -->`
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  await writeFile(html2xxFile, html, 'utf8')
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,11 +7,11 @@ if (localStorage.store_currentInstance && localStorage.store_instanceThemes) {
 | 
			
		|||
  let safeParse = (str) => str === 'undefined' ? undefined : JSON.parse(str)
 | 
			
		||||
  let theme = safeParse(localStorage.store_instanceThemes)[safeParse(localStorage.store_currentInstance)]
 | 
			
		||||
  if (theme && theme !== 'default') {
 | 
			
		||||
    document.body.classList.add(`theme-${theme}`)
 | 
			
		||||
    let link = document.createElement('link')
 | 
			
		||||
    link.rel = 'stylesheet'
 | 
			
		||||
    link.href = `/theme-${theme}.css`
 | 
			
		||||
    document.head.appendChild(link)
 | 
			
		||||
    // inserting before the offline <style> ensures that the offline style wins when offline
 | 
			
		||||
    document.head.insertBefore(link, document.getElementById('theOfflineStyle'))
 | 
			
		||||
    if (window.__themeColors[theme]) {
 | 
			
		||||
      document.getElementById('theThemeColor').content = window.__themeColors[theme]
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										71
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										71
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -529,7 +529,7 @@
 | 
			
		|||
    },
 | 
			
		||||
    "async": {
 | 
			
		||||
      "version": "0.2.6",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/async/-/async-0.2.6.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/async/-/async-0.2.6.tgz",
 | 
			
		||||
      "integrity": "sha1-rT83PZJJrjJIgVZVgryQ4VKrvWg=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -629,7 +629,7 @@
 | 
			
		|||
      "dependencies": {
 | 
			
		||||
        "jsesc": {
 | 
			
		||||
          "version": "1.3.0",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
 | 
			
		||||
          "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -815,49 +815,49 @@
 | 
			
		|||
    },
 | 
			
		||||
    "babel-plugin-syntax-async-functions": {
 | 
			
		||||
      "version": "6.13.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
 | 
			
		||||
      "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "babel-plugin-syntax-async-generators": {
 | 
			
		||||
      "version": "6.13.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz",
 | 
			
		||||
      "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "babel-plugin-syntax-class-properties": {
 | 
			
		||||
      "version": "6.13.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
 | 
			
		||||
      "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "babel-plugin-syntax-decorators": {
 | 
			
		||||
      "version": "6.13.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz",
 | 
			
		||||
      "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "babel-plugin-syntax-dynamic-import": {
 | 
			
		||||
      "version": "6.18.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
 | 
			
		||||
      "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "babel-plugin-syntax-exponentiation-operator": {
 | 
			
		||||
      "version": "6.13.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
 | 
			
		||||
      "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "babel-plugin-syntax-flow": {
 | 
			
		||||
      "version": "6.18.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz",
 | 
			
		||||
      "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "babel-plugin-syntax-object-rest-spread": {
 | 
			
		||||
      "version": "6.13.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
 | 
			
		||||
      "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -1555,7 +1555,7 @@
 | 
			
		|||
    },
 | 
			
		||||
    "bowser": {
 | 
			
		||||
      "version": "1.6.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/bowser/-/bowser-1.6.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.6.0.tgz",
 | 
			
		||||
      "integrity": "sha1-N/w4e2Fstq7zcNq01r1AK3TFxU0=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -3041,7 +3041,7 @@
 | 
			
		|||
      "dependencies": {
 | 
			
		||||
        "source-map": {
 | 
			
		||||
          "version": "0.1.43",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
 | 
			
		||||
          "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
 | 
			
		||||
          "dev": true,
 | 
			
		||||
          "requires": {
 | 
			
		||||
| 
						 | 
				
			
			@ -4480,11 +4480,6 @@
 | 
			
		|||
      "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-2hGrlv6efG4hscYVZeaYjpzpT6I2OZgYqE2yDUzeAcKj2D1SH0AsEzqJNXzdoglEddcIXQQYop3lD97XpG75Jw=="
 | 
			
		||||
    },
 | 
			
		||||
    "fg-loadcss": {
 | 
			
		||||
      "version": "2.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fg-loadcss/-/fg-loadcss-2.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-gFtSJjMMt9it0OhXz4wJQT46/LFUrJ2Db6U/fLtwClBEMEEjmVPSWSYrbGCyFwy47Cd4ULOpR+HSWXVkUKciaQ=="
 | 
			
		||||
    },
 | 
			
		||||
    "figgy-pudding": {
 | 
			
		||||
      "version": "3.5.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -5039,7 +5034,7 @@
 | 
			
		|||
      "dependencies": {
 | 
			
		||||
        "babel-plugin-transform-runtime": {
 | 
			
		||||
          "version": "6.15.0",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.15.0.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.15.0.tgz",
 | 
			
		||||
          "integrity": "sha1-PXW02Umtga8VdXAnOEb7Wa6w1Xw=",
 | 
			
		||||
          "dev": true,
 | 
			
		||||
          "requires": {
 | 
			
		||||
| 
						 | 
				
			
			@ -7437,7 +7432,7 @@
 | 
			
		|||
        },
 | 
			
		||||
        "kind-of": {
 | 
			
		||||
          "version": "1.1.0",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
 | 
			
		||||
          "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -9941,7 +9936,7 @@
 | 
			
		|||
          "dependencies": {
 | 
			
		||||
            "globby": {
 | 
			
		||||
              "version": "6.1.0",
 | 
			
		||||
              "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
 | 
			
		||||
              "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
 | 
			
		||||
              "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
 | 
			
		||||
              "dev": true,
 | 
			
		||||
              "requires": {
 | 
			
		||||
| 
						 | 
				
			
			@ -9954,7 +9949,7 @@
 | 
			
		|||
              "dependencies": {
 | 
			
		||||
                "pify": {
 | 
			
		||||
                  "version": "2.3.0",
 | 
			
		||||
                  "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
                  "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
                  "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
 | 
			
		||||
                  "dev": true
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -9970,7 +9965,7 @@
 | 
			
		|||
        },
 | 
			
		||||
        "globby": {
 | 
			
		||||
          "version": "3.0.1",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/globby/-/globby-3.0.1.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/globby/-/globby-3.0.1.tgz",
 | 
			
		||||
          "integrity": "sha1-IJSvhCHhkVIVDViT62QWsxLZoi8=",
 | 
			
		||||
          "dev": true,
 | 
			
		||||
          "requires": {
 | 
			
		||||
| 
						 | 
				
			
			@ -10046,7 +10041,7 @@
 | 
			
		|||
        },
 | 
			
		||||
        "minimist": {
 | 
			
		||||
          "version": "1.2.0",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
 | 
			
		||||
          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			@ -10058,7 +10053,7 @@
 | 
			
		|||
        },
 | 
			
		||||
        "pify": {
 | 
			
		||||
          "version": "2.3.0",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			@ -10109,7 +10104,7 @@
 | 
			
		|||
      "dependencies": {
 | 
			
		||||
        "babel-runtime": {
 | 
			
		||||
          "version": "5.8.38",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz",
 | 
			
		||||
          "integrity": "sha1-HAsC62MxL18If/IEUIJ7QlydTBk=",
 | 
			
		||||
          "dev": true,
 | 
			
		||||
          "requires": {
 | 
			
		||||
| 
						 | 
				
			
			@ -10118,13 +10113,13 @@
 | 
			
		|||
        },
 | 
			
		||||
        "core-js": {
 | 
			
		||||
          "version": "1.2.7",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
 | 
			
		||||
          "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        },
 | 
			
		||||
        "pify": {
 | 
			
		||||
          "version": "2.3.0",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -10175,7 +10170,7 @@
 | 
			
		|||
        },
 | 
			
		||||
        "lru-cache": {
 | 
			
		||||
          "version": "2.6.3",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.6.3.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.3.tgz",
 | 
			
		||||
          "integrity": "sha1-UczQtPwMhDWH16VwnOTTt2Kb7cU=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			@ -10193,7 +10188,7 @@
 | 
			
		|||
        },
 | 
			
		||||
        "pify": {
 | 
			
		||||
          "version": "2.3.0",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			@ -10242,7 +10237,7 @@
 | 
			
		|||
      "dependencies": {
 | 
			
		||||
        "babel-runtime": {
 | 
			
		||||
          "version": "5.8.38",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz",
 | 
			
		||||
          "integrity": "sha1-HAsC62MxL18If/IEUIJ7QlydTBk=",
 | 
			
		||||
          "dev": true,
 | 
			
		||||
          "requires": {
 | 
			
		||||
| 
						 | 
				
			
			@ -10251,7 +10246,7 @@
 | 
			
		|||
        },
 | 
			
		||||
        "core-js": {
 | 
			
		||||
          "version": "1.2.7",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
 | 
			
		||||
          "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			@ -10269,7 +10264,7 @@
 | 
			
		|||
        },
 | 
			
		||||
        "pify": {
 | 
			
		||||
          "version": "2.3.0",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			@ -10286,31 +10281,31 @@
 | 
			
		|||
    },
 | 
			
		||||
    "testcafe-reporter-json": {
 | 
			
		||||
      "version": "2.1.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/testcafe-reporter-json/-/testcafe-reporter-json-2.1.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/testcafe-reporter-json/-/testcafe-reporter-json-2.1.0.tgz",
 | 
			
		||||
      "integrity": "sha1-gLm1pt/y7h3h+R4mcHBsFHLmQAY=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "testcafe-reporter-list": {
 | 
			
		||||
      "version": "2.1.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/testcafe-reporter-list/-/testcafe-reporter-list-2.1.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/testcafe-reporter-list/-/testcafe-reporter-list-2.1.0.tgz",
 | 
			
		||||
      "integrity": "sha1-n6ifcbl9Pf5ktDAtXiJ97mmuxrk=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "testcafe-reporter-minimal": {
 | 
			
		||||
      "version": "2.1.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/testcafe-reporter-minimal/-/testcafe-reporter-minimal-2.1.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/testcafe-reporter-minimal/-/testcafe-reporter-minimal-2.1.0.tgz",
 | 
			
		||||
      "integrity": "sha1-Z28DVHY0FDxurzq1KGgnOkvr9CE=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "testcafe-reporter-spec": {
 | 
			
		||||
      "version": "2.1.1",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/testcafe-reporter-spec/-/testcafe-reporter-spec-2.1.1.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/testcafe-reporter-spec/-/testcafe-reporter-spec-2.1.1.tgz",
 | 
			
		||||
      "integrity": "sha1-gVb87Q9RMkhlWa1WC8gGdkaSdew=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "testcafe-reporter-xunit": {
 | 
			
		||||
      "version": "2.1.0",
 | 
			
		||||
      "resolved": "http://registry.npmjs.org/testcafe-reporter-xunit/-/testcafe-reporter-xunit-2.1.0.tgz",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/testcafe-reporter-xunit/-/testcafe-reporter-xunit-2.1.0.tgz",
 | 
			
		||||
      "integrity": "sha1-5tZsVyzhWvJmcGrw/WELKoQd1EM=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -11054,7 +11049,7 @@
 | 
			
		|||
      "dependencies": {
 | 
			
		||||
        "pify": {
 | 
			
		||||
          "version": "2.3.0",
 | 
			
		||||
          "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
 | 
			
		||||
          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,7 +64,6 @@
 | 
			
		|||
    "esm": "^3.0.84",
 | 
			
		||||
    "events": "^3.0.0",
 | 
			
		||||
    "express": "^4.16.4",
 | 
			
		||||
    "fg-loadcss": "^2.0.1",
 | 
			
		||||
    "file-api": "^0.10.4",
 | 
			
		||||
    "font-awesome-svg-png": "^1.2.2",
 | 
			
		||||
    "form-data": "^2.3.3",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,8 @@ const NOTIFY_OFFLINE_LIMIT = 1
 | 
			
		|||
 | 
			
		||||
let notifyCount = 0
 | 
			
		||||
 | 
			
		||||
let offlineStyle = process.browser && document.getElementById('theOfflineStyle')
 | 
			
		||||
 | 
			
		||||
// debounce to avoid notifying for a short connection issue
 | 
			
		||||
const notifyOffline = debounce(() => {
 | 
			
		||||
  if (process.browser && !navigator.onLine && ++notifyCount <= NOTIFY_OFFLINE_LIMIT) {
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +23,8 @@ export function onlineObservers (store) {
 | 
			
		|||
  let oldTheme = meta.content
 | 
			
		||||
 | 
			
		||||
  store.observe('online', online => {
 | 
			
		||||
    document.body.classList.toggle('offline', !online)
 | 
			
		||||
    // "only x" ensures the <style> tag does not have any effect
 | 
			
		||||
    offlineStyle.setAttribute('media', online ? 'only x' : 'all')
 | 
			
		||||
    if (online) {
 | 
			
		||||
      meta.content = oldTheme
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,41 @@
 | 
			
		|||
import { loadCSS } from 'fg-loadcss'
 | 
			
		||||
 | 
			
		||||
let meta = process.browser && document.getElementById('theThemeColor')
 | 
			
		||||
let offlineStyle = process.browser && document.getElementById('theOfflineStyle')
 | 
			
		||||
 | 
			
		||||
function getExistingThemeLink () {
 | 
			
		||||
  return document.head.querySelector('link[rel=stylesheet][href^="/theme-"]')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function resetExistingTheme () {
 | 
			
		||||
  let existingLink = getExistingThemeLink()
 | 
			
		||||
  if (existingLink) {
 | 
			
		||||
    document.head.removeChild(existingLink)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function loadCSS (href) {
 | 
			
		||||
  let existingLink = getExistingThemeLink()
 | 
			
		||||
 | 
			
		||||
  let link = document.createElement('link')
 | 
			
		||||
  link.rel = 'stylesheet'
 | 
			
		||||
  link.href = href
 | 
			
		||||
 | 
			
		||||
  link.addEventListener('load', function onload () {
 | 
			
		||||
    link.removeEventListener('load', onload)
 | 
			
		||||
    if (existingLink) { // remove after load to avoid flash of default theme
 | 
			
		||||
      document.head.removeChild(existingLink)
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // inserting before the offline <style> ensures that the offline style wins when offline
 | 
			
		||||
  document.head.insertBefore(link, offlineStyle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function switchToTheme (themeName) {
 | 
			
		||||
  let clazzList = document.body.classList
 | 
			
		||||
  for (let i = 0; i < clazzList.length; i++) {
 | 
			
		||||
    let clazz = clazzList.item(i)
 | 
			
		||||
    if (clazz.startsWith('theme-')) {
 | 
			
		||||
      clazzList.remove(clazz)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  let themeColor = window.__themeColors[themeName]
 | 
			
		||||
  meta.content = themeColor || window.__themeColors['default']
 | 
			
		||||
  if (themeName !== 'default') {
 | 
			
		||||
    clazzList.add(`theme-${themeName}`)
 | 
			
		||||
    loadCSS(`/theme-${themeName}.css`)
 | 
			
		||||
  } else {
 | 
			
		||||
    resetExistingTheme()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
@mixin baseTheme() {
 | 
			
		||||
 | 
			
		||||
:root {
 | 
			
		||||
  $deemphasized-color: #666;
 | 
			
		||||
 | 
			
		||||
  --button-primary-bg: #{lighten($main-theme-color, 7%)};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
@mixin darkTheme() {
 | 
			
		||||
:root {
 | 
			
		||||
  $deemphasized-color: lighten($main-bg-color, 45%);
 | 
			
		||||
 | 
			
		||||
  --action-button-deemphasized-fill-color: #{$deemphasized-color};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,8 +10,4 @@ $toast-bg: #333;
 | 
			
		|||
$focus-outline: lighten($main-theme-color, 30%);
 | 
			
		||||
$compose-background: lighten($main-theme-color, 32%);
 | 
			
		||||
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
}
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,3 @@ $focus-outline: lighten($main-theme-color, 15%);
 | 
			
		|||
$compose-background: lighten($main-theme-color, 17%);
 | 
			
		||||
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
 | 
			
		||||
body.the-body.offline { /* "the-body" is a specificity hack to allow offline to always trump themes */
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,10 +13,7 @@ $compose-background: lighten($main-theme-color, 32%);
 | 
			
		|||
@import "_base.scss";
 | 
			
		||||
@import "_dark.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-cobalt {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
  @include darkTheme();
 | 
			
		||||
 | 
			
		||||
:root {
 | 
			
		||||
  --settings-list-item-text: #{$main-text-color};
 | 
			
		||||
  --settings-list-item-text-hover: #{$main-text-color};
 | 
			
		||||
  
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,3 @@ $focus-outline: lighten($main-theme-color, 30%);
 | 
			
		|||
$compose-background: lighten($main-theme-color, 32%);
 | 
			
		||||
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-gecko {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,10 +14,7 @@ $compose-background: lighten($main-theme-color, 52%);
 | 
			
		|||
@import "_base.scss";
 | 
			
		||||
@import "_dark.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-hacker {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
  @include darkTheme();
 | 
			
		||||
 | 
			
		||||
:root {
 | 
			
		||||
  --nav-bg: #{lighten($body-bg-color, 10%)};
 | 
			
		||||
  --nav-a-selected-bg: #{lighten($body-bg-color, 25%)};
 | 
			
		||||
  --nav-a-bg-hover: #{lighten($body-bg-color, 25%)};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,3 @@ $focus-outline: lighten($main-theme-color, 15%);
 | 
			
		|||
$compose-background: lighten($main-theme-color, 17%);
 | 
			
		||||
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-hotpants {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,3 @@ $focus-outline: lighten($main-theme-color, 30%);
 | 
			
		|||
$compose-background: lighten($main-theme-color, 32%);
 | 
			
		||||
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-majesty {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,3 @@ $focus-outline: lighten($main-theme-color, 30%);
 | 
			
		|||
$compose-background: lighten($main-theme-color, 32%);
 | 
			
		||||
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-oaken {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,9 +11,4 @@ $focus-outline: darken($main-theme-color, 10%);
 | 
			
		|||
$compose-background: darken($main-theme-color, 12%);
 | 
			
		||||
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
@import "_dark.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-ozark {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
  @include darkTheme();
 | 
			
		||||
}
 | 
			
		||||
@import "_dark.scss";
 | 
			
		||||
| 
						 | 
				
			
			@ -14,10 +14,7 @@ $compose-background: lighten($main-theme-color, 52%);
 | 
			
		|||
@import "_base.scss";
 | 
			
		||||
@import "_dark.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-punk {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
  @include darkTheme();
 | 
			
		||||
 | 
			
		||||
:root {
 | 
			
		||||
  --nav-bg: #{lighten($body-bg-color, 10%)};
 | 
			
		||||
  --nav-a-selected-bg: #{lighten($body-bg-color, 25%)};
 | 
			
		||||
  --nav-a-bg-hover: #{lighten($body-bg-color, 25%)};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,10 +14,7 @@ $compose-background: lighten($main-theme-color, 52%);
 | 
			
		|||
@import "_base.scss";
 | 
			
		||||
@import "_dark.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-riot {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
  @include darkTheme();
 | 
			
		||||
 | 
			
		||||
:root {
 | 
			
		||||
  --nav-bg: #{lighten($body-bg-color, 10%)};
 | 
			
		||||
  --nav-a-selected-bg: #{lighten($body-bg-color, 25%)};
 | 
			
		||||
  --nav-a-bg-hover: #{lighten($body-bg-color, 25%)};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,3 @@ $focus-outline: lighten($main-theme-color, 30%);
 | 
			
		|||
$compose-background: lighten($main-theme-color, 32%);
 | 
			
		||||
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-scarlet {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,3 @@ $focus-outline: lighten($main-theme-color, 50%);
 | 
			
		|||
$compose-background: lighten($main-theme-color, 52%);
 | 
			
		||||
 | 
			
		||||
@import "_base.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-seafoam {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,10 +14,7 @@ $compose-background: lighten($main-theme-color, 52%);
 | 
			
		|||
@import "_base.scss";
 | 
			
		||||
@import "_dark.scss";
 | 
			
		||||
 | 
			
		||||
body.theme-sorcery {
 | 
			
		||||
  @include baseTheme();
 | 
			
		||||
  @include darkTheme();
 | 
			
		||||
 | 
			
		||||
:root {
 | 
			
		||||
  --nav-bg: #{lighten($body-bg-color, 10%)};
 | 
			
		||||
  --nav-a-selected-bg: #{lighten($body-bg-color, 25%)};
 | 
			
		||||
  --nav-a-bg-hover: #{lighten($body-bg-color, 25%)};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,13 +14,15 @@
 | 
			
		|||
  <meta name="apple-mobile-web-app-title" content="Pinafore" >
 | 
			
		||||
  <meta name="apple-mobile-web-app-status-bar-style" content="white" >
 | 
			
		||||
 | 
			
		||||
  <style>
 | 
			
		||||
/* auto-generated w/ build-sass.js */
 | 
			
		||||
body{--button-primary-bg: #6081e6;--button-primary-text: #fff;--button-primary-border: #132c76;--button-primary-bg-active: #456ce2;--button-primary-bg-hover: #6988e7;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #4169e1;--main-bg: #fff;--body-bg: #e8edfb;--body-text-color: #333;--main-border: #dadada;--svg-fill: #4169e1;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #4169e1;--nav-border: #214cce;--nav-a-border: #4169e1;--nav-a-selected-border: #fff;--nav-a-selected-bg: #6d8ce8;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #839deb;--nav-a-bg-hover: #577ae4;--nav-a-border-hover: #4169e1;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #90a8ee;--action-button-fill-color-hover: #a2b6f0;--action-button-fill-color-active: #577ae4;--action-button-fill-color-pressed: #2351dc;--action-button-fill-color-pressed-hover: #3862e0;--action-button-fill-color-pressed-active: #1d44b8;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #4169e1;--settings-list-item-text-hover: #4169e1;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #c5d1f6;--very-deemphasized-link-color: rgba(65,105,225,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #d2dcf8;--main-theme-color: #4169e1;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #ced8f7;--compose-autosuggest-item-active: #b8c7f4;--compose-autosuggest-outline: #dbe3f9;--compose-button-halo: rgba(255,255,255,0.1)}
 | 
			
		||||
  <!-- begin inline CSS -->
 | 
			
		||||
<style>
 | 
			
		||||
:root{--button-primary-bg: #6081e6;--button-primary-text: #fff;--button-primary-border: #132c76;--button-primary-bg-active: #456ce2;--button-primary-bg-hover: #6988e7;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #4169e1;--main-bg: #fff;--body-bg: #e8edfb;--body-text-color: #333;--main-border: #dadada;--svg-fill: #4169e1;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #4169e1;--nav-border: #214cce;--nav-a-border: #4169e1;--nav-a-selected-border: #fff;--nav-a-selected-bg: #6d8ce8;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #839deb;--nav-a-bg-hover: #577ae4;--nav-a-border-hover: #4169e1;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #90a8ee;--action-button-fill-color-hover: #a2b6f0;--action-button-fill-color-active: #577ae4;--action-button-fill-color-pressed: #2351dc;--action-button-fill-color-pressed-hover: #3862e0;--action-button-fill-color-pressed-active: #1d44b8;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #4169e1;--settings-list-item-text-hover: #4169e1;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #c5d1f6;--very-deemphasized-link-color: rgba(65,105,225,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #d2dcf8;--main-theme-color: #4169e1;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #ced8f7;--compose-autosuggest-item-active: #b8c7f4;--compose-autosuggest-outline: #dbe3f9;--compose-button-halo: rgba(255,255,255,0.1)}
 | 
			
		||||
@font-face{font-family:PinaforeRegular;src:local("BlinkMacSystemFont"),local("Segoe UI"),local("Roboto"),local("Oxygen-Sans"),local("Ubuntu"),local("Cantarell"),local("Fira Sans"),local("Droid Sans"),local("Helvetica Neue")}@font-face{font-family:PinaforeEmoji;src:local("Apple Color Emoji"),local("Segoe UI Emoji"),local("Segoe UI Symbol"),local("Twemoji Mozilla"),local("Noto Color Emoji"),local("EmojiOne Color"),local("Android Emoji")}body{margin:0;font-family:system-ui, -apple-system, PinaforeRegular, sans-serif;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);-webkit-tap-highlight-color:transparent;overflow-x:hidden}.main-content{contain:content;padding-top:42px}@media (max-width: 991px){.main-content{padding-top:52px}}@media (max-width: 767px){.main-content{padding-top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px;min-height:70vh}@media (max-width: 767px){main{margin:5px auto 15px}}footer{width:602px;max-width:100vw;box-sizing:border-box;margin:15px auto;border-radius:1px;background:var(--main-bg);font-size:0.9em;padding:20px;border:1px solid var(--main-border)}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}input[type=search]{-webkit-appearance:none}input,textarea{background:inherit;color:inherit}textarea{font-family:system-ui, -apple-system, PinaforeRegular, sans-serif, PinaforeEmoji}button,.button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover,.button:hover{background:var(--button-bg-hover);text-decoration:none}button:active,.button:active{background:var(--button-bg-active)}button[disabled],.button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary,.button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover,.button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active,.button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}.container:focus{outline:none}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}textarea{font-family:inherit;font-size:inherit;box-sizing:border-box}@keyframes spin{0%{transform:rotate(0deg)}25%{transform:rotate(90deg)}50%{transform:rotate(180deg)}75%{transform:rotate(270deg)}100%{transform:rotate(360deg)}}.spin{animation:spin 1.5s infinite linear}.ellipsis::after{content:"\2026"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.inline-custom-emoji{width:1.4em;height:1.4em;margin:-0.1em 0;object-fit:contain;vertical-align:middle}.inline-emoji{font-family:PinaforeEmoji, sans-serif}
 | 
			
		||||
body.the-body.offline{--button-primary-bg: #ababab;--button-primary-text: #fff;--button-primary-border: #4d4d4d;--button-primary-bg-active: #9c9c9c;--button-primary-bg-hover: #b0b0b0;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #999;--main-bg: #fff;--body-bg: #fafafa;--body-text-color: #333;--main-border: #dadada;--svg-fill: #999;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #999;--nav-border: gray;--nav-a-border: #999;--nav-a-selected-border: #fff;--nav-a-selected-bg: #b3b3b3;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #bfbfbf;--nav-a-bg-hover: #a6a6a6;--nav-a-border-hover: #999;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #c7c7c7;--action-button-fill-color-hover: #d1d1d1;--action-button-fill-color-active: #a6a6a6;--action-button-fill-color-pressed: #878787;--action-button-fill-color-pressed-hover: #949494;--action-button-fill-color-pressed-active: #737373;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #999;--settings-list-item-text-hover: #999;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #bfbfbf;--very-deemphasized-link-color: rgba(153,153,153,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #ededed;--main-theme-color: #999;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #c4c4c4;--compose-autosuggest-item-active: #b8b8b8;--compose-autosuggest-outline: #ccc;--compose-button-halo: rgba(255,255,255,0.1)}
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
<style media="only x" id="theOfflineStyle">
 | 
			
		||||
:root{--button-primary-bg: #ababab;--button-primary-text: #fff;--button-primary-border: #4d4d4d;--button-primary-bg-active: #9c9c9c;--button-primary-bg-hover: #b0b0b0;--button-bg: #e6e6e6;--button-text: #333;--button-border: #a7a7a7;--button-bg-active: #bfbfbf;--button-bg-hover: #f2f2f2;--input-border: #dadada;--anchor-text: #999;--main-bg: #fff;--body-bg: #fafafa;--body-text-color: #333;--main-border: #dadada;--svg-fill: #999;--form-bg: #f7f7f7;--form-border: #c1c1c1;--nav-bg: #999;--nav-border: gray;--nav-a-border: #999;--nav-a-selected-border: #fff;--nav-a-selected-bg: #b3b3b3;--nav-svg-fill: #fff;--nav-text-color: #fff;--nav-a-selected-border-hover: #fff;--nav-a-selected-bg-hover: #bfbfbf;--nav-a-bg-hover: #a6a6a6;--nav-a-border-hover: #999;--nav-svg-fill-hover: #fff;--nav-text-color-hover: #fff;--action-button-fill-color: #c7c7c7;--action-button-fill-color-hover: #d1d1d1;--action-button-fill-color-active: #a6a6a6;--action-button-fill-color-pressed: #878787;--action-button-fill-color-pressed-hover: #949494;--action-button-fill-color-pressed-active: #737373;--action-button-deemphasized-fill-color: #666;--action-button-deemphasized-fill-color-hover: #9e9e9e;--action-button-deemphasized-fill-color-active: #737373;--action-button-deemphasized-fill-color-pressed: #545454;--action-button-deemphasized-fill-color-pressed-hover: #616161;--action-button-deemphasized-fill-color-pressed-active: #404040;--settings-list-item-bg: #fff;--settings-list-item-text: #999;--settings-list-item-text-hover: #999;--settings-list-item-border: #dadada;--settings-list-item-bg-active: #e6e6e6;--settings-list-item-bg-hover: #fafafa;--toast-bg: #333;--toast-border: #fafafa;--toast-text: #fff;--mask-bg: #333;--mask-svg-fill: #fff;--mask-opaque-bg: rgba(51,51,51,0.8);--loading-bg: #ededed;--account-profile-bg-backdrop-filter: rgba(255,255,255,0.7);--account-profile-bg: rgba(255,255,255,0.9);--deemphasized-text-color: #666;--focus-outline: #bfbfbf;--very-deemphasized-link-color: rgba(153,153,153,0.6);--very-deemphasized-text-color: rgba(102,102,102,0.6);--status-direct-background: #ededed;--main-theme-color: #999;--warning-color: #e01f19;--alt-input-bg: rgba(255,255,255,0.7);--muted-modal-bg: transparent;--muted-modal-focus: #999;--muted-modal-hover: rgba(255,255,255,0.2);--compose-autosuggest-item-hover: #c4c4c4;--compose-autosuggest-item-active: #b8b8b8;--compose-autosuggest-outline: #ccc;--compose-button-halo: rgba(255,255,255,0.1)}
 | 
			
		||||
</style>
 | 
			
		||||
<!-- end inline CSS -->
 | 
			
		||||
 | 
			
		||||
  <noscript>
 | 
			
		||||
    <style>
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +41,7 @@ body.the-body.offline{--button-primary-bg: #ababab;--button-primary-text: #fff;-
 | 
			
		|||
       the current page has one -->
 | 
			
		||||
  %sapper.head%
 | 
			
		||||
</head>
 | 
			
		||||
<body class="the-body">
 | 
			
		||||
<body>
 | 
			
		||||
  <!-- auto-generated w/ build-inline-script.js -->
 | 
			
		||||
  <!-- insert inline script here --><script>(function () {'use strict'
 | 
			
		||||
// For perf reasons, this script is run inline to quickly set certain styles.
 | 
			
		||||
| 
						 | 
				
			
			@ -51,11 +53,11 @@ if (localStorage.store_currentInstance && localStorage.store_instanceThemes) {
 | 
			
		|||
  let safeParse = (str) => str === 'undefined' ? undefined : JSON.parse(str)
 | 
			
		||||
  let theme = safeParse(localStorage.store_instanceThemes)[safeParse(localStorage.store_currentInstance)]
 | 
			
		||||
  if (theme && theme !== 'default') {
 | 
			
		||||
    document.body.classList.add(`theme-${theme}`)
 | 
			
		||||
    let link = document.createElement('link')
 | 
			
		||||
    link.rel = 'stylesheet'
 | 
			
		||||
    link.href = `/theme-${theme}.css`
 | 
			
		||||
    document.head.appendChild(link)
 | 
			
		||||
    // inserting before the offline <style> ensures that the offline style wins when offline
 | 
			
		||||
    document.head.insertBefore(link, document.getElementById('theOfflineStyle'))
 | 
			
		||||
    if (window.__themeColors[theme]) {
 | 
			
		||||
      document.getElementById('theThemeColor').content = window.__themeColors[theme]
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import {
 | 
			
		||||
  getNthStatus, scrollToStatus, closeDialogButton, modalDialogContents, getActiveElementClass, goBack, getUrl,
 | 
			
		||||
  goBackButton, getActiveElementInnerText, getNthReplyButton, getActiveElementInsideNthStatus, focus,
 | 
			
		||||
  getNthStatusSelector
 | 
			
		||||
  getNthStatusSelector, getActiveElementTagName
 | 
			
		||||
} from '../utils'
 | 
			
		||||
import { loginAsFoobar } from '../roles'
 | 
			
		||||
import { Selector as $ } from 'testcafe'
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +103,6 @@ test('reply preserves focus and moves focus to the text input', async t => {
 | 
			
		|||
    .expect(getActiveElementClass()).contains('compose-box-input')
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test('focus .main-content div on index page load', async t => {
 | 
			
		||||
  await t.expect(getActiveElementClass()).contains('the-body')
 | 
			
		||||
test('focus main content element on index page load', async t => {
 | 
			
		||||
  await t.expect(getActiveElementTagName()).match(/body/i)
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import {
 | 
			
		||||
  getBodyClassList,
 | 
			
		||||
  getCurrentTheme,
 | 
			
		||||
  settingsNavButton
 | 
			
		||||
} from '../utils'
 | 
			
		||||
import { loginAsFoobar } from '../roles'
 | 
			
		||||
| 
						 | 
				
			
			@ -14,9 +14,9 @@ test('can set a theme', async t => {
 | 
			
		|||
    .click(settingsNavButton)
 | 
			
		||||
    .click($('a[href="/settings/instances"]'))
 | 
			
		||||
    .click($('a[href="/settings/instances/localhost:3000"]'))
 | 
			
		||||
    .expect(getBodyClassList()).eql([])
 | 
			
		||||
    .expect(getCurrentTheme()).eql('default')
 | 
			
		||||
    .click($('input[value="scarlet"]'))
 | 
			
		||||
    .expect(getBodyClassList()).eql(['theme-scarlet'])
 | 
			
		||||
    .expect(getCurrentTheme()).eql('scarlet')
 | 
			
		||||
    .click($('input[value="default"]'))
 | 
			
		||||
    .expect(getBodyClassList()).eql([])
 | 
			
		||||
    .expect(getCurrentTheme()).eql('default')
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,6 +60,10 @@ export const getActiveElementClass = exec(() =>
 | 
			
		|||
  (document.activeElement && document.activeElement.getAttribute('class')) || ''
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export const getActiveElementTagName = exec(() =>
 | 
			
		||||
  (document.activeElement && document.activeElement.tagName) || ''
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export const getActiveElementInnerText = exec(() =>
 | 
			
		||||
  (document.activeElement && document.activeElement.innerText) || ''
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -87,9 +91,13 @@ export const getComposeSelectionStart = exec(() => composeInput().selectionStart
 | 
			
		|||
  dependencies: { composeInput }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export const getBodyClassList = exec(() => (
 | 
			
		||||
  Array.prototype.slice.apply(document.body.classList).filter(_ => _ !== 'the-body'))
 | 
			
		||||
)
 | 
			
		||||
export const getCurrentTheme = exec(() => {
 | 
			
		||||
  let themeLink = document.head.querySelector('link[rel=stylesheet][href^="/theme-"]')
 | 
			
		||||
  if (themeLink) {
 | 
			
		||||
    return themeLink.getAttribute('href').match(/^\/theme-(.*)\.css$/, '')[1]
 | 
			
		||||
  }
 | 
			
		||||
  return 'default'
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export const uploadKittenImage = i => (exec(() => {
 | 
			
		||||
  let image = images[`kitten${i}`]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue