Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ianrodrigues/hugo-tailwind-journal.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Rodrigues <ianrdgs@gmail.com>2019-11-19 21:36:13 +0300
committerGitHub <noreply@github.com>2019-11-19 21:36:13 +0300
commit31043c498319249e241db240e85cc3609ecb5737 (patch)
treef32056d54e7aa9f52e9ed5376850e524f541254f
parentb1538c8520b5539c0db282c934c3ac668962c287 (diff)
Hugo theme (#1)
-rw-r--r--.gitignore2
-rw-r--r--.vscode/extensions.json3
-rw-r--r--README.md53
-rw-r--r--archetypes/default.md7
-rw-r--r--i18n/en.yaml5
-rw-r--r--layouts/404.html12
-rw-r--r--layouts/_default/baseof.html86
-rw-r--r--layouts/_default/list.html7
-rw-r--r--layouts/index.html18
-rw-r--r--layouts/partials/back-home.html1
-rw-r--r--layouts/partials/posts.html12
-rw-r--r--layouts/posts/single.html28
-rw-r--r--layouts/taxonomy/terms.html13
-rw-r--r--package.json6
-rw-r--r--postcss.config.js2
-rw-r--r--public/favicon-16x16.pngbin1029 -> 0 bytes
-rw-r--r--public/favicon-32x32.pngbin1295 -> 0 bytes
-rw-r--r--public/favicon.icobin15086 -> 0 bytes
-rw-r--r--public/index.html342
-rw-r--r--readme.md62
-rw-r--r--scss/theme.scss (renamed from public/theme.scss)14
-rw-r--r--static/css/chroma.dracula.css1
-rw-r--r--static/css/theme.css1
-rw-r--r--static/images/404-background.pngbin0 -> 167222 bytes
-rw-r--r--theme.toml12
25 files changed, 283 insertions, 404 deletions
diff --git a/.gitignore b/.gitignore
index 408cb74..eb1a2c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+.vscode/
+
node_modules
public/build
yarn.lock
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
deleted file mode 100644
index 99e242b..0000000
--- a/.vscode/extensions.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "recommendations": ["bradlc.vscode-tailwindcss"]
-}
diff --git a/README.md b/README.md
deleted file mode 100644
index ad88e6f..0000000
--- a/README.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# Tailwind CSS Playground
-
-A simple starter project for playing around with Tailwind in a proper PostCSS environment.
-
-To get started:
-
-1. Clone the repository:
-
- ```bash
- git clone https://github.com/tailwindcss/playground.git tailwindcss-playground
-
- cd tailwindcss-playground
- ```
-
-2. Install the dependencies:
-
- ```bash
- # Using npm
- npm install
-
- # Using Yarn
- yarn
- ```
-
-3. Start the development server:
-
- ```bash
- # Using npm
- npm run serve
-
- # Using Yarn
- yarn run serve
- ```
-
- Now you should be able to see the project running at localhost:8080.
-
-4. Open `public/index.html` in your editor and start experimenting!
-
-## Building for production
-
-Even though this isn't necessarily a starter kit for a proper project, we've included an example of setting up both [Purgecss](https://www.purgecss.com/) and [cssnano](https://cssnano.co/) to optimize your CSS for production.
-
-To build an optimized version of your CSS, simply run:
-
-```bash
-# Using npm
-npm run production
-
-# Using Yarn
-yarn run production
-```
-
-After that's done, check out `./public/build/tailwind.css` to see the optimized output.
diff --git a/archetypes/default.md b/archetypes/default.md
new file mode 100644
index 0000000..f7e5e03
--- /dev/null
+++ b/archetypes/default.md
@@ -0,0 +1,7 @@
+---
+title: "{{ replace .Name "-" " " | title }}"
+description: ""
+date: {{ .Date }}
+draft: true
+tags: []
+---
diff --git a/i18n/en.yaml b/i18n/en.yaml
new file mode 100644
index 0000000..8326be1
--- /dev/null
+++ b/i18n/en.yaml
@@ -0,0 +1,5 @@
+- id: back_home
+ translation: "Back Home"
+
+- id: not_found_page_title
+ translation: "Whoops! The page you're looking for doesn't exist :("
diff --git a/layouts/404.html b/layouts/404.html
new file mode 100644
index 0000000..afa69fe
--- /dev/null
+++ b/layouts/404.html
@@ -0,0 +1,12 @@
+{{ define "heading"}}
+<div>
+ <a class="text-lg mb-8 inline-block" href="{{ .Site.BaseURL | relLangURL }}">&larr; {{ i18n "back_home" }}</a>
+ <h1 class="text-4xl font-bold">{{ i18n "not_found_page_title" }}</h1>
+</div>
+{{ end }}
+
+{{ define "content" }}
+<section class="mb-24">
+ <img src="{{ "images/404-background.png" | relURL }}" alt="Page Not Found">
+</section>
+{{ end }}
diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html
new file mode 100644
index 0000000..2e32b75
--- /dev/null
+++ b/layouts/_default/baseof.html
@@ -0,0 +1,86 @@
+<!doctype html>
+<html lang="{{ .Site.Params.LanguageCode }}">
+
+<head>
+ <meta charset="utf-8">
+ {{ hugo.Generator }}
+
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+ <!-- Twitter Card -->
+ <meta name="twitter:card" content="summary">
+ <meta name="twitter:title" content="{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} - {{ .Site.Title }}{{ end }}">
+ <meta name="twitter:description" content="{{ if .IsHome }}{{ .Site.Params.description }}{{ else }}{{ .Summary | plainify }}{{ end }}">
+ <meta name="twitter:site" content="{{ .Site.BaseURL }}">
+ <meta name="twitter:creator" content="{{ .Params.Author }}">
+ <meta name="twitter:image" content="{{ .Site.Params.Avatar | absURL }}">
+
+ <!-- Open-Graph Data -->
+ <meta property="og:locale" content="{{ .Site.Params.LanguageCode }}">
+ <meta property="og:type" content="{{ if .IsHome }}website{{ else }}article{{ end }}">
+ <meta property="og:title" content="{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} - {{ .Site.Title }}{{ end }}">
+ <meta property="og:description" content="{{ if .IsHome }}{{ .Site.Params.description }}{{ else }}{{ .Summary | plainify }}{{ end }}">
+ <meta property="og:url" content="{{ .Permalink }}">
+ <meta property="og:site_name" content="{{ .Site.Title }}">
+ <meta property="og:image" content="{{ .Site.Params.Avatar | absURL }}">
+
+ <title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} - {{ .Site.Title }}{{ end }}</title>
+
+ <meta name="author" content="{{ .Site.Params.Author }}">
+ <meta name="description" content="{{ if .IsHome }}{{ .Site.Params.description }}{{ else }}{{ .Summary | plainify }}{{ end }}">
+
+ <!-- RSS -->
+ {{ with .OutputFormats.Get "RSS" }}
+ <link rel="alternate" href="{{ .RelPermalink | absURL }}" type="application/rss+xml" title="{{ $.Site.Title }}">
+ {{ end }}
+
+ <!-- Translations -->
+ {{ if .IsTranslated }}
+ {{ range .Translations }}
+ <link rel="alternate" hreflang="{{ .Language.Lang }}" href="{{ .Permalink }}" title="{{ .Site.Title }}">
+ {{ end }}
+ {{ end }}
+
+ <!-- Stylesheets -->
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Code+Pro|Arvo:400,700">
+ <link rel="stylesheet" href="{{ "css/theme.css" | absURL }}">
+ <link rel="stylesheet" href="{{ "css/chroma.dracula.css" | absURL }}">
+</head>
+<body class="font-serif bg-gray-200 border-t-4 border-blue-500 antialiased">
+ <div class="w-full p-6 md:w-2/3 md:px-0 md:mx-auto xl:w-2/5">
+ <header class="mb-6">
+ <!-- All the pages must have a heading block, defaults to a link for the home page and a title. -->
+ <div class="mb-6 md:flex md:items-center">
+ {{ block "heading" . }}
+ <div>
+ {{ partial "back-home.html" . }}
+ <h1 class="text-4xl font-bold">{{ .Title }}</h1>
+ </div>
+ {{ end }}
+ </div>
+
+ <!-- If the blog has translation, they shoul be displayed here. -->
+ {{ if .IsTranslated }}
+ <nav>
+ {{ range $i, $lang := .Translations }}
+ {{ if $i }}/{{ end }}
+ <a href="{{ .Permalink }}">{{ $lang.Language.LanguageName }}</a>
+ {{ end}}
+ </nav>
+ {{ end }}
+ </header>
+
+ <!-- The content block. -->
+ {{ block "content" . }}{{ end }}
+
+ <footer>
+ <p>
+ &copy; {{ now.Format "2006"}}. Proudly made with đź’• with <a href="https://gohugo.io/" target="_blank">Hugo</a> and <a href="https://tailwindcss.com/" target="_blank">TailwindCSS</a>.
+ </p>
+ </footer>
+ </div>
+
+ {{ template "_internal/google_analytics.html" . }}
+</body>
+</html>
diff --git a/layouts/_default/list.html b/layouts/_default/list.html
new file mode 100644
index 0000000..d781ce7
--- /dev/null
+++ b/layouts/_default/list.html
@@ -0,0 +1,7 @@
+{{ define "content" }}
+<section class="mb-24">
+ {{ range site.RegularPages.GroupByDate "2006" -}}
+ {{ partial "posts.html" . }}
+ {{ end }}
+</section>
+{{ end }}
diff --git a/layouts/index.html b/layouts/index.html
new file mode 100644
index 0000000..4869c46
--- /dev/null
+++ b/layouts/index.html
@@ -0,0 +1,18 @@
+{{ define "heading" }}
+{{ if .Site.Params.Avatar }}
+<img class="hidden md:block w-20 rounded-full mr-6" src="{{ .Site.Params.Avatar | absURL }}" alt="{{ .Site.Params.Author }}">
+{{ end }}
+
+<div>
+ <h1 class="text-4xl font-bold">{{ .Site.Title }}</h1>
+ <p>{{ .Site.Params.tagline }}</p>
+</div>
+{{ end }}
+
+{{ define "content" }}
+<section class="mb-24">
+ {{ range site.RegularPages.GroupByDate "2006" -}}
+ {{ partial "posts.html" . }}
+ {{ end }}
+</section>
+{{ end }}
diff --git a/layouts/partials/back-home.html b/layouts/partials/back-home.html
new file mode 100644
index 0000000..4064d52
--- /dev/null
+++ b/layouts/partials/back-home.html
@@ -0,0 +1 @@
+<a class="text-lg mb-8 inline-block" href="{{ .Site.BaseURL | relLangURL }}">&larr; {{ i18n "back_home" }}</a>
diff --git a/layouts/partials/posts.html b/layouts/partials/posts.html
new file mode 100644
index 0000000..0ebd4ca
--- /dev/null
+++ b/layouts/partials/posts.html
@@ -0,0 +1,12 @@
+<div>
+ <h2 class="text-3xl font-bold mb-2">{{ .Key }}</h2>
+
+ <ol>
+ {{ range .Pages -}}
+ <li class="mb-6 md:flex md:flex-row">
+ <time class=" block md:flex-l-24" datetime="{{ .Date.Format "2006-01-02 15:04:05 MST" }}">{{ .Date.Format "Jan 02"}}</time>
+ <a class="text-lg md:ml-12" href="{{ .RelPermalink }}">{{ .Title }}</a>
+ </li>
+ {{- end }}
+ </ol>
+</div>
diff --git a/layouts/posts/single.html b/layouts/posts/single.html
new file mode 100644
index 0000000..e4485f3
--- /dev/null
+++ b/layouts/posts/single.html
@@ -0,0 +1,28 @@
+{{ define "heading" }}
+<div>
+ {{ partial "back-home.html" . }}
+
+ <!-- Title and Publication Date -->
+ <h1 class="text-4xl font-bold">{{ .Title }}</h1>
+ <time datetime="{{ .Date.Format "2006-01-02 15:04:05 MST" }}">{{ .Date.Format "02 Jan 2006" }}</time>
+
+ <!-- Tags -->
+ {{ with .Params.tags }}
+ <ol class="mt-4">
+ {{ range . }}
+ <li class="inline-block">
+ <a class="border-none text-gray-800 text-xs bg-gray-400 hover:bg-gray-600 hover:text-white rounded-sm px-3 py-1" href="{{ "tags" | absURL }}/{{ . | urlize }}">{{ . }}</a>
+ </li>
+ {{ end }}
+ </ol>
+ {{ end }}
+</div>
+{{ end }}
+
+{{ define "content" }}
+<article class="mb-12">
+ {{ .Content }}
+
+ {{ template "_internal/disqus.html" . }}
+</article>
+{{ end }}
diff --git a/layouts/taxonomy/terms.html b/layouts/taxonomy/terms.html
new file mode 100644
index 0000000..76da49e
--- /dev/null
+++ b/layouts/taxonomy/terms.html
@@ -0,0 +1,13 @@
+{{ define "content" }}
+<section class="mb-24">
+ <ol class="-mx-2">
+ {{ range .Pages -}}
+ <li class="inline-block mx-2 my-2">
+ <a class="border-none text-gray-800 bg-gray-400 hover:bg-gray-600 hover:text-white rounded-sm px-3 py-1" href="{{ .RelPermalink }}">
+ {{ .Title }}
+ </a>
+ </li>
+ {{- end }}
+ </ol>
+</section>
+{{ end }}
diff --git a/package.json b/package.json
index 7a405cb..86bb50f 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,7 @@
{
"scripts": {
- "serve": "cross-env NODE_ENV=development concurrently \"postcss public/theme.scss -o public/build/theme.css --watch\" \"live-server ./public\"",
- "development": "cross-env NODE_ENV=development postcss public/theme.scss -o public/build/theme.css",
- "production": "cross-env NODE_ENV=production postcss public/theme.scss -o public/build/theme.css"
+ "watch": "cross-env NODE_ENV=development postcss scss/theme.scss -o static/css/theme.css --watch",
+ "build": "cross-env NODE_ENV=production postcss scss/theme.scss -o static/css/theme.css"
},
"dependencies": {
"autoprefixer": "^9.5.1",
@@ -13,7 +12,6 @@
"concurrently": "^4.1.0",
"cross-env": "^5.2.0",
"cssnano": "^4.1.10",
- "live-server": "^1.2.1",
"postcss-cli": "^6.1.2"
}
}
diff --git a/postcss.config.js b/postcss.config.js
index e4fec19..6efcb77 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -1,5 +1,5 @@
const purgecss = require('@fullhuman/postcss-purgecss')({
- content: ['./public/**/*.html'],
+ content: ['./layouts/**/*.html'],
defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
})
diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png
deleted file mode 100644
index 58aae7e..0000000
--- a/public/favicon-16x16.png
+++ /dev/null
Binary files differ
diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png
deleted file mode 100644
index 30eb539..0000000
--- a/public/favicon-32x32.png
+++ /dev/null
Binary files differ
diff --git a/public/favicon.ico b/public/favicon.ico
deleted file mode 100644
index 70be1bc..0000000
--- a/public/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/public/index.html b/public/index.html
deleted file mode 100644
index 2553f5b..0000000
--- a/public/index.html
+++ /dev/null
@@ -1,342 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>Minimalist Journal - Theme for Hugo</title>
-
- <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
- <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
-
- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Code+Pro|Arvo:400,700">
- <link rel="stylesheet" href="https://ianrodrigues.dev/css/highlight.css">
- <link rel="stylesheet" href="/build/theme.css">
-</head>
-<body class="font-serif bg-gray-200 border-t-4 border-blue-500 antialiased">
- <div class="w-full p-6 md:w-2/3 md:px-0 md:mx-auto xl:w-2/5">
- <header class="mb-12">
- <div class="mb-8 md:flex md:items-center">
- <img class="hidden md:block w-20 rounded-full mr-6" src="https://www.oowlish.com/wp-content/uploads/2018/07/ian.png" alt="Ian Rodrigues">
- <div>
- <h1 class="text-4xl font-bold">Ian Rodrigues</h1>
- <p>yet another blog about dev, sometimes ops</p>
- </div>
-
- <!-- <div>
- <a class="text-lg mb-8 inline-block" href="">&larr; Back Home</a>
- <h1 class="text-4xl font-bold">Writing value objects in PHP</h1>
- <time datetime="2019-11-03 13:30:00 -0300">03 Nov 2019</time>
-
- <ol class="mt-4">
- <li class="inline-block">
- <a class="border-none text-gray-800 text-xs bg-gray-400 hover:bg-gray-600 hover:text-white rounded-sm px-3 py-1" href="">php</a>
- </li>
- <li class="inline-block">
- <a class="border-none text-gray-800 text-xs bg-gray-400 hover:bg-gray-600 hover:text-white rounded-sm px-3 py-1" href="">ddd</a>
- </li>
- <li class="inline-block">
- <a class="border-none text-gray-800 text-xs bg-gray-400 hover:bg-gray-600 hover:text-white rounded-sm px-3 py-1" href="">value objects</a>
- </li>
- <li class="inline-block">
- <a class="border-none text-gray-800 text-xs bg-gray-400 hover:bg-gray-600 hover:text-white rounded-sm px-3 py-1" href="">doctrine</a>
- </li>
- </ol>
- </div> -->
- </div>
-
- <!-- Languages -->
- <nav>
- <a href="https://ianrodrigues.dev/pt-br/">🇺🇸 English</a> /
- <a href="https://ianrodrigues.dev/pt-br/">🇩🇪 Deustch</a> /
- <a href="https://ianrodrigues.dev/pt-br/">🇧🇷 Português</a>
- </nav>
- </header>
-
- <section class="mb-24">
- <div>
- <h2 class="text-3xl font-bold mb-2">2019</h2>
-
- <ol>
- <li class="mb-6 md:flex md:flex-row">
- <time class=" block md:flex-l-24" datetime="2019-11-03 13:30:00 -0300">Nov 09</time>
- <a class="text-lg md:ml-12" href="/2019/11/writing-value-objects-in-php/">Writing value objects in PHP</a>
- </li>
- <li class="mb-6 md:flex md:flex-row">
- <time class=" block md:flex-l-24" datetime="2019-11-03 13:30:00 -0300">Aug 23</time>
- <a class="text-lg md:ml-12" href="/2019/11/writing-value-objects-in-php/">Hello, World!</a>
- </li>
- </ol>
- </div>
- </section>
-
- <article class="mb-12">
- <p>If you already have heard about <a href="https://en.wikipedia.org/wiki/Domain-driven_design">DDD (Domain-Driven Design)</a>, you probably also may have heard about Value Objects. It is one of the building blocks introduced by Eric Evans in <a href="https://www.amazon.com.br/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215">“the blue book”</a>.</p>
-
- <p>A value object is a type which wraps data and is distinguishable only by its properties. Unlike an <code>Entity</code>, it doesn’t have a unique identifier. Thus, <strong>two value objects with the same property values should be considered equal</strong>.</p>
-
- <p>A good example of candidates for value objects are:</p>
-
- <ul>
- <li>phone number</li>
- <li>address</li>
- <li>price</li>
- <li>a commit hash</li>
- <li>a entity identifier</li>
- <li>and so on.</li>
- </ul>
-
- <p>When designing a value object, you should pay attention to its three main characteristics: <strong>immutability, structural equality, and self-validation</strong>.</p>
-
- <p>Here’s an example:</p>
-
- <pre><code class="language-php hljs"><span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);
-
- <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Price</span>
- </span>{
- <span class="hljs-keyword">const</span> USD = <span class="hljs-string">'USD'</span>;
- <span class="hljs-keyword">const</span> CAD = <span class="hljs-string">'CAD'</span>;
-
- <span class="hljs-comment">/** <span class="hljs-doctag">@var</span> float */</span>
- <span class="hljs-keyword">private</span> $amount;
-
- <span class="hljs-comment">/** <span class="hljs-doctag">@var</span> string */</span>
- <span class="hljs-keyword">private</span> $currency;
-
- <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">(float $amount, string $currency = <span class="hljs-string">'USD'</span>)</span>
- </span>{
- <span class="hljs-keyword">if</span> ($amount &lt; <span class="hljs-number">0</span>) {
- <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \InvalidArgumentException(<span class="hljs-string">"Amount should be a positive value: {$amount}."</span>);
- }
-
- <span class="hljs-keyword">if</span> (!in_array($currency, <span class="hljs-keyword">$this</span>-&gt;getAvailableCurrencies())) {
- <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \InvalidArgumentException(<span class="hljs-string">"Currency should be a valid one: {$currency}."</span>);
- }
-
- <span class="hljs-keyword">$this</span>-&gt;amount = $amount;
- <span class="hljs-keyword">$this</span>-&gt;currency = $currency;
- }
-
- <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getAvailableCurrencies</span><span class="hljs-params">()</span>: <span class="hljs-title">array</span>
- </span>{
- <span class="hljs-keyword">return</span> [<span class="hljs-keyword">self</span>::USD, <span class="hljs-keyword">self</span>::CAD];
- }
-
- <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getAmount</span><span class="hljs-params">()</span>: <span class="hljs-title">float</span>
- </span>{
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;amount;
- }
-
- <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCurrency</span><span class="hljs-params">()</span>: <span class="hljs-title">string</span>
- </span>{
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;currency;
- }
- }
- </code></pre>
-
- <h2 id="immutability">Immutability</h2>
-
- <p>Once you instantiate a value object, <strong>it should be the same for the rest of the application lifecycle</strong>. If you need to change its value, it should be done by entirely replacing that object.</p>
-
- <p>Using mutable value objects is acceptable if you are using them <strong>entirely within a local scope</strong>, with only one reference to the object. Otherwise, you may have problems.</p>
-
- <p>Taking the previous example, here’s how you can update the amount of a <code>Price</code> type:</p>
-
- <pre><code class="language-php hljs"><span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);
-
- <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Price</span>
- </span>{
- <span class="hljs-comment">// ...</span>
-
- <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hasSameCurrency</span><span class="hljs-params">(Price $price)</span>: <span class="hljs-title">bool</span>
- </span>{
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;currency === $price-&gt;currency;
- }
-
- <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span><span class="hljs-params">(Price $price)</span>: <span class="hljs-title">self</span>
- </span>{
- <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">$this</span>-&gt;hasSameCurrency($price)) {
- <span class="hljs-keyword">throw</span> \InvalidArgumentException(
- <span class="hljs-string">"You can only sum values with the same currency: {$this-&gt;currency} !== {$price-&gt;currency}."</span>
- );
- }
-
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-keyword">self</span>(<span class="hljs-keyword">$this</span>-&gt;amount + $price-&gt;amount, <span class="hljs-keyword">$this</span>-&gt;currency);
- }
- }
- </code></pre>
-
- <h2 id="structural-equality">Structural Equality</h2>
-
- <p>Value objects <strong>don’t have an identifier</strong>. In other words, if two value objects have the same internal values, they must be considered equal. As PHP doesn’t have a way to override the equality operator, you should implement it by yourself.</p>
-
- <p>You can create a specialized method to do that:</p>
-
- <pre><code class="language-php hljs"><span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);
-
- <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Price</span>
- </span>{
- <span class="hljs-comment">// ...</span>
-
- <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isEqualsTo</span><span class="hljs-params">(Price $price)</span>: <span class="hljs-title">bool</span>
- </span>{
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;amount === $price-&gt;amount &amp;&amp; <span class="hljs-keyword">$this</span>-&gt;currency === $price-&gt;currency;
- }
- }
- </code></pre>
-
- <p>Another option is to create a hash based on its properties:</p>
-
- <pre><code class="language-php hljs"><span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);
-
- <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Price</span>
- </span>{
- <span class="hljs-comment">// ...</span>
-
- <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hash</span><span class="hljs-params">()</span>: <span class="hljs-title">string</span>
- </span>{
- <span class="hljs-keyword">return</span> md5(<span class="hljs-string">"{$this-&gt;amount}{$this-&gt;currency}"</span>);
- }
-
- <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isEqualsTo</span><span class="hljs-params">(Price $price)</span>: <span class="hljs-title">bool</span>
- </span>{
- <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;hash() === $price-&gt;hash();
- }
- }
- </code></pre>
-
- <h2 id="self-validation">Self-Validation</h2>
-
- <p>The <strong>validation of a value object should occur on its creation</strong>. If any of its properties are invalid, it should throw an exception. Putting this together with immutability, once you create a value object, you can be sure it will always be valid.</p>
-
- <p>Taking the <code>Price</code> type example once again, it doesn’t make sense to have a negative amount for the domain of the application:</p>
-
- <pre><code class="language-php hljs"><span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);
-
- <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Price</span>
- </span>{
- <span class="hljs-comment">// ...</span>
-
- <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">(float $amount, string $currency = <span class="hljs-string">'USD'</span>)</span>
- </span>{
- <span class="hljs-keyword">if</span> ($amount &lt; <span class="hljs-number">0</span>) {
- <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \InvalidArgumentException(<span class="hljs-string">"Amount should be a positive value: {$amount}."</span>);
- }
-
- <span class="hljs-keyword">if</span> (!in_array($currency, <span class="hljs-keyword">$this</span>-&gt;getAvailableCurrencies())) {
- <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \InvalidArgumentException(<span class="hljs-string">"Currency should be a valid one: {$currency}."</span>);
- }
-
- <span class="hljs-keyword">$this</span>-&gt;amount = $amount;
- <span class="hljs-keyword">$this</span>-&gt;currency = $currency;
- }
- }
- </code></pre>
-
- <h2 id="using-with-doctrine">Using with Doctrine</h2>
-
- <p>Storing and retrieving value objects from the database using <a href="https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/tutorials/embeddables.html">Doctrine</a> is quite easy using <code>Embeddable</code>s. According to the documentation, <code>Embeddable</code>s are not entities. But, you embed them in entities, which makes them perfect for dealing with value objects.</p>
-
- <p>Let’s suppose you have a <code>Product</code> class, and you would like to store the price in that class. You will end up with the following modeling:</p>
-
- <pre><code class="language-php hljs"><span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">declare</span>(strict_types=<span class="hljs-number">1</span>);
-
- <span class="hljs-comment">/** <span class="hljs-doctag">@Embeddable</span> */</span>
- <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Price</span>
- </span>{
- <span class="hljs-comment">/** <span class="hljs-doctag">@Column</span>(type="float") */</span>
- <span class="hljs-keyword">private</span> $amount;
-
- <span class="hljs-comment">/** <span class="hljs-doctag">@Column</span>(type="string") */</span>
- <span class="hljs-keyword">private</span> $currency;
-
- <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">(float $amount, string $currency = <span class="hljs-string">'USD'</span>)</span>
- </span>{
- <span class="hljs-comment">// ...</span>
-
- <span class="hljs-keyword">$this</span>-&gt;amount = $amount;
- <span class="hljs-keyword">$this</span>-&gt;currency = $currency;
- }
-
- <span class="hljs-comment">// ...</span>
- }
-
- <span class="hljs-comment">/** <span class="hljs-doctag">@Entity</span> */</span>
- <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span>
- </span>{
- <span class="hljs-comment">/** <span class="hljs-doctag">@Embedded</span>(class="Price") */</span>
- <span class="hljs-keyword">private</span> $price;
-
- <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">(Price $price)</span>
- </span>{
- <span class="hljs-keyword">$this</span>-&gt;price = $price;
- }
- }
- </code></pre>
-
- <p>Doctrine will automatically create the columns from the <code>Price</code> class into the table of the <code>Product</code> class. By default, it prefixes the database columns after the <code>Embeddable</code> class name, in this case: <code>price_amount</code> and <code>price_currency</code>.</p>
-
- <h2 id="conclusion">Conclusion</h2>
-
- <p>Value objects are useful for writing <strong>clean code</strong>. Instead of writing:</p>
-
- <pre><code class="language-php hljs"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addPhoneNumber</span><span class="hljs-params">(string $phone)</span>: <span class="hljs-title">void</span> </span>{}
- </code></pre>
-
- <p>You can write:</p>
-
- <pre><code class="language-php hljs"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addPhoneNumber</span><span class="hljs-params">(PhoneNumber $phone)</span>: <span class="hljs-title">void</span> </span>{}
- </code></pre>
-
- <p>Which makes it easy to read and reason about it, also you don’t need to figure out which phone format you should use.</p>
-
- <p>Since their attributes define them, and you can share them with other different entities, they can be cacheable forever.</p>
-
- <p>They can help you to <strong>reduce duplication</strong>. Instead of having multiples <code>amount</code> and <code>currency</code> fields, you can use a pure <code>Price</code> class.</p>
-
- <p>Of course, like everything in life, you <strong>should not abuse</strong> of value objects. Imagine you converting tons of objects to primitive values to store them in the database, or converting those back to value objects when fetching them from the database.Indeed, you can have performance issues. Also, having tons of granular value objects can bloat your codebase.</p>
-
- <p>With value objects, you can <strong>reduce the <a href="https://refactoring.guru/smells/primitive-obsession">primitive obsession</a></strong>. Use them to represent a field or group of fields of your domain that require validation or can cause ambiguity if you use primitive values.</p>
-
- <p>Thanks for reading, and happy coding!</p>
-
- <h2 id="further-reading">Further Reading</h4>
-
- <ul>
- <li><a href="https://twitter.com/martinfowler">Martin Fowler</a> has an article about value objects, check it out here: <a href="https://martinfowler.com/bliki/ValueObject.html">https://martinfowler.com/bliki/ValueObject.html</a></li>
- </ul>
-
-
- <div id="disqus_thread"><iframe id="dsq-app7082" name="dsq-app7082" allowtransparency="true" scrolling="no" tabindex="0" title="Disqus" style="width: 1px !important; min-width: 100% !important; border: medium none !important; overflow: hidden !important; height: 428px !important;" src="https://disqus.com/embed/comments/?base=default&amp;f=ianrodrigues-1&amp;t_u=https%3A%2F%2Fianrodrigues.dev%2F2019%2F11%2Fwriting-value-objects-in-php%2F&amp;t_d=Writing%20value%20objects%20in%20PHP&amp;t_t=Writing%20value%20objects%20in%20PHP&amp;s_o=default#version=49c585dbc35ad09e087de9f308aa12d0" horizontalscrolling="no" verticalscrolling="no" width="100%" frameborder="0"></iframe><iframe id="indicator-north" name="indicator-north" allowtransparency="true" scrolling="no" tabindex="0" title="Disqus" style="width: 684px !important; border: medium none !important; overflow: hidden !important; top: 0px !important; min-width: 684px !important; max-width: 684px !important; position: fixed !important; z-index: 2147483646 !important; height: 19px !important; min-height: 19px !important; max-height: 19px !important; display: none !important;" frameborder="0"></iframe><iframe id="indicator-south" name="indicator-south" allowtransparency="true" scrolling="no" tabindex="0" title="Disqus" style="width: 684px !important; border: medium none !important; overflow: hidden !important; bottom: 0px !important; min-width: 684px !important; max-width: 684px !important; position: fixed !important; z-index: 2147483646 !important; height: 19px !important; min-height: 19px !important; max-height: 19px !important; display: none !important;" frameborder="0"></iframe></div>
- <script type="application/javascript">
- var disqus_config = function () {
-
-
-
- };
- (function() {
- if ([""].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 = '//' + "ianrodrigues-1" + '.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>
- </article>
-
- <footer>
- <p>
- &copy; 2019. Ian Rodrigues, software engineer @ <a class="border-b border-gray-700" href="">oowlish technology</a>
- </p>
-
- <p>
- <a href="">GitHub</a> / <a href="">Twitter</a>
- </p>
- </footer>
- </div>
-</body>
-</html>
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..1407502
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,62 @@
+# TailwindCSS Journal
+
+_TailwindCSS Journal_ is a minimalist theme for [Hugo](https://gohugo.io) using [TailwindCSS](https://tailwindcss.com).
+
+Based on [Journal](https://dashdashzako.github.io/hugo-journal-demo/), it also focuses on improving reading experience with no fancy effect.
+
+It uses [Chroma](https://gohugo.io/content-management/syntax-highlighting/) for the syntaxic coloration of code snippets.
+
+Demo is available [here](https://ianrodrigues.github.io/hugo-tailwind-demo/).
+
+## Installation
+
+Please refer to the [Hugo documentation](https://gohugo.io/themes/installing/).
+
+## Configuration
+
+A few parameters should be adjusted in the site config:
+
+```toml
+baseURL = "https://username.github.io/"
+disqusShortname = "username"
+googleAnalytics = "UA-XXXXXXXXX-X"
+title = "Tailwind Journal"
+theme = "hugo-tailwind-journal"
+pygmentsCodeFences = true
+pygmentsUseClasses = true
+
+[taxonomies]
+ tag = "tags"
+
+[permalinks]
+ posts = "/posts/:year/:month/:title/"
+
+[params]
+ author = "John Doe"
+ avatar = "images/avatar.jpg"
+ description = "A minimalist journal template for Hugo using TailwindCSS."
+ tagline = "A minimalist journal template for Hugo using TailwindCSS."
+
+[languages]
+ [languages.en]
+ contentDir = "content/english"
+ languageCode = "en-us"
+ languageName = "🇺🇸 English"
+ weight = 1
+
+ [languages.pt-br]
+ contentDir = "content/portuguese"
+ description = "Um template minimalista para Hugo usando TailwindCSS."
+ languageCode = "pt-br"
+ languageName = "🇧🇷 Português"
+ tagline = "Um template minimalista para Hugo usando TailwindCSS."
+ weight = 2
+
+ [languages.de]
+ contentDir = "content/german"
+ description = "Eine minimalistische Journalvorlage fĂĽr Hugo mit TailwindCSS."
+ languageCode = "de"
+ languageName = "🇩🇪 Deutsch"
+ tagline = "Eine minimalistische Journalvorlage fĂĽr Hugo mit TailwindCSS."
+ weight = 3
+```
diff --git a/public/theme.scss b/scss/theme.scss
index 68acd5b..9da9261 100644
--- a/public/theme.scss
+++ b/scss/theme.scss
@@ -14,7 +14,7 @@ article > p, ul, ol {
@apply text-lg tracking-wide;
}
-article > p, ul, ol, pre:not(:last-child) {
+article > div, p, ul, ol, pre:not(:last-child) {
@apply mb-6;
}
@@ -37,3 +37,15 @@ article > h2 {
a {
@apply border-b border-black text-black;
}
+
+/* purgecss ignore */
+pre.chroma {
+ @apply p-4 overflow-x-auto font-mono text-lg;
+}
+
+@screen md {
+ /* purgecss ignore */
+ div.highlight {
+ @apply -mx-12;
+ }
+}
diff --git a/static/css/chroma.dracula.css b/static/css/chroma.dracula.css
new file mode 100644
index 0000000..5e903f4
--- /dev/null
+++ b/static/css/chroma.dracula.css
@@ -0,0 +1 @@
+.chroma{color:#f8f8f2;background-color:#282a36}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block}.chroma .hl{display:block;width:100%;background-color:#ffc}.chroma .lnt{margin-right:.4em;padding:0 .4em 0 .4em;color:#7f7f7f}.chroma .ln{margin-right:.4em;padding:0 .4em 0 .4em;color:#7f7f7f}.chroma .k{color:#ff79c6}.chroma .kc{color:#ff79c6}.chroma .kd{color:#8be9fd;font-style:italic}.chroma .kn{color:#ff79c6}.chroma .kp{color:#ff79c6}.chroma .kr{color:#ff79c6}.chroma .kt{color:#8be9fd}.chroma .na{color:#50fa7b}.chroma .nb{color:#8be9fd;font-style:italic}.chroma .nc{color:#50fa7b}.chroma .nf{color:#50fa7b}.chroma .nl{color:#8be9fd;font-style:italic}.chroma .nt{color:#ff79c6}.chroma .nv{color:#8be9fd;font-style:italic}.chroma .vc{color:#8be9fd;font-style:italic}.chroma .vg{color:#8be9fd;font-style:italic}.chroma .vi{color:#8be9fd;font-style:italic}.chroma .s{color:#f1fa8c}.chroma .sa{color:#f1fa8c}.chroma .sb{color:#f1fa8c}.chroma .sc{color:#f1fa8c}.chroma .dl{color:#f1fa8c}.chroma .sd{color:#f1fa8c}.chroma .s2{color:#f1fa8c}.chroma .se{color:#f1fa8c}.chroma .sh{color:#f1fa8c}.chroma .si{color:#f1fa8c}.chroma .sx{color:#f1fa8c}.chroma .sr{color:#f1fa8c}.chroma .s1{color:#f1fa8c}.chroma .ss{color:#f1fa8c}.chroma .m{color:#bd93f9}.chroma .mb{color:#bd93f9}.chroma .mf{color:#bd93f9}.chroma .mh{color:#bd93f9}.chroma .mi{color:#bd93f9}.chroma .il{color:#bd93f9}.chroma .mo{color:#bd93f9}.chroma .o{color:#ff79c6}.chroma .ow{color:#ff79c6}.chroma .c{color:#6272a4}.chroma .ch{color:#6272a4}.chroma .cm{color:#6272a4}.chroma .c1{color:#6272a4}.chroma .cs{color:#6272a4}.chroma .cp{color:#ff79c6}.chroma .cpf{color:#ff79c6}.chroma .gd{color:#8b080b}.chroma .ge{text-decoration:underline}.chroma .gh{font-weight:700}.chroma .gi{font-weight:700}.chroma .go{color:#44475a}.chroma .gu{font-weight:700}.chroma .gl{text-decoration:underline}
diff --git a/static/css/theme.css b/static/css/theme.css
new file mode 100644
index 0000000..4d9cc99
--- /dev/null
+++ b/static/css/theme.css
@@ -0,0 +1 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}a{background-color:transparent}strong{font-weight:bolder}img{border-style:none}button,input{font-family:inherit;font-size:100%;line-height:1.15;margin:0;overflow:visible}button{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}legend{color:inherit;display:table;max-width:100%;white-space:normal}[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}[hidden],template{display:none}html{box-sizing:border-box;font-family:sans-serif}*,:after,:before{box-sizing:inherit}h1,h2,p{margin:0}button{background:transparent;padding:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}ol{list-style:none;margin:0;padding:0}html{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{border:0 solid #e2e8f0}img{border-style:solid}input::-webkit-input-placeholder{color:#a0aec0}input::-moz-placeholder{color:#a0aec0}input:-ms-input-placeholder{color:#a0aec0}input::-ms-input-placeholder{color:#a0aec0}input::placeholder{color:#a0aec0}[role=button],button{cursor:pointer}h1,h2{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input{padding:0;line-height:inherit;color:inherit}canvas,img{display:block;vertical-align:middle}img{max-width:100%;height:auto}.bg-gray-200{background-color:#edf2f7}.bg-gray-400{background-color:#cbd5e0}.hover\:bg-gray-600:hover{background-color:#718096}.border-blue-500{border-color:#4299e1}.rounded-sm{border-radius:.125rem}.rounded-full{border-radius:9999px}.border-none{border-style:none}.border-t-4{border-top-width:4px}.block{display:block}.inline-block{display:inline-block}.hidden{display:none}.font-serif{font-family:Arvo}.font-bold{font-weight:700}.my-2{margin-top:.5rem;margin-bottom:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.mb-2{margin-bottom:.5rem}.mt-4{margin-top:1rem}.mr-6{margin-right:1.5rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mb-12{margin-bottom:3rem}.mb-24{margin-bottom:6rem}.p-6{padding:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.px-3{padding-left:.75rem;padding-right:.75rem}.text-gray-800{color:#2d3748}.hover\:text-white:hover{color:#fff}.text-xs{font-size:.75rem}.text-lg{font-size:1.125rem}.text-3xl{font-size:1.875rem}.text-4xl{font-size:2.25rem}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.w-20{width:5rem}.w-full{width:100%}body{color:#2d3748}h1,h2,strong{color:#1a202c}article>p,ol{font-size:1.125rem;letter-spacing:.025em}article>div,ol,p{margin-bottom:1.5rem}article>ol{list-style-type:disc;margin-left:2rem}article>li:not(:last-of-type){margin-bottom:.5rem}article>h2{font-size:1.5rem;margin-top:2rem;margin-bottom:2rem;font-weight:700;color:#000}a{border-bottom-width:1px;border-color:#000;color:#000}pre.chroma{padding:1rem;overflow-x:auto;font-family:Source Code Pro;font-size:1.125rem}@media (min-width:768px){div.highlight{margin-left:-3rem;margin-right:-3rem}}@media (min-width:768px){.md\:block{display:block}.md\:flex{display:-webkit-box;display:flex}.md\:flex-row{-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-direction:row}.md\:items-center{-webkit-box-align:center;align-items:center}.md\:flex-l-24{-webkit-box-flex:0;flex:0 0 6rem}.md\:mx-auto{margin-left:auto;margin-right:auto}.md\:ml-12{margin-left:3rem}.md\:px-0{padding-left:0;padding-right:0}.md\:w-2\/3{width:66.666667%}}@media (min-width:1280px){.xl\:w-2\/5{width:40%}} \ No newline at end of file
diff --git a/static/images/404-background.png b/static/images/404-background.png
new file mode 100644
index 0000000..4b94538
--- /dev/null
+++ b/static/images/404-background.png
Binary files differ
diff --git a/theme.toml b/theme.toml
new file mode 100644
index 0000000..2986f65
--- /dev/null
+++ b/theme.toml
@@ -0,0 +1,12 @@
+name = "Tailwind Journal"
+license = "MIT"
+licenselink = "https://github.com/ianrodrigues/hugo-tailwind-journal/blob/master/readme.md"
+description = "A minimalist journal template for Hugo using TailwindCSS."
+homepage = "https://github.com/ianrodrigues/hugo-tailwind-journal"
+tags = ["minimalist", "reading", "blog", "tailwindcss"]
+features = ["blog"]
+min_version = "0.54.0"
+
+[author]
+ name = "Ian Rodrigues"
+ homepage = "https://ianrodrigues.dev"