Bundling JS with ESBuild (#702)
* add npm dependencies used in this theme * implement helper to configure JS and ESBuild * migrate jquery popper.js bootstrap fontawesome to js bundle * refactor main.js into smaller pieces, and moved navbar.js to assets * remove list.js. It adjusts post card height to be the same, but is actually not needed. * refactored notes.js, search.js, single.js into application.js * move ityped to js asset, implement experiences horizontal vertical line in css * align recent post height via css * migrated home.js and refactored into various sections * migrated darkMode feature to js bundle * moved mermaid feature to js bundle * migrate syntax highlight to js bundle * migrate katex ( js portion ) to js bundle * migrate pdf-js to js bundle by delegating to cdn * set explicit comparisions for feature envvars so js can properly optimize * removed goat-counter * more fixes for broken achievements and small bugs * more bug fixes * allow configuration of hightlight.js, fix video-player shortcode * remove jquery all together * add null handling and fix merge conflicts Co-authored-by: Aaron Qian <aaron@yeet.io>
This commit is contained in:
parent
fe14b0fbf5
commit
02db3d3044
491 changed files with 4919 additions and 151344 deletions
|
@ -1,6 +1,7 @@
|
|||
<!-- Add Analytics if enabled in configuration -->
|
||||
{{ with site.Params.features.analytics }}
|
||||
{{ if .enabled }}
|
||||
{{ with .services }}
|
||||
<!-- Google Analytics -->
|
||||
{{ with .google }}
|
||||
{{ $privacyConfig:= dict (slice "Site" "Config" "Privacy" "GoogleAnalytics") $.Site.Config.Privacy.GoogleAnalytics }}
|
||||
|
@ -21,7 +22,7 @@
|
|||
<script
|
||||
data-goatcounter="https://{{ .code }}.goatcounter.com/count"
|
||||
async
|
||||
src="/js/goat-counter.js"
|
||||
src="//gc.zgo.at/count.js"
|
||||
></script>
|
||||
{{ end }}
|
||||
|
||||
|
@ -42,6 +43,7 @@
|
|||
})();
|
||||
</script>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
|
|
@ -42,8 +42,9 @@
|
|||
{{ end }}
|
||||
<div class="project-btn-holder">
|
||||
{{ if .repo }}
|
||||
<!-- Place this tag where you want the button to render. -->
|
||||
<a
|
||||
class="github-button-inactive project-btn"
|
||||
class="github-button project-btn d-none"
|
||||
href="{{ .repo }}"
|
||||
data-icon="octicon-standard"
|
||||
data-show-count="true"
|
||||
|
|
|
@ -7,17 +7,14 @@
|
|||
<link rel="stylesheet" href="{{ "/css/layouts/main.css" | relURL }}"/>
|
||||
<link rel="stylesheet" href="{{ "/css/navigators/navbar.css" | relURL }}"/>
|
||||
<link rel="stylesheet" href="{{ "/css/plyr.css" | relURL }}"/>
|
||||
{{ if ne site.Params.showFlags false }}
|
||||
{{ if ne site.Params.features.flags.enable false }}
|
||||
<link rel="stylesheet" href="{{ "/css/flag-icon.min.css" | relURL }}"/>
|
||||
{{ end }}
|
||||
<!--=================== fonts ==============================-->
|
||||
<link rel="stylesheet" href="{{ "/google-fonts/Mulish/mulish.css" | relURL }}"/>
|
||||
|
||||
<!--=================== icons ==============================-->
|
||||
<link rel="stylesheet" href="{{ "/fontawesome/css/all.min.css" | relURL }}"/>
|
||||
|
||||
<!--=================== dark mode ==========================-->
|
||||
{{ if site.Params.darkMode.enable }}
|
||||
{{ if site.Params.features.darkMode.enable }}
|
||||
<link rel="stylesheet" href="{{ "/css/colortheme/colortheme.css" | relURL }}"/>
|
||||
{{ end }}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
|
||||
{{/* if the user specify a country code for a language via "params.flagOverwrites" field, then use it. */}}
|
||||
{{ range site.Params.flagOverwrites }}
|
||||
{{ range site.Params.features.flags.flagOverwrites }}
|
||||
{{ if eq $languageCode .languageCode }}
|
||||
{{ $countryCode = .countryCode }}
|
||||
{{ end }}
|
||||
|
|
209
layouts/partials/helpers/get-esbuild-options.html
Normal file
209
layouts/partials/helpers/get-esbuild-options.html
Normal file
|
@ -0,0 +1,209 @@
|
|||
{{/*
|
||||
|
||||
## Overview
|
||||
|
||||
This helper returns options dictionary used to configure ESBuild.
|
||||
The following configurations are set:
|
||||
|
||||
* Enable JS minification.
|
||||
* Enable source map if not building for production.
|
||||
* Prepare `process.env.<ENVIRONMENT VARIABLE>` defines based on enabled features.
|
||||
This allows ESBuild to optimize JS bundle size by removing code related
|
||||
to unused features.
|
||||
* Added `process-shim.js` so `process.env` is defined.
|
||||
This way we don't have to explicitly specify every environment
|
||||
variable via `defines` value.
|
||||
* Prepare `params` for feature and service configs used in JS.
|
||||
|
||||
For more details on ESBuild configuration, see: https://gohugo.io/hugo-pipes/js/
|
||||
|
||||
## Detailed Concepts
|
||||
|
||||
### `feature` and `service`
|
||||
|
||||
Features configured in site wide `config.yml` file under `params.features` section.
|
||||
A **feature** provides a certain functionality to the user via one or more services.
|
||||
A feature be can enabled or disabled.
|
||||
|
||||
A **service** is a 3rd party service, or JS library that implements a feature.
|
||||
|
||||
For example, `analytics` is considered a feature.
|
||||
There are many services that can provide this feature, to name a few:
|
||||
|
||||
* Google Analytics
|
||||
* Counter.Dev
|
||||
* GoatCounter
|
||||
|
||||
To maximize extendibility and therefore usefulness as an open source project,
|
||||
it is important to define a standard interface that is easy to understand,
|
||||
configure, and extend.
|
||||
|
||||
In this file, I took the liberty of standardizing this interface under `params.features`.
|
||||
Please note that this breaks compatibility with previous versions of `config.yaml`.
|
||||
I will provide sample `config.yaml` files with fully documented features, as well as
|
||||
documentation on migrating the `config.yaml` file to the new standard.
|
||||
|
||||
Here is a sample config file for the new `params.features` section. Notice that each `service`
|
||||
is a dictionary with `enable` and `services` key. `services` is a dictionary with each key
|
||||
corresponding to a concrete service, and value as configuration / settings. In the case of
|
||||
services that need no configuration, an empty dictionary is created.
|
||||
|
||||
```yml
|
||||
params:
|
||||
features:
|
||||
|
||||
# This is the `analytics` feature
|
||||
analytics:
|
||||
# This feature is enabled
|
||||
enable: true
|
||||
# List of services to enable
|
||||
services:
|
||||
|
||||
# Google Analytics is enabled
|
||||
google:
|
||||
# settings for Google Analytics
|
||||
id: G-xxxxx
|
||||
|
||||
# # Counter Dev is disabled
|
||||
# counterDev:
|
||||
# id: foo
|
||||
# name: bar
|
||||
|
||||
# The `darkMode` feature
|
||||
darkmode:
|
||||
enable: true
|
||||
services:
|
||||
# darkmode is realized by using DarkReader library
|
||||
darkreader:
|
||||
# options are 'system', 'dark', 'light'
|
||||
defaultColorScheme: system
|
||||
# For all available options, see `interface DynamicThemeFix`:
|
||||
# https://github.com/darkreader/darkreader/blob/main/index.d.ts#L125
|
||||
fixes:
|
||||
invert: ['img[src$=".svg"]'] # inverts svg colors.
|
||||
# For all available options, see `interface Theme` in:
|
||||
# https://github.com/darkreader/darkreader/blob/main/index.d.ts#L45
|
||||
theme:
|
||||
brightness: 100
|
||||
contrast: 100
|
||||
sepia: 0
|
||||
```
|
||||
|
||||
This helper will convert the above config into the following env vars:
|
||||
|
||||
* `FEATURE_ANALYTICS=1`
|
||||
* `FEATURE_ANALYTICS_GOOGLE=1`
|
||||
* `FEATURE_DARKMODE=1`
|
||||
* `FEATURE_DARKMODE_DARKREADER=1`
|
||||
|
||||
In JS, you can use it like this:
|
||||
|
||||
```js
|
||||
import * as params from '@params';
|
||||
|
||||
if (process.env.FEATURE_ANALYTICS) {
|
||||
// Do things to enable this feature here
|
||||
|
||||
if (process.env.FEATURE_ANALYTICS_GOOGLE) {
|
||||
// Do things things to enable google analytics
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can also access service configs via params:
|
||||
|
||||
```js
|
||||
import * as params from '@params';
|
||||
|
||||
console.log(params);
|
||||
```
|
||||
|
||||
You will see console output like below. Note, each service configuration is
|
||||
namespaced by their corresponding feature.
|
||||
|
||||
```json
|
||||
{
|
||||
"analytics": {
|
||||
"google": {
|
||||
"id": "G-xxxxx"
|
||||
}
|
||||
},
|
||||
"darkmode": {
|
||||
"darkreader": {
|
||||
"defaultColorScheme": "system",
|
||||
"fixes": {
|
||||
"invert": "['img[src$=\".svg\"]']"
|
||||
},
|
||||
"theme": {
|
||||
"brightness": 100,
|
||||
"contrast": 100,
|
||||
"sepia": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
*/}}
|
||||
|
||||
{{/* Holds all the feature flag environment variables for `process.env.*` in JS land */}}
|
||||
{{ $defines := dict }}
|
||||
|
||||
{{/* Holds all the feature configuration variables exposed to JS side */}}
|
||||
{{ $params := dict }}
|
||||
|
||||
{{/* set NODE_ENV depending on if we are building for production use. */}}
|
||||
{{ $defines = $defines | merge (dict
|
||||
"process.env.NODE_ENV" (cond hugo.IsProduction `"production"` `"development"` )
|
||||
)}}
|
||||
|
||||
{{/* Go through each feature defined in our config.yml/config.toml/config.json file. */}}
|
||||
{{ range $feature, $featureDef := site.Params.features }}
|
||||
{{/* Initialize a dictionary that will hold all service configs for this specific feature */}}
|
||||
{{ $featureParams := dict }}
|
||||
|
||||
{{ with $featureDef }}
|
||||
{{/* convert feature name to uppercase and remove '_', e.g. `darkMode` becomes `DARKMODE` */}}
|
||||
{{ $featureName := replace $feature "_" "" | upper }}
|
||||
|
||||
{{/* The feature is enabled if the `enable` key is absent, or is set to `true` */}}
|
||||
{{ $featureEnabled := or (not (isset . "enable")) .enable }}
|
||||
|
||||
{{/* Sets `FEATURE_<FEATURE_NAME>` env var to "1" or "0" depending on if the feature is enabled. */}}
|
||||
{{ $defines = $defines | merge (dict
|
||||
(printf "process.env.FEATURE_%s" $featureName) (cond $featureEnabled `'1'` `'0'`)
|
||||
) }}
|
||||
|
||||
{{ if $featureEnabled }}
|
||||
{{/* Loop through each service under this feature */}}
|
||||
{{ range $service, $config := .services }}
|
||||
{{/*
|
||||
We assume all services are enabled. To disable a service,
|
||||
simply comment it out from `config.yaml`.
|
||||
*/}}
|
||||
|
||||
{{/* Convert name to all uppercase, removing underscore */}}
|
||||
{{ $serviceName := replace $service "_" "" | upper }}
|
||||
|
||||
{{/* let JS side know this service is enabled */}}
|
||||
{{ $defines = $defines | merge (dict
|
||||
(printf "process.env.FEATURE_%s_%s" $featureName $serviceName) `'1'`
|
||||
) }}
|
||||
|
||||
{{/* add service configuration to feature params */}}
|
||||
{{ $featureParams = $featureParams | merge (dict $service $config) }}
|
||||
{{ end }}
|
||||
|
||||
{{/* add feature params to top level params */}}
|
||||
{{ $params = $params | merge (dict $feature $featureParams) }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{
|
||||
return dict
|
||||
"defines" $defines
|
||||
"params" $params
|
||||
"minify" true
|
||||
"sourceMap" (cond hugo.IsProduction "" "inline")
|
||||
"inject" "scripts/process-shim.js"
|
||||
}}
|
5
layouts/partials/helpers/script-bundle.html
Normal file
5
layouts/partials/helpers/script-bundle.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
{{- $options := partial "helpers/get-esbuild-options.html" -}}
|
||||
{{- $options = $options | merge (dict "targetPath" "application.js") -}}
|
||||
{{- $app := resources.Get "scripts/application.js" -}}
|
||||
{{- $bundle := $app | js.Build $options | fingerprint -}}
|
||||
<script src="{{ $bundle.RelPermalink }}" integrity="{{ $bundle.Data.Integrity }}" defer></script>
|
|
@ -1,15 +1 @@
|
|||
<link rel="stylesheet" href="{{ "/katex/katex.min.css" | relURL }}">
|
||||
<script type="text/javascript" defer src="{{ "/katex/katex.min.js" | relURL }}"></script>
|
||||
<script type="text/javascript" defer src="{{ "/katex/auto-render.min.js" | relURL }}" onload="renderMathInElement(document.body);">
|
||||
renderMathInElement(
|
||||
document.body,
|
||||
{
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "\\[", right: "\\]", display: true},
|
||||
{left: "$", right: "$", display: false},
|
||||
{left: "\\(", right: "\\)", display: false}
|
||||
]
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<script src="{{ "/js/mermaid-8.14.0.min.js" | relURL }}"></script>
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
startOnLoad:true
|
||||
});
|
||||
</script>
|
|
@ -1,5 +1,6 @@
|
|||
{{ with site.Params.features.support }}
|
||||
{{ if .enabled }}
|
||||
{{ if .enable }}
|
||||
{{ with .services }}
|
||||
<!-- Enable Ko-Fi floating button -->
|
||||
{{ with .kofi }}
|
||||
<script src='https://storage.ko-fi.com/cdn/scripts/overlay-widget.js'></script>
|
||||
|
@ -16,5 +17,6 @@
|
|||
{{ with .buymeacoffee }}
|
||||
<script data-name="BMC-Widget" data-cfasync="false" src="https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js" data-id="{{ .user }}" data-description="{{ .text }}" data-message="{{ .info }}" data-color="{{ .color }}" data-position="Right" data-x_margin="10" data-y_margin="18"></script>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<div class="dropdown languageSelector">
|
||||
<a class="btn dropdown-toggle" href="#" id="languageSelector" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ if ne site.Params.showFlags false }}
|
||||
{{ if ne site.Params.features.flags.enable false }}
|
||||
{{ $countryCode := partial "helpers/country-code.html" . }}
|
||||
<span class="flag-icon flag-icon-{{$countryCode}}"></span>
|
||||
{{ end }}
|
||||
|
@ -14,7 +14,7 @@
|
|||
<div class="dropdown-menu" aria-labelledby="languageSelector">
|
||||
{{ range .Translations }}
|
||||
<a class="dropdown-item nav-link languages-item" href="{{ path.Join "/" (cond (eq .Language.Lang "en") "" .Language.Lang) $pageURL }}">
|
||||
{{ if ne site.Params.showFlags false }}
|
||||
{{ if ne site.Params.features.flags.enable false }}
|
||||
{{ $countryCode := partial "helpers/country-code.html" . }}
|
||||
<span class="flag-icon flag-icon-{{$countryCode}}"></span>
|
||||
{{ end }}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="languageSelector" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ if ne site.Params.showFlags false }}
|
||||
{{ if ne site.Params.features.flags.enable false }}
|
||||
{{ $countryCode := partial "helpers/country-code.html" . }}
|
||||
<span class="flag-icon flag-icon-{{$countryCode}}"></span>
|
||||
{{ end }}
|
||||
|
@ -14,7 +14,7 @@
|
|||
<div class="dropdown-menu" aria-labelledby="languageSelector">
|
||||
{{ range .Translations }}
|
||||
<a class="dropdown-item nav-link languages-item" href="{{ path.Join "/" (cond (eq .Language.Lang "en") "" .Language.Lang) $pageURL }}">
|
||||
{{ if ne site.Params.showFlags false }}
|
||||
{{ if ne site.Params.features.flags.enable false }}
|
||||
{{ $countryCode := partial "helpers/country-code.html" . }}
|
||||
<span class="flag-icon flag-icon-{{$countryCode}}"></span>
|
||||
{{ end }}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="languageSelector" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ if ne site.Params.showFlags false }}
|
||||
{{ if ne site.Params.features.flags.enable false }}
|
||||
{{ $countryCode := partial "helpers/country-code.html" . }}
|
||||
<span class="flag-icon flag-icon-{{$countryCode}}"></span>
|
||||
{{ end }}
|
||||
|
@ -9,7 +9,7 @@
|
|||
<div class="dropdown-menu" aria-labelledby="languageSelector">
|
||||
{{ range site.Home.AllTranslations }}
|
||||
<a class="dropdown-item nav-link languages-item" href="{{ .RelPermalink }}">
|
||||
{{ if ne site.Params.showFlags false }}
|
||||
{{ if ne site.Params.features.flags.enable false }}
|
||||
{{ $countryCode := partial "helpers/country-code.html" . }}
|
||||
<span class="flag-icon flag-icon-{{$countryCode}}"></span>
|
||||
{{ end }}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<nav class="navbar navbar-expand-xl top-navbar final-navbar shadow">
|
||||
<div class="container">
|
||||
<button class="navbar-toggler navbar-light" id="sidebar-toggler" type="button" onclick="toggleSidebar()">
|
||||
<button class="navbar-toggler navbar-light" id="sidebar-toggler" type="button">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="{{ site.BaseURL | relLangURL }}">
|
||||
|
@ -38,7 +38,7 @@
|
|||
{{ end }}
|
||||
{{- site.Title -}}
|
||||
</a>
|
||||
<button class="navbar-toggler navbar-light" id="toc-toggler" type="button" onclick="toggleTOC()">
|
||||
<button class="navbar-toggler navbar-light" id="toc-toggler" type="button">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
|
@ -47,7 +47,7 @@
|
|||
{{ if .IsTranslated }}
|
||||
{{ partial "navigators/lang-selector-2.html" . }}
|
||||
{{ end }}
|
||||
{{ if site.Params.darkMode.enable }}
|
||||
{{ if site.Params.features.darkMode.enable }}
|
||||
{{ partial "navigators/theme-selector.html" . }}
|
||||
{{ end }}
|
||||
</ul>
|
||||
|
|
|
@ -124,7 +124,7 @@
|
|||
{{ if .IsTranslated }}
|
||||
{{ partial "navigators/lang-selector.html" . }}
|
||||
{{ end }}
|
||||
{{ if site.Params.darkMode.enable }}
|
||||
{{ if site.Params.features.darkMode.enable }}
|
||||
{{ partial "navigators/theme-selector.html" . }}
|
||||
{{ end }}
|
||||
</ul>
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
<li class="nav-item dropdown">
|
||||
<!-- This is for initializing the color scheme selection for new visitors. See /js/darkmode.js -->
|
||||
<div id="theme-initialization" style="display: none;"
|
||||
default-theme="{{ site.Params.darkMode.default }}"></div>
|
||||
<a class="nav-link dropdown-toggle" href="#" id="themeSelector" role="button"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<img id="navbar-theme-icon-svg" src="{{ "/icons/moon-svgrepo-com.svg" }}" width=20 alt="Dark Theme">
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-icons-only" aria-labelledby="themeSelector">
|
||||
<a class="dropdown-item nav-link" href="#" onclick="enableLightTheme()">
|
||||
<div id="themeMenu" class="dropdown-menu dropdown-menu-icons-only" aria-labelledby="themeSelector">
|
||||
<a class="dropdown-item nav-link" href="#" data-scheme="light">
|
||||
<img class="menu-icon-center" src="{{ "/icons/sun-svgrepo-com.svg" }}" width=20 alt="Light Theme">
|
||||
</a>
|
||||
<a class="dropdown-item nav-link" href="#" onclick="enableDarkTheme()">
|
||||
<a class="dropdown-item nav-link" href="#" data-scheme="dark">
|
||||
<img class="menu-icon-center" src="{{ "/icons/moon-svgrepo-com.svg" }}" width=20 alt="Dark Theme">
|
||||
</a>
|
||||
<a class="dropdown-item nav-link" href="#" onclick="useSystemTheme()">
|
||||
<a class="dropdown-item nav-link" href="#" data-scheme="system">
|
||||
<img class="menu-icon-center" src="{{ "/icons/computer-svgrepo-com.svg" }}" width=20 alt="System Theme">
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</li>
|
||||
|
|
|
@ -1,14 +1 @@
|
|||
<script type="text/javascript" src="{{ "/js/jquery-3.4.1.min.js" | relURL }}"></script>
|
||||
<script type="text/javascript" src="{{ "/js/popper.min.js" | relURL }}"></script>
|
||||
<script type="text/javascript" src="{{ "/js/bootstrap.min.js" | relURL }}"></script>
|
||||
|
||||
<script type="text/javascript" src="{{ "/js/navbar.js" | relURL }}"></script>
|
||||
<script type="text/javascript" src="{{ "/js/plyr.js" | relURL }}"></script>
|
||||
<script type="text/javascript" src="{{ "/js/main.js" | relURL }}"></script>
|
||||
|
||||
{{ if site.Params.darkMode.enable }}
|
||||
{{ if eq site.Params.darkMode.provider "darkreader" }}
|
||||
<script type="text/javascript" src="{{ "/js/darkreader.js" | relURL }}"></script>
|
||||
<script type="text/javascript" src="{{ "/js/darkmode-darkreader.js" | relURL }}"></script>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ partial "helpers/script-bundle.html" }}
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
class="achievement-entry text-center"
|
||||
style="background-image: url('{{ $achievementImageSm }}');"
|
||||
>
|
||||
<i class="fas fa-search-plus" id="enlarge-icon"></i>
|
||||
<i class="fa-solid fa-xmark hidden"></i>
|
||||
<i class="fa-solid fa-magnifying-glass-plus" id="enlarge-icon"></i>
|
||||
<h4 class="title" id="achievement-title">{{ .title }}</h4>
|
||||
<div class="caption hidden col-lg-6 text-left" id="caption">
|
||||
<h4>{{ .title }}</h4>
|
||||
|
|
|
@ -90,9 +90,9 @@
|
|||
{{ end }}
|
||||
{{ if gt (len .takenCourses.courses) $collapseAfter }}
|
||||
<button type="button" class="btn btn-link show-more-btn pt-0 {{ if .takenCourses.showGrades }}ml-1{{ else }}ml-2{{ end }}"
|
||||
onclick="toggleCourseVisibility(this);" id="show-more-btn" aria-label="{{ i18n "show_more"}}">{{ i18n "show_more"}}</button>
|
||||
id="show-more-btn" aria-label="{{ i18n "show_more"}}">{{ i18n "show_more"}}</button>
|
||||
<button type="button" class="btn btn-link show-more-btn hidden pt-0 {{ if .takenCourses.showGrades }}ml-1{{ else }}ml-2{{ end }}"
|
||||
onclick="toggleCourseVisibility(this);" id="show-less-btn" aria-label="{{ i18n "show_less"}}">{{ i18n "show_less"}}</button>
|
||||
id="show-less-btn" aria-label="{{ i18n "show_less"}}">{{ i18n "show_less"}}</button>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
|
|
@ -90,9 +90,9 @@
|
|||
{{ end }}
|
||||
{{ if gt (len .takenCourses.courses ) $collapseAfter }}
|
||||
<button type="button" class="btn btn-link show-more-btn pt-0 {{ if .takenCourses.showGrades }}ml-1{{ else }}ml-2{{ end }}"
|
||||
onclick="toggleCourseVisibility(this);" id="show-more-btn">{{ i18n "show_more"}}</button>
|
||||
id="show-more-btn">{{ i18n "show_more"}}</button>
|
||||
<button type="button" class="btn btn-link show-more-btn hidden pt-0 {{ if .takenCourses.showGrades }}ml-1{{ else }}ml-2{{ end }}"
|
||||
onclick="toggleCourseVisibility(this);" id="show-less-btn">{{ i18n "show_less"}}</button>
|
||||
id="show-less-btn">{{ i18n "show_less"}}</button>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue