feat: add Tailwind variant of Wowchemy components and layouts

This commit is contained in:
George Cushen committed 2023-10-24 18:31:41 +01:00
1 parent 110377e4b8
commit 3dc5088639
67 files changed
+2621

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
# Wowchemy Tailwind UI
The Wowchemy web framework utilising [TailwindCSS](https://tailwindcss.com/) and its [typography plugin](https://tailwindcss.com/docs/typography-plugin) for styling components.
See the Blog Starter Template for an example using this module.
## Development
```bash
hugo mod npm pack
npm install
```
You need to add this to your `config.yaml` to enable Hugo's Tailwind integration:
```yaml
build:
writeStats: true
```
@@ -0,0 +1,144 @@
.wg-about-avatar {
#profile {
text-align: center;
padding: 30px 10px;
position: relative;
}
/* Custom avatar size on homepage */
.avatar {
width: auto;
height: auto;
max-width: 225px;
max-height: 225px;
object-fit: cover;
}
.portrait-title h2 {
font-size: 1.75em;
font-weight: 300;
/* color: #000; */
margin: 20px 0 10px;
}
.portrait-title h3 {
font-size: 1rem;
font-weight: 300;
/* color: rgba(0, 0, 0, 0.54); */
margin: 0 0 10px;
}
.network-icon {
display: inline-flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
list-style: none;
padding: 0;
margin: 0;
}
#profile .network-icon {
margin-top: 0.5rem;
}
.network-icon li {
margin-right: 10px;
@media (max-width: 640px) {
/* Min 48px Lighthouse tap targets on mobile */
margin-right: 12px;
}
}
.network-icon li:last-of-type {
margin-right: 0;
}
.network-icon li:hover {
transform: scale(1.2);
}
.big-icon {
font-size: 2rem;
}
.ul-interests li {
font-size: 0.9rem;
}
.ul-edu {
list-style: none;
}
.ul-edu li {
position: relative;
padding: 0 15px 4px 3px;
}
.ul-edu li .description p {
margin: 0;
}
.ul-edu li .description p.course {
font-size: 0.9rem;
}
.ul-edu li .description p.institution {
font-size: 0.75rem;
/* color: rgba(0, 0, 0, 0.6); */
}
.network-icon .big-icon {
font-size: 1.5rem;
}
.dark .portrait-title h3 {
color: rgba(255, 255, 255, 0.9);
font-weight: bold;
}
.dark .portrait-title h2 {
color: #fff;
font-weight: bold;
}
.bio-text {
max-width: 680px;
}
}
.avatar-wrapper {
position: relative;
width: 150px; /* Match image size in about.avatar widget */
height: 150px;
margin-left: auto;
margin-right: auto;
}
.avatar-emoji {
position: absolute;
width: 40px;
height: 40px;
line-height: 40px;
border-radius: 100%;
bottom: 0;
right: 0;
text-align: center;
font-size: 20px;
background-color: #fff;
color: #000; /* override parent alpha */
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.04), 0 2px 6px rgba(0, 0, 0, 0.04), 0 0 1px rgba(0, 0, 0, 0.04);
}
.dark .avatar-emoji {
background-color: #000;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.04), 0 2px 6px rgba(0, 0, 0, 0.04), 0 0 1px rgba(255, 255, 255, 0.96);
}
@@ -0,0 +1 @@
@import "about.avatar.css";
@@ -0,0 +1,2 @@
@import "page.css";
@import "task-list.css";
@@ -0,0 +1,72 @@
/* Page layout to push footer to bottom of page */
.page-wrapper {
/* Min height = viewport height - navbar height */
min-height: 100vh;
display: grid;
grid-template-rows: auto 1fr auto;
grid-template-columns: 100%;
}
.page-header,
.page-footer {
flex-shrink: 0;
}
.page-body {
flex-grow: 1;
}
.article-header {
position: relative; /* Required for caption positioning */
clear: both;
}
.article-banner {
width: 100%;
height: 260px;
object-fit: cover;
/*@include media-breakpoint-up(lg) {*/
/* height: 310px; !* Increased height on desktop *!*/
/*}*/
}
.featured-image-wrapper {
position: relative;
padding-left: 0; /* Override container padding. */
padding-right: 0; /* Override container padding. */
}
.featured-image {
position: relative;
width: 100%;
display: block;
margin: 0 auto;
}
.article-header-caption {
position: absolute;
bottom: 0;
right: 0;
margin: 0 auto;
padding: 2px 5px;
color: #fff;
font-size: 0.7em;
background: #000;
text-align: right;
z-index: 5;
opacity: 0.65;
border-radius: 5px 0 0;
}
@media (min-width: 64em) {
.article-header-caption {
padding: 5px 10px;
}
}
.article-header-caption a {
color: #fff;
text-decoration: none;
}
@@ -0,0 +1,30 @@
/* Wowchemy - https://wowchemy.com
* Task List Component
* License: https://github.com/wowchemy/wowchemy-hugo-themes/blob/main/LICENSE.md
*/
ul.task-list {
list-style: none;
}
ul.task-list li input[type='checkbox'] {
margin-right: 0.5rem;
}
ul.task-list input[type='checkbox']:checked {
appearance: none;
width: 1em;
height: 1em;
border: none;
background: initial;
position: relative;
}
ul.task-list input[type='checkbox']:not(:checked) {
width: 0.9em;
height: 0.9em;
}
ul.task-list input[type='checkbox']:checked::after {
content: '✅';
}
@@ -0,0 +1,85 @@
/* Background */ .bg { color: #f8f8f2; background-color: #282a36 }
/* PreWrapper */ .chroma { color: #f8f8f2; background-color: #282a36; }
/* Other */ .chroma .x { }
/* Error */ .chroma .err { }
/* CodeLine */ .chroma .cl { }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .chroma .hl { background-color: #ffc }
/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Line */ .chroma .line { display: flex; }
/* Keyword */ .chroma .k { color: #ff79c6 }
/* KeywordConstant */ .chroma .kc { color: #ff79c6 }
/* KeywordDeclaration */ .chroma .kd { color: #8be9fd; font-style: italic }
/* KeywordNamespace */ .chroma .kn { color: #ff79c6 }
/* KeywordPseudo */ .chroma .kp { color: #ff79c6 }
/* KeywordReserved */ .chroma .kr { color: #ff79c6 }
/* KeywordType */ .chroma .kt { color: #8be9fd }
/* Name */ .chroma .n { }
/* NameAttribute */ .chroma .na { color: #50fa7b }
/* NameBuiltin */ .chroma .nb { color: #8be9fd; font-style: italic }
/* NameBuiltinPseudo */ .chroma .bp { }
/* NameClass */ .chroma .nc { color: #50fa7b }
/* NameConstant */ .chroma .no { }
/* NameDecorator */ .chroma .nd { }
/* NameEntity */ .chroma .ni { }
/* NameException */ .chroma .ne { }
/* NameFunction */ .chroma .nf { color: #50fa7b }
/* NameFunctionMagic */ .chroma .fm { }
/* NameLabel */ .chroma .nl { color: #8be9fd; font-style: italic }
/* NameNamespace */ .chroma .nn { }
/* NameOther */ .chroma .nx { }
/* NameProperty */ .chroma .py { }
/* NameTag */ .chroma .nt { color: #ff79c6 }
/* NameVariable */ .chroma .nv { color: #8be9fd; font-style: italic }
/* NameVariableClass */ .chroma .vc { color: #8be9fd; font-style: italic }
/* NameVariableGlobal */ .chroma .vg { color: #8be9fd; font-style: italic }
/* NameVariableInstance */ .chroma .vi { color: #8be9fd; font-style: italic }
/* NameVariableMagic */ .chroma .vm { }
/* Literal */ .chroma .l { }
/* LiteralDate */ .chroma .ld { }
/* LiteralString */ .chroma .s { color: #f1fa8c }
/* LiteralStringAffix */ .chroma .sa { color: #f1fa8c }
/* LiteralStringBacktick */ .chroma .sb { color: #f1fa8c }
/* LiteralStringChar */ .chroma .sc { color: #f1fa8c }
/* LiteralStringDelimiter */ .chroma .dl { color: #f1fa8c }
/* LiteralStringDoc */ .chroma .sd { color: #f1fa8c }
/* LiteralStringDouble */ .chroma .s2 { color: #f1fa8c }
/* LiteralStringEscape */ .chroma .se { color: #f1fa8c }
/* LiteralStringHeredoc */ .chroma .sh { color: #f1fa8c }
/* LiteralStringInterpol */ .chroma .si { color: #f1fa8c }
/* LiteralStringOther */ .chroma .sx { color: #f1fa8c }
/* LiteralStringRegex */ .chroma .sr { color: #f1fa8c }
/* LiteralStringSingle */ .chroma .s1 { color: #f1fa8c }
/* LiteralStringSymbol */ .chroma .ss { color: #f1fa8c }
/* LiteralNumber */ .chroma .m { color: #bd93f9 }
/* LiteralNumberBin */ .chroma .mb { color: #bd93f9 }
/* LiteralNumberFloat */ .chroma .mf { color: #bd93f9 }
/* LiteralNumberHex */ .chroma .mh { color: #bd93f9 }
/* LiteralNumberInteger */ .chroma .mi { color: #bd93f9 }
/* LiteralNumberIntegerLong */ .chroma .il { color: #bd93f9 }
/* LiteralNumberOct */ .chroma .mo { color: #bd93f9 }
/* Operator */ .chroma .o { color: #ff79c6 }
/* OperatorWord */ .chroma .ow { color: #ff79c6 }
/* Punctuation */ .chroma .p { }
/* Comment */ .chroma .c { color: #6272a4 }
/* CommentHashbang */ .chroma .ch { color: #6272a4 }
/* CommentMultiline */ .chroma .cm { color: #6272a4 }
/* CommentSingle */ .chroma .c1 { color: #6272a4 }
/* CommentSpecial */ .chroma .cs { color: #6272a4 }
/* CommentPreproc */ .chroma .cp { color: #ff79c6 }
/* CommentPreprocFile */ .chroma .cpf { color: #ff79c6 }
/* Generic */ .chroma .g { }
/* GenericDeleted */ .chroma .gd { color: #f55 }
/* GenericEmph */ .chroma .ge { text-decoration: underline }
/* GenericError */ .chroma .gr { }
/* GenericHeading */ .chroma .gh { font-weight: bold }
/* GenericInserted */ .chroma .gi { color: #50fa7b; font-weight: bold }
/* GenericOutput */ .chroma .go { color: #44475a }
/* GenericPrompt */ .chroma .gp { }
/* GenericStrong */ .chroma .gs { }
/* GenericSubheading */ .chroma .gu { font-weight: bold }
/* GenericTraceback */ .chroma .gt { }
/* GenericUnderline */ .chroma .gl { text-decoration: underline }
/* TextWhitespace */ .chroma .w { }
@@ -0,0 +1,271 @@
.chroma {
background-color: #0d1117;
color: #fff;
}
.chroma .nn {
color: #fff;
}
.chroma .err {
color: #f85149;
}
.chroma .p {
color: #c9d1d9;
}
.chroma .lntd {
border: 0;
margin: 0;
padding: 0;
vertical-align: top;
}
.chroma .lntable {
width: auto;
border: 0;
margin: 0;
display: block;
padding: 0;
overflow: auto;
border-spacing: 0;
}
.chroma .hl {
width: 100%;
display: block;
background-color: rgba(110,118,129,0.1);
}
.chroma .lnt {
color: #8b949e;
padding: 0 0.4em 0 0.4em;
font-size: 0.875rem;
margin-right: 0.4em;
}
.chroma .ln {
color: #8b949e;
padding: 0 0.4em 0 0.4em;
margin-right: 0.4em;
}
.chroma .k {
color: #ff7b72;
}
.chroma .kc {
color: #ff7b72;
font-weight: bold;
}
.chroma .kd {
color: #ff7b72;
font-weight: bold;
}
.chroma .kn {
color: #ff7b72;
font-weight: bold;
}
.chroma .kp {
color: #ff7b72;
font-weight: bold;
}
.chroma .kr {
color: #ff7b72;
font-weight: bold;
}
.chroma .kt {
color: #ff7b72;
font-weight: bold;
}
.chroma .na {
color: #c9d1d9;
}
.chroma .nb {
color: #c9d1d9;
}
.chroma .bp {
color: #c9d1d9;
}
.chroma .nc {
color: #7ee787;
font-weight: bold;
}
.chroma .no {
color: #79c0ff;
font-weight: bold;
}
.chroma .nd {
color: #bc8cff;
font-weight: bold;
}
.chroma .ni {
color: #ffa657;
}
.chroma .ne {
color: #ffa657;
font-weight: bold;
}
.chroma .nf {
color: #d2a8ff;
font-weight: bold;
}
.chroma .nl {
color: #79c0ff;
font-weight: bold;
}
.chroma .nm {
color: #ff7b72;
}
.chroma .nx {
color: #79c0ff;
}
.chroma .py {
color: #79c0ff;
}
.chroma .nt {
color: #7ee787;
}
.chroma .nv {
color: #79c0ff;
}
.chroma .vc {
color: #79c0ff;
}
.chroma .vg {
color: #79c0ff;
}
.chroma .vi {
color: #79c0ff;
}
.chroma .l {
color: #79c0ff;
}
.chroma .ld {
color: #79c0ff;
}
.chroma .s {
color: #79c0ff;
}
.chroma .sa {
color: #79c0ff;
}
.chroma .sb {
color: #79c0ff;
}
.chroma .sc {
color: #79c0ff;
}
.chroma .dl {
color: #79c0ff;
}
.chroma .sd {
color: #79c0ff;
}
.chroma .s2 {
color: #79c0ff;
}
.chroma .se {
color: #79c0ff;
}
.chroma .sh {
color: #79c0ff;
}
.chroma .si {
color: #79c0ff;
}
.chroma .sx {
color: #79c0ff;
}
.chroma .sr {
color: #79c0ff;
}
.chroma .s1 {
color: #79c0ff;
}
.chroma .ss {
color: #79c0ff;
}
.chroma .m {
color: #79c0ff;
}
.chroma .mb {
color: #79c0ff;
}
.chroma .mf {
color: #79c0ff;
}
.chroma .mh {
color: #79c0ff;
}
.chroma .mi {
color: #79c0ff;
}
.chroma .il {
color: #79c0ff;
}
.chroma .mo {
color: #79c0ff;
}
.chroma .o {
color: #a5d6ff;
font-weight: bold;
}
.chroma .ow {
color: #a5d6ff;
font-weight: bold;
}
.chroma .c {
color: #8b949e;
font-style: italic;
}
.chroma .ch {
color: #8b949e;
font-style: italic;
}
.chroma .cm {
color: #8b949e;
font-style: italic;
}
.chroma .c1 {
color: #8b949e;
font-style: italic;
}
.chroma .cs {
color: #8b949e;
font-style: italic;
}
.chroma .cpf {
color: #8b949e;
font-style: italic;
}
.chroma .gd {
color: #ffa198;
background-color: #490202;
}
.chroma .ge {
color: #c9d1d9;
font-style: italic;
}
.chroma .gr {
color: #ffa198;
}
.chroma .gh {
color: #79c0ff;
}
.chroma .gi {
color: #7ee787;
background-color: #56d364;
}
.chroma .go {
color: #8b949e;
}
.chroma .gp {
color: #8b949e;
}
.chroma .gs {
font-weight: bold;
}
.chroma .gu {
color: #79c0ff;
}
.chroma .gt {
color: #ffa198;
}
.chroma .gl {
text-decoration: underline;
}
.chroma .w {
color: #484f58;
}
@@ -0,0 +1,85 @@
/* Background */ .bg { background-color: #fff }
/* PreWrapper */ .chroma { background-color: #fff; }
/* Other */ .chroma .x { }
/* Error */ .chroma .err { color: #a61717; background-color: #e3d2d2 }
/* CodeLine */ .chroma .cl { }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .chroma .hl { background-color: #ffc }
/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em;color: #7f7f7f }
/* Line */ .chroma .line { display: flex; }
/* Keyword */ .chroma .k { color: #000; font-weight: bold }
/* KeywordConstant */ .chroma .kc { color: #000; font-weight: bold }
/* KeywordDeclaration */ .chroma .kd { color: #000; font-weight: bold }
/* KeywordNamespace */ .chroma .kn { color: #000; font-weight: bold }
/* KeywordPseudo */ .chroma .kp { color: #000; font-weight: bold }
/* KeywordReserved */ .chroma .kr { color: #000; font-weight: bold }
/* KeywordType */ .chroma .kt { color: #458; font-weight: bold }
/* Name */ .chroma .n { }
/* NameAttribute */ .chroma .na { color: #008080 }
/* NameBuiltin */ .chroma .nb { color: #0086b3 }
/* NameBuiltinPseudo */ .chroma .bp { color: #999 }
/* NameClass */ .chroma .nc { color: #458; font-weight: bold }
/* NameConstant */ .chroma .no { color: #008080 }
/* NameDecorator */ .chroma .nd { color: #3c5d5d; font-weight: bold }
/* NameEntity */ .chroma .ni { color: #800080 }
/* NameException */ .chroma .ne { color: #900; font-weight: bold }
/* NameFunction */ .chroma .nf { color: #900; font-weight: bold }
/* NameFunctionMagic */ .chroma .fm { }
/* NameLabel */ .chroma .nl { color: #900; font-weight: bold }
/* NameNamespace */ .chroma .nn { color: #555 }
/* NameOther */ .chroma .nx { }
/* NameProperty */ .chroma .py { }
/* NameTag */ .chroma .nt { color: #000080 }
/* NameVariable */ .chroma .nv { color: #008080 }
/* NameVariableClass */ .chroma .vc { color: #008080 }
/* NameVariableGlobal */ .chroma .vg { color: #008080 }
/* NameVariableInstance */ .chroma .vi { color: #008080 }
/* NameVariableMagic */ .chroma .vm { }
/* Literal */ .chroma .l { }
/* LiteralDate */ .chroma .ld { }
/* LiteralString */ .chroma .s { color: #d14 }
/* LiteralStringAffix */ .chroma .sa { color: #d14 }
/* LiteralStringBacktick */ .chroma .sb { color: #d14 }
/* LiteralStringChar */ .chroma .sc { color: #d14 }
/* LiteralStringDelimiter */ .chroma .dl { color: #d14 }
/* LiteralStringDoc */ .chroma .sd { color: #d14 }
/* LiteralStringDouble */ .chroma .s2 { color: #d14 }
/* LiteralStringEscape */ .chroma .se { color: #d14 }
/* LiteralStringHeredoc */ .chroma .sh { color: #d14 }
/* LiteralStringInterpol */ .chroma .si { color: #d14 }
/* LiteralStringOther */ .chroma .sx { color: #d14 }
/* LiteralStringRegex */ .chroma .sr { color: #009926 }
/* LiteralStringSingle */ .chroma .s1 { color: #d14 }
/* LiteralStringSymbol */ .chroma .ss { color: #990073 }
/* LiteralNumber */ .chroma .m { color: #099 }
/* LiteralNumberBin */ .chroma .mb { color: #099 }
/* LiteralNumberFloat */ .chroma .mf { color: #099 }
/* LiteralNumberHex */ .chroma .mh { color: #099 }
/* LiteralNumberInteger */ .chroma .mi { color: #099 }
/* LiteralNumberIntegerLong */ .chroma .il { color: #099 }
/* LiteralNumberOct */ .chroma .mo { color: #099 }
/* Operator */ .chroma .o { color: #000; font-weight: bold }
/* OperatorWord */ .chroma .ow { color: #000; font-weight: bold }
/* Punctuation */ .chroma .p { }
/* Comment */ .chroma .c { color: #998; font-style: italic }
/* CommentHashbang */ .chroma .ch { color: #998; font-style: italic }
/* CommentMultiline */ .chroma .cm { color: #998; font-style: italic }
/* CommentSingle */ .chroma .c1 { color: #998; font-style: italic }
/* CommentSpecial */ .chroma .cs { color: #999; font-weight: bold; font-style: italic }
/* CommentPreproc */ .chroma .cp { color: #999; font-weight: bold; font-style: italic }
/* CommentPreprocFile */ .chroma .cpf { color: #999; font-weight: bold; font-style: italic }
/* Generic */ .chroma .g { }
/* GenericDeleted */ .chroma .gd { color: #000; background-color: #fdd }
/* GenericEmph */ .chroma .ge { color: #000; font-style: italic }
/* GenericError */ .chroma .gr { color: #a00 }
/* GenericHeading */ .chroma .gh { color: #999 }
/* GenericInserted */ .chroma .gi { color: #000; background-color: #dfd }
/* GenericOutput */ .chroma .go { color: #888 }
/* GenericPrompt */ .chroma .gp { color: #555 }
/* GenericStrong */ .chroma .gs { font-weight: bold }
/* GenericSubheading */ .chroma .gu { color: #aaa }
/* GenericTraceback */ .chroma .gt { color: #a00 }
/* GenericUnderline */ .chroma .gl { text-decoration: underline }
/* TextWhitespace */ .chroma .w { color: #bbb }
@@ -0,0 +1,6 @@
/* Import Tailwind */
@import "./tailwind.css";
/*!* Import Wowchemy components *!*/
@import "./components/all.css";
@import "./blocks/all.css";
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
+53
View File
@@ -0,0 +1,53 @@
markup:
defaultMarkdownHandler: goldmark
goldmark:
renderer:
unsafe: true
parser:
attribute:
block: true
title: true
highlight:
codeFences: true
noHl: false
lineNumbersInTable: false
noClasses: false
guessSyntax: true
tableOfContents:
startLevel: 2
endLevel: 3
minify:
tdewolff:
html:
keepComments: true
sitemap:
changefreq: weekly
module:
hugoVersion:
min: '0.119.0'
extended: true
mounts:
- source: content
target: content
- source: static
target: static
- source: layouts
target: layouts
- source: data
target: data
- source: assets
target: assets
- source: i18n
target: i18n
- source: archetypes
target: archetypes
security:
funcs:
getenv:
- ^HUGO_
- ^WC_
params:
locale:
date_format: 'Jan 2, 2006'
time_format: '3:04 PM'
address_format: en-us
+28
View File
@@ -0,0 +1,28 @@
# Wowchemy Icon Library
# Socials
github: <svg fill="currentColor" viewBox="3 3 18 18"><path d="M12 3C7.0275 3 3 7.12937 3 12.2276C3 16.3109 5.57625 19.7597 9.15374 20.9824C9.60374 21.0631 9.77249 20.7863 9.77249 20.5441C9.77249 20.3249 9.76125 19.5982 9.76125 18.8254C7.5 19.2522 6.915 18.2602 6.735 17.7412C6.63375 17.4759 6.19499 16.6569 5.8125 16.4378C5.4975 16.2647 5.0475 15.838 5.80124 15.8264C6.51 15.8149 7.01625 16.4954 7.18499 16.7723C7.99499 18.1679 9.28875 17.7758 9.80625 17.5335C9.885 16.9337 10.1212 16.53 10.38 16.2993C8.3775 16.0687 6.285 15.2728 6.285 11.7432C6.285 10.7397 6.63375 9.9092 7.20749 9.26326C7.1175 9.03257 6.8025 8.08674 7.2975 6.81794C7.2975 6.81794 8.05125 6.57571 9.77249 7.76377C10.4925 7.55615 11.2575 7.45234 12.0225 7.45234C12.7875 7.45234 13.5525 7.55615 14.2725 7.76377C15.9937 6.56418 16.7475 6.81794 16.7475 6.81794C17.2424 8.08674 16.9275 9.03257 16.8375 9.26326C17.4113 9.9092 17.76 10.7281 17.76 11.7432C17.76 15.2843 15.6563 16.0687 13.6537 16.2993C13.98 16.5877 14.2613 17.1414 14.2613 18.0065C14.2613 19.2407 14.25 20.2326 14.25 20.5441C14.25 20.7863 14.4188 21.0746 14.8688 20.9824C16.6554 20.364 18.2079 19.1866 19.3078 17.6162C20.4077 16.0457 20.9995 14.1611 21 12.2276C21 7.12937 16.9725 3 12 3Z"></path></svg>
instagram: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 15"><path fill="currentColor" fill-rule="evenodd" d="M12.91 12.909c.326-.327.582-.72.749-1.151c.16-.414.27-.886.302-1.578c.032-.693.04-.915.04-2.68c0-1.765-.008-1.987-.04-2.68c-.032-.692-.142-1.164-.302-1.578a3.185 3.185 0 0 0-.75-1.151a3.187 3.187 0 0 0-1.151-.75c-.414-.16-.886-.27-1.578-.302C9.487 1.007 9.265 1 7.5 1c-1.765 0-1.987.007-2.68.04c-.692.03-1.164.14-1.578.301a3.2 3.2 0 0 0-1.151.75a3.2 3.2 0 0 0-.75 1.151c-.16.414-.27.886-.302 1.578C1.007 5.513 1 5.735 1 7.5c0 1.765.007 1.987.04 2.68c.03.692.14 1.164.301 1.578c.164.434.42.826.75 1.151c.325.33.718.586 1.151.75c.414.16.886.27 1.578.302c.693.031.915.039 2.68.039c1.765 0 1.987-.008 2.68-.04c.692-.03 1.164-.14 1.578-.301a3.323 3.323 0 0 0 1.151-.75ZM2 6.735v1.53c-.002.821-.002 1.034.02 1.5c.026.586.058 1.016.156 1.34c.094.312.199.63.543 1.012c.344.383.675.556 1.097.684c.423.127.954.154 1.415.175c.522.024.73.024 1.826.024H8.24c.842.001 1.054.002 1.526-.02c.585-.027 1.015-.059 1.34-.156c.311-.094.629-.2 1.011-.543c.383-.344.556-.676.684-1.098c.127-.422.155-.953.176-1.414C13 9.247 13 9.04 13 7.947v-.89c0-1.096 0-1.303-.023-1.826c-.021-.461-.049-.992-.176-1.414c-.127-.423-.3-.754-.684-1.098c-.383-.344-.7-.449-1.011-.543c-.325-.097-.755-.13-1.34-.156A27.29 27.29 0 0 0 8.24 2H7.057c-1.096 0-1.304 0-1.826.023c-.461.021-.992.049-1.415.176c-.422.128-.753.301-1.097.684c-.344.383-.45.7-.543 1.012c-.098.324-.13.754-.156 1.34c-.022.466-.022.679-.02 1.5ZM7.5 5.25a2.25 2.25 0 1 0 0 4.5a2.25 2.25 0 0 0 0-4.5ZM4.25 7.5a3.25 3.25 0 1 1 6.5 0a3.25 3.25 0 0 1-6.5 0Zm6.72-2.72a.75.75 0 1 0 0-1.5a.75.75 0 0 0 0 1.5Z" clip-rule="evenodd"/></svg>
facebook: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M22 12c0-5.52-4.48-10-10-10S2 6.48 2 12c0 4.84 3.44 8.87 8 9.8V15H8v-3h2V9.5C10 7.57 11.57 6 13.5 6H16v3h-2c-.55 0-1 .45-1 1v2h3v3h-3v6.95c5.05-.5 9-4.76 9-9.95z"/></svg>
discord: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"></path></svg>
twitter: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"></path></svg>
mastodon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"></path></svg>
youtube: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M8.051 1.999h.089c.822.003 4.987.033 6.11.335a2.01 2.01 0 0 1 1.415 1.42c.101.38.172.883.22 1.402l.01.104l.022.26l.008.104c.065.914.073 1.77.074 1.957v.075c-.001.194-.01 1.108-.082 2.06l-.008.105l-.009.104c-.05.572-.124 1.14-.235 1.558a2.007 2.007 0 0 1-1.415 1.42c-1.16.312-5.569.334-6.18.335h-.142c-.309 0-1.587-.006-2.927-.052l-.17-.006l-.087-.004l-.171-.007l-.171-.007c-1.11-.049-2.167-.128-2.654-.26a2.007 2.007 0 0 1-1.415-1.419c-.111-.417-.185-.986-.235-1.558L.09 9.82l-.008-.104A31.4 31.4 0 0 1 0 7.68v-.123c.002-.215.01-.958.064-1.778l.007-.103l.003-.052l.008-.104l.022-.26l.01-.104c.048-.519.119-1.023.22-1.402a2.007 2.007 0 0 1 1.415-1.42c.487-.13 1.544-.21 2.654-.26l.17-.007l.172-.006l.086-.003l.171-.007A99.788 99.788 0 0 1 7.858 2h.193zM6.4 5.209v4.818l4.157-2.408L6.4 5.209z"/></svg>
x: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z"/></svg>
linkedin: <svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 448 512"><path fill="currentColor" d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/></svg>
cv: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" style="stroke-width:.07717" d="M249.18 328.324c-9.788 15.384-19.179 30.434-40.222 45.055-11.256 7.89-37.164 23.306-73.99 23.306C64.709 396.685 8 345.605 8 255.801c0-78.486 53.345-140.486 128.466-140.486 30.434 0 57.474 10.521 77.387 26.304 18.414 14.65 27.038 29.304 34.563 42.456l-52.58 26.273c-3.762-8.626-8.29-17.649-19.913-27.406-12.784-10.155-25.54-13.152-36.46-13.152-42.821 0-65.364 39.825-65.364 84.145 0 58.238 29.7 87.143 65.364 87.143 34.563 0 48.48-24.042 57.474-39.426l52.243 26.673zm184.194-204.75H504l-92.037 265.22h-67.597l-90.904-265.22h70.625l54.843 188.6z"/></svg>
# Academic
graduation-cap: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M4.26 10.147a60.436 60.436 0 00-.491 6.347A48.627 48.627 0 0112 20.904a48.627 48.627 0 018.232-4.41 60.46 60.46 0 00-.491-6.347m-15.482 0a50.57 50.57 0 00-2.658-.813A59.905 59.905 0 0112 3.493a59.902 59.902 0 0110.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.697 50.697 0 0112 13.489a50.702 50.702 0 017.74-3.342M6.75 15a.75.75 0 100-1.5.75.75 0 000 1.5zm0 0v-3.675A55.378 55.378 0 0112 8.443m-7.007 11.55A5.981 5.981 0 006.75 15.75v-1.5" />
</svg>
# Email
send: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5" />
</svg>
# Blogging
rss: <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12.75 19.5v-.75a7.5 7.5 0 00-7.5-7.5H4.5m0-6.75h.75c7.87 0 14.25 6.38 14.25 14.25v.75M6 18.75a.75.75 0 11-1.5 0 .75.75 0 011.5 0z" />
</svg>
@@ -0,0 +1,82 @@
# Page Sharer
# Documentation: https://wowchemy.com/docs/customization/#page-sharer
[[buttons]]
id = "twitter"
url = "https://twitter.com/intent/tweet?url={url}&text={title}"
title = "Twitter"
icon_pack = "fab"
icon = "twitter"
enable = true
[[buttons]]
id = "facebook"
url = "https://www.facebook.com/sharer.php?u={url}&t={title}"
title = "Facebook"
icon_pack = "fab"
icon = "facebook"
enable = true
[[buttons]]
id = "email"
url = "mailto:?subject={title}&body={url}"
title = "Email"
icon_pack = "fas"
icon = "envelope"
enable = true
[[buttons]]
id = "linkedin"
url = "https://www.linkedin.com/shareArticle?url={url}&title={title}"
title = "LinkedIn"
icon_pack = "fab"
icon = "linkedin-in"
enable = true
[[buttons]]
id = "whatsapp"
url = "whatsapp://send?text={title}%20{url}"
title = "WhatsApp"
icon_pack = "fab"
icon = "whatsapp"
enable = true
[[buttons]]
id = "weibo"
url = "https://service.weibo.com/share/share.php?url={url}&title={title}"
title = "Weibo"
icon_pack = "fab"
icon = "weibo"
enable = true
[[buttons]]
id = "reddit"
url = "https://reddit.com/submit?url={url}&title={title}"
title = "Reddit"
icon_pack = "fab"
icon = "reddit-alien"
enable = false
[[buttons]]
id = "pinterest"
url = "https://pinterest.com/pin/create/link/?url={url}&description={title}"
title = "Pinterest"
icon_pack = "fab"
icon = "pinterest"
enable = false
[[buttons]]
id = "xing"
url = "https://www.xing.com/spi/shares/new?url={url}&title={title}"
title = "Xing"
icon_pack = "fab"
icon = "xing"
enable = false
[[buttons]]
id = "tumblr"
url = "https://www.tumblr.com/widgets/share/tool?canonicalUrl={url}&title={title}"
title = "Tumblr"
icon_pack = "fab"
icon = "tumblr"
enable = false
+3
View File
@@ -0,0 +1,3 @@
module github.com/wowchemy/wowchemy-hugo-themes/modules/wowchemy-tailwind
go 1.19
@@ -0,0 +1,18 @@
<!doctype html>
{{ "<!-- This site was created with Wowchemy. https://www.wowchemy.com -->" | safeHTML }}
{{ printf "<!-- Last Published: %s -->" (now | time.Format ":date_long") | safeHTML }}
{{- $language_code := site.LanguageCode | default "en-us" -}}
<html lang="{{$language_code}}" {{ if in site.Data.i18n.rtl.rtl $language_code }}dir="rtl"{{end}}>
{{ partial "site_head" . }}
<body class="dark:bg-gray-800 dark:text-white-800 page-wrapper">
<div class="page-header">
{{ partial "navbar" . }}
</div>
<div class="page-body my-10">
{{ block "main" . }}{{ end }}
</div>
<div class="page-footer">
{{ partial "site_footer" . }}
</div>
</body>
</html>
@@ -0,0 +1,38 @@
{{ define "main" }}
<div class="flex justify-center">
<article class="container prose prose-slate lg:prose-xl dark:prose-invert">
<h1 class="lg:text-6xl">{{ .Title }}</h1>
{{ .Content }}
</article>
</div>
<div class="container max-w-[65ch] mx-auto bg-white dark:bg-slate-900 rounded-xl shadow-md overflow-hidden my-5"><!--max-w-md md:max-w-2xl-->
{{ range .Pages.ByDate.Reverse }}
{{ $resource := partial "functions/get_featured_image.html" . }}
{{ $anchor := .Params.image.focal_point | default "Center" }}
<a href="{{ .RelPermalink }}">
<div class="md:flex">
<div class="md:flex-shrink-0">
{{ with $resource }}
{{ $image := .Fill (printf "655x655 %s" $anchor) }}
{{ if ne $image.MediaType.SubType "gif" }}{{ $image = $image.Process "webp" }}{{ end }}
<img class="h-48 w-full object-cover md:w-48" loading="lazy" src="{{ $image.RelPermalink }}" height="{{ $image.Height }}" width="{{ $image.Width }}" alt="{{ .Title | plainify }}">
{{end}}
</div>
<div class="p-8">
<div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">{{ .Title }}</div>
<p class="block mt-1 text-md leading-tight font-medium text-black dark:text-white">
{{ (.Params.summary | default .Summary) | plainify | htmlUnescape | chomp -}}
</p>
<p class="mt-2 text-gray-500 dark:text-gray-400">
{{- .Date | time.Format (site.Params.locale.date_format | default ":date_long") -}}
</p>
</div>
</div>
</a>
{{ end }}
</div>
{{ end }}
@@ -0,0 +1,39 @@
{{- /* Generate RSS v2 with full page content. */ -}}
{{- /* Upstream Hugo bug - RSS dates can be in future: https://github.com/gohugoio/hugo/issues/3918 */ -}}
{{- $page_context := cond .IsHome site . -}}
{{- $pages := $page_context.RegularPages -}}
{{- $limit := site.Config.Services.RSS.Limit -}}
{{- if ge $limit 1 -}}
{{- $pages = $pages | first $limit -}}
{{- end -}}
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>" | safeHTML }}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ if ne .Title site.Title }}{{ with .Title }}{{.}} | {{ end }}{{end}}{{ site.Title }}</title>
<link>{{ .Permalink }}</link>
{{- with .OutputFormats.Get "RSS" }}
{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
{{ end -}}
<description>{{ .Title | default site.Title }}</description>
<generator>Wowchemy (https://wowchemy.com)</generator>
{{- with site.LanguageCode }}<language>{{.}}</language>{{end -}}
{{- with site.Copyright }}<copyright>{{ replace (replace . "{year}" now.Year) "&copy;" "©" | plainify }}</copyright>{{end -}}
{{- if not .Date.IsZero }}<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end -}}
{{- if .Scratch.Get "og_image" }}
<image>
<url>{{ .Scratch.Get "og_image" }}</url>
<title>{{ .Title | default site.Title }}</title>
<link>{{ .Permalink }}</link>
</image>
{{end -}}
{{ range $pages }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
<guid>{{ .Permalink }}</guid>
<description>{{ .Content | html }}</description>
</item>
{{ end }}
</channel>
</rss>
@@ -0,0 +1,38 @@
{{ define "main" }}
<div class="flex justify-center">
<article class="container prose prose-slate lg:prose-xl dark:prose-invert">
<h1 class="lg:text-6xl">{{ .Title }}</h1>
{{ .Content }}
</article>
</div>
<div class="container max-w-[65ch] mx-auto bg-white dark:bg-slate-900 rounded-xl shadow-md overflow-hidden my-5"><!--max-w-md md:max-w-2xl-->
{{ range .Pages.ByDate.Reverse }}
{{ $resource := partial "functions/get_featured_image.html" . }}
{{ $anchor := .Params.image.focal_point | default "Center" }}
<a href="{{ .RelPermalink }}">
<div class="md:flex">
<div class="md:flex-shrink-0">
{{ with $resource }}
{{ $image := .Fill (printf "655x655 %s" $anchor) }}
{{ if ne $image.MediaType.SubType "gif" }}{{ $image = $image.Process "webp" }}{{ end }}
<img class="h-48 w-full object-cover md:w-48" loading="lazy" src="{{ $image.RelPermalink }}" height="{{ $image.Height }}" width="{{ $image.Width }}" alt="{{ .Title | plainify }}">
{{end}}
</div>
<div class="p-8">
<div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">{{ .Title }}</div>
<p class="block mt-1 text-md leading-tight font-medium text-black dark:text-white">
{{ (.Params.summary | default .Summary) | plainify | htmlUnescape | chomp -}}
</p>
<p class="mt-2 text-gray-500 dark:text-gray-400">
{{- .Date | time.Format (site.Params.dateFormat | default ":date_long") -}}
</p>
</div>
</div>
</a>
{{ end }}
</div>
{{ end }}
@@ -0,0 +1,44 @@
{{ define "main" }}
<div class="flex flex-col justify-center">
<article class="container mx-auto prose prose-slate lg:prose-xl dark:prose-invert">
<h1 class="lg:text-6xl">{{ .Title }}</h1>
{{ $featured := partial "functions/get_featured_image.html" . }}
{{/* Featured image layout */}}
{{ if and $featured (not .Params.image.preview_only) }}
{{/* Fit image within max size. */}}
{{ $image := $featured }}
{{/* Determine image placement. */}}
{{ $placement := .Params.image.placement | default 1 }}{{/* Default to full column width. */}}
{{/* Fit image to container's max width */}}
{{ $image_container := "" }}
{{ if eq $placement 2}}
{{ $image_container = "container" }}
{{ $image = $featured.Fit "1200x2500" }}
{{else if eq $placement 3}}
{{ $image_container = "container-fluid" }}
{{ $image := $featured.Fit "2560x2560" }}
{{else}}
{{ $image_container = "article-container" }}
{{ $image = $featured.Fit "720x2500" }}
{{end}}
{{ if ne $image.MediaType.SubType "gif" }}{{ $image = $image.Process "webp" }}{{ end }}
{{/* Featured image */}}
<div class="article-header {{$image_container}} featured-image-wrapper mt-4 mb-4" style="max-width: {{$image.Width}}px; max-height: {{$image.Height}}px;">
<div style="position: relative">
<img src="{{ $image.RelPermalink }}" width="{{ $image.Width }}" height="{{ $image.Height }}" alt="{{ with $.Params.image.alt_text }}{{.}}{{ end }}" class="featured-image">
{{ with $.Params.image.caption }}<span class="article-header-caption">{{ . | markdownify | emojify }}</span>{{ end }}
</div>
</div>
{{end}}
{{ .Content }}
</article>
<div class="container mx-auto prose prose-slate lg:prose-xl dark:prose-invert mt-5">
{{ partial "page_footer" . }}
</div>
</div>
{{ end }}
@@ -0,0 +1,16 @@
{{- define "main" -}}
{{/* Check that user fully installed Wowchemy. */}}
{{/* Commented out to allow user to have no params.yaml and just use the defaults. */}}
{{/* if not (isset site.Params "seo") */}}
{{/* errorf "Please complete the installation of Wowchemy by following the steps at https://university.wowchemy.com/" */}}
{{/* end */}}
{{/* Deprecation warnings */}}
{{/* Add here... */}}
{{/* Generate homepage. */}}
{{/* if eq .Type "landing" */}}{{/* Uncomment check once support other content types on homepage. */}}
{{ partial "landing_page.html" . }}
{{- end -}}
@@ -0,0 +1,88 @@
{{/* Wowchemy Blocks: About - avatar variation */}}
{{/* Documentation: https://wowchemy.com/blocks/ */}}
{{/* License: https://github.com/wowchemy/wowchemy-hugo-themes/blob/main/LICENSE.md */}}
{{/* Initialise */}}
{{ $page := .wcPage }}
{{ $block := .wcBlock }}
{{ $author := $block.content.username | default "admin" }}
{{ $person_page_path := (printf "/authors/%s" $author) }}
{{ $person_page := site.GetPage $person_page_path }}
{{ if not $person_page }}
{{ errorf "Could not find an author page at `%s`. Please check the value of `author` in your About widget and create an associated author page if one does not already exist. See https://wowchemy.com/docs/page-builder/#about " $person_page_path }}
{{end}}
{{ $person := $person_page.Params }}
{{ $avatar := ($person_page.Resources.ByType "image").GetMatch "*avatar*" }}
{{ $avatar_shape := site.Params.features.avatar.shape | default "circle" }}
<div id="profile" class="flex justify-center items-center flex-col">
{{ if $avatar }}
<div class="avatar-wrapper">
{{ $avatar_image := $avatar.Fill "150x150 Center" }}
<img class="avatar rounded-full {{if eq $avatar_shape "square"}}avatar-square{{else}}avatar-circle{{end}}" src="{{ $avatar_image.RelPermalink }}" alt="{{$person_page.Title}}"
width="{{ $avatar_image.Width }}" height="{{ $avatar_image.Height }}">
{{with $person.status.icon}}<span class="avatar-emoji">{{.|emojify}}</span>{{end}}
</div>
{{ end }}
<div class="portrait-title">
<h2>
{{- if $person.name_pronunciation -}}
<ruby>
<rb>{{ $person_page.Title }}</rb>
<rt>{{ $person.name_pronunciation }}</rt>
</ruby>
{{- else -}}
{{- $person_page.Title -}}
{{- end -}}
</h2>
{{ with $person.role }}<h3>{{ . | markdownify | emojify }}</h3>{{ end }}
{{ range $person.organizations }}
<h3>
{{ with .url }}<a href="{{ . }}" target="_blank" rel="noopener">{{ end }}
<span>{{ .name }}</span>
{{ if .url }}</a>{{ end }}
</h3>
{{ end }}
</div>
<ul class="network-icon">
{{ range $person.social }}
{{ $pack := or .icon_pack "fas" }}
{{ $pack_prefix := $pack }}
{{ if in (slice "fab" "fas" "far" "fal") $pack }}
{{ $pack_prefix = "fa" }}
{{ end }}
{{ $link := .link }}
{{ $scheme := (urls.Parse $link).Scheme }}
{{ $target := "" }}
{{ if not $scheme }}
{{ $link = .link | relLangURL }}
{{ if eq (path.Ext $link) ".pdf" }}{{ $target = "target=\"_blank\" rel=\"noopener\"" }}{{ end }}
{{ else if in (slice "http" "https") $scheme }}
{{ $target = "target=\"_blank\" rel=\"noopener\"" }}
{{ end }}
<li>
<a href="{{ $link | safeURL }}" {{ $target | safeHTMLAttr }} aria-label="{{ .icon }}"
{{ with .label }} data-toggle="tooltip" data-placement="top" title="{{.}}"{{ end }}>
{{ partial "functions/get_icon" (dict "name" .icon "attributes" "height=1.5rem") }}
</a>
</li>
{{ end }}
</ul>
{{ with ($block.content.text | emojify | $page.RenderString) | default $person_page.Content }}
<div class="pt-2 d-flex justify-content-center prose prose-slate lg:prose-xl dark:prose-invert">
<div class="bio-text">
{{ . }}
</div>
</div>
{{ end }}
</div>
@@ -0,0 +1,123 @@
{{/* Wowchemy Blocks: Collection */}}
{{/* Documentation: https://wowchemy.com/blocks/ */}}
{{/* License: https://github.com/wowchemy/wowchemy-hugo-themes/blob/main/LICENSE.md */}}
{{/* Initialise */}}
{{ $page := .wcPage }}
{{ $block := .wcBlock }}
{{ $items_offset := $block.content.offset | default 0 }}
{{ $items_count := $block.content.count }}
{{ if eq $items_count 0 }}
{{ $items_count = 65535 }}
{{ else }}
{{ $items_count = $items_count | default 5 }}
{{ end }}
{{/* Query */}}
{{ $query := site.RegularPages }}
{{ $archive_page := "" }}
{{/* Filters */}}
{{ if $block.content.page_type }}
{{ $query = where $query "Type" $block.content.page_type }}
{{ $archive_page = site.GetPage "Section" $block.content.page_type }}
{{ end }}
{{ if $block.content.filters.folders }}
{{ $folders := $block.content.filters.folders }}
{{ $query = where $query "Section" "in" $folders }}
{{/* Init archive page to main folder */}}
{{ $main_folder := index $folders 0 }}
{{ $archive_page = site.GetPage "Section" $main_folder }}
{{ end }}
{{ if $block.content.filters.tag }}
{{ $archive_page = site.GetPage (printf "tags/%s" (urlize $block.content.filters.tag)) }}
{{ $query = $query | intersect $archive_page.Pages }}
{{ end }}
{{ if $block.content.filters.category }}
{{ $archive_page = site.GetPage (printf "categories/%s" (urlize $block.content.filters.category)) }}
{{ $query = $query | intersect $archive_page.Pages }}
{{ end }}
{{ if $block.content.filters.publication_type }}
{{ $archive_page = site.GetPage (printf "publication_types/%s" $block.content.filters.publication_type) }}
{{ $query = $query | intersect $archive_page.Pages }}
{{ end }}
{{ if $block.content.filters.author }}
{{ $archive_page = site.GetPage (printf "authors/%s" (urlize $block.content.filters.author)) }}
{{ $query = $query | intersect $archive_page.Pages }}
{{ end }}
{{ if $block.content.filters.featured_only }}
{{ $query = where $query "Params.featured" "==" true }}
{{ end }}
{{ if $block.content.filters.exclude_featured }}
{{ $query = where $query "Params.featured" "!=" true }}
{{ end }}
{{ if $block.content.filters.exclude_past }}
{{ $query = where $query "Date" ">=" now }}
{{ end }}
{{ if $block.content.filters.exclude_future }}
{{ $query = where $query "Date" "<" now }}
{{ end }}
{{ $count := len $query }}
{{/* Sort */}}
{{ $sort_by := $block.content.sort_by | default "Date" }}
{{ $sort_by = partial "functions/get_sort_by_parameter" $sort_by }}
{{ $sort_ascending := $block.content.sort_ascending | default (eq $block.content.order "asc") | default false }}
{{ $sort_order := cond $sort_ascending "asc" "desc" }}
{{ $query = sort $query $sort_by $sort_order }}
{{/* Offset and Limit */}}
{{ if gt $items_offset 0 }}
{{ $query = first $items_count (after $items_offset $query) }}
{{ else }}
{{ $query = first $items_count $query }}
{{ end }}
{{ $columns := $block.design.columns | default "2" }}
<div class="container max-w-[65ch] mx-auto bg-white dark:bg-slate-900 rounded-xl shadow-md overflow-hidden my-5"><!--max-w-md md:max-w-2xl-->
{{ with $block.content.text }}{{ . | emojify | $page.RenderString }}{{ end }}
{{ range $index, $item := $query }}
{{ partial "functions/render_view" (dict "page" $block "item" . "view" ($block.design.view | default "card") "index" $index) }}
{{end}}
{{/* Archive link */}}
{{ $show_archive_link := $block.content.archive.enable | default (gt $count $items_count) }}
{{ if $show_archive_link | and $archive_page }}
{{ $archive_link := "" }}
{{ if $block.content.archive.link }}
{{ $archive_link = $block.content.archive.link | relLangURL }}
{{ else }}
{{ $archive_link = $archive_page.RelPermalink }}
{{ end }}
{{/* Localisation */}}
{{ $items_type := $archive_page.Type }}
{{ $i18n := "" }}
{{ if eq $items_type "post" }}
{{ $i18n = "more_posts" }}
{{ else if eq $items_type "event" }}
{{ $i18n = "more_talks" }}
{{ else if eq $items_type "publication" }}
{{ $i18n = "more_publications" }}
{{ else }}
{{ $i18n = "more_pages" }}
{{ end }}
{{ $archive_text := $block.content.archive.text | default (i18n $i18n) | default "See all" }}
<div class="see-all">
<a href="{{ $archive_link }}">
{{ $archive_text | emojify }}
<i class="fas fa-angle-right"></i>
</a>
</div>
{{ end }}
</div>
@@ -0,0 +1,17 @@
{{ $provider := trim (site.Params.features.comment.provider | lower) " " }}
{{ if $provider }}
{{ $provider_tpl := printf "partials/comments/%s.html" $provider }}
{{ $provider_exists := templates.Exists $provider_tpl }}
{{ if not $provider_exists }}
{{ errorf "The '%s' comment provider was not found." $provider }}
{{ end }}
{{ $commentable_page := .Params.commentable }}
{{ if $commentable_page }}
<section id="comments">
{{ partial $provider_tpl . }}
</section>
{{ end }}
{{ end }}
@@ -0,0 +1,3 @@
<div id="commento"></div>
{{ $url := (printf "%s/js/commento.js" (site.Params.features.comment.commento.url | default "https://cdn.commento.io")) }}
<script src="{{$url}}" defer></script>
@@ -0,0 +1,22 @@
{{ if site.Params.features.comment.disqus.shortname }}
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
{{with .Params.disqus_identifier }}this.page.identifier = '{{ . }}';{{end}}
{{with .Params.disqus_title }}this.page.title = '{{ . }}';{{end}}
{{with .Params.disqus_url }}this.page.url = '{{ . | html }}';{{end}}
};
(function() {
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;
}
var d = document, s = d.createElement('script'); s.async = true;
s.src = 'https://' + {{site.Params.features.comment.disqus.shortname}} + '.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="https://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
{{end}}
@@ -0,0 +1,19 @@
{{ if site.Params.features.comment.giscus }}
{{ $config := site.Params.features.comment.giscus }}
<script src="https://giscus.app/client.js"
data-repo="{{$config.repo}}"
data-repo-id="{{$config.repo_id}}"
data-category="{{$config.category}}"
data-category-id="{{$config.category_id}}"
data-mapping="{{ $config.mapping | default "pathname" }}"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="top"
data-theme="{{ $config.theme | default "preferred_color_scheme" }}"
data-lang="{{ $config.language_code | default "en" }}"
data-loading="lazy"
crossorigin="anonymous"
async>
</script>
{{ end }}
@@ -0,0 +1,26 @@
{{ if ne .Params.share false }}
<div class="share-box">
<ul class="share">
{{ range where site.Data.page_sharer.buttons "enable" true }}
{{ $pack := or .icon_pack "fas" }}
{{ $pack_prefix := $pack }}
{{ if in (slice "fab" "fas" "far" "fal") $pack }}
{{ $pack_prefix = "fa" }}
{{ end }}
{{/* Utilise `urlquery` over `htmlEscape` to encode sharing URL */}}
{{/* See https://github.com/wowchemy/wowchemy-hugo-themes/pull/2726 */}}
{{ $link := replace .url "{url}" ($.Permalink | urlquery) }}
{{ $link = replace $link "{title}" ($.Title | urlquery) }}
{{/* Workaround `urlquery` encoding for mailto as `urlquery` encodes `+` as `%2B` and ` ` (space) as `+` */}}
{{ if eq (urls.Parse $link).Scheme "mailto" }}
{{ $link = replace $link "+" "%20" }}
{{ end }}
<li>
<a href="{{$link|safeURL}}" target="_blank" rel="noopener" class="share-btn-{{.id}}" aria-label="{{.icon}}">
<i class="{{$pack}} {{$pack_prefix}}-{{.icon}}"></i>
</a>
</li>
{{ end }}
</ul>
</div>
{{ end }}
@@ -0,0 +1,18 @@
{{ $str := "" }}
<div class="post-nav">
{{if .NextInSection}}
{{/* For the Book layout, prev/next labels are reversed. */}}
{{ if in (slice "docs" "book") .Type }}{{ $str = "previous" }}{{else}}{{ $str = "next" }}{{end}}
<div class="post-nav-item">
<div class="meta-nav">{{ i18n $str }}</div>
<a href="{{.NextInSection.RelPermalink}}" rel="next">{{.NextInSection.Title}}</a>
</div>
{{end}}
{{if .PrevInSection}}
{{ if in (slice "docs" "book") .Type }}{{ $str = "next" }}{{else}}{{ $str = "previous" }}{{end}}
<div class="post-nav-item">
<div class="meta-nav">{{ i18n $str }}</div>
<a href="{{.PrevInSection.RelPermalink}}" rel="prev">{{.PrevInSection.Title}}</a>
</div>
{{end}}
</div>
@@ -0,0 +1,26 @@
{{/* Get name of primary author. */}}
{{ $page := . }}
{{/* Get publisher as fall back. */}}
{{ $publisher := site.Params.marketing.seo.org_name | default site.Title }}
{{ $author := "" }}
{{ $author_username := "" }}
{{ if and (not $page.Params.authors) ($page.Scratch.Get "superuser_username") }}
{{ $author_username = $page.Scratch.Get "superuser_username" }}
{{ else if $page.Params.authors }}
{{ $author = index $page.Params.authors 0 }}
{{ $author_username = urlize $author }}
{{ end }}
{{ $taxonomy := "authors" }}
{{ $profile_page := site.GetPage (printf "/%s/%s" $taxonomy $author_username) }}
{{ with $profile_page }}
{{ $author = .Title }}
{{ else }}
{{ $author = $author | default $publisher }}
{{ end }}
{{ return $author }}
@@ -0,0 +1,23 @@
{{/* Function to retrieve the featured image */}}
{{/* Inputs: page context */}}
{{/* Output: image resource, or nil if not found */}}
{{/*
Featured image is searched in this order:
1. Search for a file `*featured*` in the post directory
2. Search for a file `.Params.image.filename` in the post directory
3. Search for a file `.Params.image.filename` in the `assets/media/` directory
*/}}
{{/* Search for an image "*featured*" in post folder */}}
{{ $resource := (.Resources.ByType "image").GetMatch "*featured*" }}
{{ if eq $resource nil }}
{{/* Otherwise fall back the image file specified in front matter */}}
{{ $filename := .Params.image.filename }}
{{/* Search in post folder */}}
{{ $resource = (.Resources.ByType "image").GetMatch $filename }}
{{/* Otherwise in `assets/media/` folder */}}
{{ if eq $resource nil }} {{ $resource = resources.GetMatch (path.Join "media" $filename) }} {{ end }}
{{ end }}
{{ return $resource }}
@@ -0,0 +1,19 @@
{{/* Function to inject custom code into layouts without overriding files. */}}
{{/* Input: hook folder name (str) */}}
{{/* Output: loaded (bool) */}}
{{ $loaded := false }}
{{ $partial_dir := printf "hooks/%s/" .hook }}
{{ $context := .context }}
{{ $hook_dir_path := path.Join "layouts/partials" $partial_dir }}
{{ if fileExists $hook_dir_path }}
{{ range os.ReadDir $hook_dir_path }}
{{ if not .IsDir }}
{{ $partial_path := path.Join $partial_dir .Name }}
{{ partial $partial_path $context }}
{{ $loaded = true }}
{{ end }}
{{ end }}
{{ end }}
{{/* The return statement below is for debug purposes only and prevents the above partial(s) being included in the page */}}
{{/* return $loaded */}}
@@ -0,0 +1,18 @@
{{/* Return the requested SVG icon */}}
{{/* Search for the icon in the Wowchemy icon library, falling back to user's icon library */}}
{{- $icon := index site.Data.icons .name -}}
{{ if not $icon }}
{{ with resources.GetMatch (printf "media/icons/%s.svg" .name) }}
{{ $icon = .Content }}
{{else}}
{{ warnf "The icon `%s.svg` was not found in your `assets/media/icons/` folder" .name }}
{{ end }}
{{ end }}
{{ if .attributes }}
{{ $icon = replaceRE "<svg" (printf "<svg %s" .attributes) $icon }}
{{ end }}
{{- return ($icon | safeHTML) -}}
@@ -0,0 +1,21 @@
{{/* Function to get logo image. */}}
{{/* Inputs: constraint: max_height/fit (str); size (int) */}}
{{/* Output: resource (obj) */}}
{{/* Workaround fact Hugo does not support GetMatch in assets dir */}}
{{/* Hugo doesn't support image ops on SVG: https://discourse.gohugo.io/t/ho-do-i-convert-a-generic-resource-to-image-resource/22570/4 */}}
{{ $logo := resources.Get "media/logo.png" | default (resources.Get "media/logo.svg") }}
{{ $logo_proc := $logo }}
{{/* If the type of image can be resized by Hugo, resize it given a `.size` argument to the function. */}}
{{ if resources.Get "media/logo.png" }}
{{ if eq .constraint "max_height" }}
{{/* Resize logo to fit specified max height. */}}
{{ $logo_proc = ($logo.Resize (printf "x%s" (string .size))) }}
{{ else }}
{{/* Constrain logo to fit within specified dimensions. */}}
{{ $logo_proc = ($logo.Fit (printf "%sx%s" (string .size) (string .size))) }}
{{ end }}
{{ end }}
{{ return $logo_proc }}
@@ -0,0 +1,12 @@
{{/* Function to get logo URL for JSONLD. */}}
{{/* Inputs: page context */}}
{{/* Output: logo URL (URL) */}}
{{ $logo_url := "" }}
{{ if resources.Get "media/logo.png" | or (resources.Get "media/logo.svg") }}
{{ $logo_url = (partial "functions/get_logo" (dict "constraint" "fit" "size" 192)).Permalink }}
{{ else }}
{{ $logo_url = (partial "functions/get_site_icon" 192).Permalink }}
{{ end }}
{{ return $logo_url }}
@@ -0,0 +1,8 @@
{{ $title := "" }}
{{ with .Params.seo.title }}
{{ $title = replace . "{brand}" site.Title }}
{{ else }}
{{ $title = .Title | default site.Title }}
{{ if ne $title site.Title }}{{ $title = printf "%s | %s" $title site.Title }}{{ end }}
{{ end }}
{{ return $title }}
@@ -0,0 +1,7 @@
{{/* Function to get website icon image. */}}
{{/* Input: size (int) */}}
{{/* Output: resource (obj) */}}
{{ $icon := resources.GetMatch "media/icon.png" }}
{{ $icon_resized := $icon.Fill (printf "%sx%s Center" (string .) (string .)) }}
{{ return $icon_resized }}
@@ -0,0 +1,24 @@
{{/* Uniform 'sort_by' parameter between built-in Hugo and Wowchemy ones */}}
{{/* Input: 'sort_by' parameter (string) */}}
{{/* Output: fixed 'sort_by' parameter (string) */}}
{{/*
Fix the 'sort_by' parameter, by adding "Params." as prefix if it is not a built-in Hugo parameter.
Since Wowchemy parameters are all standardised to lowercase-underscore convention, we:
- remove any leading ".": ".Date" is the same as "Date"
- check the first letter:
- if it is capitalized, then we have a built-in Hugo parameter, and we do nothing
- otherwise, it is a custom Wowchemy parameter, and we add "Params." as prefix
This logic should also be backward compatible, since "Params.my_param" is not modified.
*/}}
{{ $param := strings.TrimLeft "." . }}
{{/* Get first letter */}}
{{ $first := substr $param 0 }}
{{/* Check if it is lowercase */}}
{{ if eq $first (lower $first) }}
{{/* Add 'Params.' prefix */}}
{{ $param = printf "Params.%s" $param }}
{{ end }}
{{ return $param }}
@@ -0,0 +1,148 @@
{{/* Wowchemy Block Parser v2 */}}
{{/* Documentation: https://wowchemy.com/blocks/ */}}
{{/* License: https://github.com/wowchemy/wowchemy-hugo-themes/blob/main/LICENSE.md */}}
{{ $page := .page }}
{{ $block := .block }}
{{ $block_type := lower $block.block | default "markdown" }}
{{ $block_path := printf "blocks/%s.html" $block_type }}
{{ if not (templates.Exists (printf "partials/%s" $block_path)) }}
{{ errorf "%s uses a `%s` block but the `%s` block was not found at `layouts/partials/%s`" $block.File.Path $block_type $block_type $block_path }}
{{ end }}
{{/* Mermaid block: Workaround to make Hugo's .Page.Store.Set cascade up to the parent of headless pages */}}
{{ if $block.Page.Store.Get "has_mermaid" }}
{{ $page.Page.Store.Set "has_mermaid" true }}
{{ end }}
{{/* Gallery block: Workaround to make Hugo's .Page.Store.Set cascade up from page blocks to the page context */}}
{{/* Unfortunately, `.HasShortcode "gallery"` won't accept string input, only page context - so irrelevant here */}}
{{/* Therefore, must do our own search for shortcodes within the `text` string */}}
{{ if (gt (len (findRE `\{\{< gallery` $block.content.text 1)) 0) }}
{{ $page.Page.Store.Set "has_gallery" true }}
{{ end }}
{{/* Begin widget styling */}}
{{ $bg := $block.design.background }}
{{ $style := "" }}
{{ $style_bg := "" }}
{{ if $bg.color }}
{{ $style_bg = printf "background-color: %s;" ($bg.color | default "transparent") }}
{{ end }}
{{ if and $bg.gradient_start $bg.gradient_end }}
{{ $angle := string $bg.gradient_angle | default "90" }}
{{ $style_bg = printf "%sbackground-image: linear-gradient(%sdeg, %s, %s);" $style_bg $angle $bg.gradient_start $bg.gradient_end }}
{{ end }}
{{ $bg_video := "" }}
{{ $bg_video_class := "" }}
{{ if $bg.video.filename }}
{{ $bg_video = resources.Get (printf "media/%s" $bg.video.filename) }}
{{ if $bg.video.flip }}
{{ $bg_video_class = "flip" }}
{{ end }}
{{ end }}
{{ if $bg.image.filename }}
{{/* See Hugo note on linking assets in styles: https://github.com/gohugoio/hugoThemes#common-permalink-issues */}}
{{ $bg_img := resources.Get (printf "media/%s" $bg.image.filename) }}
{{ if $bg_img }}
{{/* Exception for SVG as Hugo doesn't yet support image processing on SVG. */}}
{{ if ne $bg_img.MediaType.SubType "svg" }}
{{ $bg_img = $bg_img.Fit "1920x1920 webp" }}
{{ end }}
{{ $style_bg = printf "%sbackground-image: url('%s');" $style_bg $bg_img.Permalink }}
{{ else }}
{{ errorf "Couldn't find `%s` in the `assets/media/` folder - please add it." $bg.image.filename }}
{{ end }}
{{ with $bg.image.size }}
{{/* Allow sizes: actual, cover, and contain. */}}
{{ $style_bg = printf "%sbackground-size: %s;" $style_bg (replace . "actual" "auto") }}
{{ end }}
{{ with $bg.image.position }}
{{/* Allow valid CSS positions including left, center, and right. */}}
{{ $style_bg = printf "%sbackground-position: %s;" $style_bg . }}
{{ end }}
{{ end }}
{{ with $bg.image.filters.brightness }}
{{ $style_bg = printf "%sfilter: brightness(%s);" $style_bg (string .) }}
{{ end }}
{{ with $block.design.spacing.padding }}
{{ $style_pad := printf "padding: %s;" (delimit . " ") }}
{{ $style = print $style $style_pad }}
{{ end }}
{{/* Support for clip path (design.clip_path) */}}
{{ with $block.design.clip_path }}
{{ $style_clip_path := printf "clip-path: %s;" . }}
{{ $style = print $style $style_clip_path }}
{{ end }}
{{ with $block.design.css_style }}
{{ $style = print $style . }}
{{ end }}
{{/* Fix Hugo's ContentBaseName returning wrong file base name when page section is within a bundle. */}}
{{ $hash_id := $block.id | default (printf "section-%s" (replace $block_type "." "-")) }}
{{ $widget_args := dict "wcPage" $page "wcBlock" $block "wcIdentifier" $hash_id }}
{{ $css_classes := $block.design.css_class | default "" }}
{{ $extra_attributes := "" }}
{{ $use_container := true }}
{{ $columns := $block.design.columns | default "1" }}
{{/* $use_cols := in (slice "collection" "experience" "accomplishments" "contact" "markdown" "tag_cloud" "portfolio" "skills") $block_type */}}
{{ $use_cols := false }}
{{/* Special case: Slider widget. */}}
{{ if in (slice "slider") $block_type }}
{{ $css_classes = print $css_classes " carousel slide" }}
{{ $extra_attributes = printf "data-ride=\"carousel\" data-interval=\"%s\"" (cond ($block.design.loop | default true) (string $block.design.interval | default "3000") "false") }}
{{ $use_container = false }}
{{ end }}
{{ $widget_class := printf "wg-%s" (replace (replace $block_type "." "-") "_" "-") }}
{{ $widget_config_file := printf "blocks/%s-config.html" $block_type }}
{{ if templates.Exists (printf "partials/%s" $widget_config_file) }}
{{ $cfg := partial $widget_config_file $widget_args }}
{{ with $cfg.use_container }}{{ $use_container = . }}{{ end }}
{{ with $cfg.inject_section_heading }}{{ $use_cols = . }}{{ end }}
{{end}}
{{/* Dedicated child div for bg prevents parallax 100% height issue within new CSS grid page wrapper. */}}
<section id="{{$hash_id}}" class="home-section {{$widget_class}} {{if $bg.text_color_light}}dark{{else if (eq $bg.text_color_light false)}}light{{end}} {{with $css_classes}}{{.}}{{end}}" {{with $style}}style="{{. | safeCSS}}"{{end}} {{print $extra_attributes | safeHTMLAttr}}>
<div class="home-section-bg {{if $bg.image}} bg-image{{if ($bg.image.parallax | default true) }} parallax{{end}}{{end}}" {{with $style_bg}}style="{{. | safeCSS}}"{{end}}>
{{with $bg_video}}<video class="bg-video {{$bg_video_class}}" playsinline="" preload="auto" loop="" muted autoplay="" tabindex="-1" width="100%" height="100%" src="{{.RelPermalink}}" style="width: 100%; height: 100%; object-fit: cover; object-position: center center; opacity: 1;"></video>{{end}}
</div>
{{if $use_container}}<div class="container mx-auto">{{end}}
{{if $use_cols}}
<div class="row {{if not $block.content.title | or (eq $columns "1") }}justify-content-center{{end}}">
{{ if $block.content.title }}
{{ if eq $columns "1" }}
<div class="section-heading col-12 mb-3 text-center">
{{ with $block.content.title }}<h1 class="mb-0">{{ . | markdownify | emojify }}</h1>{{ end }}
{{ with $block.content.subtitle }}<p class="mt-1">{{ . | markdownify | emojify }}</p>{{ end }}
</div>
{{else}}
<div class="section-heading col-12 col-lg-4 mb-3 mb-lg-0 d-flex flex-column align-items-center align-items-lg-start">
{{ with $block.content.title }}<h1 class="mb-0">{{ . | markdownify | emojify }}</h1>{{ end }}
{{ with $block.content.subtitle }}<p class="mt-1">{{ . | markdownify | emojify }}</p>{{ end }}
</div>
{{end}}
{{end}}
{{end}}
{{ partial $block_path $widget_args }}
{{if $use_cols}}
</div>
{{end}}
{{if $use_container}}</div>{{end}}
</section>
@@ -0,0 +1,20 @@
{{/* Wowchemy content preview renderer */}}
{{ $page := .page }}
{{ $item := .item }}
{{ $view := .view }}
{{ $view_file := "" }}
{{ $view_dtype := printf "%T" $view }}
{{ $index := .index }}
{{ if templates.Exists (printf "partials/views/%s.html" (lower $view)) }}
{{ $view_file = lower $view }}
{{else}}
{{/* Fallback to card view */}}
{{ warnf "Failed to locate view at `partials/views/%s.html`. Check you specified a supported `view` in `%s`" $view $page.File.Path }}
{{ $view_file = "card" }}
{{end}}
{{ return (partial (printf "views/%s" $view_file) (dict "page" $page "item" $item "index" $index)) }}
@@ -0,0 +1,47 @@
{{- $page := .page }}
{{ $summary := .summary }}
{{ $featured_image := ($page.Resources.ByType "image").GetMatch "*featured*" }}
{{/* Get schema type. */}}
{{ $schema := "Article" }}
{{ if eq $page.Type "post" }}
{{ $schema = "BlogPosting" }}
{{ end }}
{{ $author := partial "functions/get_author_name" $page }}
{{ $publisher := site.Params.marketing.seo.org_name | default site.Title }}
{{ $logo_url := partial "functions/get_logo_url" $page -}}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": {{$schema}},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": {{$page.Permalink}}
},
"headline": {{$page.Title}},
{{ if $featured_image }}
"image": [
{{$featured_image.Permalink}}
],
{{end}}
"datePublished": {{ $page.PublishDate.Format "2006-01-02T15:04:05Z07:00" }},
"dateModified": {{ $page.Lastmod.Format "2006-01-02T15:04:05Z07:00" }},
{{with $author}}
"author": {
"@type": "Person",
"name": {{.}}
},
{{end}}
"publisher": {
"@type": "Organization",
"name": {{$publisher}},
"logo": {
"@type": "ImageObject",
"url": {{$logo_url}}
}
},
"description": {{$summary}}
}
</script>
@@ -0,0 +1,30 @@
{{- $sharing_image := resources.GetMatch (path.Join "media" "sharing.*") -}}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": {{site.Params.marketing.seo.site_type | default site.Params.marketing.seo.site_type}},
"@id": {{site.BaseURL}},
"name": {{site.Params.marketing.seo.org_name | default site.Title}},
"logo": {{ partial "functions/get_logo_url" . }},
{{with $sharing_image}}"image": {{.Permalink}},{{end}}
{{ if (eq site.Params.marketing.seo.site_type "LocalBusiness") | and site.Params.marketing.seo.coordinates }}
"geo": {
"@type": "GeoCoordinates",
"latitude": {{site.Params.marketing.seo.coordinates.latitude}},
"longitude": {{site.Params.marketing.seo.coordinates.longitude}}
},
{{end}}
{{ with site.Params.marketing.seo.address }}
"address": {
"@type": "PostalAddress",
"streetAddress": {{ .street | default "" }},
"addressLocality": {{ .city | default "" }},
"addressRegion": {{ .region | default "" }},
"postalCode": {{ .postcode | default "" }},
"addressCountry": {{ .country_code | default .country | default "" }}
},
{{end}}
{{ with site.Params.marketing.seo.phone }}"telephone": {{.}},{{end}}
"url": {{site.BaseURL}}
}
</script>
@@ -0,0 +1,47 @@
{{ $page := .page }}
{{ $summary := .summary }}
{{ $featured_image := ($page.Resources.ByType "image").GetMatch "*featured*" }}
{{ $author := partial "functions/get_author_name" $page }}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Event",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": {{$page.Permalink}}
},
"name": {{$page.Title}},
{{ with $page.Params.location }}
"location": {
"@type": "Place",
"name": {{. | plainify}}{{if $page.Params.address}},
"address": {
"@type": "PostalAddress",
"streetAddress": {{$page.Params.address.street | default ""}},
"addressLocality": {{$page.Params.address.city | default ""}},
"postalCode": {{$page.Params.address.postcode | default ""}},
"addressRegion": {{$page.Params.address.region | default ""}},
"addressCountry": {{$page.Params.address.country | default ""}}
}
{{end}}
},
{{end}}
{{ if $featured_image }}
"image": [
{{$featured_image.Permalink}}
],
{{end}}
"startDate": {{ $page.Date.Format "2006-01-02T15:04:05Z07:00" }},
{{with $page.Params.date_end}}
"endDate": {{ (time .).Format "2006-01-02T15:04:05Z07:00" }},
{{end}}
{{with $author}}
"performer": {
"@type": "Person",
"name": {{.}}
},
{{end}}
"description": {{$summary}}
}
</script>
@@ -0,0 +1,23 @@
{{ $page := .page }}
{{ $summary := .summary }}
{{ $site_type := site.Params.marketing.seo.site_type | default "Person" }}
{{- if $page.IsHome -}}
{{ partialCached "jsonld/website.html" $page }}
{{ if ne $site_type "Person" }}
{{ partial "jsonld/business.html" $page }}
{{ end }}
{{- else if $page.IsPage -}}
{{ if (eq $page.Type "post") | or (eq $page.Type "publication") | or (eq $page.Type "project") }}
{{ partial "jsonld/article.html" (dict "page" $page "summary" $summary) }}
{{ end }}
{{ if eq $page.Type "event" }}
{{ partial "jsonld/event.html" (dict "page" $page "summary" $summary) }}
{{ end }}
{{- end }}
@@ -0,0 +1,14 @@
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
{{- if site.Params.features.search.provider }}
"potentialAction": {
"@type": "SearchAction",
"target": {{ printf "%s?q={search_term_string}" site.BaseURL }},
"query-input": "required name=search_term_string"
},
{{end -}}
"url": {{site.BaseURL}}
}
</script>
@@ -0,0 +1,7 @@
{{/* Load Wowchemy blocks */}}
{{ range $index, $block := .Params.sections }}
{{/* Do not show sections intended only for the demo site. */}}
{{ if or (not $block.demo) ($block.demo | and (eq (os.Getenv "WC_DEMO") "true")) }}
{{ partial "functions/parse_block_v2" (dict "page" $ "block" $block) }}
{{ end }}
{{ end }}
@@ -0,0 +1,13 @@
{{ $baidu_tongji := site.Params.marketing.analytics.baidu_tongji | default "" }}
{{ if hugo.IsProduction | and $baidu_tongji }}
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?{{ $baidu_tongji }}";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
{{ end }}
@@ -0,0 +1,42 @@
{{ $ga := site.Params.marketing.analytics.google_analytics | default site.GoogleAnalytics | default "" }}
{{ if hugo.IsProduction | and $ga }}
{{ $gtag_config := cond site.Params.features.privacy_pack.enable "{ 'anonymize_ip': true }" "{}" }}
<script async src="https://www.googletagmanager.com/gtag/js?id={{$ga}}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
function trackOutboundLink(url, target) {
gtag('event', 'click', {
'event_category': 'outbound',
'event_label': url,
'transport_type': 'beacon',
'event_callback': function () {
if (target !== '_blank') {
document.location = url;
}
}
});
console.debug("Outbound link clicked: " + url);
}
function onClickCallback(event) {
if ((event.target.tagName !== 'A') || (event.target.host === window.location.host)) {
return;
}
trackOutboundLink(event.target, event.target.getAttribute('target')); // Send GA event.
}
gtag('js', new Date());
gtag('config', '{{$ga}}', {{$gtag_config|safeJS}});
gtag('set', {'cookie_flags': 'SameSite=None;Secure'});
// Outbound link tracking.
document.addEventListener('click', onClickCallback, false);
</script>
{{ end }}
@@ -0,0 +1,10 @@
{{ $gt := site.Params.marketing.analytics.google_tag_manager | default "" }}
{{ if hugo.IsProduction | and $gt }}
<script>
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','{{$gt}}');
</script>
{{ end }}
@@ -0,0 +1,10 @@
{{ $clarity := site.Params.marketing.analytics.microsoft_clarity | default "" }}
{{ if hugo.IsProduction | and $clarity }}
<script>
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", '{{$clarity}}');
</script>
{{ end }}
@@ -0,0 +1,90 @@
<!-- Main navigation container -->
<nav
class="relative flex w-full flex-nowrap items-center justify-between bg-white py-2 text-neutral-500 shadow-lg hover:text-neutral-700 focus:text-neutral-700 dark:bg-slate-900 lg:flex-wrap lg:justify-start lg:py-4"
data-te-navbar-ref>
<div class="flex w-full flex-wrap items-center justify-between px-3">
<!-- Hamburger button for mobile view -->
<button
class="block border-0 bg-transparent px-2 text-neutral-500 hover:no-underline hover:shadow-none focus:no-underline focus:shadow-none focus:outline-none focus:ring-0 dark:text-neutral-200 lg:hidden"
type="button"
data-te-collapse-init
data-te-target="#collapse-main-navbar"
aria-controls="collapse-main-navbar"
aria-expanded="false"
aria-label="Toggle navigation" onclick="toggleNavbar('collapse-main-navbar')">
<!-- Hamburger icon -->
<span class="[&>svg]:w-7">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="h-7 w-7">
<path
fill-rule="evenodd"
d="M3 6.75A.75.75 0 013.75 6h16.5a.75.75 0 010 1.5H3.75A.75.75 0 013 6.75zM3 12a.75.75 0 01.75-.75h16.5a.75.75 0 010 1.5H3.75A.75.75 0 013 12zm0 5.25a.75.75 0 01.75-.75h16.5a.75.75 0 010 1.5H3.75a.75.75 0 01-.75-.75z"
clip-rule="evenodd" />
</svg>
</span>
</button>
<!-- Collapsible navbar container -->
<div
class="!visible mt-2 hidden flex-grow basis-[100%] items-center justify-center lg:mt-0 lg:!flex lg:basis-auto"
id="collapse-main-navbar"
data-te-collapse-item>
<!-- Main links -->
{{- $currentPage := . }}
<ul
class="list-style-none flex flex-col pl-0 lg:mt-1 lg:flex-row"
data-te-navbar-nav-ref>
{{- range site.Menus.main }}
{{- $menu_item_url := (cond (strings.HasSuffix .URL "/") .URL (printf "%s/" .URL) ) | absLangURL }}
{{- $page_url:= $currentPage.Permalink | absLangURL }}
{{- $active := eq $menu_item_url $page_url -}}
{{- $activeClass := cond $active "active" "" -}}
<!-- Home link [&.active]:text-bold [&.active]:text-black/90 dark:[&.active]:text-neutral-300-->
<li
class="my-4 pl-2 lg:my-0 lg:pl-2 lg:pr-1"
data-te-nav-item-ref>
<a
class=" lg:px-2 text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200
[&.active]:font-bold [&.active]:text-black/90 dark:[&.active]:text-white {{ $activeClass }}"
aria-current="page"
href="{{ .URL | relLangURL }}"
data-te-nav-link-ref
>{{- .Name -}}</a
>
</li>
{{ end }}
<li>
<button class="theme-toggle mt-1" accesskey="t" title="">
<svg id="moon" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="dark:hidden">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
<svg id="sun" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24"
fill="none" stroke="white" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class=" dark:block [&:not(dark)]:hidden">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</button>
</li>
</ul>
</div>
</div>
</nav>
<script>
function toggleNavbar(collapseID){
document.getElementById(collapseID).classList.toggle("hidden");
document.getElementById(collapseID).classList.toggle("flex");
}
</script>
@@ -0,0 +1,19 @@
{{/* Author profile box */}}
{{/* Don't show author box on normal pages or if author box disabled. */}}
{{ if ne .Type "page" | and (not (or (eq site.Params.profile false) (eq .Params.profile false))) }}
{{/* Display superuser if superuser exists and page authors are not explicitly specified. */}}
{{/* Otherwise, display first author if a profile for them exists. */}}
{{ if and (not .Params.authors) (.Scratch.Get "superuser_username") }}
{{ $author_page := site.GetPage (printf "/%s/%s" "authors" (.Scratch.Get "superuser_username")) }}
{{ partial "page_author_card" (dict "author_page" $author_page) }}
{{ else if .Params.authors }}
{{ $taxonomy := "authors" }}
{{ range $author_obj := (.GetTerms $taxonomy) }}
{{ partial "page_author_card" (dict "author_page" $author_obj.Page) }}
{{ end }}
{{ end }}
{{end}}{{/* Show profile block */}}
@@ -0,0 +1,30 @@
{{ $page := .page }}
{{ $author_page := .author_page }}
{{ $site_type := site.Params.marketing.seo.site_type | default "Person" }}
{{- $has_profile := not (eq nil $author_page.Params.superuser) -}}
{{/* Check an author profile exists. */}}
{{ if $has_profile }}
{{/* If it's a personal site and primary page author is superuser, link to the homepage rather than their profile page. */}}
{{ $profile_url := $author_page.RelPermalink }}
{{ if and (eq $site_type "Person") (eq $author_page.Params.superuser true) }}
{{ $profile_url = site.BaseURL }}
{{ end }}
{{ $avatar := ($author_page.Resources.ByType "image").GetMatch "*avatar*" }}
{{ $avatar_shape := site.Params.features.avatar.shape | default "circle" }}
<div class="media author-card content-widget-hr">
{{ if and site.Params.features.avatar.gravatar $author_page.Params.email }}
{{if $profile_url}}<a href="{{$profile_url}}">{{end}}<img class="avatar mr-3 {{if eq $avatar_shape "square"}}avatar-square{{else}}avatar-circle{{end}}" src="https://s.gravatar.com/avatar/{{ md5 $author_page.Params.email }}?s=200" alt="{{$author_page.Title}}">{{if $profile_url}}</a>{{end}}
{{ else if $avatar }}
{{ $avatar_image := $avatar.Fill "270x270 Center" }}
{{if $profile_url}}<a href="{{$profile_url}}">{{end}}<img class="avatar mr-3 {{if eq $avatar_shape "square"}}avatar-square{{else}}avatar-circle{{end}}" src="{{ $avatar_image.RelPermalink }}" alt="{{$author_page.Title}}">{{if $profile_url}}</a>{{end}}
{{ end }}
<div class="media-body">
<h5 class="card-title">{{if $profile_url}}<a href="{{$profile_url}}">{{end}}{{$author_page.Title}}{{if $profile_url}}</a>{{end}}</h5>
{{ with $author_page.Params.role }}<h6 class="card-subtitle">{{. | markdownify | emojify}}</h6>{{end}}
{{ with $author_page.Params.bio }}<p class="card-text">{{. | markdownify | emojify}}</p>{{end}}
{{ partial "social_links" $author_page }}
</div>
</div>
{{end}}{{/* Profile page block */}}
@@ -0,0 +1,18 @@
{{/* Add link to let visitors edit the page on GitHub. */}}
{{/* Perform short-circuit check that page is backed by a file. */}}
{{ if and .File .Params.editable | and site.Params.features.repository.url }}
{{/* Get language subfolder for multilingual sites. */}}
{{/* Limitations: the subfolder param, `<LANG>.contentDir`, is unexposed in the Hugo `site` API so we attempt to workaround this issue. */}}
{{ $content_dir := "content" }}
{{ if site.Params.features.repository.content_dir }}
{{ $content_dir = site.Params.features.repository.content_dir }}
{{else}}
{{/* Attempt to get content dir from the LanguagePrefix URI, but defaultContentLanguageInSubdir can break this assumption. */}}
{{ $content_dir = cond site.IsMultiLingual (cond (ne .Site.LanguagePrefix "") (printf "%s%s" $content_dir .Site.LanguagePrefix) $content_dir) $content_dir }}
{{end}}
<p class="edit-page">
<a href="{{site.Params.features.repository.url}}/edit/{{site.Params.features.repository.branch | default "main"}}/{{$content_dir}}/{{.File.Path}}">
📝 {{ i18n "edit_page" | default "Edit this page" }}
</a>
</p>
{{ end }}
@@ -0,0 +1,13 @@
{{ partial "page_edit" . }}
{{ partial "tags" . }}
{{/* partial "components/page_sharer" . */}}
{{/* partial "page_author" . */}}
{{ partial "comments" . }}
{{ if .Params.pager }}
<div class="article-widget">
{{/* partial "components/pager" . */}}
</div>
{{ end }}
{{/* partial "page_related" . */}}
@@ -0,0 +1,14 @@
{{/* Show related/recommended content. */}}
{{ if .Params.show_related }}
{{ $related := site.RegularPages.Related . | first 5 }}
{{ with $related }}
<div class="article-widget content-widget-hr">
<h3>{{ i18n "related" }}</h3>
<ul>
{{ range . }}
<li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
{{ end }}
</ul>
</div>
{{ end }}
{{ end }}
@@ -0,0 +1,39 @@
<footer class="text-sm leading-6 mt-12 mb-4 text-slate-700 flex justify-center dark:text-slate-200">
{{ partial "functions/get_hook" (dict "hook" "footer-start" "context" .) }}
{{ if or (site.GetPage "/terms.md") (site.GetPage "/privacy.md") }}
<p>
{{ with site.GetPage "/privacy.md" }}
{{ printf "<a href=\"%s\">%s</a>" .RelPermalink .Title | safeHTML }}
{{ end }}
{{ with site.GetPage "/terms.md" }}
{{ if site.GetPage "/privacy.md" }} &middot; {{ end }}
{{ printf "<a href=\"%s\">%s</a>" .RelPermalink .Title | safeHTML }}
{{ end }}
</p>
{{ end }}
{{ with site.Params.footer.text }}
<p>
{{ . | markdownify | emojify }}
</p>
{{ end }}
<p>
{{ $is_sponsor := site.Params.i_am_a_sponsor | default false }}
{{ $hide_published_with_footer := site.Params.power_ups.hide_published_with | default true }}
{{ if not (and $is_sponsor $hide_published_with_footer) }}
{{ $default := "Published with {wowchemy} — the free, {repo_link}open source{/repo_link} website builder that empowers creators." }}
{{ $i18n_published_with := i18n "published_with" | default $default }}
{{ if not (findRE "{wowchemy}" $i18n_published_with) }}
{{ warnf "Please attribute Wowchemy using `{wowchemy}` in the `published_with` text." }}
{{ $i18n_published_with = $default }}
{{ end }}
{{ $i18n_published_with = replace $i18n_published_with "{wowchemy}" "<a href=\"https://wowchemy.com/?utm_campaign=poweredby\" target=\"_blank\" rel=\"noopener\">Wowchemy</a>" | safeHTML }}
{{ $i18n_published_with = replace $i18n_published_with "{repo_link}" "<a href=\"https://github.com/wowchemy/wowchemy-hugo-themes\" target=\"_blank\" rel=\"noopener\">" | safeHTML }}
{{ $i18n_published_with = replace $i18n_published_with "{/repo_link}" "</a>" | safeHTML }}
{{ $i18n_published_with | markdownify | emojify | safeHTML }}
{{ end }}
</p>
</footer>
@@ -0,0 +1,292 @@
{{ $scr := .Scratch }}
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="generator" content="Wowchemy {{ site.Data.wowchemy.version }} for Hugo" />
{{/* EXTENSIBILITY HOOK: HEAD-START */}}
{{ partial "functions/get_hook" (dict "hook" "head-start" "context" .) }}
{{ if .Params.private }}
<meta name="robots" content="noindex" />
{{- end -}}
{{/* Attempt to load superuser. */}}
{{ $superuser_name := "" }}
{{ $superuser_username := "" }}
{{ $superuser_role := "" }}
{{ range first 1 (where (where site.Pages "Section" "authors") "Params.superuser" true) }}
{{ $superuser_name = .Title }}
{{ $superuser_username = path.Base .File.Dir }}
{{ $superuser_role = .Params.role }}
{{ end }}
{{ $scr.Set "superuser_username" $superuser_username }}{{/* Set superuser globally for page_author.html. */}}
{{ with $superuser_name }}<meta name="author" content="{{ . }}" />{{ end }}
{{/* Generate page description. */}}
{{ $desc := "" }}
{{ if .Params.summary }}
{{ $desc = .Params.summary }}
{{ else if .Params.abstract }}
{{ $desc = .Params.abstract }}
{{ else if .IsPage }}
{{ $desc = .Summary }}
{{ else if site.Params.marketing.seo.description }}
{{ $desc = site.Params.marketing.seo.description }}
{{ else }}
{{ $desc = $superuser_role }}
{{ end }}
<meta name="description" content="{{ $desc }}" />
{{ range .Translations }}
<link rel="alternate" hreflang="{{ .Lang }}" href="{{ .Permalink }}" />
{{ end }}
<link rel="alternate" hreflang="{{ site.LanguageCode | default "en-us" }}" href="{{ .Permalink }}" />
{{/* Style */}}
{{ if hugo.IsProduction }}
{{ $styles := resources.Get "dist/wc.css" }}
<link href="{{ $styles.RelPermalink }}" rel="stylesheet" />
{{ else }}
{{ $options := dict "inlineImports" true }}
{{ $styles := resources.Get "css/styles.css" }}
{{ $styles = $styles | resources.PostCSS $options }}
{{ if hugo.IsProduction }}
{{ $styles = $styles | minify | fingerprint | resources.PostProcess }}
{{ end }}
<link href="{{ $styles.RelPermalink }}" rel="stylesheet" />
{{ end }}
<script>
/* Light/dark mode */
const defaultMode = 'system';
const setDarkMode = () => {
document.documentElement.classList.add("dark");
document.documentElement.style.colorScheme = "dark";
}
const setLightMode = () => {
document.documentElement.classList.remove("dark");
document.documentElement.style.colorScheme = "light";
}
if ("wc-color-theme" in localStorage) {
localStorage.getItem("wc-color-theme") === "dark" ? setDarkMode() : setLightMode();
} else {
defaultMode === "dark" ? setDarkMode() : setLightMode();
if (defaultMode === "system") {
window.matchMedia("(prefers-color-scheme: dark)").matches ? setDarkMode() : setLightMode();
}
}
document.addEventListener('DOMContentLoaded', function () {
const defaultMode = 'system'
const themeToggleButtons = document.querySelectorAll(".theme-toggle");
// Check previous theme settings or system theme, and update current theme button appropriately
if (
localStorage.getItem("wc-color-theme") === "dark" ||
(!("wc-color-theme" in localStorage) &&
((window.matchMedia("(prefers-color-scheme: dark)").matches && defaultMode === "system") || defaultMode === "dark"))
) {
themeToggleButtons.forEach((el) => el.dataset.theme = "dark");
} else {
themeToggleButtons.forEach((el) => el.dataset.theme = "light");
}
// Add click event handler to the light/dark buttons
themeToggleButtons.forEach((el) => {
el.addEventListener("click", function () {
console.debug('Theme toggled');
if (localStorage.getItem("wc-color-theme")) {
if (localStorage.getItem("wc-color-theme") === "light") {
setDarkMode();
localStorage.setItem("wc-color-theme", "dark");
} else {
setLightMode();
localStorage.setItem("wc-color-theme", "light");
}
} else {
if (document.documentElement.classList.contains("dark")) {
setLightMode();
localStorage.setItem("wc-color-theme", "light");
} else {
setDarkMode();
localStorage.setItem("wc-color-theme", "dark");
}
}
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light";
});
});
// Listen for system color theme changes
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
if (defaultMode === "system" && !("wc-color-theme" in localStorage)) {
e.matches ? setDarkMode() : setLightMode();
themeToggleButtons.forEach((el) =>
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light"
);
}
});
});
</script>
<script>
document.addEventListener('DOMContentLoaded', function () {
// Fix Hugo task list style
let checkboxes = document.querySelectorAll('li input[type=\'checkbox\'][disabled]');
checkboxes.forEach(e => {
e.parentElement.parentElement.classList.add('task-list');
});
// Fix Hugo missing <label> around checkbox and its text (fixes Lighthouse accessibility errors)
const liNodes = document.querySelectorAll('.task-list li');
liNodes.forEach(nodes => {
let textNodes = Array.from(nodes.childNodes).filter(node => node.nodeType === 3 && node.textContent.trim().length > 1);
if (textNodes.length > 0) {
const span = document.createElement('label');
textNodes[0].after(span); // Use first text node as label
span.appendChild(nodes.querySelector('input[type=\'checkbox\']'));
span.appendChild(textNodes[0]);
}
});
});
</script>
{{/* Config LaTeX math rendering. */}}
{{ if or .Params.math site.Params.features.math.enable }}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css" integrity="sha384-Xi8rHCmBmhbuyyhbI88391ZKP2dmfnOl4rT9ZfRI7mLTdk1wblIUnrIq35nqwEvC" crossorigin="anonymous" media="print" onload="this.media='all'">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.js" integrity="sha384-X/XCfMm41VSsqRNQgDerQczD69XqmjOOOwYQvr/uuC+j4OPoNhVgjdGFwhvN02Ja" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/contrib/auto-render.min.js" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
// Add support for inline math with `$...$`
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false},
{left: '\\(', right: '\\)', display: false},
{left: '\\[', right: '\\]', display: true}
],
throwOnError: false
});
});
</script>
{{ end }}
{{/* Hugo Chroma Syntax Highlighter Initialization */}}
{{/* TODO: optimize to only include the Chroma CSS themes when the page has code blocks. */}}
{{ $hl_theme_light := site.Params.features.syntax_highlighter.theme_light | default "github-light" }}
{{ $hl_theme_dark := site.Params.features.syntax_highlighter.theme_dark | default "dracula" }}
{{ $hl_theme_light_path := printf "css/libs/chroma/%s.css" $hl_theme_light }}
{{ $hl_theme_dark_path := printf "css/libs/chroma/%s.css" $hl_theme_dark }}
{{ if not (fileExists (printf "assets/%s" $hl_theme_light_path)) | or (not (fileExists (printf "assets/%s" $hl_theme_dark_path))) }}
{{ errorf "Hugo Chroma themes %s.css and %s.css not found in `css/libs/chroma/`. See https://gohugo.io/commands/hugo_gen_chromastyles/" $hl_theme_light $hl_theme_dark }}
{{ else }}
{{ $hl_theme_light_css := resources.Get $hl_theme_light_path | minify }}
{{ $hl_theme_dark_css := resources.Get $hl_theme_dark_path | minify }}
<link rel="stylesheet" href="{{ $hl_theme_light_css.RelPermalink }}" title="hl-light" media="print" onload="this.media='all'" {{ if ne ($scr.Get "light") true }}disabled{{end}}>
<link rel="stylesheet" href="{{ $hl_theme_dark_css.RelPermalink }}" title="hl-dark" media="print" onload="this.media='all'" {{ if eq ($scr.Get "light") true }}disabled{{end}}>
{{ end }}
{{/* Marketing */}}
{{ with site.Params.marketing.verification.google }}
<meta name="google-site-verification" content="{{ . }}" />
{{- end -}}
{{ with site.Params.marketing.verification.baidu }}
<meta name="baidu-site-verification" content="{{ . }}" />
{{- end -}}
{{ with site.Params.marketing.verification.bing }}
<meta name="msvalidate.01" content="{{ . }}" />
{{- end -}}
{{ partial "marketing/google_analytics" . }}
{{ partial "marketing/google_tag_manager" . }}
{{ partial "marketing/microsoft_clarity" . }}
{{ partial "marketing/baidu_tongji" . }}
{{/* RSS Feed */}}
{{ with .OutputFormats.Get "RSS" }}
<link rel="alternate" href="{{ .RelPermalink }}" type="application/rss+xml" title="{{ site.Title }}" />
{{ end }}
{{/* Progressive Web App (PWA) Icon */}}
<link rel="icon" type="image/png" href="{{ (partial "functions/get_site_icon" 32).RelPermalink }}" />
<link rel="apple-touch-icon" type="image/png" href="{{ (partial "functions/get_site_icon" 180).RelPermalink }}" />
<link rel="canonical" href="{{ .Permalink }}" />
{{/* Get page image for sharing. */}}
{{ $sharing_image := resources.GetMatch (path.Join "media" "sharing.*") }}
{{ $featured_image := (.Resources.ByType "image").GetMatch "*featured*" }}
{{ $avatar_image := (.Resources.ByType "image").GetMatch "avatar*" }}
{{ $has_logo := fileExists "assets/media/logo.png" | or (fileExists "assets/media/logo.svg") }}
{{ $og_image := "" }}
{{ $twitter_card := "summary_large_image" }}
{{ if (and (eq .Kind "term") $avatar_image) }}
{{/* Match image processing in About widget to prevent generating more images than necessary. */}}
{{ $og_image = ($avatar_image.Fill "270x270 Center").Permalink }}
{{ $twitter_card = "summary" }}
{{ else if $featured_image }}
{{ $og_image = $featured_image.Permalink }}
{{ else if $sharing_image }}
{{ $og_image = $sharing_image.Permalink }}
{{ else if $has_logo }}
{{ $og_image = (partial "functions/get_logo" (dict "constraint" "fit" "size" 300)).Permalink }}
{{ $twitter_card = "summary" }}
{{ else }}
{{ $og_image = (partial "functions/get_site_icon" 512).Permalink }}
{{ $twitter_card = "summary" }}
{{ end }}
{{ $scr.Set "og_image" $og_image }}{{/* Set `og_image` globally for `rss.xml`. */}}
{{ $title := "" }}
{{ with .Params.seo.title }}
{{ $title = replace . "{brand}" site.Title }}
{{ else }}
{{ $title = .Title | default site.Title }}
{{ if ne $title site.Title }}{{ $title = printf "%s | %s" $title site.Title }}{{ end }}
{{ end }}
<meta property="twitter:card" content="{{ $twitter_card }}" />
{{ with site.Params.marketing.seo.twitter }}
<meta property="twitter:site" content="@{{ . }}" />
<meta property="twitter:creator" content="@{{ . }}" />
{{ end }}
<meta property="og:site_name" content="{{ site.Title }}" />
<meta property="og:url" content="{{ .Permalink }}" />
<meta property="og:title" content="{{ $title }}" />
<meta property="og:description" content="{{ $desc }}" />
{{- with $og_image -}}
<meta property="og:image" content="{{ . }}" />
<meta property="twitter:image" content="{{ . }}" />
{{- end -}}
<meta property="og:locale" content="{{ site.LanguageCode | default "en-us" }}" />
{{ if .IsPage }}
{{ if not .PublishDate.IsZero }}
<meta
property="article:published_time"
content="{{ .PublishDate.Format "2006-01-02T15:04:05-07:00" | safeHTML }}"
/>
{{ else if not .Date.IsZero }}
<meta property="article:published_time" content="{{ .Date.Format "2006-01-02T15:04:05-07:00" | safeHTML }}" />
{{ end }}
{{ if not .Lastmod.IsZero }}<meta property="article:modified_time" content="{{ .Lastmod.Format "2006-01-02T15:04:05-07:00" | safeHTML }}">{{ end }}
{{ else }}
{{ if not .Date.IsZero }}
<meta property="og:updated_time" content="{{ .Date.Format "2006-01-02T15:04:05-07:00" | safeHTML }}" />
{{ end }}
{{ end }}
{{ partial "jsonld/main" (dict "page" . "summary" $desc) }}
<title>{{$title}}</title>
{{/* EXTENSIBILITY HOOK: HEAD-END */}}
{{/* Deprecated custom_head hook */}}
{{ if templates.Exists "partials/custom_head" }}
{{ partial "custom_head" . }}
{{ end }}
{{ partial "functions/get_hook" (dict "hook" "head-end" "context" .) }}
</head>
@@ -0,0 +1,22 @@
<ul class="network-icon" aria-hidden="true">
{{ range .Params.social }}
{{ $pack := or .icon_pack "fas" }}
{{ $pack_prefix := $pack }}
{{ if in (slice "fab" "fas" "far" "fal") $pack }}
{{ $pack_prefix = "fa" }}
{{ end }}
{{ $link := .link }}
{{ $scheme := (urls.Parse $link).Scheme }}
{{ $target := "" }}
{{ if not $scheme }}
{{ $link = .link | relLangURL }}
{{ else if in (slice "http" "https") $scheme }}
{{ $target = "target=\"_blank\" rel=\"noopener\"" }}
{{ end }}
<li>
<a href="{{ $link | safeURL }}" {{ $target | safeHTMLAttr }}>
<i class="{{ $pack }} {{ $pack_prefix }}-{{ .icon }}"></i>
</a>
</li>
{{end}}
</ul>
@@ -0,0 +1,8 @@
{{ $taxonomy := "tags" }}
{{ if .Param $taxonomy }}
<div class="flex justify-center">
{{ range $index, $value := (.GetTerms $taxonomy) }}
<a class="no-underline bg-blue-100 text-blue-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300" href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
{{ end }}
</div>
{{ end }}
@@ -0,0 +1,25 @@
{{ $item := .item }}
{{ $resource := partial "functions/get_featured_image.html" $item }}
{{ $anchor := $item.Params.image.focal_point | default "Center" }}
<a href="{{ $item.RelPermalink }}" class="mb-5">
<div class="md:flex">
<div class="md:flex-shrink-0">
{{ with $resource }}
{{ $image := .Fill (printf "655x655 %s" $anchor) }}
{{ if ne $image.MediaType.SubType "gif" }}{{ $image = $image.Process "webp" }}{{ end }}
<img class="h-48 w-full object-cover md:w-48" loading="lazy" src="{{ $image.RelPermalink }}" height="{{ $image.Height }}" width="{{ $image.Width }}" alt="{{ $item.Title | plainify }}">
{{end}}
</div>
<div class="p-8">
<div class="uppercase tracking-wide text-sm text-indigo-500 font-semibold">{{ $item.Title }}</div>
<p class="block mt-1 text-md leading-tight font-medium text-black dark:text-white">
{{ ($item.Params.summary | default $item.Summary) | plainify | htmlUnescape | chomp -}}
</p>
<p class="mt-2 text-gray-500 dark:text-gray-400">
{{- $item.Date | time.Format (site.Params.locale.date_format | default ":date_long") -}}
</p>
</div>
</div>
</a>
@@ -0,0 +1 @@
{{ .Inner }}
@@ -0,0 +1,40 @@
{{/* Table Shortcode for Wowchemy. */}}
{{/* Load a CSV table from page dir falling back back to remote URL */}}
{{/* Defaults to expecting a comma-separated CSV with a header row. */}}
{{ $src := .Get "path" }}
{{ $delimiter := .Get "delimiter" | default "," }}
{{ $useHeaderRow := (eq (lower (.Get "header")) "true") | default true }}
{{ $caption := .Get "caption" }}
{{ $is_remote := strings.HasPrefix $src "http" }}
{{ if not $is_remote }}
{{ $src = path.Join "content" $.Page.File.Dir $src }}
{{ end }}
{{ $rows := getCSV $delimiter $src }}
<table class="table-auto">
{{ if $useHeaderRow }}
{{ $headerRow := index $rows 0 }}
{{ $rows = after 1 $rows }}
<thead>
<tr> {{ range $headerRow }} <th>{{ . | markdownify | emojify }}</th> {{ end }} </tr>
</thead>
{{ end }}
<tbody>
{{ range $rows }}
<tr>
{{ range . }}
{{ if (findRE "^\\d+$" .) }}
<td data-table-dtype="number">{{ . }}</td>
{{ else }}
<td data-table-dtype="text">{{ . | markdownify | emojify }}</td>
{{ end }}
{{ end }}
</tr>
{{ end }}
</tbody>
{{ if $caption }}
<caption class="table-caption">{{ $caption | markdownify | emojify }}</caption>
{{ end }}
</table>
+29
View File
@@ -0,0 +1,29 @@
{
"comments": {
"dependencies": {},
"devDependencies": {
"@tailwindcss/typography": "project",
"autoprefixer": "project",
"postcss": "project",
"postcss-cli": "project",
"postcss-purgecss": "project",
"tailwindcss": "project"
}
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.4",
"autoprefixer": "^10.4.8",
"postcss": "^8.4.16",
"postcss-cli": "^10.0.0",
"postcss-import": "^14.1.0",
"postcss-purgecss": "^2.0.3",
"tailwindcss": "^3.1.8"
},
"license": "MIT",
"name": "wowchemy-tailwind",
"repository": {
"type": "git",
"url": "https://github.com/wowchemy/wowchemy-hugo-themes.git"
},
"version": "0.1.0"
}
@@ -0,0 +1,9 @@
let tailwindConfig = process.env.HUGO_FILE_TAILWIND_CONFIG_JS || './tailwind.config.js';
module.exports = {
plugins: {
'postcss-import': {},
tailwindcss: {config: tailwindConfig},
autoprefixer: {},
}
};
@@ -0,0 +1,10 @@
module.exports = {
content: ['./hugo_stats.json', './layouts/**/*.html'],
plugins: [
require('@tailwindcss/typography'),
],
safelist: [
'task-list',
],
darkMode: ['class']
}