diff --git a/modules/wowchemy-tailwind/README.md b/modules/wowchemy-tailwind/README.md
new file mode 100644
index 00000000..00942e1d
--- /dev/null
+++ b/modules/wowchemy-tailwind/README.md
@@ -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
+```
diff --git a/modules/wowchemy-tailwind/assets/css/blocks/about.avatar.css b/modules/wowchemy-tailwind/assets/css/blocks/about.avatar.css
new file mode 100644
index 00000000..cd43e0a6
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/blocks/about.avatar.css
@@ -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);
+}
diff --git a/modules/wowchemy-tailwind/assets/css/blocks/all.css b/modules/wowchemy-tailwind/assets/css/blocks/all.css
new file mode 100644
index 00000000..f3b50c40
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/blocks/all.css
@@ -0,0 +1 @@
+@import "about.avatar.css";
diff --git a/modules/wowchemy-tailwind/assets/css/components/all.css b/modules/wowchemy-tailwind/assets/css/components/all.css
new file mode 100644
index 00000000..40223b3a
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/components/all.css
@@ -0,0 +1,2 @@
+@import "page.css";
+@import "task-list.css";
diff --git a/modules/wowchemy-tailwind/assets/css/components/page.css b/modules/wowchemy-tailwind/assets/css/components/page.css
new file mode 100644
index 00000000..d3a64aaf
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/components/page.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;
+}
diff --git a/modules/wowchemy-tailwind/assets/css/components/task-list.css b/modules/wowchemy-tailwind/assets/css/components/task-list.css
new file mode 100644
index 00000000..553d67f1
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/components/task-list.css
@@ -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: '✅';
+}
diff --git a/modules/wowchemy-tailwind/assets/css/libs/chroma/dracula.css b/modules/wowchemy-tailwind/assets/css/libs/chroma/dracula.css
new file mode 100644
index 00000000..c19577dc
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/libs/chroma/dracula.css
@@ -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 { }
diff --git a/modules/wowchemy-tailwind/assets/css/libs/chroma/github-dark.css b/modules/wowchemy-tailwind/assets/css/libs/chroma/github-dark.css
new file mode 100644
index 00000000..77716777
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/libs/chroma/github-dark.css
@@ -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;
+}
diff --git a/modules/wowchemy-tailwind/assets/css/libs/chroma/github-light.css b/modules/wowchemy-tailwind/assets/css/libs/chroma/github-light.css
new file mode 100644
index 00000000..07ea90ab
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/libs/chroma/github-light.css
@@ -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 }
diff --git a/modules/wowchemy-tailwind/assets/css/styles.css b/modules/wowchemy-tailwind/assets/css/styles.css
new file mode 100644
index 00000000..3de89007
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/styles.css
@@ -0,0 +1,6 @@
+/* Import Tailwind */
+@import "./tailwind.css";
+
+/*!* Import Wowchemy components *!*/
+@import "./components/all.css";
+@import "./blocks/all.css";
diff --git a/modules/wowchemy-tailwind/assets/css/tailwind.css b/modules/wowchemy-tailwind/assets/css/tailwind.css
new file mode 100644
index 00000000..b5c61c95
--- /dev/null
+++ b/modules/wowchemy-tailwind/assets/css/tailwind.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/starters/notes/assets/media/icon.png b/modules/wowchemy-tailwind/assets/media/icon.png
similarity index 100%
rename from starters/notes/assets/media/icon.png
rename to modules/wowchemy-tailwind/assets/media/icon.png
diff --git a/modules/wowchemy-tailwind/config.yaml b/modules/wowchemy-tailwind/config.yaml
new file mode 100644
index 00000000..1c0d43cd
--- /dev/null
+++ b/modules/wowchemy-tailwind/config.yaml
@@ -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
diff --git a/modules/wowchemy-tailwind/data/icons.yaml b/modules/wowchemy-tailwind/data/icons.yaml
new file mode 100644
index 00000000..edb43908
--- /dev/null
+++ b/modules/wowchemy-tailwind/data/icons.yaml
@@ -0,0 +1,28 @@
+# Wowchemy Icon Library
+
+# Socials
+github:
+instagram:
+facebook:
+discord:
+twitter:
+mastodon:
+youtube:
+x:
+linkedin:
+cv:
+
+# Academic
+graduation-cap:
+
+
+
+# Email
+send:
+
+
+
+# Blogging
+rss:
+
+
diff --git a/modules/wowchemy-tailwind/data/page_sharer.toml b/modules/wowchemy-tailwind/data/page_sharer.toml
new file mode 100644
index 00000000..c890a604
--- /dev/null
+++ b/modules/wowchemy-tailwind/data/page_sharer.toml
@@ -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
diff --git a/modules/wowchemy-tailwind/go.mod b/modules/wowchemy-tailwind/go.mod
new file mode 100644
index 00000000..a00d7b46
--- /dev/null
+++ b/modules/wowchemy-tailwind/go.mod
@@ -0,0 +1,3 @@
+module github.com/wowchemy/wowchemy-hugo-themes/modules/wowchemy-tailwind
+
+go 1.19
diff --git a/modules/wowchemy-tailwind/layouts/_default/baseof.html b/modules/wowchemy-tailwind/layouts/_default/baseof.html
new file mode 100644
index 00000000..eec644de
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/_default/baseof.html
@@ -0,0 +1,18 @@
+
+{{ "" | safeHTML }}
+{{ printf "" (now | time.Format ":date_long") | safeHTML }}
+{{- $language_code := site.LanguageCode | default "en-us" -}}
+
+ {{ partial "site_head" . }}
+
+
+
+ {{ block "main" . }}{{ end }}
+
+
+
+
diff --git a/modules/wowchemy-tailwind/layouts/_default/list.html b/modules/wowchemy-tailwind/layouts/_default/list.html
new file mode 100644
index 00000000..955ef5d1
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/_default/list.html
@@ -0,0 +1,38 @@
+{{ define "main" }}
+
+
+
+ {{ .Title }}
+ {{ .Content }}
+
+
+
+
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/_default/rss.xml b/modules/wowchemy-tailwind/layouts/_default/rss.xml
new file mode 100644
index 00000000..3ac74e1b
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/_default/rss.xml
@@ -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 "" | safeHTML }}
+
+
+ {{ if ne .Title site.Title }}{{ with .Title }}{{.}} | {{ end }}{{end}}{{ site.Title }}
+ {{ .Permalink }}
+ {{- with .OutputFormats.Get "RSS" }}
+ {{ printf " " .Permalink .MediaType | safeHTML }}
+ {{ end -}}
+ {{ .Title | default site.Title }}
+ Wowchemy (https://wowchemy.com)
+ {{- with site.LanguageCode }}{{.}} {{end -}}
+ {{- with site.Copyright }}{{ replace (replace . "{year}" now.Year) "©" "©" | plainify }} {{end -}}
+ {{- if not .Date.IsZero }}{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} {{ end -}}
+ {{- if .Scratch.Get "og_image" }}
+
+ {{ .Scratch.Get "og_image" }}
+ {{ .Title | default site.Title }}
+ {{ .Permalink }}
+
+ {{end -}}
+ {{ range $pages }}
+ -
+
{{ .Title }}
+ {{ .Permalink }}
+ {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}
+ {{ .Permalink }}
+ {{ .Content | html }}
+
+ {{ end }}
+
+
diff --git a/modules/wowchemy-tailwind/layouts/_default/section.html b/modules/wowchemy-tailwind/layouts/_default/section.html
new file mode 100644
index 00000000..e00597e7
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/_default/section.html
@@ -0,0 +1,38 @@
+{{ define "main" }}
+
+
+
+ {{ .Title }}
+ {{ .Content }}
+
+
+
+
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/_default/single.html b/modules/wowchemy-tailwind/layouts/_default/single.html
new file mode 100644
index 00000000..60ad54f6
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/_default/single.html
@@ -0,0 +1,44 @@
+{{ define "main" }}
+
+
+ {{ .Title }}
+
+ {{ $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 */}}
+
+
+
+ {{ with $.Params.image.caption }}
{{ . | markdownify | emojify }} {{ end }}
+
+
+ {{end}}
+
+ {{ .Content }}
+
+
+
+ {{ partial "page_footer" . }}
+
+
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/index.html b/modules/wowchemy-tailwind/layouts/index.html
new file mode 100644
index 00000000..bfb44164
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/index.html
@@ -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 -}}
diff --git a/modules/wowchemy-tailwind/layouts/partials/blocks/about.avatar.html b/modules/wowchemy-tailwind/layouts/partials/blocks/about.avatar.html
new file mode 100644
index 00000000..b217d204
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/blocks/about.avatar.html
@@ -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" }}
+
+
+
+ {{ if $avatar }}
+
+ {{ $avatar_image := $avatar.Fill "150x150 Center" }}
+
+ {{with $person.status.icon}}
{{.|emojify}} {{end}}
+
+ {{ end }}
+
+
+
+
+ {{- if $person.name_pronunciation -}}
+
+ {{ $person_page.Title }}
+ {{ $person.name_pronunciation }}
+
+ {{- else -}}
+ {{- $person_page.Title -}}
+ {{- end -}}
+
+
+ {{ with $person.role }}
{{ . | markdownify | emojify }} {{ end }}
+
+ {{ range $person.organizations }}
+
+ {{ end }}
+
+
+
+ {{ 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 }}
+
+
+ {{ partial "functions/get_icon" (dict "name" .icon "attributes" "height=1.5rem") }}
+
+
+ {{ end }}
+
+
+ {{ with ($block.content.text | emojify | $page.RenderString) | default $person_page.Content }}
+
+ {{ end }}
+
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/blocks/collection.html b/modules/wowchemy-tailwind/layouts/partials/blocks/collection.html
new file mode 100644
index 00000000..fe8bc9fa
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/blocks/collection.html
@@ -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" }}
+
+
+
+
+ {{ 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" }}
+
+
+ {{ end }}
+
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/comments.html b/modules/wowchemy-tailwind/layouts/partials/comments.html
new file mode 100644
index 00000000..6118c163
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/comments.html
@@ -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 }}
+
+ {{ end }}
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/comments/commento.html b/modules/wowchemy-tailwind/layouts/partials/comments/commento.html
new file mode 100644
index 00000000..1c9e2d06
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/comments/commento.html
@@ -0,0 +1,3 @@
+
+{{ $url := (printf "%s/js/commento.js" (site.Params.features.comment.commento.url | default "https://cdn.commento.io")) }}
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/comments/disqus.html b/modules/wowchemy-tailwind/layouts/partials/comments/disqus.html
new file mode 100644
index 00000000..2fe6f1f3
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/comments/disqus.html
@@ -0,0 +1,22 @@
+{{ if site.Params.features.comment.disqus.shortname }}
+
+
+Please enable JavaScript to view the comments powered by Disqus.
+comments powered by
+{{end}}
diff --git a/modules/wowchemy-tailwind/layouts/partials/comments/giscus.html b/modules/wowchemy-tailwind/layouts/partials/comments/giscus.html
new file mode 100644
index 00000000..32e1d7f3
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/comments/giscus.html
@@ -0,0 +1,19 @@
+{{ if site.Params.features.comment.giscus }}
+ {{ $config := site.Params.features.comment.giscus }}
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/components/page_sharer.html b/modules/wowchemy-tailwind/layouts/partials/components/page_sharer.html
new file mode 100644
index 00000000..79f4d7e0
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/components/page_sharer.html
@@ -0,0 +1,26 @@
+{{ if ne .Params.share false }}
+
+
+ {{ 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 }}
+
+
+
+
+
+ {{ end }}
+
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/components/pager.html b/modules/wowchemy-tailwind/layouts/partials/components/pager.html
new file mode 100644
index 00000000..591b8c06
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/components/pager.html
@@ -0,0 +1,18 @@
+{{ $str := "" }}
+
+ {{if .NextInSection}}
+ {{/* For the Book layout, prev/next labels are reversed. */}}
+ {{ if in (slice "docs" "book") .Type }}{{ $str = "previous" }}{{else}}{{ $str = "next" }}{{end}}
+
+ {{end}}
+ {{if .PrevInSection}}
+ {{ if in (slice "docs" "book") .Type }}{{ $str = "next" }}{{else}}{{ $str = "previous" }}{{end}}
+
+ {{end}}
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/functions/get_author_name.html b/modules/wowchemy-tailwind/layouts/partials/functions/get_author_name.html
new file mode 100644
index 00000000..72e64cc3
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/functions/get_author_name.html
@@ -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 }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/functions/get_featured_image.html b/modules/wowchemy-tailwind/layouts/partials/functions/get_featured_image.html
new file mode 100644
index 00000000..03a02853
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/functions/get_featured_image.html
@@ -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 }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/functions/get_hook.html b/modules/wowchemy-tailwind/layouts/partials/functions/get_hook.html
new file mode 100644
index 00000000..5791dfb8
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/functions/get_hook.html
@@ -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 */}}
diff --git a/modules/wowchemy-tailwind/layouts/partials/functions/get_icon.html b/modules/wowchemy-tailwind/layouts/partials/functions/get_icon.html
new file mode 100644
index 00000000..b663a84b
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/functions/get_icon.html
@@ -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 "
+
+ {{with $bg_video}} {{end}}
+
+ {{if $use_container}}{{end}}
+
+ {{if $use_cols}}
+
+ {{ if $block.content.title }}
+ {{ if eq $columns "1" }}
+
+ {{ with $block.content.title }}
{{ . | markdownify | emojify }} {{ end }}
+ {{ with $block.content.subtitle }}
{{ . | markdownify | emojify }}
{{ end }}
+
+ {{else}}
+
+ {{ with $block.content.title }}
{{ . | markdownify | emojify }} {{ end }}
+ {{ with $block.content.subtitle }}
{{ . | markdownify | emojify }}
{{ end }}
+
+ {{end}}
+ {{end}}
+ {{end}}
+
+ {{ partial $block_path $widget_args }}
+
+ {{if $use_cols}}
+
+ {{end}}
+
+ {{if $use_container}}
{{end}}
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/functions/render_view.html b/modules/wowchemy-tailwind/layouts/partials/functions/render_view.html
new file mode 100644
index 00000000..8463735a
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/functions/render_view.html
@@ -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)) }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/jsonld/article.html b/modules/wowchemy-tailwind/layouts/partials/jsonld/article.html
new file mode 100644
index 00000000..e3c202af
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/jsonld/article.html
@@ -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 -}}
+
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/jsonld/business.html b/modules/wowchemy-tailwind/layouts/partials/jsonld/business.html
new file mode 100644
index 00000000..3e96f437
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/jsonld/business.html
@@ -0,0 +1,30 @@
+{{- $sharing_image := resources.GetMatch (path.Join "media" "sharing.*") -}}
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/jsonld/event.html b/modules/wowchemy-tailwind/layouts/partials/jsonld/event.html
new file mode 100644
index 00000000..a8189451
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/jsonld/event.html
@@ -0,0 +1,47 @@
+{{ $page := .page }}
+{{ $summary := .summary }}
+{{ $featured_image := ($page.Resources.ByType "image").GetMatch "*featured*" }}
+{{ $author := partial "functions/get_author_name" $page }}
+
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/jsonld/main.html b/modules/wowchemy-tailwind/layouts/partials/jsonld/main.html
new file mode 100644
index 00000000..4da4ea0b
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/jsonld/main.html
@@ -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 }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/jsonld/website.html b/modules/wowchemy-tailwind/layouts/partials/jsonld/website.html
new file mode 100644
index 00000000..ec84542a
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/jsonld/website.html
@@ -0,0 +1,14 @@
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/landing_page.html b/modules/wowchemy-tailwind/layouts/partials/landing_page.html
new file mode 100644
index 00000000..1bd72d7c
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/landing_page.html
@@ -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 }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/marketing/baidu_tongji.html b/modules/wowchemy-tailwind/layouts/partials/marketing/baidu_tongji.html
new file mode 100644
index 00000000..eb2a25cf
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/marketing/baidu_tongji.html
@@ -0,0 +1,13 @@
+{{ $baidu_tongji := site.Params.marketing.analytics.baidu_tongji | default "" }}
+
+{{ if hugo.IsProduction | and $baidu_tongji }}
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/marketing/google_analytics.html b/modules/wowchemy-tailwind/layouts/partials/marketing/google_analytics.html
new file mode 100644
index 00000000..91b9ca8b
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/marketing/google_analytics.html
@@ -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 }" "{}" }}
+
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/marketing/google_tag_manager.html b/modules/wowchemy-tailwind/layouts/partials/marketing/google_tag_manager.html
new file mode 100644
index 00000000..d916502a
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/marketing/google_tag_manager.html
@@ -0,0 +1,10 @@
+{{ $gt := site.Params.marketing.analytics.google_tag_manager | default "" }}
+{{ if hugo.IsProduction | and $gt }}
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/marketing/microsoft_clarity.html b/modules/wowchemy-tailwind/layouts/partials/marketing/microsoft_clarity.html
new file mode 100644
index 00000000..b49ef9a4
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/marketing/microsoft_clarity.html
@@ -0,0 +1,10 @@
+{{ $clarity := site.Params.marketing.analytics.microsoft_clarity | default "" }}
+{{ if hugo.IsProduction | and $clarity }}
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/navbar.html b/modules/wowchemy-tailwind/layouts/partials/navbar.html
new file mode 100644
index 00000000..6858a74c
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/navbar.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{- $currentPage := . }}
+
+ {{- 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" "" -}}
+
+
+ {{- .Name -}}
+
+ {{ end }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/page_author.html b/modules/wowchemy-tailwind/layouts/partials/page_author.html
new file mode 100644
index 00000000..74fa41c0
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/page_author.html
@@ -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 */}}
diff --git a/modules/wowchemy-tailwind/layouts/partials/page_author_card.html b/modules/wowchemy-tailwind/layouts/partials/page_author_card.html
new file mode 100644
index 00000000..06027aa8
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/page_author_card.html
@@ -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" }}
+
+ {{ if and site.Params.features.avatar.gravatar $author_page.Params.email }}
+ {{if $profile_url}}
{{end}} {{if $profile_url}} {{end}}
+ {{ else if $avatar }}
+ {{ $avatar_image := $avatar.Fill "270x270 Center" }}
+ {{if $profile_url}}
{{end}} {{if $profile_url}} {{end}}
+ {{ end }}
+
+
+
+ {{ with $author_page.Params.role }}
{{. | markdownify | emojify}} {{end}}
+ {{ with $author_page.Params.bio }}
{{. | markdownify | emojify}}
{{end}}
+ {{ partial "social_links" $author_page }}
+
+
+{{end}}{{/* Profile page block */}}
diff --git a/modules/wowchemy-tailwind/layouts/partials/page_edit.html b/modules/wowchemy-tailwind/layouts/partials/page_edit.html
new file mode 100644
index 00000000..0adf4bcb
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/page_edit.html
@@ -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, `.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}}
+
+
+ 📝 {{ i18n "edit_page" | default "Edit this page" }}
+
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/page_footer.html b/modules/wowchemy-tailwind/layouts/partials/page_footer.html
new file mode 100644
index 00000000..b5a62e97
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/page_footer.html
@@ -0,0 +1,13 @@
+{{ partial "page_edit" . }}
+{{ partial "tags" . }}
+{{/* partial "components/page_sharer" . */}}
+{{/* partial "page_author" . */}}
+{{ partial "comments" . }}
+
+{{ if .Params.pager }}
+
+ {{/* partial "components/pager" . */}}
+
+{{ end }}
+
+{{/* partial "page_related" . */}}
diff --git a/modules/wowchemy-tailwind/layouts/partials/page_related.html b/modules/wowchemy-tailwind/layouts/partials/page_related.html
new file mode 100644
index 00000000..13e35c32
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/page_related.html
@@ -0,0 +1,14 @@
+{{/* Show related/recommended content. */}}
+{{ if .Params.show_related }}
+ {{ $related := site.RegularPages.Related . | first 5 }}
+ {{ with $related }}
+
+
{{ i18n "related" }}
+
+
+ {{ end }}
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/site_footer.html b/modules/wowchemy-tailwind/layouts/partials/site_footer.html
new file mode 100644
index 00000000..8ed28482
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/site_footer.html
@@ -0,0 +1,39 @@
+
+
+ {{ partial "functions/get_hook" (dict "hook" "footer-start" "context" .) }}
+
+ {{ if or (site.GetPage "/terms.md") (site.GetPage "/privacy.md") }}
+
+ {{ with site.GetPage "/privacy.md" }}
+ {{ printf "%s " .RelPermalink .Title | safeHTML }}
+ {{ end }}
+ {{ with site.GetPage "/terms.md" }}
+ {{ if site.GetPage "/privacy.md" }} · {{ end }}
+ {{ printf "%s " .RelPermalink .Title | safeHTML }}
+ {{ end }}
+
+ {{ end }}
+
+ {{ with site.Params.footer.text }}
+
+ {{ . | markdownify | emojify }}
+
+ {{ end }}
+
+
+ {{ $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}" "Wowchemy " | safeHTML }}
+ {{ $i18n_published_with = replace $i18n_published_with "{repo_link}" "" | safeHTML }}
+ {{ $i18n_published_with = replace $i18n_published_with "{/repo_link}" " " | safeHTML }}
+ {{ $i18n_published_with | markdownify | emojify | safeHTML }}
+ {{ end }}
+
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/site_head.html b/modules/wowchemy-tailwind/layouts/partials/site_head.html
new file mode 100644
index 00000000..a269e4df
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/site_head.html
@@ -0,0 +1,292 @@
+{{ $scr := .Scratch }}
+
+
+
+
+
+
+ {{/* EXTENSIBILITY HOOK: HEAD-START */}}
+ {{ partial "functions/get_hook" (dict "hook" "head-start" "context" .) }}
+
+ {{ if .Params.private }}
+
+ {{- 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 }} {{ 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 }}
+
+
+ {{ range .Translations }}
+
+ {{ end }}
+
+
+ {{/* Style */}}
+ {{ if hugo.IsProduction }}
+ {{ $styles := resources.Get "dist/wc.css" }}
+
+ {{ 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 }}
+
+ {{ end }}
+
+
+
+
+
+ {{/* Config LaTeX math rendering. */}}
+ {{ if or .Params.math site.Params.features.math.enable }}
+
+
+
+
+ {{ 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 }}
+
+
+ {{ end }}
+
+ {{/* Marketing */}}
+ {{ with site.Params.marketing.verification.google }}
+
+ {{- end -}}
+ {{ with site.Params.marketing.verification.baidu }}
+
+ {{- end -}}
+ {{ with site.Params.marketing.verification.bing }}
+
+ {{- end -}}
+ {{ partial "marketing/google_analytics" . }}
+ {{ partial "marketing/google_tag_manager" . }}
+ {{ partial "marketing/microsoft_clarity" . }}
+ {{ partial "marketing/baidu_tongji" . }}
+
+ {{/* RSS Feed */}}
+ {{ with .OutputFormats.Get "RSS" }}
+
+ {{ end }}
+
+ {{/* Progressive Web App (PWA) Icon */}}
+
+
+
+
+
+ {{/* 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 }}
+
+ {{ with site.Params.marketing.seo.twitter }}
+
+
+ {{ end }}
+
+
+
+
+ {{- with $og_image -}}
+
+
+ {{- end -}}
+
+ {{ if .IsPage }}
+ {{ if not .PublishDate.IsZero }}
+
+ {{ else if not .Date.IsZero }}
+
+ {{ end }}
+ {{ if not .Lastmod.IsZero }} {{ end }}
+ {{ else }}
+ {{ if not .Date.IsZero }}
+
+ {{ end }}
+ {{ end }}
+
+ {{ partial "jsonld/main" (dict "page" . "summary" $desc) }}
+
+ {{$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" .) }}
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/social_links.html b/modules/wowchemy-tailwind/layouts/partials/social_links.html
new file mode 100644
index 00000000..78de30af
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/social_links.html
@@ -0,0 +1,22 @@
+
+ {{ 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 }}
+
+
+
+
+
+ {{end}}
+
diff --git a/modules/wowchemy-tailwind/layouts/partials/tags.html b/modules/wowchemy-tailwind/layouts/partials/tags.html
new file mode 100644
index 00000000..0170f09f
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/tags.html
@@ -0,0 +1,8 @@
+{{ $taxonomy := "tags" }}
+{{ if .Param $taxonomy }}
+
+ {{ range $index, $value := (.GetTerms $taxonomy) }}
+
{{ .LinkTitle }}
+ {{ end }}
+
+{{ end }}
diff --git a/modules/wowchemy-tailwind/layouts/partials/views/card.html b/modules/wowchemy-tailwind/layouts/partials/views/card.html
new file mode 100644
index 00000000..7ddbe247
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/partials/views/card.html
@@ -0,0 +1,25 @@
+{{ $item := .item }}
+
+{{ $resource := partial "functions/get_featured_image.html" $item }}
+{{ $anchor := $item.Params.image.focal_point | default "Center" }}
+
+
+
+
+ {{ with $resource }}
+ {{ $image := .Fill (printf "655x655 %s" $anchor) }}
+ {{ if ne $image.MediaType.SubType "gif" }}{{ $image = $image.Process "webp" }}{{ end }}
+
+ {{end}}
+
+
+
{{ $item.Title }}
+
+ {{ ($item.Params.summary | default $item.Summary) | plainify | htmlUnescape | chomp -}}
+
+
+ {{- $item.Date | time.Format (site.Params.locale.date_format | default ":date_long") -}}
+
+
+
+
diff --git a/modules/wowchemy-tailwind/layouts/shortcodes/math.html b/modules/wowchemy-tailwind/layouts/shortcodes/math.html
new file mode 100644
index 00000000..59448a1a
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/shortcodes/math.html
@@ -0,0 +1 @@
+{{ .Inner }}
diff --git a/modules/wowchemy-tailwind/layouts/shortcodes/table.html b/modules/wowchemy-tailwind/layouts/shortcodes/table.html
new file mode 100644
index 00000000..12f0e1c3
--- /dev/null
+++ b/modules/wowchemy-tailwind/layouts/shortcodes/table.html
@@ -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 }}
+
+
+ {{ if $useHeaderRow }}
+ {{ $headerRow := index $rows 0 }}
+ {{ $rows = after 1 $rows }}
+
+ {{ range $headerRow }} {{ . | markdownify | emojify }} {{ end }}
+
+ {{ end }}
+
+ {{ range $rows }}
+
+ {{ range . }}
+ {{ if (findRE "^\\d+$" .) }}
+ {{ . }}
+ {{ else }}
+ {{ . | markdownify | emojify }}
+ {{ end }}
+ {{ end }}
+
+ {{ end }}
+
+ {{ if $caption }}
+ {{ $caption | markdownify | emojify }}
+ {{ end }}
+
diff --git a/modules/wowchemy-tailwind/package.json b/modules/wowchemy-tailwind/package.json
new file mode 100644
index 00000000..9ce09b1f
--- /dev/null
+++ b/modules/wowchemy-tailwind/package.json
@@ -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"
+}
diff --git a/modules/wowchemy-tailwind/postcss.config.js b/modules/wowchemy-tailwind/postcss.config.js
new file mode 100644
index 00000000..aa2bb7ab
--- /dev/null
+++ b/modules/wowchemy-tailwind/postcss.config.js
@@ -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: {},
+ }
+};
diff --git a/modules/wowchemy-tailwind/tailwind.config.js b/modules/wowchemy-tailwind/tailwind.config.js
new file mode 100644
index 00000000..158091b2
--- /dev/null
+++ b/modules/wowchemy-tailwind/tailwind.config.js
@@ -0,0 +1,10 @@
+module.exports = {
+ content: ['./hugo_stats.json', './layouts/**/*.html'],
+ plugins: [
+ require('@tailwindcss/typography'),
+ ],
+ safelist: [
+ 'task-list',
+ ],
+ darkMode: ['class']
+}