How would you implement multiple tabs that remember the user's place?

+1 vote
asked Sep 14 by Senna (230 points)
So, I'm very new to Twine in general, and don't have any code to suggest on this. Just, bear with me on the concept. I recognize it may not be possible without just sitting down and bashing my face against javascript a few times, but any advice on the way would be nice.

Say you have a sidebar that's got tabs. These tabs are, maybe, "Story", "Codex", "Save Games", "Timeline" or so on.

Me, I want each of these to have a default starting point - the Story begins at the Front Page, the Codex begins at the Codex Index, the Timeline begins at Year 1, etc.

But I also want it to remember what you do, and to have interactions. Like, let's say I'm telling the Story and *boop* lil' link to the Codex, that'll ideally switch you to the Codex tab and to the specific passage of the Codex that was relevant and linked.

1 Answer

+1 vote
answered Sep 14 by greyelf (27,720 points)
selected Sep 15 by Senna
Best answer

You can create variables using the (set:) macro to store which Passage each of the different Tabs (links?) currently reference, and the ideal places to initialise these variables to their default values would be within a startup tagged special Passage

(set: $story to "Front Page")
(set: $codex to "Codex Index")
(set: $timeline to "Year 1")

You can then use these variables to indicate which passage to show when the related links are selected, and you can create the related links using the (link-goto: ) macro like so.

(link-goto: "Story", $story)
(link-goto: "Codex", $codex)
(link-goto: "Timeline", $timeline)

The next issue is how to keep the value of these variables up to date and you could do that one of two ways:

1. Manually: by using a (set:) macro to change which related Passage was last shown to the reader.

(set: $codex to "to-the-last-codex-passage-shown")

2. Automatically: by using known Passage tags to mark each of the Passages belonging to each 'Tab', and then use code within a header tagged special Passage to update the relevant variable each time a related Passage is shown.

2a. Mark all the Codex related passages with a codex tag, all the Timeline related ones with a timeline tag, and so forth. If most of the passages within the story are Story related then I would suggest leaving these ones untagged.

2b. Create a header tagged special Passage and then use code like the following to check for each tag and update the related variable. The following assumes that all Passages without any known tags are Story related passages, it also assumes that each Passage can only belong to one 'Tag'.

note: The name you give the header passage is not important but you will need to remember it so that it can be used in some CSS later, I named the header passage in this example Update Tab Variables

(set: _passage to (passage:)'s name)
(set: _tags to (passage:)'s tags)
(if: _tags contains "codex")[
	(set: $codex to _passage)
(else-if: _tags contains "timeline")[
	(set: $timeline to _passage)
	(set: $story to _passage)

The last issue to solve is removing/hiding any visual output generated by either the startup tagged passage or the header passage from point 2b, and placing CSS like the following within your story's Story Stylesheet area will do this.

tw-include[type="startup"], tw-include[title="Update Tab Variables"] {
	display: none;

note: If you named the header tagged passage from point 2b something other than Update Tab Variables then you will need to modify the above CSS to use that passage name/title instead.

commented Sep 15 by Senna (230 points)
Efficient, works with relatively few kinks, only complaint I even sort of have with the post is not mentioning the header-formatting bug, but hey, how're you to know I've never used the header before.


Thanks a lot!
commented Sep 15 by greyelf (27,720 points)

not mentioning the header-formatting bug

Which header formatting bug are you talking about?

The only header in my example is the one containing the TwineScript to update the 'Tab' variables, and if you use the CSS I supplied then it's contents isn't visual on the generated page.

commented Sep 16 by Senna (230 points)
The one where having any kind of header at all kills Twine formatting for things like # Title Goes Here on the first line of a page.
commented Sep 17 by Chapel (23,990 points)

Just use html to work around that. 

<h1>text you want to have a # before</h1>

<h3>for ### text</h3>

There's a lot to remember when helping people out and about a half-a-million possible edge cases in every answer where one thing could break another. Being passive-aggressive about it doesn't help anyone. 

commented Sep 17 by greyelf (27,720 points)

How was I meant to know you were (planning on) using Heading markup in your story?

commented Sep 17 by Senna (230 points)

Wasn't meant to be passive aggressive!

Was meant to share information that I was missing when I went into implementing this!

a 9/10 one niggling detail is still a really good review I think.

And I was able to solve that on my own after a bit of headscratching and googling, so I figured being told it was a bug would help anyone who came after.

Speaking of, useful notes for anyone who comes after: heading markup will continue to break if you use a backslash to delete whitespace. The Twine heading markup won't work until there's a linebreak, which lead to this hilarious situation for me:

<h1>A Title</h1>\
<h4>The Subtitle</h4>\
<h5>Is Really Long</h5>


commented Sep 17 by Chapel (23,990 points)

Wasn't meant to be passive aggressive!

My apologies then. That's how it read, I think it was the "how were you to know..." part. It just seemed like a weird way to put it. I shouldn't have assumed though, with how hard it is to pick up on that sort of thing via text. 

And I was able to solve that on my own... 

It might be better to just include this information in the comment in the future, if you already know the solution. The back and forth doesn't really add much. Regardless, I'm glad you got it working.