Using widgets to minimize unwieldy HTML?

Twine Version: 2.3.14
Story Format: Sugarcube 2.34.1

Hello there, I had a quick question! I’ve developed ways of styling both the choice container and the individual choices in my game. However, I’m finding that having to enclose each choice in a div container is slowing me down (entirely self-imposed, I know). Is there a way to use widgets to create HTML shortcuts so that I don’t have to write each div container out each time?

For reference, this is what a typical set of choices looks like in my code:

Which door do you take?
<<nobr>>
  <div class="choices">
   <<link '<div class="choice-item">"The red, angry door."</div>' 'reddoor'>><<fair_plus "$courage" +10>><</link>>
   <<link '<div class="choice-item">"The yellow, happy door."</div>' 'yellowdoor'>><<fair_plus "$compassionate" +10>><</link>>
   <<link '<div class="choice-item">"The green, sleepy door."</div>' 'greendoor'>><<fair_plus "$calm" +10>><</link>>
  </div>
<</nobr>>

I did see this post while I was searching for similar questions, but I’m not sure how to apply that specific example to my code. Any help in this area would be much, much appreciated! Thank you!

1 Like

Instead of typing sugarcube, you can type html.
For instance:

 <<link '<div class="choice-item">"The red, angry door."</div>' 'reddoor'>><<fair_plus "$courage" +10>><</link>>

should have the same result as

<a class="choice-item" data-passage="reddoor">The red, angry door.<<fair_plus "$courage" +10>></a>

I haven’t tested with your specifics, especially your fair_plus <<widget>>, but I’ve used a <<set>> macro, ant it worked fine.

1 Like

Assuming that you’re referring to the choice-item wrappers, you shouldn’t have to use them now as you can simply piggyback off the choices wrapper to style the links contained within.

For example, in your CSS:

/* Change the `.choice-item` selector to `.choices a`. */
.choices a {
    /* Former `.choice-item` style properties go here. */
}

You target a elements (normal HTML links) within the choices wrapper because that’s what the <<link>> macro generates.

That should allow you to write your example as:

Which door do you take?
<<nobr>>
  <div class="choices">
   <<link '"The red, angry door."' 'reddoor'>><<fair_plus "$courage" +10>><</link>>
   <<link '"The yellow, happy door."' 'yellowdoor'>><<fair_plus "$compassionate" +10>><</link>>
   <<link '"The green, sleepy door."' 'greendoor'>><<fair_plus "$calm" +10>><</link>>
  </div>
<</nobr>>

 

NOTE: There are other ways to accomplish your goal, but the above is probably the simplest.

 

It does not. Aside from the class choice-item being on a different element, which may be fine regardless, the <<fair_plus>> macro/widget will execute as soon as the link is rendered rather than when it’s activated as with the <<link>> version.

2 Likes

Expanding on @TheMadExile’s advice, might want to use nth of type.

I am not sure if this is what you are trying to do, but you said that you want to style each choice. You can color each link like this:

<<nobr>>
  <div class="choices">
   <<link "The red, angry door." "reddoor">><<fair_plus "$courage" +10>><</link>>
   <<link "The yellow, happy door." "yellowdoor">><<fair_plus "$compassionate" +10>><</link>>
   <<link "The green, sleepy door." "greendoor">><<fair_plus "$calm" +10>><</link>>
  </div>
<</nobr>>

<style>
.choices > a:nth-of-type(1) {color:red}
.choices > a:nth-of-type(2) {color:yellow}
.choices > a:nth-of-type(3) {color:green}
</style>

Make sure to put this all in a story passage, not a passage tagged stylesheet. That way the colors will only apply to a single passage.

You can repeat this for each passage and change the colors.

2 Likes

Your intention appears to be show a list of styled links, with each link being on its own line.

HTML includes two elements <ul> (unordered list) and <ol> (ordered list) that are specifically designed to do that.

If you change your code to the following…

<ul class="choices">
	<li><<link 'The red, angry door.' 'reddoor'>><<fair_plus "$courage" +10>><</link>></li>
	<li><<link 'The yellow, happy door.' 'yellowdoor'>><<fair_plus "$compassionate" +10>><</link>></li>
	<li><<link 'The green, sleepy door.' 'greendoor'>><<fair_plus "$calm" +10>><</link>></li>
</ul>

… then each link will appear on its own line, and you wont need the <<nobr>> macro as SugarCube knows to automatically suppress line-breaks within the structure of such lists.

You didn’t include an example of the CSS being applied to either the .choices class or the .choice-item class so I can’t include those settings in the following, but to remove the default dot and left padding from the <ul> element you would need to add the following to the .choices class…

.choices {
	list-style-type: none;
	padding-left: 0;
	/* the existing settings.... */
}

…and rename your existing .choice-item class based CSS Selector to be the following…

.choices li a {
	/* settings for styling the link text... */
}
2 Likes

Ah, thank you so much for this, it’s definitely much more helpful to style links within the .choices class, and will definitely simplify writing normal choices greatly! The only reason why I have a separate “choice-item” wrapper is to differentiate standard choices from other choices that might appear in the container, for example romantic choices (“flirt-item”), informational choices (“ask-item”), lying choices ("lie-item), or etc. Here’s an example of what I mean:

CSS (for .choices)

html .choices {
  border-top:1px solid var(--black);
  padding:3em;
  margin-top:3em;
  text-align: justify;
}

CSS (for .choice-item):

html .choice-item {
  transition:0.4s;
  cursor:pointer;
  letter-spacing:var(--spacing);
  color:var(--white);
}

html .choice-item::before {
  content: '\f105';
  font: normal normal normal 14px/1 FontAwesome;
  font-size:1em;
  margin-right:1em;
}

html .choice-item:hover {
  text-shadow: 0px 0px 8px #fff;
}

This results in standard choices looking like this, with the arrow preceding them to indicate a standard action:

However, I have other styled choice-items (with different prefix symbols) that might appear as well:

Which is why I wasn’t initially piggybacking off of the .choices container alone. But since the vast majority of choices are “standard,” stying the links within .choices will still definitely streamline things!

Ah, I see what you mean by using unordered lists so I don’t have to bother with <>! Given that I technically have different prefixes/styling for different types of choices/links, I think this will only apply to the “standard” ones, but still very helpful to keep in mind!

Well, if you go with a list element, then you still wouldn’t need the wrappers. Just apply a class to each list item that’s different from a normal choice.

For example:

<ul class="choices">
	<li><<link …>></li>
	<li><<link …>></li>
	<li class="ask"><<link …>></li>
	<li class="flirt"><<link …>></li>
	<li class="lie"><<link …>></li>
</ul>

And the CSS:

/* Assumes `.choices` is the list element. */
.choices > li > a {
	/* Normal choices. */
}

.choices > li.ask > a {
	/* Ask choices. */
}

.choices > li.flirt > a {
	/* Flirt choices. */
}

.choices > li.lie > a {
	/* Lie choices. */
}

You get the idea.

1 Like

Oh, that’s perfect, thank you! And if I weren’t to use them as list items, would it be something like this?

.choices  a.ask {
      /* Ask choices. */
}

If you mean like with your original <div.choices> wrapper, then not with the base <<link>> macro, since there’s no easy way to add classes to its element. You’d either need to use you original <<link>> text wrapper or just wrap the <<link>> itself.

 

Examples of the former (wrap link text) would be:

<<link 'normal response' …>>
<<link '<div class="ask">a question</div>' …>>
<<link '@@.ask;also a question@@' …>>

And the CSS:

.choices a { /* normal */ }
.choices a .ask { /* ask */ }

 

Examples of the latter (wrap link) would be:

<<link 'normal response' …>>
<div class="ask"><<link 'a question' …>></div>
@@.ask;<<link 'also a question' …>>@@

And the CSS:

.choices a { /* normal */ }
.choices .ask a { /* ask */ }

 

NOTE: The @@…@@ markup shown above is SugarCube’s custom style markup. You could use it if you find it palatable for the extra brevity.

1 Like

Oh. If you’re not against add-ons there is an add-on macro by Akjosch named <<ilink>> that does allow you to add an ID and/or classes directly to the macro’s element. It’s part of their enhancedmacros.js gist.

After copy-pasting the code into your JavaScript section, the usage would be like:

<<ilink 'normal response' 'normal passage'>>…<</ilink>>
<<ilink 'a question' 'ask passage' .ask>>…<</ilink>>
<<ilink 'another question' 'another ask passage' .ask>>…<</ilink>>

And the CSS:

.choices a { /* normal */ }
.choices a.ask { /* ask */ }
1 Like

Oh wow, that’s all perfect, thank you so much! That makes sense why it would take extra work to wrap/add classes to the <> macro. I’ll play around with things and see what ends up feeling best; thanks for taking the time to help!

Now I have another issue that’s stumping me! Using the suggested configuration here:

…and here:

I’m noticing that my choices are sliiiightly positioned different from before, and trying to figure out which property is controlling that placement is driving me crazy. Here’s what I mean:

Jun-07-2022 01-06-36

This is me switching between my original code (seen in the first post) and the new “unordered list” code. It’s pretty subtle, but using list items seems to shift everything very slightly up and to the right, even though both examples use the same .choices wrapper.

html .choices {
  list-style: none;
  list-style-type: none;
  border:1px solid var(--gold);
  padding:2em;
  margin-top:2em;
  text-align: justify;
}
Old code

Old code

<<nobr>>
  <div class="choices">
   <<link '<div class="choice-item">"Does he not deserve mercy?"</div>' 'prologue1.0.1'>><<setcompassionate +5>><</link>>
   <<link '<div class="choice-item">"Does he not deserve justice?"</div>' 'prologue1.0.2'>><<setloyal -5>><</link>>
   <<link '<div class="choice-item">"Does he not deserve the slowest death imaginable?"</div>' 'prologue1.0.3'>><<setcompassionate -5>><</link>>
  </div>
<</nobr>>

Results in:

(Note how the border of the “choices” box is aligned with the main text.)

New code

And the new code:

<ul class="choices">
   <li><<link '"Does he not deserve mercy?"' 'prologue1.0.1'>><<setcompassionate +5>><</link>></li>
   <li><<link '"Does he not deserve justice?"' 'prologue1.0.2'>><<setloyal -5>><</link>></li>
   <li><<link '"Does he not deserve the slowest death imaginable?"' 'prologue1.0.3'>><<setcompassionate -5>><</link>></li>
  </ul>

Results in:

(Notice how the border of the choice box is not exactly aligned with the main body text, and there’s a larger gap between it and the bottom of the screen.)

To my eye, all of the styling involved here is exactly the same, so I can’t figure out exactly what element is causing the shifting of the text placement, except that it’s just the hidden nature of using list items? Am I missing something more obvious?

note: adding html to the start of the your html .choices CSS select serves no real purpose, so you can either change that selector back to the original .choices suggested by both TME and me; or change it to ul.choices if you want to make it specific to the <ul> element.

Generally you can use your web-browser’s Web Developer Tools to answer most CSS related questions…

If you inspect the elements that make up the “choices” structure, and select the parent <ul> element, you will see:

  1. a coloured visual representation of any margin and/or padding being applied to that element.
  2. a list of all the CSS rules that are being applied to that element.

And you will notice that:

  1. both margins & padding is being applied.
  2. some of it is due to your own CSS. (the .choices selector rule)
  3. some of it is due to SugarCube’s default CSS. (the .passage ol, .passage ul selector rule)
  4. some of it is due to the web-browser’s default CSS. (the ul rule)
1 Like

Thank you, you were right that it was the default ul rule that was the culprit! My Inspector tool has been acting funky, but it turned out to be a recent update to the Mac OS–your comment caused me to reinstall my browser and that cleared the issue as well. :slight_smile: Thank you so much for the help!