Floating associated content beside main text

THis is great, how did you “hardcode” this?

First of all, this is not a TiddlyWiki, although I could do the same there. It is a plain HTML page that stole a lot of TW CSS.

The HTML has two divs side-by-side, #gutter and #content. Each verse numbers’ markup inside the gutter looks like this:

      <div class="verse-number" style="margin-top: 36px">
        <a class="tc-tiddlylink" data-verse="Genesis 1:3" title="Genesis 1:3" href="#Genesis 1:3">3</a>
      </div>

And the verse content markup looks like this:

      <p>
        <span class="verse" data-verse="Genesis 1:3">And God said, Let there be light: and there was
          light.</span>
        <span class="verse" data-verse="Genesis 1:4">And God saw the light, that <em>it was</em> good: and
          God divided the light from the darkness.</span>
        <span class="verse" data-verse="Genesis 1:5">And God called the light Day, and the darkness he
          called Night. And the evening and the morning were the first day.</span>
      </p>

The part that really needed hardcoding was verse numbers’ margin-top, which I simply eyeballed one-by-one, pushing them down the page to match with the verse content.

I only did it to create this demonstration. I never found a good way to automate it. In fact, I’m pretty sure this is a dead-end, unless I want to run some JS to calculate these offsets based on the actual rendered layout of the verses. While I’m fairly certain I could figure this out, it seems fragile and very much not in the spirit of TiddlyWiki.

Additional HTML content
  <div class="chapter side-by-side tc-eventcatcher">
    <div class="gutter">
      <div class="verse-number" style="margin-top: 15px">
        <a class="tc-tiddlylink" data-verse="Genesis 1:1" title="Genesis 1:1" href="#Genesis 1:1">1</a>
      </div>
      <div class="verse-number" style="margin-top: 0px">
        <a class="tc-tiddlylink" data-verse="Genesis 1:2" title="Genesis 1:2" href="#Genesis 1:2">2</a>
      </div>
      <div class="verse-number" style="margin-top: 36px">
        <a class="tc-tiddlylink" data-verse="Genesis 1:3" title="Genesis 1:3" href="#Genesis 1:3">3</a>
      </div>
      <div class="verse-number" style="margin-top: 0px">
        <a class="tc-tiddlylink" data-verse="Genesis 1:4" title="Genesis 1:4" href="#Genesis 1:4">4</a>
      </div>
      <div class="verse-number" style="margin-top: 0px">
        <a class="tc-tiddlylink" data-verse="Genesis 1:5" title="Genesis 1:5" href="#Genesis 1:5">5</a>
      </div>
      <div class="verse-number" style="margin-top: 38px">
        <a class="tc-tiddlylink" data-verse="Genesis 1:6" title="Genesis 1:6" href="#Genesis 1:6">6</a>
      </div>

      <!-- ... -->

      <div class="verse-number" style="margin-top: 59px">
        <a class="tc-tiddlylink" data-verse="Genesis 1:31" title="Genesis 1:31"
          href="#Genesis 1:31">31</a>
      </div>
    </div>
    <div class="content">
      <p>
        <span class="verse" data-verse="Genesis 1:1">In the beginning God created the heaven and the
          earth.</span>
        <span class="verse" data-verse="Genesis 1:2">And the earth was without form, and void; and
          darkness <em>was</em> upon the face of the deep. And the Spirit of God moved upon the face of
          the waters.</span>
      </p>
      <p>
        <span class="verse" data-verse="Genesis 1:3">And God said, Let there be light: and there was
          light.</span>
        <span class="verse" data-verse="Genesis 1:4">And God saw the light, that <em>it was</em> good: and
          God divided the light from the darkness.</span>
        <span class="verse" data-verse="Genesis 1:5">And God called the light Day, and the darkness he
          called Night. And the evening and the morning were the first day.</span>
      </p>

      <!-- ... -->
      
      <p>
        <span class="verse" data-verse="Genesis 1:31">And God saw every thing that he had made, and,
          behold, <em>it was</em> very good. And the evening and the morning were the sixth day.</span>
      </p>
    </div>
1 Like

Hi @Scott_Sauyet ,
could you also post the css?

Sure, but first, please remember that this was a proof of feasibility, and one that I was not able to turn into a production technique. It only works because it was hand-crafted, and it will fail as the content width changes.

You can always see the full source code with CTRL-U in most browsers.

I use a copy of the TW vanilla theme/palette to lay out the page and choose colors, etc. The custom CSS looks like this:

.side-by-side {
  display: flex;
  flex-direction: row;
  .gutter {
    flex: 0 1 2em;
    padding: 0 1em 0 0;

    .verse-number {
      display: inline-block;
      width: 100%;
      text-align: right;
      opacity: .5;
      a {width: 100%; padding: 0 .25em;}
    }

    .verse-number:hover, .verse-number.highlight, .verse-number.highlight2 {
      background: #999;
      opacity: 1;
      a {text-decoration: none; color: white;}
    }

    .content {flex: 8 1 auto;}
  }
  span.verse.highlight, span.verse.highlight2 {background: #cfc;}
}

And the JavaScript used for this is

const gutters = [...document.querySelectorAll('.side-by-side .gutter')]
gutters.forEach(gutter => {
  gutter.addEventListener("pointerover", (event) => {
    if (event.target.nodeName == 'A') {
      const verseNbr = event.target.dataset.verse
      const content = event.target.closest('.side-by-side').querySelector('.content')
      const verse = [...content.querySelectorAll('.verse')].find(v => v.dataset.verse == verseNbr)
      verse.classList.add('highlight')
    }
  })
  gutter.addEventListener("pointerout", (event) => {
    if (event.target.nodeName == 'A') {
      const verseNbr = event.target.dataset.verse
      const content = event.target.closest('.side-by-side').querySelector('.content')
      const verse = [...content.querySelectorAll('.verse')]
        .find(v => v.dataset.verse == verseNbr)
      verse.classList.remove('highlight')
    }
  })
})


const content = [...document.querySelectorAll('.side-by-side .content')]
content.forEach(c => {
  c.addEventListener("pointerover", (event) => {
    if (event.target.nodeName == 'SPAN' && event.target.classList.contains('verse')) {
      event.target.classList.add('highlight2')
      const verseNbr = event.target.dataset.verse
      const gutter = event.target.closest('.side-by-side').querySelector('.gutter')
      const link = [...gutter.querySelectorAll('.verse-number a')]
        .find(v => v.dataset.verse == verseNbr).closest('.verse-number')
      link.classList.add('highlight2')
    }
  })
})

content.forEach(c => {
  c.addEventListener("pointerout", (event) => {
    if (event.target.nodeName == 'SPAN' && event.target.classList.contains('verse')) {
      event.target.classList.remove('highlight2')
      const verseNbr = event.target.dataset.verse
      const gutter = event.target.closest('.side-by-side').querySelector('.gutter')
      const link = [...gutter.querySelectorAll('.verse-number a')]
        .find(v => v.dataset.verse == verseNbr).closest('.verse-number')
      link.classList.remove('highlight2')
    }
  })
})

If this were to be made production-ready, then the above would probably be better done with some sort of event delegation. (The native JS equivalent to TW’s $eventcatcher widget.)

1 Like

Just a question: could most of the script be done with onhover: ? This would bring us closer to a tw solution?

Probably. But please remember what this code was for: simply to show the UI I was hoping to be able to build. It was definitely not meant to be scaffolding for a TW version.

I’m sure with a little work we could use the CSS :has pseudo-class and some dynamic CSS (the maximum number of verses in any chapter is 176) to handle the hovering behavior. That’s not what I was focused on here. I did something quick and easy to display the hovering.

What I was trying to figure out was how to place the verse numbers in their column so that they aligned with the appropriate verse. The demo was just written as markup in which I could easily update those values. The rest of it, I’m pretty sure I can do. But that question stymied me, and I never really went back to it, moving on to other things in the project, and never quite deciding between two other layouts.

I do hope to look at this again soon. And I do have some hope. But a real system will not be built on this codebase.

3 Likes

Hi @Scott_Sauyet
phrasenumbers.json (17.2 KB)
This is an attempt to do this within tw by automatically segmenting a text by periods.

PhraseQuoteMacroDemo.json (2.3 KB)
Voilà. Mas beautifull. Only the first phrase of the line appears, if clicked, the number of the active phrase appears.

and a final version with typographic quotes. Final.json (4.6 KB)

It looks nice. I’ll have to investigate soon how you did it. It doesn’t capture everything I was trying to do, but it captures a lot.

Very exciting!

phrase-quote-final.json (5.0 KB)
Sorry for flooding this thread with “last versions” . This last version is better on smartphones and solves the problem of … triple periods and (no real phrase.) brackets.

By the way the name wrappit is due to this: wrappit — . A dropdown that I use in my editor to wrap expressions with macros.

@Scott_Sauyet I think from Add Notes and Figures to Tiddlers in View Mode - Tufte Style - #40 by Scott_Sauyet it should be moved to a new thread. Can you split it?

OK, Here they are! :slight_smile:

1 Like