From bd6783c5a0603acf26933f34e27b15e62e8720e8 Mon Sep 17 00:00:00 2001
From: Cory Dransfeldt <hi@coryd.dev>
Date: Wed, 5 Jul 2023 14:29:55 -0700
Subject: [PATCH] feat: popular posts

---
 .env                               |  1 +
 config/filters.js                  | 10 ++++++++++
 src/404.md                         |  2 ++
 src/_data/analytics.js             | 18 ++++++++++++++++++
 src/_includes/forms/search.liquid  | 26 --------------------------
 src/_includes/popular-posts.liquid | 16 ++++++++++++++++
 src/_includes/post.liquid          |  1 +
 src/search.md                      | 28 +++++++++++++++++++++++++++-
 8 files changed, 75 insertions(+), 27 deletions(-)
 create mode 100644 src/_data/analytics.js
 delete mode 100644 src/_includes/forms/search.liquid
 create mode 100644 src/_includes/popular-posts.liquid

diff --git a/.env b/.env
index 38775f9a..8204e5c3 100644
--- a/.env
+++ b/.env
@@ -1,3 +1,4 @@
+API_KEY_PLAUSIBLE=
 API_KEY_TRAKT=
 API_KEY_WEBMENTIONS_CORYD_DEV=
 API_BEARER_APPLE_MUSIC=
diff --git a/config/filters.js b/config/filters.js
index 47a5b5be..ddca9c3b 100644
--- a/config/filters.js
+++ b/config/filters.js
@@ -15,6 +15,16 @@ module.exports = {
     if (image && image !== '') return image
     return '/assets/img/social-card.webp'
   },
+  getPopularPosts: (posts, analytics) => {
+    return posts
+      .filter((post) => {
+        if (analytics.find((p) => p.page === post.url)) return true
+      })
+      .sort((a, b) => {
+        const visitors = (page) => analytics.filter((p) => p.page === page.url)[0].visitors
+        return visitors(b) - visitors(a)
+      })
+  },
   webmentionsByUrl: (webmentions, url) => {
     const allowedTypes = ['mention-of', 'in-reply-to', 'like-of', 'repost-of']
 
diff --git a/src/404.md b/src/404.md
index ba53cccc..8f3fbd98 100644
--- a/src/404.md
+++ b/src/404.md
@@ -20,3 +20,5 @@ permalink: 404.html
     </a>
   </div>
 </div>
+<hr />
+{% include "popular-posts.liquid" %}
diff --git a/src/_data/analytics.js b/src/_data/analytics.js
new file mode 100644
index 00000000..200e3da1
--- /dev/null
+++ b/src/_data/analytics.js
@@ -0,0 +1,18 @@
+const EleventyFetch = require('@11ty/eleventy-fetch')
+
+module.exports = async function () {
+  const API_KEY_PLAUSIBLE = process.env.API_KEY_PLAUSIBLE
+  const url =
+    'https://plausible.io/api/v1/stats/breakdown?site_id=coryd.dev&period=6mo&property=event:page&limit=30'
+  const res = EleventyFetch(url, {
+    duration: '1h',
+    type: 'json',
+    fetchOptions: {
+      headers: {
+        Authorization: `Bearer ${API_KEY_PLAUSIBLE}`,
+      },
+    },
+  }).catch()
+  const pages = await res
+  return pages.results.filter((p) => p.page.includes('posts')).splice(0, 5)
+}
diff --git a/src/_includes/forms/search.liquid b/src/_includes/forms/search.liquid
deleted file mode 100644
index 3caba2f2..00000000
--- a/src/_includes/forms/search.liquid
+++ /dev/null
@@ -1,26 +0,0 @@
-<link href="/_pagefind/pagefind-ui.css" rel="stylesheet">
-<style>
-  :root {
-    --pagefind-ui-font: InterVariable, ui-sans-serif, system-ui, -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";
-    --pagefind-ui-primary: #374151;
-    --pagefind-ui-text: #374151;
-  }
-  @media (prefers-color-scheme: dark) {
-    :root {
-      --pagefind-ui-primary: #e5e7eb;
-      --pagefind-ui-text: #e5e7eb;
-      --pagefind-ui-background: #152028;
-      --pagefind-ui-border: #152028;
-      --pagefind-ui-tag: #152028;
-    }
-  }
-</style>
-<div id="search" class="search"></div>
-<script src="/_pagefind/pagefind-ui.js" onload="new PagefindUI({ element: '#search', showImages: false });"></script>
-<script>
-  if (plausible) {
-    document.querySelector('#search').addEventListener('focusout', (e) => {
-      plausible('Search', { props: { query: e.target.value }})
-    })
-  }
-</script>
\ No newline at end of file
diff --git a/src/_includes/popular-posts.liquid b/src/_includes/popular-posts.liquid
new file mode 100644
index 00000000..b6e1d19a
--- /dev/null
+++ b/src/_includes/popular-posts.liquid
@@ -0,0 +1,16 @@
+{% assign posts = collections.posts | getPopularPosts: analytics %}
+<div class="not-prose">
+  <h2 class="m-0 text-xl flex flex-row items-center font-black leading-tight tracking-normal dark:text-gray-200 md:text-2xl mt-8 mb-4">
+    {% heroicon "outline" "fire" "Popular" "height=28" %}
+    <div class="ml-1">Popular posts</div>
+  </h2>
+  <ul class="list-inside list-disc pl-5 md:pl-10">
+    {% for post in posts %}
+      <li class="mt-1.5 mb-2">
+        <a href="{{post.url}}" title="{{ post.data.title | escape}}">
+          {{ post.data.title }}
+        </a>
+      </li>
+    {% endfor %}
+  </ul>
+</div>
diff --git a/src/_includes/post.liquid b/src/_includes/post.liquid
index 96e36658..1fc0066e 100644
--- a/src/_includes/post.liquid
+++ b/src/_includes/post.liquid
@@ -14,3 +14,4 @@ layout: main
 {% include "post-tags.liquid" %}
 {% include "webmentions.liquid" %}
 {% include "author.liquid" %}
+{% include "popular-posts.liquid" %}
\ No newline at end of file
diff --git a/src/search.md b/src/search.md
index 41c1d934..234b5d6a 100644
--- a/src/search.md
+++ b/src/search.md
@@ -17,4 +17,30 @@ meta:
   image:
     src: https://coryd.dev/assets/img/avatar.webp
 ---
-{% include "forms/search.liquid" %}
+<link href="/_pagefind/pagefind-ui.css" rel="stylesheet">
+<style>
+  :root {
+    --pagefind-ui-font: InterVariable, ui-sans-serif, system-ui, -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";
+    --pagefind-ui-primary: #374151;
+    --pagefind-ui-text: #374151;
+  }
+  @media (prefers-color-scheme: dark) {
+    :root {
+      --pagefind-ui-primary: #e5e7eb;
+      --pagefind-ui-text: #e5e7eb;
+      --pagefind-ui-background: #152028;
+      --pagefind-ui-border: #152028;
+      --pagefind-ui-tag: #152028;
+    }
+  }
+</style>
+<div id="search" class="search"></div>
+<script src="/_pagefind/pagefind-ui.js" onload="new PagefindUI({ element: '#search', showImages: false });"></script>
+<script>
+  if (plausible) {
+    document.querySelector('#search').addEventListener('focusout', (e) => {
+      plausible('Search', { props: { query: e.target.value }})
+    })
+  }
+</script>
+{% include "popular-posts.liquid" %}