Техніка & 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..."
}