Skip to content

Commit 347c66b

Browse files
committed
Allow setting home page, show titles instead of
filename in sidebar, override data and make it optional
1 parent c3a8244 commit 347c66b

File tree

8 files changed

+272
-169
lines changed

8 files changed

+272
-169
lines changed

docker-compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ services:
1111
- POCKETBASE_ADMIN_PASSWORD=password
1212
- TITLE=Markopolis
1313
- CAP1=Markdown
14-
- CAP2="Self-hosted"
14+
- CAP2="Self-hosting"
1515
- CAP3="Knowledge Garden"
1616
volumes:
1717
- ./pb_data:/app/pb

src/lib/components/FileTree.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
interface FileNode {
66
id: string;
7+
title: string;
78
name: string;
89
url: string;
910
children: FileNode[];
@@ -53,9 +54,9 @@
5354
{/if}
5455

5556
{#if node.url}
56-
<a href={`/${node.url}`} class="text-carbongray-800 hover:underline">{node.name}</a>
57+
<a href={`/${node.url}`} class="text-carbongray-800 hover:underline">{node.title}</a>
5758
{:else}
58-
<span class="font-semibold">{node.name}</span>
59+
<span class="font-semibold">{node.title}</span>
5960
{/if}
6061
</div>
6162

src/routes/+layout.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
<Button class="z-20" on:click={toggleSidebar} variant="ghost" size="icon">
6060
<Grip />
6161
</Button>
62-
<div class="title text-2xl">{siteTitle}</div>
62+
<div class="title text-2xl break-words">{siteTitle}</div>
6363
</div>
6464
<div class="gap-0.1 flex">
6565
<TagBar {tags} />

src/routes/+page.server.ts

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,75 @@
1-
import PocketBase from 'pocketbase';
2-
import { getAuthenticatedPocketBase } from '$lib/server/auth';
1+
import PocketBase from "pocketbase";
2+
import { getAuthenticatedPocketBase } from "$lib/server/auth";
33

44
const pb = await getAuthenticatedPocketBase();
55

66
export async function load({ params }) {
7-
try {
8-
const mdbase = await pb.collections.getOne('mdbase');
9-
10-
const records = await pb.collection('mdbase').getList(1, 10, { sort: '-created' });
11-
const posts = Object.values(records.items).map((item) => ({
12-
title: item.title,
13-
id: item.id,
14-
date: item.created,
15-
url: item.url
16-
}));
17-
return { posts };
18-
} catch (error) {
19-
return { posts: [], err: error };
20-
}
7+
try {
8+
const mdbase = await pb.collections.getOne("mdbase");
9+
10+
const records = await pb.collection("mdbase").getList(1, 1, {
11+
filter: "frontmatter.home = true",
12+
sort: "-created",
13+
});
14+
15+
let post = null;
16+
if (records.items.length > 0) {
17+
post = records.items[0];
18+
}
19+
20+
if (post) {
21+
const backlinks = await getBacklinks(`${post.frontmatter.mdpath}`);
22+
23+
const tags = post.expand?.tags.map((tag) => {
24+
return {
25+
name: tag.tag,
26+
};
27+
});
28+
return { post, title: post.title, backlinks, tags };
29+
} else {
30+
return { post: null, title: "", backlinks: [], tags: [] };
31+
}
32+
} catch (error) {
33+
console.error(`Failed to fetch post: ${error}`);
34+
return { message: `Failed to fetch post: ${error}` };
35+
}
36+
}
37+
38+
async function getBacklinks(url) {
39+
const mdbaseCollection = pb.collection("mdbase");
40+
const documentUrl = url;
41+
try {
42+
if (!documentUrl) {
43+
return new Response(
44+
JSON.stringify({ message: "URL parameter is required" }),
45+
{
46+
status: 400,
47+
},
48+
);
49+
}
50+
51+
const documents = await mdbaseCollection.getList(1, 1, {
52+
filter: `url="${documentUrl}"`,
53+
expand: "backlinks",
54+
});
55+
56+
if (documents.items.length === 0) {
57+
return new Response(JSON.stringify({ message: "Document not found" }), {
58+
status: 404,
59+
});
60+
}
61+
62+
const document = documents.items[0];
63+
64+
const backLinks = (document.expand?.backlinks || []).map((link) => ({
65+
id: link.id,
66+
title: link.title,
67+
url: link.url,
68+
}));
69+
70+
return backLinks;
71+
} catch (error: any) {
72+
console.error("Error in backlinks API:", error);
73+
return {};
74+
}
2175
}

src/routes/+page.svelte

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,59 @@
1-
<script>
2-
export let data;
1+
<script lang="ts">
2+
import MDsvexRenderer from '$lib/components/MDsvexRenderer.svelte';
3+
import MDGraph from '$lib/components/MDGraph.svelte';
4+
import { CalendarDays } from 'lucide-svelte';
35
4-
function formatDate(dateString) {
5-
const date = new Date(dateString);
6-
// Format the date as DD MMM YYYY
7-
return date.toLocaleDateString('en-GB', {
8-
day: '2-digit',
9-
month: 'short',
10-
year: 'numeric'
11-
});
12-
}
6+
export let data: { content: string };
7+
$: content = data.post?.content;
8+
$: tags = data?.tags;
9+
$: date = data.post?.created;
1310
</script>
1411

15-
<div class="mb-6 text-4xl font-bold">Latest</div>
16-
<div class="flex flex-col items-start justify-center gap-4">
17-
{#if data && data.posts.length > 0}
18-
{#each data.posts as p, id (id)}
19-
<div class="flex flex-col items-start justify-center gap-0.5">
20-
<div class="text-xl"><a href="/{p.url}">{p.title}</a></div>
21-
<div class="text-sm text-gray-400">{formatDate(p.date)}</div>
12+
{#if data.post}
13+
<div class="mb-10 mt-6 text-wrap md:w-[700px]">
14+
<div class="my-4 text-6xl md:text-8xl">
15+
{data.title}
16+
</div>
17+
18+
<div class="flex flex-col justify-center gap-1">
19+
{#if data?.post?.frontmatter?.date}
20+
<div class="flex items-center gap-1">
21+
<CalendarDays class="text-carbongray-400" size={15} />
22+
<div class="text-base text-carbongray-400">{data.post.frontmatter.date.split(' ')[0]}</div>
23+
</div>
24+
{/if}
25+
{#if tags}
26+
<div class="flex flex-wrap gap-1">
27+
{#each tags as tag (tag.name)}
28+
<span class="mx-0.5 rounded-sm bg-[#fedc69] p-0.5 text-carbongray-900"
29+
><a class="text-carbongray-900 dark:text-carbongray-900" href="/tags/{tag.name}"
30+
>{tag.name}</a
31+
></span
32+
>
33+
{/each}
2234
</div>
23-
{/each}
24-
{:else}
25-
<div class="text-lg">Please upload markdown files to begin</div>
35+
{/if}
36+
</div>
37+
<hr class="mt-6" />
38+
</div>
39+
<MDsvexRenderer bind:content />
40+
<div>
41+
{#if data?.backlinks?.length > 0}
42+
<hr class="my-4 w-[700px]" />
43+
<div class="mb-2 mt-4 text-2xl font-light">BACKLINKS</div>
2644
{/if}
45+
{#each data?.backlinks || [] as bl (bl.id)}
46+
<div><a href={`/${bl.url.trim()}`} class="text-large">{bl.title}</a></div>
47+
{/each}
2748
</div>
49+
{:else}
50+
<div class="mb-10 mt-6 text-wrap md:w-[700px]">
51+
Set homepage in the frontmatter of one of your markdown files to display it as home
52+
</div>
53+
{/if}
54+
55+
<style>
56+
:global(.tag a) {
57+
@apply mx-0.5 bg-[#fedc69] p-1 text-carbongray-900;
58+
}
59+
</style>
Lines changed: 84 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,107 @@
1-
import { json } from '@sveltejs/kit';
2-
import type { RequestHandler } from './$types';
3-
import PocketBase from 'pocketbase';
4-
import { promises as fs } from 'fs';
5-
import { getAuthenticatedPocketBase } from '$lib/server/auth';
1+
import { json } from "@sveltejs/kit";
2+
import type { RequestHandler } from "./$types";
3+
import PocketBase from "pocketbase";
4+
import { promises as fs } from "fs";
5+
import { getAuthenticatedPocketBase } from "$lib/server/auth";
66

77
const pb = await getAuthenticatedPocketBase();
88

99
async function getBacklinks(url) {
10-
const mdbaseCollection = pb.collection('mdbase');
11-
const documentUrl = url;
12-
try {
13-
if (!documentUrl) {
14-
return new Response(JSON.stringify({ message: 'URL parameter is required' }), {
15-
status: 400
16-
});
17-
}
10+
const mdbaseCollection = pb.collection("mdbase");
11+
const documentUrl = url;
12+
try {
13+
if (!documentUrl) {
14+
return new Response(
15+
JSON.stringify({ message: "URL parameter is required" }),
16+
{
17+
status: 400,
18+
},
19+
);
20+
}
1821

19-
const documents = await mdbaseCollection.getList(1, 1, {
20-
filter: `url="${documentUrl}"`,
21-
expand: 'backlinks'
22-
});
22+
const documents = await mdbaseCollection.getList(1, 1, {
23+
filter: `url="${documentUrl}"`,
24+
expand: "backlinks",
25+
});
2326

24-
if (documents.items.length === 0) {
25-
return new Response(JSON.stringify({ message: 'Document not found' }), { status: 404 });
26-
}
27+
if (documents.items.length === 0) {
28+
return new Response(JSON.stringify({ message: "Document not found" }), {
29+
status: 404,
30+
});
31+
}
2732

28-
const document = documents.items[0];
33+
const document = documents.items[0];
2934

30-
const backLinks = (document.expand?.backlinks || []).map((link) => ({
31-
id: link.id,
32-
title: link.title,
33-
url: link.url
34-
}));
35+
const backLinks = (document.expand?.backlinks || []).map((link) => ({
36+
id: link.id,
37+
title: link.title,
38+
url: link.url,
39+
}));
3540

36-
return backLinks;
37-
} catch (error: any) {
38-
console.error('Error in backlinks API:', error);
39-
return {};
40-
}
41+
return backLinks;
42+
} catch (error: any) {
43+
console.error("Error in backlinks API:", error);
44+
return {};
45+
}
4146
}
4247

4348
async function computeGraphData(fileUrl) {
44-
const currentPage = await pb.collection('mdbase').getFirstListItem(`url="${fileUrl}"`);
45-
const relatedPages = await pb.collection('mdbase').getList(1, 50, {
46-
filter: `id ?~ "${currentPage.backlinks}" || id ?~ "${currentPage.links}"`
47-
});
49+
const currentPage = await pb
50+
.collection("mdbase")
51+
.getFirstListItem(`url="${fileUrl}"`);
52+
const relatedPages = await pb.collection("mdbase").getList(1, 50, {
53+
filter: `id ?~ "${currentPage.backlinks}" || id ?~ "${currentPage.links}"`,
54+
});
4855

49-
// Use a Set to store unique node IDs
50-
const uniqueNodeIds = new Set([currentPage.id]);
56+
// Use a Set to store unique node IDs
57+
const uniqueNodeIds = new Set([currentPage.id]);
5158

52-
// Create nodes array with current page
53-
const nodes = [{ id: currentPage.id, label: currentPage.title, color: '#ff0000' }];
59+
// Create nodes array with current page
60+
const nodes = [
61+
{ id: currentPage.id, label: currentPage.title, color: "#ff0000" },
62+
];
5463

55-
// Add related pages to nodes array, avoiding duplicates
56-
relatedPages.items.forEach((p) => {
57-
if (!uniqueNodeIds.has(p.id)) {
58-
uniqueNodeIds.add(p.id);
59-
nodes.push({ id: p.id, label: p.title, color: '#00ff00' });
60-
}
61-
});
64+
// Add related pages to nodes array, avoiding duplicates
65+
relatedPages.items.forEach((p) => {
66+
if (!uniqueNodeIds.has(p.id)) {
67+
uniqueNodeIds.add(p.id);
68+
nodes.push({ id: p.id, label: p.title, color: "#00ff00" });
69+
}
70+
});
6271

63-
// Create edges array
64-
const edges = [
65-
...currentPage.links.map((link) => ({ from: currentPage.id, to: link })),
66-
...currentPage.backlinks.map((backlink) => ({ from: backlink, to: currentPage.id }))
67-
];
72+
// Create edges array
73+
const edges = [
74+
...currentPage.links.map((link) => ({ from: currentPage.id, to: link })),
75+
...currentPage.backlinks.map((backlink) => ({
76+
from: backlink,
77+
to: currentPage.id,
78+
})),
79+
];
6880

69-
return { nodes, edges };
81+
return { nodes, edges };
7082
}
7183
// Main load function
7284
export async function load({ params, fetch, locals }) {
73-
try {
74-
// Step 1: Authenticate
75-
/* console.log(pb); */
76-
console.log(params.post);
77-
const post = await pb
78-
.collection('mdbase')
79-
.getFirstListItem(`url="${params.post}.md"`, { expand: 'tags' });
80-
const backlinks = await getBacklinks(`${params.post}.md`);
81-
const graphData = await computeGraphData(`${params.post}.md`);
85+
try {
86+
// Step 1: Authenticate
87+
/* console.log(pb); */
88+
console.log(params.post);
89+
const post = await pb
90+
.collection("mdbase")
91+
.getFirstListItem(`url="${params.post}.md"`, { expand: "tags" });
92+
const backlinks = await getBacklinks(`${params.post}.md`);
93+
// const graphData = await computeGraphData(`${params.post}.md`);
8294

83-
const tags = post.expand?.tags.map((tag) => {
84-
return {
85-
name: tag.tag
86-
};
87-
});
88-
console.log(tags);
95+
const tags = post.expand?.tags.map((tag) => {
96+
return {
97+
name: tag.tag,
98+
};
99+
});
100+
console.log(tags);
89101

90-
return { post, title: post.title, backlinks, tags };
91-
} catch (error) {
92-
console.error(`Failed to fetch post: ${error}`);
93-
return { message: `Failed to fetch post: ${error}` };
94-
}
102+
return { post, title: post.title, backlinks, tags };
103+
} catch (error) {
104+
console.error(`Failed to fetch post: ${error}`);
105+
return { message: `Failed to fetch post: ${error}` };
106+
}
95107
}

0 commit comments

Comments
 (0)