@float.js/core 2.0.3 β 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +4 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/devtools/index.js +1 -1
- package/dist/devtools/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/devtools/index.js
CHANGED
|
@@ -593,7 +593,7 @@ function generateDashboardHTML(state) {
|
|
|
593
593
|
<div class="logo-icon">\u26A1</div>
|
|
594
594
|
<div class="logo-text">
|
|
595
595
|
<span class="logo-title">Float.js</span>
|
|
596
|
-
<span class="logo-version">v2.0.
|
|
596
|
+
<span class="logo-version">v2.0.4</span>
|
|
597
597
|
</div>
|
|
598
598
|
</div>
|
|
599
599
|
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/devtools/index.ts"],"sourcesContent":["/**\n * Float.js Dev Dashboard\n * Visual development tools integrated into the framework\n * \n * Next.js doesn't have this! π\n */\n\nimport { IncomingMessage, ServerResponse } from 'http';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\nexport interface RouteInfo {\n path: string;\n type: 'page' | 'api' | 'layout' | 'error' | 'loading' | 'not-found';\n file: string;\n methods?: string[];\n params?: string[];\n middleware?: boolean;\n}\n\nexport interface BuildInfo {\n duration: number;\n timestamp: Date;\n success: boolean;\n errors?: string[];\n warnings?: string[];\n}\n\nexport interface RequestLog {\n id: string;\n method: string;\n path: string;\n status: number;\n duration: number;\n timestamp: Date;\n headers?: Record<string, string>;\n body?: unknown;\n response?: unknown;\n}\n\nexport interface PerformanceMetrics {\n requests: number;\n avgResponseTime: number;\n errorRate: number;\n activeConnections: number;\n memoryUsage: NodeJS.MemoryUsage;\n uptime: number;\n}\n\nexport interface DevDashboardOptions {\n enabled?: boolean;\n path?: string;\n maxLogs?: number;\n auth?: {\n username: string;\n password: string;\n };\n}\n\n// ============================================================================\n// DEV DASHBOARD STATE\n// ============================================================================\n\nclass DevDashboardState {\n routes: RouteInfo[] = [];\n builds: BuildInfo[] = [];\n requestLogs: RequestLog[] = [];\n startTime: Date = new Date();\n maxLogs: number = 100;\n \n private requestCount = 0;\n private totalResponseTime = 0;\n private errorCount = 0;\n\n addRoute(route: RouteInfo): void {\n const existing = this.routes.findIndex(r => r.path === route.path);\n if (existing >= 0) {\n this.routes[existing] = route;\n } else {\n this.routes.push(route);\n }\n }\n\n addBuild(build: BuildInfo): void {\n this.builds.unshift(build);\n if (this.builds.length > 20) {\n this.builds.pop();\n }\n }\n\n logRequest(log: RequestLog): void {\n this.requestLogs.unshift(log);\n if (this.requestLogs.length > this.maxLogs) {\n this.requestLogs.pop();\n }\n \n this.requestCount++;\n this.totalResponseTime += log.duration;\n if (log.status >= 400) {\n this.errorCount++;\n }\n }\n\n getMetrics(): PerformanceMetrics {\n return {\n requests: this.requestCount,\n avgResponseTime: this.requestCount > 0 \n ? Math.round(this.totalResponseTime / this.requestCount) \n : 0,\n errorRate: this.requestCount > 0 \n ? Math.round((this.errorCount / this.requestCount) * 100) \n : 0,\n activeConnections: 0, // Updated by server\n memoryUsage: process.memoryUsage(),\n uptime: Date.now() - this.startTime.getTime(),\n };\n }\n\n clear(): void {\n this.requestLogs = [];\n this.requestCount = 0;\n this.totalResponseTime = 0;\n this.errorCount = 0;\n }\n}\n\nexport const dashboardState = new DevDashboardState();\n\n// ============================================================================\n// MIDDLEWARE\n// ============================================================================\n\nexport function createRequestLogger() {\n return (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n const startTime = Date.now();\n const id = `req_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;\n\n // Capture response\n const originalEnd = res.end.bind(res);\n res.end = function(chunk?: any, encoding?: any, callback?: any) {\n const duration = Date.now() - startTime;\n \n dashboardState.logRequest({\n id,\n method: req.method || 'GET',\n path: req.url || '/',\n status: res.statusCode,\n duration,\n timestamp: new Date(),\n });\n\n return originalEnd(chunk, encoding, callback);\n } as typeof res.end;\n\n next();\n };\n}\n\n// ============================================================================\n// DASHBOARD HTML\n// ============================================================================\n\nfunction generateDashboardHTML(state: DevDashboardState): string {\n const metrics = state.getMetrics();\n const memoryMB = Math.round(metrics.memoryUsage.heapUsed / 1024 / 1024);\n const memoryTotal = Math.round(metrics.memoryUsage.heapTotal / 1024 / 1024);\n const uptimeSeconds = Math.round(metrics.uptime / 1000);\n const uptimeFormatted = uptimeSeconds < 60 \n ? `${uptimeSeconds}s` \n : uptimeSeconds < 3600 \n ? `${Math.floor(uptimeSeconds / 60)}m ${uptimeSeconds % 60}s`\n : `${Math.floor(uptimeSeconds / 3600)}h ${Math.floor((uptimeSeconds % 3600) / 60)}m`;\n \n const lastBuild = state.builds.length > 0 ? state.builds[0] : null;\n const lastBuildTime = lastBuild \n ? new Date(lastBuild.timestamp).toLocaleTimeString() \n : 'Never';\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Float.js Dev Dashboard</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap\" rel=\"stylesheet\">\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n \n :root {\n --bg-dark: #09090b;\n --bg-card: #18181b;\n --bg-card-hover: #1f1f23;\n --bg-sidebar: #0f0f12;\n --text-primary: #fafafa;\n --text-secondary: #71717a;\n --text-muted: #52525b;\n --accent: #a855f7;\n --accent-glow: rgba(168, 85, 247, 0.15);\n --success: #22c55e;\n --warning: #f59e0b;\n --error: #ef4444;\n --border: #27272a;\n --border-subtle: #1f1f23;\n }\n\n body {\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n background: var(--bg-dark);\n color: var(--text-primary);\n min-height: 100vh;\n display: flex;\n }\n\n /* Sidebar */\n .sidebar {\n width: 280px;\n background: var(--bg-sidebar);\n border-right: 1px solid var(--border);\n display: flex;\n flex-direction: column;\n position: fixed;\n height: 100vh;\n z-index: 100;\n }\n\n .sidebar-header {\n padding: 1.5rem;\n border-bottom: 1px solid var(--border);\n }\n\n .logo {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n }\n\n .logo-icon {\n width: 40px;\n height: 40px;\n background: linear-gradient(135deg, #a855f7 0%, #ec4899 50%, #f97316 100%);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 700;\n font-size: 1.25rem;\n box-shadow: 0 0 20px rgba(168, 85, 247, 0.3);\n }\n\n .logo-text {\n display: flex;\n flex-direction: column;\n }\n\n .logo-title {\n font-weight: 700;\n font-size: 1.125rem;\n background: linear-gradient(135deg, #fff 0%, #a1a1aa 100%);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n\n .logo-version {\n font-size: 0.75rem;\n color: var(--text-muted);\n font-family: 'JetBrains Mono', monospace;\n }\n\n /* Status Cards */\n .status-section {\n padding: 1.5rem;\n border-bottom: 1px solid var(--border);\n }\n\n .status-grid {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n }\n\n .status-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: var(--bg-card);\n border-radius: 10px;\n border: 1px solid var(--border-subtle);\n }\n\n .status-label {\n font-size: 0.8rem;\n color: var(--text-secondary);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n\n .status-value {\n font-size: 0.875rem;\n font-weight: 600;\n font-family: 'JetBrains Mono', monospace;\n }\n\n .status-value.connected {\n color: var(--success);\n }\n\n .status-value.active {\n color: var(--accent);\n }\n\n .status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n animation: pulse 2s infinite;\n }\n\n .status-dot.green { background: var(--success); box-shadow: 0 0 8px var(--success); }\n .status-dot.purple { background: var(--accent); box-shadow: 0 0 8px var(--accent); }\n\n @keyframes pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.7; transform: scale(0.95); }\n }\n\n /* Navigation */\n .nav-section {\n padding: 1rem;\n flex: 1;\n }\n\n .nav-label {\n font-size: 0.7rem;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--text-muted);\n padding: 0.5rem 1rem;\n margin-bottom: 0.5rem;\n }\n\n .nav-item {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n border-radius: 10px;\n color: var(--text-secondary);\n text-decoration: none;\n font-size: 0.875rem;\n font-weight: 500;\n transition: all 0.2s;\n cursor: pointer;\n margin-bottom: 0.25rem;\n }\n\n .nav-item:hover {\n background: var(--bg-card);\n color: var(--text-primary);\n }\n\n .nav-item.active {\n background: var(--accent-glow);\n color: var(--accent);\n border: 1px solid rgba(168, 85, 247, 0.2);\n }\n\n .nav-icon {\n font-size: 1.1rem;\n }\n\n .nav-badge {\n margin-left: auto;\n background: var(--bg-card);\n padding: 0.125rem 0.5rem;\n border-radius: 6px;\n font-size: 0.7rem;\n font-family: 'JetBrains Mono', monospace;\n color: var(--text-muted);\n }\n\n /* Sidebar Footer */\n .sidebar-footer {\n padding: 1rem 1.5rem;\n border-top: 1px solid var(--border);\n }\n\n .docs-link {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem;\n background: linear-gradient(135deg, rgba(168, 85, 247, 0.1), rgba(236, 72, 153, 0.1));\n border: 1px solid rgba(168, 85, 247, 0.2);\n border-radius: 10px;\n color: var(--accent);\n text-decoration: none;\n font-size: 0.875rem;\n font-weight: 500;\n transition: all 0.2s;\n }\n\n .docs-link:hover {\n background: linear-gradient(135deg, rgba(168, 85, 247, 0.2), rgba(236, 72, 153, 0.2));\n transform: translateY(-1px);\n }\n\n /* Main Content */\n .main {\n margin-left: 280px;\n flex: 1;\n padding: 2rem;\n min-height: 100vh;\n }\n\n .page-header {\n margin-bottom: 2rem;\n }\n\n .page-title {\n font-size: 1.75rem;\n font-weight: 700;\n margin-bottom: 0.5rem;\n }\n\n .page-subtitle {\n color: var(--text-secondary);\n font-size: 0.9rem;\n }\n\n /* Metrics Grid */\n .metrics-grid {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 1rem;\n margin-bottom: 2rem;\n }\n\n .metric-card {\n background: var(--bg-card);\n border: 1px solid var(--border-subtle);\n border-radius: 16px;\n padding: 1.5rem;\n transition: all 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .metric-card::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 2px;\n background: linear-gradient(90deg, var(--accent), #ec4899);\n opacity: 0;\n transition: opacity 0.3s;\n }\n\n .metric-card:hover {\n border-color: var(--accent);\n transform: translateY(-2px);\n box-shadow: 0 8px 32px rgba(168, 85, 247, 0.1);\n }\n\n .metric-card:hover::before {\n opacity: 1;\n }\n\n .metric-icon {\n font-size: 1.5rem;\n margin-bottom: 1rem;\n }\n\n .metric-value {\n font-size: 2rem;\n font-weight: 700;\n font-family: 'JetBrains Mono', monospace;\n margin-bottom: 0.25rem;\n }\n\n .metric-label {\n font-size: 0.8rem;\n color: var(--text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n .metric-change {\n position: absolute;\n top: 1rem;\n right: 1rem;\n font-size: 0.75rem;\n padding: 0.25rem 0.5rem;\n border-radius: 6px;\n font-weight: 500;\n }\n\n .metric-change.up { background: rgba(34, 197, 94, 0.1); color: var(--success); }\n .metric-change.down { background: rgba(239, 68, 68, 0.1); color: var(--error); }\n\n /* Sections */\n .content-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n }\n\n .section {\n background: var(--bg-card);\n border: 1px solid var(--border-subtle);\n border-radius: 16px;\n overflow: hidden;\n }\n\n .section.full-width {\n grid-column: 1 / -1;\n }\n\n .section-header {\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .section-title {\n font-size: 1rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n\n .section-badge {\n background: var(--bg-dark);\n padding: 0.25rem 0.75rem;\n border-radius: 8px;\n font-size: 0.75rem;\n color: var(--text-muted);\n font-family: 'JetBrains Mono', monospace;\n }\n\n .section-content {\n max-height: 400px;\n overflow-y: auto;\n }\n\n /* Routes List */\n .route-item {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 1rem 1.5rem;\n border-bottom: 1px solid var(--border-subtle);\n transition: background 0.2s;\n }\n\n .route-item:last-child {\n border-bottom: none;\n }\n\n .route-item:hover {\n background: var(--bg-card-hover);\n }\n\n .route-type {\n padding: 0.25rem 0.75rem;\n border-radius: 6px;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n min-width: 60px;\n text-align: center;\n }\n\n .route-type.page { background: rgba(59, 130, 246, 0.15); color: #60a5fa; }\n .route-type.api { background: rgba(34, 197, 94, 0.15); color: #4ade80; }\n .route-type.layout { background: rgba(168, 85, 247, 0.15); color: #c084fc; }\n\n .route-path {\n font-family: 'JetBrains Mono', monospace;\n font-size: 0.875rem;\n flex: 1;\n }\n\n .route-file {\n color: var(--text-muted);\n font-size: 0.75rem;\n font-family: 'JetBrains Mono', monospace;\n }\n\n /* Request Logs */\n .log-item {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 0.875rem 1.5rem;\n border-bottom: 1px solid var(--border-subtle);\n font-size: 0.875rem;\n transition: background 0.2s;\n }\n\n .log-item:hover {\n background: var(--bg-card-hover);\n }\n\n .log-method {\n font-weight: 600;\n padding: 0.25rem 0.5rem;\n border-radius: 4px;\n font-size: 0.7rem;\n min-width: 50px;\n text-align: center;\n font-family: 'JetBrains Mono', monospace;\n }\n\n .log-method.GET { background: rgba(59, 130, 246, 0.15); color: #60a5fa; }\n .log-method.POST { background: rgba(34, 197, 94, 0.15); color: #4ade80; }\n .log-method.PUT { background: rgba(245, 158, 11, 0.15); color: #fbbf24; }\n .log-method.DELETE { background: rgba(239, 68, 68, 0.15); color: #f87171; }\n\n .log-status {\n font-weight: 600;\n font-family: 'JetBrains Mono', monospace;\n font-size: 0.8rem;\n }\n\n .log-status.s2xx { color: var(--success); }\n .log-status.s3xx { color: #60a5fa; }\n .log-status.s4xx { color: var(--warning); }\n .log-status.s5xx { color: var(--error); }\n\n .log-path {\n font-family: 'JetBrains Mono', monospace;\n flex: 1;\n color: var(--text-secondary);\n }\n\n .log-duration {\n font-family: 'JetBrains Mono', monospace;\n color: var(--text-muted);\n font-size: 0.8rem;\n }\n\n .log-time {\n color: var(--text-muted);\n font-size: 0.75rem;\n }\n\n /* Empty State */\n .empty-state {\n text-align: center;\n padding: 3rem;\n color: var(--text-muted);\n }\n\n .empty-icon {\n font-size: 2.5rem;\n margin-bottom: 1rem;\n opacity: 0.5;\n }\n\n /* Scrollbar */\n ::-webkit-scrollbar { width: 6px; }\n ::-webkit-scrollbar-track { background: transparent; }\n ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }\n ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }\n\n /* Responsive */\n @media (max-width: 1200px) {\n .metrics-grid { grid-template-columns: repeat(2, 1fr); }\n .content-grid { grid-template-columns: 1fr; }\n }\n </style>\n</head>\n<body>\n <!-- Sidebar -->\n <aside class=\"sidebar\">\n <div class=\"sidebar-header\">\n <div class=\"logo\">\n <div class=\"logo-icon\">β‘</div>\n <div class=\"logo-text\">\n <span class=\"logo-title\">Float.js</span>\n <span class=\"logo-version\">v2.0.1</span>\n </div>\n </div>\n </div>\n\n <div class=\"status-section\">\n <div class=\"status-grid\">\n <div class=\"status-item\">\n <span class=\"status-label\">\n <span class=\"status-dot green\"></span>\n Estado\n </span>\n <span class=\"status-value connected\">Conectado</span>\n </div>\n <div class=\"status-item\">\n <span class=\"status-label\">\n <span class=\"status-dot purple\"></span>\n HMR\n </span>\n <span class=\"status-value active\">Activo</span>\n </div>\n <div class=\"status-item\">\n <span class=\"status-label\">Γltimo build</span>\n <span class=\"status-value\">${lastBuildTime}</span>\n </div>\n <div class=\"status-item\">\n <span class=\"status-label\">Uptime</span>\n <span class=\"status-value\">${uptimeFormatted}</span>\n </div>\n </div>\n </div>\n\n <nav class=\"nav-section\">\n <div class=\"nav-label\">Dashboard</div>\n <div class=\"nav-item active\">\n <span class=\"nav-icon\">π</span>\n Overview\n </div>\n <div class=\"nav-item\">\n <span class=\"nav-icon\">π€οΈ</span>\n Routes\n <span class=\"nav-badge\">${state.routes.length}</span>\n </div>\n <div class=\"nav-item\">\n <span class=\"nav-icon\">π</span>\n Logs\n <span class=\"nav-badge\">${state.requestLogs.length}</span>\n </div>\n <div class=\"nav-item\">\n <span class=\"nav-icon\">βοΈ</span>\n Settings\n </div>\n </nav>\n\n <div class=\"sidebar-footer\">\n <a href=\"https://floatjs.dev/docs\" target=\"_blank\" class=\"docs-link\">\n <span>π</span>\n Documentation\n </a>\n </div>\n </aside>\n\n <!-- Main Content -->\n <main class=\"main\">\n <div class=\"page-header\">\n <h1 class=\"page-title\">Dev Dashboard</h1>\n <p class=\"page-subtitle\">Monitor your Float.js application in real-time</p>\n </div>\n\n <!-- Metrics -->\n <div class=\"metrics-grid\">\n <div class=\"metric-card\">\n <div class=\"metric-icon\">π‘</div>\n <div class=\"metric-value\">${metrics.requests}</div>\n <div class=\"metric-label\">Total Requests</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-icon\">β‘</div>\n <div class=\"metric-value\">${metrics.avgResponseTime}ms</div>\n <div class=\"metric-label\">Avg Response</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-icon\">πΎ</div>\n <div class=\"metric-value\">${memoryMB}/${memoryTotal}</div>\n <div class=\"metric-label\">Memory (MB)</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-icon\">${metrics.errorRate > 0 ? 'β οΈ' : 'β
'}</div>\n <div class=\"metric-value\">${metrics.errorRate}%</div>\n <div class=\"metric-label\">Error Rate</div>\n </div>\n </div>\n\n <!-- Content Grid -->\n <div class=\"content-grid\">\n <!-- Routes -->\n <div class=\"section\">\n <div class=\"section-header\">\n <span class=\"section-title\">π€οΈ Routes</span>\n <span class=\"section-badge\">${state.routes.length} registered</span>\n </div>\n <div class=\"section-content\">\n ${state.routes.length === 0 ? `\n <div class=\"empty-state\">\n <div class=\"empty-icon\">π€οΈ</div>\n <p>No routes registered</p>\n </div>\n ` : state.routes.map(route => `\n <div class=\"route-item\">\n <span class=\"route-type ${route.type}\">${route.type}</span>\n <span class=\"route-path\">${route.path}</span>\n <span class=\"route-file\">${route.file.split('/').pop()}</span>\n </div>\n `).join('')}\n </div>\n </div>\n\n <!-- Request Logs -->\n <div class=\"section\">\n <div class=\"section-header\">\n <span class=\"section-title\">π Request Logs</span>\n <span class=\"section-badge\">Live</span>\n </div>\n <div class=\"section-content\">\n ${state.requestLogs.length === 0 ? `\n <div class=\"empty-state\">\n <div class=\"empty-icon\">π</div>\n <p>No requests yet</p>\n </div>\n ` : state.requestLogs.slice(0, 20).map(log => {\n const statusClass = log.status < 300 ? 's2xx' : log.status < 400 ? 's3xx' : log.status < 500 ? 's4xx' : 's5xx';\n return `\n <div class=\"log-item\">\n <span class=\"log-method ${log.method}\">${log.method}</span>\n <span class=\"log-status ${statusClass}\">${log.status}</span>\n <span class=\"log-path\">${log.path}</span>\n <span class=\"log-duration\">${log.duration}ms</span>\n </div>\n `;\n }).join('')}\n </div>\n </div>\n </div>\n </main>\n\n <script>\n // Auto-refresh every 3 seconds\n setTimeout(() => location.reload(), 3000);\n </script>\n</body>\n</html>`;\n}\n\n// ============================================================================\n// DASHBOARD API\n// ============================================================================\n\nfunction generateAPIResponse(state: DevDashboardState): string {\n return JSON.stringify({\n metrics: state.getMetrics(),\n routes: state.routes,\n builds: state.builds.slice(0, 10),\n requestLogs: state.requestLogs.slice(0, 50),\n });\n}\n\n// ============================================================================\n// DASHBOARD HANDLER\n// ============================================================================\n\nexport function createDevDashboard(options: DevDashboardOptions = {}) {\n const {\n enabled = process.env.NODE_ENV !== 'production',\n path = '/__float',\n auth,\n } = options;\n\n if (!enabled) {\n return (_req: IncomingMessage, _res: ServerResponse, next: () => void) => next();\n }\n\n return (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n const url = req.url || '';\n \n // Check if this is a dashboard request\n if (!url.startsWith(path)) {\n return next();\n }\n\n // Basic auth if configured\n if (auth) {\n const authHeader = req.headers.authorization;\n if (!authHeader || !authHeader.startsWith('Basic ')) {\n res.setHeader('WWW-Authenticate', 'Basic realm=\"Float.js Dev Dashboard\"');\n res.statusCode = 401;\n res.end('Unauthorized');\n return;\n }\n\n const credentials = Buffer.from(authHeader.slice(6), 'base64').toString();\n const [username, password] = credentials.split(':');\n \n if (username !== auth.username || password !== auth.password) {\n res.statusCode = 401;\n res.end('Invalid credentials');\n return;\n }\n }\n\n // Route dashboard requests\n const subPath = url.slice(path.length);\n\n if (subPath === '' || subPath === '/') {\n // Main dashboard\n res.setHeader('Content-Type', 'text/html');\n res.end(generateDashboardHTML(dashboardState));\n return;\n }\n\n if (subPath === '/api' || subPath === '/api/') {\n // API endpoint\n res.setHeader('Content-Type', 'application/json');\n res.end(generateAPIResponse(dashboardState));\n return;\n }\n\n if (subPath === '/api/routes') {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(dashboardState.routes));\n return;\n }\n\n if (subPath === '/api/metrics') {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(dashboardState.getMetrics()));\n return;\n }\n\n if (subPath === '/api/logs') {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(dashboardState.requestLogs.slice(0, 100)));\n return;\n }\n\n if (subPath === '/api/clear' && req.method === 'POST') {\n dashboardState.clear();\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ success: true }));\n return;\n }\n\n // 404 for unknown dashboard routes\n res.statusCode = 404;\n res.end('Not found');\n };\n}\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport const devtools = {\n dashboard: createDevDashboard,\n logger: createRequestLogger,\n state: dashboardState,\n \n // Helpers for manual logging\n logRoute: (route: RouteInfo) => dashboardState.addRoute(route),\n logBuild: (build: BuildInfo) => dashboardState.addBuild(build),\n logRequest: (log: RequestLog) => dashboardState.logRequest(log),\n getMetrics: () => dashboardState.getMetrics(),\n clear: () => dashboardState.clear(),\n};\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/devtools/index.ts"],"sourcesContent":["/**\n * Float.js Dev Dashboard\n * Visual development tools integrated into the framework\n * \n * Next.js doesn't have this! π\n */\n\nimport { IncomingMessage, ServerResponse } from 'http';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\nexport interface RouteInfo {\n path: string;\n type: 'page' | 'api' | 'layout' | 'error' | 'loading' | 'not-found';\n file: string;\n methods?: string[];\n params?: string[];\n middleware?: boolean;\n}\n\nexport interface BuildInfo {\n duration: number;\n timestamp: Date;\n success: boolean;\n errors?: string[];\n warnings?: string[];\n}\n\nexport interface RequestLog {\n id: string;\n method: string;\n path: string;\n status: number;\n duration: number;\n timestamp: Date;\n headers?: Record<string, string>;\n body?: unknown;\n response?: unknown;\n}\n\nexport interface PerformanceMetrics {\n requests: number;\n avgResponseTime: number;\n errorRate: number;\n activeConnections: number;\n memoryUsage: NodeJS.MemoryUsage;\n uptime: number;\n}\n\nexport interface DevDashboardOptions {\n enabled?: boolean;\n path?: string;\n maxLogs?: number;\n auth?: {\n username: string;\n password: string;\n };\n}\n\n// ============================================================================\n// DEV DASHBOARD STATE\n// ============================================================================\n\nclass DevDashboardState {\n routes: RouteInfo[] = [];\n builds: BuildInfo[] = [];\n requestLogs: RequestLog[] = [];\n startTime: Date = new Date();\n maxLogs: number = 100;\n \n private requestCount = 0;\n private totalResponseTime = 0;\n private errorCount = 0;\n\n addRoute(route: RouteInfo): void {\n const existing = this.routes.findIndex(r => r.path === route.path);\n if (existing >= 0) {\n this.routes[existing] = route;\n } else {\n this.routes.push(route);\n }\n }\n\n addBuild(build: BuildInfo): void {\n this.builds.unshift(build);\n if (this.builds.length > 20) {\n this.builds.pop();\n }\n }\n\n logRequest(log: RequestLog): void {\n this.requestLogs.unshift(log);\n if (this.requestLogs.length > this.maxLogs) {\n this.requestLogs.pop();\n }\n \n this.requestCount++;\n this.totalResponseTime += log.duration;\n if (log.status >= 400) {\n this.errorCount++;\n }\n }\n\n getMetrics(): PerformanceMetrics {\n return {\n requests: this.requestCount,\n avgResponseTime: this.requestCount > 0 \n ? Math.round(this.totalResponseTime / this.requestCount) \n : 0,\n errorRate: this.requestCount > 0 \n ? Math.round((this.errorCount / this.requestCount) * 100) \n : 0,\n activeConnections: 0, // Updated by server\n memoryUsage: process.memoryUsage(),\n uptime: Date.now() - this.startTime.getTime(),\n };\n }\n\n clear(): void {\n this.requestLogs = [];\n this.requestCount = 0;\n this.totalResponseTime = 0;\n this.errorCount = 0;\n }\n}\n\nexport const dashboardState = new DevDashboardState();\n\n// ============================================================================\n// MIDDLEWARE\n// ============================================================================\n\nexport function createRequestLogger() {\n return (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n const startTime = Date.now();\n const id = `req_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;\n\n // Capture response\n const originalEnd = res.end.bind(res);\n res.end = function(chunk?: any, encoding?: any, callback?: any) {\n const duration = Date.now() - startTime;\n \n dashboardState.logRequest({\n id,\n method: req.method || 'GET',\n path: req.url || '/',\n status: res.statusCode,\n duration,\n timestamp: new Date(),\n });\n\n return originalEnd(chunk, encoding, callback);\n } as typeof res.end;\n\n next();\n };\n}\n\n// ============================================================================\n// DASHBOARD HTML\n// ============================================================================\n\nfunction generateDashboardHTML(state: DevDashboardState): string {\n const metrics = state.getMetrics();\n const memoryMB = Math.round(metrics.memoryUsage.heapUsed / 1024 / 1024);\n const memoryTotal = Math.round(metrics.memoryUsage.heapTotal / 1024 / 1024);\n const uptimeSeconds = Math.round(metrics.uptime / 1000);\n const uptimeFormatted = uptimeSeconds < 60 \n ? `${uptimeSeconds}s` \n : uptimeSeconds < 3600 \n ? `${Math.floor(uptimeSeconds / 60)}m ${uptimeSeconds % 60}s`\n : `${Math.floor(uptimeSeconds / 3600)}h ${Math.floor((uptimeSeconds % 3600) / 60)}m`;\n \n const lastBuild = state.builds.length > 0 ? state.builds[0] : null;\n const lastBuildTime = lastBuild \n ? new Date(lastBuild.timestamp).toLocaleTimeString() \n : 'Never';\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Float.js Dev Dashboard</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap\" rel=\"stylesheet\">\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n \n :root {\n --bg-dark: #09090b;\n --bg-card: #18181b;\n --bg-card-hover: #1f1f23;\n --bg-sidebar: #0f0f12;\n --text-primary: #fafafa;\n --text-secondary: #71717a;\n --text-muted: #52525b;\n --accent: #a855f7;\n --accent-glow: rgba(168, 85, 247, 0.15);\n --success: #22c55e;\n --warning: #f59e0b;\n --error: #ef4444;\n --border: #27272a;\n --border-subtle: #1f1f23;\n }\n\n body {\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n background: var(--bg-dark);\n color: var(--text-primary);\n min-height: 100vh;\n display: flex;\n }\n\n /* Sidebar */\n .sidebar {\n width: 280px;\n background: var(--bg-sidebar);\n border-right: 1px solid var(--border);\n display: flex;\n flex-direction: column;\n position: fixed;\n height: 100vh;\n z-index: 100;\n }\n\n .sidebar-header {\n padding: 1.5rem;\n border-bottom: 1px solid var(--border);\n }\n\n .logo {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n }\n\n .logo-icon {\n width: 40px;\n height: 40px;\n background: linear-gradient(135deg, #a855f7 0%, #ec4899 50%, #f97316 100%);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 700;\n font-size: 1.25rem;\n box-shadow: 0 0 20px rgba(168, 85, 247, 0.3);\n }\n\n .logo-text {\n display: flex;\n flex-direction: column;\n }\n\n .logo-title {\n font-weight: 700;\n font-size: 1.125rem;\n background: linear-gradient(135deg, #fff 0%, #a1a1aa 100%);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n\n .logo-version {\n font-size: 0.75rem;\n color: var(--text-muted);\n font-family: 'JetBrains Mono', monospace;\n }\n\n /* Status Cards */\n .status-section {\n padding: 1.5rem;\n border-bottom: 1px solid var(--border);\n }\n\n .status-grid {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n }\n\n .status-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: var(--bg-card);\n border-radius: 10px;\n border: 1px solid var(--border-subtle);\n }\n\n .status-label {\n font-size: 0.8rem;\n color: var(--text-secondary);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n\n .status-value {\n font-size: 0.875rem;\n font-weight: 600;\n font-family: 'JetBrains Mono', monospace;\n }\n\n .status-value.connected {\n color: var(--success);\n }\n\n .status-value.active {\n color: var(--accent);\n }\n\n .status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n animation: pulse 2s infinite;\n }\n\n .status-dot.green { background: var(--success); box-shadow: 0 0 8px var(--success); }\n .status-dot.purple { background: var(--accent); box-shadow: 0 0 8px var(--accent); }\n\n @keyframes pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.7; transform: scale(0.95); }\n }\n\n /* Navigation */\n .nav-section {\n padding: 1rem;\n flex: 1;\n }\n\n .nav-label {\n font-size: 0.7rem;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--text-muted);\n padding: 0.5rem 1rem;\n margin-bottom: 0.5rem;\n }\n\n .nav-item {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n border-radius: 10px;\n color: var(--text-secondary);\n text-decoration: none;\n font-size: 0.875rem;\n font-weight: 500;\n transition: all 0.2s;\n cursor: pointer;\n margin-bottom: 0.25rem;\n }\n\n .nav-item:hover {\n background: var(--bg-card);\n color: var(--text-primary);\n }\n\n .nav-item.active {\n background: var(--accent-glow);\n color: var(--accent);\n border: 1px solid rgba(168, 85, 247, 0.2);\n }\n\n .nav-icon {\n font-size: 1.1rem;\n }\n\n .nav-badge {\n margin-left: auto;\n background: var(--bg-card);\n padding: 0.125rem 0.5rem;\n border-radius: 6px;\n font-size: 0.7rem;\n font-family: 'JetBrains Mono', monospace;\n color: var(--text-muted);\n }\n\n /* Sidebar Footer */\n .sidebar-footer {\n padding: 1rem 1.5rem;\n border-top: 1px solid var(--border);\n }\n\n .docs-link {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem;\n background: linear-gradient(135deg, rgba(168, 85, 247, 0.1), rgba(236, 72, 153, 0.1));\n border: 1px solid rgba(168, 85, 247, 0.2);\n border-radius: 10px;\n color: var(--accent);\n text-decoration: none;\n font-size: 0.875rem;\n font-weight: 500;\n transition: all 0.2s;\n }\n\n .docs-link:hover {\n background: linear-gradient(135deg, rgba(168, 85, 247, 0.2), rgba(236, 72, 153, 0.2));\n transform: translateY(-1px);\n }\n\n /* Main Content */\n .main {\n margin-left: 280px;\n flex: 1;\n padding: 2rem;\n min-height: 100vh;\n }\n\n .page-header {\n margin-bottom: 2rem;\n }\n\n .page-title {\n font-size: 1.75rem;\n font-weight: 700;\n margin-bottom: 0.5rem;\n }\n\n .page-subtitle {\n color: var(--text-secondary);\n font-size: 0.9rem;\n }\n\n /* Metrics Grid */\n .metrics-grid {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 1rem;\n margin-bottom: 2rem;\n }\n\n .metric-card {\n background: var(--bg-card);\n border: 1px solid var(--border-subtle);\n border-radius: 16px;\n padding: 1.5rem;\n transition: all 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .metric-card::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 2px;\n background: linear-gradient(90deg, var(--accent), #ec4899);\n opacity: 0;\n transition: opacity 0.3s;\n }\n\n .metric-card:hover {\n border-color: var(--accent);\n transform: translateY(-2px);\n box-shadow: 0 8px 32px rgba(168, 85, 247, 0.1);\n }\n\n .metric-card:hover::before {\n opacity: 1;\n }\n\n .metric-icon {\n font-size: 1.5rem;\n margin-bottom: 1rem;\n }\n\n .metric-value {\n font-size: 2rem;\n font-weight: 700;\n font-family: 'JetBrains Mono', monospace;\n margin-bottom: 0.25rem;\n }\n\n .metric-label {\n font-size: 0.8rem;\n color: var(--text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n .metric-change {\n position: absolute;\n top: 1rem;\n right: 1rem;\n font-size: 0.75rem;\n padding: 0.25rem 0.5rem;\n border-radius: 6px;\n font-weight: 500;\n }\n\n .metric-change.up { background: rgba(34, 197, 94, 0.1); color: var(--success); }\n .metric-change.down { background: rgba(239, 68, 68, 0.1); color: var(--error); }\n\n /* Sections */\n .content-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1.5rem;\n }\n\n .section {\n background: var(--bg-card);\n border: 1px solid var(--border-subtle);\n border-radius: 16px;\n overflow: hidden;\n }\n\n .section.full-width {\n grid-column: 1 / -1;\n }\n\n .section-header {\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .section-title {\n font-size: 1rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n\n .section-badge {\n background: var(--bg-dark);\n padding: 0.25rem 0.75rem;\n border-radius: 8px;\n font-size: 0.75rem;\n color: var(--text-muted);\n font-family: 'JetBrains Mono', monospace;\n }\n\n .section-content {\n max-height: 400px;\n overflow-y: auto;\n }\n\n /* Routes List */\n .route-item {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 1rem 1.5rem;\n border-bottom: 1px solid var(--border-subtle);\n transition: background 0.2s;\n }\n\n .route-item:last-child {\n border-bottom: none;\n }\n\n .route-item:hover {\n background: var(--bg-card-hover);\n }\n\n .route-type {\n padding: 0.25rem 0.75rem;\n border-radius: 6px;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n min-width: 60px;\n text-align: center;\n }\n\n .route-type.page { background: rgba(59, 130, 246, 0.15); color: #60a5fa; }\n .route-type.api { background: rgba(34, 197, 94, 0.15); color: #4ade80; }\n .route-type.layout { background: rgba(168, 85, 247, 0.15); color: #c084fc; }\n\n .route-path {\n font-family: 'JetBrains Mono', monospace;\n font-size: 0.875rem;\n flex: 1;\n }\n\n .route-file {\n color: var(--text-muted);\n font-size: 0.75rem;\n font-family: 'JetBrains Mono', monospace;\n }\n\n /* Request Logs */\n .log-item {\n display: flex;\n align-items: center;\n gap: 1rem;\n padding: 0.875rem 1.5rem;\n border-bottom: 1px solid var(--border-subtle);\n font-size: 0.875rem;\n transition: background 0.2s;\n }\n\n .log-item:hover {\n background: var(--bg-card-hover);\n }\n\n .log-method {\n font-weight: 600;\n padding: 0.25rem 0.5rem;\n border-radius: 4px;\n font-size: 0.7rem;\n min-width: 50px;\n text-align: center;\n font-family: 'JetBrains Mono', monospace;\n }\n\n .log-method.GET { background: rgba(59, 130, 246, 0.15); color: #60a5fa; }\n .log-method.POST { background: rgba(34, 197, 94, 0.15); color: #4ade80; }\n .log-method.PUT { background: rgba(245, 158, 11, 0.15); color: #fbbf24; }\n .log-method.DELETE { background: rgba(239, 68, 68, 0.15); color: #f87171; }\n\n .log-status {\n font-weight: 600;\n font-family: 'JetBrains Mono', monospace;\n font-size: 0.8rem;\n }\n\n .log-status.s2xx { color: var(--success); }\n .log-status.s3xx { color: #60a5fa; }\n .log-status.s4xx { color: var(--warning); }\n .log-status.s5xx { color: var(--error); }\n\n .log-path {\n font-family: 'JetBrains Mono', monospace;\n flex: 1;\n color: var(--text-secondary);\n }\n\n .log-duration {\n font-family: 'JetBrains Mono', monospace;\n color: var(--text-muted);\n font-size: 0.8rem;\n }\n\n .log-time {\n color: var(--text-muted);\n font-size: 0.75rem;\n }\n\n /* Empty State */\n .empty-state {\n text-align: center;\n padding: 3rem;\n color: var(--text-muted);\n }\n\n .empty-icon {\n font-size: 2.5rem;\n margin-bottom: 1rem;\n opacity: 0.5;\n }\n\n /* Scrollbar */\n ::-webkit-scrollbar { width: 6px; }\n ::-webkit-scrollbar-track { background: transparent; }\n ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }\n ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }\n\n /* Responsive */\n @media (max-width: 1200px) {\n .metrics-grid { grid-template-columns: repeat(2, 1fr); }\n .content-grid { grid-template-columns: 1fr; }\n }\n </style>\n</head>\n<body>\n <!-- Sidebar -->\n <aside class=\"sidebar\">\n <div class=\"sidebar-header\">\n <div class=\"logo\">\n <div class=\"logo-icon\">β‘</div>\n <div class=\"logo-text\">\n <span class=\"logo-title\">Float.js</span>\n <span class=\"logo-version\">v2.0.4</span>\n </div>\n </div>\n </div>\n\n <div class=\"status-section\">\n <div class=\"status-grid\">\n <div class=\"status-item\">\n <span class=\"status-label\">\n <span class=\"status-dot green\"></span>\n Estado\n </span>\n <span class=\"status-value connected\">Conectado</span>\n </div>\n <div class=\"status-item\">\n <span class=\"status-label\">\n <span class=\"status-dot purple\"></span>\n HMR\n </span>\n <span class=\"status-value active\">Activo</span>\n </div>\n <div class=\"status-item\">\n <span class=\"status-label\">Γltimo build</span>\n <span class=\"status-value\">${lastBuildTime}</span>\n </div>\n <div class=\"status-item\">\n <span class=\"status-label\">Uptime</span>\n <span class=\"status-value\">${uptimeFormatted}</span>\n </div>\n </div>\n </div>\n\n <nav class=\"nav-section\">\n <div class=\"nav-label\">Dashboard</div>\n <div class=\"nav-item active\">\n <span class=\"nav-icon\">π</span>\n Overview\n </div>\n <div class=\"nav-item\">\n <span class=\"nav-icon\">π€οΈ</span>\n Routes\n <span class=\"nav-badge\">${state.routes.length}</span>\n </div>\n <div class=\"nav-item\">\n <span class=\"nav-icon\">π</span>\n Logs\n <span class=\"nav-badge\">${state.requestLogs.length}</span>\n </div>\n <div class=\"nav-item\">\n <span class=\"nav-icon\">βοΈ</span>\n Settings\n </div>\n </nav>\n\n <div class=\"sidebar-footer\">\n <a href=\"https://floatjs.dev/docs\" target=\"_blank\" class=\"docs-link\">\n <span>π</span>\n Documentation\n </a>\n </div>\n </aside>\n\n <!-- Main Content -->\n <main class=\"main\">\n <div class=\"page-header\">\n <h1 class=\"page-title\">Dev Dashboard</h1>\n <p class=\"page-subtitle\">Monitor your Float.js application in real-time</p>\n </div>\n\n <!-- Metrics -->\n <div class=\"metrics-grid\">\n <div class=\"metric-card\">\n <div class=\"metric-icon\">π‘</div>\n <div class=\"metric-value\">${metrics.requests}</div>\n <div class=\"metric-label\">Total Requests</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-icon\">β‘</div>\n <div class=\"metric-value\">${metrics.avgResponseTime}ms</div>\n <div class=\"metric-label\">Avg Response</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-icon\">πΎ</div>\n <div class=\"metric-value\">${memoryMB}/${memoryTotal}</div>\n <div class=\"metric-label\">Memory (MB)</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-icon\">${metrics.errorRate > 0 ? 'β οΈ' : 'β
'}</div>\n <div class=\"metric-value\">${metrics.errorRate}%</div>\n <div class=\"metric-label\">Error Rate</div>\n </div>\n </div>\n\n <!-- Content Grid -->\n <div class=\"content-grid\">\n <!-- Routes -->\n <div class=\"section\">\n <div class=\"section-header\">\n <span class=\"section-title\">π€οΈ Routes</span>\n <span class=\"section-badge\">${state.routes.length} registered</span>\n </div>\n <div class=\"section-content\">\n ${state.routes.length === 0 ? `\n <div class=\"empty-state\">\n <div class=\"empty-icon\">π€οΈ</div>\n <p>No routes registered</p>\n </div>\n ` : state.routes.map(route => `\n <div class=\"route-item\">\n <span class=\"route-type ${route.type}\">${route.type}</span>\n <span class=\"route-path\">${route.path}</span>\n <span class=\"route-file\">${route.file.split('/').pop()}</span>\n </div>\n `).join('')}\n </div>\n </div>\n\n <!-- Request Logs -->\n <div class=\"section\">\n <div class=\"section-header\">\n <span class=\"section-title\">π Request Logs</span>\n <span class=\"section-badge\">Live</span>\n </div>\n <div class=\"section-content\">\n ${state.requestLogs.length === 0 ? `\n <div class=\"empty-state\">\n <div class=\"empty-icon\">π</div>\n <p>No requests yet</p>\n </div>\n ` : state.requestLogs.slice(0, 20).map(log => {\n const statusClass = log.status < 300 ? 's2xx' : log.status < 400 ? 's3xx' : log.status < 500 ? 's4xx' : 's5xx';\n return `\n <div class=\"log-item\">\n <span class=\"log-method ${log.method}\">${log.method}</span>\n <span class=\"log-status ${statusClass}\">${log.status}</span>\n <span class=\"log-path\">${log.path}</span>\n <span class=\"log-duration\">${log.duration}ms</span>\n </div>\n `;\n }).join('')}\n </div>\n </div>\n </div>\n </main>\n\n <script>\n // Auto-refresh every 3 seconds\n setTimeout(() => location.reload(), 3000);\n </script>\n</body>\n</html>`;\n}\n\n// ============================================================================\n// DASHBOARD API\n// ============================================================================\n\nfunction generateAPIResponse(state: DevDashboardState): string {\n return JSON.stringify({\n metrics: state.getMetrics(),\n routes: state.routes,\n builds: state.builds.slice(0, 10),\n requestLogs: state.requestLogs.slice(0, 50),\n });\n}\n\n// ============================================================================\n// DASHBOARD HANDLER\n// ============================================================================\n\nexport function createDevDashboard(options: DevDashboardOptions = {}) {\n const {\n enabled = process.env.NODE_ENV !== 'production',\n path = '/__float',\n auth,\n } = options;\n\n if (!enabled) {\n return (_req: IncomingMessage, _res: ServerResponse, next: () => void) => next();\n }\n\n return (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n const url = req.url || '';\n \n // Check if this is a dashboard request\n if (!url.startsWith(path)) {\n return next();\n }\n\n // Basic auth if configured\n if (auth) {\n const authHeader = req.headers.authorization;\n if (!authHeader || !authHeader.startsWith('Basic ')) {\n res.setHeader('WWW-Authenticate', 'Basic realm=\"Float.js Dev Dashboard\"');\n res.statusCode = 401;\n res.end('Unauthorized');\n return;\n }\n\n const credentials = Buffer.from(authHeader.slice(6), 'base64').toString();\n const [username, password] = credentials.split(':');\n \n if (username !== auth.username || password !== auth.password) {\n res.statusCode = 401;\n res.end('Invalid credentials');\n return;\n }\n }\n\n // Route dashboard requests\n const subPath = url.slice(path.length);\n\n if (subPath === '' || subPath === '/') {\n // Main dashboard\n res.setHeader('Content-Type', 'text/html');\n res.end(generateDashboardHTML(dashboardState));\n return;\n }\n\n if (subPath === '/api' || subPath === '/api/') {\n // API endpoint\n res.setHeader('Content-Type', 'application/json');\n res.end(generateAPIResponse(dashboardState));\n return;\n }\n\n if (subPath === '/api/routes') {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(dashboardState.routes));\n return;\n }\n\n if (subPath === '/api/metrics') {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(dashboardState.getMetrics()));\n return;\n }\n\n if (subPath === '/api/logs') {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(dashboardState.requestLogs.slice(0, 100)));\n return;\n }\n\n if (subPath === '/api/clear' && req.method === 'POST') {\n dashboardState.clear();\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ success: true }));\n return;\n }\n\n // 404 for unknown dashboard routes\n res.statusCode = 404;\n res.end('Not found');\n };\n}\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport const devtools = {\n dashboard: createDevDashboard,\n logger: createRequestLogger,\n state: dashboardState,\n \n // Helpers for manual logging\n logRoute: (route: RouteInfo) => dashboardState.addRoute(route),\n logBuild: (build: BuildInfo) => dashboardState.addBuild(build),\n logRequest: (log: RequestLog) => dashboardState.logRequest(log),\n getMetrics: () => dashboardState.getMetrics(),\n clear: () => dashboardState.clear(),\n};\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":[]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -566,7 +566,7 @@ function generateDashboardHTML(state) {
|
|
|
566
566
|
<div class="logo-icon">\u26A1</div>
|
|
567
567
|
<div class="logo-text">
|
|
568
568
|
<span class="logo-title">Float.js</span>
|
|
569
|
-
<span class="logo-version">v2.0.
|
|
569
|
+
<span class="logo-version">v2.0.4</span>
|
|
570
570
|
</div>
|
|
571
571
|
</div>
|
|
572
572
|
</div>
|
|
@@ -869,7 +869,7 @@ init_esm_shims();
|
|
|
869
869
|
|
|
870
870
|
// src/version.ts
|
|
871
871
|
init_esm_shims();
|
|
872
|
-
var VERSION = "2.0.
|
|
872
|
+
var VERSION = "2.0.4";
|
|
873
873
|
|
|
874
874
|
// src/router/index.ts
|
|
875
875
|
init_esm_shims();
|
|
@@ -1332,7 +1332,7 @@ var FLOAT_INDICATOR_SCRIPT = `
|
|
|
1332
1332
|
|
|
1333
1333
|
var indicator = document.createElement('div');
|
|
1334
1334
|
indicator.id = '__float-dev-indicator';
|
|
1335
|
-
indicator.innerHTML = '<div class="float-btn" id="float-btn"><svg width="16" height="16" viewBox="0 0 200 200" fill="none"><path d="M50 145C50 136.716 56.7157 130 65 130H105C113.284 130 120 136.716 120 145C120 153.284 113.284 160 105 160H65C56.7157 160 50 153.284 50 145Z" fill="#3B82F6"/><path d="M50 100C50 91.7157 56.7157 85 65 85H135C143.284 85 150 91.7157 150 100C150 108.284 143.284 115 135 115H65C56.7157 115 50 108.284 50 100Z" fill="#6366F1"/><path d="M50 55C50 46.7157 56.7157 40 65 40H155C163.284 40 170 46.7157 170 55C170 63.2843 163.284 70 155 70H65C56.7157 70 50 63.2843 50 55Z" fill="#8B5CF6"/></svg><span class="float-dot" id="float-dot"></span></div><div class="float-panel" id="float-panel"><div class="float-panel-header"><svg width="20" height="20" viewBox="0 0 200 200" fill="none"><path d="M50 145C50 136.716 56.7157 130 65 130H105C113.284 130 120 136.716 120 145C120 153.284 113.284 160 105 160H65C56.7157 160 50 153.284 50 145Z" fill="#3B82F6"/><path d="M50 100C50 91.7157 56.7157 85 65 85H135C143.284 85 150 91.7157 150 100C150 108.284 143.284 115 135 115H65C56.7157 115 50 108.284 50 100Z" fill="#6366F1"/><path d="M50 55C50 46.7157 56.7157 40 65 40H155C163.284 40 170 46.7157 170 55C170 63.2843 163.284 70 155 70H65C56.7157 70 50 63.2843 50 55Z" fill="#8B5CF6"/></svg><span>Float.js</span><span class="float-version">v2.0.
|
|
1335
|
+
indicator.innerHTML = '<div class="float-btn" id="float-btn"><svg width="16" height="16" viewBox="0 0 200 200" fill="none"><path d="M50 145C50 136.716 56.7157 130 65 130H105C113.284 130 120 136.716 120 145C120 153.284 113.284 160 105 160H65C56.7157 160 50 153.284 50 145Z" fill="#3B82F6"/><path d="M50 100C50 91.7157 56.7157 85 65 85H135C143.284 85 150 91.7157 150 100C150 108.284 143.284 115 135 115H65C56.7157 115 50 108.284 50 100Z" fill="#6366F1"/><path d="M50 55C50 46.7157 56.7157 40 65 40H155C163.284 40 170 46.7157 170 55C170 63.2843 163.284 70 155 70H65C56.7157 70 50 63.2843 50 55Z" fill="#8B5CF6"/></svg><span class="float-dot" id="float-dot"></span></div><div class="float-panel" id="float-panel"><div class="float-panel-header"><svg width="20" height="20" viewBox="0 0 200 200" fill="none"><path d="M50 145C50 136.716 56.7157 130 65 130H105C113.284 130 120 136.716 120 145C120 153.284 113.284 160 105 160H65C56.7157 160 50 153.284 50 145Z" fill="#3B82F6"/><path d="M50 100C50 91.7157 56.7157 85 65 85H135C143.284 85 150 91.7157 150 100C150 108.284 143.284 115 135 115H65C56.7157 115 50 108.284 50 100Z" fill="#6366F1"/><path d="M50 55C50 46.7157 56.7157 40 65 40H155C163.284 40 170 46.7157 170 55C170 63.2843 163.284 70 155 70H65C56.7157 70 50 63.2843 50 55Z" fill="#8B5CF6"/></svg><span>Float.js</span><span class="float-version">v2.0.4</span></div><div class="float-panel-body"><div class="float-row"><span class="float-label">Estado</span><span class="float-value" id="float-state">Conectando...</span></div><div class="float-row"><span class="float-label">HMR</span><span class="float-value" id="float-hmr">\u2014</span></div><div class="float-row"><span class="float-label">Build</span><span class="float-value" id="float-build">\u2014</span></div></div><div class="float-panel-footer"><a href="/__float" class="float-link">Dashboard</a><a href="https://floatjs.dev/docs" target="_blank" class="float-link">Docs</a></div></div>';
|
|
1336
1336
|
|
|
1337
1337
|
var styles = document.createElement('style');
|
|
1338
1338
|
styles.textContent = '#__float-dev-indicator{position:fixed;bottom:16px;left:16px;z-index:99999;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:13px}.float-btn{display:flex;align-items:center;gap:6px;padding:8px 10px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;box-shadow:0 1px 2px rgba(0,0,0,0.05);cursor:pointer;transition:all 0.15s}.float-btn:hover{border-color:#d1d5db;box-shadow:0 2px 8px rgba(0,0,0,0.08)}.float-dot{width:8px;height:8px;border-radius:50%;background:#d1d5db;transition:background 0.2s}.float-dot.connected{background:#22c55e}.float-dot.error{background:#ef4444}.float-dot.building{background:#eab308;animation:blink 0.8s infinite}@keyframes blink{0%,100%{opacity:1}50%{opacity:0.4}}.float-panel{position:absolute;bottom:48px;left:0;width:240px;background:#fff;border:1px solid #e5e7eb;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.1);opacity:0;visibility:hidden;transform:translateY(8px);transition:all 0.2s ease}.float-panel.open{opacity:1;visibility:visible;transform:translateY(0)}.float-panel-header{display:flex;align-items:center;gap:8px;padding:12px 14px;border-bottom:1px solid #f3f4f6;font-weight:600;color:#111827}.float-version{margin-left:auto;font-size:11px;font-weight:400;color:#9ca3af}.float-panel-body{padding:8px 0}.float-row{display:flex;justify-content:space-between;padding:8px 14px}.float-label{color:#6b7280}.float-value{color:#111827;font-weight:500}.float-value.success{color:#16a34a}.float-value.error{color:#dc2626}.float-panel-footer{display:flex;gap:8px;padding:12px 14px;border-top:1px solid #f3f4f6}.float-link{flex:1;text-align:center;padding:8px;background:#f9fafb;border:1px solid #e5e7eb;border-radius:6px;color:#374151;text-decoration:none;font-size:12px;font-weight:500;transition:all 0.15s}.float-link:hover{background:#f3f4f6;border-color:#d1d5db}';
|
|
@@ -2241,7 +2241,7 @@ function generateWelcomePage() {
|
|
|
2241
2241
|
</div>
|
|
2242
2242
|
|
|
2243
2243
|
<div class="footer">
|
|
2244
|
-
Float.js v2.0.
|
|
2244
|
+
Float.js v2.0.4 \u2014 Made with \u26A1 for the modern web
|
|
2245
2245
|
</div>
|
|
2246
2246
|
</div>
|
|
2247
2247
|
</body>
|