jpeg: { mozjpeg: true, progressive: true, quality: 75 },
webp: { quality: 75, effort: 4, alphaQuality: 80 },
avif: { quality: 50, effort: 2 },
- }
- }
+ },
+ },
},
vite: {
build: {
"@astrojs/rss": "4.0.18",
"@astrojs/sitemap": "3.7.2",
"@iconify-json/mdi": "^1.2.3",
- "@pagefind/component-ui": "^1.5.0",
+ "@pagefind/component-ui": "^1.5.2",
"@vercel/og": "^0.8.6",
"astro": "6.1.5",
"astro-icon": "^1.1.5",
- "pagefind": "^1.5.0",
+ "pagefind": "^1.5.2",
},
"devDependencies": {
"@astrojs/check": "0.9.8",
Index](https://data.hashrateindex.com/network-data/bitcoin-hashprice-index).
</Figure>
-<Figure
- image={hashrate2yr}
- alt="Bitcoin hashrate over the last 2 years"
->
+<Figure image={hashrate2yr} alt="Bitcoin hashrate over the last 2 years">
Bitcoin hashrate over the last 2 years. Data from 2023-02-08 through
2025-02-07. Source:
[mempool.space](https://mempool.space/graphs/mining/hashrate-difficulty#2y).
---
type: video
-title: "The Return of Productive American Growth: Artemis, Oil Flippening, and Credit Expansion"
+title: 'The Return of Productive American Growth: Artemis, Oil Flippening, and Credit Expansion'
date: 2026-04-02
modified: 2026-04-02
description: 'Mine, Print, Hash - 2026 Week #14'
---
type: video
-title: "Ceasefire and Contagion: Factions Against Iran Peace & FX, Sovereign Debt, and Commodity Spillovers"
+title: 'Ceasefire and Contagion: Factions Against Iran Peace & FX, Sovereign Debt, and Commodity Spillovers'
date: 2026-04-09
modified: 2026-04-09
description: 'Mine, Print, Hash - 2026 Week #15'
---
import { Picture } from 'astro:assets';
-import type { ImageLayout, ImageMetadata } from 'astro';
+import type { ImageMetadata } from 'astro';
interface Props {
image: ImageMetadata;
alt: string;
formats?: string[];
- layout?: ImageLayout;
+ layout?: 'constrained' | 'full-width' | 'fixed' | 'none';
}
const { image, alt, formats = ['avif', 'webp'], layout } = Astro.props;
+++ /dev/null
-import { describe, it, expect } from 'bun:test';
-import formatDate from '../formatDate';
-
-describe('formatDate', () => {
- it('formats date as YYYY-MM-DD', () => {
- const date = new Date(Date.UTC(2024, 2, 15)); // March 15, 2024
- expect(formatDate(date)).toBe('2024-03-15');
- });
-
- it('pads single-digit months with zero', () => {
- const date = new Date(Date.UTC(2024, 0, 1)); // January 1, 2024
- expect(formatDate(date)).toBe('2024-01-01');
- });
-
- it('pads single-digit days with zero', () => {
- const date = new Date(Date.UTC(2024, 11, 5)); // December 5, 2024
- expect(formatDate(date)).toBe('2024-12-05');
- });
-
- it('handles year boundaries correctly', () => {
- const date = new Date(Date.UTC(2023, 11, 31)); // December 31, 2023
- expect(formatDate(date)).toBe('2023-12-31');
- });
-});
+++ /dev/null
-import { describe, it, expect } from 'bun:test';
-import generateStarRating from '../generateStarRating';
-
-describe('generateStarRating', () => {
- it('returns 5 filled stars for rating 5', () => {
- expect(generateStarRating(5)).toBe('★★★★★');
- });
-
- it('returns 1 filled and 4 empty stars for rating 1', () => {
- expect(generateStarRating(1)).toBe('★☆☆☆☆');
- });
-
- it('returns 3 filled and 2 empty stars for rating 3', () => {
- expect(generateStarRating(3)).toBe('★★★☆☆');
- });
-
- it('throws for rating 0', () => {
- expect(() => generateStarRating(0)).toThrow(
- 'Invalid rating: 0. Must be an integer between 1 and 5.',
- );
- });
-
- it('throws for rating 6', () => {
- expect(() => generateStarRating(6)).toThrow(
- 'Invalid rating: 6. Must be an integer between 1 and 5.',
- );
- });
-
- it('throws for non-integer rating', () => {
- expect(() => generateStarRating(3.5)).toThrow(
- 'Invalid rating: 3.5. Must be an integer between 1 and 5.',
- );
- });
-
- it('throws for negative rating', () => {
- expect(() => generateStarRating(-1)).toThrow(
- 'Invalid rating: -1. Must be an integer between 1 and 5.',
- );
- });
-});
+++ /dev/null
-import { describe, it, expect } from 'bun:test';
-import sortByDate from '../sortByDate';
-
-// Mock type for testing - matches the HasDate interface expected by sortByDate
-interface MockEntry {
- data: { date: Date };
-}
-
-describe('sortByDate', () => {
- it('sorts items by date in descending order (newest first)', () => {
- const items: MockEntry[] = [
- { data: { date: new Date('2024-01-15') } },
- { data: { date: new Date('2024-03-20') } },
- { data: { date: new Date('2024-02-10') } },
- ];
-
- const sorted = sortByDate(items);
-
- expect(sorted[0].data.date.getTime()).toBe(
- new Date('2024-03-20').getTime(),
- );
- expect(sorted[1].data.date.getTime()).toBe(
- new Date('2024-02-10').getTime(),
- );
- expect(sorted[2].data.date.getTime()).toBe(
- new Date('2024-01-15').getTime(),
- );
- });
-
- it('handles items with same date', () => {
- const items: MockEntry[] = [
- { data: { date: new Date('2024-01-15') } },
- { data: { date: new Date('2024-01-15') } },
- ];
-
- const sorted = sortByDate(items);
-
- expect(sorted).toHaveLength(2);
- });
-
- it('returns empty array for empty input', () => {
- const sorted = sortByDate([]);
- expect(sorted).toEqual([]);
- });
-
- it('handles single item array', () => {
- const items: MockEntry[] = [{ data: { date: new Date('2024-01-15') } }];
-
- const sorted = sortByDate(items);
-
- expect(sorted).toHaveLength(1);
- });
-
- it('does not mutate original array', () => {
- const items: MockEntry[] = [
- { data: { date: new Date('2024-01-01') } },
- { data: { date: new Date('2024-03-01') } },
- ];
- const originalFirst = items[0];
-
- sortByDate(items);
-
- expect(items[0]).toBe(originalFirst);
- });
-});
-interface HasDate {
- data: { date: Date };
-}
+import { type SiteCollectionEntry } from '@utils/globals';
-export default function sortByDate<T extends HasDate>(items: T[]): T[] {
+export default function sortByDate<T extends SiteCollectionEntry>(
+ items: T[],
+): T[] {
return [...items].sort(
(a, b) => b.data.date.getTime() - a.data.date.getTime(),
);