Commit 5da1640d by PLN (Algolia)

feat: Upgade + poems v1

parent 2d582d25
---
title: "Hello World"
date: "2024-03-04"
language: "English"
tags: ["test", "sample"]
---
This is a sample poem to test the structure.
It supports **markdown** formatting and can include:
- Lists
- *Italics*
- **Bold text**
And even images:
<div style="text-align: center">
<img src="/images/sample.jpg" alt="Sample image" />
</div>
The content will be rendered as GitHub Flavored Markdown, supporting all standard markdown features.
\ No newline at end of file
import {getAllContentData, getAllContentIds, getContentData} from './utils'
export function getPoemsData(sortBy = 'date', sortOrder = 'desc') {
const poems = getAllContentData('poems', false);
// Default sort is by date
let sortedPoems = [...poems].sort((a, b) => {
if (a.date < b.date) return sortOrder === 'desc' ? 1 : -1;
if (a.date > b.date) return sortOrder === 'desc' ? -1 : 1;
return 0;
});
// Additional sorting options
if (sortBy === 'wordcount') {
sortedPoems.sort((a, b) => {
const aWords = a.contentHtml?.split(/\s+/).length || 0;
const bWords = b.contentHtml?.split(/\s+/).length || 0;
return sortOrder === 'desc' ? bWords - aWords : aWords - bWords;
});
}
return sortedPoems;
}
export function getAllPoemIds() {
return getAllContentIds("poems");
}
export async function getPoemData(id) {
return getContentData("poems", id);
}
\ No newline at end of file
import path from "path";
import fs from "fs";
import matter from "gray-matter";
import remark from "remark";
import html from "remark-html";
import { remark } from 'remark';
import remarkHtml from 'remark-html';
function getContentDirectory(name) {
return path.join(process.cwd(), "content", name)
......@@ -67,14 +67,14 @@ async function getContentData(name, id) {
// Use remark to convert markdown into HTML string
const processedContent = await remark()
.use(html)
.use(remarkHtml)
.process(matterResult.content);
const contentHtml = processedContent.toString();
console.log(matterResult);
if ("description" in matterResult.data) {
console.log("Got desc!");
const processedDescription = await remark()
.use(html)
.use(remarkHtml)
.process(matterResult.data.description);
matterResult.data.description = processedContent.toString();
......
const path = require('path');
module.exports = {
webpack: (config) => {
config.resolve.alias['@'] = path.resolve(__dirname);
return config;
},
};
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,33 +3,28 @@
"version": "0.2.0",
"private": true,
"scripts": {
"dev": "NODE_OPTIONS='--openssl-legacy-provider' next dev",
"build": "NODE_OPTIONS='--openssl-legacy-provider' next build",
"start": "NODE_OPTIONS='--openssl-legacy-provider' next start"
},
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"engines": {
"node": "18.x"
"node": ">=18.17.0"
},
"dependencies": {
"bootstrap": "^5.0.0-beta3",
"classnames": "^2.3.1",
"date-fns": "^2.21.1",
"gray-matter": "^4.0.2",
"next": "^10.1.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-player": "^2.9.0",
"react-syntax-highlighter": "^15.4.3",
"remark": "^13.0.0",
"remark-html": "^13.0.1"
"bootstrap": "^5.3.3",
"classnames": "^2.5.1",
"date-fns": "^3.3.1",
"gray-matter": "^4.0.3",
"next": "^15.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-player": "^2.14.1",
"react-syntax-highlighter": "^15.5.0",
"remark": "^14.0.0",
"remark-html": "^15.0.0"
},
"devDependencies": {
"@types/react": "^18.0.21",
"typescript": "^4.2.4"
"@types/react": "^18.2.61",
"typescript": "^5.3.3"
}
}
......@@ -43,35 +43,37 @@ export default function Home({ posts, talks }) {
</p>
</section>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<Link href="/parvagues/">
<h3>
…code into <em>music</em>
</h3>
<Link href="/parvagues/" className={utilStyles.sectionLink}>
…code into <em>music</em>
</Link>
<p className="description">
As <Link href="/parvagues/">ParVagues</Link>, I write patterns that
As <Link href="/parvagues/" className={utilStyles.inlineLink}>ParVagues</Link>, I write patterns that
shape soundwaves.
</p>
</section>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<Link href="/hydra/">
<h3>
…code into <em>animated pixelscapes</em>
</h3>
<Link href="/hydra/" className={utilStyles.sectionLink}>
…code into <em>animated pixelscapes</em>
</Link>
<p className="description">
Using <Link href="/hydra/">Hydra</Link>, I create animations that
Using <Link href="/hydra/" className={utilStyles.inlineLink}>Hydra</Link>, I create animations that
offer windows into other worlds.
</p>
</section>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<Link href="/talks/">
<h3>
…ideas into <em>talks</em>
</h3>
<Link href="/poesie/" className={utilStyles.sectionLink}>
…words into <em>thoughts</em>
</Link>
<p className="description">
I <Link href="/talks/">speak</Link> about topics I care about: from
A selection of texts scattered across note books and note apps.
</p>
</section>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<Link href="/talks/" className={utilStyles.sectionLink}>
…ideas into <em>talks</em>
</Link>
<p className="description">
I <Link href="/talks/" className={utilStyles.inlineLink}>speak</Link> about topics I care about: from
sharing my passions and teaching useful patterns, to questioning our
current mental models.
</p>
......@@ -80,8 +82,8 @@ export default function Home({ posts, talks }) {
<ul className={utilStyles.list}>
{talks.map(({ id, title, description }) => (
<li className={utilStyles.listItem} key={id}>
<Link href={`/talks#${id}`}>
<h4>{title}</h4>
<Link href={`/talks#${id}`} className={utilStyles.listItemLink}>
{title}
</Link>
{description && (
<small className={utilStyles.lightText}>{description}</small>
......
import { useState } from 'react';
import Head from 'next/head';
import Link from 'next/link';
import Layout from '../components/layout';
import Date from '../components/date';
import utilStyles from '../styles/utils.module.css';
import { getPoemsData } from '../lib/poems';
export async function getStaticProps() {
const poems = getPoemsData();
return {
props: {
poems,
},
};
}
export default function Poems({ poems }) {
const [sortBy, setSortBy] = useState('date');
const [sortOrder, setSortOrder] = useState('desc');
const [filterLanguage, setFilterLanguage] = useState('all');
const [filterTags, setFilterTags] = useState('all');
// Get unique languages and tags
const languages = ['all', ...new Set(poems.map(p => p.language || 'unknown'))];
const tags = ['all', ...new Set(poems.flatMap(p => p.tags || []))];
// Filter and sort poems
const filteredPoems = poems
.filter(p => filterLanguage === 'all' || p.language === filterLanguage)
.filter(p => filterTags === 'all' || (p.tags && p.tags.includes(filterTags)));
const sortedPoems = [...filteredPoems].sort((a, b) => {
if (sortBy === 'date') {
if (a.date < b.date) return sortOrder === 'desc' ? 1 : -1;
if (a.date > b.date) return sortOrder === 'desc' ? -1 : 1;
return 0;
}
if (sortBy === 'wordcount') {
const aWords = a.contentHtml?.split(/\s+/).length || 0;
const bWords = b.contentHtml?.split(/\s+/).length || 0;
return sortOrder === 'desc' ? bWords - aWords : aWords - bWords;
}
return 0;
});
return (
<Layout>
<Head>
<title>Poems</title>
</Head>
<div className={utilStyles.headingMd}>
<h1>Words into thoughts</h1>
<div className={utilStyles.filters}>
<div>
<label>Sort by: </label>
<select value={sortBy} onChange={(e) => setSortBy(e.target.value)}>
<option value="date">Date</option>
<option value="wordcount">Word count</option>
</select>
<select value={sortOrder} onChange={(e) => setSortOrder(e.target.value)}>
<option value="desc">Descending</option>
<option value="asc">Ascending</option>
</select>
</div>
<div>
<label>Language: </label>
<select value={filterLanguage} onChange={(e) => setFilterLanguage(e.target.value)}>
{languages.map(lang => (
<option key={lang} value={lang}>{lang}</option>
))}
</select>
</div>
<div>
<label>Tag: </label>
<select value={filterTags} onChange={(e) => setFilterTags(e.target.value)}>
{tags.map(tag => (
<option key={tag} value={tag}>{tag}</option>
))}
</select>
</div>
</div>
<ul className={utilStyles.list}>
{sortedPoems.map(({ id, title, date, language, tags }) => (
<li className={utilStyles.listItem} key={id}>
<Link href={`/poesie/${id}`} className={utilStyles.listItemLink}>
{title}
</Link>
<small className={utilStyles.lightText}>
<Date dateString={date} />
{language && ` • ${language}`}
{tags && tags.length > 0 && ` • ${tags.join(', ')}`}
</small>
</li>
))}
</ul>
</div>
</Layout>
);
}
\ No newline at end of file
import Head from 'next/head';
import Layout from '@/components/layout';
import Date from '@/components/date';
import utilStyles from '@/styles/utils.module.css';
import { getPoemData, getAllPoemIds } from '@/lib/poems';
export async function getStaticProps({ params }) {
const poemData = await getPoemData(params.id);
return {
props: {
poemData,
},
};
}
export async function getStaticPaths() {
const paths = getAllPoemIds();
return {
paths,
fallback: false,
};
}
export default function Poem({ poemData }) {
return (
<Layout>
<Head>
<title>{poemData.title}</title>
</Head>
<article>
<h1 className={utilStyles.headingXl}>{poemData.title}</h1>
<div className={utilStyles.lightText}>
<Date dateString={poemData.date} />
{poemData.language && ` • ${poemData.language}`}
{poemData.tags && poemData.tags.length > 0 && ` • ${poemData.tags.join(', ')}`}
</div>
<div
className={utilStyles.poemContent}
dangerouslySetInnerHTML={{ __html: poemData.contentHtml }}
/>
</article>
</Layout>
);
}
\ No newline at end of file
import Head from "next/head";
import Layout from "../../components/layout";
import Date from "../../components/date";
import Layout from "@/components/layout";
import Date from "@/components/date";
import utilStyles from "../../styles/utils.module.css";
import { getAllPostIds, getPostData } from "../../lib/posts";
import utilStyles from "@/styles/utils.module.css";
import { getAllPostIds, getPostData } from "@/lib/posts";
export async function getStaticProps({ params }) {
const postData = await getPostData(params.id);
......
User-agent: *
Disallow: /poems/
......@@ -50,3 +50,68 @@
.lightText {
color: #666;
}
.filters {
display: flex;
gap: 1rem;
margin-bottom: 2rem;
flex-wrap: wrap;
}
.filters select {
margin-left: 0.5rem;
padding: 0.25rem;
border: 1px solid #ddd;
border-radius: 4px;
}
.poemContent {
margin-top: 2rem;
line-height: 1.8;
white-space: pre-wrap;
}
.poemContent p {
margin: 1rem 0;
}
.poemContent img {
max-width: 100%;
height: auto;
margin: 1rem 0;
}
.listItemLink {
font-size: 1.5rem;
font-weight: bold;
text-decoration: none;
color: inherit;
display: block;
margin-bottom: 0.5rem;
}
.listItemLink:hover {
text-decoration: underline;
}
.sectionLink {
font-size: 1.5rem;
font-weight: bold;
text-decoration: none;
color: inherit;
display: block;
margin: 1rem 0;
}
.sectionLink:hover {
text-decoration: underline;
}
.inlineLink {
color: inherit;
text-decoration: underline;
}
.inlineLink:hover {
opacity: 0.8;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"engines": { "node": "20.x" }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment