Twine Version: 2.7 Sugarcube 2.36.1
Hello! I’m hoping this is an easy fix and I’m just too unfamiliar with JS to understand what I’m doing. I am using a template that makes use of the SettingsAPI to create three themes.
var themeList = ["Sunset Theme", "Dark Theme", "Day Theme"];
var setTheme = function() {
var html = $("html");
html.removeClass("dark day");
switch(settings.theme) {
case "Dark Theme":
html.addClass("dark");
break;
case "Day Theme":
html.addClass("day");
break;
}
};
Setting.addList("theme", {
label : "Change theme",
list : themeList,
onInit : setTheme,
default : "Day Theme",
onChange : setTheme
});
However, while I would like the player to be able to change the theme via the Settings if they desire (for accessibility), I also want the theme to automatically change when the player progresses to different levels of the game. So “Day Theme” is the default theme for level 1, but when the player unlocks level two, the theme would automatically change to “Sunset Theme”, and then “Dark Theme” on reaching level 3.
I’d like to add something on the link to the first passage of level 2 that makes the theme change when loading the next passage. I was trying to add various bits of the js as a <script>
nested within the passage link, but nothing seems to take. Is this accomplishable, and if so, what’s the secret code I need to add to my passage link?
Thanks so much!!
1 Like
Hi there! I did what you were trying to do for one of my games. Essentially, I created a special theme where there will be a change happening, and two other themes where the palette stays constant. Then tagged the passages for the respective time.
You can find the code example here: github
So your example would be:
var themeList = ["Rollover Theme" "Sunset Theme", "Dark Theme", "Day Theme"];
var setTheme = function() {
var html = $("html");
html.removeClass("clock dark day");
switch(settings.theme) {
case "Rollover Theme":
html.addClass("clock");
break;
case "Dark Theme":
html.addClass("dark");
break;
case "Day Theme":
html.addClass("day");
break;
}
};
Setting.addList("theme", {
label : "Change theme",
list : themeList,
onInit : setTheme,
default : "Rollover Theme",
onChange : setTheme
});
And in your css:
.clock body[data-tags~="day"] {
background: /*the colour for the day*/
}
.clock body[data-tags~="dark"] {
background: /*the colour for the night*/
}
.clock body[data-tags~="sunset"] {
background: /*the colour for the sunset*/
}
1 Like
I was leaning away from using data-passage because it means I’d have to have each set of CSS twice (once as the theme itself, and then again in its set of data tags in the “Clock” theme). I have a hard enough time keeping CSS straight and functioning one time, haha. It seemed cleaner to just be able to use the theme that’s already styled and code a link that changes the theme and advances the passage forward…
1 Like
note: the following explanation about how “settings” work has been simplified, so it isn’t 100% technically correct, but it is close enough.
If I understand correctly you want to programmatically change the current value of the theme setting, which is possible as long as you manually do the right things in the right order.
When you change a List based setting via the Settings dialog three things occur:
-
The associated property (eg. theme) of the special settings object is updated with the selected value from the related Array (eg. themeList)
-
The setting’s onChange call-back function (eg. setTheme()
) is called, so the outcome associated with that setting occurs.
-
The Setting.save()
function is called so the setting value change is persisted to the web-browser’s LocalStorage area.
So if you do the same three things within the body of your “link” then the functional equivalent of the end-user opening the Settings dialog and selecting a new “Theme” will occur.
But before you do that you will need to make a couple of changes to how you define & call the associated onChange call-back function and related Array, because they are current only available (scoped) to code that is executed within the Story > JavaScript area.
1: Raising the scope of the call-back function and Array to be “Global” like.
This can be done by defining both on SugarCube’s special setup object.
setup.themeList = ["Sunset Theme", "Dark Theme", "Day Theme"];
setup.setTheme = function() {
var html = $("html");
html.removeClass("dark day");
switch (settings.theme) {
case "Dark Theme":
html.addClass("dark");
break;
case "Day Theme":
html.addClass("day");
break;
}
};
Setting.addList("theme", {
label : "Change theme",
list : setup.themeList,
onInit : setup.setTheme,
onChange : setup.setTheme,
default : "Day Theme"
});
2: Use a <<script>>
macro in the body of a <<link>>
macro to preform the three required steps.
<<link "Change to Sunset" "Next Passage">>
<<script>>
/* change setting to "Sunset Theme", which is the 1st element in the themeList array */
settings.theme = setup.themeList[0];
/* call the onChange function to apply the settings outcome */
setup.setTheme();
/* persist the new value of the setting to storage */
Setting.save();
<</script>>
<</link>>
2 Likes
Greyelf, this worked like a charm, thank you!!