Add view counter to articles

This commit is contained in:
Mikkel Svartveit 2024-05-13 00:39:58 -07:00
parent a42cef44bc
commit 797d93c523
7 changed files with 82 additions and 11 deletions

3
.gitignore vendored
View file

@ -19,3 +19,6 @@ pnpm-debug.log*
# macOS-specific files # macOS-specific files
.DS_Store .DS_Store
# Cloudflare
/.wrangler

View file

@ -13,4 +13,12 @@ export default defineConfig({
enabled: true, enabled: true,
}, },
}), }),
vite: {
ssr: {
external: ["node:async_hooks"],
},
},
experimental: {
actions: true,
},
}); });

18
src/actions/index.ts Normal file
View file

@ -0,0 +1,18 @@
import { defineAction, z, getApiContext } from "astro:actions";
export const server = {
registerView: defineAction({
input: z.object({ articleSlug: z.string() }),
handler: async ({ articleSlug }) => {
const context = getApiContext();
// @ts-ignore
const { ViewCountKV } = context.locals.runtime.env;
let viewCount = (await ViewCountKV.get(articleSlug)) || 0;
await ViewCountKV.put(articleSlug, ++viewCount);
return viewCount;
},
}),
};

View file

@ -0,0 +1,35 @@
<script lang="ts">
import { actions } from "astro:actions";
import { onMount } from "svelte";
export let articleSlug: string;
let counter: number | null = null;
onMount(async () => {
const readCount = await actions.registerView({ articleSlug });
counter = readCount;
});
</script>
{#if counter !== null}
<span class="px-2"></span>
<span class="inline-flex items-center space-x-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" height="12">
<!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
<style>
svg {
fill: currentColor;
}
</style>
<path
d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1 -288 0zm144-64c0 35.3-28.7 64-64 64c-7.1 0-13.9-1.2-20.3-3.3c-5.5-1.8-11.9 1.6-11.7 7.4c.3 6.9 1.3 13.8 3.2 20.7c13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3z"
/>
</svg>
<span>{counter}</span>
</span>
{/if}

1
src/env.d.ts vendored
View file

@ -1,2 +1,3 @@
/// <reference path="../.astro/actions.d.ts" />
/// <reference path="../.astro/types.d.ts" /> /// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" /> /// <reference types="astro/client" />

View file

@ -5,6 +5,7 @@ import TextContentLayout from "@layouts/TextContentLayout.astro";
import type { GetStaticPaths } from "astro"; import type { GetStaticPaths } from "astro";
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
import ProseLayout from "@layouts/ProseLayout.astro"; import ProseLayout from "@layouts/ProseLayout.astro";
import ArticleViewCounter from "@components/ArticleViewCounter.svelte";
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const blogCollection = await getCollection("blog"); const blogCollection = await getCollection("blog");
@ -25,7 +26,8 @@ const title = headings[0].text;
<BaseLayout {title} description={intro}> <BaseLayout {title} description={intro}>
<ContainerLayout> <ContainerLayout>
<TextContentLayout> <TextContentLayout>
<p class="mx-auto mb-4 text-gray-500"> <p class="mx-auto mb-4 flex items-center text-gray-500">
<span>
{ {
new Date(date).toLocaleDateString("en-US", { new Date(date).toLocaleDateString("en-US", {
month: "long", month: "long",
@ -33,6 +35,9 @@ const title = headings[0].text;
year: "numeric", year: "numeric",
}) })
} }
</span>
<ArticleViewCounter articleSlug={project.slug} client:only="svelte" />
</p> </p>
<ProseLayout> <ProseLayout>

View file

@ -1,7 +1,8 @@
# Generated by Wrangler on Sun May 12 2024 19:58:01 GMT-0700 (Pacific Daylight Time)
name = "astro-personal-website" name = "astro-personal-website"
pages_build_output_dir = "dist" pages_build_output_dir = "dist"
compatibility_date = "2023-10-15" compatibility_date = "2023-10-15"
compatibility_flags = ["nodejs_compat"]
[env.production] [[kv_namespaces]]
compatibility_date = "2023-10-15" binding = "ViewCountKV"
id = "682c01c937f94375aeec197e89074c10"