Skip to content

Commit

Permalink
Allow setting home page, show titles instead of
Browse files Browse the repository at this point in the history
filename in sidebar, override data and make it
optional
  • Loading branch information
rishikanthc committed Oct 6, 2024
1 parent c3a8244 commit 347c66b
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 169 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ services:
- POCKETBASE_ADMIN_PASSWORD=password
- TITLE=Markopolis
- CAP1=Markdown
- CAP2="Self-hosted"
- CAP2="Self-hosting"
- CAP3="Knowledge Garden"
volumes:
- ./pb_data:/app/pb
5 changes: 3 additions & 2 deletions src/lib/components/FileTree.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
interface FileNode {
id: string;
title: string;
name: string;
url: string;
children: FileNode[];
Expand Down Expand Up @@ -53,9 +54,9 @@
{/if}

{#if node.url}
<a href={`/${node.url}`} class="text-carbongray-800 hover:underline">{node.name}</a>
<a href={`/${node.url}`} class="text-carbongray-800 hover:underline">{node.title}</a>
{:else}
<span class="font-semibold">{node.name}</span>
<span class="font-semibold">{node.title}</span>
{/if}
</div>

Expand Down
2 changes: 1 addition & 1 deletion src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
<Button class="z-20" on:click={toggleSidebar} variant="ghost" size="icon">
<Grip />
</Button>
<div class="title text-2xl">{siteTitle}</div>
<div class="title text-2xl break-words">{siteTitle}</div>
</div>
<div class="gap-0.1 flex">
<TagBar {tags} />
Expand Down
86 changes: 70 additions & 16 deletions src/routes/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,75 @@
import PocketBase from 'pocketbase';
import { getAuthenticatedPocketBase } from '$lib/server/auth';
import PocketBase from "pocketbase";
import { getAuthenticatedPocketBase } from "$lib/server/auth";

const pb = await getAuthenticatedPocketBase();

export async function load({ params }) {
try {
const mdbase = await pb.collections.getOne('mdbase');

const records = await pb.collection('mdbase').getList(1, 10, { sort: '-created' });
const posts = Object.values(records.items).map((item) => ({
title: item.title,
id: item.id,
date: item.created,
url: item.url
}));
return { posts };
} catch (error) {
return { posts: [], err: error };
}
try {
const mdbase = await pb.collections.getOne("mdbase");

const records = await pb.collection("mdbase").getList(1, 1, {
filter: "frontmatter.home = true",
sort: "-created",
});

let post = null;
if (records.items.length > 0) {
post = records.items[0];
}

if (post) {
const backlinks = await getBacklinks(`${post.frontmatter.mdpath}`);

const tags = post.expand?.tags.map((tag) => {
return {
name: tag.tag,
};
});
return { post, title: post.title, backlinks, tags };
} else {
return { post: null, title: "", backlinks: [], tags: [] };
}
} catch (error) {
console.error(`Failed to fetch post: ${error}`);
return { message: `Failed to fetch post: ${error}` };
}
}

async function getBacklinks(url) {
const mdbaseCollection = pb.collection("mdbase");
const documentUrl = url;
try {
if (!documentUrl) {
return new Response(
JSON.stringify({ message: "URL parameter is required" }),
{
status: 400,
},
);
}

const documents = await mdbaseCollection.getList(1, 1, {
filter: `url="${documentUrl}"`,
expand: "backlinks",
});

if (documents.items.length === 0) {
return new Response(JSON.stringify({ message: "Document not found" }), {
status: 404,
});
}

const document = documents.items[0];

const backLinks = (document.expand?.backlinks || []).map((link) => ({
id: link.id,
title: link.title,
url: link.url,
}));

return backLinks;
} catch (error: any) {
console.error("Error in backlinks API:", error);
return {};
}
}
74 changes: 53 additions & 21 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,27 +1,59 @@
<script>
export let data;
<script lang="ts">
import MDsvexRenderer from '$lib/components/MDsvexRenderer.svelte';
import MDGraph from '$lib/components/MDGraph.svelte';
import { CalendarDays } from 'lucide-svelte';
function formatDate(dateString) {
const date = new Date(dateString);
// Format the date as DD MMM YYYY
return date.toLocaleDateString('en-GB', {
day: '2-digit',
month: 'short',
year: 'numeric'
});
}
export let data: { content: string };
$: content = data.post?.content;
$: tags = data?.tags;
$: date = data.post?.created;
</script>

<div class="mb-6 text-4xl font-bold">Latest</div>
<div class="flex flex-col items-start justify-center gap-4">
{#if data && data.posts.length > 0}
{#each data.posts as p, id (id)}
<div class="flex flex-col items-start justify-center gap-0.5">
<div class="text-xl"><a href="/{p.url}">{p.title}</a></div>
<div class="text-sm text-gray-400">{formatDate(p.date)}</div>
{#if data.post}
<div class="mb-10 mt-6 text-wrap md:w-[700px]">
<div class="my-4 text-6xl md:text-8xl">
{data.title}
</div>

<div class="flex flex-col justify-center gap-1">
{#if data?.post?.frontmatter?.date}
<div class="flex items-center gap-1">
<CalendarDays class="text-carbongray-400" size={15} />
<div class="text-base text-carbongray-400">{data.post.frontmatter.date.split(' ')[0]}</div>
</div>
{/if}
{#if tags}
<div class="flex flex-wrap gap-1">
{#each tags as tag (tag.name)}
<span class="mx-0.5 rounded-sm bg-[#fedc69] p-0.5 text-carbongray-900"
><a class="text-carbongray-900 dark:text-carbongray-900" href="/tags/{tag.name}"
>{tag.name}</a
></span
>
{/each}
</div>
{/each}
{:else}
<div class="text-lg">Please upload markdown files to begin</div>
{/if}
</div>
<hr class="mt-6" />
</div>
<MDsvexRenderer bind:content />
<div>
{#if data?.backlinks?.length > 0}
<hr class="my-4 w-[700px]" />
<div class="mb-2 mt-4 text-2xl font-light">BACKLINKS</div>
{/if}
{#each data?.backlinks || [] as bl (bl.id)}
<div><a href={`/${bl.url.trim()}`} class="text-large">{bl.title}</a></div>
{/each}
</div>
{:else}
<div class="mb-10 mt-6 text-wrap md:w-[700px]">
Set homepage in the frontmatter of one of your markdown files to display it as home
</div>
{/if}

<style>
:global(.tag a) {
@apply mx-0.5 bg-[#fedc69] p-1 text-carbongray-900;
}
</style>
156 changes: 84 additions & 72 deletions src/routes/[...post].md/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,95 +1,107 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import PocketBase from 'pocketbase';
import { promises as fs } from 'fs';
import { getAuthenticatedPocketBase } from '$lib/server/auth';
import { json } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
import PocketBase from "pocketbase";
import { promises as fs } from "fs";
import { getAuthenticatedPocketBase } from "$lib/server/auth";

const pb = await getAuthenticatedPocketBase();

async function getBacklinks(url) {
const mdbaseCollection = pb.collection('mdbase');
const documentUrl = url;
try {
if (!documentUrl) {
return new Response(JSON.stringify({ message: 'URL parameter is required' }), {
status: 400
});
}
const mdbaseCollection = pb.collection("mdbase");
const documentUrl = url;
try {
if (!documentUrl) {
return new Response(
JSON.stringify({ message: "URL parameter is required" }),
{
status: 400,
},
);
}

const documents = await mdbaseCollection.getList(1, 1, {
filter: `url="${documentUrl}"`,
expand: 'backlinks'
});
const documents = await mdbaseCollection.getList(1, 1, {
filter: `url="${documentUrl}"`,
expand: "backlinks",
});

if (documents.items.length === 0) {
return new Response(JSON.stringify({ message: 'Document not found' }), { status: 404 });
}
if (documents.items.length === 0) {
return new Response(JSON.stringify({ message: "Document not found" }), {
status: 404,
});
}

const document = documents.items[0];
const document = documents.items[0];

const backLinks = (document.expand?.backlinks || []).map((link) => ({
id: link.id,
title: link.title,
url: link.url
}));
const backLinks = (document.expand?.backlinks || []).map((link) => ({
id: link.id,
title: link.title,
url: link.url,
}));

return backLinks;
} catch (error: any) {
console.error('Error in backlinks API:', error);
return {};
}
return backLinks;
} catch (error: any) {
console.error("Error in backlinks API:", error);
return {};
}
}

async function computeGraphData(fileUrl) {
const currentPage = await pb.collection('mdbase').getFirstListItem(`url="${fileUrl}"`);
const relatedPages = await pb.collection('mdbase').getList(1, 50, {
filter: `id ?~ "${currentPage.backlinks}" || id ?~ "${currentPage.links}"`
});
const currentPage = await pb
.collection("mdbase")
.getFirstListItem(`url="${fileUrl}"`);
const relatedPages = await pb.collection("mdbase").getList(1, 50, {
filter: `id ?~ "${currentPage.backlinks}" || id ?~ "${currentPage.links}"`,
});

// Use a Set to store unique node IDs
const uniqueNodeIds = new Set([currentPage.id]);
// Use a Set to store unique node IDs
const uniqueNodeIds = new Set([currentPage.id]);

// Create nodes array with current page
const nodes = [{ id: currentPage.id, label: currentPage.title, color: '#ff0000' }];
// Create nodes array with current page
const nodes = [
{ id: currentPage.id, label: currentPage.title, color: "#ff0000" },
];

// Add related pages to nodes array, avoiding duplicates
relatedPages.items.forEach((p) => {
if (!uniqueNodeIds.has(p.id)) {
uniqueNodeIds.add(p.id);
nodes.push({ id: p.id, label: p.title, color: '#00ff00' });
}
});
// Add related pages to nodes array, avoiding duplicates
relatedPages.items.forEach((p) => {
if (!uniqueNodeIds.has(p.id)) {
uniqueNodeIds.add(p.id);
nodes.push({ id: p.id, label: p.title, color: "#00ff00" });
}
});

// Create edges array
const edges = [
...currentPage.links.map((link) => ({ from: currentPage.id, to: link })),
...currentPage.backlinks.map((backlink) => ({ from: backlink, to: currentPage.id }))
];
// Create edges array
const edges = [
...currentPage.links.map((link) => ({ from: currentPage.id, to: link })),
...currentPage.backlinks.map((backlink) => ({
from: backlink,
to: currentPage.id,
})),
];

return { nodes, edges };
return { nodes, edges };
}
// Main load function
export async function load({ params, fetch, locals }) {
try {
// Step 1: Authenticate
/* console.log(pb); */
console.log(params.post);
const post = await pb
.collection('mdbase')
.getFirstListItem(`url="${params.post}.md"`, { expand: 'tags' });
const backlinks = await getBacklinks(`${params.post}.md`);
const graphData = await computeGraphData(`${params.post}.md`);
try {
// Step 1: Authenticate
/* console.log(pb); */
console.log(params.post);
const post = await pb
.collection("mdbase")
.getFirstListItem(`url="${params.post}.md"`, { expand: "tags" });
const backlinks = await getBacklinks(`${params.post}.md`);
// const graphData = await computeGraphData(`${params.post}.md`);

const tags = post.expand?.tags.map((tag) => {
return {
name: tag.tag
};
});
console.log(tags);
const tags = post.expand?.tags.map((tag) => {
return {
name: tag.tag,
};
});
console.log(tags);

return { post, title: post.title, backlinks, tags };
} catch (error) {
console.error(`Failed to fetch post: ${error}`);
return { message: `Failed to fetch post: ${error}` };
}
return { post, title: post.title, backlinks, tags };
} catch (error) {
console.error(`Failed to fetch post: ${error}`);
return { message: `Failed to fetch post: ${error}` };
}
}
Loading

0 comments on commit 347c66b

Please sign in to comment.