diff --git a/.gitignore b/.gitignore index ba354d25..c7e1b1d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ .env +.env.local .netlify .hugo_build.lock -node_modules +node_modules/ +.cache/ public resources +.DS_Store diff --git a/README.md b/README.md index 61ec4ed4..80029d10 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# FACODI — Faculdade Comunitária Digital +# FACODI — Catálogo de Conteúdo (`facodi-docs`) + +Este repositório concentra o conteúdo versionado e a configuração Hugo/Supabase que sustentam o catálogo estático da FACODI. Ele substitui o antigo pacote `facodi.pt`, mantendo apenas Markdown, configurações e automações descritas no plano `facodi-docs`. A **FACODI** é uma plataforma de aprendizagem aberta que replica planos curriculares da Universidade do Algarve (UAlg) em formato digital. Todo o conteúdo é escrito em Markdown, sincronizado com o Supabase e disponibilizado como um site estático construído com [Hugo](https://gohugo.io/) (tema Doks). @@ -12,7 +14,7 @@ A **FACODI** é uma plataforma de aprendizagem aberta que replica planos curricu - 🎓 Unidades curriculares com ementa, resultados de aprendizagem e tópicos - 🎥 Playlists abertas do YouTube organizadas por prioridade - 📝 Conteúdo em Markdown sincronizado automaticamente com o Supabase -- 🌐 Multilíngue (PT como padrão, EN preparado como fallback) +- 🌐 Multilíngue (PT, EN, ES e FR, com navegação consistente entre diretórios) --- @@ -28,20 +30,29 @@ A **FACODI** é uma plataforma de aprendizagem aberta que replica planos curricu ## 📂 Estrutura do repositório ```bash -facodi.pt/ +facodi-docs/ ├─ README.md ├─ config/ │ └─ _default/ ├─ content/ -│ ├─ _index.md -│ └─ courses/ -│ └─ LESTI/ -│ └─ 2024-2025/ -│ ├─ index.md # Curso -│ └─ uc/ -│ └─ LESTI-ALG1/ -│ ├─ index.md # Unidade curricular -│ └─ estruturas-de-dados.md # Tópico +│ ├─ pt/ +│ │ ├─ _index.md +│ │ └─ courses/ +│ │ └─ LESTI/ +│ │ └─ 2024-2025/ +│ │ ├─ index.md # Curso +│ │ └─ uc/ +│ │ └─ LESTI-ALG1/ +│ │ ├─ index.md # Unidade curricular +│ │ └─ estruturas-de-dados.md # Tópico +│ ├─ en/_index.md +│ ├─ es/_index.md +│ └─ fr/_index.md +├─ i18n/ +│ ├─ pt.toml +│ ├─ en.toml +│ ├─ es.toml +│ └─ fr.toml ├─ layouts/ │ ├─ _default/baseof.html │ ├─ course/single.html @@ -51,6 +62,9 @@ facodi.pt/ │ └─ js/ │ ├─ loaders.js │ └─ supabaseClient.js +├─ scripts/ +│ ├─ validate-frontmatter.js +│ └─ sync-content.mjs ├─ supabase/ │ ├─ migrations/ │ │ └─ ... sql @@ -63,6 +77,14 @@ facodi.pt/ --- +## 📐 Arquitetura e separação de responsabilidades + +- **Hugo (`facodi-docs`)**: entrega o catálogo estático com i18n, layouts customizados e carregadores JavaScript leves. O build usa apenas variáveis de ambiente fornecidas pela plataforma de deploy, sem chaves persistidas em arquivos de configuração. +- **Portal dinâmico (Next.js)**: continuará responsável por experiências autenticadas e interativas. Ele deverá consumir os mesmos dados do Supabase por meio de chamadas client-side, mantendo a separação entre conteúdo estático e funcionalidades do portal. +- **Automação**: os scripts `validate-frontmatter` e `sync-content` são executados localmente ou via GitHub Actions para garantir que o Markdown siga o esquema Supabase e que a sincronização aconteça apenas a partir do serviço (sem chaves embutidas). + +--- + ## 🛠️ Scripts disponíveis | Script | Descrição | diff --git a/config/_default/hugo.toml b/config/_default/hugo.toml index 72679145..09ac7205 100644 --- a/config/_default/hugo.toml +++ b/config/_default/hugo.toml @@ -10,7 +10,7 @@ rssLimit = 10 summarylength = 40 defaultContentLanguage = "pt" -defaultContentLanguageInSubdir = false +defaultContentLanguageInSubdir = true copyRight = "FACODI — Conteúdo aberto para aprendizagem comunitária" diff --git a/config/_default/languages.toml b/config/_default/languages.toml index 8846aa2e..f06d197b 100644 --- a/config/_default/languages.toml +++ b/config/_default/languages.toml @@ -1,6 +1,6 @@ [pt] languageName = "Português" - contentDir = "content" + contentDir = "content/pt" weight = 1 [pt.params] languageISO = "PT" @@ -14,4 +14,22 @@ [en.params] languageISO = "EN" languageTag = "en-US" - footer = 'Built by the FACODI community. English content coming soon.' + footer = 'Built by the FACODI community with Hugo and Supabase.' + +[es] + languageName = "Español" + contentDir = "content/es" + weight = 3 + [es.params] + languageISO = "ES" + languageTag = "es-ES" + footer = 'Construido por la comunidad FACODI con Hugo y Supabase.' + +[fr] + languageName = "Français" + contentDir = "content/fr" + weight = 4 + [fr.params] + languageISO = "FR" + languageTag = "fr-FR" + footer = 'Construit par la communauté FACODI avec Hugo et Supabase.' diff --git a/config/_default/menus/menus.en.toml b/config/_default/menus/menus.en.toml index 91a65ca0..4036e5a8 100644 --- a/config/_default/menus/menus.en.toml +++ b/config/_default/menus/menus.en.toml @@ -4,6 +4,6 @@ weight = 10 [[footer]] - name = "Open Source" + name = "Community" url = "https://github.com/Monynha-Softwares/facodi.pt" weight = 10 diff --git a/config/_default/menus/menus.es.toml b/config/_default/menus/menus.es.toml new file mode 100644 index 00000000..3afba7b9 --- /dev/null +++ b/config/_default/menus/menus.es.toml @@ -0,0 +1,9 @@ +[[main]] + name = "Cursos" + url = "/" + weight = 10 + +[[footer]] + name = "Comunidad" + url = "https://github.com/Monynha-Softwares/facodi.pt" + weight = 10 diff --git a/config/_default/menus/menus.fr.toml b/config/_default/menus/menus.fr.toml new file mode 100644 index 00000000..b43ee009 --- /dev/null +++ b/config/_default/menus/menus.fr.toml @@ -0,0 +1,9 @@ +[[main]] + name = "Cours" + url = "/" + weight = 10 + +[[footer]] + name = "Communauté" + url = "https://github.com/Monynha-Softwares/facodi.pt" + weight = 10 diff --git a/config/_default/params.toml b/config/_default/params.toml index 1ce8f688..6e1bb80d 100644 --- a/config/_default/params.toml +++ b/config/_default/params.toml @@ -63,10 +63,6 @@ mainSections = ["courses"] krokiURL = "https://kroki.io" -[supabase] - url = "" - anon_key = "" - [seo] [seo.title] separator = " | " diff --git a/content/en/_index.md b/content/en/_index.md index 41521c1f..8466c49b 100644 --- a/content/en/_index.md +++ b/content/en/_index.md @@ -1,7 +1,8 @@ --- title: "FACODI Catalog" layout: home -draft: true +draft: false +lead: "Open academic catalog curated by the FACODI community." --- -FACODI content is primarily authored in Portuguese. English translations will be published as they become available. +FACODI content is primarily authored in Portuguese. English translations will be published as they become available. Subscribe to the community updates to know when new translations launch. diff --git a/content/es/_index.md b/content/es/_index.md new file mode 100644 index 00000000..4db8b300 --- /dev/null +++ b/content/es/_index.md @@ -0,0 +1,8 @@ +--- +title: "Catálogo FACODI" +layout: home +draft: false +lead: "Catálogo académico abierto, impulsado por la comunidad FACODI." +--- + +El contenido completo está disponible primero en portugués. Las traducciones al español se publicarán de forma progresiva con el apoyo de la comunidad. diff --git a/content/fr/_index.md b/content/fr/_index.md new file mode 100644 index 00000000..83e62ead --- /dev/null +++ b/content/fr/_index.md @@ -0,0 +1,8 @@ +--- +title: "Catalogue FACODI" +layout: home +draft: false +lead: "Catalogue académique ouvert animé par la communauté FACODI." +--- + +Le catalogue FACODI est d'abord rédigé en portugais. Les traductions en français seront publiées progressivement avec l'aide de la communauté. diff --git a/content/_index.md b/content/pt/_index.md similarity index 100% rename from content/_index.md rename to content/pt/_index.md diff --git a/content/courses/LESTI/2024-2025/index.md b/content/pt/courses/LESTI/2024-2025/index.md similarity index 100% rename from content/courses/LESTI/2024-2025/index.md rename to content/pt/courses/LESTI/2024-2025/index.md diff --git a/content/courses/LESTI/2024-2025/uc/LESTI-ALG1/estruturas-de-dados.md b/content/pt/courses/LESTI/2024-2025/uc/LESTI-ALG1/estruturas-de-dados.md similarity index 100% rename from content/courses/LESTI/2024-2025/uc/LESTI-ALG1/estruturas-de-dados.md rename to content/pt/courses/LESTI/2024-2025/uc/LESTI-ALG1/estruturas-de-dados.md diff --git a/content/courses/LESTI/2024-2025/uc/LESTI-ALG1/index.md b/content/pt/courses/LESTI/2024-2025/uc/LESTI-ALG1/index.md similarity index 100% rename from content/courses/LESTI/2024-2025/uc/LESTI-ALG1/index.md rename to content/pt/courses/LESTI/2024-2025/uc/LESTI-ALG1/index.md diff --git a/i18n/en.toml b/i18n/en.toml new file mode 100644 index 00000000..689077bd --- /dev/null +++ b/i18n/en.toml @@ -0,0 +1,42 @@ +home_course_plan = { other = "Plan {{ .plan }}" } +home_course_ects = { other = "{{ .ects }} ECTS" } +home_course_semesters = { other = "{{ .count }} semesters" } +home_course_summary_fallback = { other = "Documentation in progress." } +home_no_courses = { other = "No courses published yet. Check back soon!" } + +course_header_label = { other = "Course {{ .code }}" } +course_plan_label = { other = "Curriculum plan {{ .plan }}" } +course_synced_title = { other = "Synced content" } +course_synced_loading = { other = "Loading detailed description from Supabase…" } +course_uc_title = { other = "Course units" } +course_uc_loading = { other = "Loading course units…" } +course_details_title = { other = "Course details" } +course_details_institution = { other = "Institution" } +course_details_school = { other = "School" } +course_details_ects = { other = "ECTS" } +course_details_duration = { other = "Duration" } +course_details_language = { other = "Language" } + +uc_header_label = { other = "Course unit {{ .code }}" } +uc_content_title = { other = "Official syllabus" } +uc_content_loading = { other = "Syncing syllabus and materials…" } +uc_outcomes_title = { other = "Learning outcomes" } +uc_outcomes_loading = { other = "Loading outcomes…" } +uc_playlists_title = { other = "Recommended playlists" } +uc_playlists_loading = { other = "Loading playlists…" } +uc_topics_title = { other = "Associated topics" } +uc_topics_loading = { other = "Loading topics…" } +uc_details_title = { other = "Information" } +uc_details_course = { other = "Course" } +uc_details_ects = { other = "ECTS" } +uc_details_semester = { other = "Semester" } +uc_details_language = { other = "Language" } +uc_details_prerequisites = { other = "Prerequisites" } + +topic_header_label = { other = "Topic {{ .slug }}" } +topic_content_title = { other = "Synced content" } +topic_content_loading = { other = "Loading Markdown content…" } +topic_playlists_title = { other = "Related playlists" } +topic_playlists_loading = { other = "Loading playlists…" } +topic_tags_title = { other = "Tags" } +topic_tags_loading = { other = "Loading tags…" } diff --git a/i18n/es.toml b/i18n/es.toml new file mode 100644 index 00000000..c691d4a9 --- /dev/null +++ b/i18n/es.toml @@ -0,0 +1,42 @@ +home_course_plan = { other = "Plan {{ .plan }}" } +home_course_ects = { other = "{{ .ects }} ECTS" } +home_course_semesters = { other = "{{ .count }} semestres" } +home_course_summary_fallback = { other = "Documentación en preparación." } +home_no_courses = { other = "Todavía no hay cursos publicados. ¡Vuelve pronto!" } + +course_header_label = { other = "Curso {{ .code }}" } +course_plan_label = { other = "Plan curricular {{ .plan }}" } +course_synced_title = { other = "Contenido sincronizado" } +course_synced_loading = { other = "Cargando descripción detallada desde Supabase…" } +course_uc_title = { other = "Asignaturas" } +course_uc_loading = { other = "Cargando asignaturas…" } +course_details_title = { other = "Detalles del curso" } +course_details_institution = { other = "Institución" } +course_details_school = { other = "Escuela" } +course_details_ects = { other = "ECTS" } +course_details_duration = { other = "Duración" } +course_details_language = { other = "Idioma" } + +uc_header_label = { other = "Unidad curricular {{ .code }}" } +uc_content_title = { other = "Plan oficial" } +uc_content_loading = { other = "Sincronizando programa y materiales…" } +uc_outcomes_title = { other = "Resultados de aprendizaje" } +uc_outcomes_loading = { other = "Cargando resultados…" } +uc_playlists_title = { other = "Listas recomendadas" } +uc_playlists_loading = { other = "Cargando listas de reproducción…" } +uc_topics_title = { other = "Temas asociados" } +uc_topics_loading = { other = "Cargando temas…" } +uc_details_title = { other = "Información" } +uc_details_course = { other = "Curso" } +uc_details_ects = { other = "ECTS" } +uc_details_semester = { other = "Semestre" } +uc_details_language = { other = "Idioma" } +uc_details_prerequisites = { other = "Requisitos previos" } + +topic_header_label = { other = "Tema {{ .slug }}" } +topic_content_title = { other = "Contenido sincronizado" } +topic_content_loading = { other = "Cargando contenido Markdown…" } +topic_playlists_title = { other = "Listas relacionadas" } +topic_playlists_loading = { other = "Cargando listas de reproducción…" } +topic_tags_title = { other = "Etiquetas" } +topic_tags_loading = { other = "Cargando etiquetas…" } diff --git a/i18n/fr.toml b/i18n/fr.toml new file mode 100644 index 00000000..2447c05a --- /dev/null +++ b/i18n/fr.toml @@ -0,0 +1,42 @@ +home_course_plan = { other = "Plan {{ .plan }}" } +home_course_ects = { other = "{{ .ects }} ECTS" } +home_course_semesters = { other = "{{ .count }} semestres" } +home_course_summary_fallback = { other = "Documentation en préparation." } +home_no_courses = { other = "Aucun cours publié pour le moment. Revenez bientôt !" } + +course_header_label = { other = "Cours {{ .code }}" } +course_plan_label = { other = "Programme {{ .plan }}" } +course_synced_title = { other = "Contenu synchronisé" } +course_synced_loading = { other = "Chargement de la description détaillée depuis Supabase…" } +course_uc_title = { other = "Unités curriculaires" } +course_uc_loading = { other = "Chargement des unités curriculaires…" } +course_details_title = { other = "Détails du cours" } +course_details_institution = { other = "Institution" } +course_details_school = { other = "École" } +course_details_ects = { other = "ECTS" } +course_details_duration = { other = "Durée" } +course_details_language = { other = "Langue" } + +uc_header_label = { other = "Unité curriculaire {{ .code }}" } +uc_content_title = { other = "Programme officiel" } +uc_content_loading = { other = "Synchronisation du programme et des supports…" } +uc_outcomes_title = { other = "Résultats d'apprentissage" } +uc_outcomes_loading = { other = "Chargement des résultats…" } +uc_playlists_title = { other = "Playlists recommandées" } +uc_playlists_loading = { other = "Chargement des playlists…" } +uc_topics_title = { other = "Sujets associés" } +uc_topics_loading = { other = "Chargement des sujets…" } +uc_details_title = { other = "Informations" } +uc_details_course = { other = "Cours" } +uc_details_ects = { other = "ECTS" } +uc_details_semester = { other = "Semestre" } +uc_details_language = { other = "Langue" } +uc_details_prerequisites = { other = "Prérequis" } + +topic_header_label = { other = "Sujet {{ .slug }}" } +topic_content_title = { other = "Contenu synchronisé" } +topic_content_loading = { other = "Chargement du contenu Markdown…" } +topic_playlists_title = { other = "Playlists associées" } +topic_playlists_loading = { other = "Chargement des playlists…" } +topic_tags_title = { other = "Étiquettes" } +topic_tags_loading = { other = "Chargement des étiquettes…" } diff --git a/i18n/pt.toml b/i18n/pt.toml new file mode 100644 index 00000000..2bb473eb --- /dev/null +++ b/i18n/pt.toml @@ -0,0 +1,42 @@ +home_course_plan = { other = "Plano {{ .plan }}" } +home_course_ects = { other = "{{ .ects }} ECTS" } +home_course_semesters = { other = "{{ .count }} semestres" } +home_course_summary_fallback = { other = "Documentação em preparação." } +home_no_courses = { other = "Nenhum curso publicado ainda. Volte em breve!" } + +course_header_label = { other = "Curso {{ .code }}" } +course_plan_label = { other = "Plano curricular {{ .plan }}" } +course_synced_title = { other = "Conteúdo sincronizado" } +course_synced_loading = { other = "Carregando descrição detalhada a partir do Supabase…" } +course_uc_title = { other = "Unidades curriculares" } +course_uc_loading = { other = "Carregando unidades curriculares…" } +course_details_title = { other = "Detalhes do curso" } +course_details_institution = { other = "Instituição" } +course_details_school = { other = "Escola" } +course_details_ects = { other = "ECTS" } +course_details_duration = { other = "Duração" } +course_details_language = { other = "Idioma" } + +uc_header_label = { other = "Unidade curricular {{ .code }}" } +uc_content_title = { other = "Conteúdo oficial" } +uc_content_loading = { other = "Sincronizando ementa e materiais…" } +uc_outcomes_title = { other = "Resultados de aprendizagem" } +uc_outcomes_loading = { other = "Carregando resultados…" } +uc_playlists_title = { other = "Playlists recomendadas" } +uc_playlists_loading = { other = "Carregando playlists…" } +uc_topics_title = { other = "Tópicos associados" } +uc_topics_loading = { other = "Carregando tópicos…" } +uc_details_title = { other = "Informações" } +uc_details_course = { other = "Curso" } +uc_details_ects = { other = "ECTS" } +uc_details_semester = { other = "Semestre" } +uc_details_language = { other = "Idioma" } +uc_details_prerequisites = { other = "Pré-requisitos" } + +topic_header_label = { other = "Tópico {{ .slug }}" } +topic_content_title = { other = "Conteúdo sincronizado" } +topic_content_loading = { other = "Carregando conteúdo Markdown…" } +topic_playlists_title = { other = "Playlists relacionadas" } +topic_playlists_loading = { other = "Carregando playlists…" } +topic_tags_title = { other = "Etiquetas" } +topic_tags_loading = { other = "Carregando tags…" } diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index a98637f9..0139224b 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -1,5 +1,6 @@ - +{{- $langTag := .Language.Params.languageTag | default .Language.LanguageCode | default .Site.LanguageCode | default "pt" -}} + {{ partial "head/head" . }} {{ partial "head/body-class" . }}
diff --git a/layouts/_partials/footer/script-footer-custom.html b/layouts/_partials/footer/script-footer-custom.html index 9a1de999..a0f06c31 100644 --- a/layouts/_partials/footer/script-footer-custom.html +++ b/layouts/_partials/footer/script-footer-custom.html @@ -1,5 +1,5 @@ -{{- $supabaseUrl := site.Params.supabase.url | default (getenv "SUPABASE_URL") -}} -{{- $supabaseAnon := site.Params.supabase.anon_key | default (getenv "SUPABASE_ANON_KEY") -}} +{{- $supabaseUrl := (getenv "SUPABASE_URL") | default "" -}} +{{- $supabaseAnon := (getenv "SUPABASE_ANON_KEY") | default "" -}}