From 2d12f9dd9322754b7a8e7245fcbe3100d2c5d5ba Mon Sep 17 00:00:00 2001 From: JsCodeDevlopment Date: Fri, 8 May 2026 15:59:13 -0300 Subject: [PATCH 1/4] feat: implement new application pages including courses, changelog, interview prep, and pricing UI --- app/changelog/page.tsx | 16 +- app/concepts/page.tsx | 61 ++++--- app/course/page.tsx | 35 ++-- app/engineering-work/page.tsx | 139 ++++++++++------ app/explorer/page.tsx | 28 ++-- app/interview-en/page.tsx | 84 +++++----- app/pricing/page.tsx | 23 +-- app/tests/page.tsx | 58 +++---- app/tracks/page.tsx | 67 +++++--- .../catalog/problems-catalog-client.tsx | 156 ++++++++++++------ .../concepts/concepts-catalog-client.tsx | 115 +++++++------ 11 files changed, 465 insertions(+), 317 deletions(-) diff --git a/app/changelog/page.tsx b/app/changelog/page.tsx index ef2efe0..782e277 100644 --- a/app/changelog/page.tsx +++ b/app/changelog/page.tsx @@ -2,6 +2,7 @@ import { ArrowLeft } from "lucide-react"; import type { Metadata } from "next"; import Link from "next/link"; +import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { getChangelogHtml } from "@/lib/content/loader"; @@ -32,14 +33,17 @@ export default async function ChangelogPage() {
-
-

- Atualizações -

-

+
+ + Últimas Atualizações + +

Novidades

-

+

Descobre as últimas melhorias, novos conteúdos e funcionalidades desenhadas para levar o teu conhecimento técnico ao próximo nível.

diff --git a/app/concepts/page.tsx b/app/concepts/page.tsx index 51a904e..a42366c 100644 --- a/app/concepts/page.tsx +++ b/app/concepts/page.tsx @@ -1,23 +1,24 @@ -import Link from 'next/link'; -import type { Metadata } from 'next'; +import type { Metadata } from "next"; +import Link from "next/link"; -import { ConceptsCatalogClient } from '@/components/concepts/concepts-catalog-client'; -import { getAllConcepts } from '@/lib/content/loader'; -import { buildPublicMetadata } from '@/lib/seo/build-metadata'; +import { ConceptsCatalogClient } from "@/components/concepts/concepts-catalog-client"; +import { Badge } from "@/components/ui/badge"; +import { getAllConcepts } from "@/lib/content/loader"; +import { buildPublicMetadata } from "@/lib/seo/build-metadata"; export const metadata: Metadata = buildPublicMetadata({ - title: 'Conceitos de algoritmos e estruturas de dados', + title: "Conceitos de algoritmos e estruturas de dados", description: - 'Mini-guias sobre Big O, tabelas hash, duas ponteiros, janela deslizante e mais — base para ler as soluções com contexto.', - pathname: '/concepts', + "Mini-guias sobre Big O, tabelas hash, duas ponteiros, janela deslizante e mais — base para ler as soluções com contexto.", + pathname: "/concepts", keywords: [ - 'Big O', - 'complexidade algorítmica', - 'hash table', - 'two pointers', - 'sliding window', - 'fundamentos algoritmos', - 'Algoria conceitos', + "Big O", + "complexidade algorítmica", + "hash table", + "two pointers", + "sliding window", + "fundamentos algoritmos", + "Algoria conceitos", ], }); @@ -36,13 +37,35 @@ export default async function ConceptsPage() { return (
+
+ + Conceitos de algoritmos e estruturas de dados + +

+ Conceitos fundamentais +

+

+ Os pilares fundamentais para entender problemas de algoritmos e + estruturas de dados. +

+
+
-

Nova trilha

-

Prefere um programa com ordem fixa?

+

+ Nova trilha +

+

+ Prefere um programa com ordem fixa? +

- O mesmo conteúdo abaixo entra também no curso de Fundamentos: progresso no browser, dois níveis nos exemplos - interativos e certificado próprio assim que resolveres a avaliação de cada módulo. + O mesmo conteúdo abaixo entra também no curso de Fundamentos: + progresso no browser, dois níveis nos exemplos interativos e + certificado próprio assim que resolveres a avaliação de cada + módulo.

-
-
-
-
- -
-
-

- Algoria.curriculum -

-

- Cursos Guiados -

-

- Cada curso combina leitura, exemplos práticos e exercícios no browser. - Obtém certificados modulares ao concluir as avaliações de cada capítulo. -

-
-
-
+
+ + Trilhas de Aprendizagem + +

+ Cursos Guiados +

+

+ Percursos estruturados com leitura curada, exercícios no browser e certificado modular + ao concluir cada avaliação. +

diff --git a/app/engineering-work/page.tsx b/app/engineering-work/page.tsx index a164761..4cf85e0 100644 --- a/app/engineering-work/page.tsx +++ b/app/engineering-work/page.tsx @@ -1,31 +1,42 @@ -import Link from 'next/link'; -import type { Metadata } from 'next'; -import type { ReactNode } from 'react'; -import { Briefcase, Clock, MonitorSmartphone, Server, CloudCog } from 'lucide-react'; +import { Clock, CloudCog, MonitorSmartphone, Server } from "lucide-react"; +import type { Metadata } from "next"; +import Link from "next/link"; +import type { ReactNode } from "react"; -import { Badge } from '@/components/ui/badge'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { ENGINEERING_WORK_PILLARS, type EngineeringWorkPillar } from '@/lib/content/schemas'; -import { getAllEngineeringWorkGuides } from '@/lib/content/loader'; -import { buildPublicMetadata } from '@/lib/seo/build-metadata'; +import { Badge } from "@/components/ui/badge"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { getAllEngineeringWorkGuides } from "@/lib/content/loader"; +import { + ENGINEERING_WORK_PILLARS, + type EngineeringWorkPillar, +} from "@/lib/content/schemas"; +import { buildPublicMetadata } from "@/lib/seo/build-metadata"; export const metadata: Metadata = buildPublicMetadata({ - title: 'Engenharia no trabalho — guias práticos', + title: "Engenharia no trabalho — guias práticos", description: - 'Guias em português sobre frontend e produto, backend e APIs, DevOps e operação — aplicáveis na sprint real, sem lista de buzzwords.', - pathname: '/engineering-work', + "Guias em português sobre frontend e produto, backend e APIs, DevOps e operação — aplicáveis na sprint real, sem lista de buzzwords.", + pathname: "/engineering-work", keywords: [ - 'engenharia software prática', - 'frontend produção', - 'APIs backend', - 'DevOps dia a dia', - 'observabilidade', - 'segurança aplicações', - 'Algoria guias', + "engenharia software prática", + "frontend produção", + "APIs backend", + "DevOps dia a dia", + "observabilidade", + "segurança aplicações", + "Algoria guias", ], }); -const PILLAR_ORDER = new Map(ENGINEERING_WORK_PILLARS.map((p, i) => [p, i])); +const PILLAR_ORDER = new Map( + ENGINEERING_WORK_PILLARS.map((p, i) => [p, i]), +); const PILLAR_ICON: Record = { frontend: , @@ -34,21 +45,26 @@ const PILLAR_ICON: Record = { }; const PILLAR_TITLE: Record = { - frontend: 'Frontend e produto', - backend: 'Backend e APIs', - devops: 'DevOps e sistema', + frontend: "Frontend e produto", + backend: "Backend e APIs", + devops: "DevOps e sistema", }; const PILLAR_TAGLINE: Record = { - frontend: 'Performance real, segurança em superfícies web e SEO técnico honesto.', - backend: 'Identidade, permissões, contratos estáveis e resiliência sob carga.', - devops: 'Entrega contínua, observabilidade e segurança operacional sem teatro.', + frontend: + "Performance real, segurança em superfícies web e SEO técnico honesto.", + backend: + "Identidade, permissões, contratos estáveis e resiliência sob carga.", + devops: + "Entrega contínua, observabilidade e segurança operacional sem teatro.", }; export default async function EngineeringWorkHubPage() { const guides = await getAllEngineeringWorkGuides(); guides.sort((a, b) => { - const pd = (PILLAR_ORDER.get(a.meta.pillar) ?? 99) - (PILLAR_ORDER.get(b.meta.pillar) ?? 99); + const pd = + (PILLAR_ORDER.get(a.meta.pillar) ?? 99) - + (PILLAR_ORDER.get(b.meta.pillar) ?? 99); if (pd !== 0) return pd; return a.meta.title.localeCompare(b.meta.title); }); @@ -61,48 +77,58 @@ export default async function EngineeringWorkHubPage() { return (
-
-
-
- -
-
-

Área aplicada

-

Engenharia no trabalho

-

- Material pensado para ler com calma e usar na segunda-feira: cada guia separa o que é conceito, o que é decisão de produto e o que é - checklist na prática. Sem pressupor cloud específica nem framework único — quando há exemplos, são ilustrativos. -

-

- Voltaste da página inicial? Os mesmos três pilares (front, back, DevOps) estão aqui expandidos em capítulos longos. Usa o tempo estimado - como bloco de foco — pausa entre guias para experimentar no teu projeto. -

-
-
+
+ + Conteúdo prático de engenharia + +

+ Engenharia no trabalho +

+

+ Frontend, Backend e DevOps aplicados ao mundo real. Material pensado + para ler com calma e usar na segunda-feira. +

{byPillar.map(({ pillar, guides: list }) => ( -
+
{PILLAR_ICON[pillar]}
- + Pilar · {pillar} -

+

{PILLAR_TITLE[pillar]}

-

{PILLAR_TAGLINE[pillar]}

+

+ {PILLAR_TAGLINE[pillar]} +

{list.length === 0 ? ( -

Conteúdo deste pilar em preparação.

+

+ Conteúdo deste pilar em preparação. +

) : (
{list.map((g) => ( @@ -117,11 +143,14 @@ export default async function EngineeringWorkHubPage() { {g.meta.title} - ~{g.meta.estimatedMinutes} min de leitura + ~ + {g.meta.estimatedMinutes} min de leitura -

{g.meta.summary}

+

+ {g.meta.summary} +

@@ -133,8 +162,10 @@ export default async function EngineeringWorkHubPage() {

- Sugestão de uso: escolhe um pilar por sprint, lê um guia na sexta ou segunda, e implementa uma única melhoria mensurável (métrica de produto ou - observabilidade) em vez de uma lista enorme de "best practices". + Sugestão de uso: escolhe um pilar por sprint, lê um guia na sexta ou + segunda, e implementa uma única melhoria mensurável (métrica de + produto ou observabilidade) em vez de uma lista enorme de "best + practices".

diff --git a/app/explorer/page.tsx b/app/explorer/page.tsx index 5df9dde..09b35f1 100644 --- a/app/explorer/page.tsx +++ b/app/explorer/page.tsx @@ -2,6 +2,7 @@ import { Pagination } from "@/components/explorer/pagination"; import { SearchBar } from "@/components/explorer/search-bar"; import { TechFilter } from "@/components/explorer/tech-filter"; import { UserCard } from "@/components/explorer/user-card"; +import { Badge } from "@/components/ui/badge"; import { db } from "@/lib/db"; import { user, userProfile } from "@/lib/db/schema"; import { buildPublicMetadata } from "@/lib/seo/build-metadata"; @@ -80,22 +81,19 @@ export default async function ExplorerPage({ return (
-
-
-
- -
-

- Comunidade Algoria -

-
-

- Explorar Talentos +
+ + Comunidade Algoria + +

+ Explorar Talentos

-

- Conecta-te com outros engenheiros da plataforma. Filtra por stack - tecnológica, percurso profissional ou procura diretamente por nomes - e especialidades. +

+ Conecta-te com outros engenheiros da plataforma. Filtra por stack tecnológica, + percurso profissional ou procura diretamente por nomes e especialidades.

diff --git a/app/interview-en/page.tsx b/app/interview-en/page.tsx index ad8cb41..f342a48 100644 --- a/app/interview-en/page.tsx +++ b/app/interview-en/page.tsx @@ -1,27 +1,29 @@ -import type { Metadata } from 'next'; -import { Languages } from 'lucide-react'; +import type { Metadata } from "next"; -import { Badge } from '@/components/ui/badge'; -import { InterviewCatalogClient } from '@/components/interview-en/interview-catalog-client'; -import { INTERVIEW_EN_TRACKS, type InterviewEnglishTrack } from '@/lib/content/schemas'; -import { getAllInterviewEnglishTopics } from '@/lib/content/loader'; -import { buildPublicMetadata } from '@/lib/seo/build-metadata'; +import { InterviewCatalogClient } from "@/components/interview-en/interview-catalog-client"; +import { Badge } from "@/components/ui/badge"; +import { getAllInterviewEnglishTopics } from "@/lib/content/loader"; +import { + INTERVIEW_EN_TRACKS, + type InterviewEnglishTrack, +} from "@/lib/content/schemas"; +import { buildPublicMetadata } from "@/lib/seo/build-metadata"; export const metadata: Metadata = buildPublicMetadata({ - title: 'Technical English for interviews — hub Algoria', + title: "Technical English for interviews — hub Algoria", description: - 'English-only hub: vocabulary for data structures & algorithms, live coding talk tracks, behavioral STAR answers and system design phrases for hiring loops.', - pathname: '/interview-en', + "English-only hub: vocabulary for data structures & algorithms, live coding talk tracks, behavioral STAR answers and system design phrases for hiring loops.", + pathname: "/interview-en", keywords: [ - 'technical English interviews', - 'coding interview English', - 'live coding phrases', - 'STAR method behavioral', - 'system design vocabulary', - 'FAANG interview English', - 'Algoria', + "technical English interviews", + "coding interview English", + "live coding phrases", + "STAR method behavioral", + "system design vocabulary", + "FAANG interview English", + "Algoria", ], - openGraphLocale: 'en_US', + openGraphLocale: "en_US", }); const TRACK_ORDER = new Map( @@ -31,7 +33,9 @@ const TRACK_ORDER = new Map( export default async function InterviewEnglishIndexPage() { const topics = await getAllInterviewEnglishTopics(); topics.sort((a, b) => { - const td = (TRACK_ORDER.get(a.meta.track) ?? 99) - (TRACK_ORDER.get(b.meta.track) ?? 99); + const td = + (TRACK_ORDER.get(a.meta.track) ?? 99) - + (TRACK_ORDER.get(b.meta.track) ?? 99); if (td !== 0) return td; return a.meta.title.localeCompare(b.meta.title); }); @@ -39,36 +43,22 @@ export default async function InterviewEnglishIndexPage() { return (
-
-
-
-
- -
-
-

Nova área · conteúdo 100% EN

-

Technical English for interviews

-

- Toda a matéria das páginas abaixo está em inglês, orientada para quem já programa e está entre B1/B2 — - foco em soar claro sob pressão: vocabulário de entrevistas, pensar em voz alta em DSA, - comportamental (STAR), design de sistemas e e-mails típicos da pipeline de hiring. - Usa repetição activa antes de rounds reais. -

-
-
-
-
- -
- - Interview.EN +
+ + Inglês Técnico -

Speak like you are on the call

-

- Vocabulary, narration templates, STAR stories, and framing phrases — everything below is written for hiring conversations, - not generic textbook English. +

+ Inglês Técnico para Entrevistas +

+

+ Vocabulário, modelos de narração, histórias STAR e frases de + orientação — tudo escrito para conversas de contratação, não para o + inglês genérico de livros didáticos.

-
+

({ diff --git a/app/pricing/page.tsx b/app/pricing/page.tsx index b540045..5fa810f 100644 --- a/app/pricing/page.tsx +++ b/app/pricing/page.tsx @@ -6,6 +6,7 @@ import { CheckoutButton } from "@/components/billing/checkout-button"; import { ManageSubscriptionButton } from "@/components/billing/manage-subscription-button"; import { PricingPageAnalytics } from "@/components/billing/pricing-analytics"; import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; import { auth } from "@/lib/auth"; import { userHasPro } from "@/lib/billing/entitlements"; import { @@ -46,17 +47,19 @@ export default async function PricingPage() { Início -
-

- Monetização transparente -

-

- Planos +
+ + Monetização Transparente + +

+ Planos e Preços

-

- Dez problemas e funcionalidades essenciais gratuitos. Pro - desbloqueia o catálogo completo, sincronização de progresso e - investimento contínuo em conteúdo. +

+ Compara o plano gratuito com a subscrição Pro: desbloqueia o catálogo completo, + sincronização de progresso e investimento contínuo em conteúdo.

diff --git a/app/tests/page.tsx b/app/tests/page.tsx index fb4c9d6..82c182b 100644 --- a/app/tests/page.tsx +++ b/app/tests/page.tsx @@ -1,7 +1,8 @@ -import { ArrowRight, Code2, Layout, Database, Server } from "lucide-react"; +import { ArrowRight, Database, Layout, Server } from "lucide-react"; import type { Metadata } from "next"; import Link from "next/link"; +import { Badge } from "@/components/ui/badge"; import { buildPublicMetadata } from "@/lib/seo/build-metadata"; export const metadata: Metadata = buildPublicMetadata({ @@ -13,21 +14,22 @@ export const metadata: Metadata = buildPublicMetadata({ export default function TechnicalTestsIndexPage() { const tracks = [ - { - id: "frontend", - title: "Frontend", - description: "React, Next.js, Performance, Acessibilidade e Ecossistema Web.", + { + id: "frontend", + title: "Frontend", + description: + "React, Next.js, Performance, Acessibilidade e Ecossistema Web.", icon: Layout, }, - { - id: "backend", - title: "Backend", + { + id: "backend", + title: "Backend", description: "Node.js, APIs, Bases de Dados, Segurança e Arquitetura.", icon: Database, }, - { - id: "devops", - title: "DevOps", + { + id: "devops", + title: "DevOps", description: "Docker, CI/CD, Cloud, Monitorização e Infraestrutura.", icon: Server, }, @@ -36,26 +38,20 @@ export default function TechnicalTestsIndexPage() { return (
-
-
-
-
- -
-
-

- Assessment -

-

- Escolhe a tua Trilha -

-

- Seleciona a tua área de especialização para ver os simulados disponíveis. - Cada trilha contém testes de diferentes níveis e tópicos específicos. -

-
-
-
+
+ + Trilhas de Testes Técnicos + +

+ Avaliações Técnicas +

+

+ Simulados reais para vagas de Frontend, Backend e DevOps. Escolhe a + tua trilha e começa a tua avaliação profissional. +

diff --git a/app/tracks/page.tsx b/app/tracks/page.tsx index 1377fc1..6c18242 100644 --- a/app/tracks/page.tsx +++ b/app/tracks/page.tsx @@ -1,17 +1,27 @@ -import Link from 'next/link'; -import type { Metadata } from 'next'; +import type { Metadata } from "next"; +import Link from "next/link"; -import { Badge } from '@/components/ui/badge'; -import { Card, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { getAllStudyTracks } from '@/lib/content/track-loader'; -import { buildPublicMetadata } from '@/lib/seo/build-metadata'; +import { Badge } from "@/components/ui/badge"; +import { + Card, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { getAllStudyTracks } from "@/lib/content/track-loader"; +import { buildPublicMetadata } from "@/lib/seo/build-metadata"; export const metadata: Metadata = buildPublicMetadata({ - title: 'Trilhos curados de problemas', + title: "Trilhos curados de problemas", description: - 'Listas editoriais ordenadas — fundamentos na ordem recomendada ou foco arrays & hashing — para estudar sem escolher tu próprio a sequência.', - pathname: '/tracks', - keywords: ['trilho estudo', 'roadmap algoritmos', 'arrays hashing', 'ordem recomendada'], + "Listas editoriais ordenadas — fundamentos na ordem recomendada ou foco arrays & hashing — para estudar sem escolher tu próprio a sequência.", + pathname: "/tracks", + keywords: [ + "trilho estudo", + "roadmap algoritmos", + "arrays hashing", + "ordem recomendada", + ], }); export default async function TracksIndexPage() { @@ -20,26 +30,40 @@ export default async function TracksIndexPage() { return (
-
- - STUDY.TRACKS +
+ + Roadmaps Algorítmicos -

Trilhos curados

-

- Cada trilho é uma lista ordenada de slugs em content/tracks/ — mantém ritmo editorial sem backend. +

+ Trilhas Recomendadas +

+

+ Listas editoriais organizadas por tópicos específicos ou fundamentos + gerais.

{tracks.map((t) => ( - + {t.title} - {t.summary} -

{t.problemSlugs.length} problemas

+ + {t.summary} + +

+ {t.problemSlugs.length} problemas +

@@ -47,7 +71,10 @@ export default async function TracksIndexPage() {

- + Voltar ao catálogo completo

diff --git a/components/catalog/problems-catalog-client.tsx b/components/catalog/problems-catalog-client.tsx index a0bd59e..d3343fe 100644 --- a/components/catalog/problems-catalog-client.tsx +++ b/components/catalog/problems-catalog-client.tsx @@ -1,43 +1,54 @@ -'use client'; +"use client"; -import { useMemo, useState } from 'react'; -import Link from 'next/link'; -import { Clock } from 'lucide-react'; +import { Clock } from "lucide-react"; +import Link from "next/link"; +import { useMemo, useState } from "react"; -import { Badge } from '@/components/ui/badge'; -import { CatalogReviewSection } from '@/components/catalog/catalog-review-section'; -import { ProgressBackupControls } from '@/components/catalog/progress-backup-controls'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { DifficultyBadge } from '@/components/catalog/difficulty-badge'; -import { ProblemStatusBadge } from '@/components/catalog/problem-status-badge'; -import { Input } from '@/components/ui/input'; -import type { ProblemsCatalogProblem } from '@/lib/catalog/problem-card-model'; -import { catalogCategoryLabels, categoryLabelPt } from '@/lib/catalog/category-labels'; -import type { SortMode } from '@/lib/catalog/problem-filters'; +import { CatalogReviewSection } from "@/components/catalog/catalog-review-section"; +import { DifficultyBadge } from "@/components/catalog/difficulty-badge"; +import { ProblemStatusBadge } from "@/components/catalog/problem-status-badge"; +import { ProgressBackupControls } from "@/components/catalog/progress-backup-controls"; +import { Badge } from "@/components/ui/badge"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { + catalogCategoryLabels, + categoryLabelPt, +} from "@/lib/catalog/category-labels"; +import type { ProblemsCatalogProblem } from "@/lib/catalog/problem-card-model"; +import type { SortMode } from "@/lib/catalog/problem-filters"; import { DIFFICULTY_LABEL_PT, filterProblems, sortCatalogProblems, type CategoryFilter, -} from '@/lib/catalog/problem-filters'; -import type { Category, Difficulty } from '@/lib/content/schemas'; +} from "@/lib/catalog/problem-filters"; +import type { Category, Difficulty } from "@/lib/content/schemas"; interface Props { problems: ProblemsCatalogProblem[]; } const SORT_LABEL: Record = { - recommended: 'Ordem recomendada', - difficulty_asc: 'Dificuldade (fácil → difícil)', - title_az: 'Título (A–Z)', + recommended: "Ordem recomendada", + difficulty_asc: "Dificuldade (fácil → difícil)", + title_az: "Título (A–Z)", }; export function ProblemsCatalogClient({ problems }: Props) { const categories = catalogCategoryLabels(); - const [q, setQ] = useState(''); - const [difficultyFilter, setDifficultyFilter] = useState('all'); - const [categoryFilter, setCategoryFilter] = useState('all'); - const [sortMode, setSortMode] = useState('recommended'); + const [q, setQ] = useState(""); + const [difficultyFilter, setDifficultyFilter] = useState( + "all", + ); + const [categoryFilter, setCategoryFilter] = useState("all"); + const [sortMode, setSortMode] = useState("recommended"); const filteredSorted = useMemo(() => { const f = filterProblems(problems, q, difficultyFilter, categoryFilter); @@ -47,16 +58,20 @@ export function ProblemsCatalogClient({ problems }: Props) { return (
-
- - SYSTEM.CATALOG_v1.0 +
+ + Lista de problemas -

- Catálogo de
problemas +

+ Catálogo de problemas

-

- Filtra por dificuldade e categoria, pesquisa por título e segue a ordem recomendada de aprendizagem. - O progresso fica no teu browser (localStorage); com conta Pro podes sincronizar na nuvem após iniciar sessão. +

+ Filtra por dificuldade e categoria, pesquisa por título e segue a + ordem recomendada. O progresso fica no teu browser; sincroniza na + nuvem com conta Pro.

Trilhos curados (por tema e ordem editorial) - + Novidades

@@ -75,7 +93,10 @@ export function ProblemsCatalogClient({ problems }: Props) {
-
-
-
-
-
-