Техніка & AHA-Stack

Як була побудована Математична Скринька

Математична Скринька - це демо-додаток для AHA-Stack та @casoon/fragment-renderer. Вона показує, як можна створювати сучасні веб-додатки з мінімальним JavaScript та максимальною продуктивністю.

Що таке AHA-Stack?

AHA-Stack поєднує три легкі технології:

Astro

Astro - Сучасний веб-фреймворк для сайтів з фокусом на контент з нульовим JS за замовчуванням

HTMX

HTMX - Забезпечує динамічні взаємодії через HTML-атрибути замість JavaScript

Alpine.js

Alpine.js - Легкий JavaScript для реактивних UI-компонентів

@casoon/fragment-renderer

Fragment Renderer - це бібліотека від casoon, яка дозволяє серверний рендеринг Astro-компонентів як HTML-фрагментів. Це ідеально підходить для HTMX-додатків.

Можливості:

  • Серверний рендеринг Astro-компонентів
  • HTMX-інтеграція з автоматичними заголовками відповіді
  • Preset для AHA-Stack
  • TypeScript підтримка

Приклад: Фрагмент зворотного зв'язку

Ось як рендериться зворотний зв'язок у Математичній Скриньці після відповіді:

// task-renderer.ts
import { createAstroRuntime } from "@casoon/fragment-renderer";
import { ahaStackPreset } from "@casoon/fragment-renderer/presets/aha-stack";

const runtime = createAstroRuntime({
  ...ahaStackPreset({ locale, htmxHeaders: true }),
  components: [
    { id: "feedback-correct", loader: () => import("./FeedbackCorrect.astro") },
    { id: "feedback-incorrect", loader: () => import("./FeedbackIncorrect.astro") },
  ],
});

// Render feedback as HTML fragment
const html = await runtime.renderToString({
  componentId: result.isCorrect ? "feedback-correct" : "feedback-incorrect",
  props: { locale, nextUrl, isComplete },
});

Система завдань

Математична Скринька використовує модульну систему завдань з:

  • Єдиний інтерфейс для всіх типів завдань
  • Самоперевіряючі завдання з підказками
  • SVG-візуалізації для геометрії та дробів
  • Підтримка множинного вибору та drag-and-drop
  • Адаптивна складність та повторення помилок
// Unified Task Interface
interface TaskInstance {
  id: string;
  question: string;
  validate(answer: string): ValidationResult;
  getHint(): string;
  getCorrectAnswer(): string | number;
}

// Self-validating task
const result = task.validate(userAnswer);
if (!result.isCorrect) {
  console.log(result.hint);  // "Der kleine Zeiger zeigt die Stunde..."
}

Посилання