fix indent
This commit is contained in:
776
index.html
776
index.html
@@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -9,213 +10,683 @@
|
||||
<script src="js/chartjs-plugin-zoom.min.js"></script>
|
||||
<script src="js/hammer.min.js"></script>
|
||||
<style>
|
||||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
:root {
|
||||
--bg:#0d0f12;--surface:#131619;--surface2:#191c21;--surface3:#1e2128;
|
||||
--border:#ffffff0f;--border2:#ffffff18;--border3:#ffffff28;
|
||||
--text:#e8eaf0;--text2:#8b8f9a;--text3:#555966;
|
||||
--accent:#4f8ef7;--accent-dim:#4f8ef720;
|
||||
--debug:#555966;--info:#4f8ef7;--warn:#f5a623;--error:#e8504a;--fatal:#c72b2b;
|
||||
--debug-bg:#55596610;--info-bg:#4f8ef710;--warn-bg:#f5a62310;--error-bg:#e8504a10;--fatal-bg:#c72b2b18;
|
||||
--radius:6px;--radius-lg:10px;
|
||||
--bg: #0d0f12;
|
||||
--surface: #131619;
|
||||
--surface2: #191c21;
|
||||
--surface3: #1e2128;
|
||||
--border: #ffffff0f;
|
||||
--border2: #ffffff18;
|
||||
--border3: #ffffff28;
|
||||
--text: #e8eaf0;
|
||||
--text2: #8b8f9a;
|
||||
--text3: #555966;
|
||||
--accent: #4f8ef7;
|
||||
--accent-dim: #4f8ef720;
|
||||
--trace: #818594;
|
||||
--debug: #555966;
|
||||
--info: #4f8ef7;
|
||||
--warn: #f5a623;
|
||||
--error: #e8504a;
|
||||
--fatal: #c72b2b;
|
||||
--trace-bg: #55596610;
|
||||
--debug-bg: #55596610;
|
||||
--info-bg: #4f8ef710;
|
||||
--warn-bg: #f5a62310;
|
||||
--error-bg: #e8504a10;
|
||||
--fatal-bg: #c72b2b18;
|
||||
--radius: 6px;
|
||||
--radius-lg: 10px;
|
||||
--font-mono: 'JetBrains Mono', monospace;
|
||||
--font-sans: 'DM Sans', sans-serif;
|
||||
}
|
||||
html,body{height:100%;overflow:hidden}
|
||||
body{background:var(--bg);color:var(--text);font-family:var(--font-sans);font-size:13px;display:flex;flex-direction:column}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: var(--font-sans);
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
flex-direction: column
|
||||
}
|
||||
|
||||
/* Drop overlay */
|
||||
#drop-overlay {
|
||||
position:fixed;inset:0;z-index:9999;
|
||||
background:#0d0f12f0;backdrop-filter:blur(8px);
|
||||
display:none;align-items:center;justify-content:center;
|
||||
flex-direction:column;gap:20px;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9999;
|
||||
background: #0d0f12f0;
|
||||
backdrop-filter: blur(8px);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
border: 2px dashed var(--accent);
|
||||
pointer-events: none;
|
||||
}
|
||||
#drop-overlay.active{display:flex;pointer-events:all}
|
||||
#drop-overlay .drop-icon{width:64px;height:64px;opacity:.6;animation:pulse 1.4s ease-in-out infinite}
|
||||
@keyframes pulse{0%,100%{transform:scale(1);opacity:.6}50%{transform:scale(1.08);opacity:1}}
|
||||
#drop-overlay .drop-label{font-size:18px;font-weight:500;color:var(--text);letter-spacing:.01em}
|
||||
#drop-overlay .drop-sub{font-size:13px;color:var(--text2)}
|
||||
|
||||
#drop-overlay.active {
|
||||
display: flex;
|
||||
pointer-events: all
|
||||
}
|
||||
|
||||
#drop-overlay .drop-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
opacity: .6;
|
||||
animation: pulse 1.4s ease-in-out infinite
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: .6
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.08);
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
#drop-overlay .drop-label {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: var(--text);
|
||||
letter-spacing: .01em
|
||||
}
|
||||
|
||||
#drop-overlay .drop-sub {
|
||||
font-size: 13px;
|
||||
color: var(--text2)
|
||||
}
|
||||
|
||||
/* Header */
|
||||
#header {
|
||||
display:flex;align-items:center;gap:16px;
|
||||
padding:10px 20px;border-bottom:1px solid var(--border);
|
||||
background:var(--surface);flex-shrink:0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 10px 20px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
#logo{font-family:var(--font-mono);font-size:15px;font-weight:500;color:var(--text);letter-spacing:-.02em}
|
||||
#logo span{color:var(--accent)}
|
||||
#file-info{font-family:var(--font-mono);font-size:11px;color:var(--text3);flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||
|
||||
#logo {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: var(--text);
|
||||
letter-spacing: -.02em
|
||||
}
|
||||
|
||||
#logo span {
|
||||
color: var(--accent)
|
||||
}
|
||||
|
||||
#file-info {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
color: var(--text3);
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis
|
||||
}
|
||||
|
||||
#file-btn {
|
||||
display:flex;align-items:center;gap:7px;
|
||||
background:var(--surface3);border:1px solid var(--border2);border-radius:var(--radius);
|
||||
color:var(--text2);font-family:var(--font-sans);font-size:12px;font-weight:500;
|
||||
padding:6px 12px;cursor:pointer;transition:all .15s;white-space:nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
background: var(--surface3);
|
||||
border: 1px solid var(--border2);
|
||||
border-radius: var(--radius);
|
||||
color: var(--text2);
|
||||
font-family: var(--font-sans);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
transition: all .15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#file-btn:hover {
|
||||
border-color: var(--border3);
|
||||
color: var(--text);
|
||||
background: var(--surface2)
|
||||
}
|
||||
|
||||
#file-input {
|
||||
display: none
|
||||
}
|
||||
|
||||
.hdr-sep {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background: var(--border)
|
||||
}
|
||||
#file-btn:hover{border-color:var(--border3);color:var(--text);background:var(--surface2)}
|
||||
#file-input{display:none}
|
||||
.hdr-sep{width:1px;height:20px;background:var(--border)}
|
||||
|
||||
/* Filter bar */
|
||||
#filter-bar {
|
||||
display:flex;align-items:center;gap:10px;
|
||||
padding:8px 20px;border-bottom:1px solid var(--border);
|
||||
background:var(--surface);flex-shrink:0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 20px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
#search-wrap{position:relative;flex:1;max-width:420px}
|
||||
#search-wrap svg{position:absolute;left:10px;top:50%;transform:translateY(-50%);opacity:.4;pointer-events:none}
|
||||
|
||||
#search-wrap {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
max-width: 420px
|
||||
}
|
||||
|
||||
#search-wrap svg {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
opacity: .4;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
#search {
|
||||
width:100%;background:var(--surface3);border:1px solid var(--border2);border-radius:var(--radius);
|
||||
color:var(--text);font-family:var(--font-mono);font-size:12px;
|
||||
padding:6px 10px 6px 32px;outline:none;transition:border-color .15s;
|
||||
width: 100%;
|
||||
background: var(--surface3);
|
||||
border: 1px solid var(--border2);
|
||||
border-radius: var(--radius);
|
||||
color: var(--text);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
padding: 6px 10px 6px 32px;
|
||||
outline: none;
|
||||
transition: border-color .15s;
|
||||
}
|
||||
#search:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-dim)}
|
||||
#search.invalid{border-color:var(--error);box-shadow:0 0 0 3px #e8504a18}
|
||||
#search::placeholder{color:var(--text3)}
|
||||
|
||||
#search:focus {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 3px var(--accent-dim)
|
||||
}
|
||||
|
||||
#search.invalid {
|
||||
border-color: var(--error);
|
||||
box-shadow: 0 0 0 3px #e8504a18
|
||||
}
|
||||
|
||||
#search::placeholder {
|
||||
color: var(--text3)
|
||||
}
|
||||
|
||||
#regex-badge {
|
||||
position:absolute;right:8px;top:50%;transform:translateY(-50%);
|
||||
font-family:var(--font-mono);font-size:10px;padding:2px 5px;
|
||||
border-radius:3px;background:var(--accent-dim);color:var(--accent);opacity:.7;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
background: var(--accent-dim);
|
||||
color: var(--accent);
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
/* Level pills */
|
||||
.level-pills{display:flex;gap:6px;flex-wrap:wrap}
|
||||
.level-pill{
|
||||
display:flex;align-items:center;gap:6px;
|
||||
padding:5px 10px;border-radius:20px;
|
||||
border:1px solid var(--border2);
|
||||
background:transparent;cursor:pointer;font-family:var(--font-sans);font-size:11px;
|
||||
font-weight:500;color:var(--text2);transition:all .15s;white-space:nowrap;
|
||||
.level-pills {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap
|
||||
}
|
||||
|
||||
.level-pill {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 20px;
|
||||
border: 1px solid var(--border2);
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font-family: var(--font-sans);
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
color: var(--text2);
|
||||
transition: all .15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.level-pill:hover {
|
||||
border-color: var(--border3);
|
||||
color: var(--text)
|
||||
}
|
||||
|
||||
.level-pill.active {
|
||||
border-color: currentColor
|
||||
}
|
||||
|
||||
.level-pill[data-level="TRACE"] {
|
||||
--lc: var(--trace)
|
||||
}
|
||||
|
||||
.level-pill[data-level="DEBUG"] {
|
||||
--lc: var(--debug)
|
||||
}
|
||||
|
||||
.level-pill[data-level="INFO"] {
|
||||
--lc: var(--info)
|
||||
}
|
||||
|
||||
.level-pill[data-level="WARN"] {
|
||||
--lc: var(--warn)
|
||||
}
|
||||
|
||||
.level-pill[data-level="ERROR"] {
|
||||
--lc: var(--error)
|
||||
}
|
||||
|
||||
.level-pill[data-level="FATAL"] {
|
||||
--lc: var(--fatal)
|
||||
}
|
||||
|
||||
.level-pill.active {
|
||||
color: var(--lc);
|
||||
border-color: var(--lc);
|
||||
background: color-mix(in srgb, var(--lc) 10%, transparent)
|
||||
}
|
||||
|
||||
.pill-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--lc, var(--text3));
|
||||
flex-shrink: 0
|
||||
}
|
||||
|
||||
.pill-count {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
opacity: .7
|
||||
}
|
||||
|
||||
.filter-actions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-left: auto
|
||||
}
|
||||
.level-pill:hover{border-color:var(--border3);color:var(--text)}
|
||||
.level-pill.active{border-color:currentColor}
|
||||
.level-pill[data-level="DEBUG"]{--lc:var(--debug)}
|
||||
.level-pill[data-level="INFO"]{--lc:var(--info)}
|
||||
.level-pill[data-level="WARN"]{--lc:var(--warn)}
|
||||
.level-pill[data-level="ERROR"]{--lc:var(--error)}
|
||||
.level-pill[data-level="FATAL"]{--lc:var(--fatal)}
|
||||
.level-pill.active{color:var(--lc);border-color:var(--lc);background:color-mix(in srgb,var(--lc) 10%,transparent)}
|
||||
.pill-dot{width:6px;height:6px;border-radius:50%;background:var(--lc,var(--text3));flex-shrink:0}
|
||||
.pill-count{font-family:var(--font-mono);font-size:10px;opacity:.7}
|
||||
|
||||
.filter-actions{display:flex;gap:6px;margin-left:auto}
|
||||
#clear-filters {
|
||||
padding:5px 10px;border-radius:var(--radius);border:1px solid var(--border2);
|
||||
background:transparent;color:var(--text3);font-size:11px;font-family:var(--font-sans);
|
||||
cursor:pointer;transition:all .15s;
|
||||
padding: 5px 10px;
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--border2);
|
||||
background: transparent;
|
||||
color: var(--text3);
|
||||
font-size: 11px;
|
||||
font-family: var(--font-sans);
|
||||
cursor: pointer;
|
||||
transition: all .15s;
|
||||
}
|
||||
#clear-filters:hover{color:var(--text);border-color:var(--border3)}
|
||||
|
||||
#clear-filters:hover {
|
||||
color: var(--text);
|
||||
border-color: var(--border3)
|
||||
}
|
||||
|
||||
#time-badge {
|
||||
display:none;align-items:center;gap:5px;
|
||||
padding:5px 10px;border-radius:var(--radius);
|
||||
background:var(--accent-dim);border:1px solid var(--accent);
|
||||
color:var(--accent);font-size:11px;font-family:var(--font-mono);cursor:pointer;
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 5px 10px;
|
||||
border-radius: var(--radius);
|
||||
background: var(--accent-dim);
|
||||
border: 1px solid var(--accent);
|
||||
color: var(--accent);
|
||||
font-size: 11px;
|
||||
font-family: var(--font-mono);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#time-badge.visible {
|
||||
display: flex
|
||||
}
|
||||
|
||||
#time-badge:hover {
|
||||
background: #4f8ef730
|
||||
}
|
||||
|
||||
#time-badge .tx-close {
|
||||
opacity: .6;
|
||||
margin-left: 2px
|
||||
}
|
||||
#time-badge.visible{display:flex}
|
||||
#time-badge:hover{background:#4f8ef730}
|
||||
#time-badge .tx-close{opacity:.6;margin-left:2px}
|
||||
|
||||
/* Main layout */
|
||||
#main{display:flex;flex-direction:column;flex:1;overflow:hidden}
|
||||
#main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
/* Chart panel */
|
||||
#chart-panel {
|
||||
flex-shrink:0;padding:16px 20px 12px;
|
||||
flex-shrink: 0;
|
||||
padding: 16px 20px 12px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
#chart-wrap{position:relative;height:100px}
|
||||
#chart-hint{position:absolute;top:4px;right:0;font-size:10px;color:var(--text3);font-family:var(--font-mono)}
|
||||
|
||||
#chart-wrap {
|
||||
position: relative;
|
||||
height: 100px
|
||||
}
|
||||
|
||||
#chart-hint {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 0;
|
||||
font-size: 10px;
|
||||
color: var(--text3);
|
||||
font-family: var(--font-mono)
|
||||
}
|
||||
|
||||
/* Table area */
|
||||
#table-area{flex:1;overflow:hidden;display:flex;flex-direction:column}
|
||||
#table-area {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column
|
||||
}
|
||||
|
||||
/* DataTables custom styles */
|
||||
#dt-wrap{flex:1;overflow:auto;padding:0 20px 20px}
|
||||
table#log-table{width:100%;border-collapse:collapse;font-family:var(--font-mono);font-size:11.5px}
|
||||
table#log-table thead th{
|
||||
position:sticky;top:0;z-index:10;
|
||||
background:var(--surface);border-bottom:1px solid var(--border2);
|
||||
padding:10px 12px;text-align:left;font-weight:500;
|
||||
color:var(--text2);font-size:11px;letter-spacing:.05em;text-transform:uppercase;
|
||||
white-space:nowrap;cursor:pointer;user-select:none;
|
||||
#dt-wrap {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: 0 20px 20px
|
||||
}
|
||||
|
||||
table#log-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11.5px
|
||||
}
|
||||
|
||||
table#log-table thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: var(--surface);
|
||||
border-bottom: 1px solid var(--border2);
|
||||
padding: 10px 12px;
|
||||
text-align: left;
|
||||
font-weight: 500;
|
||||
color: var(--text2);
|
||||
font-size: 11px;
|
||||
letter-spacing: .05em;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
table#log-table thead th:hover {
|
||||
color: var(--text)
|
||||
}
|
||||
|
||||
table#log-table thead th.sort-asc::after {
|
||||
content: ' ↑'
|
||||
}
|
||||
|
||||
table#log-table thead th.sort-desc::after {
|
||||
content: ' ↓'
|
||||
}
|
||||
|
||||
table#log-table tbody tr {
|
||||
border-bottom: 1px solid var(--border);
|
||||
cursor: pointer;
|
||||
transition: background .1s
|
||||
}
|
||||
|
||||
table#log-table tbody tr:hover>td {
|
||||
background: var(--surface2)
|
||||
}
|
||||
|
||||
table#log-table tbody td {
|
||||
padding: 7px 12px;
|
||||
vertical-align: top
|
||||
}
|
||||
|
||||
.col-time {
|
||||
width: 180px;
|
||||
color: var(--text3);
|
||||
white-space: nowrap
|
||||
}
|
||||
|
||||
.col-level {
|
||||
width: 72px
|
||||
}
|
||||
|
||||
.col-msg {
|
||||
word-break: break-word
|
||||
}
|
||||
table#log-table thead th:hover{color:var(--text)}
|
||||
table#log-table thead th.sort-asc::after{content:' ↑'}
|
||||
table#log-table thead th.sort-desc::after{content:' ↓'}
|
||||
table#log-table tbody tr{border-bottom:1px solid var(--border);cursor:pointer;transition:background .1s}
|
||||
table#log-table tbody tr:hover>td{background:var(--surface2)}
|
||||
table#log-table tbody td{padding:7px 12px;vertical-align:top}
|
||||
.col-time{width:180px;color:var(--text3);white-space:nowrap}
|
||||
.col-level{width:72px}
|
||||
.col-msg{word-break:break-word}
|
||||
|
||||
/* Level badges */
|
||||
.lv{display:inline-block;padding:2px 7px;border-radius:3px;font-size:10px;font-weight:500;letter-spacing:.04em}
|
||||
.lv-DEBUG{background:var(--debug-bg);color:var(--debug)}
|
||||
.lv-INFO{background:var(--info-bg);color:var(--info)}
|
||||
.lv-WARN{background:var(--warn-bg);color:var(--warn)}
|
||||
.lv-ERROR{background:var(--error-bg);color:var(--error)}
|
||||
.lv-FATAL{background:var(--fatal-bg);color:var(--fatal)}
|
||||
.lv {
|
||||
display: inline-block;
|
||||
padding: 2px 7px;
|
||||
border-radius: 3px;
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
letter-spacing: .04em
|
||||
}
|
||||
|
||||
.lv-TRACE {
|
||||
background: var(--trace-bg);
|
||||
color: var(--trace)
|
||||
}
|
||||
|
||||
.lv-DEBUG {
|
||||
background: var(--debug-bg);
|
||||
color: var(--debug)
|
||||
}
|
||||
|
||||
.lv-INFO {
|
||||
background: var(--info-bg);
|
||||
color: var(--info)
|
||||
}
|
||||
|
||||
.lv-WARN {
|
||||
background: var(--warn-bg);
|
||||
color: var(--warn)
|
||||
}
|
||||
|
||||
.lv-ERROR {
|
||||
background: var(--error-bg);
|
||||
color: var(--error)
|
||||
}
|
||||
|
||||
.lv-FATAL {
|
||||
background: var(--fatal-bg);
|
||||
color: var(--fatal)
|
||||
}
|
||||
|
||||
/* Row details (expanded) */
|
||||
.row-detail{background:var(--surface2)!important;border-left:2px solid var(--accent)!important}
|
||||
.row-detail td{padding:0!important}
|
||||
.detail-inner{padding:12px 16px 16px;display:flex;flex-direction:column;gap:12px}
|
||||
.detail-section{display:flex;flex-direction:column;gap:6px}
|
||||
.detail-label{font-size:10px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--text3)}
|
||||
.row-detail {
|
||||
background: var(--surface2) !important;
|
||||
border-left: 2px solid var(--accent) !important
|
||||
}
|
||||
|
||||
.row-detail td {
|
||||
padding: 0 !important
|
||||
}
|
||||
|
||||
.detail-inner {
|
||||
padding: 12px 16px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
letter-spacing: .08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text3)
|
||||
}
|
||||
|
||||
.detail-val {
|
||||
background:var(--surface3);border:1px solid var(--border);border-radius:var(--radius);
|
||||
padding:10px 12px;font-family:var(--font-mono);font-size:11px;color:var(--text2);
|
||||
white-space:pre-wrap;word-break:break-all;max-height:200px;overflow-y:auto;
|
||||
background: var(--surface3);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 10px 12px;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
color: var(--text2);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Empty state */
|
||||
#empty-state {
|
||||
flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
|
||||
gap:16px;color:var(--text3);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
color: var(--text3);
|
||||
}
|
||||
#empty-state svg{opacity:.3}
|
||||
#empty-state .es-title{font-size:15px;font-weight:500;color:var(--text2)}
|
||||
#empty-state .es-sub{font-size:12px;text-align:center;max-width:280px;line-height:1.6}
|
||||
|
||||
#empty-state svg {
|
||||
opacity: .3
|
||||
}
|
||||
|
||||
#empty-state .es-title {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: var(--text2)
|
||||
}
|
||||
|
||||
#empty-state .es-sub {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
max-width: 280px;
|
||||
line-height: 1.6
|
||||
}
|
||||
|
||||
#empty-state .es-btn {
|
||||
margin-top:8px;padding:8px 20px;border-radius:var(--radius);
|
||||
background:var(--accent-dim);border:1px solid var(--accent);
|
||||
color:var(--accent);font-size:13px;font-family:var(--font-sans);cursor:pointer;
|
||||
margin-top: 8px;
|
||||
padding: 8px 20px;
|
||||
border-radius: var(--radius);
|
||||
background: var(--accent-dim);
|
||||
border: 1px solid var(--accent);
|
||||
color: var(--accent);
|
||||
font-size: 13px;
|
||||
font-family: var(--font-sans);
|
||||
cursor: pointer;
|
||||
transition: all .15s;
|
||||
}
|
||||
#empty-state .es-btn:hover{background:#4f8ef730}
|
||||
|
||||
#empty-state .es-btn:hover {
|
||||
background: #4f8ef730
|
||||
}
|
||||
|
||||
/* Table status bar */
|
||||
#status-bar {
|
||||
display:flex;align-items:center;gap:12px;
|
||||
padding:7px 20px;border-top:1px solid var(--border);
|
||||
background:var(--surface);flex-shrink:0;font-size:11px;color:var(--text3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 7px 20px;
|
||||
border-top: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
flex-shrink: 0;
|
||||
font-size: 11px;
|
||||
color: var(--text3);
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
#status-bar .status-count{color:var(--text2)}
|
||||
.sb-sep{color:var(--border3)}
|
||||
|
||||
#status-bar .status-count {
|
||||
color: var(--text2)
|
||||
}
|
||||
|
||||
.sb-sep {
|
||||
color: var(--border3)
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
::-webkit-scrollbar{width:6px;height:6px}
|
||||
::-webkit-scrollbar-track{background:transparent}
|
||||
::-webkit-scrollbar-thumb{background:var(--border2);border-radius:3px}
|
||||
::-webkit-scrollbar-thumb:hover{background:var(--border3)}
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--border2);
|
||||
border-radius: 3px
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--border3)
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes fadeIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}
|
||||
.fade-in{animation:fadeIn .2s ease forwards}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(4px)
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0)
|
||||
}
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fadeIn .2s ease forwards
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- Drop Overlay -->
|
||||
<div id="drop-overlay">
|
||||
<svg class="drop-icon" width="64" height="64" viewBox="0 0 64 64" fill="none">
|
||||
<rect x="8" y="8" width="48" height="48" rx="8" stroke="#4f8ef7" stroke-width="2" stroke-dasharray="6 4" />
|
||||
<path d="M32 20v24M22 34l10 10 10-10" stroke="#4f8ef7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M32 20v24M22 34l10 10 10-10" stroke="#4f8ef7" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
<div class="drop-label">Drop log file here</div>
|
||||
<div class="drop-sub">Supports .log, .txt, .json and plain text</div>
|
||||
@@ -227,7 +698,10 @@ table#log-table tbody td{padding:7px 12px;vertical-align:top}
|
||||
<div class="hdr-sep"></div>
|
||||
<div id="file-info">No file loaded — drag & drop or select a file</div>
|
||||
<button id="file-btn" onclick="document.getElementById('file-input').click()">
|
||||
<svg width="13" height="13" viewBox="0 0 16 16" fill="none"><path d="M2 12V4a1 1 0 011-1h5l2 2h3a1 1 0 011 1v6a1 1 0 01-1 1H3a1 1 0 01-1-1z" stroke="currentColor" stroke-width="1.4"/></svg>
|
||||
<svg width="13" height="13" viewBox="0 0 16 16" fill="none">
|
||||
<path d="M2 12V4a1 1 0 011-1h5l2 2h3a1 1 0 011 1v6a1 1 0 01-1 1H3a1 1 0 01-1-1z" stroke="currentColor"
|
||||
stroke-width="1.4" />
|
||||
</svg>
|
||||
Open File
|
||||
</button>
|
||||
<input type="file" id="file-input" accept=".log,.txt,.json,text/plain">
|
||||
@@ -236,21 +710,34 @@ table#log-table tbody td{padding:7px 12px;vertical-align:top}
|
||||
<!-- Filter bar -->
|
||||
<div id="filter-bar">
|
||||
<div id="search-wrap">
|
||||
<svg width="13" height="13" viewBox="0 0 16 16" fill="none"><circle cx="6.5" cy="6.5" r="4.5" stroke="currentColor" stroke-width="1.4"/><path d="M10.5 10.5L14 14" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
|
||||
<svg width="13" height="13" viewBox="0 0 16 16" fill="none">
|
||||
<circle cx="6.5" cy="6.5" r="4.5" stroke="currentColor" stroke-width="1.4" />
|
||||
<path d="M10.5 10.5L14 14" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" />
|
||||
</svg>
|
||||
<input type="text" id="search" placeholder="Filter messages… (regex supported)" autocomplete="off">
|
||||
<span id="regex-badge">.*</span>
|
||||
</div>
|
||||
<div class="hdr-sep"></div>
|
||||
<div class="level-pills" id="level-pills">
|
||||
<button class="level-pill" data-level="DEBUG"><span class="pill-dot"></span>Debug<span class="pill-count" id="cnt-DEBUG">0</span></button>
|
||||
<button class="level-pill" data-level="INFO"><span class="pill-dot"></span>Info<span class="pill-count" id="cnt-INFO">0</span></button>
|
||||
<button class="level-pill" data-level="WARN"><span class="pill-dot"></span>Warn<span class="pill-count" id="cnt-WARN">0</span></button>
|
||||
<button class="level-pill" data-level="ERROR"><span class="pill-dot"></span>Error<span class="pill-count" id="cnt-ERROR">0</span></button>
|
||||
<button class="level-pill" data-level="FATAL"><span class="pill-dot"></span>Fatal<span class="pill-count" id="cnt-FATAL">0</span></button>
|
||||
<button class="level-pill" data-level="TRACE"><span class="pill-dot"></span>Trace<span class="pill-count"
|
||||
id="cnt-TRACE">0</span></button>
|
||||
<button class="level-pill" data-level="DEBUG"><span class="pill-dot"></span>Debug<span class="pill-count"
|
||||
id="cnt-DEBUG">0</span></button>
|
||||
<button class="level-pill" data-level="INFO"><span class="pill-dot"></span>Info<span class="pill-count"
|
||||
id="cnt-INFO">0</span></button>
|
||||
<button class="level-pill" data-level="WARN"><span class="pill-dot"></span>Warn<span class="pill-count"
|
||||
id="cnt-WARN">0</span></button>
|
||||
<button class="level-pill" data-level="ERROR"><span class="pill-dot"></span>Error<span class="pill-count"
|
||||
id="cnt-ERROR">0</span></button>
|
||||
<button class="level-pill" data-level="FATAL"><span class="pill-dot"></span>Fatal<span class="pill-count"
|
||||
id="cnt-FATAL">0</span></button>
|
||||
</div>
|
||||
<div class="filter-actions">
|
||||
<div id="time-badge">
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.4"/><path d="M8 5v3l2 2" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none">
|
||||
<circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.4" />
|
||||
<path d="M8 5v3l2 2" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" />
|
||||
</svg>
|
||||
<span id="time-badge-label">time range</span>
|
||||
<span class="tx-close">✕</span>
|
||||
</div>
|
||||
@@ -271,7 +758,8 @@ table#log-table tbody td{padding:7px 12px;vertical-align:top}
|
||||
<!-- Empty state / Table area -->
|
||||
<div id="empty-state">
|
||||
<svg width="48" height="48" viewBox="0 0 48 48" fill="none">
|
||||
<rect x="6" y="6" width="36" height="36" rx="6" stroke="currentColor" stroke-width="1.5" stroke-dasharray="5 3"/>
|
||||
<rect x="6" y="6" width="36" height="36" rx="6" stroke="currentColor" stroke-width="1.5"
|
||||
stroke-dasharray="5 3" />
|
||||
<path d="M16 20h16M16 24h10M16 28h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
|
||||
</svg>
|
||||
<div class="es-title">No log file loaded</div>
|
||||
@@ -641,7 +1129,7 @@ function toggleDetail(tr, log, idx) {
|
||||
|
||||
// ---- Level counts ----
|
||||
function updateLevelCounts() {
|
||||
const counts = {DEBUG:0,INFO:0,WARN:0,ERROR:0,FATAL:0};
|
||||
const counts = { TRACE: 0, DEBUG: 0, INFO: 0, WARN: 0, ERROR: 0, FATAL: 0 };
|
||||
allLogs.forEach(l => { if (counts[l.level] !== undefined) counts[l.level]++; });
|
||||
Object.entries(counts).forEach(([lv, cnt]) => {
|
||||
document.getElementById('cnt-' + lv).textContent = cnt.toLocaleString();
|
||||
@@ -669,6 +1157,7 @@ function esc(s) {
|
||||
|
||||
// ---- Load file ----
|
||||
function loadFile(file) {
|
||||
//debugger
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => {
|
||||
const text = e.target.result;
|
||||
@@ -770,7 +1259,8 @@ document.addEventListener('drop', e => {
|
||||
});
|
||||
|
||||
// Load demo on start
|
||||
//loadDemo();
|
||||
loadDemo();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user