QMF Framework

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

Tính năng

Kiến trúc 4 lớp · Plugin system · Error isolation · DevTools

🔌

Plugin System

Đăng ký module dạng plugin với dependency resolution tự động. Hỗ trợ eager & lazy loading.

📦

DI Container

Dependency injection dựa trên token — đăng ký và resolve service ở bất kỳ đâu trong app.

🔒

Error Isolation

Mỗi module có error boundary riêng. Một module crash không ảnh hưởng đến module khác.

📊

State Management

Global + isolated module store với Zod schema validation. Selector, watcher, immutable update.

🚀

Lazy Loading

Code-split module, chỉ load khi cần. CSS tự inject khi plugin mount.

🛠

DevTools

Event tracing, state inspection, plugin graph — tất cả qua window.__QMF_DEVTOOLS__.

📡

Event Bus

Pub/sub với wildcard, scoped bus, và tracing. Giao tiếp giữa các module không cần coupling.

🔄

Lifecycle Hooks

Quản lý vòng đời module: onInit → onMount → onReady → onDestroy. Đồng bộ và async.

🌐

HTTP Client

Fetch wrapper với interceptor, retry logic, auth injection, và error mapping tự động.

Kiến trúc 4 lớp

Mỗi lớp chỉ được import từ lớp thấp hơn — không có circular dependency.

Layer 3 — Modules @qmf/header · @qmf/footer · @qmf/chat-embed · @qmf/noti-embed · @qmf/loading-screen Layer 2 — UI Kit @qmf/ui → Button · Modal · Dropdown · Toast · Panel · Avatar · Badge Layer 1 — Core @qmf/core → EventBus · Store · Lifecycle · Config · HttpClient · DI · PluginLoader · ErrorBoundary Layer 0 — Foundation @qmf/tokens · @qmf/utils → CSS custom properties · Logger · DOM helpers · Fetch wrapper

Quick Start

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);
});

Core API

Các API chính của @qmf/core

ModuleAPIMô tả
EventBus on · off · emit · once Pub/sub với wildcard *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

Dynamic Island

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.

🎮 Live Demo

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 */
🔔

Queue System

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.

🎨

5 Priority Levels

info · success · warning · error · promo — mỗi level có gradient color riêng.

📱

Responsive + A11y

Responsive trên mọi thiết bị. ARIA role="status", aria-live="polite", prefers-reduced-motion.

🌙

Light / Dark Theme

Tự động nhận [data-theme="light"]. Tất cả màu sắc qua CSS custom properties, dễ override.

💫

Action Buttons

Mỗi notification có thể có action buttons: link (href) hoặc callback (onClick).

🧰

Zero Dependencies

Chỉ cần 1 CSS + 1 JS file. Không phụ thuộc framework hay thư viện nào. <10KB combined.

📦 CDN Files

CSS https://ui.quizzman.com/qmf/dist/modules/header/dynamic-island.css
JS https://ui.quizzman.com/qmf/dist/modules/header/dynamic-island.js

Tài liệu

Đọc chi tiết từng phần của QMF.