- {#if prevPost}
-
{prevPost.title}
-
-
Previous Post
+
+ {#if nextPost}
+
{nextPost.title}
+
{:else}
-
You are reading our first post.
+
You're up to date. More to come soon!
{/if}
@@ -64,11 +64,12 @@
}
.nextPost {
- border-right: 1px solid #979797;
+ border-left: 1px solid #979797;
+ text-align: right;
}
.previousPost {
- text-align: right;
+ text-align: left;
}
.arrow {
@@ -77,11 +78,11 @@
}
.arrowNext {
- justify-content: flex-start;
+ justify-content: flex-end;
}
.arrowPrevious {
- justify-content: flex-end;
+ justify-content: flex-start;
}
.inactive {
diff --git a/src/lib/components/singletons/SearchBar.svelte b/src/lib/components/singletons/SearchBar.svelte
new file mode 100644
index 0000000..272b415
--- /dev/null
+++ b/src/lib/components/singletons/SearchBar.svelte
@@ -0,0 +1,238 @@
+
+
+
+
+ {#if showInput}
+
+
+
+ {#if searchTerm}
+
+ {/if}
+
+ {:else}
+
+ {/if}
+
+ {#if search === 'ready' && searchTerm}
+
+ {#if results.length > 0}
+
+ {:else}
+
No results found for query "{searchTerm}"
+ {/if}
+
+ {/if}
+
+
+
diff --git a/src/lib/utils/search.ts b/src/lib/utils/search.ts
new file mode 100644
index 0000000..f7bbea4
--- /dev/null
+++ b/src/lib/utils/search.ts
@@ -0,0 +1,70 @@
+import FlexSearch from 'flexsearch';
+import type { BlogPost } from '$lib/utils/types';
+
+interface Post {
+ slug: string;
+ title: string;
+ excerpt: string;
+ tags: string[];
+}
+
+let postsIndex: FlexSearch.Index;
+let posts: Post[];
+
+export function createPostsIndex(data: BlogPost[]) {
+ postsIndex = new FlexSearch.Index({ tokenize: 'forward' });
+
+ const mappedPosts = data.map((post) => ({
+ slug: post.slug,
+ title: post.title,
+ excerpt: post.excerpt || '',
+ tags: post.tags
+ }));
+
+ mappedPosts.forEach((post, i) => {
+ const item = `${post.title} ${post.excerpt} ${post.tags}`;
+ postsIndex.add(i, item);
+ });
+
+ posts = mappedPosts;
+}
+
+export function searchPostsIndex(searchTerm: string) {
+ const match = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ const results = postsIndex.search(match);
+
+ return results
+ .map((index) => posts[index as number])
+ .map(({ slug, title, excerpt, tags }) => {
+ return {
+ slug,
+ title: replaceTextWithMarker(title, match),
+ content: getMatches(excerpt, match),
+ tags: tags.map((tag) => replaceTextWithMarker(tag, match))
+ };
+ });
+}
+
+function replaceTextWithMarker(text: string, match: string) {
+ const regex = new RegExp(match, 'gi');
+ return text.replaceAll(regex, (match) => `
${match}`);
+}
+
+function getMatches(text: string, searchTerm: string, limit = 1) {
+ const regex = new RegExp(searchTerm, 'gi');
+ const indexes = [];
+ let matches = 0;
+ let match;
+
+ while ((match = regex.exec(text)) !== null && matches < limit) {
+ indexes.push(match.index);
+ matches++;
+ }
+
+ return indexes.map((index) => {
+ const start = Math.max(0, index - 20);
+ const end = Math.min(text.length, index + 80);
+ const excerpt = text.substring(start, end).trim();
+ return `...${replaceTextWithMarker(excerpt, searchTerm)}...`;
+ });
+}
diff --git a/src/routes/(blog-article)/+layout.svelte b/src/routes/(blog-article)/+layout.svelte
index cdffdd0..2b8ddff 100644
--- a/src/routes/(blog-article)/+layout.svelte
+++ b/src/routes/(blog-article)/+layout.svelte
@@ -1,7 +1,5 @@
-
-
@@ -64,8 +60,6 @@