Formatting Demo
Comprehensive showcase of formatting options including presets, colors, timestamps, and object display with live configuration builder.
📄 Source Code
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Loggical Formatting Showcase</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen, Ubuntu, sans-serif;
line-height: 1.6;
color: #333;
background: #f8f9fa;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #6f42c1 0%, #e83e8c 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
}
.header p {
font-size: 1.1rem;
opacity: 0.9;
}
.nav {
background: #e9ecef;
padding: 15px 30px;
border-bottom: 1px solid #dee2e6;
}
.nav a {
color: #495057;
text-decoration: none;
margin-right: 20px;
font-weight: 500;
}
.nav a:hover {
color: #6f42c1;
}
.content {
padding: 30px;
}
.comparison-section {
margin-bottom: 40px;
padding: 25px;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid #6f42c1;
}
.comparison-section h2 {
color: #2c3e50;
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 10px;
}
.comparison-section .icon {
font-size: 1.5rem;
}
.comparison-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 20px;
margin-top: 20px;
}
.format-example {
background: white;
border: 1px solid #dee2e6;
border-radius: 8px;
overflow: hidden;
}
.format-header {
background: #6f42c1;
color: white;
padding: 12px 15px;
font-weight: 600;
font-size: 14px;
}
.format-output {
background: #1e1e1e;
color: #d4d4d4;
padding: 15px;
font-family: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas,
monospace;
font-size: 12px;
line-height: 1.4;
overflow-x: auto;
white-space: pre-wrap;
min-height: 120px;
}
.controls-panel {
background: white;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
}
.controls-row {
display: flex;
gap: 20px;
margin-bottom: 15px;
align-items: center;
flex-wrap: wrap;
}
.control-group {
display: flex;
flex-direction: column;
gap: 5px;
}
.control-group label {
font-weight: 600;
color: #495057;
font-size: 14px;
}
.control-group select,
.control-group input {
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 14px;
}
.checkbox-group {
display: flex;
align-items: center;
gap: 8px;
}
.checkbox-group input[type="checkbox"] {
width: auto;
margin: 0;
}
.demo-button {
background: linear-gradient(135deg, #6f42c1 0%, #e83e8c 100%);
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s ease;
margin-right: 10px;
margin-bottom: 10px;
}
.demo-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(111, 66, 193, 0.3);
}
.preset-buttons {
display: flex;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.preset-button {
background: #6c757d;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s ease;
}
.preset-button:hover {
background: #5a6268;
}
.preset-button.active {
background: #6f42c1;
}
.explanation {
background: #e8f4fd;
border-left: 4px solid #17a2b8;
padding: 15px;
margin: 15px 0;
border-radius: 4px;
}
.explanation h4 {
color: #0c5460;
margin-bottom: 8px;
}
.explanation p {
color: #0c5460;
margin: 0;
}
/* ANSI color classes */
.ansi-black {
color: #2d3748;
}
.ansi-red {
color: #f56565;
}
.ansi-green {
color: #48bb78;
}
.ansi-yellow {
color: #ed8936;
}
.ansi-blue {
color: #4299e1;
}
.ansi-magenta {
color: #9f7aea;
}
.ansi-cyan {
color: #38b2ac;
}
.ansi-white {
color: #f7fafc;
}
.ansi-gray {
color: #a0aec0;
}
.ansi-bright-red {
color: #fc8181;
}
.ansi-bright-green {
color: #68d391;
}
.ansi-bright-yellow {
color: #f6e05e;
}
.ansi-bright-blue {
color: #63b3ed;
}
.ansi-bright-magenta {
color: #b794f6;
}
.ansi-bright-cyan {
color: #4fd1c7;
}
.ansi-bright-white {
color: #ffffff;
}
.ansi-dim {
opacity: 0.6;
}
.ansi-bold {
font-weight: bold;
}
@media (max-width: 768px) {
.comparison-grid {
grid-template-columns: 1fr;
}
.controls-row {
flex-direction: column;
align-items: stretch;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎨 Formatting Showcase</h1>
<p>Explore all formatting options with side-by-side comparisons</p>
</div>
<div class="nav">
<a href="index.html">← Back to Demos</a>
<a href="basic-demo.html">Basic Usage</a>
<a href="playground/">Interactive Playground</a>
</div>
<div class="content">
<!-- Preset Comparison -->
<div class="comparison-section">
<h2><span class="icon">🎭</span>Preset Comparison</h2>
<div class="explanation">
<h4>Built-in Presets</h4>
<p>
Loggical comes with 4 built-in presets optimized for different use
cases. Compare them side-by-side to see the differences.
</p>
</div>
<div class="preset-buttons">
<button class="preset-button active" onclick="showPresets()">
Show All Presets
</button>
<button class="preset-button" onclick="showPreset('standard')">
Standard Only
</button>
<button class="preset-button" onclick="showPreset('compact')">
Compact Only
</button>
<button class="preset-button" onclick="showPreset('readable')">
Readable Only
</button>
<button class="preset-button" onclick="showPreset('server')">
Server Only
</button>
</div>
<div class="comparison-grid" id="preset-comparison">
<div class="format-example">
<div class="format-header">Standard Preset</div>
<div class="format-output" id="standard-output"></div>
</div>
<div class="format-example">
<div class="format-header">Compact Preset</div>
<div class="format-output" id="compact-output"></div>
</div>
<div class="format-example">
<div class="format-header">Readable Preset</div>
<div class="format-output" id="readable-output"></div>
</div>
<div class="format-example">
<div class="format-header">Server Preset</div>
<div class="format-output" id="server-output"></div>
</div>
</div>
<button class="demo-button" onclick="demonstratePresets()">
🎯 Run Preset Demo
</button>
</div>
<!-- Color Level Comparison -->
<div class="comparison-section">
<h2><span class="icon">🌈</span>Color Level Comparison</h2>
<div class="explanation">
<h4>Color Levels</h4>
<p>
Control the amount of colorization in your logs. From no colors
(server-friendly) to enhanced colors (development-friendly).
</p>
</div>
<div class="comparison-grid">
<div class="format-example">
<div class="format-header">None (No Colors)</div>
<div class="format-output" id="color-none-output"></div>
</div>
<div class="format-example">
<div class="format-header">Basic Colors</div>
<div class="format-output" id="color-basic-output"></div>
</div>
<div class="format-example">
<div class="format-header">Enhanced Colors</div>
<div class="format-output" id="color-enhanced-output"></div>
</div>
</div>
<button class="demo-button" onclick="demonstrateColors()">
🎨 Run Color Demo
</button>
</div>
<!-- Timestamp Formats -->
<div class="comparison-section">
<h2><span class="icon">⏰</span>Timestamp Formats</h2>
<div class="explanation">
<h4>Timestamp Options</h4>
<p>
Choose between different timestamp formats based on your needs.
Short timestamps save space, while full timestamps provide
complete information.
</p>
</div>
<div class="comparison-grid">
<div class="format-example">
<div class="format-header">No Timestamps</div>
<div class="format-output" id="timestamp-none-output"></div>
</div>
<div class="format-example">
<div class="format-header">Short Timestamps</div>
<div class="format-output" id="timestamp-short-output"></div>
</div>
<div class="format-example">
<div class="format-header">Full Timestamps</div>
<div class="format-output" id="timestamp-full-output"></div>
</div>
<div class="format-example">
<div class="format-header">Relative Timestamps</div>
<div class="format-output" id="timestamp-relative-output"></div>
</div>
</div>
<button class="demo-button" onclick="demonstrateTimestamps()">
⏱️ Run Timestamp Demo
</button>
</div>
<!-- Object Formatting -->
<div class="comparison-section">
<h2><span class="icon">📦</span>Object Formatting</h2>
<div class="explanation">
<h4>Object Display Options</h4>
<p>
Control how objects and complex data are displayed. Compact
formatting saves space, while expanded formatting is more
readable.
</p>
</div>
<div class="comparison-grid">
<div class="format-example">
<div class="format-header">Compact Objects</div>
<div class="format-output" id="object-compact-output"></div>
</div>
<div class="format-example">
<div class="format-header">Expanded Objects</div>
<div class="format-output" id="object-expanded-output"></div>
</div>
</div>
<button class="demo-button" onclick="demonstrateObjects()">
📋 Run Object Demo
</button>
</div>
<!-- Pre-configured Instances -->
<div class="comparison-section">
<h2><span class="icon">⚡</span>Pre-configured Instances</h2>
<div class="explanation">
<h4>Ready-to-Use Logger Instances</h4>
<p>
Import and use these pre-configured logger instances directly.
Each is optimized for specific use cases and environments.
</p>
<div class="code-example">
<code
>import { logger, compactLogger, readableLogger, serverLogger }
from 'loggical'</code
>
</div>
</div>
<div class="demo-controls">
<button class="demo-button" onclick="demonstrateInstances()">
⚡ Show Pre-configured Instances
</button>
</div>
<div class="output-container">
<div id="instances-output" class="output"></div>
</div>
</div>
<!-- Custom Configuration -->
<div class="comparison-section">
<h2><span class="icon">⚙️</span>Custom Configuration</h2>
<div class="explanation">
<h4>Build Your Own Format</h4>
<p>
Mix and match different formatting options to create your perfect
logging format. See the results in real-time.
</p>
</div>
<div class="controls-panel">
<div class="controls-row">
<div class="control-group">
<label>Color Level</label>
<select id="custom-color">
<option value="NONE">None</option>
<option value="BASIC">Basic</option>
<option value="ENHANCED" selected>Enhanced</option>
</select>
</div>
<div class="control-group">
<label>Prefix</label>
<input
type="text"
id="custom-prefix"
placeholder="e.g., CUSTOM"
value="DEMO"
/>
</div>
<div class="control-group">
<div class="checkbox-group">
<input type="checkbox" id="custom-timestamps" checked />
<label for="custom-timestamps">Timestamps</label>
</div>
</div>
<div class="control-group">
<div class="checkbox-group">
<input type="checkbox" id="custom-short-timestamp" checked />
<label for="custom-short-timestamp">Short Timestamps</label>
</div>
</div>
</div>
<div class="controls-row">
<div class="control-group">
<div class="checkbox-group">
<input type="checkbox" id="custom-symbols" checked />
<label for="custom-symbols">Use Symbols</label>
</div>
</div>
<div class="control-group">
<div class="checkbox-group">
<input type="checkbox" id="custom-compact" />
<label for="custom-compact">Compact Objects</label>
</div>
</div>
<div class="control-group">
<div class="checkbox-group">
<input type="checkbox" id="custom-space" />
<label for="custom-space">Space Messages</label>
</div>
</div>
<div class="control-group">
<div class="checkbox-group">
<input type="checkbox" id="custom-separators" />
<label for="custom-separators">Show Separators</label>
</div>
</div>
</div>
</div>
<div class="format-example">
<div class="format-header">Your Custom Format</div>
<div class="format-output" id="custom-output"></div>
</div>
<button class="demo-button" onclick="demonstrateCustom()">
🔧 Test Custom Format
</button>
<button class="demo-button" onclick="autoUpdateCustom()">
🔄 Auto Update
</button>
</div>
</div>
</div>
<script type="module">
import {
Logger,
ColorLevel,
logger,
compactLogger,
readableLogger,
serverLogger,
} from "loggical";
// ANSI to HTML conversion function
function ansiToHtml(text) {
const ansiMap = {
0: "reset",
1: "ansi-bold",
2: "ansi-dim",
30: "ansi-black",
31: "ansi-red",
32: "ansi-green",
33: "ansi-yellow",
34: "ansi-blue",
35: "ansi-magenta",
36: "ansi-cyan",
37: "ansi-white",
90: "ansi-gray",
91: "ansi-bright-red",
92: "ansi-bright-green",
93: "ansi-bright-yellow",
94: "ansi-bright-blue",
95: "ansi-bright-magenta",
96: "ansi-bright-cyan",
97: "ansi-bright-white",
39: "reset-fg",
};
let html = text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
let openSpans = [];
html = html.replace(
/(?:\033\[|\x1b\[|\[)([0-9;]+)m/g,
(match, codes) => {
const codeList = codes.split(";");
let result = "";
codeList.forEach((code) => {
if (code === "0" || code === "39") {
result += "</span>".repeat(openSpans.length);
openSpans = [];
} else if (ansiMap[code]) {
const className = ansiMap[code];
if (className !== "reset" && className !== "reset-fg") {
result += `<span class="${className}">`;
openSpans.push(className);
}
}
});
return result;
}
);
html += "</span>".repeat(openSpans.length);
return html;
}
// Custom transport for capturing output
class DemoTransport {
constructor(outputElementId) {
this.name = "demo";
this.outputElementId = outputElementId;
this.messages = [];
this.colorLevel = ColorLevel.ENHANCED;
}
write(formattedMessage, metadata) {
this.messages.push(formattedMessage);
const element = document.getElementById(this.outputElementId);
if (element) {
if (this.colorLevel === ColorLevel.NONE) {
const plainText = formattedMessage.replace(
/(?:\033\[|\x1b\[|\[)([0-9;]+)m/g,
""
);
element.textContent += plainText + "\n";
} else {
const htmlOutput = ansiToHtml(formattedMessage);
element.innerHTML += htmlOutput + "\n";
}
}
}
setColorLevel(colorLevel) {
this.colorLevel = colorLevel;
}
clear() {
this.messages = [];
const element = document.getElementById(this.outputElementId);
if (element) {
element.innerHTML = "";
}
}
}
// Preset configurations
const presets = {
standard: { preset: "standard" },
compact: { preset: "compact" },
readable: { preset: "readable" },
server: { preset: "server" },
};
// Sample data for demonstrations
const sampleData = {
user: {
id: 12345,
name: "John Doe",
email: "john@example.com",
preferences: {
theme: "dark",
notifications: true,
language: "en",
},
},
metrics: {
responseTime: "125ms",
memoryUsage: "45MB",
cpuUsage: "12%",
},
};
// Global functions for demo buttons
window.demonstratePresets = function () {
Object.keys(presets).forEach((presetName) => {
const transport = new DemoTransport(`${presetName}-output`);
transport.clear();
const logger = new Logger({
...presets[presetName],
transports: [transport],
});
logger.debug("Debug message for testing");
logger.info("Application started successfully", { version: "1.0.0" });
logger.warn("Configuration fallback used");
logger.error("Database connection failed", { retries: 3 });
logger.info("User data", sampleData.user);
});
};
window.demonstrateColors = function () {
const colorLevels = ["NONE", "BASIC", "ENHANCED"];
colorLevels.forEach((colorLevel) => {
const outputId = `color-${colorLevel.toLowerCase()}-output`;
const transport = new DemoTransport(outputId);
transport.setColorLevel(ColorLevel[colorLevel]);
transport.clear();
const logger = new Logger({
colorLevel: ColorLevel[colorLevel],
transports: [transport],
});
logger.debug("Debug message with colors");
logger.info("Info message with colors");
logger.warn("Warning message with colors");
logger.error("Error message with colors");
logger.highlight("Highlighted message");
});
};
window.demonstrateTimestamps = function () {
const timestampConfigs = [
{ id: "timestamp-none-output", timestamped: false },
{
id: "timestamp-short-output",
timestamped: true,
shortTimestamp: true,
},
{
id: "timestamp-full-output",
timestamped: true,
shortTimestamp: false,
},
{
id: "timestamp-relative-output",
timestamped: true,
relativeTimestamps: true,
},
];
timestampConfigs.forEach((config) => {
const transport = new DemoTransport(config.id);
transport.clear();
const logger = new Logger({
...config,
transports: [transport],
});
logger.info("First message");
setTimeout(() => {
logger.info("Second message (+100ms)");
}, 100);
setTimeout(() => {
logger.warn("Third message (+250ms)");
}, 250);
});
};
window.demonstrateObjects = function () {
const objectConfigs = [
{ id: "object-compact-output", compactObjects: true },
{ id: "object-expanded-output", compactObjects: false },
];
objectConfigs.forEach((config) => {
const transport = new DemoTransport(config.id);
transport.clear();
const logger = new Logger({
...config,
transports: [transport],
});
logger.info("Simple object", { status: "success", count: 42 });
logger.info("Complex object", sampleData.user);
logger.info("Array data", ["apple", "banana", "cherry"]);
logger.info("Mixed data", {
timestamp: new Date(),
metrics: sampleData.metrics,
tags: ["important", "user-action"],
});
});
};
window.demonstrateCustom = function () {
const colorLevel = document.getElementById("custom-color").value;
const prefix = document.getElementById("custom-prefix").value;
const timestamped =
document.getElementById("custom-timestamps").checked;
const shortTimestamp = document.getElementById(
"custom-short-timestamp"
).checked;
const useSymbols = document.getElementById("custom-symbols").checked;
const compactObjects =
document.getElementById("custom-compact").checked;
const spaceMessages = document.getElementById("custom-space").checked;
const showSeparators =
document.getElementById("custom-separators").checked;
const transport = new DemoTransport("custom-output");
transport.setColorLevel(ColorLevel[colorLevel]);
transport.clear();
const logger = new Logger({
colorLevel: ColorLevel[colorLevel],
prefix: prefix || undefined,
timestamped,
shortTimestamp,
useSymbols,
compactObjects,
spaceMessages,
showSeparators,
transports: [transport],
});
logger.debug("Debug message with custom format");
logger.info("Application event", {
action: "user_login",
userId: "user123",
});
logger.warn("Performance warning", sampleData.metrics);
logger.error("Operation failed", {
error: "Network timeout",
retries: 3,
});
logger.highlight("Important notification");
};
window.showPresets = function () {
document
.querySelectorAll(".preset-button")
.forEach((btn) => btn.classList.remove("active"));
event.target.classList.add("active");
const grid = document.getElementById("preset-comparison");
grid.innerHTML = `
<div class="format-example">
<div class="format-header">Standard Preset</div>
<div class="format-output" id="standard-output"></div>
</div>
<div class="format-example">
<div class="format-header">Compact Preset</div>
<div class="format-output" id="compact-output"></div>
</div>
<div class="format-example">
<div class="format-header">Readable Preset</div>
<div class="format-output" id="readable-output"></div>
</div>
<div class="format-example">
<div class="format-header">Server Preset</div>
<div class="format-output" id="server-output"></div>
</div>
`;
};
window.showPreset = function (presetName) {
document
.querySelectorAll(".preset-button")
.forEach((btn) => btn.classList.remove("active"));
event.target.classList.add("active");
const grid = document.getElementById("preset-comparison");
const presetTitle =
presetName.charAt(0).toUpperCase() + presetName.slice(1);
grid.innerHTML = `
<div class="format-example" style="grid-column: 1 / -1;">
<div class="format-header">${presetTitle} Preset</div>
<div class="format-output" id="${presetName}-output"></div>
</div>
`;
};
let autoUpdateInterval;
window.autoUpdateCustom = function () {
if (autoUpdateInterval) {
clearInterval(autoUpdateInterval);
autoUpdateInterval = null;
event.target.textContent = "🔄 Auto Update";
return;
}
event.target.textContent = "⏹️ Stop Auto Update";
demonstrateCustom();
autoUpdateInterval = setInterval(() => {
demonstrateCustom();
}, 2000);
};
window.demonstrateInstances = function () {
const transport = new DemoTransport("instances-output");
transport.clear();
const message = "User session started";
const data = {
userId: 12345,
sessionId: "sess_abc123",
userAgent: "Mozilla/5.0 (Chrome)",
timestamp: new Date().toISOString(),
};
transport.write("=== Pre-configured Logger Instances ===\n");
// Standard logger
transport.write("📋 logger (Standard):");
const standardTransport = new DemoTransport("instances-output", false);
const standardLogger = new Logger({ transports: [standardTransport] });
standardLogger.info(message, data);
// Compact logger
transport.write("\n💾 compactLogger (Space-efficient):");
const compactTransport = new DemoTransport("instances-output", false);
const demoCompactLogger = new Logger({
preset: "compact",
transports: [compactTransport],
});
demoCompactLogger.info(message, data);
// Readable logger
transport.write("\n👁️ readableLogger (Development-friendly):");
const readableTransport = new DemoTransport("instances-output", false);
const demoReadableLogger = new Logger({
preset: "readable",
transports: [readableTransport],
});
demoReadableLogger.info(message, data);
// Server logger
transport.write("\n🖥️ serverLogger (Production-optimized):");
const serverTransport = new DemoTransport("instances-output", false);
const demoServerLogger = new Logger({
preset: "server",
transports: [serverTransport],
});
demoServerLogger.info(message, data);
transport.write(
"\n\n💡 Usage: Import and use directly without any configuration!"
);
transport.write(" import { compactLogger } from 'loggical'");
transport.write(" compactLogger.info('Ready to go!')");
};
// Add event listeners for custom controls
document.addEventListener("DOMContentLoaded", function () {
const customControls = [
"custom-color",
"custom-prefix",
"custom-timestamps",
"custom-short-timestamp",
"custom-symbols",
"custom-compact",
"custom-space",
"custom-separators",
];
customControls.forEach((id) => {
const element = document.getElementById(id);
if (element) {
element.addEventListener("change", demonstrateCustom);
element.addEventListener("input", demonstrateCustom);
}
});
// Initial demonstrations
demonstratePresets();
demonstrateColors();
demonstrateTimestamps();
demonstrateObjects();
demonstrateCustom();
});
</script>
</body>
</html>✨ Features
- ✅ Side-by-side preset comparisons (compact, readable, server)
- ✅ Live color level configuration
- ✅ Dynamic timestamp format switching
- ✅ Object formatting options showcase
- ✅ Interactive configuration builder with real-time preview
🚀 Running This Demo
bash
# Build the package first
pnpm run build
# Start the demo server
node examples/serve.js
# Then open in your browser:
# http://localhost:3000/formatting-demo.html🔗 Related
- ← Back to Examples Overview
- API Reference - Technical documentation
- Getting Started Guide - Setup instructions
This interactive demo is automatically embedded from examples/formatting-demo.html.
