Skip to content
Merged
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
73 changes: 72 additions & 1 deletion src/components/pages/CommunityPage.astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
---
import Base from "../../layouts/Base.astro";
import { community, categoryUrl } from "../../i18n/pages/community";
import {
community,
categoryUrl,
composerUrl,
maintainerOnlySlugs,
} from "../../i18n/pages/community";
import { alternatesFor, localePath, type Locale } from "../../i18n/config";
import { t } from "../../i18n/ui";

Expand Down Expand Up @@ -28,6 +33,32 @@ const chrome = t(locale);
</section>

<div class="narrow">
{/* #48 — how to reach the conversation, for readers without a GitHub account. */}
<section class="card howto" aria-labelledby="howto-title">
<h2 id="howto-title">{c.howToPost.title}</h2>
<ul class="howto-facts">
{
c.howToPost.facts.map((fact) => (
<li>
<strong>{fact.lead}</strong> {fact.rest}
</li>
))
}
</ul>
<ol class="howto-steps">
{
c.howToPost.steps.map((step) => (
<li>
{step.before}
{step.link ? <a href={step.link.href}>{step.link.label}</a> : null}
{step.after}
</li>
))
}
</ol>
<p class="howto-guide">{c.howToPost.categoryGuide}</p>
</section>

<section aria-label={c.title}>
<ul class="card-grid">
{
Expand All @@ -37,6 +68,11 @@ const chrome = t(locale);
<h2>{category.name}</h2>
<p>{category.description}</p>
</a>
{!maintainerOnlySlugs.has(category.slug) && (
<a class="card-action" href={composerUrl(category.slug)}>
{c.howToPost.startLabel} <span aria-hidden="true">→</span>
</a>
)}
</li>
))
}
Expand All @@ -55,3 +91,38 @@ const chrome = t(locale);
</div>
</div>
</Base>

<style>
/* #48 — the how-to-post card. Reuses .card; these only shape the lists
inside it. Inline-start padding keeps the numbered list correct in RTL. */
.howto-facts {
list-style: none;
margin: 0.75rem 0 1rem;
padding: 0;
}

.howto-facts li {
margin-bottom: 0.45rem;
}

.howto-steps {
margin: 0.75rem 0 0;
padding-inline-start: 1.5em;
}

.howto-steps li {
margin-bottom: 0.45rem;
}

.howto-guide {
margin-top: 1rem;
}

/* Second link on category cards: straight to the composer, category
preselected. Sits outside the browse link (no nested anchors). */
.card-action {
display: inline-block;
margin-top: 0.75rem;
font-size: 0.9rem;
}
</style>
172 changes: 167 additions & 5 deletions src/i18n/pages/community.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,119 @@ import type { LocalizedPage } from "../config";
* on the engine repo (verified slugs: announcements, compliance-classification,
* general, ideas, polls, q-a, show-and-tell), each with one plain paragraph.
* The site only reads and links — posting/voting happen on GitHub (non-goal).
*
* `howToPost` (#48) is the reader-facing exception to that silence: it explains
* how to reach the place where interaction happens. It says an account is
* required and a real name is not — never that a pseudonym is anonymity.
*/
export interface CommunityCategory {
name: string;
slug: string;
description: string;
}

export interface HowToFact {
/** The bolded lead — the rule or promise, in one sentence. */
lead: string;
/** The rest of the fact, on the same line. */
rest: string;
}

export interface HowToStep {
/** Text before the embedded link (the whole step when there is no link). */
before: string;
/** Rendered as a link between `before` and `after`. */
link?: { label: string; href: string };
/** Text after the link (may be empty). */
after: string;
}

export interface HowToPostContent {
title: string;
facts: HowToFact[];
steps: HowToStep[];
/** One-sentence category guidance, closing the section. */
categoryGuide: string;
/** Label for the composer link on each open category card. */
startLabel: string;
}

export interface CommunityContent {
rev: string;
title: string;
description: string;
intro: string[];
note: string;
howToPost: HowToPostContent;
categories: CommunityCategory[];
translatedFromRev?: string;
}

const SLUG_BASE = "https://github.com/CodeGateSoftware/keel/discussions/categories";
const NEW_BASE = "https://github.com/CodeGateSoftware/keel/discussions/new";

/**
* GitHub's composer with a category preselected — …/discussions/new?category=<slug>
* (verified working for compliance-classification on 2026-08-21).
*/
export const composerUrl = (slug: string) => `${NEW_BASE}?category=${slug}`;

/**
* Announcement-type categories only let maintainers open discussions, so those
* cards get no composer link — a link that ends in a permission wall would not
* be honest (#48's own rule).
*/
export const maintainerOnlySlugs = new Set(["announcements"]);

export const community: LocalizedPage<CommunityContent> = {
en: {
rev: "2026-08-20.2",
rev: "2026-08-21.1",
title: "keel Community on GitHub Discussions",
description:
"Questions, ideas, polls, and classification debate happen on GitHub Discussions. The site only reads and links — interaction stays where the project lives.",
intro: [
"Everything community-shaped happens on GitHub Discussions — posting, voting, polling, answering. This website deliberately has none of that: it reads and links, because that is where the project, its history, and its moderation already live.",
],
note: "One category deserves a special mention: Compliance & classification. “Should X be treated this way?” is a question, not a bug — and there is a place for it.",
howToPost: {
title: "New here? How to post",
facts: [
{
lead: "You need a free GitHub account to post",
rest: "— reading is open to everyone.",
},
{
lead: "You do not need to use your real name.",
rest: "Pick any username you like. Your email address stays private and is never shown.",
},
{
lead: "It is just a web page with a comment box.",
rest: "Nothing installs on your computer, and you can edit or delete anything you post.",
},
],
steps: [
{
before: "Sign up at ",
link: { label: "github.com/signup", href: "https://github.com/signup" },
after: " — an email, a password, a username of your choosing.",
},
{
before: "Enter the code they email you, and complete the “are you human” check. Around two minutes.",
after: "",
},
{
before: "Use a “Start a discussion” button below — it opens the form with the category already chosen.",
after: "",
},
{
before: "Title, then your question, then “Start discussion”.",
after: "",
},
],
categoryGuide:
"Not sure which category? Compliance & classification for “should X be treated this way”, Q&A for running or configuring keel, General for anything else. Picking the wrong one is not a problem — it can be moved.",
startLabel: "Start a discussion",
},
categories: [
{
name: "Announcements",
Expand Down Expand Up @@ -74,15 +158,54 @@ export const community: LocalizedPage<CommunityContent> = {
},

ar: {
rev: "2026-08-20.2",
translatedFromRev: "2026-08-20.2",
rev: "2026-08-21.1",
translatedFromRev: "2026-08-21.1",
title: "مجتمع كيل على نقاشات GitHub",
description:
"الأسئلة والأفكار واستطلاعات الرأي ونقاش التصنيف تجري في نقاشات GitHub. وهذا الموقع يقرأ ويربط فقط — ويبقى التفاعل حيث يعيش المشروع.",
intro: [
"كلُّ ما هو مجتمعيٌّ يحدث في نقاشات GitHub — النشر والتصويت واستطلاع الرأي والإجابة. وهذا الموقع لا يملك شيئًا من ذلك عن قصد: فهو يقرأ ويربط، لأن المشروع وتاريخه وإدارته موجودةٌ هناك أصلًا.",
],
note: "وثمّة فئةٌ تستحق ذكرًا خاصًّا: «الامتثال والتصنيف». فسؤال «هل ينبغي أن يُعامَل X بهذه الطريقة؟» سؤالٌ لا بلاغُ خلل — وله مكانٌ مخصّص.",
howToPost: {
title: "جديدٌ هنا؟ كيف تنشر",
facts: [
{
lead: "تحتاج إلى حساب GitHub مجاني لتنشر",
rest: "— أمّا القراءة فمفتوحةٌ للجميع.",
},
{
lead: "لستَ مضطرًّا لاستخدام اسمك الحقيقي.",
rest: "اختر أيَّ اسمِ مستخدمٍ شئت. بريدك الإلكتروني يبقى خاصًّا ولا يُعرَض أبدًا.",
},
{
lead: "إنها مجردُ صفحةِ ويبٍ فيها صندوقُ تعليق.",
rest: "لا شيء يُثبَّت على حاسوبك، ويمكنك تعديل كلِّ ما تنشره أو حذفه.",
},
],
steps: [
{
before: "أنشئ حسابًا على ",
link: { label: "github.com/signup", href: "https://github.com/signup" },
after: " — بريدٌ إلكتروني، وكلمةُ سرٍّ، واسمُ مستخدمٍ من اختيارك.",
},
{
before: "أدخِل الرمزَ الذي يصلك بالبريد، ثم أكمِل فحص «هل أنت إنسان». نحو دقيقتين.",
after: "",
},
{
before: "استخدم زرَّ «ابدأ نقاشًا» في الأسفل — يفتح الاستمارة والفئةُ محدَّدةٌ سلفًا.",
after: "",
},
{
before: "العنوان أولًا، ثم سؤالك، ثم «ابدأ نقاشًا».",
after: "",
},
],
categoryGuide:
"مترددٌ في اختيار الفئة؟ «الامتثال والتصنيف» لأسئلة «هل يُعامَل X بهذه الطريقة؟»، و«الأسئلة والأجوبة» لتشغيل كيل وإعداده، و«عام» لأيِّ شيءٍ آخر. اختيارُ الفئة الخطأ ليس مشكلة — يمكن نقل النقاش.",
startLabel: "ابدأ نقاشًا",
},
categories: [
{
name: "Announcements",
Expand Down Expand Up @@ -123,15 +246,54 @@ export const community: LocalizedPage<CommunityContent> = {
},

fr: {
rev: "2026-08-20.2",
translatedFromRev: "2026-08-20.2",
rev: "2026-08-21.1",
translatedFromRev: "2026-08-21.1",
title: "La communauté keel — sur GitHub, par choix",
description:
"Questions, idées, sondages et débats de classification ont lieu dans les Discussions GitHub de keel. Ce site se contente de lire et de renvoyer : l'échange reste là où vit le projet.",
intro: [
"Tout ce qui relève de la communauté se passe dans les Discussions GitHub — publier, voter, sonder, répondre. Ce site n'offre délibérément aucune de ces fonctions : il lit et il renvoie, parce que le projet, son histoire et sa modération vivent déjà là-bas.",
],
note: "Une catégorie mérite une mention particulière : Conformité et classification. « X doit-il être traité ainsi ? » est une question, pas un bug — et elle a son espace dédié.",
howToPost: {
title: "Nouveau ici ? Comment publier",
facts: [
{
lead: "Il faut un compte GitHub gratuit pour publier",
rest: "— la lecture, elle, reste ouverte à tous.",
},
{
lead: "Votre vrai nom n'est pas nécessaire.",
rest: "Choisissez l'identifiant qu'il vous plaît. Votre adresse e-mail reste privée et n'est jamais affichée.",
},
{
lead: "C'est juste une page web avec une zone de commentaire.",
rest: "Rien ne s'installe sur votre ordinateur, et vous pouvez modifier ou supprimer tout ce que vous publiez.",
},
],
steps: [
{
before: "Inscrivez-vous sur ",
link: { label: "github.com/signup", href: "https://github.com/signup" },
after: " — une adresse e-mail, un mot de passe, un identifiant de votre choix.",
},
{
before: "Saisissez le code reçu par e-mail, puis passez la vérification « êtes-vous humain ». Deux minutes, à peu près.",
after: "",
},
{
before: "Servez-vous d'un bouton « Lancer une discussion » ci-dessous — il ouvre le formulaire avec la catégorie déjà choisie.",
after: "",
},
{
before: "Un titre, puis votre question, puis « Lancer la discussion ».",
after: "",
},
],
categoryGuide:
"Pas sûr de la catégorie ? « Conformité et classification » pour « X doit-il être traité ainsi ? », « Questions et réponses » pour utiliser ou configurer keel, « Général » pour tout le reste. Se tromper de catégorie n'est pas un problème — une discussion peut être déplacée.",
startLabel: "Lancer une discussion",
},
categories: [
{
name: "Announcements",
Expand Down
Loading