Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions content/news/all-things-ai-2026-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: "All Things AI 2026"
date: "2026-05-03"
category: "Event"
excerpt: "Using Mellea to reliably get information from documents with a small model using Docling and Granite"
url: "https://2026.allthingsai.org/sessions/from-unstructured-documents-to-actionable-insights-a-workshop-on-docling-granite-and-mellea"
source: "All Things AI"
---
8 changes: 8 additions & 0 deletions content/news/mellea-v0.5-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: "Mellea v0.5 Released"
date: "2026-04-07"
category: "Release"
excerpt: "This release contains maintainence and new capabilities for streaming and telemetry, and more."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo.

Suggested change
excerpt: "This release contains maintainence and new capabilities for streaming and telemetry, and more."
excerpt: "This release contains maintenance and new capabilities for streaming and telemetry, and more."

url: "https://github.com/generative-computing/mellea/releases/tag/v0.5.0"
source: "GitHub"
---
8 changes: 8 additions & 0 deletions content/news/nyt-techweek-2026-june.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filename nit (no inline rename possible, flagging here): nyt- reads as "New York Times". The event is "NY Tech Week"; ny-tech-week-2026-june.md is clearer.

title: "NY Tech Week: Generative Computing Masterclass"
date: "2026-06-01"
category: "Event"
excerpt: "Generative Computing Masterclass: Building Predictable, Auditable AI with Mellea. https://www.tech-week.com/calendar/nyc/tracks/ai-infra"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The excerpt has a raw URL appended, which renders as unclickable plain text in the card. The card already has its own url field; the excerpt should be prose only.

Suggested change
excerpt: "Generative Computing Masterclass: Building Predictable, Auditable AI with Mellea. https://www.tech-week.com/calendar/nyc/tracks/ai-infra"
excerpt: "Generative Computing Masterclass: Building Predictable, Auditable AI with Mellea."

url: "https://partiful.com/e/3WdKVdPlKG4V9vvsgNBa"
source: "NY Tech Week"
---
113 changes: 102 additions & 11 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -850,31 +850,122 @@ a {
}

/* ── Stats / Feature strip ── */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale section header from the removed feature-strip code, sitting directly above the new News Highlights block.

Suggested change
/* ── Stats / Feature strip ── */
/* ── News Highlights ── */

(and delete the duplicate /* ── News Highlights ── */ on the next line)

.feature-strip {
/* ── News Highlights ── */
.news-section {
margin: 3rem -2rem 0;
padding: 1.5rem 2rem 1.75rem;
background: var(--bg-secondary);
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
}

.news-section-label {
font-family: var(--font-mono);
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--text-tertiary);
margin-bottom: 0.75rem;
}

.news-strip {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1px;
background: var(--border);
margin: 3rem 0;
}
Comment on lines +872 to 877
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gap: 1px; background: var(--border) trick produces an unbordered, full-width orphan card whenever item count isn't a multiple of the column count (visible at 5 items today). .blog-grid (L530-535) solved the same problem with real borders. Cheapest mitigation here is auto-fill instead of auto-fit — keeps empty tracks reserved so the orphan stays its minmax size:

Suggested change
.news-strip {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1px;
background: var(--border);
margin: 3rem 0;
}
.news-strip {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 1px;
background: var(--border);
}

Moot if we cap to 3-4 items on the homepage and never let an orphan happen.


.feature-item {
.news-card {
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 1.25rem 1.5rem;
padding-left: calc(1.5rem + 2px);
background: var(--bg-card);
padding: 2rem;
border-left: 2px solid var(--accent-blue);
transition: background 0.15s, border-color 0.15s;
text-decoration: none;
color: inherit;
}

.news-card:hover {
background: var(--bg-card-hover);
}

.news-card-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
}

.feature-number {
.news-card-category {
font-family: var(--font-mono);
font-size: 2rem;
font-size: 0.6rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--accent-blue);
display: block;
margin-bottom: 0.25rem;
background: rgba(69, 137, 255, 0.1);
padding: 0.2rem 0.5rem;
border-radius: 2px;
}

.feature-label {
font-size: 0.85rem;
.news-card[data-category="event"] .news-card-category {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSS themes event, integration, and community chips, but Release (used in mellea-v0.5-release.md) falls back to default blue with no themed treatment. Intentional (releases own the brand color), or should Release get its own chip color?

color: var(--accent-green);
background: rgba(66, 190, 101, 0.1);
}

.news-card[data-category="integration"] .news-card-category {
color: var(--accent-purple);
background: rgba(165, 110, 255, 0.1);
}

.news-card[data-category="community"] .news-card-category {
color: var(--accent-cyan);
background: rgba(51, 177, 255, 0.1);
}

.news-card-date {
font-size: 0.7rem;
color: var(--text-tertiary);
}

.news-card-title {
font-size: 0.875rem;
font-weight: 600;
color: var(--text-primary);
line-height: 1.4;
}

.news-card-excerpt {
font-size: 0.8rem;
color: var(--text-secondary);
line-height: 1.55;
}

.news-card-link {
font-family: var(--font-mono);
font-size: 0.7rem;
color: var(--accent-blue);
margin-top: auto;
}

.news-card:hover .news-card-link {
text-decoration: underline;
}

.news-card[data-category="event"] {
border-left-color: var(--accent-green);
}

.news-card[data-category="integration"] {
border-left-color: var(--accent-purple);
}

.news-card[data-category="community"] {
border-left-color: var(--accent-cyan);
}

/* ── How it works ── */
Expand Down
23 changes: 6 additions & 17 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import ImageCompare from '@/components/ImageCompare';
import InstallCommand from '@/components/InstallCommand';
import CodeShowcase from '@/components/CodeShowcase';
import { getAllBlogs } from '@/lib/blogs';
import { getAllNews } from '@/lib/news';
import NewsHighlights from '@/components/NewsHighlights';

const basePath = process.env.NEXT_PUBLIC_BASE_PATH || '';

export default function HomePage() {
const blogs = getAllBlogs();
const recent = blogs.slice(0, 3);
const news = getAllNews();

return (
<>
Expand Down Expand Up @@ -51,23 +54,9 @@ export default function HomePage() {
</div>
</div>

<div className="feature-strip">
<div className="feature-item">
<span className="feature-number">Unit</span>
<span className="feature-label">testable</span>
</div>
<div className="feature-item">
<span className="feature-number">100%</span>
<span className="feature-label">Open source</span>
</div>
<div className="feature-item">
<span className="feature-number">Typed</span>
<span className="feature-label">constrained output</span>
</div>
<div className="feature-item">
<span className="feature-number">Any</span>
<span className="feature-label">LLM provider</span>
</div>
<div className="news-section">
<p className="news-section-label">Latest News</p>
<NewsHighlights items={news} />
</div>
</div>
</section>
Expand Down
37 changes: 37 additions & 0 deletions src/components/NewsHighlights.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { NewsItem } from '@/lib/news';

function formatDate(dateStr: string) {
if (!dateStr) return '';
const [year, month, day] = dateStr.split('-').map(Number);
const d = new Date(year, month - 1, day);
return d.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
}

export default function NewsHighlights({ items }: { items: NewsItem[] }) {
if (items.length === 0) return null;

return (
<div className="news-strip">
{items.map((item) => (
<a
key={item.slug}
href={item.url}
target="_blank"
rel="noopener noreferrer"
className="news-card"
data-category={item.category.toLowerCase()}
>
<div className="news-card-top">
<span className="news-card-category">{item.category}</span>
<span className="news-card-date">{formatDate(item.date)}</span>
</div>
<h3 className="news-card-title">{item.title}</h3>
<p className="news-card-excerpt">{item.excerpt}</p>
<span className="news-card-link">
{item.source ? `${item.source} ↗` : 'Read more ↗'}
</span>
</a>
))}
</div>
);
}
38 changes: 38 additions & 0 deletions src/lib/news.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';

const NEWS_DIR = path.join(process.cwd(), 'content/news');

export interface NewsItem {
slug: string;
title: string;
date: string;
category: string;
excerpt: string;
url: string;
source: string;
}

export function getAllNews(): NewsItem[] {
const files = fs.readdirSync(NEWS_DIR).filter((f) => f.endsWith('.md'));

const items = files.map((filename) => {
const slug = filename.replace(/\.md$/, '');
const filePath = path.join(NEWS_DIR, filename);
const raw = fs.readFileSync(filePath, 'utf-8');
const { data } = matter(raw);

return {
slug,
title: data.title ?? slug,
date: data.date ?? '',
category: data.category ?? 'News',
excerpt: data.excerpt ?? '',
url: data.url ?? '',
source: data.source ?? '',
} as NewsItem;
});

return items.sort((a, b) => (a.date < b.date ? 1 : -1));
}
18 changes: 12 additions & 6 deletions tests/e2e/home.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,21 @@ test('GitHub stats section renders', async ({ page }) => {
await expect(hero.getByText('Forks')).toBeVisible();
});

// ── Feature Strip ──
// ── News Highlights ──

test('feature strip shows key attributes', async ({ page }) => {
test('news section renders with cards linking externally', async ({ page }) => {
await page.goto('/');
const hero = page.getByRole('region', { name: /Hero/i });
// Use text unique to the feature strip (not shared with eyebrow or body copy)
await expect(hero.getByText('100%')).toBeVisible();
await expect(hero.getByText(/constrained output/i)).toBeVisible();
await expect(hero.getByText(/LLM provider/i)).toBeVisible();
await expect(hero.getByText('Latest News')).toBeVisible();

const cards = hero.locator('.news-card');
const count = await cards.count();
expect(count).toBeGreaterThanOrEqual(1);

for (const card of await cards.all()) {
await expect(card).toHaveAttribute('target', '_blank');
await expect(card).toHaveAttribute('href', /^https?:\/\//);
}
});

// ── How It Works Section ──
Expand Down
Loading