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
20 changes: 18 additions & 2 deletions messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1832,13 +1832,29 @@
"clearFilters": "Filter zurücksetzen"
},
"emptyAll": {
"title": "Aktuell sind keine Workshops geplant",
"subtitle": "Schau bald wieder vorbei!"
"title": "Noch ist kein Termin ausgeschrieben",
"subtitle": "Das Programm entsteht aus Vorschlägen. Schlag einen Workshop vor — als Thema, das du lernen willst, oder als Kurs, den du selbst geben möchtest. Wir schauen ihn an und schreiben ihn aus.",
"cta": "Workshop vorschlagen"
},
"cta": {
"title": "Workshop vorschlagen?",
"subtitle": "Hast du eine Idee für einen Workshop? Wir freuen uns über deine Vorschläge für neue Themen und Inhalte.",
"button": "Workshop vorschlagen"
},
"meanwhile": {
"eyebrow": "SCHON JETZT VERFÜGBAR",
"title": "Kein Termin heisst nicht: nichts zu lernen",
"subtitle": "Zwei Dinge kannst du sofort nutzen — beide von uns gepflegt, beide kostenlos.",
"openSource": {
"title": "Open-Source-Alternativen",
"body": "43 freie Programme, die teure Software ersetzen — mit Einschätzung, wie ausgereift sie sind und wie aufwendig der Umstieg ist.",
"cta": "Alternativen durchsuchen"
},
"linux": {
"title": "Linux einrichten",
"body": "Welche Distribution zu welchem Gerät passt, und wie du ein älteres Notebook wieder schnell bekommst.",
"cta": "Zur Anleitung"
}
}
},
"detail": {
Expand Down
20 changes: 18 additions & 2 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1832,13 +1832,29 @@
"clearFilters": "Reset filters"
},
"emptyAll": {
"title": "No workshops scheduled at the moment",
"subtitle": "Check back soon!"
"title": "No date is scheduled yet",
"subtitle": "The programme grows out of proposals. Propose a workshop — either a topic you want to learn, or a course you would like to teach. We review it and put it on the calendar.",
"cta": "Propose a workshop"
},
"cta": {
"title": "Want to propose a workshop?",
"subtitle": "Have an idea for a workshop? We welcome your suggestions for new topics and content.",
"button": "Propose a workshop"
},
"meanwhile": {
"eyebrow": "AVAILABLE ALREADY",
"title": "No date does not mean nothing to learn",
"subtitle": "Two things you can use right now — both maintained by us, both free.",
"openSource": {
"title": "Open-source alternatives",
"body": "43 free programs that replace expensive software, each with how mature it is and how much work the switch takes.",
"cta": "Browse the alternatives"
},
"linux": {
"title": "Set up Linux",
"body": "Which distribution suits which machine, and how to make an older laptop fast again.",
"cta": "Read the guide"
}
}
},
"detail": {
Expand Down
20 changes: 18 additions & 2 deletions messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -4280,13 +4280,29 @@
"clearFilters": "Restablecer filtros"
},
"emptyAll": {
"title": "No hay talleres programados en este momento",
"subtitle": "¡Vuelve pronto!"
"title": "Todavía no hay ninguna fecha programada",
"subtitle": "El programa nace de las propuestas. Propón un taller: un tema que quieras aprender o un curso que quieras impartir. Lo revisamos y lo publicamos en el calendario.",
"cta": "Proponer un taller"
},
"cta": {
"title": "¿Quieres proponer un taller?",
"subtitle": "¿Tienes una idea para un taller? Nos encantan las propuestas de nuevos temas y contenidos.",
"button": "Proponer taller"
},
"meanwhile": {
"eyebrow": "YA DISPONIBLE",
"title": "Sin fecha no significa sin nada que aprender",
"subtitle": "Dos cosas que puedes usar ahora mismo, ambas mantenidas por nosotros y gratuitas.",
"openSource": {
"title": "Alternativas de código abierto",
"body": "43 programas libres que sustituyen software caro, cada uno con su madurez y el esfuerzo que exige la migración.",
"cta": "Explorar las alternativas"
},
"linux": {
"title": "Configurar Linux",
"body": "Qué distribución encaja con cada equipo y cómo volver a hacer rápido un portátil antiguo.",
"cta": "Leer la guía"
}
}
},
"detail": {
Expand Down
20 changes: 18 additions & 2 deletions messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1831,13 +1831,29 @@
"clearFilters": "Réinitialiser les filtres"
},
"emptyAll": {
"title": "Aucun atelier planifié actuellement",
"subtitle": "Revenez bientôt!"
"title": "Aucune date n'est encore programmée",
"subtitle": "Le programme naît des propositions. Proposez un atelier : un sujet que vous voulez apprendre, ou un cours que vous aimeriez donner. Nous l'examinons et le mettons au calendrier.",
"cta": "Proposer un atelier"
},
"cta": {
"title": "Proposer un atelier?",
"subtitle": "Vous avez une idée d'atelier? Nous sommes ravis de recevoir vos suggestions de nouveaux thèmes et contenus.",
"button": "Proposer un atelier"
},
"meanwhile": {
"eyebrow": "DÉJÀ DISPONIBLE",
"title": "Pas de date ne veut pas dire rien à apprendre",
"subtitle": "Deux choses utilisables tout de suite — toutes deux entretenues par nous, toutes deux gratuites.",
"openSource": {
"title": "Alternatives open source",
"body": "43 logiciels libres qui remplacent des logiciels coûteux, avec leur maturité et l'effort que demande la migration.",
"cta": "Parcourir les alternatives"
},
"linux": {
"title": "Installer Linux",
"body": "Quelle distribution convient à quelle machine, et comment rendre un portable ancien à nouveau rapide.",
"cta": "Lire le guide"
}
}
},
"detail": {
Expand Down
20 changes: 18 additions & 2 deletions messages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -4280,13 +4280,29 @@
"clearFilters": "Reimposta filtri"
},
"emptyAll": {
"title": "Al momento non ci sono workshop in programma",
"subtitle": "Torna presto!"
"title": "Non è ancora fissata nessuna data",
"subtitle": "Il programma nasce dalle proposte. Proponi un laboratorio: un tema che vuoi imparare, o un corso che vorresti tenere tu. Lo esaminiamo e lo mettiamo in calendario.",
"cta": "Proporre un laboratorio"
},
"cta": {
"title": "Vuoi proporre un workshop?",
"subtitle": "Hai un'idea per un workshop? Siamo felici di ricevere i tuoi suggerimenti su nuovi temi e contenuti.",
"button": "Proponi un workshop"
},
"meanwhile": {
"eyebrow": "GIÀ DISPONIBILE",
"title": "Nessuna data non significa niente da imparare",
"subtitle": "Due cose che puoi usare subito, entrambe curate da noi e gratuite.",
"openSource": {
"title": "Alternative open source",
"body": "43 programmi liberi che sostituiscono software costoso, ognuno con la sua maturità e quanto lavoro richiede il passaggio.",
"cta": "Sfoglia le alternative"
},
"linux": {
"title": "Configurare Linux",
"body": "Quale distribuzione si adatta a quale macchina e come rendere di nuovo veloce un portatile datato.",
"cta": "Leggi la guida"
}
}
},
"detail": {
Expand Down
20 changes: 18 additions & 2 deletions messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -4280,13 +4280,29 @@
"clearFilters": "フィルターをリセット"
},
"emptyAll": {
"title": "現在予定されているワークショップはありません",
"subtitle": "またご確認ください!"
"title": "まだ日程は決まっていません",
"subtitle": "講座は提案から生まれます。学びたいテーマでも、自分が教えたい講座でも構いません。提案してください。こちらで検討して日程を組みます。",
"cta": "ワークショップを提案する"
},
"cta": {
"title": "ワークショップを提案しませんか?",
"subtitle": "ワークショップのアイデアがありますか?新しいテーマや内容のご提案をお待ちしています。",
"button": "ワークショップを提案"
},
"meanwhile": {
"eyebrow": "いますぐ使えるもの",
"title": "日程がないことと、学ぶものがないことは違います",
"subtitle": "すぐに使える二つ。どちらも私たちが手入れしていて、どちらも無料です。",
"openSource": {
"title": "オープンソースの代替",
"body": "高価なソフトを置き換える 43 の自由なプログラム。それぞれの成熟度と、乗り換えにかかる手間つき。",
"cta": "代替を見る"
},
"linux": {
"title": "Linux を設定する",
"body": "どの端末にどのディストリビューションが合うか、古いノートをまた速くする方法。",
"cta": "手順を読む"
}
}
},
"detail": {
Expand Down
20 changes: 18 additions & 2 deletions messages/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -4280,13 +4280,29 @@
"clearFilters": "필터 초기화"
},
"emptyAll": {
"title": "현재 예정된 워크숍이 없습니다",
"subtitle": "곧 다시 확인해 주세요!"
"title": "아직 잡힌 일정이 없습니다",
"subtitle": "과정은 제안에서 시작됩니다. 배우고 싶은 주제도 좋고, 직접 가르치고 싶은 강좌도 좋습니다. 제안해 주시면 검토해서 일정을 잡습니다.",
"cta": "워크숍 제안하기"
},
"cta": {
"title": "워크숍을 제안하시겠어요?",
"subtitle": "워크숍 아이디어가 있으신가요? 새로운 주제와 내용에 대한 제안을 환영합니다.",
"button": "워크숍 제안하기"
},
"meanwhile": {
"eyebrow": "지금 바로 쓸 수 있는 것",
"title": "일정이 없다고 배울 것이 없는 건 아닙니다",
"subtitle": "지금 바로 쓸 수 있는 두 가지. 둘 다 저희가 관리하고, 둘 다 무료입니다.",
"openSource": {
"title": "오픈소스 대안",
"body": "비싼 소프트웨어를 대체하는 43개의 자유 프로그램. 각각의 성숙도와 전환에 드는 수고까지.",
"cta": "대안 살펴보기"
},
"linux": {
"title": "리눅스 설치하기",
"body": "어떤 기기에 어떤 배포판이 맞는지, 오래된 노트북을 다시 빠르게 만드는 방법.",
"cta": "안내 읽기"
}
}
},
"detail": {
Expand Down
20 changes: 18 additions & 2 deletions messages/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -1835,13 +1835,29 @@
"clearFilters": "Сбросить фильтры"
},
"emptyAll": {
"title": "На данный момент воркшопы не запланированы",
"subtitle": "Загляните позже!"
"title": "Дата пока не назначена",
"subtitle": "Программа рождается из предложений. Предложите мастерскую — тему, которой хотите научиться, или курс, который хотели бы вести сами. Мы рассмотрим и поставим в календарь.",
"cta": "Предложить мастерскую"
},
"cta": {
"title": "Предложить воркшоп?",
"subtitle": "У вас есть идея для воркшопа? Будем рады вашим предложениям новых тем и материалов.",
"button": "Предложить воркшоп"
},
"meanwhile": {
"eyebrow": "ДОСТУПНО УЖЕ СЕЙЧАС",
"title": "Нет даты — не значит, что нечему учиться",
"subtitle": "Две вещи, которыми можно пользоваться прямо сейчас: обе ведём мы, обе бесплатны.",
"openSource": {
"title": "Открытые альтернативы",
"body": "43 свободные программы, заменяющие дорогой софт, — с оценкой зрелости и того, насколько труден переход.",
"cta": "Посмотреть альтернативы"
},
"linux": {
"title": "Настроить Linux",
"body": "Какой дистрибутив подходит какой машине и как снова сделать старый ноутбук быстрым.",
"cta": "Читать руководство"
}
}
},
"detail": {
Expand Down
110 changes: 87 additions & 23 deletions src/app/[locale]/workshops/WorkshopBrowseClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ interface WorkshopBrowseClientProps {
workshops: WorkshopWithInstances[]
}

/**
* What evig can teach you TODAY, shown when nothing is scheduled.
*
* Structure here, strings in messages under `workshops.browse.meanwhile.<id>`,
* paired by the stable id — the same rule the divisions and pillars follow.
* These are the only two teaching assets evig actually owns right now; do not
* add a third here unless the page behind it is real.
*/
const MEANWHILE_LINKS = [
{ id: 'openSource', href: '/services/open-source-solutions' },
{ id: 'linux', href: '/services/linux-open-source' },
] as const

export default function WorkshopBrowseClient({ workshops }: WorkshopBrowseClientProps) {
const t = useTranslations('workshops.browse')
const tCat = useTranslations('workshops.categories')
Expand Down Expand Up @@ -282,29 +295,80 @@ export default function WorkshopBrowseClient({ workshops }: WorkshopBrowseClient
})}
</div>
) : (
<div className="text-center py-12">
<BookOpen className="w-16 h-16 text-text-muted dark:text-text-secondary mx-auto mb-4" />
<Heading level={3} className="text-xl font-semibold text-text-primary mb-2">
{categoryFilter !== 'all' || levelFilter !== 'all'
? t('emptyFiltered.title')
: t('emptyAll.title')}
</Heading>
<p className="text-text-secondary mb-4">
{categoryFilter !== 'all' || levelFilter !== 'all'
? t('emptyFiltered.subtitle')
: t('emptyAll.subtitle')}
</p>
{(categoryFilter !== 'all' || levelFilter !== 'all') && (
<Button
variant="ghost"
onClick={() => {
setCategoryFilter('all')
setLevelFilter('all')
}}
className="text-action hover:text-action font-medium"
>
{t('emptyFiltered.clearFilters')}
</Button>
<div className="py-12">
<div className="text-center">
<BookOpen className="w-16 h-16 text-text-muted dark:text-text-secondary mx-auto mb-4" />
<Heading level={3} className="text-xl font-semibold text-text-primary mb-2">
{categoryFilter !== 'all' || levelFilter !== 'all'
? t('emptyFiltered.title')
: t('emptyAll.title')}
</Heading>
<p className="text-text-secondary mb-4 mx-auto max-w-2xl">
{categoryFilter !== 'all' || levelFilter !== 'all'
? t('emptyFiltered.subtitle')
: t('emptyAll.subtitle')}
</p>
{categoryFilter !== 'all' || levelFilter !== 'all' ? (
<Button
variant="ghost"
onClick={() => {
setCategoryFilter('all')
setLevelFilter('all')
}}
className="text-action hover:text-action font-medium"
>
{t('emptyFiltered.clearFilters')}
</Button>
) : (
// The proposal pipeline is real and complete — propose, an
// admin approves, and the approve route inserts the workshop
// AND a scheduled instance, which lands on this page. Saying
// "Schau bald wieder vorbei" here told people to wait for
// something they could start themselves, with a working
// "Workshop vorschlagen" button directly above it.
<Link href="/workshops/propose" className="ui-public-cta mt-2 inline-flex items-center gap-2">
{t('emptyAll.cta')}
<ArrowRight className="w-4 h-4" />
</Link>
)}
</div>

{/* Nothing scheduled is not the same as nothing to learn.
This page is where pillar 4 (retraining) sends people, and it
answered them with "Schau bald wieder vorbei!" — a dead end on
a core promise. These are the two teaching assets evig owns
today and can hand over immediately: a 43-entry open-source
alternatives registry and a Linux setup guide with a distro
matrix. Shown only when the calendar is empty; once workshops
exist, the workshops are the answer. */}
{categoryFilter === 'all' && levelFilter === 'all' && (
<div className="mt-14 border-t border-subtle pt-14">
<div className="mx-auto max-w-2xl text-center">
<Eyebrow as="div">{t('meanwhile.eyebrow')}</Eyebrow>
<Heading level={3} className="ui-public-display-md mt-3">
{t('meanwhile.title')}
</Heading>
<p className="ui-public-section-lede mt-4 mx-auto">
{t('meanwhile.subtitle')}
</p>
</div>

<div className="mt-10 grid gap-4 md:grid-cols-2">
{MEANWHILE_LINKS.map((item) => (
<Link key={item.id} href={item.href} className="ui-public-card group">
<Heading level={4} className="ui-public-card-title">
{t(`meanwhile.${item.id}.title` as never)}
</Heading>
<p className="ui-public-card-body">
{t(`meanwhile.${item.id}.body` as never)}
</p>
<span className="ui-public-card-meta inline-flex items-center gap-1 group-hover:text-text-primary transition-colors">
{t(`meanwhile.${item.id}.cta` as never)} →
</span>
</Link>
))}
</div>
</div>
)}
</div>
)}
Expand Down
Loading