Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing tabbed-set label placement for cases where alternative renderers keep the HTML element order #2420

Closed
wants to merge 2 commits into from

Conversation

nbanyan
Copy link

@nbanyan nbanyan commented Jul 24, 2024

Adding hidden alt-style tabbed-set labels to the top of tabbed-blocks

  • Replicating the structure of .tabbed-labels to make replicating that CSS easier.
  • Using the hidden attribute on the new label's div wrapper because so it can easily be overridden by CSS and doesn't alter the existing appearance.
  • Apparently aria-hidden: false doesn't counteract display: none for AT, so I didn't add that. Such would likely need to be another, separate solution.

Scenario:
I'm working with Material for MkDocs using the alternate tabbed style. I also use domWalter's continuation of the mkdocs-with-pdf plugin using RelaxedJS. When exporting to PDF, tabbed-sets would print all the tab labels at the top followed by the tabbed-contents, just like it is in HTML despite the web browser's print view showing differently. So this is my fix for this - essentially creating something closer to the standard tabbed style for use only with @media print.

@gir-bot gir-bot added S: needs-review Needs to be reviewed and/or approved. C: docs Related to documentation. C: source Related to source code. C: tabbed Related to the tabbed extension. labels Jul 24, 2024
@facelessuser
Copy link
Owner

This addition will break documentation for people, even MkDocs Material, without them adding some new CSS.

Additionally, I don't think you've really made clear what you are "fixing" either. Can you demonstrate with some images or something showing what the change is?

@nbanyan
Copy link
Author

nbanyan commented Jul 25, 2024

Using a new mkdocs project with only the following YAML and no additional CSS:

site_name: My Docs
theme:
  name:        material

plugins: 
  - search
  # Uncomment this block and use `PDF_GENERATE=1 mkdocs build`
  # to export this MkDocs to HTML and PDF
  - with-pdf:
      enabled_if_env: PDF_GENERATE
      relaxedjs_path: "/opt/homebrew/bin/relaxed"
      render_js: True
      headless_chrome_path: "/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome" #"/opt/homebrew/bin/chromium"

markdown_extensions:
  - pymdownx.superfences
  - pymdownx.tabbed:
      alternate_style: true
Renderer Web Browser Print View PDF Export
Current Screenshot 2024-07-25 at 10 04 58 Screenshot 2024-07-25 at 10 05 13 Screenshot 2024-07-25 at 10 05 37
With Changes Screenshot 2024-07-25 at 10 12 19 Screenshot 2024-07-25 at 10 12 35 Screenshot 2024-07-25 at 10 13 41
Changes with CSS Screenshot 2024-07-25 at 11 13 49 Screenshot 2024-07-25 at 11 14 11 Screenshot 2024-07-25 at 11 14 32

The added CSS is:

<style>
  /* @media print { */
  .md-typeset .tabbed-set .tabbed-label-print {
    display: none;
  }
  /* } */
  .md-typeset .tabbed-set .tabbed-label-print > label,
  .md-typeset .tabbed-set .tabbed-labels > label {
    border-bottom: .1rem solid #0000;
    border-radius: .1rem .1rem 0 0;
    color: var(--md-default-fg-color--light);
    cursor: pointer;
    flex-shrink: 0;
    font-size: .64rem;
    font-weight: 700;
    padding: .78125em 1.25em .625em;
    scroll-margin-inline-start: 1rem;
    transition: background-color .25s,color .25s;
    white-space: nowrap;
    width: auto;
  }
  .md-typeset .tabbed-set .tabbed-label-print > label {
    padding-left: 0;
  }
  @media print {
    .md-typeset .tabbed-set .tabbed-labels {
      display: none;
    }
    .md-typeset .tabbed-set .tabbed-label-print {
      display: block;
    }
  }
</style>

@nbanyan
Copy link
Author

nbanyan commented Jul 25, 2024

Noticing the extra space the hidden div adds. It shouldn't do that and I can't find a way to make it not add that space, so I added a alternate_style_for_pdf config option to enable these additional labels when needed.

@facelessuser
Copy link
Owner

Unfortunately, you are claiming that export to PDF messes up tabs when printing, but I am not finding that true. I exported a site to PDF with absolutely no issues here.

pdf

Maybe you are claiming a specific PDF exporter is having trouble? But I'm not sure we should break documents because one exporter has trouble.

@nbanyan
Copy link
Author

nbanyan commented Jul 25, 2024

What PDF export tools/plugins did you use for that?
The reason I'm using with-pdf with the RelaxedJS option is that it's the only method I've found so far that can export pages with Mermaid diagrams and Draw.io SVGs to PDF.

@facelessuser
Copy link
Owner

Browsers seem to print to PDF just fine.

@nbanyan
Copy link
Author

nbanyan commented Jul 25, 2024

Right, that's the Print View. But that doesn't work well when you need to print multiple pages with a cover page and table of contents. That's what Weasyprint and RelaxedJS can do, but some things end up rendered differently even when using headless Chrome as a generator.

@facelessuser
Copy link
Owner

Is that an "pymdownx" problem or a "Weasyprint" problem? This injects unnecessary HTML elements that will break other documentation. Yes, they can add additional CSS to hide them, but what you are suggesting is a hack for this specific PDF exporter.

@facelessuser
Copy link
Owner

I will add, if there is a specific need for this, a workaround mkdocs plugin could be crafted to post process the content and add such elements. I would recommend going this route as a work around. If/when this is resolved in the exporter, the required mkdocs plugin could be retired.

@nbanyan
Copy link
Author

nbanyan commented Jul 26, 2024

For anyone else who happens to needs this:

  • Add this as an MkDocs hook:

    from mkdocs.config.defaults import MkDocsConfig, Page
    from mkdocs.structure.files import Files
    from typing import Union
    from bs4 import BeautifulSoup
    
    
    def on_page_content(html: str,
                        page: Page,
                        config: MkDocsConfig,
                        files: Files) -> Union[str, None]:
        """
        The page_content event is called after the Markdown text
        is rendered to HTML (but before being passed to a template)
        and can be used to alter the HTML body of the page.
    
        :param html: HTML rendered from Markdown source as string
        :type html: str
        :param page: mkdocs.structure.pages.Page instance
        :type page: Page
        :param config: global configuration object
        :type config: MkDocsConfig
        :param files: global files collection
        :type files: Files
        :return: Modified HTML
        :rtype: str | None
        """
    
        # Parse the HTML content
        parsed_html = BeautifulSoup(html, 'html.parser')
    
        # Process all 'tabbed-set' elements
        for tabbed_set in parsed_html.find_all('div', class_='tabbed-set'):
            # Ensure we're only processing the direct children of this tabbed-set
            direct_children = list(tabbed_set.children)
    
            # Find direct children that are 'tabbed-labels' and 'tabbed-content'
            tabbed_labels = None
            tabbed_content = None
    
            for child in direct_children:
                if child.name == 'div':
                    if 'tabbed-labels' in child.get('class', []):
                        tabbed_labels = child
                    elif 'tabbed-content' in child.get('class', []):
                        tabbed_content = child
    
            if tabbed_labels and tabbed_content:
                # Get all labels and content blocks
                labels = tabbed_labels.find_all('label', recursive=False)
                blocks = tabbed_content.find_all('div',
                                                 class_='tabbed-block',
                                                 recursive=False)
    
                # Ensure the number of labels matches the number of blocks
                if len(labels) == len(blocks):
                    for label, block in zip(labels, blocks):
                        # Create a new wrapper div
                        label_print_div = parsed_html.new_tag(
                                            'div',
                                            attrs={'class': 'tabbed-label-print'})
    
                        # Create a new label element with the same contents
                        new_label = parsed_html.new_tag('label')
                        new_label.string = label.get_text()
    
                        # Append the new label to the wrapper div
                        label_print_div.append(new_label)
    
                        # Insert the new wrapper div into the block
                        block.insert(0, label_print_div)
    
        # Return the modified HTML
        return str(parsed_html)
  • Add this to your CSS:

    .md-typeset .tabbed-set .tabbed-label-print {
      display: none;
    }
    .md-typeset .tabbed-set .tabbed-label-print > label,
    .md-typeset .tabbed-set .tabbed-labels > label {
      border-bottom: .1rem solid #0000;
      border-radius: .1rem .1rem 0 0;
      color: var(--md-default-fg-color--light);
      cursor: pointer;
      flex-shrink: 0;
      font-size: .64rem;
      font-weight: 700;
      padding: .78125em 1.25em .625em;
      scroll-margin-inline-start: 1rem;
      transition: background-color .25s,color .25s;
      white-space: nowrap;
      width: auto;
    }
    .md-typeset .tabbed-set .tabbed-label-print > label {
      padding-left: 0;
    }
    @media print {
      .md-typeset .tabbed-set .tabbed-labels {
        display: none;
      }
      .md-typeset .tabbed-set .tabbed-label-print {
        display: block;
      }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C: docs Related to documentation. C: source Related to source code. C: tabbed Related to the tabbed extension. S: needs-review Needs to be reviewed and/or approved.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants