Compare commits
5 commits
350f6f3865
...
e59c84bb2f
Author | SHA1 | Date | |
---|---|---|---|
|
e59c84bb2f | ||
|
6474fbcac1 | ||
|
f42d71a948 | ||
|
9411ec22c1 | ||
|
7e5f8ce06f |
15 changed files with 113 additions and 33 deletions
|
@ -19,8 +19,13 @@
|
||||||
|
|
||||||
let fuse;
|
let fuse;
|
||||||
let posts = [];
|
let posts = [];
|
||||||
|
let searchInitialized = false;
|
||||||
|
|
||||||
async function initializeSearch() {
|
async function initializeSearch() {
|
||||||
|
// Prevent multiple initializations
|
||||||
|
if (searchInitialized) return;
|
||||||
|
try {
|
||||||
|
// Fetch the search index
|
||||||
const response = await fetch('/search-index.json');
|
const response = await fetch('/search-index.json');
|
||||||
posts = await response.json();
|
posts = await response.json();
|
||||||
|
|
||||||
|
@ -29,6 +34,11 @@
|
||||||
threshold: 0.3,
|
threshold: 0.3,
|
||||||
includeMatches: true
|
includeMatches: true
|
||||||
});
|
});
|
||||||
|
searchInitialized = true;
|
||||||
|
document.getElementById('search-results').innerHTML = '';
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching search index:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function performSearch(query) {
|
function performSearch(query) {
|
||||||
|
@ -37,6 +47,8 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!searchInitialized) return;
|
||||||
|
|
||||||
const results = fuse.search(query);
|
const results = fuse.search(query);
|
||||||
const resultsElement = document.getElementById('search-results');
|
const resultsElement = document.getElementById('search-results');
|
||||||
|
|
||||||
|
@ -58,15 +70,28 @@
|
||||||
|
|
||||||
resultsElement.innerHTML = html;
|
resultsElement.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize search when the component mounts
|
|
||||||
initializeSearch();
|
|
||||||
|
|
||||||
// Add event listener for search input
|
// Add event listener for search input
|
||||||
const searchInput = document.getElementById('search-input');
|
const searchInput = document.getElementById('search-input');
|
||||||
|
|
||||||
|
// Initialize search only when the input is focused or clicked
|
||||||
|
searchInput.addEventListener('focus', initializeSearch);
|
||||||
|
searchInput.addEventListener('click', initializeSearch);
|
||||||
|
|
||||||
searchInput.addEventListener('input', (e) => {
|
searchInput.addEventListener('input', (e) => {
|
||||||
|
if (!searchInitialized) {
|
||||||
|
initializeSearch().then(() => {
|
||||||
performSearch(e.target.value);
|
performSearch(e.target.value);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
performSearch(e.target.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
searchInput.addEventListener('focus', () => {
|
||||||
|
if (!searchInitialized) {
|
||||||
|
document.getElementById('search-results').innerHTML = '<p>Loading search index...</p>';
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
import { defineCollection } from 'astro:content';
|
import { defineCollection } from 'astro:content';
|
||||||
import { blogs } from './blog/_schemas';
|
import { posts } from './posts/_schemas';
|
||||||
|
import { pages } from "./pages/_schemas";
|
||||||
|
|
||||||
const blogCollection = defineCollection({
|
const blogCollection = defineCollection({
|
||||||
type: 'content',
|
type: 'content',
|
||||||
schema: blogs,
|
schema: posts,
|
||||||
|
});
|
||||||
|
const pageCollection = defineCollection({
|
||||||
|
type: 'content',
|
||||||
|
schema: pages,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const collections = {
|
export const collections = {
|
||||||
'blog': blogCollection,
|
'posts': blogCollection,
|
||||||
|
'pages': pageCollection,
|
||||||
};
|
};
|
7
src/content/pages/_schemas.ts
Normal file
7
src/content/pages/_schemas.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { z } from 'astro:content';
|
||||||
|
|
||||||
|
export const pages = z.object({
|
||||||
|
title: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
heroImage: z.string().optional()
|
||||||
|
});
|
5
src/content/pages/test.md
Normal file
5
src/content/pages/test.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: 'Test Page'
|
||||||
|
description: 'This is a test page'
|
||||||
|
---
|
||||||
|
testestestest
|
|
@ -1,6 +1,6 @@
|
||||||
import { z } from 'astro:content';
|
import { z } from 'astro:content';
|
||||||
|
|
||||||
export const blogs = z.object({
|
export const posts = z.object({
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
pubDate: z.coerce.date(),
|
pubDate: z.coerce.date(),
|
21
src/pages/[...slug].astro
Normal file
21
src/pages/[...slug].astro
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
import Layout from '../layouts/Layout.astro';
|
||||||
|
import { getCollection } from "astro:content";
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const pageEntries = await getCollection('pages');
|
||||||
|
return pageEntries.map(entry => ({
|
||||||
|
params: { slug: entry.slug }, props: { entry },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
const { entry } = Astro.props;
|
||||||
|
const { Content } = await entry.render();
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title={`${entry.data.title} | Terminal Blog`} path={`/var/log/${entry.slug}`}>
|
||||||
|
<h1 class="post-title">{entry.data.title}</h1>
|
||||||
|
<div class="post-content">
|
||||||
|
<Content/>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
|
@ -2,7 +2,7 @@
|
||||||
import Layout from '../layouts/Layout.astro';
|
import Layout from '../layouts/Layout.astro';
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
|
|
||||||
const posts = await getCollection('blog');
|
const posts = await getCollection('posts');
|
||||||
posts.sort((a, b) => new Date(b.data.pubDate).getTime() - new Date(a.data.pubDate).getTime());
|
posts.sort((a, b) => new Date(b.data.pubDate).getTime() - new Date(a.data.pubDate).getTime());
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ posts.sort((a, b) => new Date(b.data.pubDate).getTime() - new Date(a.data.pubDat
|
||||||
{posts.map((post) => (
|
{posts.map((post) => (
|
||||||
<p>
|
<p>
|
||||||
<span style="color: var(--terminal-yellow);">{new Date(post.data.pubDate).toISOString().split('T')[0]}</span>
|
<span style="color: var(--terminal-yellow);">{new Date(post.data.pubDate).toISOString().split('T')[0]}</span>
|
||||||
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
|
<a href={`/post/${post.slug}`}>{post.data.title}</a>
|
||||||
</p>
|
</p>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Layout from '../../layouts/Layout.astro';
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const blogEntries = await getCollection('blog');
|
const blogEntries = await getCollection('posts');
|
||||||
return blogEntries.map(entry => ({
|
return blogEntries.map(entry => ({
|
||||||
params: { slug: entry.slug }, props: { entry },
|
params: { slug: entry.slug }, props: { entry },
|
||||||
}));
|
}));
|
25
src/pages/post/[...slug].txt.js
Normal file
25
src/pages/post/[...slug].txt.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { getCollection } from 'astro:content';
|
||||||
|
|
||||||
|
export const prerender = true;
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const blogEntries = await getCollection('posts');
|
||||||
|
return blogEntries.map(entry => ({
|
||||||
|
params: { slug: entry.slug }, props: { entry },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
export async function GET({ props }) {
|
||||||
|
const { entry } = props;
|
||||||
|
// Format the content as plain text
|
||||||
|
const title = entry.data.title;
|
||||||
|
const date = entry.data.pubDate.toISOString().split('T')[0];
|
||||||
|
const content = entry.body;
|
||||||
|
|
||||||
|
// Combine the post info and body into a single text file
|
||||||
|
const textContent = `Title: ${title}\nPublished at: ${date}\n\n${content}`;
|
||||||
|
|
||||||
|
return new Response(textContent, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ export async function GET(context) {
|
||||||
const container = await AstroContainer.create({ renderers });
|
const container = await AstroContainer.create({ renderers });
|
||||||
|
|
||||||
// Load the content collection entries to add to our RSS feed.
|
// Load the content collection entries to add to our RSS feed.
|
||||||
const posts = (await getCollection("blog")).sort((a, b) =>
|
const posts = (await getCollection("posts")).sort((a, b) =>
|
||||||
// Sort by publication date descending.
|
// Sort by publication date descending.
|
||||||
a.data.pubDate > b.data.pubDate ? -1 : 1
|
a.data.pubDate > b.data.pubDate ? -1 : 1
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const posts = await getCollection('blog');
|
const posts = await getCollection('posts');
|
||||||
const searchIndex = posts.map(post => ({
|
const searchIndex = posts.map(post => ({
|
||||||
title: post.data.title,
|
title: post.data.title,
|
||||||
description: post.data.description,
|
description: post.data.description,
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
}
|
}
|
||||||
/* Light theme */
|
/* Light theme */
|
||||||
@media (prefers-color-scheme: light) {
|
@media (prefers-color-scheme: light) {
|
||||||
:root {
|
:root:not([data-theme="dark"]) {
|
||||||
--bg-color: #f3f4f6;
|
--bg-color: #f3f4f6;
|
||||||
--text-color: #374151;
|
--text-color: #374151;
|
||||||
--accent-color: #3b82f6;
|
--accent-color: #3b82f6;
|
||||||
|
@ -23,16 +23,6 @@
|
||||||
--terminal-yellow: #d97706;
|
--terminal-yellow: #d97706;
|
||||||
--terminal-red: #dc2626;
|
--terminal-red: #dc2626;
|
||||||
}
|
}
|
||||||
:root:not([data-theme="light"]) {
|
|
||||||
--bg-color: #1f2937;
|
|
||||||
--text-color: #a5b4cf;
|
|
||||||
--accent-color: #64a0ff;
|
|
||||||
--border-color: #3b4351;
|
|
||||||
--header-color: #83a2ce;
|
|
||||||
--terminal-green: #4ade80;
|
|
||||||
--terminal-yellow: #fbbf24;
|
|
||||||
--terminal-red: #ef4444;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* Light theme override (for switch) */
|
/* Light theme override (for switch) */
|
||||||
:root[data-theme="light"] {
|
:root[data-theme="light"] {
|
||||||
|
@ -46,6 +36,7 @@
|
||||||
--terminal-red: #dc2626;
|
--terminal-red: #dc2626;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
*, *::before, *::after {
|
*, *::before, *::after {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue