Quizzman Modular Framework v3 — Framework frontend dạng modular, plugin-based, dùng cho toàn bộ hệ thống Quizzman.
echo '@qmf:registry=https://ui.quizzman.com/registry/' >> .npmrc && pnpm add @qmf/core @qmf/tokens
Kiến trúc 4 lớp · Plugin system · Error isolation · DevTools
Đăng ký module dạng plugin với dependency resolution tự động. Hỗ trợ eager & lazy loading.
Dependency injection dựa trên token — đăng ký và resolve service ở bất kỳ đâu trong app.
Mỗi module có error boundary riêng. Một module crash không ảnh hưởng đến module khác.
Global + isolated module store với Zod schema validation. Selector, watcher, immutable update.
Code-split module, chỉ load khi cần. CSS tự inject khi plugin mount.
Event tracing, state inspection, plugin graph — tất cả qua window.__QMF_DEVTOOLS__.
Pub/sub với wildcard, scoped bus, và tracing. Giao tiếp giữa các module không cần coupling.
Quản lý vòng đời module: onInit → onMount → onReady → onDestroy. Đồng bộ và async.
Fetch wrapper với interceptor, retry logic, auth injection, và error mapping tự động.
Mỗi lớp chỉ được import từ lớp thấp hơn — không có circular dependency.
Chọn cách tích hợp phù hợp với project của bạn.
<!-- 1. Load QMF -->
<link rel="stylesheet" href="https://ui.quizzman.com/qmf/dist/tokens.css">
<script src="https://ui.quizzman.com/qmf/dist/qmf.iife.js"></script>
<!-- 2. Init -->
<script>
QMF.init({
appId: 'my-app',
debug: true
}).then(() => {
console.log('QMF Ready!');
});
</script>
// 1. Add to .npmrc (one-time)
// echo '@qmf:registry=https://ui.quizzman.com/registry/' >> .npmrc
// 2. Install
// pnpm add @qmf/core @qmf/tokens @qmf/header
import { QMF, lazy } from '@qmf/core';
import { createHeaderPlugin } from '@qmf/header';
import '@qmf/tokens/css';
// Register plugins
QMF.use(createHeaderPlugin({ brandName: 'My App' }));
QMF.use(lazy(() => import('@qmf/chat-embed')));
// Initialize
await QMF.init({
appId: 'my-app',
channel: 'production',
debug: false
});
import { QMF, lazy, getGlobalEventBus } from '@qmf/core';
import { createHeaderPlugin } from '@qmf/header';
import { createFooterPlugin } from '@qmf/footer';
import '@qmf/tokens/css';
// 1. Register plugins (eager)
QMF.use(createHeaderPlugin({ brandName: 'QuizzMan LMS' }));
QMF.use(createFooterPlugin());
// 2. Register plugins (lazy — loaded on demand)
QMF.use(lazy(() => import('@qmf/chat-embed')));
QMF.use(lazy(() => import('@qmf/noti-embed')));
// 3. Init framework
await QMF.init({
appId: 'quizzman-lms',
channel: 'production',
debug: import.meta.env.DEV,
});
// 4. Use event bus
const bus = getGlobalEventBus();
bus.on('auth:login', (user) => console.log('Logged in:', user));
bus.emit('auth:login', { id: 1, name: 'Admin' });
// 5. Access store
const state = QMF.store.getState();
QMF.store.watch(s => s.user, (newUser) => {
console.log('User changed:', newUser);
});
Các API chính của @qmf/core
| Module | API | Mô tả |
|---|---|---|
| EventBus | on · off · emit · once |
Pub/sub với wildcard * và EventBus.scoped(prefix) |
| Store | getState · setState · select · watch |
Immutable state container, Zod validation, selector + watcher |
| Lifecycle | hook · transition |
Module lifecycle: onInit → onMount → onReady → onDestroy |
| Config | validateConfig · resolveEnvUrls |
Zod schema validation + environment URL resolution |
| HttpClient | get · post · put · delete |
Fetch wrapper: interceptor, retry, auth injection |
| DI | register · resolve · createToken |
Token-based dependency injection |
| PluginLoader | QMF.use · lazy |
Plugin registration với dependency graph + lazy loading |
| ErrorBoundary | protect · onError |
Per-module error isolation, fallback UI |
Notification pill — Hiển thị thông báo hệ thống dạng "viên thuốc" ở đầu trang, mở rộng khi hover/click.
Nhấn nút để xem Dynamic Island. Hover để mở rộng, click nút close hoặc chờ auto-dismiss.
<!-- 1. Load CSS + JS -->
<link rel="stylesheet"
href="https://ui.quizzman.com/qmf/dist/modules/header/dynamic-island.css">
<script src="https://ui.quizzman.com/qmf/dist/modules/header/dynamic-island.js"></script>
<!-- 2. Use -->
<script>
const island = new QMFDynamicIsland();
// Push a notification
island.push({
title: 'Cập nhật hệ thống',
message: 'Phiên bản 3.0 đã sẵn sàng!',
icon: 'fas fa-rocket',
priority: 'info', // info | success | warning | error | promo
duration: 6000, // ms, 0 = sticky
actions: [
{ label: 'Xem chi tiết', href: 'https://quizzman.com', primary: true },
{ label: 'Bỏ qua' }
]
});
</script>
// Constructor
const island = new QMFDynamicIsland({
autoDismiss: 6000, // Default auto-dismiss (ms)
maxQueue: 10, // Max queued notifications
hoverExpand: true, // Expand on hover (desktop)
container: document.body
});
// Methods
island.push(data) // Add notification to queue
island.dismiss() // Dismiss current, show next
island.expand() // Expand to full view
island.collapse() // Collapse to compact pill
island.clear() // Clear all notifications
// Notification data shape
{
title: 'string', // Required — Heading
message: 'string', // Required — Body text
icon: 'fas fa-bell', // FontAwesome class
priority: 'info', // info | success | warning | error | promo
duration: 6000, // Auto-dismiss ms (0 = sticky)
actions: [ // Optional buttons
{ label: 'Click', href: '...', primary: true },
{ label: 'Action', onClick: () => {} }
]
}
/* Override these CSS variables to customize */
:root {
--qmf-island-bg: rgba(15, 15, 30, 0.92); /* Background */
--qmf-island-border: rgba(255, 255, 255, 0.1);
--qmf-island-text: #ffffff;
--qmf-island-text-muted: rgba(255, 255, 255, 0.7);
--qmf-island-radius: 28px; /* Compact pill radius */
--qmf-island-z: 10000; /* z-index */
/* Priority colors */
--qmf-island-info: #4facfe;
--qmf-island-success: #43e97b;
--qmf-island-warning: #f5b942;
--qmf-island-error: #ff6b6b;
--qmf-island-promo: linear-gradient(135deg, #667eea, #764ba2);
}
/* BEM classes */
.qmf-island /* Container */
.qmf-island--visible /* Shown */
.qmf-island--expanded /* Full view */
.qmf-island--has-queue /* Queue dots visible */
.qmf-island__compact /* Pill row */
.qmf-island__icon /* Icon circle */
.qmf-island__icon--info /* Priority modifier */
.qmf-island__label /* Title text */
.qmf-island__body /* Expanded content */
.qmf-island__actions /* Action buttons row */
.qmf-island__action--primary /* Primary CTA */
.qmf-island__queue /* Queue dots container */
Push nhiều notification liên tiếp — chúng được xếp hàng và hiển thị lần lượt với queue dots indicator.
info · success · warning · error · promo — mỗi level có gradient color riêng.
Responsive trên mọi thiết bị. ARIA role="status", aria-live="polite", prefers-reduced-motion.
Tự động nhận [data-theme="light"]. Tất cả màu sắc qua CSS custom properties, dễ override.
Mỗi notification có thể có action buttons: link (href) hoặc callback (onClick).
Chỉ cần 1 CSS + 1 JS file. Không phụ thuộc framework hay thư viện nào. <10KB combined.
https://ui.quizzman.com/qmf/dist/modules/header/dynamic-island.css
https://ui.quizzman.com/qmf/dist/modules/header/dynamic-island.js
Đọc chi tiết từng phần của QMF.
Hướng dẫn sử dụng cơ bản: init, plugin, state, event bus, config.
Chi tiết API của EventBus, Store, Lifecycle, HttpClient, DI, Config.
Kiến trúc 4 lớp, import rules, plugin system, module structure.
Hướng dẫn chuyển từ share-ui (v2) sang QMF v3. Hỗ trợ compat layer.