Skip to content

Commit

Permalink
Shortcodes for tabbed panes:
Browse files Browse the repository at this point in the history
- allow tab content in markdown
- improve storage of active language
- new option to turn storage of active language off
- improvements and fixes
- documentation update
  • Loading branch information
deining committed May 17, 2022
1 parent 553faa7 commit a4851dc
Show file tree
Hide file tree
Showing 14 changed files with 178 additions and 93 deletions.
1 change: 1 addition & 0 deletions assets/scss/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
@import "pageinfo";
@import "taxonomy";
@import "drawio";
@import "shortcodes";

@if $td-enable-google-fonts {
@import url($web-font-path);
Expand Down
2 changes: 2 additions & 0 deletions assets/scss/shortcodes.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@import "shortcodes/tabbed-pane.scss";
@import "shortcodes/cards-pane.scss";
19 changes: 19 additions & 0 deletions assets/scss/shortcodes/cards-pane.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.card-deck {
max-width: 83%;
}
.card {
max-width: 80%;
.highlight {
border: none;
}
}
.card-body.code {
background-color: #f8f9fa;
padding: 0 0 0 1ex;
}
.card-body {
pre {
margin: 0;
padding: 0 1rem 1rem 1rem;
}
}
39 changes: 39 additions & 0 deletions assets/scss/shortcodes/tabbed-pane.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.td-content {
.highlight {
margin: 0rem 0 2rem 0;
}
}
.tab-content {
.tab-pane {
.highlight {
border: none;
max-width: 100%;
}
pre {
border-left: 1px solid rgba(0, 0, 0, 0.125);
border-right: 1px solid rgba(0, 0, 0, 0.125);
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}
margin: 0rem;
max-width: 80%;
border-left: none;
border-right: none;
border-bottom: none;
}
}

.tab-body {
font-weight: $font-weight-medium;
background: $gray-100;
color: inherit;
border-radius: 0;
padding: 1.5rem;

@each $color, $value in $theme-colors {
&-#{$color} {

border-style: solid;
border-color: $value;
}
}
}
21 changes: 12 additions & 9 deletions layouts/shortcodes/tab.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!-- Make sure that we are enclosed within a tabpane shortcode block -->
{{ with $.Parent }}
{{- if ne $.Parent.Name "tabpane" -}}
{{- errorf "tab must be used within a tabpane block" -}}
{{- end -}}
{{- if ne $.Parent.Name "tabpane" -}}
{{- errorf "tab must be used within a tabpane block" -}}
{{- end -}}
{{- end -}}

<!-- Prefill header if not given as parameter -->
Expand All @@ -11,18 +11,21 @@
<!-- store all tab info in dict tab -->
{{ $tab := dict "header" $header }}
{{ with $.Get "lang" }}
{{ $tab = merge $tab (dict "language" ($.Get "lang")) }}
{{ $tab = merge $tab (dict "language" ($.Get "lang")) }}
{{ end }}
{{ with $.Get "highlight" }}
{{ $tab = merge $tab (dict "highlight" ($.Get "highlight")) }}
{{ $tab = merge $tab (dict "highlight" ($.Get "highlight")) }}
{{ end }}
{{ with $.Get "code" }}
{{ $tab = merge $tab (dict "code" ($.Get "code")) }}
{{ end }}
{{ with $.Inner }}
<!-- Trim any leading and trailing newlines from .Inner, this avoids
spurious lines during syntax highlighting -->
{{ $tab = merge $tab (dict "content" (trim $.Inner "\n")) }}
<!-- Trim any leading and trailing newlines from .Inner, this avoids
spurious lines during syntax highlighting -->
{{ $tab = merge $tab (dict "content" $.Inner ) }}
{{ end }}

<!-- add dict tab to parent's scratchpad -->
{{ with .Parent }}
{{- $.Parent.Scratch.SetInMap "tabs" (printf "%v" $.Ordinal) $tab -}}
{{- $.Parent.Scratch.SetInMap "tabs" (printf "%v" $.Ordinal) $tab -}}
{{ end }}
86 changes: 68 additions & 18 deletions layouts/shortcodes/tabpane.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,56 @@
<!-- Scratchpad gets populated through call to .Inner -->
<!-- Check parameter types -->
{{ with .Get "langEqualsHeader" }}
{{ if ne ( printf "%T" . ) "bool" }}
{{- errorf "shortcode tabpane: parameter langEqualsHeader must be either true or false" -}}
{{ end }}
{{ end }}

{{ with .Get "code" }}
{{ if ne ( printf "%T" . ) "bool" }}
{{- errorf "shortcode tabpane: parameter code must be either true or false" -}}
{{ end }}
{{ end }}

{{ with .Get "persistLang" }}
{{ if ne ( printf "%T" . ) "bool" }}
{{- errorf "shortcode tabpane: parameter persistLang must be either true or false" -}}
{{ end }}
{{ end }}

<!-- Set values given defined within tabpane -->
{{- $langPane := default "" ($.Get "lang") -}}
{{- $hloptionsPane := default "" ($.Get "highlight") -}}
{{- $codePane := default true ($.Get "code") -}}
{{- $langEqualsHeader := default false ($.Get "langEqualsHeader") -}}
{{- $persistLang := default true ($.Get "persistLang") -}}

<!-- Scratchpad gets populated through call to .Inner -->
{{- .Inner -}}

<ul class="nav nav-tabs" id="tabs-{{- $.Ordinal -}}" role="tablist">
{{- range $index, $element := $.Scratch.Get "tabs" -}}

{{- $lang := $langPane -}}
{{- if $langEqualsHeader -}}
{{- $lang = $element.header -}}
{{end}}
{{- with $element.language -}}
{{- $lang = $element.language -}}
{{- end -}}

<!-- Replace space and +, not valid for css selectors -->
{{- $lang := replaceRE "[\\s+]" "-" $lang -}}

<li class="nav-item">
<!-- Generate the IDs for the <a> and the <div> elements -->
{{- $tabid := printf "tabs-%v-%v-tab" $.Ordinal $index | anchorize -}}
{{- $entryid := printf "tabs-%v-%v" $.Ordinal $index | anchorize -}}
<!-- Replace space and + from tabname to set class -->
{{- $tabname := replaceRE "(\\s)" "-" $element.header -}}
{{- $tabname := replaceRE "(\\+)" "-" $tabname -}}
<a class="nav-link{{ if eq $index "0" }} active{{ end }} tab-{{ $tabname }}"
id="{{ $tabid }}" data-toggle="tab" href="#{{ $entryid }}" role="tab" onclick="handleClick({{ $tabname }});"
aria-controls="{{ $entryid }}" aria-selected="{{- cond (eq $index "0") "true" "false" -}}">
{{ index . "header" }}

<a class="nav-link{{ if eq $index "0" }} active{{ end }}{{ if ne $lang "" }}{{ if $persistLang }} persistLang-{{- $lang -}}{{ end }}{{ end }}"
id="{{- $tabid -}}" data-toggle="tab" href="#{{ $entryid }}" role="tab"
{{ if ne $lang "" }}{{- if $persistLang -}}onclick="handleClick({{- $lang -}});"{{end}}{{end}}
aria-controls="{{- $entryid -}}" aria-selected="{{- cond (eq $index "0") "true" "false" -}}">
{{- index . "header" -}}
</a>
</li>
{{- end -}}
Expand All @@ -23,24 +60,37 @@
<div class="tab-content" id="tabs-{{- $.Ordinal -}}-content">
{{- range $index, $element := $.Scratch.Get "tabs" -}}

{{- $lang := default $.Site.Language.Lang ($.Get "lang") -}}
{{with $.Get "langEqualsHeader"}}
{{ if $.Get "langEqualsHeader"}}
{{ $lang = $element.header }}
{{end}}
{{- $lang := $langPane -}}
{{- if $langEqualsHeader -}}
{{- $lang = $element.header -}}
{{end}}
{{- $hloptions := default "" ($.Get "highlight") -}}
{{- with $element.language -}}
{{ $lang = $element.language }}
{{- $lang = $element.language -}}
{{- end -}}

{{- $hloptions := $hloptionsPane -}}
{{- with $element.highlight -}}
{{ $hloptions = $element.highlight }}
{{- $hloptions = $element.highlight -}}
{{- end -}}

{{- $code := $codePane -}}
{{- with $element.code -}}
{{ if ne ( printf "%T" . ) "bool" }}
{{- errorf "shortcode tab: parameter code must be either true or false" -}}
{{ end }}
{{- $code = . }}
{{- end -}}

{{- $tabid := printf "tabs-%v-%v-tab" $.Ordinal $index | anchorize -}}
{{- $entryid := printf "tabs-%v-%v" $.Ordinal $index | anchorize -}}
<div class="tab-pane fade{{ if eq $index "0" }} show active{{ end }}"

<div class="{{ if not $code }}tab-body {{end}}tab-pane fade{{ if eq $index "0" }} show active{{ end }}"
id="{{ $entryid }}" role="tabpanel" aria-labelled-by="{{ $tabid }}">
{{- highlight (index . "content") $lang $hloptions -}}
{{ if $code }}
{{- highlight (trim (index . "content") "\n") $lang $hloptions -}}
{{- else -}}
{{- index . "content" -}}
{{- end -}}
</div>
{{ end }}
</div>
2 changes: 0 additions & 2 deletions static/css/shortcodes.css

This file was deleted.

21 changes: 0 additions & 21 deletions static/css/shortcodes/cards-pane.css

This file was deleted.

18 changes: 0 additions & 18 deletions static/css/shortcodes/tabbed-pane.css

This file was deleted.

4 changes: 2 additions & 2 deletions static/js/tabpane-persist.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ if (typeof Storage !== 'undefined') {
const activeLanguage = localStorage.getItem('active_language');
if (activeLanguage) {
document
.querySelectorAll('.tab-' + activeLanguage)
.querySelectorAll('.persistLang-' + activeLanguage)
.forEach((element) => {
$('#' + element.id).tab('show');
});
Expand All @@ -11,7 +11,7 @@ if (typeof Storage !== 'undefined') {
function handleClick(language) {
if (typeof Storage !== 'undefined') {
localStorage.setItem('active_language', language);
document.querySelectorAll('.tab-' + language)
document.querySelectorAll('.persistLang-' + language)
.forEach((element) => {
$('#' + element.id).tab('show');
});
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 35 additions & 23 deletions userguide/content/en/docs/Adding content/Shortcodes/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ in the response headers." you __CAN__ embed it, but when the test says "Great! X

## Tabbed panes

Sometimes it's very useful to have tabbed panes when authoring content. One common use-case is to show multiple syntax highlighted code blocks that showcase the same problem, and how to solve it in different programming languages. As an example, the table below shows the language-specific variants of the famous `Hello world!` program one usually writes first when learning a new programming language from scratch:
Sometimes it's very useful to have tabbed panes when authoring content. One common use-case is to show multiple syntax highlighted code blocks that showcase the same problem, and how to solve it in different programming languages. As an example, the tabbed pane below shows the language-specific variants of the famous `Hello world!` program one usually writes first when learning a new programming language:

{{< tabpane langEqualsHeader=true >}}
{{< tab header="C" >}}
Expand Down Expand Up @@ -330,39 +330,51 @@ object HelloWorld extends App {
The Docsy template provides two shortcodes `tabpane` and `tab` that let you easily create tabbed panes. To see how to use them, have a look at the following code block, which renders to a pane with three tabs:

```go-html-template
{{</* tabpane */>}}
{{</* tab header="English" */>}}
Welcome!
{{</* tabpane code=false */>}}
{{%/* tab header="English" lang="en" */%}}
![Flag United Kingdom](flags/uk.png)
Welcome!
{{%/* /tab */%}}
{{</* tab header="German" lang="de" */>}}
<b>Herzlich willkommen!</b>
<img src="flags/de.png" style="float: right; padding: 0 0 0 0px">
{{</* /tab */>}}
{{</* tab header="German" */>}}
Herzlich willkommen!
{{</* /tab */>}}
{{</* tab header="Swahili" */>}}
Karibu sana!
{{</* /tab */>}}
{{</* /tabpane */>}}
{{%/* tab header="Swahili" lang="sw" */%}}
![Flag Tanzania](flags/tz.png)
**Karibu sana!**
{{%/* /tab */%}}
{{%/* /tabpane */%}}
```

This code translates to the tabbed pane below, showing a `Welcome!` greeting in English, German or Swahili:

{{< tabpane >}}
{{< tab header="English" >}}
Welcome!
{{< /tab >}}
{{< tab header="German" lang="de" >}}
Herzlich willkommen!
{{< /tab >}}
{{< tab header="Swahili" >}}
Karibu sana!
{{< /tab >}}
{{< tabpane code=false >}}
{{% tab header="English" lang="en" %}}
![Flag United Kingdom](flags/uk.png)
**Welcome!**
{{% /tab %}}
{{< tab header="German" lang="de" >}}
<b>Herzlich willkommen!</b>
<img src="flags/de.png" style="float: right; padding: 0 0 0 0px">
{{< /tab >}}
{{% tab header="Swahili" lang="sw" %}}
![Flag Tanzania](flags/tz.png)
**Karibu sana!**
{{% /tab %}}
{{< /tabpane >}}

### Shortcode details

Tabbed panes are implemented using two shortcodes:

* The `tabpane` shortcode, which is the container element for the tabs. This shortcode can optionally hold the named parameters `lang` and/or `highlight`. The values of these optional parameters are passed on as second `LANG` and third `OPTIONS` arguments to Hugo's built-in [`highlight`](https://gohugo.io/functions/highlight/) function which is used to render the code blocks of the individual tabs. In case the header text of the tab equals the `language` used in the tab's code block (as in the first tabbed pane example above), you may specify `langEqualsHeader=true` in the surrounding `tabpane` shortcode. Then, the header text of the individual tab is automatically set as `language` parameter of the respective tab.
* The various `tab` shortcodes which actually represent the tabs you would like to show. We recommend specifying the named parameter `header` for each text in order to set the header text of each tab. If needed, you can additionally specify the named parameters `lang` and `highlight` for each tab. This allows you to overwrite the settings given in the parent `tabpane` shortcode. If the language is neither specified in the `tabpane` nor in the `tab`shortcode, it defaults to Hugo's site variable `.Site.Language.Lang`.
* The `tabpane` shortcode, which is the container element for the tabs. This shortcode can optionally hold the named parameters `lang` and/or `highlight`. The values of these optional parameters are passed on as second `LANG` and third `OPTIONS` arguments to Hugo's built-in [`highlight`](https://gohugo.io/functions/highlight/) function which is used to render the code blocks of the individual tabs. In case the header text of the tab equals the language used in the tab's code block (as in the first tabbed pane example above), you may specify `langEqualsHeader=true` in the surrounding `tabpane` shortcode. Then, the header text of the individual tab is automatically set as `lang` parameter of the respective tab.
* The various `tab` shortcodes represent the tabs you would like to show. Specify the named parameter `header` for each tab in order to set the header text of each tab. There are two modes for content display, `code` representation and _textual_ representation:
* By default, the tab's content is rendered as `code block`. In order to get proper syntax highlighting, specify the named parameter `lang` --and optionally the parameter `highlight`-- for each tab. Parameters set in the parent `tabpane` shortcode will be overwritten.
* If the contents of your tabs should be rendered as text with different styles and with optional images, specify `code=false` as parameter of your `tabpane` (or your `tab`). If your content is markdown, use the percent sign `%` as outermost delimiter of your `tab` shortcode, your markup should look like `{{%/* tab */%}}`Your \*\*markdown\*\* content`{{%/* /tab */%}}`. In case of HTML content, use square brackets `<>` as outermost delimiters: `{{</* tab */>}}`Your &lt;b&gt;HTML&lt;/b&gt; content`{{</* /tab */>}}`.

{{% alert title="Info" %}}
By default, the language of the selected tab is stored and preserved between different browser sessions. If the content length within your tabs differs greatly, this may lead to unwanted scrolling when switching between tabs. To disable this unwanted behaviour, specify `persistLang=false` within your `tabpane` shortcode.
{{% /alert %}}

## Card panes

Expand Down

0 comments on commit a4851dc

Please sign in to comment.