squidfunk / mkdocs-material

Documentation that simply works
https://squidfunk.github.io/mkdocs-material/
MIT License
20.73k stars 3.52k forks source link

Code-tabs extension support request #778

Closed yacir closed 6 years ago

yacir commented 6 years ago

Hello @squidfunk, first off, thanks for your great job with material theme! 😊

I'm working on a new version of the markdown-fenced-code-tabs extension and i will be happy if it could be supported by the mkdocs-material.

The current version generates tabs exclusively as Bootstrap3 HTML template 😞.

But the new version i'm working on and which is already ready offerts the option to choose the rendering template. You can choose bootstrap3, bootstrap4 or default.

There is any chance that you support the default-template ? 😊

Here is the branch link for the new version.

Let me know if you need more details or if you have any suggestions.

squidfunk commented 6 years ago

Hey @yacir, that sounds awesome. It's a feature that was requested quite often and I like the general way how you implemented it. I would be happy to integrate it into Material if we can make it work, however I would favor a way that degrades gracefully in older browsers or if JavaScript is not available because Material is built with progressive enhancement in mind which is why it is so successful.

My general feeling is that I want to use radio buttons to allow interaction without JavaScript, see for example this link - I know it's ugly but it shows the basic idea. What you would need to provide is source that can be styled by Material. It must be dependency free (no Bootstrap) and work with HTMl and CSS only. Of course I can assist you on the way. Also I think that our users would favor minimal configuration, so the defaults should work with Material if possible.

A very good example of such a symbiosis is facelessuser/pymdown-extensions which is tightly integrated with Material. @facelessuser and me did a lot of iteration on extensions like Task List and Details for example.

Does this work for you?

yacir commented 6 years ago

Hey @squidfunk thank you for your quick feedback, i'm really happy with it.

I'm agree with you. The idea is that the developer who wants to use a Bootstrap based template, he can choose between the bootstrap3 or bootstrap4 and he will not have to add any extra css ou js. But for the one who wana use it with a dependency free template like material he will use the default one.

I made the default-template.html following the the W3C Exemple but i can definitely change it for something JS free like the link you gived me 😊

I ll made the needed changes and let you know.

Is it good for you?

squidfunk commented 6 years ago

Yes, of course. Just try to implement it without JavaScript and come back to me when you got a proposal we can discuss.

yacir commented 6 years ago

What do you think about this solution:

{% extends "base-template.html" %}

{% macro code_tabs(headers, contents, active_class, group_id) -%}
{% for header in headers %}
<input name="{{ group_id }}" 
       type="radio" 
       id="{{ header.id }}" 
       {{ 'checked="checked"' if loop.first else '' }}
       class="code-tab"
       data-lang="{{ header.lang }}"
       aria-controls="{{ contents[loop.index0].id }}-panel"
       role="tab"/>

<label for="{{ header.id }}" 
       class="code-tab-label" 
       data-lang="{{ header.lang }}"
       id="{{ header.id }}-label">{{ header.title|title }}</label>

<div class="code-tabpanel" 
     role="tabpanel" 
     data-lang="{{ header.lang }}"
     id="{{ contents[loop.index0].id }}-panel"
     aria-labelledby="{{ header.id }}-label">{{ contents[loop.index0].code }}
</div>
{% endfor %}
{%- endmacro %}

The generated code will be:

<div class="md-fenced-code-tabs" id="tab-group-0">
    <input name="tab-group-0" type="radio" id="tab-group-0-0_swift" checked="checked" class="code-tab" data-lang="swift" aria-controls="tab-group-0-0_swift-panel"
        role="tab">
    <label for="tab-group-0-0_swift" class="code-tab-label" data-lang="swift" id="tab-group-0-0_swift-label">Swift 2</label>
    <div class="code-tabpanel" role="tabpanel" data-lang="swift" id="tab-group-0-0_swift-panel" aria-labelledby="tab-group-0-0_swift-label">
        code...
    </div>
    <input name="tab-group-0" type="radio" id="tab-group-0-1_swift" class="code-tab" data-lang="swift" aria-controls="tab-group-0-1_swift-panel"
        role="tab">
    <label for="tab-group-0-1_swift" class="code-tab-label" data-lang="swift" id="tab-group-0-1_swift-label">Swift 3</label>
    <div class="code-tabpanel" role="tabpanel" data-lang="swift" id="tab-group-0-1_swift-panel" aria-labelledby="tab-group-0-1_swift-label">
        code...
    </div>
</div>

A basic CSS to manage the interaction could be like

.md-fenced-code-tabs { display: flex; flex-wrap: wrap;}
.code-tab {  position: absolute;  opacity: 0; }
.code-tabpanel { display: none; order: 99; }
.code-tab:checked + .code-tab-label + .code-tabpanel { display: block; }
squidfunk commented 6 years ago

Thanks! Do you have some site where I can see this? It's easier to check out and evaluate then.

facelessuser commented 6 years ago

@yacir I'd also make a note that this tab implementation will not allow nesting of tabbed fenced code. To use this extension, a user will have to sacrifice nested fenced code which pymdown-extensions provides via SuperFences. Both extensions will not work together. While there is nothing wrong with this if the user expects it, it should be at least noted so that this is pointed out in Material docs if it is decided that it will support it.

squidfunk commented 6 years ago

Hmm, I was hoping that it works somehow. Is there no way to support this in SuperFences?

facelessuser commented 6 years ago

They both use the same syntax, but with extra options in the header. So when using these tabbed fences, SuperFences would most likely ignore tabbed fenced if the fences included the fct_label in the header.

```lang fct_label="whatever"


Since the tab extension auto-generates a label if `fct_label` is not included, SuperFences would need to be run *before* this tab extension is run.  Then hopefully SuperFences would capture what it needed, and then this extension would capture whatever is left.

So in this case, fences without labels would work nested, but the tabbed ones would not be nested.  SuperFences would need to add this tabbed functionality for it to work with both, or be forked and altered and used instead of SuperFences.  We had talked before about tabbed fenced blocks, and I was never against it, but what I generally don't like is the approach of assuming consecutive code blocks are meant to be tabbed.  I much prefer an explicit way of saying this "this code block is meant to be tabbed".  That way just posting two fences right after one another won't auto-magically become tabs.  Most likely this could be done with a slight tweak to the fence syntax to signify a tabbed fence.

We never really settled on a standardized HTML output, so I never investigated this further. 
facelessuser commented 6 years ago

In short, if we have a reasonable HTML output, we could deal with how to augment the Markdown syntax and add tabbed support.

yacir commented 6 years ago

@squidfunk here is a sample file md-code-tabs.html.zip.

@facelessuser Thanks for the feedback! Agree with you and with you approach:

what I generally don't like is the approach of assuming consecutive code blocks are meant to be tabbed.

I think there's a way to do it right, adding an option in code first line to explicitly tel us that this following fences should be rendered as a tabs. The extension will only render those fences and ignore the others. I'm thinking about something like that:

```lang as_tab=true tab_label="whatever"
```

What do you think about it?

facelessuser commented 6 years ago
```lang as_tab=true tab_label="whatever"

@yacir I think something like this is reasonable.

I think at this point, I'm most interested in seeing @squidfunk's evaluation of the HTML output. I'm generally not interested in multiple tab output modes. I would generally prefer a generalized, singular output. Maybe just support default-template. I'm not sure I want to support specific things like bootstrap iterations etc.

squidfunk commented 6 years ago

Thanks for your input. I fiddled a little and this is my proposal (see CodePen for demo). Narrow your browser window to < 900px to see the mobile.

Requirements

My proposal is based on the following requirements:

  1. The language should be changeable without JavaScript (and thus degrade gracefully)
  2. It should be visible which language is selected
  3. On small screens, the languages should be collapsed behind a selection
  4. On big screens, the languages should be next to each other
  5. It should work with 5-6 languages without breaking (i.e. when the tabs won't fit the screen)

Solution

Here is how I addressed the requirements

  1. As discussed, the solution is based on radio buttons which target input fields that make the respective code section appear or disappear. For this to work, the input field must be located in front of the code section and on the same level.

  2. In order to make the label styleable, the corresponding input must also be located in front of the label. This leads to the only possible design where the order is input, label, code section.

  3. Because we want to collapse all non-active languages on mobile behind a selection, we need a state of the radio button that hides all code sections and displays all labels. This input field must precede all other labels. I thought of this design because in my opinion it's the only possible option. In theory, we could put languages and code sections in separate containers so we could make the languages container horizontally scrollable but this would violate 2., because the labels would not be located to the input elements which is not fixable due to requirement 1.

  4. As we must place everything like discussed, the code sections and input and label tags are interleaved, so we need to use display: flex and wrap the code section around with maximum width. We apply order: 99 to the active code section so that it comes after all labels and hide all other code sections. For this to work, all labels must be on the same level, which is a further requirement and satisfies 1., 2. and 3.

  5. On mobile, we show a Change language label, which when active displays all other labels and hides all other code sections. The display is no perfect in the CodePen demo I made, there's still some room for experimentation, but the basic idea is clear.

When we have JavaScript available, we could synchronize all code tabs, so if the language in one code section is changed, it changes all other code sections. For this to be reasonably easy, the best thing would be to add a data-language="${language} to each label, so we can better register event listeners with JavaScript.

I'm also happy with the proposed syntax by @yacir, maybe renaming the flags a little:

``` lang as_tab=true tab_label="Custom label"

I know that the HTML I'm proposing may seem a little weird, but all of it is necessary for this solution to work. The most headache will probably be the Change language label/code, because without styling there's no real application for it. Maybe we could do it like we did it with Task List - optional CSS classes which are mandatory for Material to be set but leave a little flexibility for other implementations.

Questions

Questions I have:

  1. What if two code sections with the same language are specified?
  2. What if in three consecutive code sections, the middle section doesn't define the as_tab flag?
  3. Is this integrateable into SuperFences, so that we could even render indented tabbed code sections (e.g. in lists)?

Source

Disclaimer: I just hacked this together, so the CSS might change, but the HTML is final

<div class="superfences-tabs">
  <input name="tabs_1" type="radio" id="tab_1_0" />
  <label for="tab_1_0">Change language</label>
  <input name="tabs_1" type="radio" id="tab_1_1" checked="checked" />
  <label for="tab_1_1">Bash</label>
  <div class="codehilite">
    <pre>
#!/bin/bash
STR="Hello World!"
echo $STR
    </pre>
  </div>
  <input name="tabs_1" type="radio" id="tab_1_2" />
  <label for="tab_1_2">C</label>
  <div class="codehilite">
    <pre>
#include <stdio.h>

int main(void) {
  printf("hello, world\n");
}
    </pre>
  </div>
  <input name="tabs_1" type="radio" id="tab_1_3" />
  <label for="tab_1_3">C++</label>
  <div class="codehilite">
    <pre>
#include &lt;iostream&gt;

int main() {
  std::cout &lt;&lt; "Hello, world!\n";
  return 0;
}
    </pre>
  </div>
  <input name="tabs_1" type="radio" id="tab_1_4" />
  <label for="tab_1_4">C#</label>
  <div class="codehilite">
    <pre>
using System;

class Program {
  static void Main(string[] args) {
    Console.WriteLine("Hello, world!");
  }
}
    </pre>
  </div>
</div>
* {
  box-sizing: border-box;
}

body {
  padding: 10px;
  background: #f2f2f2;
  font-family: Helvetica;
}

.superfences-tabs {
  display: flex;
  position: relative;
  flex-wrap: wrap;
}

.superfences-tabs input {
  position: absolute;
  opacity: 0;
}

.superfences-tabs label {
  width: 100%;
  padding: 4px;
  margin: 0 8px;
  cursor: pointer;
}

.superfences-tabs input:nth-child(n+1):checked + label {
  color: #333;
}

@media (min-width: 900px) {
  .superfences-tabs label {
    width: auto;
  }
}

.superfences-tabs .codehilite {
  display: none;
  width: 100%;
  background: #ddd;
  margin-top: 10px;
}

.superfences-tabs .codehilite pre {
  font-family: Monaco;
  font-size: 13px;
  padding: 10px 12px;
  margin: 0;
}

@media (min-width: 900px) {
  .superfences-tabs .codehilite {
    order: 99;
  }

  .superfences-tabs input:nth-child(n+1):checked + label {
    color: #ff5252;
  }
}

.superfences-tabs input:nth-child(n+1):checked + label + .codehilite {
  display: block;
}

.superfences-tabs input:first-child + label {
  display: none;
}

@media (max-width: 899px) {
  .superfences-tabs input:first-child + label {
    display: initial !important;
    position: absolute;
    width: auto;
    display: initial;
    right: 0;
    color: #ff5252;
  } 

  .superfences-tabs input:first-child ~ label {
    display: none;
  }

  .superfences-tabs input:first-child:checked ~ label {
    display: initial;
  }

  .superfences-tabs input:checked + label {
    display: initial !important;
  }
}

The next requirement that is very likely to come is tabbed content. I'd bet on it. All in all I now think we have a great direction for implementing this feature which was, as I said, demanded quite often.

squidfunk commented 6 years ago

For explanation: my last post was mainly targetted at @facelessuser regarding the integration of this feature into SuperFences. This would make the proposed markdown-fenced-code-tabs extension obsolete, but as PymdownX is tightly integrated with Material and offers some nice features like SuperFences, it's the best possible way. @yacir: I hope you don't take this the wrong way, but I would rather favor integration into SuperFences than rolling something own. Interferences with SuperFences is also a real killer for integrating this feature.

facelessuser commented 6 years ago

@squidfunk, thanks for the detailed post. I will review it and let you know what I think when I get around to implemented this. I have a couple of things that are currently eating up my time, but when I have a chance, I'll come back to this and collaborate further to see what we can do.

The demo looked cool, and I definitely like the idea of this. I will create an issue over on pymdown-extensions and link it back here.

facelessuser commented 6 years ago

I can answer at least a couple of questions:

What if two code sections with the same language are specified?

I don't think this is a problem. We'll keep it dumb. If the user puts two blocks with the same language, it is on them. I'm fine with managing things to prevent duplicate id's etc., but I'm not big on protecting the user from themselves. The example currently is that people would use this for only different languages, but I think people could use this for lots of different purposes, I'm not going to police or babysit how people use it 😄 .

What if in three consecutive code sections, the middle section doesn't define the as_tab flag?

That's on them. First will be a tab set with one entry. Second would be a normal code block, third will be a tab set with one entry. It doesn't make sense to have a single tab, but I won't prevent people from doing such. See answer to first question.

Is this integrateable into SuperFences, so that we could even render indented tabbed code sections (e.g. in lists)?

Yes, this should be doable in SuperFences. The idea is to add the option into SuperFences. Exactly how that will work and look yet, I'm not sure, but user side, I imagine it will be similar to what has been suggested. Exact implementation is subject to change, but I'll keep you posted if I plan to deviate at all from the initial proposal. I haven't looked it over it great detail yet, but I'll keep things open for input as well.

Impressions on Demo

squidfunk commented 6 years ago

Thanks @facelessuser, glad you also think this is a good direction to progress. Regarding the Change language label - I don't know if it makes sense that you generate this in SuperFences because we need to localize (i18n) it properly, so it should be generated by Material. I thought a little about it and have the following idea:

We generate the bare-minimum HTML (so for for each code block a label + input + code section) and on mobile, if no JS is available, fall back to an accordion-based approach (see this link which I took for inspiration). If we have JavaScript available, which should be the default case, we generate the additional input/label and collapse all languages behind that selection as proposed. So Superfences would need to generate this:

<div class="superfences-tabs">
  <input name="tabs_${index}" type="radio" id="tab_${index}_${tab_index}" />
  <label for="tab_${index}_${tab_index}">Bash</label>
  <div class="codehilite"> <!-- or <pre>, should depend on environment -->
    ...
  </div>
   ...
</div>

Feel free to change the class names, but it would be nice if they would be in the style of the Task List extension, for consistency. I thought about giving the label also a class name, but it's theoretically targetable like this, so, I'm undecided.

The first item should be marked with checked="checked". This should also work if Codehililite is not enabled (thus rendering pre and code tags instead of the div, as it works with Material now, so people can use other JS-based syntax highlighters if they want to.

squidfunk commented 6 years ago

Oh regarding your ideas concerning my questions - I totally agree. I tend to overthink possible pitfalls when users try to use that extension and minimize them, but that's probably not necessary for developers. Let's keep it as simple as possible.

facelessuser commented 6 years ago

I don't know if it makes sense that you generate this in SuperFences because we need to localize (i18n) it properly

Ahh, sorry, I actually misinterpreted your question. I see now that there is a "Change Language". You are correct, I would absolutely omit that as it should be a generalized output.

We generate the bare-minimum HTML (so for for each code block a label + input + code section) and on mobile, if no JS is available, fall back to an accordion-based approach (see this link which I took for inspiration).

This is what I originally thought you'd do, so I think we are on the same page.

Oh regarding your ideas concerning my questions - I totally agree. I tend to overthink possible pitfalls when users try to use that extension and minimize them, but that's probably not necessary for developers. Let's keep it as simple as possible.

Yeah, it all depends on who your customer is. If I am dealing with a user interface, I put a lot of checks in as the user needs protection from themselves. If I'm writing for a developer, I avoid catastrophic stuff, but I'd rather give them flexibility and let them do the work of "user proofing" their code.

squidfunk commented 6 years ago

Okay, great! This means we should have a pretty solid concept now and I will wait for your implementation. When you have a working prototype ready, I will integrate it into Material, add some documentation and push out a new release. Feel free to come back if you have any questions.

markpiller commented 6 years ago

Hey guys, will this implementation allow to eliminate current problems with using markdown_fenced_code_tabs with superfences in the same mkdocs project? The problem we're facing is the handling of the ordered and non-ordered lists is broken when both superfences and fenced code tabs extensions are added. Consider the following example (directly from our docs):


  1. Data objects can be stored/retrieved as instances of java.util.Map. For example, the following code saves an object with properties "name" and "age" in the "Person" table:
    HashMap person = new HashMap();
    person.put( "name", "Joe" );
    person.put( "age", 25 );
    Backendless.Data.of( "Person" ).save( person );

    This approach is referenced as "Java Map" further in the documentation. or

  2. Data objects can be represented as instances of custom classes mapped to data tables. Object's class does not need to implement any special Backendless interfaces or extend a class from the Backendless SDK.

    When both markdown_fenced_code_tabs and superfences are enabled, it is rendered like this (which is great, but code tabs in other parts of the doc do not work): http://take.ms/cHD4C

However, without superfences, it looks broken: http://take.ms/DtDWJ

facelessuser commented 6 years ago

The original fenced_code extension that is shipped with Python Markdown doesn't handle nesting (nested under things like lists, dictionary, admonitions, etc.). markdown_fenced_code_tabs likely builds off the the original, so it shares the same issues. This is due to a weakness in Python Markdown. I won't go into details here.

With SuperFences, I went through great pains to make it work in most situations, working around Python Markdown's weaknesses. That is why SuperFences is required for proper nested code. With that said, by adding tab support into the SuperFences syntax, you will automatically get tabs with the benefit of nesting support.

I just need to carve out the time to make it happen.

markpiller commented 6 years ago

@facelessuser thank you for the response. I would love to see these changes, I am sure many other users would too.

yacir commented 6 years ago

@squidfunk thank for the help.

@markainick because this feature is still unavailable with superfences i've pushed un new version of the markdown_fenced_code_tabs extension you can take a look to the documentation.

Hope it helps.

markpiller commented 6 years ago

@yacir is this update supposed to work when the pymdownx.superfences extension is enabled? I updated to the latest version of the markdown_fenced_code_tabs extension and when the superfences are turned on, the code tabs are not rendered at all.

yacir commented 6 years ago

@markpiller unfortunately it still don't work with superfences.

facelessuser commented 6 years ago

(WIP) Superfences + tabs 😮

screenshot 2018-06-01 00 24 53

```Bash tab=""
#!/bin/bash
STR="Hello World!"
echo $STR
#include 

int main(void) {
  printf("hello, world\n");
}
#include <iostream>

int main() {
  std::cout << "Hello, world!\n";
  return 0;
}
using System;

class Program {
  static void Main(string[] args) {
    Console.WriteLine("Hello, world!");
  }
}
#!/bin/bash
STR="Hello World!"
echo $STR

Break

#include 

int main(void) {
  printf("hello, world\n");
}

Break

#include <iostream>

int main() {
  std::cout << "Hello, world!\n";
  return 0;
}

Break

using System;

class Program {
  static void Main(string[] args) {
    Console.WriteLine("Hello, world!");
  }
}
squidfunk commented 6 years ago

Looks great, really works for me! The syntax is also nice - only one option for tab rendering and title.

facelessuser commented 6 years ago

Thanks! Yeah, multiple options in the header kind of rubbed me wrong. I couldn't find a reason to justify requiring two. I may in the end allow tab= if you don't want to define a title. There are still some little details I need to think about, and some more tests that need to be done, but overall, I'm pretty pleased with the results. It turned out much easier to implement than I thought.

squidfunk commented 6 years ago

That sounds great :-) Happy to integrate it into Material finally solving this problem.

max-ci commented 6 years ago

Will Change language label on mobile be editable? I'm asking because sometimes you want to use tabs for different things than programming languages.

facelessuser commented 6 years ago

My personal opinion is it should be something more general like "change tab", or just an icon that gets the idea across.

max-ci commented 6 years ago

Or maybe something like https://codepen.io/lukejacksonn/pen/PwmwWV Bad: requires JS for hiding elements.

Edit: only CSS version - https://codepen.io/chriscoyier/pen/GJRXYE

squidfunk commented 6 years ago

Will Change language label on mobile be editable? I'm asking because sometimes you want to use tabs for different things than programming languages.

It will definitely be translatable via i18n and localized. However, as I understand tabs are only supported for code blocks, not regular content so there's always code inside those tabs, or am I wrong?

squidfunk commented 6 years ago

Edit: only CSS version - https://codepen.io/chriscoyier/pen/GJRXYE

I very much like this one, may take something out of it for the implementation.

facelessuser commented 6 years ago

Well..."code blocks" yes, but "code blocks" can contain anything, not just code. It's more preformatted text, commonly used for code. In addition, we could render things like flow charts in it...which technically isn't even in code blocks. It may make sense to wrap content of a tab in another div with a class and target that instead of the code blocks directly...

That is some of the things I am still figuring out. But code blocks, they look pretty awesome so far 🙂 .

facelessuser commented 6 years ago

Okay, so SuperFences allows users to create special, custom fences which is used to create flow charts and/or sequence diagrams. In order to get these to work, I had to add a div around the tab content so I could craft a generalized approach. Instead of targeting the code block and hiding that, you'd just target the content div with the class .superfences-content; that way it works with code blocks or whatever has been customized to be rendered in the fence's place.

screenshot 2018-06-01 17 17 00

facelessuser commented 6 years ago

@squidfunk, I think I'm done with support for now: https://github.com/facelessuser/pymdown-extensions/pull/302. You are free to start playing with it and give feedback if it turns out something needs to change. As noted, I did add an extra div to the output that wraps the tab content. It makes sense that the div should be targeted for hiding and showing instead of the content inside (code blocks etc.).

squidfunk commented 6 years ago

Sounds great. I could try and integrate it – how do it do that? I guess I clone the repository, uninstall the version I installed with pip and install it from source? Not very experienced with Python ;-)

facelessuser commented 6 years ago

You can actually upgrade your local version based on the tag with pip. Cloning it yourself is not required. When I'm by my computer again, I'll illustrate how this is done.

facelessuser commented 6 years ago

@squidfunk, you can install with the following. It just performs an install upgrade, and you specify that you are using git + the git URL @ the branch.

python -m pip install -U git+https://github.com/facelessuser/pymdown-extensions.git@fenced-tabs
markpiller commented 6 years ago

@facelessuser, I am having a difficulty getting it working. I have installed per the instruction you provided above, here's the output of the installation command:

Collecting git+https://github.com/facelessuser/pymdown-extensions.git@fenced-tabs
  Cloning https://github.com/facelessuser/pymdown-extensions.git (to revision fenced-tabs) to /private/var/folders/4k/pxnpxlp963n_l2zh87rdc_v00000gn/T/pip-req-build-E1lCmk
Requirement not upgraded as not directly required: Markdown>=2.6.10 in /usr/local/lib/python2.7/site-packages (from pymdown-extensions==4.10.2) (2.6.11)
Building wheels for collected packages: pymdown-extensions
  Running setup.py bdist_wheel for pymdown-extensions ... done
  Stored in directory: /private/var/folders/4k/pxnpxlp963n_l2zh87rdc_v00000gn/T/pip-ephem-wheel-cache-6d9QhQ/wheels/de/f0/9f/718b0ab1c3218cbd3f7d5fd56c80d973fc2d85fcd8f1924153
Successfully built pymdown-extensions
Installing collected packages: pymdown-extensions
  Found existing installation: pymdown-extensions 4.10.2
    Uninstalling pymdown-extensions-4.10.2:
      Successfully uninstalled pymdown-extensions-4.10.2
Successfully installed pymdown-extensions-4.10.2

My mkdocs extensions are:

markdown_extensions:
  - admonition
  - codehilite:
      linenums: False
      guess_lang: False
  - toc:
      permalink: True
  - pymdownx.details
  - pymdownx.superfences

The markdown content is written as follows:

#### Blocking API
````
```java tab="Using Java Map"
Long result = Backendless.Persistence.of( "TABLE-NAME" ).remove( Map entity )
```

```java tab="Custom Class"
Long result = Backendless.Persistence.of( E ).remove( E entity );
```

````
#### Non-Blocking API
````
```java tab="Using Java Map"
public void Backendless.Persistence.of( "TABLE-NAME" ).remove( Map entity, AsyncCallback responder )
```

```java tab="Custom Class"
Backendless.Persistence.of( E ).remove( E entity, AsyncCallback responder );
```
````

And with that the content is rendered like this: http://take.ms/cMmGZ

Could you please let me know if I am doing something wrong here?

facelessuser commented 6 years ago

Why do you have two tab fences wrapped in another fence? Basically you have one non tabbed fence with the text showing tab fence syntax. Also, you'll have to add sufficient CSS.

markpiller commented 6 years ago

I was following the example from here: https://github.com/facelessuser/pymdown-extensions/blob/fenced-tabs/docs/src/markdown/extensions/superfences.md#tabbed-fences

Specifically, this: http://take.ms/jjaO1

I added the CSS, the problem is with the HTML that's generated.

facelessuser commented 6 years ago

@markpiller, thinking about this, most likely you probably got your example from the GitHub rendering of the docs? It isn't always easy looking at that as it isn't rendered properly with the non-standard features that my docs use.

Here is a good example of syntax that should work: test file. It's just various test cases. As you can see, this test file renders as this: html. This is the current CSS used to render the test: css.

facelessuser commented 6 years ago

@markpiller, Just for reference, this is how the document you referenced looks when rendered for publishing:

screenshot 2018-06-02 19 06 04

markpiller commented 6 years ago

@facelessuser my bad, it works great for all our use-cases. Thank you very much!

facelessuser commented 6 years ago

@markpiller, no problem, glad it's working and you find it useful. Keep in mind that this is currently in beta. Some things are subject to change between now and release.

facelessuser commented 6 years ago

After evaluating this feature, I think I'm going to lock in the current format and cut a release over the weekend. I'm doubtful there will be any real changes to the structure at this point.

squidfunk commented 6 years ago

Implemented in #793, it now looks like this:

bildschirmfoto 2018-06-10 um 17 24 09

I made it very simple and tried to add as few noise as possible by leaving the bottom borders out. Also I didn't realize the mobile version I discussed before because I don't really think it's necessary and most of the time the proposed solution should work. It could only be a problem when people have too many tabs.

facelessuser commented 6 years ago

Very cool. I should be releasing latest pymdown-extensions later today.