Custom Widget Help - delayed link activation

Twine Version:
2.10.0.0

I’ve got the following code for a custom widget, which disables clickable links for the duration specified in the first argument. Often, this ends up being put within a passage using the <<type>> macro.

<<widget "fade" container>><<set _delay = _args[0] ?? "0.5s">><div id="instance1" class="link-disabled">_contents<<timed _delay>><<removeclass #instance1 "link-disabled">><<addclass #instance1 "link-enabled">><</timed>></div><</widget>>

To go with that, I’ve got the following written in my Stylesheet.

.link-disabled a {
  pointer-events: none;
  color: white;
  transition: color 0.5s ease;
}
.link-enabled a {
  pointer-events: auto;
  color: DarkMagenta;
  background-image: linear-gradient(DarkOrchid, DarkMagenta);
  background-position: 0% 100%;
  background-repeat: no-repeat;
  background-size: 0% 2px;
  transition: background-size .3s, color 0.5s ease;
}
.link-enabled a:hover {
  color:DarkOrchid;
  background-size: 100% 2px;
  text-decoration: none;
}

I initially included the event macro by chapel to detect when typing had finished with :typingcomplete, but I removed it for simplicity. The widget worked as expected in a vacuum, but I encountered two problems when trying to implement it into the rest of my game.

  1. The widget interfered with spacing, adding line breaks where there were none. This doesn’t seem to affect the <<cycle>> macro, but it happened in this section that uses <<link>>.
  2. The widget stops working if multiple instances of it are used in the same passage. I’d like to increment the div id, but I couldn’t figure it out.

The approach of targetting the contents with an ID doesn’t work with multiple instances, because they all have the same ID, as you noticed.

There are two general approaches that come to mind to deal with this:

  1. Make a unique ID for each time the widget is used on a passage
  2. Target the element in a way other than it’s ID (e.g. using JS)

The first option is easier, so I’ll give an idea how that would work:

<<widget "fade" container>><<nobr>>
    <<set _fade_count = _fade_count ? _fade_count + 1 : 0>>
    <<set _fade_id    = 'widget-fade-' + _fade_count>>
    <<set _delay      = _args[0] ?? "0.5s">>
    <div @id="_fade_id" class="link-disabled">_contents</div>
    <<timed _delay>><<removeclass _fade_id "link-disabled">><<addclass _fade_id "link-enabled">><</timed>>
<</nobr>><</widget>>

(Note the user of <<nobr>> to prevent white space being turned into newlines inside the widget)

Sorry for the delayed response, but I managed to figure it out! I ended up taking a completely different approach. Still, I appreciate your help; it definitely steered me in the right direction.

I managed to achieve this same effect using only CSS through an animation. Here’s the relevant portion of the stylesheet:

.macro-type a {
pointer-events: none;
color: white;
transition: color 0.5s ease;
}

@keyframes please_work {
0% { color: white; pointer-events: none; }
99% { color: DarkOrchid; pointer-events: none; }
100% { color: DarkOrchid; pointer-events: auto; }
}

.macro-type-done a {
animation-name: please_work;
animation-duration: 1.5s;
animation-timing-function: cubic-bezier(1,0,.7,1);
color: DarkOrchid;
pointer-events: auto;
background-image: linear-gradient(DarkMagenta, DarkOrchid);
background-position: 0% 100%;
background-repeat: no-repeat;
background-size: 0% 2px;
transition: background-size .3s;

}
.macro-type-done a:hover {
color:DarkMagenta;
background-size: 100% 2px;
text-decoration: none;
}

Great!

I’m interested, though, why you choose to fade colours instead of just opacity?

I faded colors because I wanted the links to appear as if they were normal text, then only reveal themselves as links after typing was completed. They still needed to be readable before becoming interactive.