mirror of
https://github.com/CaiJimmy/hugo-theme-stack.git
synced 2025-04-29 20:13:31 +08:00
Merge branch 'CaiJimmy:master' into master
This commit is contained in:
commit
d119f08631
31
.devcontainer/Dockerfile
Normal file
31
.devcontainer/Dockerfile
Normal file
@ -0,0 +1,31 @@
|
||||
# Update the NODE_VERSION arg in docker-compose.yml to pick a Node version: 10, 12, 14
|
||||
ARG NODE_VERSION=14
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${NODE_VERSION}
|
||||
|
||||
# VARIANT can be either 'hugo' for the standard version or 'hugo_extended' for the extended version.
|
||||
ARG VARIANT=hugo
|
||||
# VERSION can be either 'latest' or a specific version number
|
||||
ARG VERSION=latest
|
||||
|
||||
# Download Hugo
|
||||
RUN apt-get update && apt-get install -y ca-certificates openssl git curl && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
case ${VERSION} in \
|
||||
latest) \
|
||||
export VERSION=$(curl -s https://api.github.com/repos/gohugoio/hugo/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4)}') ;;\
|
||||
esac && \
|
||||
echo ${VERSION} && \
|
||||
wget -O ${VERSION}.tar.gz https://github.com/gohugoio/hugo/releases/download/v${VERSION}/${VARIANT}_${VERSION}_Linux-64bit.tar.gz && \
|
||||
tar xf ${VERSION}.tar.gz && \
|
||||
mv hugo /usr/bin/hugo
|
||||
|
||||
# Hugo dev server port
|
||||
EXPOSE 1313
|
||||
|
||||
# [Optional] Uncomment this section to install additional OS packages you may want.
|
||||
#
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
# [Optional] Uncomment if you want to install more global node packages
|
||||
# RUN sudo -u node npm install -g <your-package-list-here>
|
45
.devcontainer/devcontainer.json
Normal file
45
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,45 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.202.3/containers/hugo
|
||||
{
|
||||
"name": "Hugo (Community)",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
// Update VARIANT to pick hugo variant.
|
||||
// Example variants: hugo, hugo_extended
|
||||
// Rebuild the container if it already exists to update.
|
||||
"VARIANT": "hugo_extended",
|
||||
// Update VERSION to pick a specific hugo version.
|
||||
// Example versions: latest, 0.73.0, 0,71.1
|
||||
// Rebuild the container if it already exists to update.
|
||||
"VERSION": "latest",
|
||||
// Update NODE_VERSION to pick the Node.js version: 12, 14
|
||||
"NODE_VERSION": "14",
|
||||
}
|
||||
},
|
||||
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"html.format.templating": true,
|
||||
},
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"bungcip.better-toml",
|
||||
"davidanson.vscode-markdownlint"
|
||||
],
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [
|
||||
1313
|
||||
],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "uname -a",
|
||||
|
||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "node",
|
||||
"features": {
|
||||
"golang": "latest"
|
||||
}
|
||||
}
|
45
.github/ISSUE_TEMPLATE/bug_report.md
vendored
45
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -7,32 +7,39 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
<!--
|
||||
Before creating this bug report, make sure you have read the theme documentation: https://docs.stack.jimmycai.com/
|
||||
-->
|
||||
|
||||
## Describe the bug
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
## Expected behavior
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
## To Reproduce
|
||||
Indicate the steps to reproduce this bug, if applicable.
|
||||
|
||||
## Screenshots
|
||||
Add screenshots to help explain your problem.
|
||||
|
||||
## Environment
|
||||
|
||||
- **Hugo version** [e.g: 0.80.0]:
|
||||
- **Hugo extended?**: Yes / No
|
||||
|
||||
## Additional context
|
||||
Add any other context about the problem here.
|
||||
|
||||
If it's a UI issue, fill the following information:
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
## Content of config.yaml
|
||||
```yaml
|
||||
### Paste the content of the config file here
|
||||
```
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
## Link to the demo site and/or source repository
|
||||
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
public
|
||||
resources
|
||||
assets/jsconfig.json
|
||||
.hugo_build.lock
|
52
README.md
52
README.md
@ -5,13 +5,13 @@
|
||||
|
||||
## Demo
|
||||
|
||||
[Example Site](https://theme-stack.jimmycai.com/)
|
||||
[Example Site](https://demo.stack.jimmycai.com/)
|
||||
|
||||
[](https://app.netlify.com/sites/hugo-theme-stack/deploys)
|
||||
|
||||
## Documentation & more information
|
||||
## Documentation
|
||||
|
||||
[Documentation](https://docs.stack.jimmycai.com/) | [中文文档](https://docs.stack.jimmycai.com/v/zh-cn/)
|
||||
[Documentation](https://docs.stack.jimmycai.com/) | [中文文档](https://docs.stack.jimmycai.com/zh/)
|
||||
|
||||
## Introduction
|
||||
|
||||
@ -27,21 +27,20 @@ Stack is a simple card-style Hugo theme designed for bloggers, some of its featu
|
||||
- No CSS framework, keep it simple and minimal
|
||||
- Properly cropped thumbnails
|
||||
- Subsection support
|
||||
- Table of contents
|
||||
|
||||
## Requirements
|
||||
|
||||
It's necessary to use **Hugo ≥ 0.78.0**.
|
||||
|
||||
Use Hugo Extended version (recommended) if you want to:
|
||||
|
||||
* Use the latest feature/fix from `master` branch
|
||||
* Edit SCSS files
|
||||
|
||||
**Compiled CSS are updated once per release.**
|
||||
It's necessary to use **Hugo Extended ≥ 0.87.0**.
|
||||
|
||||
## Installation
|
||||
|
||||
Clone / Download this repository to `theme` folder, and edit your site config following `exampleSite/config.toml`.
|
||||
* Route 1: Clone / Download this repository to `theme` folder
|
||||
* Route 2: Turn your site into a hugo module and add this theme as a module dependency
|
||||
|
||||
Edit your site config following `exampleSite/config.yaml`.
|
||||
|
||||
*Note: Remove `config.toml` if there is one in the site folder.*
|
||||
|
||||
Check [documentation](https://docs.stack.jimmycai.com/) for more details.
|
||||
|
||||
@ -63,13 +62,22 @@ Your support is greatly appreciated :)
|
||||
|
||||
## Thanks to
|
||||
|
||||
- [Vibrant-Colors/node-vibrant](https://github.com/Vibrant-Colors/node-vibrant)
|
||||
- [Normalize.css](https://necolas.github.io/normalize.css/)
|
||||
- [Tabler icons](https://tablericons.com/)
|
||||
- [Pure CSS implementation of Google Photos / 500px image layout](https://github.com/xieranmaya/blog/issues/6)
|
||||
- [jonsuh/hamburgers](https://github.com/jonsuh/hamburgers)
|
||||
- [PhotoSwipe](https://photoswipe.com/)
|
||||
- [artchen/hexo-theme-element](https://github.com/artchen/hexo-theme-element)
|
||||
- [MunifTanjim/minimo](https://github.com/MunifTanjim/minimo)
|
||||
- [lepture/yue.css](https://github.com/lepture/yue.css)
|
||||
- Markdown gallery syntax from [Typlog](https://typlog.com/)
|
||||
| Project | Description | Licence |
|
||||
| ------- | ----------- | ------- |
|
||||
| [PhotoSwipe](https://photoswipe.com/) | For the lightbox effect | [MIT](https://github.com/dimsemenov/PhotoSwipe/blob/master/LICENSE) |
|
||||
| [Normalize.css](https://github.com/necolas/normalize.css) | - | [MIT](https://github.com/necolas/normalize.css/blob/master/LICENSE.md) |
|
||||
| [Node Vibrant](https://github.com/Vibrant-Colors/node-vibrant) | To extract the color from images | [MIT](https://github.com/Vibrant-Colors/node-vibrant/blob/master/LICENSE.md)
|
||||
| [Tabler icons](https://github.com/tabler/tabler-icons) | Default menu icons | [MIT](https://github.com/tabler/tabler-icons/blob/master/LICENSE) |
|
||||
| [jonsuh/hamburgers](https://github.com/jonsuh/hamburgers) | Hamburger icon of menu | [MIT](https://github.com/jonsuh/hamburgers/blob/master/LICENSE) |
|
||||
| [lepture/yue.css](https://github.com/lepture/yue.css) | Part of it is used for styling article content | MIT |
|
||||
| [Typlog](https://typlog.com/) | Where the markdown gallery syntax is borrowed from | The author gave me the permission |
|
||||
| [Pure CSS implementation of Google Photos / 500px image layout](https://github.com/xieranmaya/blog/issues/6) | Used for image gallery | - |
|
||||
|
||||
### References
|
||||
|
||||
Some references that I took while building this theme:
|
||||
|
||||
| Project | Licence|
|
||||
| ------- | ------|
|
||||
| [artchen/hexo-theme-element](https://github.com/artchen/hexo-theme-element) | [MIT](https://github.com/artchen/hexo-theme-element/blob/master/LICENSE) |
|
||||
| [MunifTanjim/minimo](https://github.com/MunifTanjim/minimo) | [MIT](https://github.com/MunifTanjim/minimo/blob/master/LICENSE) |
|
||||
|
6
assets/icons/brand-github.svg
Normal file
6
assets/icons/brand-github.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-github" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5" />
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 603 B |
6
assets/icons/brand-twitter.svg
Normal file
6
assets/icons/brand-twitter.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-twitter" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M22 4.01c-1 .49 -1.98 .689 -3 .99c-1.121 -1.265 -2.783 -1.335 -4.38 -.737s-2.643 2.06 -2.62 3.737v1c-3.245 .083 -6.135 -1.395 -8 -4c0 0 -4.182 7.433 4 11c-1.872 1.247 -3.739 2.088 -6 2c3.308 1.803 6.913 2.423 10.034 1.517c3.58 -1.04 6.522 -3.723 7.651 -7.742a13.84 13.84 0 0 0 .497 -3.753c-.002 -.249 1.51 -2.772 1.818 -4.013z" />
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 638 B |
9
assets/icons/date.svg
Normal file
9
assets/icons/date.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-calendar-time" width="56" height="56" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M11.795 21h-6.795a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v4" />
|
||||
<circle cx="18" cy="18" r="4" />
|
||||
<path d="M15 3v4" />
|
||||
<path d="M7 3v4" />
|
||||
<path d="M3 11h16" />
|
||||
<path d="M18 16.496v1.504l1 1" />
|
||||
</svg>
|
After Width: | Height: | Size: 508 B |
@ -6,5 +6,7 @@
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"lib": ["es2020", "dom"],
|
||||
"jsx": "preserve"
|
||||
}
|
||||
}
|
@ -1,4 +1,17 @@
|
||||
$on-phone: 812px;
|
||||
$on-tablet: 1024px;
|
||||
$on-desktop: 1519px;
|
||||
$on-desktop-large: 1920px;
|
||||
$breakpoints: (
|
||||
sm: 640px,
|
||||
md: 768px,
|
||||
lg: 1024px,
|
||||
xl: 1280px,
|
||||
2xl: 1536px,
|
||||
);
|
||||
|
||||
@mixin respond($breakpoint) {
|
||||
@if not map-has-key($breakpoints, $breakpoint) {
|
||||
@warn "'#{$breakpoint}' is not a valid breakpoint";
|
||||
} @else {
|
||||
@media (min-width: map-get($breakpoints, $breakpoint)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,67 +2,52 @@
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
.left-sidebar {
|
||||
max-width: var(--left-sidebar-max-width);
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
max-width: var(--right-sidebar-max-width);
|
||||
|
||||
/// Display right sidebar when min-width: lg
|
||||
@include respond(lg) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&.extended {
|
||||
@media (min-width: $on-phone) {
|
||||
max-width: 800px;
|
||||
|
||||
.left-sidebar {
|
||||
width: 25%;
|
||||
}
|
||||
@include respond(md) {
|
||||
max-width: 1024px;
|
||||
--left-sidebar-max-width: 25%;
|
||||
--right-sidebar-max-width: 30%;
|
||||
}
|
||||
|
||||
@media (min-width: $on-tablet) {
|
||||
max-width: 972px;
|
||||
|
||||
.right-sidebar {
|
||||
width: 25%;
|
||||
}
|
||||
@include respond(lg) {
|
||||
max-width: 1280px;
|
||||
--left-sidebar-max-width: 20%;
|
||||
--right-sidebar-max-width: 30%;
|
||||
}
|
||||
|
||||
@media (min-width: $on-desktop) {
|
||||
max-width: 1200px;
|
||||
|
||||
.left-sidebar {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $on-desktop-large) {
|
||||
@include respond(xl) {
|
||||
max-width: 1536px;
|
||||
|
||||
.left-sidebar {
|
||||
width: 15%;
|
||||
}
|
||||
--left-sidebar-max-width: 15%;
|
||||
--right-sidebar-max-width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
&.compact {
|
||||
@media (min-width: $on-phone) {
|
||||
max-width: 800px;
|
||||
|
||||
.left-sidebar {
|
||||
width: 25%;
|
||||
}
|
||||
@include respond(md) {
|
||||
--left-sidebar-max-width: 25%;
|
||||
max-width: 768px;
|
||||
}
|
||||
|
||||
@media (min-width: $on-tablet) {
|
||||
max-width: 972px;
|
||||
@include respond(lg) {
|
||||
max-width: 1024px;
|
||||
--left-sidebar-max-width: 20%;
|
||||
}
|
||||
|
||||
@media (min-width: $on-desktop) {
|
||||
max-width: 1050px;
|
||||
|
||||
.left-sidebar {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $on-desktop-large) {
|
||||
max-width: 1300px;
|
||||
@include respond(xl) {
|
||||
max-width: 1280px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,8 +61,9 @@
|
||||
}
|
||||
|
||||
&.on-phone--column {
|
||||
@media (max-width: $on-phone) {
|
||||
flex-direction: column;
|
||||
flex-direction: column;
|
||||
@include respond(md) {
|
||||
flex-direction: unset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,7 +92,6 @@
|
||||
|
||||
main.main {
|
||||
min-width: 0;
|
||||
padding: 0 15px;
|
||||
max-width: 100%;
|
||||
flex-grow: 1;
|
||||
padding-top: var(--main-top-padding);
|
||||
@ -114,4 +99,11 @@ main.main {
|
||||
|
||||
.main-container {
|
||||
min-height: 100vh;
|
||||
}
|
||||
align-items: flex-start;
|
||||
padding: 0 15px;
|
||||
column-gap: var(--section-separation);
|
||||
|
||||
@include respond(md) {
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
|
@ -24,14 +24,14 @@
|
||||
.article-image {
|
||||
img {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
|
||||
@media (max-width: $on-tablet) {
|
||||
height: 150px;
|
||||
@include respond(md) {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
@media (min-width: $on-desktop-large) {
|
||||
@include respond(xl) {
|
||||
height: 250px;
|
||||
}
|
||||
}
|
||||
@ -62,7 +62,7 @@
|
||||
color: var(--card-text-color-main);
|
||||
font-size: 2.2rem;
|
||||
|
||||
@media (min-width: $on-desktop-large) {
|
||||
@include respond(xl) {
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@
|
||||
line-height: 1.5;
|
||||
|
||||
font-size: 1.75rem;
|
||||
@media (min-width: $on-desktop-large) {
|
||||
@include respond(xl) {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
@ -95,7 +95,9 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--card-text-color-tertiary);
|
||||
gap: 15px;
|
||||
margin-top: 10px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
@ -108,6 +110,11 @@
|
||||
time {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
& > div {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.article-category,
|
||||
@ -135,10 +142,10 @@
|
||||
border-radius: var(--card-border-radius);
|
||||
box-shadow: var(--shadow-l1);
|
||||
background-color: var(--card-background);
|
||||
--image-size: 60px;
|
||||
--image-size: 50px;
|
||||
|
||||
@media (max-width: $on-tablet) {
|
||||
--image-size: 50px;
|
||||
@include respond(md) {
|
||||
--image-size: 60px;
|
||||
}
|
||||
|
||||
& + .pagination {
|
||||
@ -165,10 +172,10 @@
|
||||
|
||||
.article-title {
|
||||
margin: 0;
|
||||
font-size: 1.8rem;
|
||||
font-size: 1.6rem;
|
||||
|
||||
@media (max-width: $on-tablet) {
|
||||
font-size: 1.6rem;
|
||||
@include respond(md) {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,20 +249,20 @@
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
z-index: 2;
|
||||
padding: 20px;
|
||||
padding: 15px;
|
||||
|
||||
@media (max-width: $on-phone) {
|
||||
padding: 15px;
|
||||
@include respond(sm) {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.article-title {
|
||||
font-size: 2.2rem;
|
||||
font-size: 2rem;
|
||||
font-weight: 500;
|
||||
color: var(--card-text-color-main);
|
||||
|
||||
@media (max-width: $on-phone) {
|
||||
font-size: 2rem;
|
||||
@include respond(sm) {
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,3 +15,24 @@ body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* scrollbar styles for Firefox */
|
||||
* {
|
||||
scrollbar-width: auto;
|
||||
scrollbar-color: var(--scrollbar-thumb) transparent;
|
||||
}
|
||||
/**/
|
||||
|
||||
/* scrollbar styles for Chromium */
|
||||
::-webkit-scrollbar {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: var(--scrollbar-thumb);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
/**/
|
||||
|
394
assets/scss/partials/comments/disqusjs.scss
Normal file
394
assets/scss/partials/comments/disqusjs.scss
Normal file
@ -0,0 +1,394 @@
|
||||
.disqus-container {
|
||||
background-color: var(--card-background);
|
||||
border-radius: var(--card-border-radius);
|
||||
box-shadow: var(--shadow-l1);
|
||||
padding: var(--card-padding);
|
||||
}
|
||||
|
||||
#dsqjs * {
|
||||
margin: 0;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
#dsqjs a {
|
||||
text-decoration: none;
|
||||
color: #076dd0
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-hide {
|
||||
display: none!important
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: .5
|
||||
}
|
||||
|
||||
#dsqjs #dsqjs-msg {
|
||||
text-align: center;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
font-size: 14px
|
||||
}
|
||||
|
||||
#dsqjs #dsqjs-msg .dsqjs-msg-btn {
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-bullet {
|
||||
line-height: 1.4;
|
||||
margin: 0 2px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-bullet:after {
|
||||
color: #c2c6cc;
|
||||
content: "·";
|
||||
font-weight: 700
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-clearfix:after,#dsqjs .dsqjs-clearfix:before {
|
||||
display: table;
|
||||
content: "";
|
||||
line-height: 0;
|
||||
clear: both
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-nav {
|
||||
position: relative;
|
||||
margin: 0 0 20px;
|
||||
border-bottom: 2px solid #e7e9ee
|
||||
}
|
||||
|
||||
#dsqjs ol,#dsqjs ul {
|
||||
list-style: none;
|
||||
list-style-type: none
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-no-comment {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
color: #2a2e2e;
|
||||
margin-bottom: 6px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-nav-tab {
|
||||
float: left;
|
||||
text-transform: capitalize;
|
||||
font-size: 15px;
|
||||
padding: 12px 8px;
|
||||
color: #656c7a;
|
||||
display: block;
|
||||
margin: 0 15px 0 0;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
position: relative;
|
||||
transition: all .2s ease-in-out
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-nav-tab:last-child {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-tab-active {
|
||||
color: #2a2e2e
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-tab-active>span:after {
|
||||
content: " ";
|
||||
display: block;
|
||||
height: 2px;
|
||||
background-color: #076dd0!important;
|
||||
position: absolute;
|
||||
bottom: -5px;
|
||||
left: 0;
|
||||
right: 0
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list .dsqjs-post-item {
|
||||
position: relative;
|
||||
margin-bottom: 16px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list .dsqjs-post-avatar {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
position: relative;
|
||||
background: #dbdfe4;
|
||||
padding: 0;
|
||||
display: block;
|
||||
border-radius: 4px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list .dsqjs-post-avatar img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
display: block;
|
||||
border-radius: 4px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list .dsqjs-post-header {
|
||||
line-height: 1;
|
||||
font-size: 14px;
|
||||
margin-bottom: 3px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list .dsqjs-post-header .dsqjs-post-author {
|
||||
color: #656c7a;
|
||||
font-weight: 700
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list .dsqjs-post-header .dsqjs-admin-badge {
|
||||
color: #fff;
|
||||
background: #687a86;
|
||||
padding: 1px 3px;
|
||||
margin-left: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
font-weight: 700;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
left: 1px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list .dsqjs-post-header .dsqjs-meta {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: #656c7a
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-body {
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
color: #2a2e2e
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-body code {
|
||||
padding: .2em .4em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background: #f5f5f5;
|
||||
color: inherit;
|
||||
border-radius: 3px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-body pre {
|
||||
padding: .5em;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
border-radius: 3px;
|
||||
background: #f5f5f5;
|
||||
margin: .5em 0
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-body blockquote {
|
||||
padding: 0 .8em;
|
||||
margin: .5em 0;
|
||||
color: #6a737d;
|
||||
border-left: .25em solid #dfe2e5
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-body p:last-child {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list.dsqjs-children>li {
|
||||
margin-left: 30px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list.dsqjs-children .dsqjs-post-avatar img {
|
||||
width: 38px;
|
||||
height: 38px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-load-more {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding: 11px 14px;
|
||||
margin: 0 0 24px;
|
||||
background: #687a86;
|
||||
color: #fff;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-load-more:hover {
|
||||
opacity: .8
|
||||
}
|
||||
|
||||
#dsqjs footer {
|
||||
text-align: right;
|
||||
line-height: 1.5;
|
||||
padding-top: 10px;
|
||||
padding-right: 10px;
|
||||
border-top: 2px solid #e7e9ee;
|
||||
margin-top: 12px;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
color: #555
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-disqus-logo {
|
||||
background-image: url(https://c.disquscdn.com/next/embed/assets/img/sprite.654110a9206fd22f08cca0798e34a65e.png);
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block;
|
||||
background-size: 86px 40.5px;
|
||||
height: 16.5px;
|
||||
width: 86px;
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-order {
|
||||
display: flex;
|
||||
float: right;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 12px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-order-radio {
|
||||
display: none
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-order-radio:checked+.dsqjs-order-label {
|
||||
color: #fff;
|
||||
background-color: #888
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-order-label {
|
||||
display: block;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
margin-right: 10px;
|
||||
font-size: 12px;
|
||||
border-radius: 2px;
|
||||
padding: 0 5px;
|
||||
background-color: #dcdcdc;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
#dsqjs p.dsqjs-has-more {
|
||||
margin-bottom: 24px;
|
||||
margin-left: 48px;
|
||||
font-size: 13px;
|
||||
line-height: 15px
|
||||
}
|
||||
|
||||
#dsqjs p.dsqjs-has-more a.dsqjs-has-more-btn {
|
||||
color: #656c7a;
|
||||
text-decoration: underline;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#dsqjs .dsqjs-post-list.dsqjs-children>li {
|
||||
margin-left:48px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list .dsqjs-post-avatar {
|
||||
margin-right: 12px
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-list .dsqjs-post-item {
|
||||
margin-bottom: 20px
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
#dsqjs .dsqjs-post-list.dsqjs-children>li {
|
||||
margin-left:60px
|
||||
}
|
||||
}
|
||||
|
||||
:root[data-scheme="light"] {
|
||||
#dsqjs .dsqjs-disqus-logo {
|
||||
background-position: 0 -7px;
|
||||
}
|
||||
}
|
||||
|
||||
:root[data-scheme="dark"] {
|
||||
#dsqjs {
|
||||
--t-s: rgba(255,255,255,0.9);
|
||||
--alt: #3e4b5e;
|
||||
--link-hover: #47a2e0;
|
||||
--hover-bg: #3e4b5e;
|
||||
--tag: #3e4b5e;
|
||||
--border: #435266;
|
||||
--pre: #3c495b;
|
||||
--c-bg: #2f3947;
|
||||
--code: #c3c7cb;
|
||||
--kbd: #4e5f77;
|
||||
--hl: #abb2bf;
|
||||
--hlc: #808895;
|
||||
--hlk: #c678dd;
|
||||
--hln: #e06c75;
|
||||
--hll: #56b6c2;
|
||||
--hls: #98c379;
|
||||
--hlt: #e6c07b;
|
||||
--hlv: #d19a66;
|
||||
--bg: #181c27;
|
||||
--main: #252d38;
|
||||
--t: rgba(255,255,255,0.86);
|
||||
--t-l: rgba(255,255,255,0.66);
|
||||
--logo: #fff;
|
||||
--link: #38a3fd;
|
||||
--title: rgba(255,255,255,0.92);
|
||||
--fab: #364151;
|
||||
--shadow: none;
|
||||
}
|
||||
|
||||
#disqus_thread {
|
||||
color: var(--body-text-color)
|
||||
}
|
||||
|
||||
#dsqjs #dsqjs-msg {
|
||||
color: var(--t)
|
||||
}
|
||||
|
||||
#dsqjs a {
|
||||
color:var(--link)
|
||||
}
|
||||
|
||||
#dsqjs a:focus,#dsqjs a:hover {
|
||||
color: var(--link-hover)
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-disqus-logo {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-nav,#dsqjs footer {
|
||||
border-color: var(--hlc)
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-load-more,#dsqjs .dsqjs-load-more:hover,#dsqjs .dsqjs-nav-tab,#dsqjs .dsqjs-no-comment,#dsqjs .dsqjs-post-content {
|
||||
color: var(--t)
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-order-label {
|
||||
background-color: var(--hlc)
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-order-radio:checked+.dsqjs-order-label {
|
||||
background-color: var(--kbd)
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-tab-active>span:after {
|
||||
background-color: #2e9fff
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-footer,#dsqjs .dsqjs-meta {
|
||||
color: var(--t-l)
|
||||
}
|
||||
|
||||
#dsqjs .dsqjs-post-body blockquote {
|
||||
border-color: var(--border)
|
||||
}
|
||||
}
|
@ -10,7 +10,8 @@
|
||||
}
|
||||
|
||||
/* Other */
|
||||
.chroma .x {}
|
||||
.chroma .x {
|
||||
}
|
||||
|
||||
/* Error */
|
||||
.chroma .err {
|
||||
@ -40,367 +41,369 @@
|
||||
.chroma .hl {
|
||||
display: block;
|
||||
width: 100%;
|
||||
background-color: #ffffcc
|
||||
background-color: #ffffcc;
|
||||
}
|
||||
|
||||
/* LineNumbersTable */
|
||||
.chroma .lnt {
|
||||
margin-right: 0.4em;
|
||||
padding: 0 0.4em 0 0.4em;
|
||||
color: #7f7f7f
|
||||
color: #7f7f7f;
|
||||
}
|
||||
|
||||
/* LineNumbers */
|
||||
.chroma .ln {
|
||||
margin-right: 0.4em;
|
||||
padding: 0 0.4em 0 0.4em;
|
||||
color: #7f7f7f
|
||||
color: #7f7f7f;
|
||||
}
|
||||
|
||||
/* Keyword */
|
||||
.chroma .k {
|
||||
color: #00a8c8
|
||||
color: #00a8c8;
|
||||
}
|
||||
|
||||
/* KeywordConstant */
|
||||
.chroma .kc {
|
||||
color: #00a8c8
|
||||
color: #00a8c8;
|
||||
}
|
||||
|
||||
/* KeywordDeclaration */
|
||||
.chroma .kd {
|
||||
color: #00a8c8
|
||||
color: #00a8c8;
|
||||
}
|
||||
|
||||
/* KeywordNamespace */
|
||||
.chroma .kn {
|
||||
color: #f92672
|
||||
color: #f92672;
|
||||
}
|
||||
|
||||
/* KeywordPseudo */
|
||||
.chroma .kp {
|
||||
color: #00a8c8
|
||||
color: #00a8c8;
|
||||
}
|
||||
|
||||
/* KeywordReserved */
|
||||
.chroma .kr {
|
||||
color: #00a8c8
|
||||
color: #00a8c8;
|
||||
}
|
||||
|
||||
/* KeywordType */
|
||||
.chroma .kt {
|
||||
color: #00a8c8
|
||||
color: #00a8c8;
|
||||
}
|
||||
|
||||
/* Name */
|
||||
.chroma .n {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameAttribute */
|
||||
.chroma .na {
|
||||
color: #75af00
|
||||
color: #75af00;
|
||||
}
|
||||
|
||||
/* NameBuiltin */
|
||||
.chroma .nb {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameBuiltinPseudo */
|
||||
.chroma .bp {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameClass */
|
||||
.chroma .nc {
|
||||
color: #75af00
|
||||
color: #75af00;
|
||||
}
|
||||
|
||||
/* NameConstant */
|
||||
.chroma .no {
|
||||
color: #00a8c8
|
||||
color: #00a8c8;
|
||||
}
|
||||
|
||||
/* NameDecorator */
|
||||
.chroma .nd {
|
||||
color: #75af00
|
||||
color: #75af00;
|
||||
}
|
||||
|
||||
/* NameEntity */
|
||||
.chroma .ni {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameException */
|
||||
.chroma .ne {
|
||||
color: #75af00
|
||||
color: #75af00;
|
||||
}
|
||||
|
||||
/* NameFunction */
|
||||
.chroma .nf {
|
||||
color: #75af00
|
||||
color: #75af00;
|
||||
}
|
||||
|
||||
/* NameFunctionMagic */
|
||||
.chroma .fm {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameLabel */
|
||||
.chroma .nl {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameNamespace */
|
||||
.chroma .nn {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameOther */
|
||||
.chroma .nx {
|
||||
color: #75af00
|
||||
color: #75af00;
|
||||
}
|
||||
|
||||
/* NameProperty */
|
||||
.chroma .py {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameTag */
|
||||
.chroma .nt {
|
||||
color: #f92672
|
||||
color: #f92672;
|
||||
}
|
||||
|
||||
/* NameVariable */
|
||||
.chroma .nv {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameVariableClass */
|
||||
.chroma .vc {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameVariableGlobal */
|
||||
.chroma .vg {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameVariableInstance */
|
||||
.chroma .vi {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* NameVariableMagic */
|
||||
.chroma .vm {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* Literal */
|
||||
.chroma .l {
|
||||
color: #ae81ff
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
/* LiteralDate */
|
||||
.chroma .ld {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralString */
|
||||
.chroma .s {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringAffix */
|
||||
.chroma .sa {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringBacktick */
|
||||
.chroma .sb {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringChar */
|
||||
.chroma .sc {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringDelimiter */
|
||||
.chroma .dl {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringDoc */
|
||||
.chroma .sd {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringDouble */
|
||||
.chroma .s2 {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringEscape */
|
||||
.chroma .se {
|
||||
color: #8045ff
|
||||
color: #8045ff;
|
||||
}
|
||||
|
||||
/* LiteralStringHeredoc */
|
||||
.chroma .sh {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringInterpol */
|
||||
.chroma .si {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringOther */
|
||||
.chroma .sx {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringRegex */
|
||||
.chroma .sr {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringSingle */
|
||||
.chroma .s1 {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralStringSymbol */
|
||||
.chroma .ss {
|
||||
color: #d88200
|
||||
color: #d88200;
|
||||
}
|
||||
|
||||
/* LiteralNumber */
|
||||
.chroma .m {
|
||||
color: #ae81ff
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
/* LiteralNumberBin */
|
||||
.chroma .mb {
|
||||
color: #ae81ff
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
/* LiteralNumberFloat */
|
||||
.chroma .mf {
|
||||
color: #ae81ff
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
/* LiteralNumberHex */
|
||||
.chroma .mh {
|
||||
color: #ae81ff
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
/* LiteralNumberInteger */
|
||||
.chroma .mi {
|
||||
color: #ae81ff
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
/* LiteralNumberIntegerLong */
|
||||
.chroma .il {
|
||||
color: #ae81ff
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
/* LiteralNumberOct */
|
||||
.chroma .mo {
|
||||
color: #ae81ff
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
/* Operator */
|
||||
.chroma .o {
|
||||
color: #f92672
|
||||
color: #f92672;
|
||||
}
|
||||
|
||||
/* OperatorWord */
|
||||
.chroma .ow {
|
||||
color: #f92672
|
||||
color: #f92672;
|
||||
}
|
||||
|
||||
/* Punctuation */
|
||||
.chroma .p {
|
||||
color: #111111
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* Comment */
|
||||
.chroma .c {
|
||||
color: #75715e
|
||||
color: #75715e;
|
||||
}
|
||||
|
||||
/* CommentHashbang */
|
||||
.chroma .ch {
|
||||
color: #75715e
|
||||
color: #75715e;
|
||||
}
|
||||
|
||||
/* CommentMultiline */
|
||||
.chroma .cm {
|
||||
color: #75715e
|
||||
color: #75715e;
|
||||
}
|
||||
|
||||
/* CommentSingle */
|
||||
.chroma .c1 {
|
||||
color: #75715e
|
||||
color: #75715e;
|
||||
}
|
||||
|
||||
/* CommentSpecial */
|
||||
.chroma .cs {
|
||||
color: #75715e
|
||||
color: #75715e;
|
||||
}
|
||||
|
||||
/* CommentPreproc */
|
||||
.chroma .cp {
|
||||
color: #75715e
|
||||
color: #75715e;
|
||||
}
|
||||
|
||||
/* CommentPreprocFile */
|
||||
.chroma .cpf {
|
||||
color: #75715e
|
||||
color: #75715e;
|
||||
}
|
||||
|
||||
/* Generic */
|
||||
.chroma .g {}
|
||||
|
||||
.chroma .g {
|
||||
}
|
||||
/* GenericDeleted */
|
||||
.chroma .gd {}
|
||||
|
||||
.chroma .gd {
|
||||
color: #f92672;
|
||||
}
|
||||
/* GenericEmph */
|
||||
.chroma .ge {
|
||||
font-style: italic
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* GenericError */
|
||||
.chroma .gr {}
|
||||
|
||||
.chroma .gr {
|
||||
}
|
||||
/* GenericHeading */
|
||||
.chroma .gh {}
|
||||
|
||||
.chroma .gh {
|
||||
}
|
||||
/* GenericInserted */
|
||||
.chroma .gi {}
|
||||
|
||||
.chroma .gi {
|
||||
color: #7ca727;
|
||||
}
|
||||
/* GenericOutput */
|
||||
.chroma .go {}
|
||||
|
||||
.chroma .go {
|
||||
}
|
||||
/* GenericPrompt */
|
||||
.chroma .gp {}
|
||||
|
||||
.chroma .gp {
|
||||
}
|
||||
/* GenericStrong */
|
||||
.chroma .gs {
|
||||
font-weight: bold
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* GenericSubheading */
|
||||
.chroma .gu {}
|
||||
|
||||
.chroma .gu {
|
||||
color: #75715e;
|
||||
}
|
||||
/* GenericTraceback */
|
||||
.chroma .gt {}
|
||||
|
||||
.chroma .gt {
|
||||
}
|
||||
/* GenericUnderline */
|
||||
.chroma .gl {}
|
||||
|
||||
.chroma .gl {
|
||||
}
|
||||
/* TextWhitespace */
|
||||
.chroma .w {}
|
||||
.chroma .w {
|
||||
}
|
||||
|
@ -1,43 +1,9 @@
|
||||
.keep-sidebar {
|
||||
@media (min-width: $on-phone) and (max-width: $on-tablet) {
|
||||
--main-top-padding: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.article-page {
|
||||
&.with-toolbar {
|
||||
@media (max-width: $on-tablet) {
|
||||
--main-top-padding: 0;
|
||||
}
|
||||
}
|
||||
&.hide-sidebar-sm .left-sidebar {
|
||||
display: none;
|
||||
|
||||
&:not(.keep-sidebar) .left-sidebar {
|
||||
@media (max-width: $on-tablet) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.article-sidebar {
|
||||
position: sticky;
|
||||
top: 50px;
|
||||
flex-shrink: 0;
|
||||
|
||||
@media (max-width: $on-tablet) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: $on-tablet) {
|
||||
padding-left: 15px;
|
||||
margin-left: 1%;
|
||||
}
|
||||
|
||||
@media (min-width: $on-tablet) {
|
||||
width: 25%;
|
||||
margin-right: 1%;
|
||||
}
|
||||
|
||||
@media (min-width: $on-desktop) {
|
||||
width: 30%;
|
||||
@include respond(md) {
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,6 +70,13 @@
|
||||
flex-wrap: wrap;
|
||||
text-transform: unset;
|
||||
}
|
||||
|
||||
.article-copyright,
|
||||
.article-lastmod {
|
||||
a {
|
||||
color: var(--body-text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,12 +84,9 @@
|
||||
#article-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 20px 0;
|
||||
|
||||
@media (max-width: $on-tablet) {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
@media (min-width: $on-tablet) {
|
||||
@include respond(md) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -147,6 +117,157 @@
|
||||
|
||||
span {
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.article-page.has-toc {
|
||||
.left-sidebar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
display: none;
|
||||
|
||||
@include respond(xl) {
|
||||
display: block;
|
||||
top: var(--main-top-padding);
|
||||
}
|
||||
}
|
||||
|
||||
#article-toolbar {
|
||||
display: block;
|
||||
|
||||
@include respond(md) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@include respond(xl) {
|
||||
margin-top: 0;
|
||||
position: sticky;
|
||||
top: var(--main-top-padding);
|
||||
flex-shrink: 1;
|
||||
|
||||
a {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
border: 1px solid var(--body-text-color);
|
||||
width: 100%;
|
||||
margin-right: 0;
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-container {
|
||||
align-items: start;
|
||||
flex-direction: column;
|
||||
|
||||
@include respond(xl) {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
padding-top: 0;
|
||||
|
||||
@include respond(xl) {
|
||||
padding-top: var(--main-top-padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.widget--toc {
|
||||
background-color: var(--card-background);
|
||||
border-radius: var(--card-border-radius);
|
||||
box-shadow: var(--shadow-l1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--card-text-color-main);
|
||||
overflow: hidden;
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: var(--card-separator-color);
|
||||
}
|
||||
|
||||
#TableOfContents {
|
||||
overflow-x: auto;
|
||||
max-height: 75vh;
|
||||
|
||||
ol,
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style-type: none;
|
||||
counter-reset: item;
|
||||
|
||||
li a::before {
|
||||
counter-increment: item;
|
||||
content: counters(item, ".") ". ";
|
||||
font-weight: bold;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
& > ul {
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 15px 0 15px 20px;
|
||||
padding: 5px;
|
||||
|
||||
& > ol,
|
||||
& > ul {
|
||||
margin-top: 10px;
|
||||
padding-left: 10px;
|
||||
margin-bottom: -5px;
|
||||
|
||||
& > li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
li.active-class > a {
|
||||
border-left: var(--heading-border-size) solid var(--accent-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul li.active-class > a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@function repeat($str, $n) {
|
||||
$result: "";
|
||||
@for $_ from 0 to $n {
|
||||
$result: $result + $str;
|
||||
}
|
||||
@return $result;
|
||||
}
|
||||
|
||||
// Support up to 6 levels of indentation for lists in ToCs
|
||||
@for $i from 0 to 5 {
|
||||
& > ul #{repeat("> li > ul", $i)} > li.active-class > a {
|
||||
$n: 25 + $i * 35;
|
||||
margin-left: calc(-#{$n}px - 1em);
|
||||
padding-left: calc(#{$n}px + 1em - var(--heading-border-size));
|
||||
}
|
||||
|
||||
& > ol #{repeat("> li > ol", $i)} > li.active-class > a {
|
||||
$n: 9 + $i * 35;
|
||||
margin-left: calc(-#{$n}px - 1em);
|
||||
padding-left: calc(#{$n}px + 1em - var(--heading-border-size));
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,11 +308,11 @@
|
||||
.article-content {
|
||||
font-family: var(--article-font-family);
|
||||
font-size: var(--article-font-size);
|
||||
padding: 0 var(--card-padding);
|
||||
line-height: var(--article-line-height);
|
||||
|
||||
& > p {
|
||||
margin: 1.5em 0;
|
||||
padding: 0 var(--card-padding);
|
||||
}
|
||||
|
||||
h1,
|
||||
@ -200,12 +321,12 @@
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
padding: 0 calc(var(--card-padding) - var(--heading-border-size));
|
||||
margin-left: calc((var(--card-padding)) * -1);
|
||||
padding-left: calc(var(--card-padding) - var(--heading-border-size));
|
||||
border-left: var(--heading-border-size) solid var(--accent-color);
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
|
||||
figcaption {
|
||||
@ -216,17 +337,12 @@
|
||||
|
||||
blockquote {
|
||||
position: relative;
|
||||
margin: 10px 0;
|
||||
margin: 1.5em 0;
|
||||
border-left: var(--blockquote-border-size) solid var(--card-separator-color);
|
||||
padding: 15px calc(var(--card-padding) - var(--blockquote-border-size));
|
||||
background-color: var(--blockquote-background-color);
|
||||
}
|
||||
|
||||
& > ul,
|
||||
& > ol {
|
||||
margin: 1em var(--card-padding);
|
||||
}
|
||||
|
||||
hr {
|
||||
width: 100px;
|
||||
margin: 40px auto;
|
||||
@ -249,7 +365,7 @@
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
margin: 20px 0;
|
||||
margin: 1.5em 0;
|
||||
|
||||
figure {
|
||||
margin: 0;
|
||||
@ -278,10 +394,49 @@
|
||||
}
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: var(--pre-background-color);
|
||||
padding: var(--card-padding);
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
.copyCodeButton {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: initial;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.copyCodeButton {
|
||||
position: absolute;
|
||||
top: calc(var(--card-padding));
|
||||
right: calc(var(--card-padding));
|
||||
background: var(--card-background);
|
||||
border: none;
|
||||
box-shadow: var(--shadow-l2);
|
||||
border-radius: var(--tag-border-radius);
|
||||
padding: 8px 16px;
|
||||
color: var(--card-text-color-main);
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
padding: 0 var(--card-padding);
|
||||
overflow-x: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 0 var(--card-padding);
|
||||
width: 100%;
|
||||
max-width: calc(100% - var(--card-padding) * 2);
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
margin-bottom: 1.5em;
|
||||
@ -306,4 +461,36 @@
|
||||
.twitter-tweet {
|
||||
color: var(--card-text-color-main);
|
||||
}
|
||||
|
||||
.video-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-bottom: 56.25%;
|
||||
overflow: hidden;
|
||||
|
||||
& > iframe,
|
||||
& > video {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Negative margins
|
||||
blockquote,
|
||||
figure,
|
||||
.highlight,
|
||||
pre,
|
||||
.gallery,
|
||||
.video-wrapper,
|
||||
.table-wrapper,
|
||||
.s_video_simple {
|
||||
margin-left: calc((var(--card-padding)) * -1);
|
||||
margin-right: calc((var(--card-padding)) * -1);
|
||||
width: calc(100% + var(--card-padding) * 2);
|
||||
}
|
||||
}
|
||||
|
@ -106,9 +106,10 @@
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
|
||||
@media (min-width: $on-phone + 1) {
|
||||
@include respond(md) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
outline: none;
|
||||
|
||||
&.is-active {
|
||||
@ -126,67 +127,59 @@
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: var(--sidebar-element-separation);
|
||||
margin-bottom: 0;
|
||||
overflow-y: auto;
|
||||
flex-grow: 1;
|
||||
font-size: 1.5rem;
|
||||
font-size: 1.4rem;
|
||||
|
||||
@media (min-width: $on-desktop-large) {
|
||||
margin-top: 30px;
|
||||
background-color: var(--card-background);
|
||||
padding: 15px 0;
|
||||
box-shadow: var(--shadow-l1);
|
||||
display: none;
|
||||
|
||||
margin: 0 -15px;
|
||||
|
||||
&.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (max-width: $on-phone) {
|
||||
background-color: var(--card-background);
|
||||
margin-top: 0;
|
||||
padding: 15px 0;
|
||||
box-shadow: var(--shadow-l1);
|
||||
display: none;
|
||||
|
||||
&.show {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $on-phone + 1) {
|
||||
@include respond(md) {
|
||||
align-items: flex-end;
|
||||
display: flex;
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
margin-top: var(--sidebar-element-separation);
|
||||
}
|
||||
|
||||
@include respond(xl) {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
padding: 10px 0;
|
||||
padding: 10px 30px;
|
||||
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: 15px;
|
||||
|
||||
@media (min-width: $on-desktop-large) {
|
||||
@include respond(xl) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $on-phone) {
|
||||
padding: 10px 30px;
|
||||
}
|
||||
|
||||
@media (min-width: $on-phone + 1) and (max-width: ($on-desktop - 1)) {
|
||||
@include respond(md) {
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
@media (min-width: $on-phone + 1) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
stroke-width: 1.33;
|
||||
margin-right: 40px;
|
||||
|
||||
@media (max-width: $on-desktop-large) {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
a {
|
||||
@ -194,10 +187,6 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--body-text-color);
|
||||
|
||||
@media (max-width: $on-desktop-large) {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
@ -212,3 +201,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.social-menu {
|
||||
list-style: none;
|
||||
padding: 0%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
|
||||
svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
stroke: var(--body-text-color);
|
||||
stroke-width: 1.33;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
.sidebar {
|
||||
padding: 0 15px;
|
||||
&.sticky {
|
||||
@media (min-width: ($on-phone + 1)) {
|
||||
@include respond(md) {
|
||||
position: sticky;
|
||||
}
|
||||
}
|
||||
@ -11,45 +10,41 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
align-self: stretch;
|
||||
|
||||
--sidebar-avatar-size: 150px;
|
||||
--sidebar-element-separation: 25px;
|
||||
width: 100%;
|
||||
padding: 30px 0 15px 0;
|
||||
max-width: none;
|
||||
|
||||
@media (max-width: $on-desktop-large) {
|
||||
--sidebar-avatar-size: 120px;
|
||||
--sidebar-element-separation: 20px;
|
||||
--sidebar-avatar-size: 120px;
|
||||
--sidebar-element-separation: 20px;
|
||||
|
||||
@include respond(md) {
|
||||
width: auto;
|
||||
padding-top: var(--main-top-padding);
|
||||
padding-bottom: var(--main-top-padding);
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
@media (max-width: $on-phone) {
|
||||
width: 100%;
|
||||
padding: 30px 0;
|
||||
max-width: none;
|
||||
@include respond(2xl) {
|
||||
--sidebar-avatar-size: 140px;
|
||||
--sidebar-element-separation: 25px;
|
||||
}
|
||||
|
||||
&.sticky {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
@media (min-width: $on-phone + 1) {
|
||||
margin-right: 1%;
|
||||
padding: var(--main-top-padding) 15px;
|
||||
max-height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
flex-shrink: 0;
|
||||
display: none;
|
||||
|
||||
&.sticky {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
@media (max-width: $on-desktop - 1) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: $on-tablet) {
|
||||
margin-left: 1%;
|
||||
@include respond(lg) {
|
||||
padding-top: var(--main-top-padding);
|
||||
}
|
||||
}
|
||||
@ -58,8 +53,10 @@
|
||||
z-index: 1;
|
||||
transition: box-shadow 0.5s ease;
|
||||
|
||||
@media (max-width: $on-phone) {
|
||||
padding: 15px 30px;
|
||||
padding: 15px;
|
||||
|
||||
@include respond(md) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.site-avatar {
|
||||
@ -79,9 +76,9 @@
|
||||
|
||||
.emoji {
|
||||
position: absolute;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border-radius: 100%;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
@ -90,20 +87,20 @@
|
||||
background-color: var(--card-background);
|
||||
box-shadow: var(--shadow-l2);
|
||||
|
||||
@media (max-width: $on-desktop-large) {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
@include respond(2xl) {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.site-name {
|
||||
color: var(--accent-color);
|
||||
font-size: 2.4rem;
|
||||
margin: 0;
|
||||
font-size: 1.8rem;
|
||||
|
||||
@media (max-width: $on-desktop-large) {
|
||||
@include respond(2xl) {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
@ -112,10 +109,10 @@
|
||||
color: var(--body-text-color);
|
||||
font-weight: normal;
|
||||
margin: 10px 0;
|
||||
font-size: 1.8rem;
|
||||
font-size: 1.6rem;
|
||||
|
||||
@media (max-width: $on-desktop-large) {
|
||||
font-size: 1.6rem;
|
||||
@include respond(2xl) {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,15 @@
|
||||
$defaultTagBackgrounds: #8ea885, #df7988, #0177b8, #ffb900, #6b69d6;
|
||||
$defaultTagColors: #fff, #fff, #fff, #fff, #fff;
|
||||
|
||||
[data-scheme="light"] {
|
||||
--pre-text-color: #272822;
|
||||
--pre-background-color: #fafafa;
|
||||
@import "partials/highlight/light.scss";
|
||||
}
|
||||
|
||||
[data-scheme="dark"] {
|
||||
--pre-text-color: #f8f8f2;
|
||||
--pre-background-color: #272822;
|
||||
@import "partials/highlight/dark.scss";
|
||||
}
|
||||
|
||||
/*
|
||||
* Global style
|
||||
*/
|
||||
:root {
|
||||
@media (min-width: $on-phone + 1) {
|
||||
@include respond(md) {
|
||||
--main-top-padding: 35px;
|
||||
}
|
||||
|
||||
@media (min-width: $on-desktop-large) {
|
||||
@include respond(xl) {
|
||||
--main-top-padding: 50px;
|
||||
}
|
||||
|
||||
@ -36,12 +24,17 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
|
||||
|
||||
--section-separation: 40px;
|
||||
|
||||
[data-scheme="dark"] {
|
||||
--scrollbar-thumb: hsl(0, 0%, 85%);
|
||||
--scrollbar-track: var(--body-background);
|
||||
|
||||
&[data-scheme="dark"] {
|
||||
--body-background: #303030;
|
||||
--accent-color: #ecf0f1;
|
||||
--accent-color-darker: #bdc3c7;
|
||||
--accent-color-text: #000;
|
||||
--body-text-color: rgba(255, 255, 255, 0.7);
|
||||
--scrollbar-thumb: hsl(0, 0%, 40%);
|
||||
--scrollbar-track: var(--body-background);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,20 +63,23 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
|
||||
|
||||
--card-border-radius: 10px;
|
||||
|
||||
--card-padding: 30px;
|
||||
@media (max-width: $on-desktop-large) {
|
||||
--card-padding: 20px;
|
||||
|
||||
@include respond(md) {
|
||||
--card-padding: 25px;
|
||||
}
|
||||
@media (max-width: $on-tablet) {
|
||||
--card-padding: 20px;
|
||||
|
||||
@include respond(xl) {
|
||||
--card-padding: 30px;
|
||||
}
|
||||
|
||||
--small-card-padding: 25px;
|
||||
@media (max-width: $on-tablet) {
|
||||
--small-card-padding: 25px 20px;
|
||||
--small-card-padding: 25px 20px;
|
||||
|
||||
@include respond(md) {
|
||||
--small-card-padding: 25px;
|
||||
}
|
||||
|
||||
[data-scheme="dark"] {
|
||||
&[data-scheme="dark"] {
|
||||
--card-background: #424242;
|
||||
--card-background-selected: rgba(255, 255, 255, 0.16);
|
||||
--card-text-color-main: rgba(255, 255, 255, 0.9);
|
||||
@ -98,10 +94,12 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
|
||||
*/
|
||||
:root {
|
||||
--article-font-family: var(--base-font-family);
|
||||
--article-font-size: 1.7rem;
|
||||
@media (max-width: $on-tablet) {
|
||||
--article-font-size: 1.6rem;
|
||||
--article-font-size: 1.6rem;
|
||||
|
||||
@include respond(md) {
|
||||
--article-font-size: 1.7rem;
|
||||
}
|
||||
|
||||
--article-line-height: 1.85;
|
||||
}
|
||||
|
||||
@ -127,7 +125,7 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
|
||||
--table-border-color: #dadada;
|
||||
--tr-even-background-color: #efefee;
|
||||
|
||||
[data-scheme="dark"] {
|
||||
&[data-scheme="dark"] {
|
||||
--code-background-color: #272822;
|
||||
--code-text-color: rgba(255, 255, 255, 0.9);
|
||||
|
||||
@ -149,3 +147,15 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
|
||||
--shadow-l4: 0px 24px 32px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04), 0px 4px 8px rgba(0, 0, 0, 0.04),
|
||||
0px 0px 1px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
[data-scheme="light"] {
|
||||
--pre-text-color: #272822;
|
||||
--pre-background-color: #fafafa;
|
||||
@import "partials/highlight/light.scss";
|
||||
}
|
||||
|
||||
[data-scheme="dark"] {
|
||||
--pre-text-color: #f8f8f2;
|
||||
--pre-background-color: #272822;
|
||||
@import "partials/highlight/dark.scss";
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ class StackColorScheme {
|
||||
this.bindMatchMedia();
|
||||
this.currentScheme = this.getSavedScheme();
|
||||
|
||||
this.dispatchEvent(document.body.dataset.scheme as colorScheme);
|
||||
this.dispatchEvent(document.documentElement.dataset.scheme as colorScheme);
|
||||
|
||||
if (toggleEl)
|
||||
this.bindClick(toggleEl);
|
||||
@ -22,7 +22,7 @@ class StackColorScheme {
|
||||
localStorage.setItem(this.localStorageKey, this.currentScheme);
|
||||
}
|
||||
|
||||
private bindClick(toggleEl) {
|
||||
private bindClick(toggleEl: HTMLElement) {
|
||||
toggleEl.addEventListener('click', (e) => {
|
||||
if (this.isDark()) {
|
||||
/// Disable dark mode
|
||||
@ -56,13 +56,13 @@ class StackColorScheme {
|
||||
|
||||
private setBodyClass() {
|
||||
if (this.isDark()) {
|
||||
document.body.dataset.scheme = 'dark';
|
||||
document.documentElement.dataset.scheme = 'dark';
|
||||
}
|
||||
else {
|
||||
document.body.dataset.scheme = 'light';
|
||||
document.documentElement.dataset.scheme = 'light';
|
||||
}
|
||||
|
||||
this.dispatchEvent(document.body.dataset.scheme as colorScheme);
|
||||
this.dispatchEvent(document.documentElement.dataset.scheme as colorScheme);
|
||||
}
|
||||
|
||||
private getSavedScheme(): colorScheme {
|
||||
@ -85,4 +85,4 @@ class StackColorScheme {
|
||||
}
|
||||
}
|
||||
|
||||
export default StackColorScheme;
|
||||
export default StackColorScheme;
|
||||
|
@ -34,7 +34,7 @@ class StackGallery {
|
||||
private loadItems(container: HTMLElement) {
|
||||
this.items = [];
|
||||
|
||||
const figures = container.querySelectorAll('figure');
|
||||
const figures = container.querySelectorAll('figure.gallery-image');
|
||||
|
||||
for (const el of figures) {
|
||||
const figcaption = el.querySelector('figcaption'),
|
||||
@ -57,7 +57,61 @@ class StackGallery {
|
||||
}
|
||||
|
||||
public static createGallery(container: HTMLElement) {
|
||||
const figuresEl = container.querySelectorAll('figure');
|
||||
/// The process of wrapping image with figure tag is done using JavaScript instead of only Hugo markdown render hook
|
||||
/// because it can not detect whether image is being wrapped by a link or not
|
||||
/// and it lead to a invalid HTML construction (<a><figure><img></figure></a>)
|
||||
|
||||
const images = container.querySelectorAll('img');
|
||||
for (const img of Array.from(images)) {
|
||||
/// Images are wrapped with figure tag if the paragraph has only images without texts
|
||||
/// This is done to allow inline images within paragraphs
|
||||
const paragraph = img.closest('p');
|
||||
|
||||
if (!paragraph || !container.contains(paragraph)) continue;
|
||||
|
||||
if (paragraph.textContent.trim() == '') {
|
||||
/// Once we insert figcaption, this check no longer works
|
||||
/// So we add a class to paragraph to mark it
|
||||
paragraph.classList.add('no-text');
|
||||
}
|
||||
|
||||
let isNewLineImage = paragraph.classList.contains('no-text');
|
||||
if (!isNewLineImage) continue;
|
||||
|
||||
const hasLink = img.parentElement.tagName == 'A';
|
||||
|
||||
let el: HTMLElement = img;
|
||||
/// Wrap image with figure tag, with flex-grow and flex-basis values extracted from img's data attributes
|
||||
const figure = document.createElement('figure');
|
||||
figure.style.setProperty('flex-grow', img.getAttribute('data-flex-grow') || '1');
|
||||
figure.style.setProperty('flex-basis', img.getAttribute('data-flex-basis') || '0');
|
||||
if (hasLink) {
|
||||
/// Wrap <a> if it exists
|
||||
el = img.parentElement;
|
||||
}
|
||||
el.parentElement.insertBefore(figure, el);
|
||||
figure.appendChild(el);
|
||||
|
||||
/// Add figcaption if it exists
|
||||
if (img.hasAttribute('alt')) {
|
||||
const figcaption = document.createElement('figcaption');
|
||||
figcaption.innerText = img.getAttribute('alt');
|
||||
figure.appendChild(figcaption);
|
||||
}
|
||||
|
||||
/// Wrap img tag with <a> tag if image was not wrapped by <a> tag
|
||||
if (!hasLink) {
|
||||
figure.className = 'gallery-image';
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = img.src;
|
||||
a.setAttribute('target', '_blank');
|
||||
img.parentNode.insertBefore(a, img);
|
||||
a.appendChild(img);
|
||||
}
|
||||
}
|
||||
|
||||
const figuresEl = container.querySelectorAll('figure.gallery-image');
|
||||
|
||||
let currentGallery = [];
|
||||
|
||||
|
@ -10,6 +10,8 @@ import { getColor } from 'ts/color';
|
||||
import menu from 'ts/menu';
|
||||
import createElement from 'ts/createElement';
|
||||
import StackColorScheme from 'ts/colorScheme';
|
||||
import { setupScrollspy } from 'ts/scrollspy';
|
||||
import { setupSmoothAnchors } from "ts/smoothAnchors";
|
||||
|
||||
let Stack = {
|
||||
init: () => {
|
||||
@ -21,6 +23,8 @@ let Stack = {
|
||||
const articleContent = document.querySelector('.article-content') as HTMLElement;
|
||||
if (articleContent) {
|
||||
new StackGallery(articleContent);
|
||||
setupSmoothAnchors();
|
||||
setupScrollspy();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,6 +58,39 @@ let Stack = {
|
||||
observer.observe(articleTile)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add copy button to code block
|
||||
*/
|
||||
const highlights = document.querySelectorAll('.article-content div.highlight');
|
||||
const copyText = `Copy`,
|
||||
copiedText = `Copied!`;
|
||||
|
||||
highlights.forEach(highlight => {
|
||||
const copyButton = document.createElement('button');
|
||||
copyButton.innerHTML = copyText;
|
||||
copyButton.classList.add('copyCodeButton');
|
||||
highlight.appendChild(copyButton);
|
||||
|
||||
const codeBlock = highlight.querySelector('code[data-lang]');
|
||||
if (!codeBlock) return;
|
||||
|
||||
copyButton.addEventListener('click', () => {
|
||||
navigator.clipboard.writeText(codeBlock.textContent)
|
||||
.then(() => {
|
||||
copyButton.textContent = copiedText;
|
||||
|
||||
setTimeout(() => {
|
||||
copyButton.textContent = copyText;
|
||||
}, 1000);
|
||||
})
|
||||
.catch(err => {
|
||||
alert(err)
|
||||
console.log('Something went wrong', err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
new StackColorScheme(document.getElementById('dark-mode-toggle'));
|
||||
}
|
||||
}
|
||||
|
131
assets/ts/scrollspy.ts
Normal file
131
assets/ts/scrollspy.ts
Normal file
@ -0,0 +1,131 @@
|
||||
// Implements a scroll spy system for the ToC, displaying the current section with an indicator and scrolling to it when needed.
|
||||
|
||||
// Inspired from https://gomakethings.com/debouncing-your-javascript-events/
|
||||
function debounced(func: Function) {
|
||||
let timeout;
|
||||
return () => {
|
||||
if (timeout) {
|
||||
window.cancelAnimationFrame(timeout);
|
||||
}
|
||||
|
||||
timeout = window.requestAnimationFrame(() => func());
|
||||
}
|
||||
}
|
||||
|
||||
const headersQuery = ".article-content h1[id], .article-content h2[id], .article-content h3[id], .article-content h4[id], .article-content h5[id], .article-content h6[id]";
|
||||
const tocQuery = "#TableOfContents";
|
||||
const navigationQuery = "#TableOfContents li";
|
||||
const activeClass = "active-class";
|
||||
|
||||
function scrollToTocElement(tocElement: HTMLElement, scrollableNavigation: HTMLElement) {
|
||||
let textHeight = tocElement.querySelector("a").offsetHeight;
|
||||
let scrollTop = tocElement.offsetTop - scrollableNavigation.offsetHeight / 2 + textHeight / 2 - scrollableNavigation.offsetTop;
|
||||
if (scrollTop < 0) {
|
||||
scrollTop = 0;
|
||||
}
|
||||
scrollableNavigation.scrollTo({ top: scrollTop, behavior: "smooth" });
|
||||
}
|
||||
|
||||
type IdToElementMap = { [key: string]: HTMLElement };
|
||||
|
||||
function buildIdToNavigationElementMap(navigation: NodeListOf<Element>): IdToElementMap {
|
||||
const sectionLinkRef: IdToElementMap = {};
|
||||
navigation.forEach((navigationElement: HTMLElement) => {
|
||||
const link = navigationElement.querySelector("a");
|
||||
const href = link.getAttribute("href");
|
||||
if (href.startsWith("#")) {
|
||||
sectionLinkRef[href.slice(1)] = navigationElement;
|
||||
}
|
||||
});
|
||||
|
||||
return sectionLinkRef;
|
||||
}
|
||||
|
||||
function computeOffsets(headers: NodeListOf<Element>) {
|
||||
let sectionsOffsets = [];
|
||||
headers.forEach((header: HTMLElement) => { sectionsOffsets.push({ id: header.id, offset: header.offsetTop }) });
|
||||
sectionsOffsets.sort((a, b) => a.offset - b.offset);
|
||||
return sectionsOffsets;
|
||||
}
|
||||
|
||||
function setupScrollspy() {
|
||||
let headers = document.querySelectorAll(headersQuery);
|
||||
if (!headers) {
|
||||
console.warn("No header matched query", headers);
|
||||
return;
|
||||
}
|
||||
|
||||
let scrollableNavigation = document.querySelector(tocQuery) as HTMLElement | undefined;
|
||||
if (!scrollableNavigation) {
|
||||
console.warn("No toc matched query", tocQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
let navigation = document.querySelectorAll(navigationQuery);
|
||||
if (!navigation) {
|
||||
console.warn("No navigation matched query", navigationQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
let sectionsOffsets = computeOffsets(headers);
|
||||
|
||||
// We need to avoid scrolling when the user is actively interacting with the ToC. Otherwise, if the user clicks on a link in the ToC,
|
||||
// we would scroll their view, which is not optimal usability-wise.
|
||||
let tocHovered: boolean = false;
|
||||
scrollableNavigation.addEventListener("mouseenter", debounced(() => tocHovered = true));
|
||||
scrollableNavigation.addEventListener("mouseleave", debounced(() => tocHovered = false));
|
||||
|
||||
let activeSectionLink: Element;
|
||||
|
||||
let idToNavigationElement: IdToElementMap = buildIdToNavigationElementMap(navigation);
|
||||
|
||||
function scrollHandler() {
|
||||
let scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
|
||||
let newActiveSection: HTMLElement | undefined;
|
||||
|
||||
// Find the section that is currently active.
|
||||
// It is possible for no section to be active, so newActiveSection may be undefined.
|
||||
sectionsOffsets.forEach((section) => {
|
||||
if (scrollPosition >= section.offset - 20) {
|
||||
newActiveSection = document.getElementById(section.id);
|
||||
}
|
||||
});
|
||||
|
||||
// Find the link for the active section. Once again, there are a few edge cases:
|
||||
// - No active section = no link => undefined
|
||||
// - No active section but the link does not exist in toc (e.g. because it is outside of the applicable ToC levels) => undefined
|
||||
let newActiveSectionLink: HTMLElement | undefined
|
||||
if (newActiveSection) {
|
||||
newActiveSectionLink = idToNavigationElement[newActiveSection.id];
|
||||
}
|
||||
|
||||
if (newActiveSection && !newActiveSectionLink) {
|
||||
// The active section does not have a link in the ToC, so we can't scroll to it.
|
||||
console.debug("No link found for section", newActiveSection);
|
||||
} else if (newActiveSectionLink !== activeSectionLink) {
|
||||
if (activeSectionLink)
|
||||
activeSectionLink.classList.remove(activeClass);
|
||||
if (newActiveSectionLink) {
|
||||
newActiveSectionLink.classList.add(activeClass);
|
||||
if (!tocHovered) {
|
||||
// Scroll so that newActiveSectionLink is in the middle of scrollableNavigation, except when it's from a manual click (hence the tocHovered check)
|
||||
scrollToTocElement(newActiveSectionLink, scrollableNavigation);
|
||||
}
|
||||
}
|
||||
activeSectionLink = newActiveSectionLink;
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("scroll", debounced(scrollHandler));
|
||||
|
||||
// Resizing may cause the offset values to change: recompute them.
|
||||
function resizeHandler() {
|
||||
sectionsOffsets = computeOffsets(headers);
|
||||
scrollHandler();
|
||||
}
|
||||
|
||||
window.addEventListener("resize", debounced(resizeHandler));
|
||||
}
|
||||
|
||||
export { setupScrollspy };
|
@ -8,6 +8,11 @@ interface pageData {
|
||||
matchCount: number
|
||||
}
|
||||
|
||||
interface match {
|
||||
start: number,
|
||||
end: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape HTML tags as HTML entities
|
||||
* Edited from:
|
||||
@ -53,79 +58,131 @@ class Search {
|
||||
this.bindSearchForm();
|
||||
}
|
||||
|
||||
private async searchKeywords(keywords: string[]) {
|
||||
const rawData = await this.getData();
|
||||
let results: pageData[] = [];
|
||||
|
||||
/// Sort keywords by their length
|
||||
keywords.sort((a, b) => {
|
||||
return b.length - a.length
|
||||
/**
|
||||
* Processes search matches
|
||||
* @param str original text
|
||||
* @param matches array of matches
|
||||
* @param ellipsis whether to add ellipsis to the end of each match
|
||||
* @param charLimit max length of preview string
|
||||
* @param offset how many characters before and after the match to include in preview
|
||||
* @returns preview string
|
||||
*/
|
||||
private static processMatches(str: string, matches: match[], ellipsis: boolean = true, charLimit = 140, offset = 20): string {
|
||||
matches.sort((a, b) => {
|
||||
return a.start - b.start;
|
||||
});
|
||||
|
||||
let i = 0,
|
||||
lastIndex = 0,
|
||||
charCount = 0;
|
||||
|
||||
const resultArray: string[] = [];
|
||||
|
||||
while (i < matches.length) {
|
||||
const item = matches[i];
|
||||
|
||||
/// item.start >= lastIndex (equal only for the first iteration)
|
||||
/// because of the while loop that comes after, iterating over variable j
|
||||
|
||||
if (ellipsis && item.start - offset > lastIndex) {
|
||||
resultArray.push(`${replaceHTMLEnt(str.substring(lastIndex, lastIndex + offset))} [...] `);
|
||||
resultArray.push(`${replaceHTMLEnt(str.substring(item.start - offset, item.start))}`);
|
||||
charCount += offset * 2;
|
||||
}
|
||||
else {
|
||||
/// If the match is too close to the end of last match, don't add ellipsis
|
||||
resultArray.push(replaceHTMLEnt(str.substring(lastIndex, item.start)));
|
||||
charCount += item.start - lastIndex;
|
||||
}
|
||||
|
||||
let j = i + 1,
|
||||
end = item.end;
|
||||
|
||||
/// Include as many matches as possible
|
||||
/// [item.start, end] is the range of the match
|
||||
while (j < matches.length && matches[j].start <= end) {
|
||||
end = Math.max(matches[j].end, end);
|
||||
++j;
|
||||
}
|
||||
|
||||
resultArray.push(`<mark>${replaceHTMLEnt(str.substring(item.start, end))}</mark>`);
|
||||
charCount += end - item.start;
|
||||
|
||||
i = j;
|
||||
lastIndex = end;
|
||||
|
||||
if (ellipsis && charCount > charLimit) break;
|
||||
}
|
||||
|
||||
/// Add the rest of the string
|
||||
if (lastIndex < str.length) {
|
||||
let end = str.length;
|
||||
if (ellipsis) end = Math.min(end, lastIndex + offset);
|
||||
|
||||
resultArray.push(`${replaceHTMLEnt(str.substring(lastIndex, end))}`);
|
||||
|
||||
if (ellipsis && end != str.length) {
|
||||
resultArray.push(` [...]`);
|
||||
}
|
||||
}
|
||||
|
||||
return resultArray.join('');
|
||||
}
|
||||
|
||||
private async searchKeywords(keywords: string[]) {
|
||||
const rawData = await this.getData();
|
||||
const results: pageData[] = [];
|
||||
|
||||
const regex = new RegExp(keywords.filter((v, index, arr) => {
|
||||
arr[index] = escapeRegExp(v);
|
||||
return v.trim() !== '';
|
||||
}).join('|'), 'gi');
|
||||
|
||||
for (const item of rawData) {
|
||||
const titleMatches: match[] = [],
|
||||
contentMatches: match[] = [];
|
||||
|
||||
let result = {
|
||||
...item,
|
||||
preview: '',
|
||||
matchCount: 0
|
||||
}
|
||||
|
||||
let matched = false;
|
||||
|
||||
for (const keyword of keywords) {
|
||||
if (keyword === '') continue;
|
||||
|
||||
const regex = new RegExp(escapeRegExp(replaceHTMLEnt(keyword)), 'gi');
|
||||
|
||||
const contentMatch = regex.exec(result.content);
|
||||
regex.lastIndex = 0; /// Reset regex
|
||||
|
||||
const titleMatch = regex.exec(result.title);
|
||||
regex.lastIndex = 0; /// Reset regex
|
||||
|
||||
if (titleMatch) {
|
||||
result.title = result.title.replace(regex, Search.marker);
|
||||
}
|
||||
|
||||
if (titleMatch || contentMatch) {
|
||||
matched = true;
|
||||
++result.matchCount;
|
||||
|
||||
let start = 0,
|
||||
end = 100;
|
||||
|
||||
if (contentMatch) {
|
||||
start = contentMatch.index - 20;
|
||||
end = contentMatch.index + 80
|
||||
|
||||
if (start < 0) start = 0;
|
||||
}
|
||||
|
||||
if (result.preview.indexOf(keyword) !== -1) {
|
||||
result.preview = result.preview.replace(regex, Search.marker);
|
||||
}
|
||||
else {
|
||||
if (start !== 0) result.preview += `[...] `;
|
||||
result.preview += `${result.content.slice(start, end).replace(regex, Search.marker)} `;
|
||||
}
|
||||
}
|
||||
const contentMatchAll = item.content.matchAll(regex);
|
||||
for (const match of Array.from(contentMatchAll)) {
|
||||
contentMatches.push({
|
||||
start: match.index,
|
||||
end: match.index + match[0].length
|
||||
});
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
result.preview += '[...]';
|
||||
results.push(result);
|
||||
const titleMatchAll = item.title.matchAll(regex);
|
||||
for (const match of Array.from(titleMatchAll)) {
|
||||
titleMatches.push({
|
||||
start: match.index,
|
||||
end: match.index + match[0].length
|
||||
});
|
||||
}
|
||||
|
||||
if (titleMatches.length > 0) result.title = Search.processMatches(result.title, titleMatches, false);
|
||||
if (contentMatches.length > 0) {
|
||||
result.preview = Search.processMatches(result.content, contentMatches);
|
||||
}
|
||||
else {
|
||||
/// If there are no matches in the content, use the first 140 characters as preview
|
||||
result.preview = replaceHTMLEnt(result.content.substring(0, 140));
|
||||
}
|
||||
|
||||
result.matchCount = titleMatches.length + contentMatches.length;
|
||||
if (result.matchCount > 0) results.push(result);
|
||||
}
|
||||
|
||||
/** Result with more matches appears first */
|
||||
/// Result with more matches appears first
|
||||
return results.sort((a, b) => {
|
||||
return b.matchCount - a.matchCount;
|
||||
});
|
||||
}
|
||||
|
||||
public static marker(match) {
|
||||
return '<mark>' + match + '</mark>';
|
||||
}
|
||||
|
||||
private async doSearch(keywords: string[]) {
|
||||
const startTime = performance.now();
|
||||
|
||||
@ -150,6 +207,11 @@ class Search {
|
||||
/// Not fetched yet
|
||||
const jsonURL = this.form.dataset.json;
|
||||
this.data = await fetch(jsonURL).then(res => res.json());
|
||||
const parser = new DOMParser();
|
||||
|
||||
for (const item of this.data) {
|
||||
item.content = parser.parseFromString(item.content, 'text/html').body.innerText;
|
||||
}
|
||||
}
|
||||
|
||||
return this.data;
|
||||
@ -160,7 +222,7 @@ class Search {
|
||||
|
||||
const eventHandler = (e) => {
|
||||
e.preventDefault();
|
||||
const keywords = this.input.value;
|
||||
const keywords = this.input.value.trim();
|
||||
|
||||
Search.updateQueryString(keywords, true);
|
||||
|
||||
@ -225,7 +287,7 @@ class Search {
|
||||
<a href={item.permalink}>
|
||||
<div class="article-details">
|
||||
<h2 class="article-title" dangerouslySetInnerHTML={{ __html: item.title }}></h2>
|
||||
<secion class="article-preview" dangerouslySetInnerHTML={{ __html: item.preview }}></secion>
|
||||
<section class="article-preview" dangerouslySetInnerHTML={{ __html: item.preview }}></section>
|
||||
</div>
|
||||
{item.image &&
|
||||
<div class="article-image">
|
||||
|
34
assets/ts/smoothAnchors.ts
Normal file
34
assets/ts/smoothAnchors.ts
Normal file
@ -0,0 +1,34 @@
|
||||
// Implements smooth scrolling when clicking on an anchor link.
|
||||
// This is required instead of using modern CSS because Chromium does not currently support scrolling
|
||||
// one element with scrollTo while another element is scrolled because of a click on a link. This would
|
||||
// thus not work with the ToC scrollspy and e.g. footnotes.
|
||||
|
||||
// Here are additional links about this issue:
|
||||
// - https://stackoverflow.com/questions/49318497/google-chrome-simultaneously-smooth-scrollintoview-with-more-elements-doesn
|
||||
// - https://stackoverflow.com/questions/57214373/scrollintoview-using-smooth-function-on-multiple-elements-in-chrome
|
||||
// - https://bugs.chromium.org/p/chromium/issues/detail?id=833617
|
||||
// - https://bugs.chromium.org/p/chromium/issues/detail?id=1043933
|
||||
// - https://bugs.chromium.org/p/chromium/issues/detail?id=1121151
|
||||
|
||||
const anchorLinksQuery = "a[href]";
|
||||
|
||||
function setupSmoothAnchors() {
|
||||
document.querySelectorAll(anchorLinksQuery).forEach(aElement => {
|
||||
let href = aElement.getAttribute("href");
|
||||
if (!href.startsWith("#")) {
|
||||
return;
|
||||
}
|
||||
aElement.addEventListener("click", clickEvent => {
|
||||
clickEvent.preventDefault();
|
||||
|
||||
let targetId = aElement.getAttribute("href").substring(1);
|
||||
// The replace done on ':' is here for footnotes, as this character would otherwise interfere when used as a CSS selector.
|
||||
let target = document.querySelector(`#${targetId.replace(":", "\\:")}`) as HTMLElement;
|
||||
|
||||
window.history.pushState({}, "", aElement.getAttribute("href"));
|
||||
scrollTo({ top: target.offsetTop, behavior: "smooth" });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export { setupSmoothAnchors };
|
147
config.yaml
Normal file
147
config.yaml
Normal file
@ -0,0 +1,147 @@
|
||||
module:
|
||||
hugoVersion:
|
||||
extended: true
|
||||
min: "0.87.0"
|
||||
|
||||
params:
|
||||
mainSections:
|
||||
- post
|
||||
featuredImageField: image
|
||||
rssFullContent: true
|
||||
favicon:
|
||||
|
||||
footer:
|
||||
since:
|
||||
customText:
|
||||
|
||||
dateFormat:
|
||||
published: Jan 02, 2006
|
||||
lastUpdated: Jan 02, 2006 15:04 MST
|
||||
|
||||
sidebar:
|
||||
emoji:
|
||||
subtitle:
|
||||
avatar:
|
||||
enabled: true
|
||||
local: true
|
||||
src: img/avatar.png
|
||||
|
||||
article:
|
||||
math: false
|
||||
toc: true
|
||||
readingTime: true
|
||||
license:
|
||||
enabled: false
|
||||
default: Licensed under CC BY-NC-SA 4.0
|
||||
|
||||
comments:
|
||||
enabled: false
|
||||
provider: disqus
|
||||
|
||||
disqusjs:
|
||||
shortname:
|
||||
apiUrl:
|
||||
apiKey:
|
||||
admin:
|
||||
adminLabel:
|
||||
|
||||
utterances:
|
||||
repo:
|
||||
issueTerm: pathname
|
||||
label:
|
||||
|
||||
remark42:
|
||||
host:
|
||||
site:
|
||||
locale:
|
||||
|
||||
vssue:
|
||||
platform:
|
||||
owner:
|
||||
repo:
|
||||
clientId:
|
||||
clientSecret:
|
||||
autoCreateIssue: false
|
||||
|
||||
# Waline client configuration see: https://waline.js.org/en/reference/client.html
|
||||
waline:
|
||||
serverURL:
|
||||
lang:
|
||||
visitor:
|
||||
avatar:
|
||||
emoji:
|
||||
- https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo
|
||||
requiredMeta:
|
||||
- name
|
||||
- email
|
||||
- url
|
||||
placeholder:
|
||||
locale:
|
||||
admin: Admin
|
||||
|
||||
twikoo:
|
||||
envId:
|
||||
region:
|
||||
path:
|
||||
lang:
|
||||
|
||||
giscus:
|
||||
repo:
|
||||
repoID:
|
||||
category:
|
||||
categoryID:
|
||||
mapping:
|
||||
lightTheme:
|
||||
darkTheme:
|
||||
reactionsEnabled: 1
|
||||
emitMetadata: 0
|
||||
|
||||
gitalk:
|
||||
owner:
|
||||
admin:
|
||||
repo:
|
||||
clientID:
|
||||
clientSecret:
|
||||
|
||||
cusdis:
|
||||
host:
|
||||
id:
|
||||
|
||||
widgets:
|
||||
enabled:
|
||||
- search
|
||||
- archives
|
||||
- tag-cloud
|
||||
|
||||
archives:
|
||||
limit: 5
|
||||
|
||||
tagCloud:
|
||||
limit: 10
|
||||
|
||||
opengraph:
|
||||
twitter:
|
||||
# Your Twitter username
|
||||
site:
|
||||
|
||||
# Available values: summary, summary_large_image
|
||||
card: summary_large_image
|
||||
|
||||
defaultImage:
|
||||
opengraph:
|
||||
enabled: false
|
||||
local: false
|
||||
src:
|
||||
|
||||
colorScheme:
|
||||
# Display toggle
|
||||
toggle: true
|
||||
|
||||
# Available values: auto, light, dark
|
||||
default: auto
|
||||
|
||||
imageProcessing:
|
||||
cover:
|
||||
enabled: true
|
||||
content:
|
||||
enabled: true
|
@ -23,16 +23,24 @@ PhotoSwipe:
|
||||
type: style
|
||||
|
||||
KaTeX:
|
||||
- src: https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css
|
||||
integrity: sha384-AfEj0r4/OFrOo5t7NnNe46zW/tFgW6x/bCJG8FqQCEo3+Aro6EYUG4+cU+KJWu/X
|
||||
- src: https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/katex.min.css
|
||||
integrity: sha384-RZU/ijkSsFbcmivfdRBQDtwuwVqK7GMOw6IMvKyeWL2K5UAlyp6WonmB8m7Jd0Hn
|
||||
type: style
|
||||
|
||||
- src: https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.js
|
||||
integrity: sha384-g7c+Jr9ZivxKLnZTDUhnkOnsh30B4H0rpLUpJ4jAIKs4fnJI+sEnkvrMWph2EDg4
|
||||
- src: https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/katex.min.js
|
||||
integrity: sha384-pK1WpvzWVBQiP0/GjnvRxV4mOb0oxFuyRxJlk6vVw146n3egcN5C925NCP7a7BY8
|
||||
type: script
|
||||
defer: true
|
||||
|
||||
- src: https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/contrib/auto-render.min.js
|
||||
integrity: sha384-mll67QQFJfxn0IYznZYonOWZ644AWYC+Pt2cHqMaRhXVrursRwvLnLaebdGIlYNa
|
||||
- src: https://cdn.jsdelivr.net/npm/katex@0.13.13/dist/contrib/auto-render.min.js
|
||||
integrity: sha384-vZTG03m+2yp6N6BNi5iM4rW4oIwk5DfcNdFfxkk9ZWpDriOkXX8voJBFrAO7MpVl
|
||||
type: script
|
||||
defer: true
|
||||
|
||||
Cactus:
|
||||
- src: https://latest.cactus.chat/cactus.js
|
||||
integrity:
|
||||
type: script
|
||||
- src: https://latest.cactus.chat/style.css
|
||||
integrity:
|
||||
type: style
|
||||
|
1
debug.sh
Executable file
1
debug.sh
Executable file
@ -0,0 +1 @@
|
||||
cd exampleSite && hugo server --gc --themesDir=../..
|
7
exampleSite/.gitignore
vendored
7
exampleSite/.gitignore
vendored
@ -22,6 +22,9 @@ _testmain.go
|
||||
*.exe
|
||||
*.test
|
||||
|
||||
/public
|
||||
/themes
|
||||
public
|
||||
themes
|
||||
resources
|
||||
|
||||
assets/jsconfig.json
|
||||
.DS_Store
|
||||
|
@ -11,9 +11,13 @@ disqusShortname: hugo-theme-stack
|
||||
googleAnalytics:
|
||||
|
||||
# Theme i18n support
|
||||
# Available values: en, fr, id, ja, ko, pt-br, zh-cn
|
||||
# Available values: en, fr, id, ja, ko, pt-br, zh-cn, zh-tw, es, de, nl, it, th, el, uk
|
||||
DefaultContentLanguage: en
|
||||
|
||||
# Set hasCJKLanguage to true if DefaultContentLanguage is in [zh-cn ja ko]
|
||||
# This will make .Summary and .WordCount behave correctly for CJK languages.
|
||||
hasCJKLanguage: false
|
||||
|
||||
permalinks:
|
||||
post: /p/:slug/
|
||||
page: /:slug/
|
||||
@ -37,11 +41,14 @@ params:
|
||||
emoji: 🍥
|
||||
subtitle: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
avatar:
|
||||
enabled: true
|
||||
local: true
|
||||
src: img/avatar.png
|
||||
|
||||
article:
|
||||
math: false
|
||||
toc: true
|
||||
readingTime: true
|
||||
license:
|
||||
enabled: true
|
||||
default: Licensed under CC BY-NC-SA 4.0
|
||||
@ -50,6 +57,13 @@ params:
|
||||
enabled: true
|
||||
provider: disqus
|
||||
|
||||
disqusjs:
|
||||
shortname:
|
||||
apiUrl:
|
||||
apiKey:
|
||||
admin:
|
||||
adminLabel:
|
||||
|
||||
utterances:
|
||||
repo:
|
||||
issueTerm: pathname
|
||||
@ -60,6 +74,63 @@ params:
|
||||
site:
|
||||
locale:
|
||||
|
||||
vssue:
|
||||
platform:
|
||||
owner:
|
||||
repo:
|
||||
clientId:
|
||||
clientSecret:
|
||||
autoCreateIssue: false
|
||||
|
||||
# Waline client configuration see: https://waline.js.org/en/reference/client.html
|
||||
waline:
|
||||
serverURL:
|
||||
lang:
|
||||
visitor:
|
||||
avatar:
|
||||
emoji:
|
||||
- https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo
|
||||
requiredMeta:
|
||||
- name
|
||||
- email
|
||||
- url
|
||||
placeholder:
|
||||
locale:
|
||||
admin: Admin
|
||||
|
||||
twikoo:
|
||||
envId:
|
||||
region:
|
||||
path:
|
||||
lang:
|
||||
|
||||
# See https://cactus.chat/docs/reference/web-client/#configuration for description of the various options
|
||||
cactus:
|
||||
defaultHomeserverUrl: "https://matrix.cactus.chat:8448"
|
||||
serverName: "cactus.chat"
|
||||
siteName: "" # You must insert a unique identifier here matching the one you registered (See https://cactus.chat/docs/getting-started/quick-start/#register-your-site)
|
||||
|
||||
giscus:
|
||||
repo:
|
||||
repoID:
|
||||
category:
|
||||
categoryID:
|
||||
mapping:
|
||||
lightTheme:
|
||||
darkTheme:
|
||||
reactionsEnabled: 1
|
||||
emitMetadata: 0
|
||||
|
||||
gitalk:
|
||||
owner:
|
||||
admin:
|
||||
repo:
|
||||
clientID:
|
||||
clientSecret:
|
||||
|
||||
cusdis:
|
||||
host:
|
||||
id:
|
||||
widgets:
|
||||
enabled:
|
||||
- search
|
||||
@ -99,31 +170,32 @@ params:
|
||||
content:
|
||||
enabled: true
|
||||
|
||||
### Custom menu
|
||||
### See https://docs.stack.jimmycai.com/configuration/custom-menu.html
|
||||
### To remove about, archive and search page menu item, remove `menu` field from their FrontMatter
|
||||
menu:
|
||||
main:
|
||||
- identifier: home
|
||||
name: Home
|
||||
url: /
|
||||
weight: -100
|
||||
pre: home
|
||||
params:
|
||||
### For demonstration purpose, the home link will be open in a new tab
|
||||
newTab: true
|
||||
icon: home
|
||||
|
||||
- identifier: about
|
||||
name: About
|
||||
url: about
|
||||
weight: -90
|
||||
pre: user
|
||||
social:
|
||||
- identifier: github
|
||||
name: GitHub
|
||||
url: https://github.com/CaiJimmy/hugo-theme-stack
|
||||
params:
|
||||
icon: brand-github
|
||||
|
||||
- identifier: archives
|
||||
name: Archives
|
||||
url: archives
|
||||
weight: -70
|
||||
pre: archives
|
||||
|
||||
- identifier: search
|
||||
name: Search
|
||||
url: search
|
||||
weight: -60
|
||||
pre: search
|
||||
- identifier: twitter
|
||||
name: Twitter
|
||||
url: https://twitter.com
|
||||
params:
|
||||
icon: brand-twitter
|
||||
|
||||
related:
|
||||
includeNewer: true
|
||||
@ -137,5 +209,19 @@ related:
|
||||
weight: 200
|
||||
|
||||
markup:
|
||||
goldmark:
|
||||
renderer:
|
||||
## Set to true if you have HTML content inside Markdown
|
||||
unsafe: false
|
||||
tableOfContents:
|
||||
endLevel: 4
|
||||
ordered: true
|
||||
startLevel: 2
|
||||
highlight:
|
||||
noClasses: false
|
||||
codeFences: true
|
||||
guessSyntax: true
|
||||
lineNoStart: 1
|
||||
lineNos: true
|
||||
lineNumbersInTable: true
|
||||
tabWidth: 4
|
||||
|
@ -1,9 +1,9 @@
|
||||
---
|
||||
title: "Test"
|
||||
description: "This is a example category"
|
||||
description: "This is an example category"
|
||||
slug: "test"
|
||||
image: "hutomo-abrianto-l2jk-uxb1BY-unsplash.jpg"
|
||||
style:
|
||||
background: "#2a9d8f"
|
||||
color: "#fff"
|
||||
---
|
||||
---
|
||||
|
@ -1,12 +1,19 @@
|
||||
+++
|
||||
title = "About"
|
||||
description = "Hugo, the world's fastest framework for building websites"
|
||||
date = "2019-02-28"
|
||||
aliases = ["about-us", "about-hugo", "contact"]
|
||||
author = "Hugo Authors"
|
||||
license = "CC BY-NC-ND"
|
||||
lastmod = "2020-10-09"
|
||||
+++
|
||||
---
|
||||
title: About
|
||||
description: Hugo, the world's fastest framework for building websites
|
||||
date: '2019-02-28'
|
||||
aliases:
|
||||
- about-us
|
||||
- about-hugo
|
||||
- contact
|
||||
license: CC BY-NC-ND
|
||||
lastmod: '2020-10-09'
|
||||
menu:
|
||||
main:
|
||||
weight: -90
|
||||
params:
|
||||
icon: user
|
||||
---
|
||||
|
||||
Written in Go, Hugo is an open source static site generator available under the [Apache Licence 2.0.](https://github.com/gohugoio/hugo/blob/master/LICENSE) Hugo supports TOML, YAML and JSON data file types, Markdown and HTML content files and uses shortcodes to add rich content. Other notable features are taxonomies, multilingual mode, image processing, custom output formats, HTML/CSS/JS minification and support for Sass SCSS workflows.
|
||||
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
title: "Archives"
|
||||
date: 2019-05-28
|
||||
layout: "archives"
|
||||
slug: "archives"
|
||||
---
|
11
exampleSite/content/page/archives/index.md
Normal file
11
exampleSite/content/page/archives/index.md
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
title: "Archives"
|
||||
date: 2019-05-28
|
||||
layout: "archives"
|
||||
slug: "archives"
|
||||
menu:
|
||||
main:
|
||||
weight: -70
|
||||
params:
|
||||
icon: archives
|
||||
---
|
37
exampleSite/content/page/links/index.md
Normal file
37
exampleSite/content/page/links/index.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: Links
|
||||
links:
|
||||
- title: GitHub
|
||||
description: GitHub is the world's largest software development platform.
|
||||
website: https://github.com
|
||||
image: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
|
||||
- title: TypeScript
|
||||
description: TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
|
||||
website: https://www.typescriptlang.org
|
||||
image: ts-logo-128.jpg
|
||||
menu:
|
||||
main:
|
||||
weight: -50
|
||||
params:
|
||||
icon: link
|
||||
|
||||
comments: false
|
||||
---
|
||||
|
||||
To use this feature, add `links` section to frontmatter.
|
||||
|
||||
This page's frontmatter:
|
||||
|
||||
```yaml
|
||||
links:
|
||||
- title: GitHub
|
||||
description: GitHub is the world's largest software development platform.
|
||||
website: https://github.com
|
||||
image: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
|
||||
- title: TypeScript
|
||||
description: TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
|
||||
website: https://www.typescriptlang.org
|
||||
image: ts-logo-128.jpg
|
||||
```
|
||||
|
||||
`image` field accepts both local and external images.
|
BIN
exampleSite/content/page/links/ts-logo-128.jpg
Normal file
BIN
exampleSite/content/page/links/ts-logo-128.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
@ -5,4 +5,9 @@ layout: "search"
|
||||
outputs:
|
||||
- html
|
||||
- json
|
||||
menu:
|
||||
main:
|
||||
weight: -60
|
||||
params:
|
||||
icon: search
|
||||
---
|
@ -69,6 +69,10 @@ Tables aren't part of the core Markdown spec, but Hugo supports supports them ou
|
||||
| -------- | -------- | ------ |
|
||||
| *italics* | **bold** | `code` |
|
||||
|
||||
| A | B | C | D | E | F |
|
||||
|----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------|------------------------------------------------------------|----------------------------------------------------------------------|
|
||||
| Lorem ipsum dolor sit amet, consectetur adipiscing elit. | Phasellus ultricies, sapien non euismod aliquam, dui ligula tincidunt odio, at accumsan nulla sapien eget ex. | Proin eleifend dictum ipsum, non euismod ipsum pulvinar et. Vivamus sollicitudin, quam in pulvinar aliquam, metus elit pretium purus | Proin sit amet velit nec enim imperdiet vehicula. | Ut bibendum vestibulum quam, eu egestas turpis gravida nec | Sed scelerisque nec turpis vel viverra. Vivamus vitae pretium sapien |
|
||||
|
||||
## Code Blocks
|
||||
|
||||
#### Code block with backticks
|
||||
@ -113,6 +117,16 @@ Tables aren't part of the core Markdown spec, but Hugo supports supports them ou
|
||||
</html>
|
||||
{{< /highlight >}}
|
||||
|
||||
#### Diff code block
|
||||
|
||||
```diff
|
||||
[dependencies.bevy]
|
||||
git = "https://github.com/bevyengine/bevy"
|
||||
rev = "11f52b8c72fc3a568e8bb4a4cd1f3eb025ac2e13"
|
||||
- features = ["dynamic"]
|
||||
+ features = ["jpeg", "dynamic"]
|
||||
```
|
||||
|
||||
## List Types
|
||||
|
||||
#### Ordered List
|
||||
@ -148,3 +162,7 @@ X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
|
||||
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
|
||||
|
||||
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
|
||||
|
||||
## Hyperlinked image
|
||||
|
||||
[](https://google.com)
|
@ -32,3 +32,11 @@ Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-manageme
|
||||
## Vimeo Simple Shortcode
|
||||
|
||||
{{< vimeo_simple 48912912 >}}
|
||||
|
||||
## bilibilibi Shortcode
|
||||
|
||||
{{< bilibili av498363026 >}}
|
||||
|
||||
## Gist Shortcode
|
||||
|
||||
{{< gist spf13 7896402 >}}
|
@ -1,27 +0,0 @@
|
||||
> Original Repo: https://github.com/cdeleeuwe/netlify-plugin-hugo-cache-resources
|
||||
>
|
||||
# Netlify Build Plugin: Persist Hugo resources Between Builds
|
||||
|
||||
Persist [Hugo](https://gohugo.io/) resources folder between Netlify builds for huge build speed improvements! ⚡️
|
||||
|
||||
This plugin caches the `resources` folder after build. If you are processing many images, this would improve build duration significantly.
|
||||
|
||||
Note: Restoring cache only comes from the production branch. So once cache is saved on the production branch, the next preview build would use the cache. For example, when pushing to the same preview build, the latest preview build will not get the cache from the previous preview build, but will get it from master.
|
||||
|
||||
## Usage
|
||||
|
||||
To install, add the following lines to your `netlify.toml` file:
|
||||
|
||||
```toml
|
||||
[build]
|
||||
publish = "public"
|
||||
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-hugo-cache-resources"
|
||||
|
||||
[plugins.inputs]
|
||||
# If it should show more verbose logs (optional, default = true)
|
||||
debug = true
|
||||
```
|
||||
|
||||
Note: The `[[plugins]]` line is required for each plugin, even if you have other plugins in your `netlify.toml` file already.
|
@ -1,39 +0,0 @@
|
||||
const getResourcesDir = () => {
|
||||
return 'exampleSite/resources';
|
||||
}
|
||||
|
||||
const printList = (items) => {
|
||||
console.log('---');
|
||||
items.forEach((item, index) => {
|
||||
console.log(`${index + 1}. ${item}`);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
async onPreBuild({ utils, inputs }) {
|
||||
const path = getResourcesDir();
|
||||
const success = await utils.cache.restore(path);
|
||||
|
||||
if (success) {
|
||||
const cachedFiles = await utils.cache.list(path);
|
||||
console.log(`Restored cached resources folder. Total files: ${cachedFiles.length}`);
|
||||
if (inputs.debug) printList(cachedFiles);
|
||||
} else {
|
||||
console.log(`No cache found for resources folder`);
|
||||
}
|
||||
},
|
||||
|
||||
async onPostBuild({ utils, inputs }) {
|
||||
const path = getResourcesDir();
|
||||
const success = await utils.cache.save(path);
|
||||
|
||||
if (success) {
|
||||
const cachedFiles = await utils.cache.list(path);
|
||||
console.log(`Saved resources folder to cache. Total files: ${cachedFiles.length}`);
|
||||
if (inputs.debug) printList(cachedFiles);
|
||||
} else {
|
||||
console.log(`No resources folder cached`);
|
||||
}
|
||||
}
|
||||
};
|
@ -1,5 +0,0 @@
|
||||
name: netlify-plugin-hugo-cache
|
||||
inputs:
|
||||
- name: debug
|
||||
description: Show more verbose logs
|
||||
default: true
|
3
go.mod
Normal file
3
go.mod
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/CaiJimmy/hugo-theme-stack/v3
|
||||
|
||||
go 1.12
|
70
i18n/de.yaml
Normal file
70
i18n/de.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
toggleMenu:
|
||||
other: Menü umschalten
|
||||
|
||||
darkMode:
|
||||
other: Dunkler Modus
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} Seite"
|
||||
other: "{{ .Count }} Seiten"
|
||||
|
||||
section:
|
||||
other: Abschnitt
|
||||
|
||||
subsection:
|
||||
one: Unterabschnitt
|
||||
other: Unterabschnitte
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Zurück
|
||||
|
||||
tableOfContents:
|
||||
other: Inhaltsverzeichnis
|
||||
|
||||
relatedContents:
|
||||
other: Verwandte Inhalte
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Zuletzt aktualisiert am
|
||||
|
||||
readingTime:
|
||||
one: "{{ .Count }} Minute Lesezeit"
|
||||
other: "{{ .Count }} Minuten Lesezeit"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Seite nicht gefunden
|
||||
|
||||
subtitle:
|
||||
other: Diese Seite existiert nicht
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: Archiv
|
||||
|
||||
more:
|
||||
other: Weitere
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: Schlagwörter
|
||||
|
||||
search:
|
||||
title:
|
||||
other: Suche
|
||||
|
||||
placeholder:
|
||||
other: Etwas tippen...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT Seiten (#TIME_SECONDS Sekunden)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Erstellt mit {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: Theme {{ .Theme }} gestaltet von {{ .DesignedBy }}
|
70
i18n/el.yaml
Normal file
70
i18n/el.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
toggleMenu:
|
||||
other: Εναλλαγή Μενού
|
||||
|
||||
darkMode:
|
||||
other: Σκοτεινό θέμα
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} σελιδα"
|
||||
other: "{{ .Count }} σελιδες"
|
||||
|
||||
section:
|
||||
other: Ενότητα
|
||||
|
||||
subsection:
|
||||
one: Υποενότητα
|
||||
other: Υποενότητες
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Πισω
|
||||
|
||||
tableOfContents:
|
||||
other: Πινακας περιεχομενων
|
||||
|
||||
relatedContents:
|
||||
other: Σχετικο περιεχομενο
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Τελευταια τροποποιηση στις
|
||||
|
||||
readingTime:
|
||||
one: "{{ .Count }} λεπτό ανάγνωσης"
|
||||
### Seems that there's no need to add 's' even if it's plural in English
|
||||
other: "{{ .Count }} λεπτά ανάγνωσης"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Δε βρέθηκε
|
||||
subtitle:
|
||||
other: Η σελίδα δε βρέθηκε.
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: Αρχειο
|
||||
|
||||
more:
|
||||
other: Περισσότερα
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: Tags
|
||||
|
||||
search:
|
||||
title:
|
||||
other: Αναζήτηση
|
||||
|
||||
placeholder:
|
||||
other: Πληκτρολογήστε κάτι...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT σελιδες (#TIME_SECONDS δευτερολεπτα)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Δημιουργήθηκε με τη χρήση {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: Το θέμα {{ .Theme }} σχεδιάστηκε από το {{ .DesignedBy }}
|
19
i18n/en.yaml
19
i18n/en.yaml
@ -17,23 +17,37 @@ list:
|
||||
other: Subsections
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Back
|
||||
|
||||
tableOfContents:
|
||||
other: Table of contents
|
||||
|
||||
relatedContents:
|
||||
other: Related contents
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Last updated on
|
||||
|
||||
readingTime:
|
||||
one: "{{ .Count }} minute read"
|
||||
other: "{{ .Count }} minute read"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Not Found
|
||||
|
||||
subtitle:
|
||||
other: This page does not exist.
|
||||
other: This page does not exist
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: Archives
|
||||
|
||||
more:
|
||||
other: More
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: Tags
|
||||
@ -41,13 +55,16 @@ widget:
|
||||
search:
|
||||
title:
|
||||
other: Search
|
||||
|
||||
placeholder:
|
||||
other: Type something...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT pages (#TIME_SECONDS seconds)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Built with {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: Theme {{ .Theme }} designed by {{ .DesignedBy }}
|
||||
|
70
i18n/es.yaml
Normal file
70
i18n/es.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
toggleMenu:
|
||||
other: Toggle Menu
|
||||
|
||||
darkMode:
|
||||
other: Modo oscuro
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} página"
|
||||
other: "{{ .Count }} páginas"
|
||||
|
||||
section:
|
||||
other: Sección
|
||||
|
||||
subsection:
|
||||
one: Subsección
|
||||
other: Subsecciones
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Volver
|
||||
|
||||
tableOfContents:
|
||||
other: Tabla de contenido
|
||||
|
||||
relatedContents:
|
||||
other: Contenidos relacionados
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Última vez actualizado
|
||||
|
||||
readingTime:
|
||||
one: "{{ .Count }} minuto a leer"
|
||||
other: "{{ .Count }} minutos a leer"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: No Encontrado
|
||||
|
||||
subtitle:
|
||||
other: Esta página no existe
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: Archivo
|
||||
|
||||
more:
|
||||
other: Más
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: Etiquetas
|
||||
|
||||
search:
|
||||
title:
|
||||
other: Búsqueda
|
||||
|
||||
placeholder:
|
||||
other: Teclea algo...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT páginas en (#TIME_SECONDS segundos)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Creado con {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: Tema {{ .Theme }} diseñado por {{ .DesignedBy }}
|
31
i18n/fr.yaml
31
i18n/fr.yaml
@ -1,12 +1,38 @@
|
||||
toggleMenu:
|
||||
other: Afficher le menu
|
||||
|
||||
darkMode:
|
||||
other: Mode sombre
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} page"
|
||||
other: "{{ .Count }} pages"
|
||||
|
||||
section:
|
||||
other: Section
|
||||
|
||||
subsection:
|
||||
one: Sous-section
|
||||
other: Sous-sections
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Retour
|
||||
|
||||
tableOfContents:
|
||||
other: Table des matières
|
||||
|
||||
relatedContents:
|
||||
other: Contenus liés
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Dernière mise à jour le
|
||||
|
||||
readingTime:
|
||||
one: "{{ .Count }} minute de lecture"
|
||||
other: "{{ .Count }} minutes de lecture"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Page non trouvée
|
||||
@ -17,8 +43,10 @@ widget:
|
||||
archives:
|
||||
title:
|
||||
other: Archives
|
||||
|
||||
more:
|
||||
other: Autres
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: Mots clés
|
||||
@ -26,13 +54,16 @@ widget:
|
||||
search:
|
||||
title:
|
||||
other: Rechercher
|
||||
|
||||
placeholder:
|
||||
other: Cherchez un article, une publication, etc.
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT pages (#TIME_SECONDS secondes)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Généré avec {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: Thème {{ .Theme }} conçu par {{ .DesignedBy }}
|
||||
|
35
i18n/id.yaml
35
i18n/id.yaml
@ -1,24 +1,52 @@
|
||||
toggleMenu:
|
||||
other: Tampilkan Menu
|
||||
|
||||
darkMode:
|
||||
other: Mode Gelap
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} halaman"
|
||||
other: "{{ .Count }} halaman"
|
||||
|
||||
section:
|
||||
other: Bagian
|
||||
|
||||
subsection:
|
||||
one: Subbagian
|
||||
other: Subbagian
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Kembali
|
||||
|
||||
tableOfContents:
|
||||
other: Daftar Isi
|
||||
|
||||
relatedContents:
|
||||
other: Konten terkait
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Terakhir diperbarui pada
|
||||
|
||||
readingTime:
|
||||
one: "Waktu Membaca: {{ .Count }} menit"
|
||||
other: "Waktu Membaca: {{ .Count }} menit"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Not Found
|
||||
other: Tidak ditemukan
|
||||
subtitle:
|
||||
other: Halaman ini tidak ada.
|
||||
other: Halaman yang Anda akses tidak ditemukan.
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: Arsip
|
||||
|
||||
more:
|
||||
other: Lebih
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: Tag
|
||||
@ -26,13 +54,16 @@ widget:
|
||||
search:
|
||||
title:
|
||||
other: Cari
|
||||
|
||||
placeholder:
|
||||
other: Ketik sesuatu...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT halaman (#TIME_SECONDS detik)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Dibangun dengan {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: Tema {{ .Theme }} dirancang oleh {{ .DesignedBy }}
|
||||
|
69
i18n/it.yaml
Normal file
69
i18n/it.yaml
Normal file
@ -0,0 +1,69 @@
|
||||
toggleMenu:
|
||||
other: Toggle Menu
|
||||
|
||||
darkMode:
|
||||
other: Dark Mode
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} pagina"
|
||||
other: "{{ .Count }} pagine"
|
||||
|
||||
section:
|
||||
other: Sezione
|
||||
|
||||
subsection:
|
||||
one: Sottosezione
|
||||
other: Sottosezioni
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Indietro
|
||||
|
||||
tableOfContents:
|
||||
other: Indice
|
||||
|
||||
relatedContents:
|
||||
other: Contenuti correlati
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Aggiornato il
|
||||
|
||||
readingTime:
|
||||
one: "{{ .Count }} min per leggere"
|
||||
other: "{{ .Count }} min per leggere"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Non trovato
|
||||
subtitle:
|
||||
other: Questa pagina non esiste.
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: Archivi
|
||||
|
||||
more:
|
||||
other: Di più
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: Tags
|
||||
|
||||
search:
|
||||
title:
|
||||
other: Cerca
|
||||
|
||||
placeholder:
|
||||
other: Scrivi qualcosa...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT pagine (#TIME_SECONDS secondi)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Realizzato con {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: Tema {{ .Theme }} realizzato da {{ .DesignedBy }}
|
16
i18n/ja.yaml
16
i18n/ja.yaml
@ -5,11 +5,21 @@ darkMode:
|
||||
other: ダークモード
|
||||
|
||||
article:
|
||||
back:
|
||||
other: 前のページ
|
||||
|
||||
tableOfContents:
|
||||
other: 目次
|
||||
|
||||
relatedContents:
|
||||
other: 関連するコンテンツ
|
||||
|
||||
lastUpdatedOn:
|
||||
other: 最終更新
|
||||
|
||||
readingTime:
|
||||
other: "読了時間: {{ .Count }}分"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: 404 Not Found
|
||||
@ -20,16 +30,20 @@ widget:
|
||||
archives:
|
||||
title:
|
||||
other: アーカイブ
|
||||
|
||||
more:
|
||||
other: さらに見る
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: タグ
|
||||
|
||||
search:
|
||||
title:
|
||||
other: サーチ
|
||||
other: 検索
|
||||
|
||||
placeholder:
|
||||
other: 入力...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT 件 (#TIME_SECONDS 秒)"
|
||||
|
30
i18n/ko.yaml
30
i18n/ko.yaml
@ -1,15 +1,42 @@
|
||||
toggleMenu:
|
||||
other: 메뉴 여닫기
|
||||
|
||||
darkMode:
|
||||
other: 다크 모드
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} 페이지"
|
||||
other: "{{ .Count }} 페이지"
|
||||
|
||||
section:
|
||||
other: 섹션
|
||||
|
||||
subsection:
|
||||
one: 서브섹션
|
||||
other: 서브섹션
|
||||
|
||||
article:
|
||||
back:
|
||||
other: 뒤로가기
|
||||
|
||||
tableOfContents:
|
||||
other: 목차
|
||||
|
||||
relatedContents:
|
||||
other: 관련 글
|
||||
|
||||
lastUpdatedOn:
|
||||
other: "마지막 수정: "
|
||||
|
||||
readingTime:
|
||||
one: "{{ .Count }} 분 정도"
|
||||
other: "{{ .Count }} 분 정도"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: 찾을 수 없음
|
||||
|
||||
subtitle:
|
||||
other: 페이지를 찾을 수 없습니다.
|
||||
|
||||
@ -19,6 +46,7 @@ widget:
|
||||
other: 보관함
|
||||
more:
|
||||
other: 더보기
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: 태그
|
||||
@ -26,8 +54,10 @@ widget:
|
||||
search:
|
||||
title:
|
||||
other: 검색
|
||||
|
||||
placeholder:
|
||||
other: 검색어를 입력하세요...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT 페이지 (#TIME_SECONDS 초)"
|
||||
|
||||
|
53
i18n/nl.yaml
Normal file
53
i18n/nl.yaml
Normal file
@ -0,0 +1,53 @@
|
||||
toggleMenu:
|
||||
other: Open Menu
|
||||
|
||||
darkMode:
|
||||
other: Donkere modus
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} pagina"
|
||||
other: "{{ .Count }} pagina's"
|
||||
|
||||
section:
|
||||
other: Sectie
|
||||
|
||||
subsection:
|
||||
one: Subsectie
|
||||
other: Subsecties
|
||||
|
||||
article:
|
||||
relatedContents:
|
||||
other: Gerelateerde inhoud
|
||||
lastUpdatedOn:
|
||||
other: Laatst bijgewerkt op
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Niet gevonden
|
||||
subtitle:
|
||||
other: Deze pagina bestaat niet.
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: Archief
|
||||
more:
|
||||
other: Meer
|
||||
tagCloud:
|
||||
title:
|
||||
other: Tags
|
||||
|
||||
search:
|
||||
title:
|
||||
other: Zoeken
|
||||
placeholder:
|
||||
other: Typ iets
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT pagina's (#TIME_SECONDS seconden)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Gemaakt met {{ .Generator }}
|
||||
designedBy:
|
||||
other: Theme {{ .Theme }} ontworpen door {{ .DesignedBy }}
|
69
i18n/pl.yaml
Normal file
69
i18n/pl.yaml
Normal file
@ -0,0 +1,69 @@
|
||||
toggleMenu:
|
||||
other: Przełącz Menu
|
||||
|
||||
darkMode:
|
||||
other: Tryb ciemny
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} strona"
|
||||
other: "{{ .Count }} stron"
|
||||
|
||||
section:
|
||||
other: Sekcja
|
||||
|
||||
subsection:
|
||||
one: Podsekcja
|
||||
other: Podsekcje
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Wróć
|
||||
|
||||
tableOfContents:
|
||||
other: Spis treści
|
||||
|
||||
relatedContents:
|
||||
other: Powiązane artykuły
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Ostatnio zaktualizowany
|
||||
|
||||
readingTime:
|
||||
one: "Przeczytasz w {{ .Count }} minutę"
|
||||
other: "Przeczytasz w {{ .Count }} minut"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Nie znaleziono
|
||||
subtitle:
|
||||
other: Ta strona nie istnieje
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: Archiwum
|
||||
|
||||
more:
|
||||
other: Więcej
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: Tagi
|
||||
|
||||
search:
|
||||
title:
|
||||
other: Szukaj
|
||||
|
||||
placeholder:
|
||||
other: Wpisz coś...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT stron (#TIME_SECONDS sekund)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Zbudowano z {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: Motyw {{ .Theme }} zaprojektowany przez {{ .DesignedBy }}
|
@ -17,11 +17,22 @@ list:
|
||||
other: Subseções
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Voltar
|
||||
|
||||
tableOfContents:
|
||||
other: Índice
|
||||
|
||||
relatedContents:
|
||||
other: Conteúdos Relacionados
|
||||
other: Conteúdo relacionado
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Última atualização em
|
||||
|
||||
readingTime:
|
||||
one: "{{ .Count }} minuto de leitura"
|
||||
other: "{{ .Count }} minutos de leitura"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Não Encontrado
|
||||
|
@ -21,10 +21,16 @@ list:
|
||||
other: Подразделы
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Назад
|
||||
relatedContents:
|
||||
other: Также рекомендуем
|
||||
lastUpdatedOn:
|
||||
other: Обновлено
|
||||
tableOfContents:
|
||||
other: Содержание
|
||||
readingTime:
|
||||
other: "Время чтения: {{ .Count }} мин."
|
||||
|
||||
notFound:
|
||||
title:
|
||||
|
70
i18n/th.yaml
Normal file
70
i18n/th.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
toggleMenu:
|
||||
other: สลับเมนู
|
||||
|
||||
darkMode:
|
||||
other: ธีมมืด
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} หน้า"
|
||||
other: "{{ .Count }} หน้า"
|
||||
|
||||
section:
|
||||
other: หมวดหมู่
|
||||
|
||||
subsection:
|
||||
one: หมวดหมู่ย่อย
|
||||
other: หมวดหมู่ย่อยอื่นๆ
|
||||
|
||||
article:
|
||||
back:
|
||||
other: กลับไป
|
||||
|
||||
tableOfContents:
|
||||
other: สารบัญ
|
||||
|
||||
relatedContents:
|
||||
other: เนื้อหาคล้ายคลึงกัน
|
||||
|
||||
lastUpdatedOn:
|
||||
other: อัปเดตล่าสุดเมื่อ
|
||||
|
||||
readingTime:
|
||||
one: "น่าจะใช้เวลา {{ .Count }} นาทีในการอ่าน"
|
||||
other: "น่าจะใช้เวลา {{ .Count }} นาทีในการอ่าน"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: ไม่พบหัวข้อ
|
||||
|
||||
subtitle:
|
||||
other: ไม่พบหน้านี้ในระบบ
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: เนื้อหาที่เก็บถาวรแล้ว
|
||||
|
||||
more:
|
||||
other: อื่นๆ นอกจากนี้
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: แท็ก
|
||||
|
||||
search:
|
||||
title:
|
||||
other: ค้นหา
|
||||
|
||||
placeholder:
|
||||
other: พิมพ์เพื่อค้นหา ...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT pages (#TIME_SECONDS seconds)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: ถูกสร้างด้วย {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: ธีม {{ .Theme }} ออกแบบโดย {{ .DesignedBy }}
|
71
i18n/uk.yaml
Normal file
71
i18n/uk.yaml
Normal file
@ -0,0 +1,71 @@
|
||||
toggleMenu:
|
||||
other: Показати меню
|
||||
|
||||
darkMode:
|
||||
other: Темна тема
|
||||
|
||||
list:
|
||||
page:
|
||||
one: "{{ .Count }} сторінка"
|
||||
few: "{{ .Count }} сторінки"
|
||||
other: "{{ .Count }} сторінок"
|
||||
|
||||
section:
|
||||
other: Секція
|
||||
|
||||
subsection:
|
||||
one: Підсекція
|
||||
other: Підсекції
|
||||
|
||||
article:
|
||||
back:
|
||||
other: Назад
|
||||
|
||||
tableOfContents:
|
||||
other: Зміст
|
||||
|
||||
relatedContents:
|
||||
other: Схожі матеріали
|
||||
|
||||
lastUpdatedOn:
|
||||
other: Востаннє оновлено
|
||||
|
||||
readingTime:
|
||||
one: "Час читання: {{ .Count }} хв"
|
||||
other: "Час читання: {{ .Count }} хв"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: Не знайдено
|
||||
|
||||
subtitle:
|
||||
other: Ця сторінка не існує
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: Архіви
|
||||
|
||||
more:
|
||||
other: Більше
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: Теґи
|
||||
|
||||
search:
|
||||
title:
|
||||
other: Пошук
|
||||
|
||||
placeholder:
|
||||
other: Напишіть що-небудь...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT сторінок (#TIME_SECONDS секунд)"
|
||||
|
||||
footer:
|
||||
builtWith:
|
||||
other: Створено з {{ .Generator }}
|
||||
|
||||
designedBy:
|
||||
other: Тема {{ .Theme }}, дизайн {{ .DesignedBy }}
|
@ -5,11 +5,21 @@ darkMode:
|
||||
other: 暗色模式
|
||||
|
||||
article:
|
||||
back:
|
||||
other: 返回
|
||||
|
||||
tableOfContents:
|
||||
other: 目录
|
||||
|
||||
relatedContents:
|
||||
other: 相关文章
|
||||
|
||||
lastUpdatedOn:
|
||||
other: 最后更新于
|
||||
|
||||
readingTime:
|
||||
other: "阅读时长: {{ .Count }} 分钟"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: 404 错误
|
||||
@ -20,8 +30,10 @@ widget:
|
||||
archives:
|
||||
title:
|
||||
other: 归档
|
||||
|
||||
more:
|
||||
other: 更多
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: 标签云
|
||||
@ -29,7 +41,9 @@ widget:
|
||||
search:
|
||||
title:
|
||||
other: 搜索
|
||||
|
||||
placeholder:
|
||||
other: 输入关键词...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT 个结果 (用时 #TIME_SECONDS 秒)"
|
||||
|
49
i18n/zh-TW.yaml
Normal file
49
i18n/zh-TW.yaml
Normal file
@ -0,0 +1,49 @@
|
||||
toggleMenu:
|
||||
other: 切換選單
|
||||
|
||||
darkMode:
|
||||
other: 夜晚模式
|
||||
|
||||
article:
|
||||
back:
|
||||
other: 返回
|
||||
|
||||
tableOfContents:
|
||||
other: 目錄
|
||||
|
||||
relatedContents:
|
||||
other: 相關文章
|
||||
|
||||
lastUpdatedOn:
|
||||
other: 最後更新
|
||||
|
||||
readingTime:
|
||||
other: "閱讀時間: {{ .Count }} 分鐘"
|
||||
|
||||
notFound:
|
||||
title:
|
||||
other: 404 錯誤
|
||||
subtitle:
|
||||
other: 頁面不存在
|
||||
|
||||
widget:
|
||||
archives:
|
||||
title:
|
||||
other: 紀錄
|
||||
|
||||
more:
|
||||
other: 更多
|
||||
|
||||
tagCloud:
|
||||
title:
|
||||
other: 標籤雲
|
||||
|
||||
search:
|
||||
title:
|
||||
other: 搜尋
|
||||
|
||||
placeholder:
|
||||
other: 輸入關鍵字...
|
||||
|
||||
resultTitle:
|
||||
other: "#PAGES_COUNT 個結果 (用時 #TIME_SECONDS 秒)"
|
@ -1,30 +1,41 @@
|
||||
{{- $image := .Page.Resources.GetMatch (printf "%s" (.Destination | safeURL)) -}}
|
||||
{{- if and $image (ne (path.Ext .Destination) ".svg") -}}
|
||||
{{- $alt := .PlainText | safeHTML -}}
|
||||
<figure style="flex-grow: {{ div (mul $image.Width 100) $image.Height }}; flex-basis: {{ div (mul $image.Width 240) $image.Height }}px">
|
||||
<a href="{{ $image.RelPermalink }}" data-size="{{ $image.Width }}x{{ $image.Height }}">
|
||||
{{- $Permalink := $image.RelPermalink -}}
|
||||
{{- $Width := $image.Width -}}
|
||||
{{- $Height := $image.Height -}}
|
||||
{{- $Srcset := "" -}}
|
||||
{{- $Permalink := .Destination | relURL | safeURL -}}
|
||||
{{- $alt := .PlainText | safeHTML -}}
|
||||
{{- $Width := 0 -}}
|
||||
{{- $Height := 0 -}}
|
||||
{{- $Srcset := "" -}}
|
||||
|
||||
{{- if (default true .Page.Site.Params.imageProcessing.content.enabled) -}}
|
||||
{{- $small := $image.Resize "480x" -}}
|
||||
{{- $big := $image.Resize "1024x" -}}
|
||||
{{- $Srcset = printf "%s 480w, %s 1024w" $small.RelPermalink $big.RelPermalink -}}
|
||||
{{- end -}}
|
||||
|
||||
<img src="{{ $Permalink }}"
|
||||
{{ with $Srcset }}srcset="{{ . }}"{{ end }}
|
||||
width="{{ $Width }}"
|
||||
height="{{ $Height }}"
|
||||
loading="lazy"
|
||||
{{ with $alt }}alt="{{ . }}"{{ end }}>
|
||||
</a>
|
||||
{{ with $alt }}
|
||||
<figcaption>{{ . | markdownify }}</figcaption>
|
||||
{{ end }}
|
||||
</figure>
|
||||
{{- else -}}
|
||||
<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" {{ with .Title }} title="{{ . }}"{{ end }} />
|
||||
{{- end -}}
|
||||
{{/* SVG and external images won't work with gallery layout, because their width and height attributes are unknown */}}
|
||||
{{- $galleryImage := false -}}
|
||||
|
||||
{{- if $image -}}
|
||||
{{- $notSVG := ne (path.Ext .Destination) ".svg" -}}
|
||||
{{- $Permalink = $image.RelPermalink -}}
|
||||
|
||||
{{- if $notSVG -}}
|
||||
{{- $Width = $image.Width -}}
|
||||
{{- $Height = $image.Height -}}
|
||||
{{- $galleryImage = true -}}
|
||||
|
||||
{{- if (default true .Page.Site.Params.imageProcessing.content.enabled) -}}
|
||||
{{- $small := $image.Resize `480x` -}}
|
||||
{{- $big := $image.Resize `1024x` -}}
|
||||
{{- $Srcset = printf `%s 480w, %s 1024w` $small.RelPermalink $big.RelPermalink -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
<img src="{{ $Permalink }}"
|
||||
{{ with $Width }}width="{{ . }}"{{ end }}
|
||||
{{ with $Height }}height="{{ . }}"{{ end }}
|
||||
{{ with $Srcset }}srcset="{{ . }}"{{ end }}
|
||||
loading="lazy"
|
||||
{{ with $alt }}
|
||||
alt="{{ . }}"
|
||||
{{ end }}
|
||||
{{ if $galleryImage }}
|
||||
class="gallery-image"
|
||||
data-flex-grow="{{ div (mul $image.Width 100) $image.Height }}"
|
||||
data-flex-basis="{{ div (mul $image.Width 240) $image.Height }}px"
|
||||
{{ end }}
|
||||
>
|
@ -6,8 +6,10 @@
|
||||
</head>
|
||||
<body class="{{ block `body-class` . }}{{ end }}">
|
||||
{{- partial "head/colorScheme" . -}}
|
||||
<div class="container main-container flex on-phone--column {{ if .Site.Params.widgets.enabled }}extended{{ else }}compact{{ end }} {{ block `container-class` . }}{{end}}">
|
||||
{{ partial "sidebar/left.html" . }}
|
||||
<div class="container main-container flex {{ block `container-class` . }}on-phone--column {{ if .Site.Params.widgets.enabled }}extended{{ else }}compact{{ end }}{{ end }}">
|
||||
{{- block "left-sidebar" . -}}
|
||||
{{ partial "sidebar/left.html" . }}
|
||||
{{- end -}}
|
||||
<main class="main full-width">
|
||||
{{- block "main" . }}{{- end }}
|
||||
</main>
|
||||
|
@ -1,12 +1,61 @@
|
||||
{{ define "body-class" }}article-page keep-sidebar{{ end }}
|
||||
{{ define "body-class" }}
|
||||
{{ $TOCEnabled := default (default false .Site.Params.article.toc) .Params.toc }}
|
||||
{{- .Scratch.Set "hasTOC" (and (ge (len .TableOfContents) 100) $TOCEnabled) -}}
|
||||
article-page {{ if (.Scratch.Get "hasTOC") }}has-toc{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "container-class" }}
|
||||
{{ if (.Scratch.Get "hasTOC") }}
|
||||
extended
|
||||
{{ else }}
|
||||
on-phone--column {{ if .Site.Params.widgets.enabled }}extended{{ else }}compact{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
{{ partial "article/article.html" . }}
|
||||
|
||||
{{ if or (not (isset .Params "comments")) (eq .Params.comments "true")}}
|
||||
{{ if .Params.links }}
|
||||
{{ partial "article/components/links" . }}
|
||||
{{ end }}
|
||||
|
||||
{{ partial "article/components/related-contents" . }}
|
||||
|
||||
{{ if not (eq .Params.comments false) }}
|
||||
{{ partial "comments/include" . }}
|
||||
{{ end }}
|
||||
|
||||
{{ partialCached "footer/footer" . }}
|
||||
|
||||
{{ partialCached "article/components/photoswipe" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "left-sidebar" }}
|
||||
{{ if (.Scratch.Get "hasTOC") }}
|
||||
<div id="article-toolbar">
|
||||
<a href="{{ .Site.BaseURL | relLangURL }}" class="back-home">
|
||||
{{ (resources.Get "icons/back.svg").Content | safeHTML }}
|
||||
<span>{{ T "article.back" }}</span>
|
||||
</a>
|
||||
</div>
|
||||
{{ else }}
|
||||
{{ partial "sidebar/left.html" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "right-sidebar" }}
|
||||
{{ if (.Scratch.Get "hasTOC") }}
|
||||
<aside class="sidebar right-sidebar sticky">
|
||||
<section class="widget archives">
|
||||
<div class="widget-icon">
|
||||
{{ partial "helper/icon" "hash" }}
|
||||
</div>
|
||||
<h2 class="widget-title section-title">{{ T "article.tableOfContents" }}</h2>
|
||||
|
||||
<div class="widget--toc">
|
||||
{{ .TableOfContents }}
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
@ -29,6 +29,7 @@
|
||||
<img src="{{ $Permalink }}"
|
||||
width="{{ $Width }}"
|
||||
height="{{ $Height }}"
|
||||
alt="{{ .Title }}"
|
||||
loading="lazy">
|
||||
{{ else }}
|
||||
<img src="{{ $image.permalink }}" loading="lazy" alt="Featured image of post {{ .Title }}" />
|
||||
|
@ -20,8 +20,9 @@
|
||||
<img src="{{ $Permalink }}"
|
||||
width="{{ $Width }}"
|
||||
height="{{ $Height }}"
|
||||
loading="lazy"
|
||||
data-key="{{ .context.Slug }}"
|
||||
loading="lazy"
|
||||
alt="Featured image of post {{ .context.Title }}"
|
||||
{{ with .context.Slug }}data-key="{{ . }}" {{ end }}
|
||||
data-hash="{{ $imageRaw.Data.Integrity }}">
|
||||
{{ else }}
|
||||
<img src="{{ $image.permalink }}" loading="lazy" data-key="{{ .context.Slug }}" data-hash="{{ $image.permalink }}"/>
|
||||
|
@ -1,3 +1,5 @@
|
||||
<section class="article-content">
|
||||
{{ .Content }}
|
||||
<!-- Refer to https://discourse.gohugo.io/t/responsive-tables-in-markdown/10639/5 -->
|
||||
{{ $wrappedTable := printf "<div class=\"table-wrapper\">${1}</div>" }}
|
||||
{{ .Content | replaceRE "(<table>(?:.|\n)+?</table>)" $wrappedTable | safeHTML }}
|
||||
</section>
|
||||
|
@ -21,12 +21,25 @@
|
||||
</h3>
|
||||
{{ end }}
|
||||
|
||||
{{- if not .Date.IsZero -}}
|
||||
{{ if or (not .Date.IsZero) (.Site.Params.article.readingTime) }}
|
||||
<footer class="article-time">
|
||||
{{ partial "helper/icon" "clock" }}
|
||||
<time class="article-time--published">
|
||||
{{- .Date.Format (or .Site.Params.dateFormat.published "Jan 02, 2006") -}}
|
||||
</time>
|
||||
{{ if not .Date.IsZero }}
|
||||
<div>
|
||||
{{ partial "helper/icon" "date" }}
|
||||
<time class="article-time--published">
|
||||
{{- .Date.Format (or .Site.Params.dateFormat.published "Jan 02, 2006") -}}
|
||||
</time>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ if .Site.Params.article.readingTime }}
|
||||
<div>
|
||||
{{ partial "helper/icon" "clock" }}
|
||||
<time class="article-time--reading">
|
||||
{{ T "article.readingTime" .ReadingTime }}
|
||||
</time>
|
||||
</div>
|
||||
{{ end }}
|
||||
</footer>
|
||||
{{- end -}}
|
||||
{{ end }}
|
||||
</div>
|
@ -4,16 +4,16 @@
|
||||
{{ if and (.Site.Params.article.license.enabled) (not (eq .Params.license false)) }}
|
||||
<section class="article-copyright">
|
||||
{{ partial "helper/icon" "copyright" }}
|
||||
<span>{{ default .Site.Params.article.license.default .Params.license }}</span>
|
||||
<span>{{ default .Site.Params.article.license.default .Params.license | markdownify }}</span>
|
||||
</section>
|
||||
{{ end }}
|
||||
|
||||
{{- if ne .Lastmod .Date -}}
|
||||
<section class="article-time">
|
||||
<section class="article-lastmod">
|
||||
{{ partial "helper/icon" "clock" }}
|
||||
<span class="article-time--modified">
|
||||
<span>
|
||||
{{ T "article.lastUpdatedOn" }} {{ .Lastmod.Format ( or .Site.Params.dateFormat.lastUpdated "Jan 02, 2006 15:04 MST" ) }}
|
||||
</span>
|
||||
</section>
|
||||
{{- end -}}
|
||||
</footer>
|
||||
</footer>
|
||||
|
26
layouts/partials/article/components/links.html
Normal file
26
layouts/partials/article/components/links.html
Normal file
@ -0,0 +1,26 @@
|
||||
<div class="article-list--compact links">
|
||||
{{ range $i, $link := .Params.links }}
|
||||
<article>
|
||||
<a href="{{ $link.website }}" target="_blank" rel="noopener">
|
||||
<div class="article-details">
|
||||
<h2 class="article-title">
|
||||
{{- $link.title -}}
|
||||
</h2>
|
||||
<footer class="article-time">
|
||||
{{ with $link.description }}
|
||||
{{ . }}
|
||||
{{ else }}
|
||||
{{ $link.website }}
|
||||
{{ end }}
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
{{ with $link.image }}
|
||||
<div class="article-image">
|
||||
<img src="{{ . }}" loading="lazy">
|
||||
</div>
|
||||
{{ end }}
|
||||
</a>
|
||||
</article>
|
||||
{{ end }}
|
||||
</div>
|
29
layouts/partials/comments/provider/cactus.html
Normal file
29
layouts/partials/comments/provider/cactus.html
Normal file
@ -0,0 +1,29 @@
|
||||
{{- with .Site.Params.comments.cactus -}}
|
||||
{{- partial "helper/external" (dict "Context" $ "Namespace" "Cactus") -}}
|
||||
|
||||
<style>
|
||||
.cactus-editor-textarea {
|
||||
color: var(--body-text-color);
|
||||
}
|
||||
|
||||
.cactus-comment-header {
|
||||
color: var(--card-text-color-main);
|
||||
}
|
||||
|
||||
.cactus-message-text > p {
|
||||
color: var(--body-text-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="comment-section"></div>
|
||||
|
||||
<script>
|
||||
initComments({
|
||||
node: document.getElementById("comment-section"),
|
||||
defaultHomeserverUrl: "{{ .defaultHomeserverUrl | safeJS }}",
|
||||
serverName: "{{ .serverName }}",
|
||||
siteName: "{{ .siteName }}",
|
||||
commentSectionId: "{{ $.File.UniqueID }}"
|
||||
})
|
||||
</script>
|
||||
{{- end -}}
|
21
layouts/partials/comments/provider/cusdis.html
Normal file
21
layouts/partials/comments/provider/cusdis.html
Normal file
@ -0,0 +1,21 @@
|
||||
{{- $host := default "https://cusdis.com" .Site.Params.comments.cusdis.host -}}
|
||||
<div id="cusdis_thread"
|
||||
data-host="{{ $host }}"
|
||||
data-app-id="{{ .Site.Params.comments.cusdis.id }}"
|
||||
data-page-id="{{ .File.UniqueID }}"
|
||||
data-page-url="{{ .Permalink }}"
|
||||
data-page-title="{{ .Title }}"></div>
|
||||
<script async defer src="{{ $host }}/js/cusdis.es.js"></script>
|
||||
|
||||
<script>
|
||||
function setCusdisTheme(theme) {
|
||||
let cusdis = document.querySelector('#cusdis_thread iframe');
|
||||
if (cusdis) {
|
||||
window.CUSDIS.setTheme(theme)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('onColorSchemeChange', (e) => {
|
||||
setCusdisTheme(e.detail)
|
||||
})
|
||||
</script>
|
61
layouts/partials/comments/provider/disqusjs.html
Normal file
61
layouts/partials/comments/provider/disqusjs.html
Normal file
@ -0,0 +1,61 @@
|
||||
{{- $pc := .Site.Config.Privacy.Disqus -}}
|
||||
{{- $disqusjs := .Site.Params.Comments.disqusjs -}}
|
||||
{{- if and (not $pc.Disable) (and $disqusjs.Shortname $disqusjs.ApiKey) -}}
|
||||
|
||||
{{- $style := resources.Get "scss/partials/comments/disqusjs.scss" | resources.ToCSS | minify -}}
|
||||
<link rel="stylesheet" href="{{ $style.RelPermalink }}">
|
||||
|
||||
<div class="disqus-container">
|
||||
<div id="disqus_thread"></div>
|
||||
<script type="application/javascript">
|
||||
let disqusjs;
|
||||
function loadDisqusJS() {
|
||||
disqusjs = new DisqusJS({
|
||||
shortname: {{ $disqusjs.Shortname }},
|
||||
siteName: {{ .Site.Title }},
|
||||
apikey: {{ $disqusjs.ApiKey }},
|
||||
{{ with $disqusjs.ApiUrl }}api: {{ . }},{{ end }}
|
||||
{{ with $disqusjs.Admin }}admin: {{ . }},{{ end }}
|
||||
{{ with $disqusjs.AdminLabel }}adminLabel: {{ . }}{{ end }}
|
||||
});
|
||||
}
|
||||
|
||||
function lazyLoadDisqusJS() {
|
||||
if (["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1) {
|
||||
document.getElementById('disqus_thread').innerHTML = 'Disqus comments not available by default when the website is previewed locally.';
|
||||
return;
|
||||
}
|
||||
|
||||
let d = document.createElement('script');
|
||||
d.src = 'https://cdn.jsdelivr.net/npm/disqusjs@1.3/dist/disqus.js';
|
||||
d.async = false;
|
||||
document.body.appendChild(d);
|
||||
d.onload = () => {
|
||||
loadDisqusJS();
|
||||
window.addEventListener('onColorSchemeChange', (e) => {
|
||||
if (disqusjs) {
|
||||
loadDisqusJS();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let runningOnBrowser = typeof window !== "undefined";
|
||||
let isBot = runningOnBrowser && !("onscroll" in window) || typeof navigator !== "undefined" && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent);
|
||||
let supportsIntersectionObserver = runningOnBrowser && "IntersectionObserver" in window;
|
||||
|
||||
if (!isBot && supportsIntersectionObserver) {
|
||||
let disqus_observer = new IntersectionObserver(function(entries) {
|
||||
if (entries[0].isIntersecting) {
|
||||
lazyLoadDisqusJS();
|
||||
disqus_observer.disconnect();
|
||||
}
|
||||
});
|
||||
disqus_observer.observe(document.getElementById('disqus_thread'));
|
||||
} else {
|
||||
lazyLoadDisqusJS();
|
||||
}
|
||||
</script>
|
||||
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
|
||||
</div>
|
||||
{{- end -}}
|
49
layouts/partials/comments/provider/giscus.html
Normal file
49
layouts/partials/comments/provider/giscus.html
Normal file
@ -0,0 +1,49 @@
|
||||
{{- with .Site.Params.comments.giscus -}}
|
||||
<script
|
||||
src="https://giscus.app/client.js"
|
||||
data-repo="{{- .repo -}}"
|
||||
data-repo-id="{{- .repoID -}}"
|
||||
data-category="{{- .category -}}"
|
||||
data-category-id="{{- .categoryID -}}"
|
||||
data-mapping="{{- default `title` .mapping -}}"
|
||||
data-reactions-enabled="{{- default 1 .reactionsEnabled -}}"
|
||||
data-emit-metadata="{{- default 0 .emitMetadata -}}"
|
||||
data-theme="{{- default `light` .lightTheme -}}"
|
||||
crossorigin="anonymous"
|
||||
async
|
||||
></script>
|
||||
<script>
|
||||
function setGiscusTheme(theme) {
|
||||
let giscus = document.querySelector('iframe.giscus-frame');
|
||||
if (giscus) {
|
||||
giscus.contentWindow.postMessage(
|
||||
{
|
||||
giscus: {
|
||||
setConfig: {
|
||||
theme: theme
|
||||
}
|
||||
}
|
||||
},
|
||||
"https://giscus.app"
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
(function(){
|
||||
addEventListener('message', (e) => {
|
||||
if (event.origin !== 'https://giscus.app') return;
|
||||
handler()
|
||||
});
|
||||
window.addEventListener('onColorSchemeChange', handler);
|
||||
|
||||
function handler() {
|
||||
if (document.documentElement.dataset.scheme === "light") {
|
||||
setGiscusTheme('{{- default "light" .lightTheme -}}');
|
||||
} else {
|
||||
setGiscusTheme('{{- default "dark_dimmed" .darkTheme -}}');
|
||||
};
|
||||
};
|
||||
}());
|
||||
</script>
|
||||
{{- end -}}
|
||||
|
30
layouts/partials/comments/provider/gitalk.html
Normal file
30
layouts/partials/comments/provider/gitalk.html
Normal file
@ -0,0 +1,30 @@
|
||||
{{- with .Site.Params.comments.gitalk -}}
|
||||
<div id="gitalk-container"></div>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.css"
|
||||
/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/blueimp-md5@2.18.0/js/md5.min.js"></script>
|
||||
<script>
|
||||
const gitalk = new Gitalk({
|
||||
clientID: "{{- .clientID -}}",
|
||||
clientSecret: "{{- .clientSecret -}}",
|
||||
repo: "{{- .repo -}}",
|
||||
owner: "{{- .owner -}}",
|
||||
admin: ["{{- .admin -}}"],
|
||||
distractionFreeMode: false, // Facebook-like distraction free mode
|
||||
id: md5(location.pathname), // Max Location.pathname Legth:75 https://github.com/gitalk/gitalk/issues/102
|
||||
});
|
||||
(function () {
|
||||
if (
|
||||
["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1
|
||||
) {
|
||||
document.getElementById("gitalk-container").innerHTML =
|
||||
"Gitalk comments not available by default when the website is previewed locally.";
|
||||
return;
|
||||
}
|
||||
gitalk.render("gitalk-container");
|
||||
})();
|
||||
</script>
|
||||
{{ end }}
|
@ -7,7 +7,7 @@
|
||||
components: ['embed'],
|
||||
url: "{{ $.Permalink }}",
|
||||
max_shown_comments: {{ default 15 .max_shown_comments }},
|
||||
theme: document.body.dataset.scheme,
|
||||
theme: document.documentElement.dataset.scheme,
|
||||
page_title: '{{ $.Title }}',
|
||||
locale: '{{ default "en" .locale }}',
|
||||
show_email_subscription: {{ default true .show_email_subscription }}
|
||||
@ -26,4 +26,4 @@
|
||||
window.REMARK42.changeTheme(e.detail);
|
||||
})
|
||||
</script>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
49
layouts/partials/comments/provider/twikoo.html
Normal file
49
layouts/partials/comments/provider/twikoo.html
Normal file
@ -0,0 +1,49 @@
|
||||
<script src="//cdn.jsdelivr.net/npm/twikoo@1.4.15/dist/twikoo.all.min.js"></script>
|
||||
<div id="tcomment"></div>
|
||||
<style>
|
||||
.twikoo {
|
||||
background-color: var(--card-background);
|
||||
border-radius: var(--card-border-radius);
|
||||
box-shadow: var(--shadow-l1);
|
||||
padding: var(--card-padding);
|
||||
}
|
||||
:root[data-scheme="dark"] {
|
||||
--twikoo-body-text-color-main: rgba(255, 255, 255, 0.9);
|
||||
--twikoo-body-text-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.twikoo .el-input-group__prepend,
|
||||
.twikoo .tk-action-icon,
|
||||
.twikoo .tk-time,
|
||||
.twikoo .tk-comments-count {
|
||||
color: var(--twikoo-body-text-color);
|
||||
}
|
||||
.twikoo .el-input__inner,
|
||||
.twikoo .el-textarea__inner,
|
||||
.twikoo .tk-preview-container,
|
||||
.twikoo .tk-content,
|
||||
.twikoo .tk-nick,
|
||||
.twikoo .tk-send {
|
||||
color: var(--twikoo-body-text-color-main);
|
||||
}
|
||||
.twikoo .el-button{
|
||||
color: var(--twikoo-body-text-color)!important;
|
||||
}
|
||||
</style>
|
||||
|
||||
{{- with .Site.Params.comments.twikoo -}}
|
||||
<script>
|
||||
twikoo.init({
|
||||
envId: '{{- .envId -}}',
|
||||
el: '#tcomment',
|
||||
{{- with .region -}}
|
||||
region: '{{- . -}}',
|
||||
{{- end -}}
|
||||
{{- with .path -}}
|
||||
path: '{{- . -}}',
|
||||
{{- end -}}
|
||||
{{- with .lang -}}
|
||||
lang: '{{- . -}}',
|
||||
{{- end -}}
|
||||
})
|
||||
</script>
|
||||
{{- end -}}
|
@ -31,10 +31,10 @@
|
||||
|
||||
addEventListener('message', event => {
|
||||
if (event.origin !== 'https://utteranc.es') return;
|
||||
setUtterancesTheme(document.body.dataset.scheme)
|
||||
setUtterancesTheme(document.documentElement.dataset.scheme)
|
||||
});
|
||||
|
||||
window.addEventListener('onColorSchemeChange', (e) => {
|
||||
setUtterancesTheme(e.detail)
|
||||
})
|
||||
</script>
|
||||
</script>
|
||||
|
27
layouts/partials/comments/provider/vssue.html
Normal file
27
layouts/partials/comments/provider/vssue.html
Normal file
@ -0,0 +1,27 @@
|
||||
{{- with .Site.Params.comments.vssue -}}
|
||||
<link rel="stylesheet" href="https://unpkg.com/vssue/dist/vssue.min.css" />
|
||||
|
||||
<div id="vssue"></div>
|
||||
|
||||
<script src="https://unpkg.com/vue/dist/vue.runtime.min.js"></script>
|
||||
<script src="https://unpkg.com/vssue/dist/vssue.{{ .platform }}.min.js"></script>
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
el: "#vssue",
|
||||
render: (h) =>
|
||||
h("Vssue", {
|
||||
props: {
|
||||
title: "{{ $.Title }}",
|
||||
options: {
|
||||
autoCreateIssue: {{ default false .autoCreateIssue }},
|
||||
owner: "{{ .owner }}",
|
||||
repo: "{{ .repo }}",
|
||||
clientId: "{{ .clientId }}",
|
||||
clientSecret: "{{ .clientSecret }}",
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
</script>
|
||||
{{- end -}}
|
32
layouts/partials/comments/provider/waline.html
Normal file
32
layouts/partials/comments/provider/waline.html
Normal file
@ -0,0 +1,32 @@
|
||||
<script src='//cdn.jsdelivr.net/npm/@waline/client/dist/Waline.min.js'></script>
|
||||
<div id="waline" class="waline-container"></div>
|
||||
<style>
|
||||
.waline-container {
|
||||
background-color: var(--card-background);
|
||||
border-radius: var(--card-border-radius);
|
||||
box-shadow: var(--shadow-l1);
|
||||
padding: var(--card-padding);
|
||||
}
|
||||
.waline-container .vcount {
|
||||
color: var(--card-text-color-main);
|
||||
}
|
||||
</style>
|
||||
|
||||
{{- with .Site.Params.comments.waline -}}
|
||||
{{- $config := dict "el" "#waline" "dark" `html[data-scheme="dark"]` -}}
|
||||
{{- $replaceKeys := dict "serverurl" "serverURL" "requiredmeta" "requiredMeta" "wordlimit" "wordLimit" "pagesize" "pageSize" "avatarcdn" "avatarCDN" "avatarforce" "avatarForce" -}}
|
||||
|
||||
{{- range $key, $val := . -}}
|
||||
{{- if $val -}}
|
||||
{{- $replaceKey := index $replaceKeys $key -}}
|
||||
{{- $k := default $key $replaceKey -}}
|
||||
|
||||
{{- $config = merge $config (dict $k $val) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
<script>
|
||||
/// Waline client configuration see: https://waline.js.org/en/reference/client.html
|
||||
new Waline({{ $config | jsonify | safeJS }});
|
||||
</script>
|
||||
{{- end -}}
|
@ -3,4 +3,10 @@
|
||||
{{- $opts := dict "minify" hugo.IsProduction -}}
|
||||
{{- $script := resources.Get "ts/main.ts" | js.Build $opts -}}
|
||||
|
||||
<script type="text/javascript" src="{{ $script.RelPermalink }}" defer></script>
|
||||
<script type="text/javascript" src="{{ $script.RelPermalink }}" defer></script>
|
||||
|
||||
{{- with resources.Get "ts/custom.ts" -}}
|
||||
{{/* Place your custom script in HUGO_SITE_FOLDER/assets/ts/custom.ts */}}
|
||||
{{- $customScript := . | js.Build $opts -}}
|
||||
<script type="text/javascript" src="{{ $customScript.RelPermalink }}" defer></script>
|
||||
{{- end -}}
|
@ -1,4 +1,4 @@
|
||||
{{- $ThemeVersion := "2.2.0" -}}
|
||||
{{- $ThemeVersion := "3.8.0" -}}
|
||||
<footer class="site-footer">
|
||||
<section class="copyright">
|
||||
©
|
||||
@ -20,4 +20,4 @@
|
||||
{{ T "footer.builtWith" (dict "Generator" $Generator) | safeHTML }} <br />
|
||||
{{ T "footer.designedBy" (dict "Theme" $Theme "DesignedBy" $DesignedBy) | safeHTML }}
|
||||
</section>
|
||||
</footer>
|
||||
</footer>
|
||||
|
@ -31,9 +31,9 @@
|
||||
* 1. If dark mode is set already (in local storage)
|
||||
* 2. Auto mode & prefere color scheme is dark
|
||||
*/
|
||||
document.body.dataset.scheme = 'dark';
|
||||
document.documentElement.dataset.scheme = 'dark';
|
||||
} else {
|
||||
document.body.dataset.scheme = 'light';
|
||||
document.documentElement.dataset.scheme = 'light';
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</script>
|
||||
|
@ -21,5 +21,5 @@
|
||||
<link rel="shortcut icon" href="{{ . }}" />
|
||||
{{ end }}
|
||||
|
||||
{{- template "_internal/google_analytics_async.html" . -}}
|
||||
{{- template "_internal/google_analytics.html" . -}}
|
||||
{{- partial "head/custom.html" . -}}
|
||||
|
@ -1,5 +1,6 @@
|
||||
{{- with .Site.Params.opengraph.twitter.site -}}
|
||||
<meta name="twitter:site" content="{{ . }}">
|
||||
<meta name="twitter:site" content="@{{ . }}">
|
||||
<meta name="twitter:creator" content="@{{ . }}">
|
||||
{{- end -}}
|
||||
|
||||
{{- $title := partialCached "data/title" . .RelPermalink -}}
|
||||
|
@ -1,3 +1,3 @@
|
||||
{{ $sass := resources.Get "scss/style.scss" }}
|
||||
{{ $style := $sass | resources.ToCSS | minify }}
|
||||
{{ $style := $sass | resources.ToCSS | minify | resources.Fingerprint "sha256" }}
|
||||
<link rel="stylesheet" href="{{ $style.RelPermalink }}">
|
@ -8,7 +8,7 @@
|
||||
integrity="{{ . }}"
|
||||
{{- end -}}
|
||||
crossorigin="anonymous"
|
||||
defer="{{ default false .defer }}"
|
||||
{{ if .defer }}defer{{ end }}
|
||||
>
|
||||
</script>
|
||||
{{- else if eq .type "style" -}}
|
||||
|
@ -8,7 +8,7 @@
|
||||
{{ $url := urls.Parse $imageValue }}
|
||||
|
||||
{{ if or (eq $url.Scheme "http") (eq $url.Scheme "https") }}
|
||||
<!-- Is a external image -->
|
||||
<!-- Is an external image -->
|
||||
{{ $result = merge $result (dict "permalink" $imageValue) }}
|
||||
{{ else }}
|
||||
{{ $pageResourceImage := .Context.Resources.GetMatch (printf "%s" ($imageValue | safeURL)) }}
|
||||
@ -23,7 +23,7 @@
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<!-- Can not find the image under page bundle. Could be a relative linked image -->
|
||||
{{ $result = merge $result (dict "permalink" $imageValue) }}
|
||||
{{ $result = merge $result (dict "permalink" (relURL $imageValue)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
@ -51,11 +51,11 @@
|
||||
|
||||
{{ else }}
|
||||
<!-- External image -->
|
||||
{{ $result = merge $result (dict "permalink" $defaultImageSetting.src) }}
|
||||
{{ $result = merge $result (dict "permalink" (relURL $defaultImageSetting.src)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
|
||||
{{ return $result }}
|
||||
{{ return $result }}
|
||||
|
@ -7,7 +7,9 @@
|
||||
|
||||
<header class="site-info">
|
||||
{{ with .Site.Params.sidebar.avatar }}
|
||||
{{ if (default true .enabled) }}
|
||||
<figure class="site-avatar">
|
||||
<a href="{{ .Site.BaseURL | relLangURL }}">
|
||||
{{ if not .local }}
|
||||
<img src="{{ .src }}" width="300" height="300" class="site-logo" loading="lazy" alt="Avatar">
|
||||
{{ else }}
|
||||
@ -21,14 +23,35 @@
|
||||
{{ errorf "Failed loading avatar from %q" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
</a>
|
||||
{{ with $.Site.Params.sidebar.emoji }}
|
||||
<span class="emoji">{{ . }}</span>
|
||||
{{ end }}
|
||||
</figure>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<h1 class="site-name"><a href="{{ .Site.BaseURL }}">{{ .Site.Title }}</a></h1>
|
||||
|
||||
<h1 class="site-name"><a href="{{ .Site.BaseURL | relLangURL }}">{{ .Site.Title }}</a></h1>
|
||||
<h2 class="site-description">{{ .Site.Params.sidebar.subtitle }}</h2>
|
||||
|
||||
{{- with .Site.Menus.social -}}
|
||||
<ol class="social-menu">
|
||||
{{ range . }}
|
||||
<li>
|
||||
<a
|
||||
href='{{ .URL }}'
|
||||
{{ if eq (default true .Params.newTab) true }}target="_blank"{{ end }}
|
||||
{{ with .Name }}title="{{ . }}"{{ end }}
|
||||
>
|
||||
{{ $icon := default "link" .Params.Icon }}
|
||||
{{ with $icon }}
|
||||
{{ partial "helper/icon" . }}
|
||||
{{ end }}
|
||||
</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ol>
|
||||
{{- end -}}
|
||||
</header>
|
||||
|
||||
<ol class="menu" id="main-menu">
|
||||
@ -37,9 +60,13 @@
|
||||
{{ $active := or (eq $currentPage.Title .Name) (or ($currentPage.HasMenuCurrent "main" .) ($currentPage.IsMenuCurrent "main" .)) }}
|
||||
|
||||
<li {{ if $active }} class='current' {{ end }}>
|
||||
<a href='{{ .URL | relURL }}'>
|
||||
<a href='{{ .URL | relLangURL }}' {{ if eq .Params.newTab true }}target="_blank"{{ end }}>
|
||||
{{ $icon := default .Pre .Params.Icon }}
|
||||
{{ if .Pre }}
|
||||
{{ partial "helper/icon" .Pre }}
|
||||
{{ warnf "Menu item [%s] is using [pre] field to set icon, please use [params.icon] instead.\nMore information: https://docs.stack.jimmycai.com/configuration/custom-menu.html" .URL }}
|
||||
{{ end }}
|
||||
{{ with $icon }}
|
||||
{{ partial "helper/icon" . }}
|
||||
{{ end }}
|
||||
<span>{{- .Name -}}</span>
|
||||
</a>
|
||||
|
@ -1,21 +0,0 @@
|
||||
{{ define "container-class" }}article-page with-toolbar{{ end }}
|
||||
{{ define "main" }}
|
||||
<div id="article-toolbar">
|
||||
<a href="{{ .Site.BaseURL }}" class="back-home">
|
||||
{{ (resources.Get "icons/back.svg").Content | safeHTML }}
|
||||
<span>Back</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{ partial "article/article.html" . }}
|
||||
|
||||
{{ partial "article/components/related-contents" . }}
|
||||
|
||||
{{ if or (not (isset .Params "comments")) (eq .Params.comments "true")}}
|
||||
{{ partial "comments/include" . }}
|
||||
{{ end }}
|
||||
|
||||
{{ partialCached "footer/footer" . }}
|
||||
|
||||
{{- partialCached "article/components/photoswipe.html" . -}}
|
||||
{{ end }}
|
@ -12,13 +12,12 @@
|
||||
<p>当前视频av或BV号:{{ $vid }},视频分P:{{ $videopage }}</p>
|
||||
{{ end }}
|
||||
|
||||
<div style="position: relative; width: 100%; height: 0; padding-bottom: 56.25%;">
|
||||
<iframe src="//player.bilibili.com/player.html?{{ $basicQuery | safeURL }}&{{ $videoQuery | safeURL }}"
|
||||
<div class="video-wrapper">
|
||||
<iframe src="https://player.bilibili.com/player.html?{{ $basicQuery | safeURL }}&{{ $videoQuery | safeURL }}"
|
||||
scrolling="no"
|
||||
frameborder="no"
|
||||
framespacing="0"
|
||||
allowfullscreen="true"
|
||||
style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
|
@ -1,10 +1,10 @@
|
||||
{{ $vid := .Get 0 }}
|
||||
<div style="position: relative; width: 100%; height: 0; padding-bottom: 56.25%;">
|
||||
<iframe src="http://v.qq.com/txp/iframe/player.html?vid={{ $vid }}&auto=0"
|
||||
<div class="video-wrapper">
|
||||
<iframe src="https://v.qq.com/txp/iframe/player.html?vid={{ $vid }}&auto=0"
|
||||
scrolling="no"
|
||||
frameborder="no"
|
||||
framespacing="0"
|
||||
allowfullscreen="true"
|
||||
style="position: absolute; width: 100%; height: 100%;">
|
||||
allowfullscreen="true"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
14
layouts/shortcodes/video.html
Normal file
14
layouts/shortcodes/video.html
Normal file
@ -0,0 +1,14 @@
|
||||
{{- $src := .Get "src" | default (.Get 0) -}}
|
||||
<div class="video-wrapper">
|
||||
<video
|
||||
controls
|
||||
src="{{- $src -}}"
|
||||
{{ with .Get "poster" }}poster="{{- . -}}"{{ end }}
|
||||
{{ with .Get "autoplay" }}autoplay{{ end }}
|
||||
>
|
||||
<p>
|
||||
Your browser doesn't support HTML5 video. Here is a
|
||||
<a href="{{- $src -}}">link to the video</a> instead.
|
||||
</p>
|
||||
</video>
|
||||
</div>
|
@ -2,8 +2,12 @@
|
||||
{{- if not $pc.Disable -}}
|
||||
{{- $ytHost := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" -}}
|
||||
{{- $id := .Get "id" | default (.Get 0) -}}
|
||||
{{- $class := .Get "class" | default (.Get 1) }}
|
||||
<div {{ with $class }}class="{{ . }}"{{ else }}style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"{{ end }}>
|
||||
<iframe loading="lazy" src="https://{{ $ytHost }}/embed/{{ $id }}{{ with .Get "autoplay" }}{{ if eq . "true" }}?autoplay=1{{ end }}{{ end }}" {{ if not $class }}style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" {{ end }}allowfullscreen title="YouTube Video"></iframe>
|
||||
<div class="video-wrapper">
|
||||
<iframe loading="lazy"
|
||||
src="https://{{ $ytHost }}/embed/{{ $id }}{{ with .Get "autoplay" }}{{ if eq . "true" }}?autoplay=1{{ end }}{{ end }}"
|
||||
allowfullscreen
|
||||
title="YouTube Video"
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
{{ end -}}
|
10
netlify.toml
10
netlify.toml
@ -2,7 +2,7 @@
|
||||
publish = "exampleSite/public"
|
||||
|
||||
[build.environment]
|
||||
HUGO_VERSION = "0.79.0"
|
||||
HUGO_VERSION = "0.87.0"
|
||||
HUGO_THEME = "repo"
|
||||
|
||||
[context.production]
|
||||
@ -17,4 +17,10 @@
|
||||
command = "cd exampleSite && hugo --gc --themesDir ../.. -b ${DEPLOY_PRIME_URL}"
|
||||
|
||||
[[plugins]]
|
||||
package = "/exampleSite/plugins/netlify-plugin-hugo-cache-resources"
|
||||
package = "netlify-plugin-hugo-cache-resources"
|
||||
|
||||
[plugins.inputs]
|
||||
# If it should show more verbose logs (optional, default = true)
|
||||
debug = true
|
||||
# Relative path to source directory in case you use Hugo's "--s" option
|
||||
srcdir = "exampleSite"
|
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
{"Target":"scss/style.min.css","MediaType":"text/css","Data":{}}
|
26
theme.toml
26
theme.toml
@ -5,23 +5,23 @@ name = "Stack"
|
||||
license = "GPL-3.0-only"
|
||||
licenselink = "https://github.com/CaiJimmy/hugo-theme-stack/blob/master/LICENSE"
|
||||
description = "Card-style Hugo theme designed for bloggers"
|
||||
homepage = "https://theme-stack.jimmycai.com"
|
||||
tags = [
|
||||
"blog",
|
||||
"responsive",
|
||||
"clean",
|
||||
"light",
|
||||
"dark",
|
||||
"personal"
|
||||
]
|
||||
homepage = "https://github.com/CaiJimmy/hugo-theme-stack"
|
||||
demosite = "https://demo.stack.jimmycai.com"
|
||||
|
||||
tags = ["blog", "responsive", "clean", "light", "dark", "personal"]
|
||||
|
||||
features = [
|
||||
"disqus",
|
||||
"photoswipe",
|
||||
"opengraph",
|
||||
"widgets"
|
||||
"widgets",
|
||||
"darkmode",
|
||||
"table of contents",
|
||||
"search",
|
||||
]
|
||||
min_version = "0.78.0"
|
||||
|
||||
min_version = "0.87.0"
|
||||
|
||||
[author]
|
||||
name = "Jimmy Cai"
|
||||
homepage = "https://jimmycai.com"
|
||||
name = "Jimmy Cai"
|
||||
homepage = "https://jimmycai.com"
|
||||
|
Loading…
Reference in New Issue
Block a user