TBjs
tbjs Framework: Comprehensive Guide & Documentation¶
Table of Contents
- Introduction
- Key Design Principles & Features
- Getting Started
- Prerequisites
- Installation
- HTML Setup
- Application Initialization (
TB.init)
- Core Modules (
TB.*)TB.config: Configuration ManagementTB.logger: Logging UtilityTB.state: Global State ManagementTB.events: Event Bus / Pub/SubTB.env: Environment DetectionTB.api: Backend CommunicationTB.router: SPA RoutingTB.crypto: Cryptographic UtilitiesTB.user: User Session & AuthenticationTB.sse: Server-Sent EventsTB.sw: Service Worker ManagementTB.utils: General UtilitiesTB.graphics: 3D Graphics (THREE.js)
- UI System (
TB.ui.*)TB.ui.theme: Theming (Light/Dark Mode, Backgrounds)TB.ui.htmxIntegration: HTMX Event HandlingTB.ui.processDynamicContent: Handling New DOM Content- UI Components:
TB.ui.ModalTB.ui.ToastTB.ui.LoaderTB.ui.ButtonTB.ui.DarkModeToggleTB.ui.CookieBannerTB.ui.MarkdownRendererTB.ui.NavMenuTB.ui.AutocompleteWidget
- Styling with Tailwind CSS
- Prefixing and CSS Variables
- Using
tbjsTailwind Config in Your Project
- Advanced Topics
- Tauri Integration
- Working with 3D Graphics
- Example: Login Flow Walkthrough
- Building
tbjs(For Developers)
1. Introduction¶
tbjs is a modular frontend framework designed for building modern web applications, with special consideration for integration with Tauri for desktop applications and tools like HTMX and Three.js. It provides a comprehensive set of tools for managing configuration, state, API communication, routing, UI components, user authentication, and more.
Key Design Principles & Features:
- Modularity: Clear separation of concerns into
coreanduimodules. You can use only the parts you need. - Event-Driven: Facilitates decoupled communication between modules via an event bus.
- Configuration-Centric: Application behavior is heavily influenced by a central configuration object.
- State Management: Centralized application state with optional persistence.
- SPA Router: Handles client-side navigation and view loading.
- API Abstraction: Simplifies backend communication, supporting both HTTP and Tauri
invokecalls. - UI System: Includes theme management (light/dark mode), dynamic backgrounds, and reusable UI components.
- 3D Graphics Integration: Built-in support for THREE.js for dynamic backgrounds or scenes, managed by
TB.graphics. - User Authentication: Robust support for various authentication flows, including device key (asymmetric crypto) and WebAuthn (passkeys).
- HTMX Friendly: Designed to work seamlessly alongside HTMX for enhancing HTML with dynamic behaviors.
- Tauri-Aware: Core functionalities can adapt to run optimally in a Tauri environment.
- Modern Tooling: Built with Webpack, Babel, PostCSS, and Tailwind CSS.
2. Getting Started¶
Prerequisites¶
Before using tbjs, ensure you have the following (or plan to include them if using related features):
- HTMX (Recommended):
tbjsintegrates well with HTMX for server-rendered partials and dynamic updates.<script defer src="https://unpkg.com/htmx.org@2.0.2/dist/htmx.min.js"></script> - Three.js (Optional, if using
TB.graphics):<script defer src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.153.0/three.min.js"></script> -
Marked & Highlight.js (Optional, if using
TB.ui.MarkdownRenderer): For rendering Markdown to HTML with syntax highlighting.Ensure<script defer src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/marked-highlight/lib/index.umd.min.js"></script> <script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">window.marked,window.markedHighlight, andwindow.hljsare available beforeTB.ui.MarkdownRendereris used. -
Material Symbols (Optional, used by some default UI components):
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
Installation¶
-
Add
tbjsto your project: Iftbjswere published to npm:Since it's often used locally or as part of a larger monorepo, you'd typically:npm install tbjs # or yarn add tbjs- Build
tbjsfrom source (see Buildingtbjs) to getdist/tbjs.jsanddist/tbjs.css. - Or, if integrating into a build system, import directly from its source path (e.g.,
import TB from 'path/to/tbjs/src/index.js';).
- Build
-
Include files in your HTML (if using pre-built dist files):
<link rel="stylesheet" href="path/to/your/tbjs/dist/tbjs.css"> <!-- Load tbjs.js as a module or a global script depending on its build --> <script defer type="module" src="path/to/your/tbjs/dist/tbjs.js"></script> <!-- If ES Module build --> <!-- <script defer src="path/to/your/tbjs/dist/tbjs.js"></script> --> <!-- If UMD build --> -
Peer Dependencies (Reminder): Ensure you have
htmx.organdthreeinstalled/included if you plan to use features that depend on them.npm install htmx.org three # Or yarn add
3. Core Modules (TB.*)¶
TB.config: Configuration Management¶
Manages application-wide settings. It's initialized by TB.init() with default values merged with your provided configuration.
- Initialization:
TB.config.init(userAppConfig)is called byTB.init.userAppConfigoptions:appRootId(string): ID of the main DOM element for router views. Default:app-root.baseApiUrl(string): Base URL for API calls. Default:/api. Normalized to be absolute (e.g.,/apibecomeswindow.location.origin/api).baseFileUrl(string): Base URL for fetching static HTML files for routing. Default:window.location.origin. Normalized to end with/if it has a path, and ensures it doesn't include file names.initialState(object): Initial state forTB.state.themeSettings(object): SeeTB.ui.themesection.routes(array): Predefined routes forTB.router(currently for reference/future use).logLevel(string):debug,info,warn,error,none. Default:info.isProduction(boolean): Inferred based on hostname (localhost,127.0.0.1) if not explicitly set.serviceWorker(object):{ enabled: boolean, url: string, scope: string }.
- Getting Configuration:
const apiUrl = TB.config.get('baseApiUrl'); const logLevel = TB.config.get('logLevel'); const themePref = TB.config.get('themeSettings.defaultPreference'); // Dot notation for nested const allConfig = TB.config.getAll(); // Returns a copy of the entire config - Setting Configuration (dynamically, use with caution after init):
TB.config.set('myCustomSetting', 'someValue'); TB.config.set('featureFlags.newFeature', true);
TB.logger: Logging Utility¶
Provides leveled, prefixed, and timestamped logging to the console.
- Initialization:
TB.logger.init({ logLevel: '...' })is called byTB.initbased onTB.config. - Setting Log Level:
TB.logger.setLevel('debug'); // 'debug', 'info', 'warn', 'error', 'none' - Logging Messages:
Output includes a timestamp,
TB.logger.debug('Detailed debug message:', { data: 123 }); TB.logger.info('Informational message.'); // Alias: TB.logger.log() TB.logger.warn('Potential issue warning.'); TB.logger.error('An error occurred:', new Error('Something went wrong'));[tbjs], and the log level (e.g.,[DEBUG]).
TB.state: Global State Management¶
A simple key-value store for global application state with optional persistence to localStorage.
- Initialization:
TB.state.init(initialState)is called byTB.initwithTB.config.get('initialState'). Loads any persisted state. - Getting State:
const username = TB.state.get('user.username'); // Dot notation for nested const allState = TB.state.get(); // Returns a copy of the entire state - Setting State:
// Set a simple value TB.state.set('ui.darkMode', true); // Set a nested value, creating intermediate objects if they don't exist TB.state.set('user.profile.avatarUrl', '/path/to/avatar.png'); // Persist the top-level key 'user' to localStorage TB.state.set('user.isLoggedIn', true, { persist: true }); // Any change under 'user' (e.g., 'user.settings.notifications') will now persist 'user'.- Emits
state:changedevent with{ key, value, fullState }. - Emits specific event like
state:changed:user:profile:avatarUrlwith thevalue.
- Emits
- Deleting State:
TB.state.delete('user.profile.temporaryToken'); TB.state.delete('featureFlags.oldFlag', { persist: true }); // Will update persisted 'featureFlags' - Legacy "Var" Methods (for simple key-value persistence, prefer structured state with
persistoption):TB.state.initVar('myVar', 'defaultValue'): Sets if not already defined, persists.TB.state.delVar('myVar'): Deletes and updates persisted state.TB.state.getVar('myVar'): Gets value.TB.state.setVar('myVar', 'newValue'): Sets value, persists.
TB.events: Event Bus / Pub/Sub¶
Allows modules to communicate without direct dependencies.
- Subscribing to Events:
function handleThemeChange(eventData) { console.log('Theme changed to:', eventData.mode); } TB.events.on('theme:changed', handleThemeChange); // Subscribe only once TB.events.once('app:firstLogin', (userData) => { /* ... */ }); - Unsubscribing from Events:
TB.events.off('theme:changed', handleThemeChange); - Emitting Events:
If a listener throws an error,
TB.events.emit('user:loggedIn', { userId: 123, username: 'testuser' });TB.logger.erroris called, and other listeners still execute. - Common Framework Events:
tbjs:initialized,state:changed,router:navigationSuccess,theme:changed,api:networkError,graphics:initialized,user:loggedOut, etc.
TB.env: Environment Detection¶
Provides information about the runtime environment.
- Initialization:
TB.env.detect()is called byTB.init. - Checking Environment:
if (TB.env.isTauri()) { console.log('Running in Tauri environment.'); } else if (TB.env.isWeb()) { console.log('Running in a web browser.'); } if (TB.env.isMobile()) { // Currently implies Tauri mobile if detected console.log('Running on a mobile platform (Tauri).'); }
TB.api: Backend Communication¶
Handles all HTTP and Tauri invoke calls, standardizing responses.
- Core
ResultObject: AllTB.apimethods (and Tauri invokes) aim to return or be wrapped into aResultobject:// Structure of a Result object (simplified) // const result = { // origin: Array<string>, // e.g., ['http'], ['tauri'] // error: string, // From TB.ToolBoxError (e.g., 'none', 'InternalError') // result: { // Instance of ToolBoxResult // data_to: string, // From TB.ToolBoxInterfaces (e.g., 'API', 'NATIVE') // data_info: string|null,// Additional info // data: any // The actual payload // }, // info: { // Instance of ToolBoxInfo // exec_code: number, // HTTP status or custom code (0 for success) // help_text: string // Descriptive message // }, // get: function() { return this.result.data; }, // Helper to get payload // log: function() { /* console logs details */ }, // html: function() { /* returns an HTML representation for debugging */ } // }; -
TB.api.request(moduleName, functionName, payload, method, useTauri, isSpecialAuthRoute): The primary method for making backend requests.moduleName(string): Backend module/class OR full path (e.g.,/validateSession).functionName(string|object): Backend function/method OR query params object ifmoduleNameis a full path (for GET/DELETE).payload(object|string|null): Data to send. Object for JSON POST/PUT; string can be form-urlencoded or query params.method(string): HTTP method (GET,POST, etc.). Default:POST.useTauri(string):auto(default),force(Tauri only),never(HTTP only).isSpecialAuthRoute(boolean): Iftrue, influences token handling (rarely needed).
URL Construction (HTTP): * Standard:
baseApiUrl/moduleName/functionName* Full path:baseApiUrl+moduleName(wheremoduleNamestarts with/, e.g.,/custom/endpoint)*// POST request (HTTP or Tauri if available and 'auto') const userData = { name: 'John Doe', email: 'john@example.com' }; let response = await TB.api.request('UserModule', 'createUser', userData); // Defaults to POST if (response.error === TB.ToolBoxError.none) { console.log('User created:', response.get()); } else { TB.logger.error('Failed to create user:', response.info.help_text); } // GET request with query parameters from an object response = await TB.api.request('ProductModule', 'getProduct', { id: 123 }, 'GET'); // URL: /api/ProductModule/getProduct?id=123 // Full path GET (functionName is query params object) response = await TB.api.request('/custom/data', { type: 'summary' }, null, 'GET'); // URL: /api/custom/data?type=summary (if baseApiUrl is /api)TB.api.fetchHtml(path): Fetches HTML content, typically for router views. Path is relative tobaseFileUrl.*const htmlResult = await TB.api.fetchHtml('/about.html'); // Fetches /web/pages/about.html if (!htmlResult.startsWith('HTTP error!')) { /* ... */ }TB.api.AuthHttpPostData(username): Specific method for validating a session. Calls/validateSession. *TB.api.logoutServer(): Notifies the backend to invalidate the current user's session token (calls/web/logoutS). * Events: *api:networkError: Emitted on fetch network failures. Payload:{ url, error }.
TB.router: SPA Routing¶
Manages client-side navigation and view rendering.
- Initialization:
TB.router.init(rootElement, predefinedRoutes)called byTB.init.rootElement: The DOM element where views will be rendered (fromTB.config.appRootId).- Automatically navigates to the initial URL (or
/index.html).
- Navigating:
// Navigate to a new path, updating browser history TB.router.navigateTo('/products/123'); // Fetches baseFileUrl + /products/123.html // Navigate and replace current history entry TB.router.navigateTo('/profile/settings', true);- Fetches HTML from
TB.config.get('baseFileUrl') + path + '.html'(by default, unless path includes an extension). - Handles script loading within new views (external once, inline executed,
unsaveattribute for fresh execution,global="true"for potential preservation). - Updates
appRootElement.innerHTMLwith fetched content. - Calls
TB.ui.processDynamicContent()on the new content. - Handles 404 errors by trying to navigate to
/web/assets/404.html. - Handles 401 errors by trying to navigate to
/web/assets/401.html.
- Fetches HTML from
- Getting Current Path:
TB.router.getCurrentPath() - Cache Management:
TB.router.clearCache(path): Clears HTML cache for a specific path or all ifpathis omitted (usessessionStorageifUSE_SESSION_CACHEis true in router.js).scriptCache(Set of scriptsrcURLs) prevents re-fetching external scripts.
- Events:
router:beforeNavigation:{ from, to }router:navigationSuccess:{ path, contentSource }('cache' or 'fetched')router:navigationError:{ path, error }router:contentProcessed:{ path, element }
TB.crypto: Cryptographic Utilities¶
Provides functions for various cryptographic operations, including WebAuthn. Relies on browser's Web Crypto API.
- Key Management & Signing:
TB.crypto.generateAsymmetricKeys(): Generates RSA-OAEP key pair (PEM & Base64).TB.crypto.decryptAsymmetric(encryptedBase64Data, privateKeyBase64, convertHex = false): Decrypts RSA-OAEP encrypted data.TB.crypto.signMessage(privateKeyBase64, message): Signs a message using RSA-PSS.TB.crypto.storePrivateKey(privateKeyBase64, username): Stores private key inlocalStorage.TB.crypto.retrievePrivateKey(username): Retrieves private key.
- Symmetric Encryption/Decryption:
TB.crypto.generateSymmetricKey(): Generates an AES-GCM key (Base64 of raw key).TB.crypto.decryptSymmetric(encryptedDataB64, password): Decrypts AES-GCM data (assumes IV is prepended to ciphertext, password used for key derivation via PBKDF2).
- WebAuthn (Passkeys):
- The Relying Party ID (
rpId) is determined fromwindow.location.hostname(or "localhost"). TB.crypto.registerWebAuthnCredential(registrationData, singData):registrationData:{ challenge, userId, username }from server.singData: Additional data (e.g., session token) to associate.- Calls
navigator.credentials.create(). Returns payload for server verification.
TB.crypto.authorizeWebAuthnCredential(rawIdAsBase64, challenge, username):rawIdAsBase64,challenge,usernamefrom server.- Calls
navigator.credentials.get(). Returns assertion payload for server verification.
- The Relying Party ID (
- Data Conversions:
arrayBufferToBase64,base64ToArrayBuffer,strToBase64, etc.
TB.user: User Session & Authentication¶
Manages user state, authentication flows, and user-specific data. User state is stored under TB.state.get('user').
- Initialization:
TB.user.init(forceServerFetch = false):- Called by
TB.init. Loads session, validates with backend, synchronizes user data.
- Called by
- Authentication State:
TB.user.isAuthenticated(),TB.user.getUsername(),TB.user.getToken(), etc. - Login Methods:
async TB.user.signup(username, email, initiationKey, registerAsPersona = false): Initiates user creation.async TB.user.loginWithDeviceKey(username): Login using locally stored asymmetric key.async TB.user.loginWithWebAuthn(username): Login using WebAuthn (passkey).async TB.user.requestMagicLink(username): Requests a magic link email.async TB.user.registerDeviceWithInvitation(username, invitationKey): Registers a new device.async TB.user.registerWebAuthnForCurrentUser(username): Adds a WebAuthn credential for an authenticated user.
- Session Management:
async TB.user.checkSessionValidity(): Validates current token with server.async TB.user.logout(notifyServer = true): Clears local session, notifies server.
- User-Specific Data:
TB.user.getUserData(key),TB.user.setUserData(keyOrObject, value, syncToServer = false),async TB.user.syncUserData(),async TB.user.fetchUserData(). - Events:
user:stateChanged,user:loggedOut.
TB.sse: Server-Sent Events¶
Manages connections to Server-Sent Event streams.
- Connecting:
TB.sse.connect(url, options = {})options:{ onOpen, onError, onMessage, listeners: { eventName: handler }, eventSourceOptions }.TB.sse.connect('/api/sse/updates', { listeners: { 'user-update': (data) => TB.state.set('user.profile', data), 'new-notification': (data) => TB.ui.Toast.showInfo(data.message) } });
- Disconnecting:
TB.sse.disconnect(url),TB.sse.disconnectAll() - Getting Connection:
TB.sse.getConnection(url) - Events Emitted:
sse:open:<url>,sse:error:<url>,sse:event:<url>:<eventName>, etc.
TB.sw: Service Worker Management¶
Handles registration and communication with your application's service worker.
- Configuration (
TB.config.get('serviceWorker')):enabled,url,scope. - Registration: Called automatically by
TB.initif enabled. Manual:await TB.sw.register(). - Unregistration:
await TB.sw.unregister() - Sending Messages:
await TB.sw.sendMessage({ type: 'GET_VERSION' }) - Events Emitted:
sw:updateAvailable,sw:contentCached.TB.events.on('sw:updateAvailable', ({ registration }) => { if (confirm('New version available. Reload?')) { registration.waiting.postMessage({ type: 'SKIP_WAITING' }); // Listen for controllerchange to reload navigator.serviceWorker.addEventListener('controllerchange', () => window.location.reload()); } });
TB.utils: General Utilities¶
A collection of helper functions.
TB.utils.autocomplete(inputElement, arrayOrFunctionSource): Basic autocomplete (preferTB.ui.AutocompleteWidget).TB.utils.debounce(func, delay)TB.utils.throttle(func, limit)TB.utils.uniqueId(prefix = 'id-')TB.utils.deepClone(obj)TB.utils.cleanUrl(url): Basic URL cleaning.
TB.graphics: 3D Graphics (THREE.js)¶
Manages a THREE.js scene, typically for background effects.
- Initialization:
TB.graphics.init(canvasContainerSelector, options = {})canvasContainerSelector: CSS selector for the DOM element (e.g.,'#threeDScene').options:{ cameraY, cameraZ, sierpinskiDepth, loaderHideDelay }.- Typically called if
themeSettings.background.typeis'3d'.
- Control Methods:
TB.graphics.dispose(),TB.graphics.pause(),TB.graphics.resume().TB.graphics.updateTheme(themeMode): Called byTB.ui.theme.TB.graphics.setSierpinskiDepth(newDepth).TB.graphics.setAnimationSpeed(x, y, z, factor).TB.graphics.adjustCameraZoom(delta),TB.graphics.setCameraZoom(absoluteZoomValue).
- Programmed Animation Sequences:
TB.graphics.playAnimationSequence(sequenceString, onCompleteCallback, baseSpeedOverride, speedFactorOverride)sequenceString: e.g.,"R1+32:P2-14"(Type, Repeat, Direction, Speed, Complexity).
TB.graphics.stopAnimationSequence().
- Events:
graphics:initialized,graphics:disposed.
4. UI System (TB.ui.*)¶
TB.ui.theme: Theming¶
Manages light/dark mode and application background.
- Initialization:
TB.ui.theme.init(themeSettings)called byTB.init.themeSettings:{ defaultPreference ('light'|'dark'|'system'), background: { type, light, dark, placeholder } }.background.type:'3d','image','color','none'.background.light/dark:{ color: string, image: string|null }.background.placeholder:{ image_light, image_dark, displayUntil3DReady }.
- Interacting with Theme:
TB.ui.theme.setPreference('dark'),TB.ui.theme.togglePreference().TB.ui.theme.getCurrentMode()('light' or 'dark').TB.ui.theme.getPreference()('light', 'dark', or 'system').
- Background Management:
- Uses
#appBackgroundContainerfor image/color and#threeDScenefor 3D.
- Uses
- Events:
theme:changed(payload:{ mode: 'light' | 'dark' }).
TB.ui.htmxIntegration: HTMX Event Handling¶
Listens to HTMX events to integrate tbjs functionalities.
- Initialization:
TB.ui.htmxIntegration.init()is called byTB.init. htmx:afterSwap: CallsTB.ui.processDynamicContenton the new HTMX target element.htmx:afterRequest:- Inspects XHR response. If JSON, wraps in
TB.api.Result, shows toasts for errors. - Handles
REMOTErender commands. - Emits
htmx:jsonResponse.
- Inspects XHR response. If JSON, wraps in
TB.ui.processDynamicContent(parentElement, options = {})¶
Initializes tbjs features/components within newly added DOM content.
parentElement: The container of the new content.options:{ addScripts (default true), scriptCache }.- Actions: Calls
window.htmx.process(), handles scripts, callsTB.ui.MarkdownRenderer.renderAllIn(), initializes data-attribute driven components likeAutocompleteWidget.
UI Components¶
TB.ui.Modal¶
Displays modal dialogs.
- Static Usage:
TB.ui.Modal.show({ title, content, maxWidth, buttons, onOpen, onClose, ... })buttons:[{ text, action: (modalInstance) => {}, variant, className }]
- Styling: Uses Tailwind CSS, "milk glass" effect.
-
Events:
modal:shown,modal:closed. -
Static Usage: `TB.ui.Modal.confirm({ title, content, confirmButtonText = 'OK', cancelButtonText = 'Cancel', confirmButtonVariant = 'primary', cancelButtonVariant = 'secondary', confirmButtonClass = '', cancelButtonClass = '', hideCancelButton = false, resolveOnClose = false, ...extraModalOptions // Collects any other options passed to confirm
TB.ui.Toast¶
Displays "speech balloon" style toast notifications.
- Static Usage:
TB.ui.Toast.showInfo(message, options)TB.ui.Toast.showSuccess(message, options)TB.ui.Toast.showWarning(message, options)TB.ui.Toast.showError(message, options)
- Options:
{ title, duration, position, actions, icon, closable, showDotOnHide, dotDuration }. - Events:
toast:shown,toast:hidden.
TB.ui.Loader¶
Displays a loading indicator.
- Static Usage (Global Page Loader):
const loaderElement = TB.ui.Loader.show('Processing...');TB.ui.Loader.hide(loaderElement);(orTB.ui.Loader.hide()for default).
- Options:
{ text, fullscreen, customSpinnerHtml }.
TB.ui.Button¶
Creates styled button elements programmatically.
- Static Usage:
const myButtonElement = TB.ui.Button.create(text, onClickCallback, options) - Options:
{ variant, size, iconLeft, iconRight, type, disabled, isLoading, ... }. - Instance Methods:
setLoading(true),setDisabled(true).
TB.ui.DarkModeToggle¶
UI component for switching themes, syncing with TB.ui.theme.
- HTML (Example):
<div id="darkModeToggleContainer"> <label for="darkModeSwitch"><span class="tb-toggle-icon material-symbols-outlined">light_mode</span></label> <input type="checkbox" id="darkModeSwitch" class="tb-sr-only"> </div> - Initialization:
TB.ui.DarkModeToggle.init({ containerSelector, iconSelector, checkboxSelector, ... }). Default init uses common selectors. - Updates icon and checkbox based on
theme:changedevent.
TB.ui.CookieBanner¶
Displays a cookie consent banner and settings modal.
- Static Usage:
TB.ui.CookieBanner.show({ title, message, termsLink, onConsent, ... }) onConsentcallback receives{ essential, preferences, analytics, source }.- Methods:
CookieBanner.getConsent(),CookieBanner.clearConsent(). - Events:
cookieConsent:updated,cookieBanner:shown/hidden.
TB.ui.MarkdownRenderer¶
Renders Markdown to HTML, with optional highlight.js syntax highlighting.
- Dependencies:
marked,highlight.js,marked-highlight(global or loaded). - Methods:
TB.ui.MarkdownRenderer.render(markdownString)TB.ui.MarkdownRenderer.renderAllIn(parentElement)(for elements with.markdownclass)TB.ui.MarkdownRenderer.renderElement(element)
- Adds Tailwind Prose classes (
prose dark:prose-invert) for styling.
TB.ui.NavMenu¶
A slide-in (or modal-style) navigation menu.
- HTML Trigger (Example):
<div id="Nav-Main"> <!-- Menu is appended here --> <div id="links"><span class="material-symbols-outlined">menu</span></div> </div> - Initialization:
TB.ui.NavMenu.init({ triggerSelector, menuContentHtml, ... }). - Events:
navMenu:opened,navMenu:closed.
TB.ui.AutocompleteWidget¶
Provides autocomplete suggestions for input fields.
- HTML (Declarative):
<input type="text" data-tb-autocomplete data-tb-autocomplete-source='["Apple", "Banana"]'> <!-- Or data-tb-autocomplete-source="myGlobalFunctionName" --> - Initialization:
- Automatic:
TB.ui.AutocompleteWidget.initAll()(called byprocessDynamicContent). - Manual:
new TB.ui.AutocompleteWidget(inputEl, { source, minLength, onSelect, ... }).
- Automatic:
- Features: Keyboard navigation, ARIA attributes.
5. Styling with Tailwind CSS¶
tbjs components are primarily styled using Tailwind CSS utility classes.
Prefixing and CSS Variables¶
- Prefix:
tbjs's internal Tailwind configuration uses atb-prefix (e.g.,tb-bg-primary-500,tb-text-lg). This is crucial to avoid conflicts if your main application also uses Tailwind without a prefix or with a different one. - Main CSS (
tbjs.cssortbjs-main.css):- Imports Tailwind utilities generated with the
tb-prefix. - Defines CSS custom properties (variables) for theming (e.g.,
--tb-color-primary-500,--theme-bg,--glass-bg). These are used by the prefixed Tailwind classes. - Includes light and dark theme definitions typically applied to
body[data-theme="dark"]orbody.dark-mode. - Provides base styles and some component-specific styles hard to achieve with utilities alone (e.g., toast speech balloon tail).
- Imports Tailwind utilities generated with the
- Customization:
- Applications can override the CSS variables defined in
tbjs.cssin their own stylesheets to customize the look and feel. - For deeper Tailwind customization (new colors, variants specific to
tbjs), you would edittbjs/tailwind.config.jsand rebuildtbjs.
- Applications can override the CSS variables defined in
Using tbjs Tailwind Config in Your Project¶
If your project also uses Tailwind CSS, you have a few options:
-
Separate Builds (Recommended for Isolation):
- Build
tbjs.cssusing its own Tailwind configuration (with thetb-prefix). - Build your application's CSS using its Tailwind configuration.
- Include both CSS files in your HTML. The
tb-prefix prevents most conflicts.
- Build
-
Merging Configurations (Advanced): If you want a single Tailwind build process, you might try to merge configurations. This can be complex due to prefixing and potential conflicts.
- You would need to ensure your main
tailwind.config.jsincludes thecontentpaths fortbjssource files. - You'd also need to decide how to handle the
tb-prefix. If your app doesn't use a prefix,tbjscomponents might not be styled correctly unless you manually adapt their classes or adjust thetbjssource. - A simpler merge might involve including
tbjs's Tailwind plugin or preset if it were structured that way, but this is not the default.
Example (Conceptual - requires careful setup):
Generally, keeping// your-app/tailwind.config.js // const tbjsTailwindConfig = require('path/to/tbjs/tailwind.config.js'); // If CJS export default { content: [ './src/**/*.{html,js,svelte,vue,jsx,tsx}', // Your app's content './node_modules/tbjs/src/**/*.{html,js}', // Or path to tbjs source ], // If your app uses a prefix, it might conflict or work alongside tb- // prefix: 'app-', theme: { extend: { // You might try to extend with tbjs colors if they are defined without prefix in its config // This part is tricky due to the 'tb-' prefix baked into tbjs's own build }, }, plugins: [], };tbjs.cssseparate with itstb-prefix is the most straightforward way to avoid styling conflicts. - You would need to ensure your main
6. Advanced Topics¶
Tauri Integration¶
- Environment Check: Use
TB.env.isTauri()to execute Tauri-specific code. - API Calls:
TB.api.request()automatically useswindow.__TAURI__.invokeifuseTauriis'auto'(default) or'force'and the environment is Tauri.- The Tauri command invoked is typically
moduleName.functionName(e.g.,MyRustModule.my_function).if (TB.env.isTauri()) { const result = await TB.api.request('my_rust_command', 'sub_command_or_payload_key', { data: 'payload' }); // Effective Tauri invoke: window.__TAURI__.invoke('my_rust_command.sub_command_or_payload_key', { data: 'payload' }); }
- The Tauri command invoked is typically
- Platform-Specific Features: The
initializeAppfunction shows a pattern for loading Tauri-specific listeners or UI adjustments.
Working with 3D Graphics¶
- The
TB.graphicsmodule manages a THREE.js scene, typically for background effects. - Integration with Theme: If
themeSettings.background.typeis'3d',TB.ui.themewill initializeTB.graphics(targeting#threeDScene) and callTB.graphics.updateTheme()on light/dark mode changes. - Manual Control:
TB.graphics.setSierpinskiDepth(3); TB.graphics.playAnimationSequence("R2+52:P1-31", () => console.log("3D Animation done!")); // Mouse/touch drag for interaction is usually enabled by default.
7. Example: Login Flow Walkthrough¶
This conceptual example (based on a typical login.js implementation with tbjs) demonstrates how various modules work together:
-
Initialization (e.g., in a
setupLoginfunction called when the login page loads):- Wait for
tbjs:initializedor checkTB.isInitialized. - Optionally, play an initial graphics animation:
TB.graphics.playAnimationSequence("Z0+12"). - Check session validity:
TB.user.checkSessionValidity(). If valid, show a toast and offer navigation to a dashboard.
- Wait for
-
Form Submission (e.g., on login button click):
- Prevent default form submission.
- Get username from input. Validate locally (show info/toast on error).
- Play a "login attempt" graphics animation:
TB.graphics.playAnimationSequence("R1+11:P1-11"). - Show a global loader:
TB.ui.Loader.show('Attempting login...'). - Authentication Logic (Conditional):
- If user opts for WebAuthn/Passkey:
await TB.user.loginWithWebAuthn(username). - Else (e.g., device key):
await TB.user.loginWithDeviceKey(username).- If
loginWithDeviceKeyfails due to no key: Show a sticky error toast with actions:- "Try Passkey/WebAuthn": Calls
TB.user.loginWithWebAuthn(). - "Register with Invitation": Prompts for key, calls
TB.user.registerDeviceWithInvitation(). - "Send Magic Link": Calls
TB.user.requestMagicLink(). - Each action would have its own loader management and graphics animations.
- "Try Passkey/WebAuthn": Calls
- If
- If user opts for WebAuthn/Passkey:
-
Result Handling:
- Based on
result.successfromTB.userlogin methods:- Success:
- Show success toast:
TB.ui.Toast.showSuccess('Login successful!'). - Play success animation:
TB.graphics.playAnimationSequence("Z1+32:R0+50"). - Navigate:
TB.router.navigateTo('/dashboard').
- Show success toast:
- Failure:
- Show error toast:
TB.ui.Toast.showError(result.message). - Play failure animation:
TB.graphics.playAnimationSequence("P2-42").
- Show error toast:
- Success:
- Use
TB.loggerfor detailed console logging throughout the process. - Hide loader (
TB.ui.Loader.hide()) and stop animations (TB.graphics.stopAnimationSequence()) in afinallyblock or after completion.
- Based on
This flow showcases:
* Event-driven UI: Graphics and toasts respond to login states.
* Module Orchestration: TB.user, TB.graphics, TB.ui.Toast, TB.ui.Loader, TB.router, TB.logger working in concert.
* User Feedback: Clear messages and visual cues for different scenarios.
8. Building tbjs (For Developers)¶
If you are modifying the tbjs framework itself or need to build it from source:
- Prerequisites:
- Node.js and npm (or yarn) installed.
- Install Dependencies:
Navigate to the
tbjsroot directory in your terminal and run:npm install # or # yarn install - Build Scripts (examples from a typical
package.json):- Production Build:
This usually creates optimized, minified files in a
npm run builddist/directory (e.g.,dist/tbjs.jsanddist/tbjs.css). The build process uses Webpack, configured inwebpack.config.js. - Development Watch Mode:
This watches source files for changes and automatically rebuilds, often in a non-minified format for easier debugging.
npm run watch # or npm run dev - Linting:
Checks the JavaScript code for style consistency and potential errors using a linter like ESLint.
npm run lint
- Production Build: