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
1 change: 1 addition & 0 deletions .munkit/MEMORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ IMASUS App is the participant-facing workshop application for the IMASUS project
- Production transactional email uses Amazon SES SMTP in `eu-west-1` through a dedicated IAM SMTP user. Fly secrets: `MAILER_FROM`, `SMTP_ADDRESS`, `SMTP_PORT`, `SMTP_DOMAIN`, `SMTP_USERNAME`, `SMTP_PASSWORD`; optional `SMTP_AUTHENTICATION` and `SMTP_ENABLE_STARTTLS_AUTO`. `APP_HOST` must be a bare hostname because mailers generate absolute invitation and password-reset links from it.
- Initial Fly launch uses `ACTIVE_JOB_QUEUE_ADAPTER=async` and does not set `SOLID_QUEUE_IN_PUMA` because the production Solid Queue tables still need explicit schema provisioning.
- Fly sets the primary `DATABASE_URL`; production `cache`, `queue`, and `cable` database configs fall back to that same URL unless `CACHE_DATABASE_URL`, `QUEUE_DATABASE_URL`, or `CABLE_DATABASE_URL` are explicitly provided later.
- Production analytics uses the Plausible-compatible script hosted at `stats.munkun.com`. It is rendered only in production, does not use an analytics cookie banner, and is disclosed in the Privacy Policy alongside the app's session and locale cookies.

## Boundaries

Expand Down
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ This repository keeps durable project context under `.munkit/`. Read those files
- Record durable findings in `.munkit/MEMORY.md`, `.munkit/DECISIONS.md`, or the relevant spec `notes.md`, not only in chat.
- When one worktree lands first, rebase or merge forward in the other worktree before continuing.

## Merge Method

- Use Squash and merge for normal feature/fix PRs so `main` keeps one commit per reviewed slice.
- After a squash merge, local feature branch commits are not ancestors of `main`, so `git branch -d` may report "not fully merged" even when the PR content landed. Confirm the PR is merged, remove any worktree for the branch, then delete the local branch with `git branch -D <branch>`.
- Use merge commits only for intentional long-running branches where preserving individual commits matters.

## Specs

Each spec contains:
Expand Down
7 changes: 7 additions & 0 deletions app/assets/stylesheets/application.css
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,10 @@ details > summary::-webkit-details-marker { display: none; }

.trix-content strong { font-weight: 700; }
.trix-content em { font-style: italic; }

trix-toolbar .trix-button--text {
min-width: 2.6em;
height: 1.6em;
padding-inline: 0.55em;
text-indent: 0;
}
16 changes: 16 additions & 0 deletions app/controllers/legal_pages_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class LegalPagesController < ApplicationController
def privacy
render_page("privacy")
end

def terms
render_page("terms")
end

private

def render_page(page_key)
@page_key = page_key
render :show
end
end
1 change: 1 addition & 0 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "trix"
import "trix_headings"
import "@rails/actiontext"
import "controllers"
60 changes: 60 additions & 0 deletions app/javascript/trix_headings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const configureTrixHeadings = () => {
const Trix = window.Trix
if (!Trix) return

Trix.config.blockAttributes.heading2 ||= {
tagName: "h2",
terminal: true,
breakOnReturn: true,
group: false
}

Trix.config.blockAttributes.heading3 ||= {
tagName: "h3",
terminal: true,
breakOnReturn: true,
group: false
}

Trix.config.lang.heading2 ||= "Heading 2"
Trix.config.lang.heading3 ||= "Heading 3"
}

const addHeadingButtons = (toolbar) => {
const blockTools = toolbar.querySelector("[data-trix-button-group='block-tools']")
if (!blockTools || blockTools.querySelector("[data-trix-attribute='heading2']")) return

const heading1 = blockTools.querySelector("[data-trix-attribute='heading1']")
if (heading1) {
heading1.textContent = "H1"
heading1.classList.remove("trix-button--icon", "trix-button--icon-heading-1")
heading1.classList.add("trix-button--text")
}

const heading2 = document.createElement("button")
heading2.type = "button"
heading2.className = "trix-button trix-button--text"
heading2.dataset.trixAttribute = "heading2"
heading2.title = window.Trix.config.lang.heading2
heading2.tabIndex = -1
heading2.textContent = "H2"

const heading3 = document.createElement("button")
heading3.type = "button"
heading3.className = "trix-button trix-button--text"
heading3.dataset.trixAttribute = "heading3"
heading3.title = window.Trix.config.lang.heading3
heading3.tabIndex = -1
heading3.textContent = "H3"

heading1?.after(heading2, heading3)
}

configureTrixHeadings()

document.addEventListener("trix-before-initialize", configureTrixHeadings)

document.addEventListener("trix-initialize", (event) => {
const toolbar = event.target.toolbarElement
if (toolbar) addHeadingButtons(toolbar)
})
18 changes: 11 additions & 7 deletions app/views/home/_recent_bookmarks.html.erb
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
<%
bookmarks = local_assigns.fetch(:bookmarks)
bookmark_dot_color = {
"TrainingModule" => "bg-imasus-navy",
"Material" => "bg-imasus-light-blue",
"Challenge" => "bg-imasus-mint",
"GlossaryTerm" => "bg-imasus-light-pink"
}
%>

<% if bookmarks.any? %>
Expand All @@ -20,9 +14,19 @@
</div>
<ul class="mt-3 divide-y divide-imasus-dark-green/5">
<% bookmarks.each do |bookmark| %>
<% preview_src = bookmark_preview_image_src(bookmark) %>
<li class="flex items-center gap-3 py-2">
<span class="mt-px h-2 w-2 shrink-0 rounded-full <%= bookmark_dot_color.fetch(bookmark.bookmarkable_type, "bg-imasus-dark-green/20") %>"
<span class="mt-px h-2 w-2 shrink-0 rounded-full <%= bookmark_dot_color(bookmark) %>"
title="<%= bookmark.bookmarkable_type.underscore.humanize %>"></span>
<% if preview_src.present? %>
<%= link_to bookmark.url, class: "shrink-0", aria: { label: bookmark.label } do %>
<%= image_tag preview_src,
alt: "",
loading: "lazy",
data: { bookmark_preview: "" },
class: "h-10 w-14 rounded-md border border-imasus-dark-green/10 object-cover" %>
<% end %>
<% end %>
<%= link_to bookmark.label, bookmark.url,
class: "min-w-0 flex-1 truncate text-sm font-medium text-imasus-dark-green hover:underline" %>
</li>
Expand Down
8 changes: 8 additions & 0 deletions app/views/layouts/_plausible_analytics.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<% if Rails.env.production? %>
<!-- Privacy-friendly analytics by Plausible -->
<%= javascript_include_tag "https://stats.munkun.com/js/pa-AEv3S9_hJMk___wHOsvRL.js", async: true %>
<%= javascript_tag do %>
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
plausible.init()
<% end %>
<% end %>
1 change: 1 addition & 0 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<%= render "layouts/social_meta" %>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= render "layouts/plausible_analytics" %>

<%= yield :head %>

Expand Down
1 change: 1 addition & 0 deletions app/views/layouts/public.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<%= render "layouts/social_meta" %>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= render "layouts/plausible_analytics" %>

<%= yield :head %>

Expand Down
29 changes: 29 additions & 0 deletions app/views/legal_pages/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<% content_for :title, t("legal.#{@page_key}.title") %>

<section class="bg-stone-100 px-6 py-12 sm:px-10 lg:px-16">
<div class="mx-auto max-w-3xl">
<p class="text-xs font-bold uppercase tracking-widest text-imasus-dark-green/50"><%= t("legal.eyebrow") %></p>
<h1 class="mt-3 text-4xl font-bold text-imasus-dark-green"><%= t("legal.#{@page_key}.title") %></h1>
<p class="mt-4 text-base leading-relaxed text-imasus-dark-green/70"><%= t("legal.#{@page_key}.lead") %></p>

<div class="mt-10 space-y-8 rounded-lg border border-imasus-dark-green/10 bg-white p-6 shadow-sm sm:p-8">
<% t("legal.#{@page_key}.sections").each do |section| %>
<section class="space-y-3">
<h2 class="text-lg font-bold text-imasus-dark-green"><%= section[:title] || section["title"] %></h2>

<% Array(section[:paragraphs] || section["paragraphs"]).each do |paragraph| %>
<p class="text-sm leading-relaxed text-imasus-dark-green/75"><%= paragraph %></p>
<% end %>

<% if section[:bullets] || section["bullets"] %>
<ul class="list-disc space-y-2 pl-5 text-sm leading-relaxed text-imasus-dark-green/75">
<% Array(section[:bullets] || section["bullets"]).each do |bullet| %>
<li><%= bullet %></li>
<% end %>
</ul>
<% end %>
</section>
<% end %>
</div>
</div>
</section>
15 changes: 14 additions & 1 deletion app/views/shared/_footer.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,20 @@
</div>

<div class="flex flex-col gap-4 border-t border-white/10 pt-6 sm:flex-row sm:items-center sm:justify-between">
<p class="text-xs text-white/40"><%= t("footer.copyright") %></p>
<div class="flex flex-col gap-3 text-xs text-white/40 sm:flex-row sm:items-center sm:gap-5">
<p>
<%= t("footer.copyright_prefix") %>
<%= link_to t("footer.project_name"),
"https://imasus.eu",
target: "_blank",
rel: "noopener noreferrer",
class: "underline underline-offset-2 transition hover:text-white" %>.
</p>
<nav aria-label="<%= t("footer.legal_label") %>" class="flex gap-4">
<%= link_to t("footer.privacy"), privacy_path, class: "underline underline-offset-2 transition hover:text-white" %>
<%= link_to t("footer.terms"), terms_path, class: "underline underline-offset-2 transition hover:text-white" %>
</nav>
</div>
<%= link_to "https://munkun.com",
target: "_blank",
rel: "noopener noreferrer",
Expand Down
1 change: 1 addition & 0 deletions config/importmap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

pin "application"
pin "trix"
pin "trix_headings"
pin "@rails/actiontext", to: "actiontext.esm.js"
pin "@hotwired/turbo-rails", to: "turbo.min.js"
pin "@hotwired/stimulus", to: "stimulus.min.js"
Expand Down
4 changes: 4 additions & 0 deletions config/locales/el.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ el:
project_name: "IMASUS"
eu_notice: "Χρηματοδοτείται από την Ευρωπαϊκή Ένωση. Οι απόψεις και οι γνώμες που εκφράζονται είναι αποκλειστικά του/των συγγραφέα/ων και δεν αντικατοπτρίζουν κατ' ανάγκη τις απόψεις της Ευρωπαϊκής Ένωσης ή του Ευρωπαϊκού Εκτελεστικού Οργανισμού Εκπαίδευσης και Πολιτισμού (EACEA). Ούτε η Ευρωπαϊκή Ένωση ούτε ο EACEA μπορούν να θεωρηθούν υπεύθυνοι γι' αυτές."
copyright: "© 2024–2026 Έργο IMASUS."
copyright_prefix: "© 2024–2026 Έργο"
developed_by: "Αναπτύχθηκε από"
legal_label: "Νομικοί σύνδεσμοι"
privacy: "Πολιτική απορρήτου"
terms: "Όροι χρήσης"
partners_label: "Εταίροι"
partners:
inma: "INMA (CSIC)"
Expand Down
4 changes: 4 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ en:
project_name: "IMASUS"
eu_notice: "Funded by the European Union. Views and opinions expressed are however those of the author(s) only and do not necessarily reflect those of the European Union or the European Education and Culture Executive Agency (EACEA). Neither the European Union nor EACEA can be held responsible for them."
copyright: "© 2024–2026 IMASUS Project."
copyright_prefix: "© 2024–2026"
developed_by: "Developed by"
legal_label: "Legal links"
privacy: "Privacy policy"
terms: "Terms of use"
partners_label: "Partners"
partners:
inma: "INMA (CSIC)"
Expand Down
4 changes: 4 additions & 0 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ es:
project_name: "IMASUS"
eu_notice: "Financiado por la Unión Europea. Las opiniones expresadas son exclusivamente las del autor o autores y no reflejan necesariamente las de la Unión Europea ni las de la Agencia Ejecutiva Europea de Educación y Cultura (EACEA). Ni la Unión Europea ni la EACEA pueden ser consideradas responsables de las mismas."
copyright: "© 2024–2026 Proyecto IMASUS."
copyright_prefix: "© 2024–2026 Proyecto"
developed_by: "Desarrollado por"
legal_label: "Enlaces legales"
privacy: "Política de privacidad"
terms: "Condiciones de uso"
partners_label: "Socios"
partners:
inma: "INMA (CSIC)"
Expand Down
4 changes: 4 additions & 0 deletions config/locales/it.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ it:
project_name: "IMASUS"
eu_notice: "Finanziato dall'Unione Europea. I punti di vista e le opinioni espresse sono tuttavia esclusivamente quelli dell'autore o degli autori e non riflettono necessariamente quelli dell'Unione Europea o dell'Agenzia esecutiva europea per l'istruzione e la cultura (EACEA). Né l'Unione Europea né l'EACEA possono essere ritenute responsabili."
copyright: "© 2024–2026 Progetto IMASUS."
copyright_prefix: "© 2024–2026 Progetto"
developed_by: "Sviluppato da"
legal_label: "Link legali"
privacy: "Informativa sulla privacy"
terms: "Termini di utilizzo"
partners_label: "Partner"
partners:
inma: "INMA (CSIC)"
Expand Down
Loading