forked from cybrespace/pinafore
finish theme engine
This commit is contained in:
parent
f69797544d
commit
1f9029f457
|
@ -10,6 +10,7 @@ const pify = require('pify')
|
|||
const writeFile = pify(fs.writeFile.bind(fs))
|
||||
const readdir = pify(fs.readdir.bind(fs))
|
||||
const render = pify(sass.render.bind(sass))
|
||||
const now = require('performance-now')
|
||||
|
||||
const globalScss = path.join(__dirname, '../scss/global.scss')
|
||||
const defaultThemeScss = path.join(__dirname, '../scss/themes/_default.scss')
|
||||
|
@ -19,9 +20,15 @@ const themesScssDir = path.join(__dirname, '../scss/themes')
|
|||
const assetsDir = path.join(__dirname, '../assets')
|
||||
|
||||
function doWatch() {
|
||||
var start = now()
|
||||
chokidar.watch(scssDir).on('change', debounce(() => {
|
||||
compileGlobalSass()
|
||||
compileThemesSass()
|
||||
console.log('Recompiling SCSS...')
|
||||
Promise.all([
|
||||
compileGlobalSass(),
|
||||
compileThemesSass()
|
||||
]).then(() => {
|
||||
console.log('Recompiled SCSS in ' + (now() - start) + 'ms')
|
||||
})
|
||||
}, 500))
|
||||
chokidar.watch()
|
||||
}
|
||||
|
@ -41,7 +48,8 @@ async function compileThemesSass() {
|
|||
let files = (await readdir(themesScssDir)).filter(file => !path.basename(file).startsWith('_'))
|
||||
await Promise.all(files.map(async file => {
|
||||
let res = await render({file: path.join(themesScssDir, file)})
|
||||
await writeFile(path.join(assetsDir, path.basename(file).replace(/\.scss$/, '.css')), res.css, 'utf8')
|
||||
let outputFilename = 'theme-' + path.basename(file).replace(/\.scss$/, '.css')
|
||||
await writeFile(path.join(assetsDir, outputFilename), res.css, 'utf8')
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -1803,6 +1803,11 @@
|
|||
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",
|
||||
"integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg="
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"filename-regex": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
|
||||
|
@ -4806,6 +4811,11 @@
|
|||
"sha.js": "2.4.9"
|
||||
}
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"css-loader": "^0.28.7",
|
||||
"express": "^4.16.2",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"fg-loadcss": "^2.0.1",
|
||||
"font-awesome-svg-png": "^1.2.2",
|
||||
"glob": "^7.1.2",
|
||||
"idb": "^2.0.4",
|
||||
|
@ -27,6 +28,7 @@
|
|||
"node-fetch": "^1.7.3",
|
||||
"node-sass": "^4.7.2",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"performance-now": "^2.1.0",
|
||||
"pify": "^3.0.0",
|
||||
"sapper": "^0.3.1",
|
||||
"serve-static": "^1.13.1",
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { loadCSS } from 'fg-loadcss';
|
||||
|
||||
export function switchToTheme(themeName) {
|
||||
let CL = document.body.classList
|
||||
for (let i = 0; i < CL.length; i++) {
|
||||
let clazz = CL.item(i)
|
||||
if (clazz.startsWith('theme-')) {
|
||||
CL.remove(clazz)
|
||||
}
|
||||
}
|
||||
if (themeName !== 'default') {
|
||||
CL.add(`theme-${themeName}`)
|
||||
loadCSS(`/theme-${themeName}.css`)
|
||||
}
|
||||
}
|
|
@ -7,23 +7,30 @@
|
|||
<h1>{{params.instanceName}}</h1>
|
||||
|
||||
{{#if currentUser}}
|
||||
<h2>Logged in as:</h2>
|
||||
<div class="current-user">
|
||||
<img src="{{currentUser.avatar}}" />
|
||||
<a rel="noopener" target="_blank" href="{{currentUser.url}}">@{{currentUser.acct}}</a>
|
||||
<span class="acct-name">{{currentUser.display_name}}</span>
|
||||
</div>
|
||||
<h2>Theme:</h2>
|
||||
<form class="theme-chooser">
|
||||
{{#each themes as theme}}
|
||||
<div class="theme-group">
|
||||
<input type="radio" id="choice-theme-{{theme.name}}"
|
||||
value="{{theme.name}}" checked="$currentTheme === theme.name"
|
||||
bind:group="selectedTheme" on:change="onThemeChange()">
|
||||
<label for="choice-theme-{{theme.name}}">{{theme.label}}</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
</form>
|
||||
<h2>Logged in as:</h2>
|
||||
<div class="current-user">
|
||||
<img src="{{currentUser.avatar}}" />
|
||||
<a rel="noopener" target="_blank" href="{{currentUser.url}}">@{{currentUser.acct}}</a>
|
||||
<span class="acct-name">{{currentUser.display_name}}</span>
|
||||
</div>
|
||||
<h2>Theme:</h2>
|
||||
<form class="theme-chooser">
|
||||
{{#each themes as theme}}
|
||||
<div class="theme-group">
|
||||
<input type="radio" id="choice-theme-{{theme.name}}"
|
||||
value="{{theme.name}}" checked="$currentTheme === theme.name"
|
||||
bind:group="selectedTheme" on:change="onThemeChange()">
|
||||
<label for="choice-theme-{{theme.name}}">{{theme.label}}</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
</form>
|
||||
|
||||
<form class="instance-actions">
|
||||
<button class="primary" disabled="$currentInstance === params.instanceName">
|
||||
Switch to this instance
|
||||
</button>
|
||||
<button>Log out</button>
|
||||
</form>
|
||||
{{/if}}
|
||||
</SettingsLayout>
|
||||
</Layout>
|
||||
|
@ -54,6 +61,15 @@
|
|||
.theme-chooser label {
|
||||
margin: 2px 10px 0;
|
||||
}
|
||||
.instance-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
}
|
||||
.instance-actions button {
|
||||
margin: 0 20px;
|
||||
flex-basis: 100%;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import { store } from '../../_utils/store'
|
||||
|
@ -61,6 +77,7 @@
|
|||
import SettingsLayout from '../_components/SettingsLayout.html'
|
||||
import { getCurrentUser } from '../../_utils/mastodon/user'
|
||||
import { themes } from '../../_static/themes'
|
||||
import { switchToTheme } from '../../_utils/themeEngine'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -87,6 +104,9 @@
|
|||
instanceThemes[instanceName] = newTheme
|
||||
this.store.set({instanceThemes: instanceThemes})
|
||||
this.store.save()
|
||||
if (this.get('params').instanceName === this.store.get('currentInstance')) {
|
||||
switchToTheme(newTheme)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,21 @@
|
|||
},
|
||||
store: () => store,
|
||||
methods: {
|
||||
onSubmit: async function(event) {
|
||||
event.preventDefault()
|
||||
let instanceName = this.store.get('instanceNameInSearch')
|
||||
instanceName = instanceName.replace(/^https?:\/\//, '').replace('/$', '')
|
||||
// TODO: show toast error if you're already logged into this instance
|
||||
let instanceData = await (await registerApplication(instanceName)).json()
|
||||
// TODO: handle error
|
||||
this.store.set({
|
||||
currentRegisteredInstanceName: instanceName,
|
||||
currentRegisteredInstance: instanceData
|
||||
})
|
||||
this.store.save()
|
||||
let oauthUrl = generateAuthLink(instanceName, instanceData.client_id)
|
||||
document.location.href = oauthUrl
|
||||
},
|
||||
onReceivedOauthCode: async function(code) {
|
||||
let currentRegisteredInstanceName = this.store.get('currentRegisteredInstanceName')
|
||||
let currentRegisteredInstance = this.store.get('currentRegisteredInstance')
|
||||
|
@ -88,6 +103,8 @@
|
|||
}
|
||||
this.store.set({
|
||||
instanceNameInSearch: '',
|
||||
currentRegisteredInstanceName: null,
|
||||
currentRegisteredInstance: null,
|
||||
loggedInInstances: loggedInInstances,
|
||||
currentInstance: currentRegisteredInstanceName,
|
||||
loggedInInstancesInOrder: loggedInInstancesInOrder
|
||||
|
@ -95,20 +112,6 @@
|
|||
this.store.save()
|
||||
goto('/')
|
||||
},
|
||||
onSubmit: async function(event) {
|
||||
event.preventDefault()
|
||||
let instanceName = this.store.get('instanceNameInSearch')
|
||||
instanceName = instanceName.replace(/^https?:\/\//, '').replace('/$', '')
|
||||
let instanceData = await (await registerApplication(instanceName)).json()
|
||||
// TODO: handle error
|
||||
this.store.set({
|
||||
currentRegisteredInstanceName: instanceName,
|
||||
currentRegisteredInstance: instanceData
|
||||
})
|
||||
this.store.save()
|
||||
let oauthUrl = generateAuthLink(instanceName, instanceData.client_id)
|
||||
document.location.href = oauthUrl
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -62,29 +62,37 @@ button {
|
|||
border: 1px solid var(--button-border);
|
||||
cursor: pointer;
|
||||
color: var(--button-text);
|
||||
|
||||
&:hover {
|
||||
background: var(--button-bg-hover);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--button-bg-active);
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.35;
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.primary {
|
||||
border: 1px solid var(--button-primary-border);
|
||||
background: var(--button-primary-bg);
|
||||
color: var(--button-primary-text);
|
||||
|
||||
&:hover {
|
||||
background: var(--button-primary-bg-hover);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--button-primary-bg-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: var(--button-bg-hover);
|
||||
}
|
||||
|
||||
button:active {
|
||||
background: var(--button-bg-active);
|
||||
}
|
||||
|
||||
button.primary {
|
||||
border: 1px solid var(--button-primary-border);
|
||||
background: var(--button-primary-bg);
|
||||
color: var(--button-primary-text);
|
||||
}
|
||||
|
||||
button.primary:hover {
|
||||
background: var(--button-primary-bg-hover);
|
||||
}
|
||||
|
||||
button.primary:active {
|
||||
background: var(--button-primary-bg-active);
|
||||
}
|
||||
|
||||
p, label, input {
|
||||
font-size: 1.3em;
|
||||
|
|
|
@ -7,6 +7,6 @@ $secondary-text-color: white;
|
|||
|
||||
@import "_base.scss";
|
||||
|
||||
body.theme-crimson {
|
||||
body.theme-scarlet {
|
||||
@include baseTheme()
|
||||
}
|
||||
|
|
|
@ -25,6 +25,19 @@
|
|||
%sapper.head%
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
<!-- load theme on startup (handled outside of Sapper/Svelte) -->
|
||||
if (localStorage.store_currentInstance && localStorage.store_instanceThemes) {
|
||||
let theme = JSON.parse(localStorage.store_instanceThemes)[JSON.parse(localStorage.store_currentInstance)]
|
||||
if (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)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display:none;">
|
||||
|
||||
<symbol id="pinafore-logo" viewBox="0 0 100 100">
|
||||
|
|
Loading…
Reference in New Issue