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 path from "path";
import fs from "fs"; import fs from "fs";
import matter from "gray-matter"; import matter from "gray-matter";
import remark from "remark"; import { remark } from 'remark';
import html from "remark-html"; import remarkHtml from 'remark-html';
function getContentDirectory(name) { function getContentDirectory(name) {
return path.join(process.cwd(), "content", name) return path.join(process.cwd(), "content", name)
...@@ -67,14 +67,14 @@ async function getContentData(name, id) { ...@@ -67,14 +67,14 @@ async function getContentData(name, id) {
// Use remark to convert markdown into HTML string // Use remark to convert markdown into HTML string
const processedContent = await remark() const processedContent = await remark()
.use(html) .use(remarkHtml)
.process(matterResult.content); .process(matterResult.content);
const contentHtml = processedContent.toString(); const contentHtml = processedContent.toString();
console.log(matterResult); console.log(matterResult);
if ("description" in matterResult.data) { if ("description" in matterResult.data) {
console.log("Got desc!"); console.log("Got desc!");
const processedDescription = await remark() const processedDescription = await remark()
.use(html) .use(remarkHtml)
.process(matterResult.data.description); .process(matterResult.data.description);
matterResult.data.description = processedContent.toString(); 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 @@ ...@@ -3,33 +3,28 @@
"version": "0.2.0", "version": "0.2.0",
"private": true, "private": true,
"scripts": { "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", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start" "start": "next start"
}, },
"engines": { "engines": {
"node": "18.x" "node": ">=18.17.0"
}, },
"dependencies": { "dependencies": {
"bootstrap": "^5.0.0-beta3", "bootstrap": "^5.3.3",
"classnames": "^2.3.1", "classnames": "^2.5.1",
"date-fns": "^2.21.1", "date-fns": "^3.3.1",
"gray-matter": "^4.0.2", "gray-matter": "^4.0.3",
"next": "^10.1.3", "next": "^15.3.0",
"react": "^17.0.2", "react": "^18.2.0",
"react-dom": "^17.0.2", "react-dom": "^18.2.0",
"react-player": "^2.9.0", "react-player": "^2.14.1",
"react-syntax-highlighter": "^15.4.3", "react-syntax-highlighter": "^15.5.0",
"remark": "^13.0.0", "remark": "^14.0.0",
"remark-html": "^13.0.1" "remark-html": "^15.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.0.21", "@types/react": "^18.2.61",
"typescript": "^4.2.4" "typescript": "^5.3.3"
} }
} }
...@@ -43,35 +43,37 @@ export default function Home({ posts, talks }) { ...@@ -43,35 +43,37 @@ export default function Home({ posts, talks }) {
</p> </p>
</section> </section>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}> <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<Link href="/parvagues/"> <Link href="/parvagues/" className={utilStyles.sectionLink}>
<h3> …code into <em>music</em>
…code into <em>music</em>
</h3>
</Link> </Link>
<p className="description"> <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. shape soundwaves.
</p> </p>
</section> </section>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}> <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<Link href="/hydra/"> <Link href="/hydra/" className={utilStyles.sectionLink}>
<h3> …code into <em>animated pixelscapes</em>
…code into <em>animated pixelscapes</em>
</h3>
</Link> </Link>
<p className="description"> <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. offer windows into other worlds.
</p> </p>
</section> </section>
<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}> <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
<Link href="/talks/"> <Link href="/poesie/" className={utilStyles.sectionLink}>
<h3> …words into <em>thoughts</em>
…ideas into <em>talks</em>
</h3>
</Link> </Link>
<p className="description"> <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 sharing my passions and teaching useful patterns, to questioning our
current mental models. current mental models.
</p> </p>
...@@ -80,8 +82,8 @@ export default function Home({ posts, talks }) { ...@@ -80,8 +82,8 @@ export default function Home({ posts, talks }) {
<ul className={utilStyles.list}> <ul className={utilStyles.list}>
{talks.map(({ id, title, description }) => ( {talks.map(({ id, title, description }) => (
<li className={utilStyles.listItem} key={id}> <li className={utilStyles.listItem} key={id}>
<Link href={`/talks#${id}`}> <Link href={`/talks#${id}`} className={utilStyles.listItemLink}>
<h4>{title}</h4> {title}
</Link> </Link>
{description && ( {description && (
<small className={utilStyles.lightText}>{description}</small> <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 Head from "next/head";
import Layout from "../../components/layout"; import Layout from "@/components/layout";
import Date from "../../components/date"; import Date from "@/components/date";
import utilStyles from "../../styles/utils.module.css"; import utilStyles from "@/styles/utils.module.css";
import { getAllPostIds, getPostData } from "../../lib/posts"; import { getAllPostIds, getPostData } from "@/lib/posts";
export async function getStaticProps({ params }) { export async function getStaticProps({ params }) {
const postData = await getPostData(params.id); const postData = await getPostData(params.id);
......
User-agent: *
Disallow: /poems/
...@@ -50,3 +50,68 @@ ...@@ -50,3 +50,68 @@
.lightText { .lightText {
color: #666; 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