Hacking <<actions>> unordered list

Twine Version: 2.3.5
Story Format: SugarCube 2.30.0

I really like the functionality of the <<actions>> macro, but I don’t like the fact that it defaults to an unordered list. I want to use <<actions>> for dialogue with NPCs, and a list just doesn’t fit with my style.

So, I hacked the <ul> and <li> elements in my stylesheet, like so:

ul, li {
  list-style-type: none;
  margin: 0px;
  padding: 0px;
  text-indent: -2em;

Is there a better way to do this? I don’t expect that I will need regular lists later in my story, but this feels a bit heavy handed.

Unfortunately you only state what you don’t want, and not what HTML element structure you do want. This makes it difficult to supply an example of a custom macro that solves your issue.

The JavaScript source code for the <<actions>> macro can be found here in the story format’s GitHub repository.

Essentially, I just want to remove the bullets (both the disc and margin). I can see from the code that the <ul> and <li> elements are hardcoded into the macro.

I’ve created a custom CSS class “dialogue” that effectively styles it the way I want, but it will be a hassle to add html divs every time I want to use it. To create a custom macro <<dialogue>> that does what I want, do I just use the Macro API and copy/paste the <<actions>> code into my JavaScript file, rename, then tweak the <ul> and <li> references?


This is how I tweaked the <<actions>> macro into my own <<dialogue>> macro. I removed some of the logic as I didn’t need any image handling and I’ll just use the wiki links syntax. It seems to work as intended, but how does it look? Am I missing anything?

Macro.add('dialogue', {
    handler() {
        const $list = jQuery(document.createElement('div'))

        for (let i = 0; i < this.args.length; ++i) {
            let passage;
            let text;
            let setFn;

            // Only handle arguments for wiki link syntax
            text    = this.args[i].text;
            passage = this.args[i].link;
            setFn   = this.args[i].setFn;

            if (
                && State.variables['#dialogue'].hasOwnProperty(passage)
                && State.variables['#dialogue'][passage]
            ) {

                ((passage, fn) => () => {
                    if (!State.variables.hasOwnProperty('#dialogue')) {
                        State.variables['#dialogue'] = {};

                    State.variables['#dialogue'][passage] = true;

                    if (typeof fn === 'function') {
                })(passage, setFn)

I was going to make a couple of suggestions about checking for String arguments and ES6 vs ES5 but I then saw TME was writing a reply. :smile:

The <<actions>> macro assigns the class actions to the list element, so you may use the class to make the selectors specific to the macro. For example:

ul.actions {
	list-style: none;
	margin: 0;
	padding: 0;
ul.actions > li {
	margin: 0;
  1. It’s written in ES6+, which may or may not bite you in the arse. If you have players using older browsers (i.e., ES5 only), then that code is guaranteed to explode. While SugarCube’s source code is written in ES6+, releases are transpiled to ES5 for compatibility.
  2. You’re not sanity checking the arguments it receives, which could cause issues. That’s probably not a huge concern, if this is only for your own use, but I’d be remiss if I didn’t mention it.
  3. Frankly. If you’re going to be emitting a list of links, then you should be using a list, styled as appropriate for your needs—you don’t have to use the default styling. Using <div> or <span> elements simply for styling is suboptimal.

Yes, this is very helpful! Good to know about the transpiling and ES issues.

Since I don’t need anything more than just styling changes, the actions class modifications seems the best way to go.

Thank you both for the information and the help!