Bike to HTML

:pray: thank you!

today I tried seeing if I could publish a Bike outline as a note on by website, and it turns out the answer is yes. I ran a post-processing step on the HTML to insert a few extra HTML tags into the header (such as a stylesheet and a meta tag for a nicer appearance on mobile devices), and after that the markup gave me all the hooks I needed to style the node types differently (eg. li[data-type=note] { ... }). I also ran a regex replacement over my outline, replacing [[[img: foo.png]]] with <img src='foo.png' />. Everything worked really well!

Though now I think of it, there was one difficulty I ran into, which is figuring out how to style numbered lists with numbers. I think there’s a way to do it with CSS counters, but I never figured it out. The trouble is that the list element is a <ul> rather than an <ol>. I can see the argument for keeping the node type uniform so it seems acceptable to work around this with CSS, long as that’s possible.

Another thing I noticed in the process is that Bike can emit invalid HTML in the form of self-closing tags that the HTML spec does not allow to be self-closing, such as <p/> instead of <p></p>. Browsers probably do the right thing with this, but I think It’s an annoying feature of the HTML spec that only a limited set of tags can be self-closing. For example, as a consequence, web components need to always be written as <my-component></my-component> rather than <my-component /> even when they have no content…

And another thing I noticed is that pasting code into a code block will create indented nodes rather than prefixing the lines with spaces. This made lining things up difficult when rendering in a browser. In particular, I was actually trying to render a diagram:

which I eventually got working by adding the spaces back myself. but it would have been really nice if the default paste mode for code would paste code into a code block as code (leading spaces/tabs and all) rather than as nested list items.

At one point I had the goal of making Bike’s HTML representation look exactly like the in app representation. The main driver was so that I could use web view to show Bike file previews in macOS finder. After some trial and error I ended up using a more native solution for macOS Finder previews, so the work on Bike to HTML has fallen by the wayside…

But if you are interested in Bike > HTML @Blake Did some nice work in that direction here:

I’m not sure what to do about that. My goal is to say that Bike writes XML using a subset of HTML tags:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">

When I put a Bike document into a pure XML validator it seems to validate well. Other validators start to interrupt the document as some HTML variant and then it doesn’t validate.

If there’s some way I can change the header construction to make it “right” I’m happy to do that, but I generally want to write as XML without too many other promises, other then that I’ll be using a subset of HTML tags.

I can see how this would be useful, but I can also see how the current behavior could be useful, and the current behavior is more consistent with how pasting in general works. I think for now I would prefer that you just handle this as you are, with a post processing script.

1 Like

Oh, thanks for pointing out that you’re trying to write XML – maybe my comments about HTML don’t apply in that case. Maybe this means that I shouldn’t be treating the Bike file as HTML, and instead think of it as something HTML-like that should be postprocessed more heavily into a “proper” HTML file (eg. converting <p /> to <p></p> and so on) to ensure valid HTML output. (I should also add that this is an area I don’t know a lot about, so apologies if anything here is misstated… Will research more and edit this post if I was misunderstanding.) Out of curiosity I tried my notes page in the W3 validator and it noticed the self-closing tags, and also the indent attribute on some of the <li> elements.

I can see how this would be useful, but I can also see how the current behavior could be useful, and the current behavior is more consistent with how pasting in general works. I think for now I would prefer that you just handle this as you are, with a post processing script.

One issue here is that in general I’m not sure it is possible to handle in a post-processing script because not all spacing information is preserved with the current paste behavior. For example, if I paste the following into a Bike code block:

indent 0
 indent 1
indent 0
  indent 2
indent 0
   indent 3
indent 0
    indent 4
indent 0
     indent 5

I get this:

which, if I copy-and-paste it back, looks like this:

indent 0
indent 1
indent 0
indent 2
indent 0
indent 3
indent 0
  indent 4
indent 0
  indent 5

My workaround was to add the spacing back manually, which is actually fine so long as I don’t make too many diagrams, so this isn’t really a big issue for that particular case, and is probably fine with code too, so long as it’s indented with tabs or four spaces.

One consequence of the current four-spaces → one indentation level rule is that if I try putting content from BIke’s own format into a Bike code block, it loses all spacing since the HTML was indented with two spaces per indent level:

<li id="FbHw" indent="2" data-type="quote">
  <p>The above program works with word type data (no negatives). To handle integer data</p>
</li>
<li id="Bb" indent="2" data-type="quote">
  <p>(possibly negative), just invert the sign bit. This converts the data range to</p>
</li>
<li id="c3" indent="2" data-type="quote">
  <p>0000..0 (lowest negative) to 1111..1 (highest positive).</p>
</li>

becomes

Yes, I think that’s a good way to think about it. It’s very close to HTML, and should always be readable by a browser, but I don’t think can ever validate 100% because I use some extra attributes such as “level”, and I write using XML mode (I’m using libxml2) to perform the actual XML serialization.

Yikes, you’ve got me on that one :slight_smile:

Anyone else have thoughts?

I’m still not sure that I like the idea of special case pasting into code blocks. It wouldn’t cover every case, but what if I made Bike’s plain text to outliner parser a bit smarter by detecting indentation level instead of always just using 4 spaces?

1 Like

Another angle might be to add a “Raw Paste” option that always puts the contents of the clipboard into the current node without splitting it into multiple nodes, ie. treating all whitespace as content to go inside the current node, without depending on the node type. This wouldn’t help for 2-space-indented code by default so auto-detection could still be a good idea even if a raw paste option were to be added.

1 Like

Yes, I can imagine adding that. There is already the “Paste and match Style” behavior, I think this would fit with that well.

I don’t think it would work quite like this. Each line would be inserted into a new row/node. It’s just each line would retain leading whitespace and the rows would all be inserted at the same level, not indented. Make sense?

Yes, that makes sense and would fit my use case perfectly. I’m not exactly sure why I suggested keeping all of the content in one node other than that it seemed a bit conceptually cleaner, but I actually like your idea more, I think. Edit: And it would also take care of the two-space-indent case, nice.

Glad to see someone else is interested in publishing bike outlines as HTML pages.

@jonsterling did some great work with bike-converters to transform outlines from .bike → HTML → Markdown.

I forked his script to just convert to HTML, and added a custom stylesheet as well.

2 Likes

Playing around with this a little more I refined my simple pre-processing script to the following, which seems to work well and passes the W3 validation checks. It’s vulnerable to error since it operates on HTML using regular expressions, but I think in the context of Bike this will probably be fine, or can at least serve as the basis of a more robust transform in the future:

  const outline = fs.readFileSync(path, 'utf8');
  let outlineHtml = outline
    .replace('<html', '<html lang="en"')
    .replace('<meta charset="utf-8"/>', '<meta charset="utf-8">')
    .replace(
      '<?xml version="1.0" encoding="UTF-8"?>', 
      '<!doctype html>'
    ).replace(
      '</head>', `
        <title>${title}</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="index.bundle.css">
        </head>
    `).replaceAll(
        // the bike file is valid svg, but in html only a small set of tags
        // are allowed to be self-closing
        '<p/>',
        '<p></p>'
      ).replaceAll(
        // replace links to static images with <img> elements
        /<a href="static\/(.*?.(?:png|jpg|gif))\">Image: (.*?)<\/a>/g,
        `<img src="static/$1" title="$2">`
      );
1 Like