I was trying to figure this out myself, and I thought it was going well, but... turns out not so much. I feel like there's a clue for me involving "dark-body," but my brain is not quite making the jump. Now, I'm afraid I'm just gonna make a mess if I don't ask.
I want to change the entire color scheme of the UI on the fly, in response to a player's actions, with several color theme options.
Ultimately, I think what I'm going to want is a variety of room templates, where different types of rooms are different colors, and when the player enters each room, the UI changes to the corresponding color. Like so:
If you're in the woods, the screen is green themed.
If you're by a lake, the screen is blue themed.
If you're in the desert, the screen is amber themed.
Etc., etc. ...
I've got a reasonable looking green version WIP, but I've hit a snag on the part where it changes mid-game.
Where should I write up the various style listings? Can I give them each names and put them all in one "MyStyles" file together? Do they each need their own file? Is there a better file to put them in if I'm doing several of them?
Also, what is the best way to swap them out?
I thought I could put each theme in a different css file and just change
settings.styleFile = "Color-Theme"
during play, but that did nothing. It didn't error, but nothing changed.
Would that have worked if I followed it with some kind of "screen refresh" order?
Are you just changing the colours in the alternate stylesheets? In that case, it might be easier to use CSS variables.
You would define variables for things like text colour, highlight colour, background colour, and so on. So your stylesheet would look like this:
body {
background-color: var(--themebg, white);
color: var(--themetext, black);
}
em {
color: var(--themehilight, red);
}
(the first parameter to var
is the name of the variable, the second is the default)
Then when the player gets to a place where you want to change the colour, you just define the variables by outputting a piece of HTML like:
<style>
:root {
--themebg: darkgreen;
--themetext: green;
--themehilight: orange;
}
</style>
This quickly changes all the colours that are defined using that variable, so that you don't need a whole separate copy of the stylesheet.
You could use script to append a <style>
element with an ID to the head
, and then use something like $('style#colourtheme').text(":root {new values go here}")
to change it; or you could just print out a new <style>
block along with your other output.
The main downside of this method is that it may be buggy for anyone who hasn't updated their browser since 2016; but I hope that's not many people now.
What I did to support dark mode is to use JavaScript to add a class to the body element, "dark-body", and have everything else hang off that.
if (settings.darkModeActive) {
$('body').addClass("dark-body")
}
else {
$('body').removeClass("dark-body")
}
The in the CSS file, have that set the style for the whole page:
.dark-body {
background-color: #111;
color: #eee;
}
Any individual element of class can also be set to change to, for example:
.dark-body #textbox {
background-color: #111;
color: white;
}
So that will set the style for the element with the id "textbox", but only when a parent element has the "dark-body" class. So add that to the body element, and this will get applied, remove it and it will not.
I've been playing with the first method, using css variables, since yesterday, and it works almost perfectly. I am having two problems, though. I think either I'm implementing it wrong or quest just isn't set-up to do this, because I keep getting an error. The only way I got the html to work was by putting it in a msg, like so:
createRoom("lake", {
beforeEnter:function() {
msg("<style>:root {--themeBack:#001433; --themeShdw:#002966; --themeBase:#0066ff; --themeBrit:#4d94ff;}</style>");
},
desc:"You are standing near a lake.",
})
but that's what gives the error:
Attempting to use unknown text processor directive ' --themeBack' (<i><style>:root { --themeBack: #250033; --themeShdw: #4b0066; --themeBase: #bb00ff; --themeBrit: #dd80ff;}</style></i>)
Apparently, the tp doesn't like css variables. These kinds of errors are always head-scratchers to me. I keep thinking, "You say it's an unknown directive, but you just did what it said to do!"
The other problem is, if I do clearScreen, it undoes all the changes (I was trying to hide the error from the player). Again, I imagine this is subject to my putting the html in a msg, so I'm hoping there's another way to do that which I'm just not aware of.
I looked into more of the file references of how dark-body operates, and I see that involves the io, which feels "above my paygrade" to be messing with, but I think I get how it works. I think some of what's there is because that's a mode that the player can choose to turn on or off, and I'm hoping I wouldn't actually need some of it. If I did that, I'd be back to making separate css lists of everything that needs to be changed. If I did that, could I use a case switch, something like this? (presumably, in _io.js)
io.terrainMode = function(terrain) {
let t
t = terrain
switch (t) {
case ("field"):
$('body').removeClass("amber-body")
$('body').removeClass("white-body")
$('body').addClass("green-body")
break
case ("desert"):
$('body').removeClass("green-body")
$('body').removeClass("white-body")
$('body').addClass("amber-body")
break
case ("graveyard"):
$('body').removeClass("green-body")
$('body').removeClass("amber-body")
$('body').addClass("white-body")
break
default:
$('body').removeClass("amber-body")
$('body').removeClass("white-body")
$('body').addClass("green-body")
}
io.textColour = $(".side-panes").css("color")
return world.SUCCESS_NO_TURNSCRIPTS
}
and then format my room templates with:
const FIELD = {
beforeEnter(
script:io.terrainMode("field"),
),
}
Another alternative would be using attribute selectors. For example:
html[uitheme=green] {
color: darkgreen;
}
html[uitheme=green] body {
background-color: black;
}
html[uitheme=green] em,b {
color: green;
}
Then you can change the theme by using $('html').attr('uitheme', 'green')
rather than using a separate class for each option.
To make the files a little easier, you could use something like Less. Then you could make a stylesheet like:
@import "default-style.css";
html[uitheme=dark] {
@import "dark-style.css";
}
html[uitheme=orange] {
@import "orange-style.css";
}
html[uitheme=green] {
@import "green-style.css";
}
html[uitheme=pink] {
@import "pink-style.css";
}
(Note: The less compiler lessc
compiles your .less stylesheets to .css; it's basically there to make the actual stylesheets more human-readable when you're editing them. For more info check out https://lesscss.org)
Ah, we were replying at the same time.
The text processor error is annoying. I guess it does that if you output any text that contains {
and }
that isn't intended to be handled by the text processor (where Quest5 would just ignore it).
Is there a function equivalent to 'OutputTextRaw' that you can use to skip the text processor? I've not played with this version properly yet, so I'm answering from a straight JS perspective.
I tried a few other things to get it to accept the css variables, but I couldn't get it going. So, I went with the dark-body style attributes. Fortunately, I thought up a way to make that go a little quicker. I now have a .txt dummy file with all and only the parts of the style sheet that affect colors, which look something like:
.NAME-body .existingAttribute{
color: THEME-MAIN
background-color: THEME-BACK
border: THEME-SHADOW
hover: THEME-BRIGHT
}
So, I can just do 5 rounds of ctrl-h to replace all, and I've got another theme.
The case switch I made based on the existing darkMode function seems to be working. So, woo! It works! And as a nice bonus, I learned lots of stuff in the process, lol.
Thanks for the help!
There is a rawPrint
function, but after reading the above, I realised it did not work properly, so you need the latest version of _io.js from Github.
I have also added escape codes for { and }, like Quest 5 has, @@@lcurly@@@ and @@@rcurly@@@. They get swapped in msg
so again in that same file.