Update content documentation and implement basic learn page
This commit is contained in:
@@ -93,6 +93,9 @@ export default async function BlogPostPage({ params }) {
|
|||||||
// Get related articles with improved algorithm
|
// Get related articles with improved algorithm
|
||||||
const allPosts = getAllPosts();
|
const allPosts = getAllPosts();
|
||||||
|
|
||||||
|
// Create slug order for consistent background cycling
|
||||||
|
const slugOrder = allPosts.map((post) => post.slug);
|
||||||
|
|
||||||
// Simple related articles algorithm based on content similarity
|
// Simple related articles algorithm based on content similarity
|
||||||
const getRelatedArticles = (currentPost, allPosts, limit = 3) => {
|
const getRelatedArticles = (currentPost, allPosts, limit = 3) => {
|
||||||
const otherPosts = allPosts.filter((p) => p.slug !== currentPost.slug);
|
const otherPosts = allPosts.filter((p) => p.slug !== currentPost.slug);
|
||||||
@@ -265,6 +268,7 @@ export default async function BlogPostPage({ params }) {
|
|||||||
<RelatedArticles
|
<RelatedArticles
|
||||||
relatedPosts={relatedArticles}
|
relatedPosts={relatedArticles}
|
||||||
currentPostSlug={post.slug}
|
currentPostSlug={post.slug}
|
||||||
|
slugOrder={slugOrder}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Ask Organizer Section */}
|
{/* Ask Organizer Section */}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { getAllBlogPosts } from "../../lib/content";
|
import { getAllBlogPosts } from "../../lib/content";
|
||||||
import Header from "../components/Header";
|
|
||||||
import ContentThumbnailTemplate from "../components/ContentThumbnailTemplate";
|
import ContentThumbnailTemplate from "../components/ContentThumbnailTemplate";
|
||||||
import ContentContainer from "../components/ContentContainer";
|
import ContentContainer from "../components/ContentContainer";
|
||||||
|
|
||||||
@@ -31,7 +30,6 @@ export default function BlogPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[#F4F3F1]">
|
<div className="min-h-screen bg-[#F4F3F1]">
|
||||||
<Header />
|
|
||||||
<main className="pt-16">
|
<main className="pt-16">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ const ContentThumbnailTemplate = ({
|
|||||||
post,
|
post,
|
||||||
className = "",
|
className = "",
|
||||||
variant = "vertical", // Internal prop for testing/development
|
variant = "vertical", // Internal prop for testing/development
|
||||||
|
slugOrder = [], // Array of slugs for consistent icon cycling
|
||||||
}) => {
|
}) => {
|
||||||
// Post-specific background selection - different SVG for each post
|
// Post-specific background selection - different SVG for each post
|
||||||
const getBackgroundImage = (slug, variant) => {
|
const getBackgroundImage = (slug, variant, slugOrder) => {
|
||||||
const verticalImages = [
|
const verticalImages = [
|
||||||
getAssetPath(ASSETS.VERTICAL_1),
|
getAssetPath(ASSETS.VERTICAL_1),
|
||||||
getAssetPath(ASSETS.VERTICAL_2),
|
getAssetPath(ASSETS.VERTICAL_2),
|
||||||
@@ -28,23 +29,20 @@ const ContentThumbnailTemplate = ({
|
|||||||
getAssetPath(ASSETS.HORIZONTAL_3),
|
getAssetPath(ASSETS.HORIZONTAL_3),
|
||||||
];
|
];
|
||||||
|
|
||||||
const images = variant === "vertical" ? verticalImages : horizontalImages;
|
if (!slug)
|
||||||
|
return variant === "vertical" ? verticalImages[0] : horizontalImages[0];
|
||||||
|
|
||||||
if (!slug) return images[0];
|
// Use the passed slugOrder for consistent cycling through background variants
|
||||||
|
|
||||||
// Simple cycling approach to ensure different styles
|
|
||||||
const slugOrder = [
|
|
||||||
"building-community-trust",
|
|
||||||
"operational-security-mutual-aid",
|
|
||||||
"making-decisions-without-hierarchy",
|
|
||||||
"resolving-active-conflicts",
|
|
||||||
];
|
|
||||||
const index = slugOrder.indexOf(slug);
|
const index = slugOrder.indexOf(slug);
|
||||||
const finalIndex = index >= 0 ? index % images.length : 0;
|
const backgroundIndex = index >= 0 ? index % 3 : 0; // Cycle through 3 background variants
|
||||||
return images[finalIndex];
|
|
||||||
|
// Return the same background index for both vertical and horizontal variants
|
||||||
|
return variant === "vertical"
|
||||||
|
? verticalImages[backgroundIndex]
|
||||||
|
: horizontalImages[backgroundIndex];
|
||||||
};
|
};
|
||||||
|
|
||||||
const backgroundImage = getBackgroundImage(post.slug, variant);
|
const backgroundImage = getBackgroundImage(post.slug, variant, slugOrder);
|
||||||
|
|
||||||
if (variant === "vertical") {
|
if (variant === "vertical") {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { getAssetPath, ASSETS } from "../../lib/assetUtils";
|
|||||||
// Configuration data for testing
|
// Configuration data for testing
|
||||||
export const navigationItems = [
|
export const navigationItems = [
|
||||||
{ href: "#", text: "Use cases", extraPadding: true },
|
{ href: "#", text: "Use cases", extraPadding: true },
|
||||||
{ href: "#", text: "Learn" },
|
{ href: "/learn", text: "Learn" },
|
||||||
{ href: "#", text: "About" },
|
{ href: "#", text: "About" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default function HomeHeader() {
|
|||||||
|
|
||||||
const navigationItems = [
|
const navigationItems = [
|
||||||
{ href: "#", text: "Use cases", extraPadding: true },
|
{ href: "#", text: "Use cases", extraPadding: true },
|
||||||
{ href: "#", text: "Learn" },
|
{ href: "/learn", text: "Learn" },
|
||||||
{ href: "#", text: "About" },
|
{ href: "#", text: "About" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,14 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import ContentThumbnailTemplate from "./ContentThumbnailTemplate";
|
import ContentThumbnailTemplate from "./ContentThumbnailTemplate";
|
||||||
|
|
||||||
export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
|
export default function RelatedArticles({
|
||||||
|
relatedPosts,
|
||||||
|
currentPostSlug,
|
||||||
|
slugOrder = [],
|
||||||
|
}) {
|
||||||
// Filter out the current post from related posts
|
// Filter out the current post from related posts
|
||||||
const filteredPosts = relatedPosts.filter(
|
const filteredPosts = relatedPosts.filter(
|
||||||
(post) => post.slug !== currentPostSlug,
|
(post) => post.slug !== currentPostSlug
|
||||||
);
|
);
|
||||||
|
|
||||||
const [currentIndex, setCurrentIndex] = useState(0);
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
@@ -93,7 +97,7 @@ export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
|
|||||||
const handleMouseUp = () => {
|
const handleMouseUp = () => {
|
||||||
document.removeEventListener(
|
document.removeEventListener(
|
||||||
"mousemove",
|
"mousemove",
|
||||||
handleMouseMove,
|
handleMouseMove
|
||||||
);
|
);
|
||||||
document.removeEventListener("mouseup", handleMouseUp);
|
document.removeEventListener("mouseup", handleMouseUp);
|
||||||
};
|
};
|
||||||
@@ -112,6 +116,7 @@ export default function RelatedArticles({ relatedPosts, currentPostSlug }) {
|
|||||||
<ContentThumbnailTemplate
|
<ContentThumbnailTemplate
|
||||||
post={relatedPost}
|
post={relatedPost}
|
||||||
variant="vertical"
|
variant="vertical"
|
||||||
|
slugOrder={slugOrder}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import ContentThumbnailTemplate from "../components/ContentThumbnailTemplate";
|
||||||
|
|
||||||
|
// Mock blog post data for testing
|
||||||
|
const mockPost1 = {
|
||||||
|
slug: "resolving-active-conflicts",
|
||||||
|
frontmatter: {
|
||||||
|
title: "Resolving Active Conflicts",
|
||||||
|
description:
|
||||||
|
"Practical steps for resolving conflicts while maintaining trust, cooperation, and shared goals",
|
||||||
|
author: "Author name",
|
||||||
|
date: "2025-04-15",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockPost2 = {
|
||||||
|
slug: "operational-security-mutual-aid",
|
||||||
|
frontmatter: {
|
||||||
|
title: "Operational Security for Mutual Aid",
|
||||||
|
description:
|
||||||
|
"Tactics to protect members, secure communication, and prevent Infiltration",
|
||||||
|
author: "Author name",
|
||||||
|
date: "2025-04-10",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockPost3 = {
|
||||||
|
slug: "making-decisions-without-hierarchy",
|
||||||
|
frontmatter: {
|
||||||
|
title: "Making decisions without hierarchy",
|
||||||
|
description:
|
||||||
|
"A brief guide to collaborative nonhierarchical decision making",
|
||||||
|
author: "Author name",
|
||||||
|
date: "2025-04-05",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function LearnPage() {
|
||||||
|
// Mock slug order for consistent background cycling
|
||||||
|
const mockSlugOrder = [
|
||||||
|
"resolving-active-conflicts",
|
||||||
|
"operational-security-mutual-aid",
|
||||||
|
"making-decisions-without-hierarchy",
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-[#F4F3F1]">
|
||||||
|
<div className="max-w-6xl mx-auto p-8 pt-24">
|
||||||
|
<h1 className="text-3xl font-bold text-[var(--color-content-default-primary)] mb-8">
|
||||||
|
Learn
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div className="space-y-12">
|
||||||
|
{/* Featured Articles */}
|
||||||
|
<section>
|
||||||
|
<h2 className="text-2xl font-semibold text-[var(--color-content-default-primary)] mb-6">
|
||||||
|
Featured Articles
|
||||||
|
</h2>
|
||||||
|
<div className="flex flex-wrap gap-6">
|
||||||
|
<ContentThumbnailTemplate
|
||||||
|
post={mockPost1}
|
||||||
|
className="mb-4"
|
||||||
|
slugOrder={mockSlugOrder}
|
||||||
|
/>
|
||||||
|
<ContentThumbnailTemplate
|
||||||
|
post={mockPost2}
|
||||||
|
className="mb-4"
|
||||||
|
slugOrder={mockSlugOrder}
|
||||||
|
/>
|
||||||
|
<ContentThumbnailTemplate
|
||||||
|
post={mockPost3}
|
||||||
|
className="mb-4"
|
||||||
|
slugOrder={mockSlugOrder}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* More Articles */}
|
||||||
|
<section>
|
||||||
|
<h2 className="text-2xl font-semibold text-[var(--color-content-default-primary)] mb-6">
|
||||||
|
More Articles
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<ContentThumbnailTemplate
|
||||||
|
post={mockPost1}
|
||||||
|
variant="horizontal"
|
||||||
|
slugOrder={mockSlugOrder}
|
||||||
|
/>
|
||||||
|
<ContentThumbnailTemplate
|
||||||
|
post={mockPost2}
|
||||||
|
variant="horizontal"
|
||||||
|
slugOrder={mockSlugOrder}
|
||||||
|
/>
|
||||||
|
<ContentThumbnailTemplate
|
||||||
|
post={mockPost3}
|
||||||
|
variant="horizontal"
|
||||||
|
slugOrder={mockSlugOrder}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Coming Soon */}
|
||||||
|
<section className="bg-white p-6 rounded-lg shadow">
|
||||||
|
<h2 className="text-xl font-semibold text-[var(--color-content-default-primary)] mb-4">
|
||||||
|
More Content Coming Soon
|
||||||
|
</h2>
|
||||||
|
<p className="text-[var(--color-content-default-secondary)]">
|
||||||
|
We're working on adding more educational content to help you build
|
||||||
|
better communities. Check back soon for new articles and
|
||||||
|
resources.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
import ContentThumbnailTemplate from "../components/ContentThumbnailTemplate";
|
|
||||||
|
|
||||||
// Mock blog post data for testing
|
|
||||||
const mockPost1 = {
|
|
||||||
slug: "resolving-active-conflicts",
|
|
||||||
frontmatter: {
|
|
||||||
title: "Resolving Active Conflicts",
|
|
||||||
description:
|
|
||||||
"Practical steps for resolving conflicts while maintaining trust, cooperation, and shared goals",
|
|
||||||
author: "Author name",
|
|
||||||
date: "2025-04-15",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockPost2 = {
|
|
||||||
slug: "operational-security-mutual-aid",
|
|
||||||
frontmatter: {
|
|
||||||
title: "Operational Security for Mutual Aid",
|
|
||||||
description:
|
|
||||||
"Tactics to protect members, secure communication, and prevent Infiltration",
|
|
||||||
author: "Author name",
|
|
||||||
date: "2025-04-10",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockPost3 = {
|
|
||||||
slug: "making-decisions-without-hierarchy",
|
|
||||||
frontmatter: {
|
|
||||||
title: "Making decisions without hierarchy",
|
|
||||||
description:
|
|
||||||
"A brief guide to collaborative nonhierarchical decision making",
|
|
||||||
author: "Author name",
|
|
||||||
date: "2025-04-05",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function TestThumbnailPage() {
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen bg-gray-50 p-8">
|
|
||||||
<div className="max-w-6xl mx-auto">
|
|
||||||
<h1 className="text-3xl font-bold text-gray-900 mb-8">
|
|
||||||
ContentThumbnailTemplate Test
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div className="space-y-12">
|
|
||||||
{/* Vertical Variant */}
|
|
||||||
<section>
|
|
||||||
<h2 className="text-2xl font-semibold text-gray-800 mb-6">
|
|
||||||
Vertical Variant
|
|
||||||
</h2>
|
|
||||||
<div className="flex flex-wrap gap-6">
|
|
||||||
<ContentThumbnailTemplate post={mockPost1} className="mb-4" />
|
|
||||||
<ContentThumbnailTemplate post={mockPost2} className="mb-4" />
|
|
||||||
<ContentThumbnailTemplate post={mockPost3} className="mb-4" />
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Horizontal Variant */}
|
|
||||||
<section>
|
|
||||||
<h2 className="text-2xl font-semibold text-gray-800 mb-6">
|
|
||||||
Horizontal Variant
|
|
||||||
</h2>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<ContentThumbnailTemplate post={mockPost1} variant="horizontal" />
|
|
||||||
<ContentThumbnailTemplate post={mockPost2} variant="horizontal" />
|
|
||||||
<ContentThumbnailTemplate post={mockPost3} variant="horizontal" />
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Component Props */}
|
|
||||||
<section className="bg-white p-6 rounded-lg shadow">
|
|
||||||
<h2 className="text-xl font-semibold text-gray-800 mb-4">
|
|
||||||
Component Props
|
|
||||||
</h2>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
|
|
||||||
<div>
|
|
||||||
<h3 className="font-medium text-gray-700 mb-2">
|
|
||||||
Required Props:
|
|
||||||
</h3>
|
|
||||||
<ul className="space-y-1 text-gray-600">
|
|
||||||
<li>
|
|
||||||
<code>post</code> - Blog post object with frontmatter
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className="font-medium text-gray-700 mb-2">
|
|
||||||
Optional Props:
|
|
||||||
</h3>
|
|
||||||
<ul className="space-y-1 text-gray-600">
|
|
||||||
<li>
|
|
||||||
<code>className</code> - Additional CSS classes
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<code>variant</code> - "vertical" (default) or
|
|
||||||
"horizontal" (for development/testing)
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Mock Data */}
|
|
||||||
<section className="bg-white p-6 rounded-lg shadow">
|
|
||||||
<h2 className="text-xl font-semibold text-gray-800 mb-4">
|
|
||||||
Mock Data Structure
|
|
||||||
</h2>
|
|
||||||
<pre className="bg-gray-100 p-4 rounded text-sm overflow-x-auto">
|
|
||||||
{JSON.stringify(mockPost1, null, 2)}
|
|
||||||
</pre>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,31 @@
|
|||||||
|
|
||||||
A simple guide for creating blog content for Community Rule.
|
A simple guide for creating blog content for Community Rule.
|
||||||
|
|
||||||
|
## How to Upload an Article
|
||||||
|
|
||||||
|
Here's how to contribute a new article:
|
||||||
|
|
||||||
|
1. **Fork the repository** (if you haven't already)
|
||||||
|
2. **Create a new branch** for your article: `git checkout -b add-my-article-title`
|
||||||
|
3. **Create your article file** in the `content/blog/` directory
|
||||||
|
4. **Test locally** (optional but recommended):
|
||||||
|
- Run `npm install` to install dependencies
|
||||||
|
- Run `npm run dev` to start the development server
|
||||||
|
- Visit `http://localhost:3000/blog/your-article-slug` to preview
|
||||||
|
5. **Commit your changes**:
|
||||||
|
```bash
|
||||||
|
git add content/blog/your-article.md
|
||||||
|
git commit -m "Add article: Your Article Title"
|
||||||
|
```
|
||||||
|
6. **Push to your fork**:
|
||||||
|
```bash
|
||||||
|
git push origin add-my-article-title
|
||||||
|
```
|
||||||
|
7. **Create a pull request** in Gitea with:
|
||||||
|
- Clear title describing your article
|
||||||
|
- Brief description of what the article covers
|
||||||
|
- Any relevant context or notes for reviewers
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
1. **Copy the template**: Use `content/blog/_template.md` as your starting point
|
1. **Copy the template**: Use `content/blog/_template.md` as your starting point
|
||||||
|
|||||||
Reference in New Issue
Block a user