diff --git a/assets/scss/main.scss b/assets/scss/main.scss index f1a1aa6f7d..ed21add190 100644 --- a/assets/scss/main.scss +++ b/assets/scss/main.scss @@ -28,6 +28,7 @@ @import "pageinfo"; @import "taxonomy"; @import "drawio"; +@import "shortcodes"; @if $td-enable-google-fonts { @import url($web-font-path); diff --git a/assets/scss/shortcodes.scss b/assets/scss/shortcodes.scss new file mode 100644 index 0000000000..5d1f94f62c --- /dev/null +++ b/assets/scss/shortcodes.scss @@ -0,0 +1,2 @@ +@import "shortcodes/tabbed-pane.scss"; +@import "shortcodes/cards-pane.scss"; diff --git a/assets/scss/shortcodes/cards-pane.scss b/assets/scss/shortcodes/cards-pane.scss new file mode 100644 index 0000000000..00f00f9f2f --- /dev/null +++ b/assets/scss/shortcodes/cards-pane.scss @@ -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; + } +} diff --git a/assets/scss/shortcodes/tabbed-pane.scss b/assets/scss/shortcodes/tabbed-pane.scss new file mode 100644 index 0000000000..15e54700f6 --- /dev/null +++ b/assets/scss/shortcodes/tabbed-pane.scss @@ -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; + } + } +} diff --git a/layouts/shortcodes/tab.html b/layouts/shortcodes/tab.html index a907de70b5..5a644bc788 100644 --- a/layouts/shortcodes/tab.html +++ b/layouts/shortcodes/tab.html @@ -1,28 +1,39 @@ {{ with $.Parent }} -{{- if ne $.Parent.Name "tabpane" -}} -{{- errorf "tab must be used within a tabpane block" -}} -{{- end -}} + {{- if ne $.Parent.Name "tabpane" -}} + {{- errorf "shortcode 'tab' must be used within a 'tabpane' block" -}} + {{- end -}} {{- end -}} - -{{ $header := default (printf "Tab %v" ( add $.Ordinal 1)) (.Get "header") }} +{{ $header := "Tab" }} +{{ if and (not .IsNamedParams) (.Get 0) }} + {{ $header = (.Get 0) }} +{{ else }} + + {{ $header = default (printf "Tab %v" ( add $.Ordinal 1)) (.Get "header") }} +{{ end }} {{ $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 $.Get "disabled" }} + {{ $tab = merge $tab (dict "disabled" ($.Get "disabled")) }} {{ end }} {{ with $.Inner }} - -{{ $tab = merge $tab (dict "content" (trim $.Inner "\n")) }} + + {{ $tab = merge $tab (dict "content" $.Inner ) }} {{ end }} {{ with .Parent }} -{{- $.Parent.Scratch.SetInMap "tabs" (printf "%v" $.Ordinal) $tab -}} + {{- $.Parent.Scratch.SetInMap "tabs" (printf "%v" $.Ordinal) $tab -}} {{ end }} \ No newline at end of file diff --git a/layouts/shortcodes/tabpane.html b/layouts/shortcodes/tabpane.html index 51709a6e4c..88c93e0e94 100644 --- a/layouts/shortcodes/tabpane.html +++ b/layouts/shortcodes/tabpane.html @@ -1,46 +1,123 @@ - + +{{ 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 }} + + +{{- $langPane := default "" ($.Get "lang") -}} +{{- $hloptionsPane := default "" ($.Get "highlight") -}} +{{- $codePane := default true ($.Get "code") -}} +{{- $langEqualsHeader := default false ($.Get "langEqualsHeader") -}} +{{- $persistLang := default true ($.Get "persistLang") -}} +{{- $disabled := false -}} +{{- $activeSet := false -}} + + {{- .Inner -}} +{{ $activeSet = false }} +
{{- 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 -}} + + {{- $disabled := false -}} + {{- with $element.disabled -}} + {{- $disabled = . }} + {{- 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 -}} -
- {{- highlight (index . "content") $lang $hloptions -}} + {{ if $code }} + {{- highlight (trim (index . "content") "\n") $lang $hloptions -}} + {{- else -}} + {{- index . "content" -}} + {{- end -}}
+ + {{ if not $disabled }} + {{ $activeSet = true }} + {{ end }} + {{ end }}
diff --git a/package.json b/package.json index 4f432bef68..e71aae7a3b 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,6 @@ "bootstrap": "^4.6.1" }, "devDependencies": { - "hugo-extended": "0.98.0" + "hugo-extended": "0.99.1" } } diff --git a/static/css/shortcodes.css b/static/css/shortcodes.css deleted file mode 100644 index 0aa1c0f830..0000000000 --- a/static/css/shortcodes.css +++ /dev/null @@ -1,2 +0,0 @@ -@import "shortcodes/tabbed-pane.css"; -@import "shortcodes/cards-pane.css"; diff --git a/static/css/shortcodes/cards-pane.css b/static/css/shortcodes/cards-pane.css deleted file mode 100644 index 34c85450dd..0000000000 --- a/static/css/shortcodes/cards-pane.css +++ /dev/null @@ -1,21 +0,0 @@ -.card-deck { - max-width: 83%; -} - -.card { - max-width: 80%; -} - -.card-body.code { - background-color: #f8f9fa; - padding: 0 0 0 1ex; -} - -.card-body pre { - margin: 0; - padding: 0 1rem 1rem 1rem; -} - -.card .highlight { - border: none; -} diff --git a/static/css/shortcodes/tabbed-pane.css b/static/css/shortcodes/tabbed-pane.css deleted file mode 100644 index 3016398728..0000000000 --- a/static/css/shortcodes/tabbed-pane.css +++ /dev/null @@ -1,18 +0,0 @@ -.td-content .highlight { - margin: 0rem 0 2rem 0; -} - -.tab-content .highlight { - border: none; -} - -.tab-content { - margin: 0rem; - max-width: 80%; -} - -.tab-content 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); -} diff --git a/static/js/tabpane-persist.js b/static/js/tabpane-persist.js index 8a02bb6d41..0df34c6241 100644 --- a/static/js/tabpane-persist.js +++ b/static/js/tabpane-persist.js @@ -2,16 +2,16 @@ 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'); }); } } -function handleClick(language) { +function persistLang(language) { if (typeof Storage !== 'undefined') { localStorage.setItem('active_language', language); - document.querySelectorAll('.tab-' + language) + document.querySelectorAll('.persistLang-' + language) .forEach((element) => { $('#' + element.id).tab('show'); }); diff --git a/userguide/content/en/docs/Adding content/Shortcodes/flags/de.png b/userguide/content/en/docs/Adding content/Shortcodes/flags/de.png new file mode 100644 index 0000000000..0256951301 Binary files /dev/null and b/userguide/content/en/docs/Adding content/Shortcodes/flags/de.png differ diff --git a/userguide/content/en/docs/Adding content/Shortcodes/flags/tz.png b/userguide/content/en/docs/Adding content/Shortcodes/flags/tz.png new file mode 100644 index 0000000000..d8786c42b9 Binary files /dev/null and b/userguide/content/en/docs/Adding content/Shortcodes/flags/tz.png differ diff --git a/userguide/content/en/docs/Adding content/Shortcodes/flags/uk.png b/userguide/content/en/docs/Adding content/Shortcodes/flags/uk.png new file mode 100644 index 0000000000..eaa4a7e5aa Binary files /dev/null and b/userguide/content/en/docs/Adding content/Shortcodes/flags/uk.png differ diff --git a/userguide/content/en/docs/Adding content/Shortcodes/index.md b/userguide/content/en/docs/Adding content/Shortcodes/index.md index 735e2a88f2..de79d11827 100644 --- a/userguide/content/en/docs/Adding content/Shortcodes/index.md +++ b/userguide/content/en/docs/Adding content/Shortcodes/index.md @@ -266,10 +266,10 @@ 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" >}} + {{< tab "C" >}} #include #include @@ -279,7 +279,7 @@ int main(void) return EXIT_SUCCESS; } {{< /tab >}} -{{< tab header="C++" >}} +{{< tab "C++" >}} #include int main() @@ -287,82 +287,98 @@ int main() std::cout << "Hello World!" << std::endl; } {{< /tab >}} -{{< tab header="Go" >}} +{{< tab "Go" >}} package main import "fmt" func main() { fmt.Printf("Hello World!\n") } {{< /tab >}} -{{< tab header="Java" >}} +{{< tab "Java" >}} class HelloWorld { static public void main( String args[] ) { System.out.println( "Hello World!" ); } } {{< /tab >}} -{{< tab header="Kotlin" >}} +{{< tab "Kotlin" >}} fun main(args : Array) { println("Hello, world!") } {{< /tab >}} -{{< tab header="Lua" >}} +{{< tab "Lua" >}} print "Hello world" {{< /tab >}} -{{< tab header="PHP" >}} +{{< tab PHP >}} {{< /tab >}} -{{< tab header="Python" >}} +{{< tab "Python" >}} print("Hello World!") {{< /tab >}} -{{< tab header="Ruby" >}} +{{< tab "Ruby" >}} puts "Hello World!" {{< /tab >}} -{{< tab header="Scala" >}} +{{< tab "Scala" >}} object HelloWorld extends App { println("Hello world!") } {{< /tab >}} {{< /tabpane >}} -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: +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 one disabled and three active tabs: ```go-html-template -{{}} - {{}} - Welcome! +{{}} + {{}} {{}} - {{}} - Herzlich willkommen! + {{%/* tab header="English" lang="en" */%}} + ![Flag United Kingdom](flags/uk.png) + Welcome! + {{%/* /tab */%}} + {{}} + Herzlich willkommen! + {{}} - {{}} - Karibu sana! - {{}} -{{}} + {{%/* 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="**Languages**:" disabled=true %}} + {{% /tab %}} + {{% tab header="English" lang="en" %}} + ![Flag United Kingdom](flags/uk.png) + **Welcome!** + {{% /tab %}} + {{< tab header="German" lang="de" >}} + Herzlich willkommen! + + {{< /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 the tab. If the `header` parameter is the only parameter inside your tab shortcode, you can specify the header as unnamed parameter, something like `{ tab "My header" }} … {{ /tab }}`. If your `tab` shortcode does not have any parameters, the header of the tab will default to `Tab n`. You can disable a tab by specifying the parameter `disabled=true`. For enabled tabs, 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: `{{}}`Your <b>HTML</b> content`{{}}`. + +{{% 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