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
|
@ -55,7 +55,3 @@
|
|||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
|
||||
{{ define "scripts" }}
|
||||
<script src="{{ "/js/list.js" | relURL }}"></script>
|
||||
{{ end }}
|
||||
|
|
|
@ -66,9 +66,3 @@
|
|||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
|
||||
{{ define "scripts" }}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.2.0/fuse.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/jquery.mark.min.js"></script>
|
||||
<script src="{{ "/js/search.js" | absURL }}"></script>
|
||||
{{ end }}
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
<div class="title">
|
||||
<h1>{{ .Page.Title }}</h1>
|
||||
</div>
|
||||
{{ if site.Params.enableTags }}
|
||||
{{ if site.Params.features.tags.enable }}
|
||||
<div class="taxonomy-terms">
|
||||
<ul style="padding-left: 0;">
|
||||
{{ range .Params.tags }}
|
||||
|
@ -158,7 +158,7 @@
|
|||
|
||||
<!----- Add comment support ----->
|
||||
{{ if site.Params.features.comment.enable }}
|
||||
{{ partial "comments.html" site.Params.features.comment }}
|
||||
{{ partial "comments.html" site.Params.features.comment.services }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Keep backward compatibility with old config.yaml -->
|
||||
|
@ -179,7 +179,7 @@
|
|||
|
||||
{{ define "toc" }}
|
||||
<section class="toc-section" id="toc-section">
|
||||
{{ if and site.Params.enableTOC ( .Params.enableTOC | default true ) }}
|
||||
{{ if and site.Params.features.toc.enable ( .Params.enableTOC | default true ) }}
|
||||
<div class="toc-holder">
|
||||
<h5 class="text-center pl-3">{{ i18n "toc_heading" }}</h5>
|
||||
<hr>
|
||||
|
@ -192,20 +192,9 @@
|
|||
{{ end }}
|
||||
|
||||
{{ define "scripts" }}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js"></script>
|
||||
<script src="{{ "/js/single.js" | relURL }}"></script>
|
||||
<script>
|
||||
hljs.initHighlightingOnLoad();
|
||||
</script>
|
||||
|
||||
<!-------------- Enable Math support for this page ---------------->
|
||||
{{ if .Params.math }}
|
||||
{{ if site.Params.features.math.enable }}
|
||||
{{ partial "math.html" . }}
|
||||
{{ end }}
|
||||
|
||||
<!-------------- Enable mermaid support for this page ---------------->
|
||||
{{ if .Params.mermaid }}
|
||||
{{ partial "mermaid.html" . }}
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
|
|
|
@ -56,7 +56,3 @@
|
|||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
|
||||
{{ define "scripts" }}
|
||||
<script src="{{ "/js/list.js" | relURL }}"></script>
|
||||
{{ end }}
|
||||
|
|
|
@ -75,12 +75,6 @@
|
|||
<!--- ADD COMMON SCRIPTS --------------->
|
||||
{{ partial "scripts.html" . }}
|
||||
|
||||
<!--- ADD INDEX PAGE SPECIFIC SCRIPTS -->
|
||||
<script src="{{ "/js/itype.min.js" | relURL }}"></script>
|
||||
<script src="{{ "/js/github-button.js" | relURL }}"></script>
|
||||
<script src="{{ "/js/home.js" | relURL }}"></script>
|
||||
<script src="{{ "/js/jquery.filterizr.min.js" | relURL }}"></script>
|
||||
|
||||
<!------ ADD SUPPORT LINKS -------->
|
||||
{{- partial "misc/support.html" . -}}
|
||||
|
||||
|
|
|
@ -57,13 +57,7 @@
|
|||
{{ end }}
|
||||
|
||||
{{ define "scripts" }}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js"></script>
|
||||
<script src="{{ "/js/imagesloaded.pkgd.min.js" | relURL }}"></script>
|
||||
<script src="{{ "/js/note.js" | relURL }}"></script>
|
||||
<script>
|
||||
hljs.initHighlightingOnLoad();
|
||||
</script>
|
||||
{{ if .Params.math }}
|
||||
{{ if site.Params.features.math.enable }}
|
||||
{{ partial "math.html" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
|
|
@ -47,13 +47,7 @@
|
|||
{{ end }}
|
||||
|
||||
{{ define "scripts" }}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js"></script>
|
||||
<script src="{{ "/js/imagesloaded.pkgd.min.js" | relURL }}"></script>
|
||||
<script src="{{ "/js/note.js" | relURL }}"></script>
|
||||
<script>
|
||||
hljs.initHighlightingOnLoad();
|
||||
</script>
|
||||
{{ if .Params.math }}
|
||||
{{ if site.Params.features.math.enable }}
|
||||
{{ partial "math.html" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -1,185 +1,32 @@
|
|||
<!--
|
||||
{{ $url := .Get "src" }}
|
||||
{{ $hidePaginator := .Get "hidePaginator" | default "false" }}
|
||||
{{ $hideLoader := .Get "hidePaginator" | default "false" }}
|
||||
{{ $pageNum := .Get "renderPageNum" | default "1"}}
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
<div
|
||||
class="pdf-viewer"
|
||||
data-url="{{ $url }}"
|
||||
data-hide-paginator="{{ $hidePaginator }}"
|
||||
data-hide-loader="{{ $hideLoader }}"
|
||||
data-page-num="{{ $pageNum }}"
|
||||
>
|
||||
<div class="paginator">
|
||||
<button class="prev">Previous</button>
|
||||
<button class="next">Next</button>
|
||||
<span>Page: <span class="page-num"></span> / <span class="page-count"></span></span>
|
||||
</div>
|
||||
|
||||
This shortcut was originally taken from: https://github.com/anvithks/hugo-embed-pdf-shortcode,
|
||||
where it is available under the MIT License, where it was originally created by https://github.com/anvithks
|
||||
|
||||
Since the project seems discontinued, it has been re-created here
|
||||
-->
|
||||
|
||||
<!-- Load the PDF-JS from the local folder (should be updated over time) -->
|
||||
<script src= '/js/pdf-js/build/pdf.js'></script>
|
||||
|
||||
<!-- Set the navigation menu -->
|
||||
<div id="paginator">
|
||||
<button id="prev">Previous</button>
|
||||
<button id="next">Next</button>
|
||||
|
||||
<span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>
|
||||
<div class="embed-pdf-container">
|
||||
<div class="loading-wrapper">
|
||||
<div class="loading"></div>
|
||||
</div>
|
||||
<canvas class="pdf-canvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- And the canvas where the PDF will load -->
|
||||
<div id="embed-pdf-container">
|
||||
<div id="loadingWrapper">
|
||||
<div id="loading"></div>
|
||||
</div>
|
||||
<canvas id="the-canvas"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- This script gets the PDF, sets it and passes it on to the already-loaded pdf-js -->
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
// If absolute URL from the remote server is provided, configure the CORS
|
||||
// header on that server.
|
||||
var url = "{{.Site.BaseURL}}" + '{{ .Get "src" }}';
|
||||
|
||||
var hidePaginator = "{{ .Get "hidePaginator" }}" === "true";
|
||||
var hideLoader = "{{ .Get "hideLoader" }}" === "true";
|
||||
var selectedPageNum = parseInt("{{ .Get "renderPageNum" }}") || 1;
|
||||
|
||||
// Loaded via <script> tag, create shortcut to access PDF.js exports.
|
||||
var pdfjsLib = window['pdfjs-dist/build/pdf'];
|
||||
|
||||
// The workerSrc property shall be specified.
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = "{{.Site.BaseURL}}" + '/js/pdf-js/build/pdf.worker.js';
|
||||
|
||||
// Change the Scale value for lower or higher resolution.
|
||||
var pdfDoc = null,
|
||||
pageNum = selectedPageNum,
|
||||
pageRendering = false,
|
||||
pageNumPending = null,
|
||||
scale = 3,
|
||||
canvas = document.getElementById('the-canvas'),
|
||||
ctx = canvas.getContext('2d'),
|
||||
paginator = document.getElementById("paginator"),
|
||||
loadingWrapper = document.getElementById('loadingWrapper');
|
||||
|
||||
|
||||
// Attempt to show paginator and loader if enabled
|
||||
showPaginator();
|
||||
showLoader();
|
||||
|
||||
/**
|
||||
* Get page info from document, resize canvas accordingly, and render page.
|
||||
* @param num Page number.
|
||||
*/
|
||||
function renderPage(num) {
|
||||
pageRendering = true;
|
||||
// Using promise to fetch the page
|
||||
pdfDoc.getPage(num).then(function(page) {
|
||||
var viewport = page.getViewport({scale: scale});
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
|
||||
// Render PDF page into canvas context
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
viewport: viewport
|
||||
};
|
||||
var renderTask = page.render(renderContext);
|
||||
|
||||
// Wait for rendering to finish
|
||||
renderTask.promise.then(function() {
|
||||
pageRendering = false;
|
||||
showContent();
|
||||
|
||||
if (pageNumPending !== null) {
|
||||
// New page rendering is pending
|
||||
renderPage(pageNumPending);
|
||||
pageNumPending = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Update page counters
|
||||
document.getElementById('page_num').textContent = num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides loader and shows canvas
|
||||
*/
|
||||
function showContent() {
|
||||
loadingWrapper.style.display = 'none';
|
||||
canvas.style.display = 'block';
|
||||
}
|
||||
|
||||
/**
|
||||
* If we haven't disabled the loader, show loader and hide canvas
|
||||
*/
|
||||
function showLoader() {
|
||||
if(hideLoader) return
|
||||
loadingWrapper.style.display = 'flex';
|
||||
canvas.style.display = 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* If we haven't disabled the paginator, show paginator
|
||||
*/
|
||||
function showPaginator() {
|
||||
if(hidePaginator) return
|
||||
paginator.style.display = 'block';
|
||||
}
|
||||
|
||||
/**
|
||||
* If another page rendering in progress, waits until the rendering is
|
||||
* finished. Otherwise, executes rendering immediately.
|
||||
*/
|
||||
function queueRenderPage(num) {
|
||||
if (pageRendering) {
|
||||
pageNumPending = num;
|
||||
} else {
|
||||
renderPage(num);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays previous page.
|
||||
*/
|
||||
function onPrevPage() {
|
||||
if (pageNum <= 1) {
|
||||
return;
|
||||
}
|
||||
pageNum--;
|
||||
queueRenderPage(pageNum);
|
||||
}
|
||||
document.getElementById('prev').addEventListener('click', onPrevPage);
|
||||
|
||||
/**
|
||||
* Displays next page.
|
||||
*/
|
||||
function onNextPage() {
|
||||
if (pageNum >= pdfDoc.numPages) {
|
||||
return;
|
||||
}
|
||||
pageNum++;
|
||||
queueRenderPage(pageNum);
|
||||
}
|
||||
document.getElementById('next').addEventListener('click', onNextPage);
|
||||
|
||||
/**
|
||||
* Asynchronously downloads PDF.
|
||||
*/
|
||||
pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
|
||||
pdfDoc = pdfDoc_;
|
||||
var numPages = pdfDoc.numPages;
|
||||
document.getElementById('page_count').textContent = numPages;
|
||||
|
||||
// If the user passed in a number that is out of range, render the last page.
|
||||
if(pageNum > numPages) {
|
||||
pageNum = numPages
|
||||
}
|
||||
|
||||
// Initial/first page rendering
|
||||
renderPage(pageNum);
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- Finally, make the canvas more beautiful -->
|
||||
<style>
|
||||
#the-canvas {
|
||||
.pdf-viewer canvas {
|
||||
border: 1px solid black;
|
||||
direction: ltr;
|
||||
width: 100%;
|
||||
|
@ -187,13 +34,13 @@ pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#paginator {
|
||||
.pdf-viewer .paginator {
|
||||
display: none;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#loadingWrapper {
|
||||
.pdf-viewer .loading-wrapper {
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
@ -201,7 +48,7 @@ pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
|
|||
height: 350px;
|
||||
}
|
||||
|
||||
#loading {
|
||||
.pdf-viewer .loading {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
|
|
|
@ -56,7 +56,3 @@
|
|||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
|
||||
{{ define "scripts" }}
|
||||
<script src="{{ "/js/list.js" | relURL }}"></script>
|
||||
{{ end }}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue