|$ curl https://forge-ai.dev/api/markdown?path=docs/components/data-display
$cat docs/data-display.md
updated Recently·12 min read·published
Data Display
◆CSS◆HTML◆UI◆Intermediate
12+ data display components — tables, progress bars, avatars, skeleton loaders, stat cards, timelines, and more.
Avatars
Avatar sizes, initials, online status, and avatar groups.
avatars
Live
untitled.html
HTML
| 1 | <div class="wrap"> |
| 2 | <div class="row"> |
| 3 | <div class="av sm" style="background:#3B82F6"> |
| 4 | JD |
| 5 | </div> |
| 6 | <div class="av md" style="background:#22C55E"> |
| 7 | AK |
| 8 | </div> |
| 9 | <div class="av lg" style="background:#EAB308"> |
| 10 | MR |
| 11 | </div> |
| 12 | <div class="av xl" style="background:#EF4444;font-size:13px"> |
| 13 | SP |
| 14 | </div> |
| 15 | </div> |
| 16 | <div class="row"> |
| 17 | <div class="av-group"> |
| 18 | <div class="av sm" style="background:#3B82F6;border:2px solid #0D0D0D"> |
| 19 | J |
| 20 | </div> |
| 21 | <div class="av sm" style="background:#22C55E;border:2px solid #0D0D0D;margin-left:-8px"> |
| 22 | A |
| 23 | </div> |
| 24 | <div class="av sm" style="background:#EAB308;border:2px solid #0D0D0D;margin-left:-8px"> |
| 25 | M |
| 26 | </div> |
| 27 | <div class="av more sm" style="margin-left:-8px"> |
| 28 | +3 |
| 29 | </div> |
| 30 | </div> |
| 31 | <div class="dot-group"> |
| 32 | <div class="av sm" style="background:#3B82F6"> |
| 33 | <span class="dot on"> |
| 34 | </span> |
| 35 | J |
| 36 | </div> |
| 37 | <div class="av sm" style="background:#22C55E"> |
| 38 | <span class="dot away"> |
| 39 | </span> |
| 40 | A |
| 41 | </div> |
| 42 | </div> |
| 43 | </div> |
| 44 | </div> |
untitled.css
CSS
| 1 | * { |
| 2 | margin:0; |
| 3 | padding:0; |
| 4 | box-sizing:border-box |
| 5 | } |
| 6 | body { |
| 7 | font-family:system-ui, |
| 8 | sans-serif; |
| 9 | background:#0D0D0D; |
| 10 | padding:24px |
| 11 | } |
| 12 | .wrap { |
| 13 | display:flex; |
| 14 | flex-direction:column; |
| 15 | gap:20px; |
| 16 | padding:20px; |
| 17 | align-items:center |
| 18 | } |
| 19 | .row { |
| 20 | display:flex; |
| 21 | align-items:center; |
| 22 | gap:12px |
| 23 | } |
| 24 | .av { |
| 25 | display:inline-flex; |
| 26 | align-items:center; |
| 27 | justify-content:center; |
| 28 | border-radius:50%; |
| 29 | font-weight:700; |
| 30 | color:#fff; |
| 31 | position:relative |
| 32 | } |
| 33 | .sm { |
| 34 | width:32px; |
| 35 | height:32px; |
| 36 | font-size:11px |
| 37 | } |
| 38 | .md { |
| 39 | width:40px; |
| 40 | height:40px; |
| 41 | font-size:14px |
| 42 | } |
| 43 | .lg { |
| 44 | width:52px; |
| 45 | height:52px; |
| 46 | font-size:18px |
| 47 | } |
| 48 | .xl { |
| 49 | width:64px; |
| 50 | height:64px; |
| 51 | font-size:22px |
| 52 | } |
| 53 | .av-group { |
| 54 | display:flex |
| 55 | } |
| 56 | .more { |
| 57 | background:#1A1A2E!important; |
| 58 | color:#808080!important; |
| 59 | border:2px solid #0D0D0D; |
| 60 | font-size:10px |
| 61 | } |
| 62 | .dot { |
| 63 | position:absolute; |
| 64 | bottom:0; |
| 65 | right:0; |
| 66 | width:10px; |
| 67 | height:10px; |
| 68 | border-radius:50%; |
| 69 | border:2px solid #0D0D0D |
| 70 | } |
| 71 | .dot.on { |
| 72 | background:#22C55E |
| 73 | } |
| 74 | .dot.away { |
| 75 | background:#EAB308 |
| 76 | } |
| 77 | .dot-group { |
| 78 | display:flex; |
| 79 | gap:4px |
| 80 | } |
Progress Bars
Progress bar variants, sizes, with labels, and animated.
progress
Live
untitled.html
HTML
| 1 | <div class="wrap"> |
| 2 | <div class="p-group"> |
| 3 | <span class="p-label"> |
| 4 | Storage |
| 5 | </span> |
| 6 | <div class="p-bar"> |
| 7 | <div class="p-fill" style="width:65%"> |
| 8 | </div> |
| 9 | </div> |
| 10 | <span class="p-val"> |
| 11 | 65% |
| 12 | </span> |
| 13 | </div> |
| 14 | <div class="p-group"> |
| 15 | <span class="p-label"> |
| 16 | CPU |
| 17 | </span> |
| 18 | <div class="p-bar green"> |
| 19 | <div class="p-fill" style="width:80%"> |
| 20 | </div> |
| 21 | </div> |
| 22 | <span class="p-val"> |
| 23 | 80% |
| 24 | </span> |
| 25 | </div> |
| 26 | <div class="p-group"> |
| 27 | <span class="p-label"> |
| 28 | Memory |
| 29 | </span> |
| 30 | <div class="p-bar sm"> |
| 31 | <div class="p-fill" style="width:45%"> |
| 32 | </div> |
| 33 | </div> |
| 34 | <span class="p-val"> |
| 35 | 45% |
| 36 | </span> |
| 37 | </div> |
| 38 | <div class="p-group"> |
| 39 | <span class="p-label"> |
| 40 | Network |
| 41 | </span> |
| 42 | <div class="p-bar"> |
| 43 | <div class="p-fill stripes" style="width:90%"> |
| 44 | </div> |
| 45 | </div> |
| 46 | <span class="p-val"> |
| 47 | 90% |
| 48 | </span> |
| 49 | </div> |
| 50 | </div> |
untitled.css
CSS
| 1 | * { |
| 2 | margin:0; |
| 3 | padding:0; |
| 4 | box-sizing:border-box |
| 5 | } |
| 6 | body { |
| 7 | font-family:system-ui, |
| 8 | sans-serif; |
| 9 | background:#0D0D0D; |
| 10 | padding:24px |
| 11 | } |
| 12 | .wrap { |
| 13 | display:flex; |
| 14 | flex-direction:column; |
| 15 | gap:16px; |
| 16 | max-width:400px; |
| 17 | margin:16px auto |
| 18 | } |
| 19 | .p-group { |
| 20 | display:flex; |
| 21 | align-items:center; |
| 22 | gap:12px |
| 23 | } |
| 24 | .p-label { |
| 25 | font-size:11px; |
| 26 | color:#808080; |
| 27 | min-width:55px |
| 28 | } |
| 29 | .p-bar { |
| 30 | flex:1; |
| 31 | height:8px; |
| 32 | background:#1A1A2E; |
| 33 | border-radius:4px; |
| 34 | overflow:hidden; |
| 35 | border:1px solid #222 |
| 36 | } |
| 37 | .p-bar.sm { |
| 38 | height:4px; |
| 39 | border-radius:2px |
| 40 | } |
| 41 | .p-bar.green .p-fill { |
| 42 | background:#22C55E |
| 43 | } |
| 44 | .p-fill { |
| 45 | height:100%; |
| 46 | background:#00FF41; |
| 47 | border-radius:4px; |
| 48 | transition:width .5s ease |
| 49 | } |
| 50 | .p-fill.stripes { |
| 51 | background:repeating-linear-gradient(45deg, |
| 52 | #00FF41, |
| 53 | #00FF41 4px, |
| 54 | rgba(0, |
| 55 | 0, |
| 56 | 0, |
| 57 | .1) 4px, |
| 58 | rgba(0, |
| 59 | 0, |
| 60 | 0, |
| 61 | .1) 8px) |
| 62 | } |
| 63 | .p-val { |
| 64 | font-size:11px; |
| 65 | color:#A0A0A0; |
| 66 | font-weight:600; |
| 67 | min-width:32px; |
| 68 | text-align:right |
| 69 | } |
Skeleton Loaders
Loading placeholders for text, cards, tables, and avatars.
skeleton
Live
untitled.html
HTML
| 1 | <div class="wrap"> |
| 2 | <div class="sk-card"> |
| 3 | <div class="sk-av"> |
| 4 | </div> |
| 5 | <div class="sk-body"> |
| 6 | <div class="sk-line w-60"> |
| 7 | </div> |
| 8 | <div class="sk-line w-80"> |
| 9 | </div> |
| 10 | <div class="sk-line w-40"> |
| 11 | </div> |
| 12 | </div> |
| 13 | </div> |
| 14 | <div class="sk-card"> |
| 15 | <div class="sk-img"> |
| 16 | </div> |
| 17 | <div class="sk-body"> |
| 18 | <div class="sk-line w-70"> |
| 19 | </div> |
| 20 | <div class="sk-line w-90"> |
| 21 | </div> |
| 22 | <div class="sk-line w-50"> |
| 23 | </div> |
| 24 | <div class="sk-line w-30" style="margin-top:8px"> |
| 25 | </div> |
| 26 | </div> |
| 27 | </div> |
| 28 | </div> |
untitled.css
CSS
| 1 | * { |
| 2 | margin:0; |
| 3 | padding:0; |
| 4 | box-sizing:border-box |
| 5 | } |
| 6 | body { |
| 7 | font-family:system-ui, |
| 8 | sans-serif; |
| 9 | background:#0D0D0D; |
| 10 | padding:24px |
| 11 | } |
| 12 | .wrap { |
| 13 | display:flex; |
| 14 | flex-direction:column; |
| 15 | gap:16px; |
| 16 | max-width:360px; |
| 17 | margin:16px auto |
| 18 | } |
| 19 | @keyframes shimmer { |
| 20 | 0% { |
| 21 | background-position:-200px 0 |
| 22 | } |
| 23 | 100% { |
| 24 | background-position:calc(200px + 100%) 0 |
| 25 | } |
| 26 | } |
| 27 | .sk-card { |
| 28 | display:flex; |
| 29 | gap:12px; |
| 30 | padding:14px; |
| 31 | border-radius:8px; |
| 32 | border:1px solid #222; |
| 33 | background:#0F0F0F |
| 34 | } |
| 35 | .sk-av { |
| 36 | width:40px; |
| 37 | height:40px; |
| 38 | border-radius:50%; |
| 39 | background:linear-gradient(90deg, |
| 40 | #1A1A2E 25%, |
| 41 | #22223A 50%, |
| 42 | #1A1A2E 75%); |
| 43 | background-size:200px 100%; |
| 44 | animation:shimmer 1.5s infinite |
| 45 | } |
| 46 | .sk-img { |
| 47 | width:80px; |
| 48 | height:60px; |
| 49 | border-radius:6px; |
| 50 | background:linear-gradient(90deg, |
| 51 | #1A1A2E 25%, |
| 52 | #22223A 50%, |
| 53 | #1A1A2E 75%); |
| 54 | background-size:200px 100%; |
| 55 | animation:shimmer 1.5s infinite; |
| 56 | flex-shrink:0 |
| 57 | } |
| 58 | .sk-body { |
| 59 | flex:1; |
| 60 | display:flex; |
| 61 | flex-direction:column; |
| 62 | gap:8px |
| 63 | } |
| 64 | .sk-line { |
| 65 | height:10px; |
| 66 | border-radius:5px; |
| 67 | background:linear-gradient(90deg, |
| 68 | #1A1A2E 25%, |
| 69 | #22223A 50%, |
| 70 | #1A1A2E 75%); |
| 71 | background-size:200px 100%; |
| 72 | animation:shimmer 1.5s infinite |
| 73 | } |
| 74 | .w-30 { |
| 75 | width:30% |
| 76 | } |
| 77 | .w-40 { |
| 78 | width:40% |
| 79 | } |
| 80 | .w-50 { |
| 81 | width:50% |
| 82 | } |
| 83 | .w-60 { |
| 84 | width:60% |
| 85 | } |
| 86 | .w-70 { |
| 87 | width:70% |
| 88 | } |
| 89 | .w-80 { |
| 90 | width:80% |
| 91 | } |
| 92 | .w-90 { |
| 93 | width:90% |
| 94 | } |
Stat Cards
Metric display cards with labels, values, and change indicators.
stats
Live
untitled.html
HTML
| 1 | <div class="grid"> |
| 2 | <div class="stat"> |
| 3 | <span class="stat-label"> |
| 4 | Revenue |
| 5 | </span> |
| 6 | <span class="stat-val"> |
| 7 | $12,430 |
| 8 | </span> |
| 9 | <span class="stat-chg up"> |
| 10 | ↑ 12.5% |
| 11 | </span> |
| 12 | </div> |
| 13 | <div class="stat"> |
| 14 | <span class="stat-label"> |
| 15 | Users |
| 16 | </span> |
| 17 | <span class="stat-val"> |
| 18 | 1,842 |
| 19 | </span> |
| 20 | <span class="stat-chg up"> |
| 21 | ↑ 8.2% |
| 22 | </span> |
| 23 | </div> |
| 24 | <div class="stat"> |
| 25 | <span class="stat-label"> |
| 26 | Bounce Rate |
| 27 | </span> |
| 28 | <span class="stat-val"> |
| 29 | 32.1% |
| 30 | </span> |
| 31 | <span class="stat-chg down"> |
| 32 | ↓ 2.4% |
| 33 | </span> |
| 34 | </div> |
| 35 | <div class="stat"> |
| 36 | <span class="stat-label"> |
| 37 | Avg. Session |
| 38 | </span> |
| 39 | <span class="stat-val"> |
| 40 | 4m 12s |
| 41 | </span> |
| 42 | <span class="stat-chg up"> |
| 43 | ↑ 6.1% |
| 44 | </span> |
| 45 | </div> |
| 46 | </div> |
untitled.css
CSS
| 1 | * { |
| 2 | margin:0; |
| 3 | padding:0; |
| 4 | box-sizing:border-box |
| 5 | } |
| 6 | body { |
| 7 | font-family:system-ui, |
| 8 | sans-serif; |
| 9 | background:#0D0D0D; |
| 10 | padding:24px |
| 11 | } |
| 12 | .grid { |
| 13 | display:grid; |
| 14 | grid-template-columns:1fr 1fr; |
| 15 | gap:12px; |
| 16 | max-width:420px; |
| 17 | margin:16px auto |
| 18 | } |
| 19 | .stat { |
| 20 | background:#0F0F0F; |
| 21 | border:1px solid #222; |
| 22 | border-radius:10px; |
| 23 | padding:16px |
| 24 | } |
| 25 | .stat-label { |
| 26 | display:block; |
| 27 | font-size:10px; |
| 28 | color:#808080; |
| 29 | text-transform:uppercase; |
| 30 | letter-spacing:1px; |
| 31 | margin-bottom:6px |
| 32 | } |
| 33 | .stat-val { |
| 34 | display:block; |
| 35 | font-size:22px; |
| 36 | font-weight:700; |
| 37 | color:#E0E0E0; |
| 38 | margin-bottom:4px |
| 39 | } |
| 40 | .stat-chg { |
| 41 | font-size:11px; |
| 42 | font-weight:600 |
| 43 | } |
| 44 | .up { |
| 45 | color:#22C55E |
| 46 | } |
| 47 | .down { |
| 48 | color:#EF4444 |
| 49 | } |
Table
Clean data table with header, rows, and hover states.
table
Live
untitled.html
HTML
| 1 | <table class="table"> |
| 2 | <thead> |
| 3 | <tr> |
| 4 | <th data-sort> |
| 5 | Name |
| 6 | </th> |
| 7 | <th data-sort> |
| 8 | Role |
| 9 | </th> |
| 10 | <th data-sort> |
| 11 | Status |
| 12 | </th> |
| 13 | <th style="text-align:right"> |
| 14 | Actions |
| 15 | </th> |
| 16 | </tr> |
| 17 | </thead> |
| 18 | <tbody> |
| 19 | <tr> |
| 20 | <td> |
| 21 | John Doe |
| 22 | </td> |
| 23 | <td> |
| 24 | Developer |
| 25 | </td> |
| 26 | <td> |
| 27 | <span class="t-badge active"> |
| 28 | Active |
| 29 | </span> |
| 30 | </td> |
| 31 | <td style="text-align:right"> |
| 32 | <button class="t-btn"> |
| 33 | Edit |
| 34 | </button> |
| 35 | </td> |
| 36 | </tr> |
| 37 | <tr> |
| 38 | <td> |
| 39 | Jane Smith |
| 40 | </td> |
| 41 | <td> |
| 42 | Designer |
| 43 | </td> |
| 44 | <td> |
| 45 | <span class="t-badge away"> |
| 46 | Away |
| 47 | </span> |
| 48 | </td> |
| 49 | <td style="text-align:right"> |
| 50 | <button class="t-btn"> |
| 51 | Edit |
| 52 | </button> |
| 53 | </td> |
| 54 | </tr> |
| 55 | <tr> |
| 56 | <td> |
| 57 | Sam Wilson |
| 58 | </td> |
| 59 | <td> |
| 60 | Manager |
| 61 | </td> |
| 62 | <td> |
| 63 | <span class="t-badge off"> |
| 64 | Offline |
| 65 | </span> |
| 66 | </td> |
| 67 | <td style="text-align:right"> |
| 68 | <button class="t-btn"> |
| 69 | Edit |
| 70 | </button> |
| 71 | </td> |
| 72 | </tr> |
| 73 | <tr> |
| 74 | <td> |
| 75 | Lisa Ray |
| 76 | </td> |
| 77 | <td> |
| 78 | Developer |
| 79 | </td> |
| 80 | <td> |
| 81 | <span class="t-badge active"> |
| 82 | Active |
| 83 | </span> |
| 84 | </td> |
| 85 | <td style="text-align:right"> |
| 86 | <button class="t-btn"> |
| 87 | Edit |
| 88 | </button> |
| 89 | </td> |
| 90 | </tr> |
| 91 | </tbody> |
| 92 | </table> |
untitled.css
CSS
| 1 | * { |
| 2 | margin:0; |
| 3 | padding:0; |
| 4 | box-sizing:border-box |
| 5 | } |
| 6 | body { |
| 7 | font-family:system-ui, |
| 8 | sans-serif; |
| 9 | background:#0D0D0D; |
| 10 | padding:24px |
| 11 | } |
| 12 | .table { |
| 13 | width:100%; |
| 14 | max-width:500px; |
| 15 | margin:16px auto; |
| 16 | border-collapse:collapse; |
| 17 | font-size:12px |
| 18 | } |
| 19 | .table th { |
| 20 | padding:10px 14px; |
| 21 | text-align:left; |
| 22 | font-size:10px; |
| 23 | font-weight:600; |
| 24 | color:#525252; |
| 25 | text-transform:uppercase; |
| 26 | letter-spacing:1px; |
| 27 | border-bottom:1px solid #222; |
| 28 | user-select:none |
| 29 | } |
| 30 | .table th[data-sort] { |
| 31 | cursor:pointer |
| 32 | } |
| 33 | .table th[data-sort]:hover { |
| 34 | color:#808080 |
| 35 | } |
| 36 | .table th[data-sort]::after { |
| 37 | content:'⇅'; |
| 38 | font-size:9px; |
| 39 | margin-left:6px; |
| 40 | opacity:.2; |
| 41 | display:inline-block |
| 42 | } |
| 43 | .table th.asc::after { |
| 44 | content:'↑'; |
| 45 | opacity:1; |
| 46 | color:#00FF41 |
| 47 | } |
| 48 | .table th.desc::after { |
| 49 | content:'↓'; |
| 50 | opacity:1; |
| 51 | color:#00FF41 |
| 52 | } |
| 53 | .table td { |
| 54 | padding:10px 14px; |
| 55 | color:#A0A0A0; |
| 56 | border-bottom:1px solid #1A1A1A |
| 57 | } |
| 58 | .table tbody tr:hover td { |
| 59 | background:rgba(255, |
| 60 | 255, |
| 61 | 255, |
| 62 | .02); |
| 63 | color:#E0E0E0 |
| 64 | } |
| 65 | .t-badge { |
| 66 | padding:2px 8px; |
| 67 | border-radius:999px; |
| 68 | font-size:10px; |
| 69 | font-weight:600 |
| 70 | } |
| 71 | .active { |
| 72 | background:rgba(34, |
| 73 | 197, |
| 74 | 94, |
| 75 | .12); |
| 76 | color:#22C55E |
| 77 | } |
| 78 | .away { |
| 79 | background:rgba(234, |
| 80 | 179, |
| 81 | 8, |
| 82 | .12); |
| 83 | color:#EAB308 |
| 84 | } |
| 85 | .off { |
| 86 | background:rgba(160, |
| 87 | 160, |
| 88 | 160, |
| 89 | .12); |
| 90 | color:#808080 |
| 91 | } |
| 92 | .t-btn { |
| 93 | padding:4px 12px; |
| 94 | border-radius:4px; |
| 95 | font-size:10px; |
| 96 | font-weight:500; |
| 97 | border:1px solid #2A2A3E; |
| 98 | background:transparent; |
| 99 | color:#808080; |
| 100 | cursor:pointer; |
| 101 | transition:all .2s; |
| 102 | font-family:inherit |
| 103 | } |
| 104 | .t-btn:hover { |
| 105 | background:#1A1A2E; |
| 106 | color:#E0E0E0 |
| 107 | } |
untitled.js
JavaScript
| 1 | document.querySelectorAll('th[data-sort]').forEach(th=>{th.addEventListener('click',()=>{const i=Array.from(th.parentElement.children).indexOf(th);const tbody=th.closest('table').querySelector('tbody');const rows=Array.from(tbody.querySelectorAll('tr'));const asc=th.classList.contains('asc')?false:!th.classList.contains('desc');rows.sort((a,b)=>{const va=a.children[i].textContent.trim().toLowerCase();const vb=b.children[i].textContent.trim().toLowerCase();return asc?va.localeCompare(vb):vb.localeCompare(va)});rows.forEach(r=>tbody.appendChild(r));document.querySelectorAll('th[data-sort]').forEach(h=>{h.classList.toggle('asc',h===th&&asc);h.classList.toggle('desc',h===th&&!asc)})})}) |
Timeline
Vertical timeline with events, dates, and status indicators.
timeline
Live
untitled.html
HTML
| 1 | <div class="tl"> |
| 2 | <div class="tl-item"> |
| 3 | <div class="tl-dot done"> |
| 4 | </div> |
| 5 | <div class="tl-content"> |
| 6 | <div class="tl-date"> |
| 7 | 2 min ago |
| 8 | </div> |
| 9 | <div class="tl-title"> |
| 10 | Deployed v2.4.1 |
| 11 | </div> |
| 12 | <div class="tl-desc"> |
| 13 | Production release with bug fixes and performance improvements. |
| 14 | </div> |
| 15 | </div> |
| 16 | </div> |
| 17 | <div class="tl-item"> |
| 18 | <div class="tl-dot done"> |
| 19 | </div> |
| 20 | <div class="tl-content"> |
| 21 | <div class="tl-date"> |
| 22 | 1 hour ago |
| 23 | </div> |
| 24 | <div class="tl-title"> |
| 25 | Code Review Approved |
| 26 | </div> |
| 27 | <div class="tl-desc"> |
| 28 | PR #342 merged to main branch. |
| 29 | </div> |
| 30 | </div> |
| 31 | </div> |
| 32 | <div class="tl-item"> |
| 33 | <div class="tl-dot current"> |
| 34 | </div> |
| 35 | <div class="tl-content"> |
| 36 | <div class="tl-date"> |
| 37 | In progress |
| 38 | </div> |
| 39 | <div class="tl-title"> |
| 40 | Database Migration |
| 41 | </div> |
| 42 | <div class="tl-desc"> |
| 43 | Migrating user data to new schema. |
| 44 | </div> |
| 45 | </div> |
| 46 | </div> |
| 47 | <div class="tl-item"> |
| 48 | <div class="tl-dot"> |
| 49 | </div> |
| 50 | <div class="tl-content"> |
| 51 | <div class="tl-date"> |
| 52 | Next |
| 53 | </div> |
| 54 | <div class="tl-title"> |
| 55 | Load Testing |
| 56 | </div> |
| 57 | <div class="tl-desc"> |
| 58 | Scheduled for next sprint. |
| 59 | </div> |
| 60 | </div> |
| 61 | </div> |
| 62 | </div> |
untitled.css
CSS
| 1 | * { |
| 2 | margin:0; |
| 3 | padding:0; |
| 4 | box-sizing:border-box |
| 5 | } |
| 6 | body { |
| 7 | font-family:system-ui, |
| 8 | sans-serif; |
| 9 | background:#0D0D0D; |
| 10 | padding:24px |
| 11 | } |
| 12 | .tl { |
| 13 | max-width:400px; |
| 14 | margin:16px auto; |
| 15 | padding:8px 0 |
| 16 | } |
| 17 | .tl-item { |
| 18 | display:flex; |
| 19 | gap:16px; |
| 20 | padding-bottom:24px; |
| 21 | position:relative |
| 22 | } |
| 23 | .tl-item:last-child { |
| 24 | padding-bottom:0 |
| 25 | } |
| 26 | .tl-dot { |
| 27 | width:14px; |
| 28 | height:14px; |
| 29 | border-radius:50%; |
| 30 | background:#333; |
| 31 | border:3px solid #0D0D0D; |
| 32 | flex-shrink:0; |
| 33 | margin-top:3px; |
| 34 | position:relative; |
| 35 | z-index:1 |
| 36 | } |
| 37 | .tl-dot.done { |
| 38 | background:#00FF41 |
| 39 | } |
| 40 | .tl-dot.current { |
| 41 | background:#00FF41; |
| 42 | box-shadow:0 0 0 4px rgba(0, |
| 43 | 255, |
| 44 | 65, |
| 45 | .2) |
| 46 | } |
| 47 | .tl-item:not(:last-child)::after { |
| 48 | content:''; |
| 49 | position:absolute; |
| 50 | left:6px; |
| 51 | top:20px; |
| 52 | bottom:0; |
| 53 | width:2px; |
| 54 | background:#222 |
| 55 | } |
| 56 | .tl-date { |
| 57 | font-size:10px; |
| 58 | color:#525252; |
| 59 | margin-bottom:2px |
| 60 | } |
| 61 | .tl-title { |
| 62 | font-size:13px; |
| 63 | color:#E0E0E0; |
| 64 | font-weight:600; |
| 65 | margin-bottom:2px |
| 66 | } |
| 67 | .tl-desc { |
| 68 | font-size:11px; |
| 69 | color:#808080; |
| 70 | line-height:1.4 |
| 71 | } |