Skip to content
maciekpaszkiewiczPublic

About

Local-first open-source CMS for Astro 6+. Schema-driven forms from your Zod content config, built-in SEO panel + SERP preview, and 301 redirect management. MIT.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

Repository files navigation

Blask

Polski CMS dla Astro. Lokalny, git-native, z wbudowanym panelem SEO.

License: MIT Astro Next.js PRs Welcome

Status: early / v0.1 — soft launch. Repo nie jest jeszcze na npm (uruchamiasz z klona, patrz Quick start). API i config mogą się jeszcze zmienić przed v1.

Blask to lokalny CMS do Astro 6+. Edytujesz wpisy w przeglądarce (localhost), a Blask zapisuje pliki .md w twoim repo Astro i pcha zmiany do git. Zero bazy danych, zero chmury, zero kont.

Dlaczego Blask

Narzędzie Astro 6 Panel SEO Redirecty Polski-native
Keystatic ❌ (PR #1527) ❌ ❌ ❌
Sveltia CMS ⚠️ niejasne ❌ ❌ ❌
Decap CMS ⚠️ legacy ❌ ❌ ❌
Pages CMS ✅ ❌ ❌ ❌
Blask ✅ ✅ ✅ ✅

Quick start

Blask nie jest jeszcze na npm — na razie uruchamiasz ją z lokalnego klona repo. Komenda npx blask init zadziała po publikacji pakietu.

# 1. sklonuj Zorzę obok swojego projektu Astro:
git clone https://github.com/maciekpaszkiewicz/blask.git
cd blask && npm install

# 2. wygeneruj blask.config.ts w root'cie swojego projektu Astro:
node bin/blask.mjs init /sciezka/do/projektu-astro

# 3. uruchom Zorzę wskazując na swój projekt:
BLASK_PROJECT=/sciezka/do/projektu-astro npm run dev
# i otwórz http://localhost:3001

⚠️ Bezpieczeństwo: Blask nie ma wbudowanej autoryzacji i ma pełny dostęp do zapisu plików + git push w twoim repo. Trzymaj ją na localhost — nigdy nie wystawiaj portu publicznie bez autoryzującego reverse proxy (patrz SECURITY.md).

Co umie

  • Schema-driven UI — formularz auto-generowany z twoich Zod schem Content Collections
  • Live preview — iframe twojego Astro dev servera, odświeża się po zapisie
  • Panel SEO 17 checków w 4 sekcjach (Podstawy / Treść / AI GEO / Linki) — z patent-driven sygnałami: citable fragment density, entity salience, topic-sentence length, inline attribution, human-likeness composite. Każdy check ma rozwijany hint z numerem patentu.
  • Live SERP preview — Google-style miniatura wyniku z badge'em domeny
  • Social card preview — Open Graph (1200×630), X (1200×675), LinkedIn — platform-accurate rendering + warnings o brakujących polach
  • JSON-LD generator + validator — Article, FAQPage, HowTo, BreadcrumbList z auto-detect typu, copy-to-clipboard, walidacją Verified Entity Status (sameAs/url/image/knowsAbout) i fact-data alignment audit (liczby w schemie muszą zgadzać się z body). Wystawia <BlaskHead /> jako Astro component (single-file, copy-paste) — to co panel zwalidował, ląduje 1:1 w twoim <head>
  • Redirecty — zarządzaj 301/302, automatyczne dodanie przy rename slug
  • TipTap editor — markdown body z bidirectional serializacją
  • Command palette — ⌘K do szybkiej nawigacji
  • Multi-collection — sidebar tabs dla każdej kolekcji z src/content/
  • i18n — UI po polsku (default) lub angielsku
  • Modern stack — Next.js 16, React 19, Tailwind 4, React Compiler

Rozpoznawane pola frontmatter

Panel SEO i generator JSON-LD czytają poniższe pola jeśli istnieją we frontmatterze wpisu. Wszystkie są opcjonalne — Blask działa z pustym frontmatterem, ale każde wypełnione pole odblokowuje kolejny fragment walidacji / silniejszą encję w schemie.

Treść i SEO

Pole Typ Do czego
title string Headline + Article.headline + SERP title
description string Meta description + Article.description
seoTitle string Override title w <title> i SERP preview
seoDescription string Override description w meta
focusKeyword string Driver dla 5 checków SEO (in-title / in-desc / first-para / density / entity salience)
pubDate Date Article.datePublished
updatedDate Date Article.dateModified
canonical URL <link rel="canonical"> + check w panelu
noindex boolean Ostrzeżenie w schemie + SERP preview
tags string[] Lista tagów (chip input w AutoForm)
tldr string[] Jeśli ≥3 items → auto-detekcja FAQPage schema
schemaType 'Article' | 'FAQPage' | 'HowTo' Wymusza typ JSON-LD
locale string Article.inLanguage (default pl-PL)

Obrazki i social

Pole Typ Do czego
image URL/path Article.image + fallback dla OG
imageAlt string Alt text check (≥10 chars)
ogImage URL/path Override dla Open Graph card

Encja autora (Verified Entity Status — US12197525B2)

Pole Typ Do czego
author string Person.name (lub Organization.name przy authorType)
authorType 'Person' | 'Organization' Default Person
authorImage URL/path Person.image — silniejsza disambiguation
authorUrl URL/path Link do dedykowanej strony autora (np. /autor/imie/)
authorJobTitle string Person.jobTitle
authorBio string Person.description
authorKnowsAbout string[] Topical authority (Source Authority for Entity — US8244689B2)
authorSameAs URL[] LinkedIn / ORCID / GitHub / Wikidata — verified entity

Encja wydawcy

Pole Typ Do czego
publisherType 'Organization' | 'Person' Default Organization
publisherLogo URL/path Wymagane przez Google Rich Results dla Article
publisherSameAs URL[] LinkedIn company page, Wikidata, GitHub org

Przykładowy fragment Zod schemy

Skopiuj do swojego src/content.config.ts i wyeksportuj jako named export (Blask importuje przez blask.config.ts):

import { defineCollection, z } from 'astro:content';

export const blogSchema = z.object({
  title: z.string().min(10).max(70),
  description: z.string().max(165).optional(),
  pubDate: z.date(),
  updatedDate: z.date().optional(),
  tags: z.array(z.string()).default([]),
  focusKeyword: z.string().optional(),
  schemaType: z.enum(['Article', 'FAQPage', 'HowTo']).default('Article'),
  tldr: z.array(z.string()).optional(),

  // Obrazki
  image: z.string().optional(),
  imageAlt: z.string().optional(),
  ogImage: z.string().optional(),

  // Encja autora — opcjonalne, im więcej, tym silniejsza disambiguation
  author: z.string().default('Anna Kowalska'),
  authorUrl: z.string().optional(),
  authorImage: z.string().optional(),
  authorJobTitle: z.string().optional(),
  authorBio: z.string().optional(),
  authorKnowsAbout: z.array(z.string()).optional(),
  authorSameAs: z.array(z.string().url()).optional(),

  // Encja wydawcy
  publisherLogo: z.string().optional(),
  publisherSameAs: z.array(z.string().url()).optional(),

  // SEO advanced
  canonical: z.string().url().optional(),
  noindex: z.boolean().default(false),
});

const blog = defineCollection({ schema: blogSchema });
export const collections = { blog };

Potem w blask.config.ts:

// blask.config.ts — plain object export (działa bez instalowania paczki).
// Po publikacji `blask` na npm możesz owinąć to w `defineConfig(...)`
// dla podpowiedzi typów: import { defineConfig } from 'blask'.
import { blogSchema } from './src/content.config';

export default {
  site: { name: 'Mój blog', domain: 'mojblog.pl', defaultAuthor: 'Anna Kowalska' },
  collections: { blog: { schema: blogSchema } },
};

Uwaga: jeśli blogSchema importujesz z astro:content, jego z to Zod 3. Blask introspektuje schematy przez Zod 4 — zbuduj schema zwykłym import { z } from "zod" (Zod 4), inaczej formularz Fields będzie pusty.

Stack

Next.js 16 · React 19 (+ React Compiler) · TypeScript 5 · Tailwind 4 · TipTap 3 · Zod 4 · simple-git · jiti · node:fs/promises

Jak to działa

┌─────────────────────────┐         ┌─────────────────────────┐
│   Twój projekt Astro    │         │      Blask (CMS)        │
│  (np. ~/sites/blog/)    │ ◄─────► │   localhost:3001        │
│                         │  read   │   (Next.js 16)          │
│  src/content/blog/*.md  │  write  │                         │
│  src/content.config.ts  │         │  ┌───────────────────┐  │
│  blask.config.ts        │         │  │  Schema-driven UI │  │
│  src/redirects.json     │         │  │  (AutoForm + Zod) │  │
│  .git/                  │         │  └───────────────────┘  │
└──────────┬──────────────┘         │  ┌───────────────────┐  │
           │                        │  │   SEO panel       │  │
           │ git push               │  │   + SERP preview  │  │
           ▼                        │  └───────────────────┘  │
┌─────────────────────────┐         │  ┌───────────────────┐  │
│   GitHub (deploy)       │         │  │  Redirects 301/302│  │
│   GitHub Actions →      │         │  └───────────────────┘  │
│   Cloudflare/Vercel/... │         └─────────────────────────┘
└─────────────────────────┘

Zero bazy danych, zero chmury, zero kont. Pliki .md żyją w twoim repo, Blask jest tylko narzędziem do edycji.

Astro integration — <BlaskHead />

Blask generuje JSON-LD i pokazuje walidację w UI, ale finalnie schema musi wyemitować twoja strona Astro. Najmniej tarcia: skopiuj astro/BlaskHead.astro z repo Zorzy do src/components/ twojej strony i wstaw w <head>:

---
// src/layouts/BlogLayout.astro
import BlaskHead from '../components/BlaskHead.astro';
const { entry } = Astro.props;
---
<html lang="pl">
  <head>
    <BlaskHead
      entry={entry}
      siteName="Mój blog"
      siteDomain="mojblog.pl"
      defaultAuthor="Anna Kowalska"
      collection="blog"
    />
  </head>
  <body><slot /></body>
</html>

Komponent emituje <title>, meta description, robots, canonical, OG, Twitter Card i dwa bloki <script type="application/ld+json"> (główna schema + BreadcrumbList). Logika lustruje src/lib/schema-generator.ts z Zorzy — czyli to co pokazał panel SEO ("schema passes validation") jest dokładnie tym co dostaje twój <head>. Zero external runtime dependencies, jeden plik, copy-paste.

Pełna dokumentacja w astro/README.md.

Development

git clone https://github.com/maciekpaszkiewicz/blask.git
cd blask
npm install
# w innym katalogu — twoja strona Astro z plikiem blask.config.ts
BLASK_PROJECT=/path/to/your/astro-site npm run dev

Patrz ARCHITECTURE.md dla docelowej architektury, ROADMAP.md dla planowanych funkcji w v1, oraz CONTRIBUTING.md jeśli chcesz dorzucić PR.

Roadmap

Soft launch (obecny stan):

  • ✅ Schema-driven AutoForm z Zod
  • ✅ Multi-collection sidebar
  • ✅ Panel SEO (17 checków w 4 sekcjach, w tym AI/GEO)
  • ✅ JSON-LD generator + validator (Article/FAQPage/HowTo/BreadcrumbList) z fact-data alignment audit
  • ✅ Social card preview (OG / X / LinkedIn)
  • ✅ SERP preview (Google-style)
  • ✅ Redirecty 301/302 z auto-add przy rename
  • ✅ CLI npx blask init
  • ✅ i18n EN + PL

Kolejna iteracja (v1, po walidacji community) — patrz ROADMAP.md:

  • Plugin system / custom widgets
  • Image management (drag&drop, WebP)
  • Multi-theme (poza butelkową zielenią)
  • Documentation site
  • Testy (Playwright + Vitest)

Licencja

MIT © 2026 Blask Contributors

About

Local-first open-source CMS for Astro 6+. Schema-driven forms from your Zod content config, built-in SEO panel + SERP preview, and 301 redirect management. MIT.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages