mirror of
https://github.com/mikkelsvartveit/astro-personal-website.git
synced 2025-12-22 11:12:38 +00:00
Add view counter to articles
This commit is contained in:
parent
a42cef44bc
commit
797d93c523
7 changed files with 82 additions and 11 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -19,3 +19,6 @@ pnpm-debug.log*
|
||||||
|
|
||||||
# macOS-specific files
|
# macOS-specific files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# Cloudflare
|
||||||
|
/.wrangler
|
||||||
|
|
@ -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
18
src/actions/index.ts
Normal 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;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
35
src/components/ArticleViewCounter.svelte
Normal file
35
src/components/ArticleViewCounter.svelte
Normal 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
1
src/env.d.ts
vendored
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue