936 lines
29 KiB
HTML
936 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-Hant">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>dotlog — 把所有日誌管線串成一行</title>
|
||
<meta name="description" content="dotlog 是為工程師而生的 CLI 工具:一條指令完成擷取、過濾、聚合、輸出。" />
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||
<style>
|
||
/* ===================== Tokens ===================== */
|
||
:root {
|
||
--background: #fcfcfc;
|
||
--foreground: #171717;
|
||
--card: #fcfcfc;
|
||
--primary: #00bb7f;
|
||
--primary-soft: rgba(0, 187, 127, 0.25);
|
||
--primary-bg: rgba(0, 187, 127, 0.10);
|
||
--secondary: #fdfdfd;
|
||
--muted: #ededed;
|
||
--muted-foreground: #525252;
|
||
--neutral-400: #a1a1a1;
|
||
--accent: #ededed;
|
||
--border: #dfdfdf;
|
||
--ring: #72e3ad;
|
||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||
--shadow-lg: 0 12px 32px -14px rgba(0, 0, 0, 0.18);
|
||
--radius-xs: 4px;
|
||
--radius-md: 10px;
|
||
--radius-2xl: 16px;
|
||
--radius-3xl: 24px;
|
||
--font-sans: "Space Grotesk", system-ui, -apple-system, "Noto Sans TC", sans-serif;
|
||
--font-mono: "JetBrains Mono", "Fira Code", ui-monospace, monospace;
|
||
--transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
||
--container: 1152px;
|
||
}
|
||
|
||
html.dark {
|
||
--background: #121212;
|
||
--foreground: #e2e8f0;
|
||
--card: #171717;
|
||
--primary: #00bb7f;
|
||
--primary-soft: rgba(74, 222, 128, 0.30);
|
||
--primary-bg: rgba(0, 187, 127, 0.14);
|
||
--secondary: #242424;
|
||
--muted: #1f1f1f;
|
||
--muted-foreground: #a2a2a2;
|
||
--accent: #313131;
|
||
--border: #292929;
|
||
--ring: #4ade80;
|
||
--shadow-lg: 0 12px 32px -14px rgba(0, 0, 0, 0.6);
|
||
}
|
||
|
||
/* ===================== Reset ===================== */
|
||
*, *::before, *::after { box-sizing: border-box; }
|
||
html { scroll-behavior: smooth; }
|
||
body {
|
||
margin: 0;
|
||
font-family: var(--font-sans);
|
||
background: var(--background);
|
||
color: var(--foreground);
|
||
font-size: 16px;
|
||
line-height: 1.5;
|
||
-webkit-font-smoothing: antialiased;
|
||
transition: background var(--transition), color var(--transition);
|
||
}
|
||
a { color: inherit; text-decoration: none; }
|
||
button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; padding: 0; }
|
||
code { font-family: var(--font-mono); background: var(--muted); padding: 1px 6px; border-radius: var(--radius-xs); font-size: 0.875em; }
|
||
|
||
.container {
|
||
max-width: var(--container);
|
||
margin: 0 auto;
|
||
padding: 0 24px;
|
||
}
|
||
|
||
/* ===================== Header ===================== */
|
||
.site-header {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 50;
|
||
height: 64px;
|
||
display: flex;
|
||
align-items: center;
|
||
background: color-mix(in srgb, var(--background) 78%, transparent);
|
||
backdrop-filter: blur(10px);
|
||
-webkit-backdrop-filter: blur(10px);
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.site-header .container {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
width: 100%;
|
||
}
|
||
.brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
font-weight: 700;
|
||
font-size: 18px;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
.brand-dot {
|
||
width: 10px; height: 10px;
|
||
border-radius: 50%;
|
||
background: var(--primary);
|
||
box-shadow: 0 0 10px var(--primary);
|
||
}
|
||
.nav {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
.nav > a {
|
||
padding: 8px 12px;
|
||
font-size: 14px;
|
||
color: var(--muted-foreground);
|
||
border-radius: 8px;
|
||
transition: color var(--transition);
|
||
}
|
||
.nav > a:hover { color: var(--primary); }
|
||
.theme-toggle {
|
||
width: 36px; height: 36px;
|
||
border-radius: var(--radius-md);
|
||
display: grid;
|
||
place-items: center;
|
||
border: 1px solid var(--border);
|
||
transition: background var(--transition), border-color var(--transition);
|
||
margin: 0 4px;
|
||
}
|
||
.theme-toggle:hover { background: var(--accent); border-color: var(--primary-soft); }
|
||
.theme-toggle svg { width: 16px; height: 16px; }
|
||
.theme-toggle .sun { display: none; }
|
||
html.dark .theme-toggle .sun { display: block; }
|
||
html.dark .theme-toggle .moon { display: none; }
|
||
|
||
.nav-github {
|
||
padding: 8px 14px !important;
|
||
font-size: 13.5px !important;
|
||
border-radius: 12px !important;
|
||
}
|
||
|
||
@media (max-width: 639px) {
|
||
.nav > a:not(.nav-github) { display: none; }
|
||
}
|
||
|
||
/* ===================== Buttons ===================== */
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 12px 24px;
|
||
border-radius: var(--radius-2xl);
|
||
font-weight: 600;
|
||
font-size: 15px;
|
||
transition: transform var(--transition), box-shadow var(--transition), background var(--transition), border-color var(--transition), color var(--transition);
|
||
border: 1px solid transparent;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
}
|
||
.btn-primary {
|
||
background: var(--primary);
|
||
color: #fff;
|
||
}
|
||
.btn-primary:hover {
|
||
transform: translateY(-1px);
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
.btn-outline {
|
||
background: transparent;
|
||
color: var(--foreground);
|
||
border-color: var(--border);
|
||
}
|
||
.btn-outline:hover {
|
||
background: var(--accent);
|
||
border-color: var(--primary);
|
||
}
|
||
|
||
/* ===================== Hero ===================== */
|
||
.hero {
|
||
padding: 96px 0 72px;
|
||
text-align: center;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.hero::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
background:
|
||
radial-gradient(ellipse 60% 50% at 50% 0%, var(--primary-bg), transparent 70%);
|
||
pointer-events: none;
|
||
}
|
||
.hero > * { position: relative; }
|
||
.hero h1 {
|
||
font-size: clamp(36px, 7.2vw, 72px);
|
||
line-height: 1.02;
|
||
letter-spacing: -0.03em;
|
||
font-weight: 700;
|
||
margin: 0 0 24px;
|
||
}
|
||
.hero h1 .accent { color: var(--primary); }
|
||
.hero .subtitle {
|
||
font-size: clamp(16px, 1.5vw, 20px);
|
||
line-height: 1.55;
|
||
color: var(--muted-foreground);
|
||
max-width: 42rem;
|
||
margin: 0 auto 28px;
|
||
}
|
||
.hero-badges {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 12px 14px;
|
||
margin-bottom: 40px;
|
||
font-size: 13px;
|
||
color: var(--muted-foreground);
|
||
font-family: var(--font-mono);
|
||
}
|
||
.hero-badges .sep { color: var(--neutral-400); }
|
||
.hero-ctas {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
/* ===================== Section base ===================== */
|
||
.section {
|
||
padding: 80px 0;
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
.section-head {
|
||
text-align: center;
|
||
margin-bottom: 56px;
|
||
}
|
||
.section-kicker {
|
||
font-family: var(--font-mono);
|
||
font-size: 12.5px;
|
||
color: var(--primary);
|
||
letter-spacing: 0.12em;
|
||
text-transform: uppercase;
|
||
margin-bottom: 14px;
|
||
font-weight: 500;
|
||
}
|
||
.section h2 {
|
||
font-size: clamp(30px, 4.2vw, 48px);
|
||
line-height: 1.1;
|
||
font-weight: 700;
|
||
margin: 0 0 14px;
|
||
letter-spacing: -0.02em;
|
||
}
|
||
.section-sub {
|
||
color: var(--muted-foreground);
|
||
font-size: 16.5px;
|
||
max-width: 40rem;
|
||
margin: 0 auto;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
/* ===================== Grids ===================== */
|
||
.grid-4 {
|
||
display: grid;
|
||
gap: 20px;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
}
|
||
@media (max-width: 1023px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
|
||
@media (max-width: 559px) { .grid-4 { grid-template-columns: 1fr; } }
|
||
|
||
.grid-steps {
|
||
display: grid;
|
||
gap: 20px;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
}
|
||
@media (max-width: 1023px) { .grid-steps { grid-template-columns: repeat(2, 1fr); } }
|
||
@media (max-width: 559px) { .grid-steps { grid-template-columns: 1fr; } }
|
||
|
||
.grid-apps {
|
||
display: grid;
|
||
gap: 20px;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
}
|
||
@media (max-width: 767px) { .grid-apps { grid-template-columns: repeat(2, 1fr); } }
|
||
@media (max-width: 479px) { .grid-apps { grid-template-columns: 1fr; } }
|
||
|
||
/* ===================== Card ===================== */
|
||
.card {
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-2xl);
|
||
padding: 24px;
|
||
transition: border-color var(--transition), box-shadow var(--transition), transform var(--transition);
|
||
}
|
||
.card:hover {
|
||
border-color: var(--primary-soft);
|
||
box-shadow: var(--shadow-lg);
|
||
transform: translateY(-2px);
|
||
}
|
||
.card .icon {
|
||
width: 40px; height: 40px;
|
||
display: grid; place-items: center;
|
||
border-radius: var(--radius-md);
|
||
background: var(--primary-bg);
|
||
color: var(--primary);
|
||
margin-bottom: 18px;
|
||
}
|
||
.card .icon svg { width: 20px; height: 20px; stroke-width: 1.6; }
|
||
.card h3 {
|
||
font-size: 17px;
|
||
margin: 0 0 8px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
.card p {
|
||
margin: 0;
|
||
color: var(--muted-foreground);
|
||
font-size: 14.5px;
|
||
line-height: 1.55;
|
||
}
|
||
|
||
/* ===================== Step ===================== */
|
||
.step .num {
|
||
font-family: var(--font-mono);
|
||
font-size: 44px;
|
||
font-weight: 600;
|
||
color: var(--primary);
|
||
line-height: 1;
|
||
margin-bottom: 16px;
|
||
}
|
||
.step h3 {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
margin: 0 0 14px;
|
||
}
|
||
.cmd {
|
||
font-family: var(--font-mono);
|
||
font-size: 13px;
|
||
background: var(--muted);
|
||
color: var(--foreground);
|
||
padding: 8px 12px;
|
||
border-radius: var(--radius-xs);
|
||
display: block;
|
||
white-space: nowrap;
|
||
overflow-x: auto;
|
||
max-width: 100%;
|
||
}
|
||
.cmd::-webkit-scrollbar { height: 0; }
|
||
|
||
/* ===================== App card ===================== */
|
||
.app-card h3 {
|
||
font-size: 15.5px;
|
||
font-weight: 600;
|
||
margin: 0 0 14px;
|
||
}
|
||
.tag-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
}
|
||
.tag {
|
||
font-family: var(--font-mono);
|
||
font-size: 11.5px;
|
||
background: var(--muted);
|
||
color: var(--muted-foreground);
|
||
padding: 3px 8px;
|
||
border-radius: var(--radius-xs);
|
||
}
|
||
|
||
/* ===================== Pipeline ===================== */
|
||
.pipeline-wrap {
|
||
max-width: 960px;
|
||
margin: 0 auto;
|
||
}
|
||
.pipeline {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
position: relative;
|
||
padding: 40px 0 32px;
|
||
}
|
||
.pipeline::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 47px;
|
||
left: 7%;
|
||
right: 7%;
|
||
height: 2px;
|
||
background: linear-gradient(to right,
|
||
var(--primary-soft),
|
||
var(--primary) 15%,
|
||
var(--primary) 85%,
|
||
var(--primary-soft));
|
||
z-index: 0;
|
||
opacity: 0.55;
|
||
}
|
||
.stage {
|
||
flex: 1;
|
||
position: relative;
|
||
z-index: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
text-align: center;
|
||
}
|
||
.stage .dot {
|
||
width: 14px; height: 14px;
|
||
border-radius: 50%;
|
||
background: var(--primary);
|
||
margin: 0 0 18px;
|
||
box-shadow:
|
||
0 0 0 4px var(--background),
|
||
0 0 0 6px var(--primary-soft);
|
||
}
|
||
.stage .num-sm {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
color: var(--muted-foreground);
|
||
margin-bottom: 2px;
|
||
letter-spacing: 0.05em;
|
||
}
|
||
.stage .label {
|
||
font-size: 14px;
|
||
color: var(--foreground);
|
||
font-weight: 500;
|
||
}
|
||
@media (max-width: 767px) {
|
||
.pipeline {
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
padding-left: 20px;
|
||
}
|
||
.pipeline::before {
|
||
top: 40px;
|
||
bottom: 40px;
|
||
left: 26px;
|
||
right: auto;
|
||
width: 2px;
|
||
height: auto;
|
||
background: linear-gradient(to bottom,
|
||
var(--primary-soft),
|
||
var(--primary) 15%,
|
||
var(--primary) 85%,
|
||
var(--primary-soft));
|
||
}
|
||
.stage {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 14px;
|
||
text-align: left;
|
||
flex: none;
|
||
padding: 8px 0;
|
||
}
|
||
.stage .dot { margin: 0; flex-shrink: 0; }
|
||
.stage-meta { display: flex; flex-direction: column; }
|
||
}
|
||
|
||
/* ===================== FAQ ===================== */
|
||
.faq {
|
||
max-width: 760px;
|
||
margin: 0 auto;
|
||
}
|
||
.faq details {
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 20px 4px;
|
||
}
|
||
.faq details:first-child { border-top: 1px solid var(--border); }
|
||
.faq details[open] summary { color: var(--primary); }
|
||
.faq summary {
|
||
list-style: none;
|
||
cursor: pointer;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: 16px;
|
||
transition: color var(--transition);
|
||
}
|
||
.faq summary::-webkit-details-marker { display: none; }
|
||
.faq summary::after {
|
||
content: "+";
|
||
font-family: var(--font-mono);
|
||
font-size: 22px;
|
||
color: var(--primary);
|
||
line-height: 1;
|
||
transition: transform var(--transition);
|
||
flex-shrink: 0;
|
||
}
|
||
.faq details[open] summary::after {
|
||
content: "−";
|
||
}
|
||
.faq .answer {
|
||
color: var(--muted-foreground);
|
||
margin-top: 14px;
|
||
font-size: 15px;
|
||
line-height: 1.65;
|
||
}
|
||
|
||
/* ===================== Footer ===================== */
|
||
.site-footer {
|
||
border-top: 1px solid var(--border);
|
||
padding: 56px 0 32px;
|
||
}
|
||
.footer-grid {
|
||
display: grid;
|
||
gap: 32px;
|
||
grid-template-columns: 1.5fr 1fr 1fr 1fr;
|
||
}
|
||
@media (max-width: 767px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
|
||
@media (max-width: 479px) { .footer-grid { grid-template-columns: 1fr; } }
|
||
.footer-brand p {
|
||
color: var(--muted-foreground);
|
||
font-size: 14px;
|
||
margin: 14px 0 0;
|
||
line-height: 1.65;
|
||
max-width: 22rem;
|
||
}
|
||
.footer-col h4 {
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
margin: 0 0 16px;
|
||
color: var(--foreground);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.1em;
|
||
font-family: var(--font-mono);
|
||
}
|
||
.footer-col ul {
|
||
list-style: none;
|
||
padding: 0; margin: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
.footer-col a {
|
||
color: var(--muted-foreground);
|
||
font-size: 14px;
|
||
transition: color var(--transition);
|
||
}
|
||
.footer-col a:hover { color: var(--primary); }
|
||
.copyright {
|
||
text-align: center;
|
||
margin-top: 48px;
|
||
padding-top: 24px;
|
||
border-top: 1px solid var(--border);
|
||
font-size: 13px;
|
||
color: var(--neutral-400);
|
||
font-family: var(--font-mono);
|
||
}
|
||
|
||
/* ===================== Focus ring ===================== */
|
||
:is(a, button, summary, .btn):focus-visible {
|
||
outline: 2px solid var(--ring);
|
||
outline-offset: 3px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
/* ===================== Fade-up ===================== */
|
||
.fade-up {
|
||
opacity: 0;
|
||
transform: translateY(14px);
|
||
transition:
|
||
opacity 520ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
transform 520ms cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
.fade-up.visible {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.fade-up { opacity: 1; transform: none; transition: none; }
|
||
html { scroll-behavior: auto; }
|
||
}
|
||
|
||
/* ===================== Mobile tweaks ===================== */
|
||
@media (max-width: 639px) {
|
||
.hero { padding: 56px 0 48px; }
|
||
.section { padding: 64px 0; }
|
||
.section-head { margin-bottom: 40px; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- ============ Header ============ -->
|
||
<header class="site-header">
|
||
<div class="container">
|
||
<a href="#top" class="brand" aria-label="dotlog 首頁">
|
||
<span class="brand-dot" aria-hidden="true"></span>
|
||
<span>dotlog</span>
|
||
</a>
|
||
<nav class="nav" aria-label="主要導覽">
|
||
<a href="#features">功能特性</a>
|
||
<a href="#steps">文件</a>
|
||
<a href="#faq">FAQ</a>
|
||
<button class="theme-toggle" type="button" id="themeToggle" aria-label="切換深淺主題">
|
||
<svg class="moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
||
</svg>
|
||
<svg class="sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<circle cx="12" cy="12" r="4"/>
|
||
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
|
||
</svg>
|
||
</button>
|
||
<a href="#" class="btn btn-primary nav-github">在 GitHub 查看</a>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
|
||
<main id="top">
|
||
|
||
<!-- ============ Hero ============ -->
|
||
<section class="hero">
|
||
<div class="container">
|
||
<h1 class="fade-up">
|
||
把所有日誌管線<br/>
|
||
<span class="accent">串成一行</span>
|
||
</h1>
|
||
<p class="subtitle fade-up">
|
||
dotlog 是為工程師而生的 CLI 工具。一條指令完成擷取、過濾、聚合、輸出,取代雜亂的 shell pipeline 與多套 daemon。
|
||
</p>
|
||
<div class="hero-badges fade-up">
|
||
<span>⭐ 1.2k Stars</span>
|
||
<span class="sep">·</span>
|
||
<span>98% 測試通過</span>
|
||
<span class="sep">·</span>
|
||
<span>MIT 授權</span>
|
||
</div>
|
||
<div class="hero-ctas fade-up">
|
||
<a href="#steps" class="btn btn-primary">立即開始</a>
|
||
<a href="#" class="btn btn-outline">在 GitHub 查看</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Why dotlog ============ -->
|
||
<section class="section" id="features">
|
||
<div class="container">
|
||
<div class="section-head fade-up">
|
||
<div class="section-kicker">Why dotlog</div>
|
||
<h2>為什麼選擇 dotlog</h2>
|
||
<p class="section-sub">不需要 YAML、不需要 daemon、不需要額外的容器。一支二進位檔,裝了就能用。</p>
|
||
</div>
|
||
<div class="grid-4">
|
||
<article class="card fade-up">
|
||
<div class="icon" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
|
||
</div>
|
||
<h3>零配置啟動</h3>
|
||
<p>裝了就跑,不需要設定檔。<code>dotlog tap nginx</code> 一行搞定。</p>
|
||
</article>
|
||
<article class="card fade-up">
|
||
<div class="icon" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 10h18"/><path d="M8 14h2M8 17h5"/></svg>
|
||
</div>
|
||
<h3>全格式支援</h3>
|
||
<p>JSON、syslog、Apache、Nginx、K8s events 自動偵測並結構化。</p>
|
||
</article>
|
||
<article class="card fade-up">
|
||
<div class="icon" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12h4l3-9 4 18 3-9h4"/></svg>
|
||
</div>
|
||
<h3>低資源佔用</h3>
|
||
<p>Rust 撰寫,單一二進位檔 6MB,常駐記憶體不到 15MB。</p>
|
||
</article>
|
||
<article class="card fade-up">
|
||
<div class="icon" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/><polyline points="7 11 12 16 17 11"/><line x1="12" y1="4" x2="12" y2="16"/></svg>
|
||
</div>
|
||
<h3>原生輸出整合</h3>
|
||
<p>直接送進 S3、Loki、OpenTelemetry、Kafka,無須轉接器。</p>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Quick Start ============ -->
|
||
<section class="section" id="steps">
|
||
<div class="container">
|
||
<div class="section-head fade-up">
|
||
<div class="section-kicker">Quick Start</div>
|
||
<h2>5 分鐘上手</h2>
|
||
<p class="section-sub">四個指令,把你的伺服器日誌送到雲端。</p>
|
||
</div>
|
||
<div class="grid-steps">
|
||
<article class="step card fade-up">
|
||
<div class="num">01</div>
|
||
<h3>安裝</h3>
|
||
<code class="cmd">brew install dotlog</code>
|
||
</article>
|
||
<article class="step card fade-up">
|
||
<div class="num">02</div>
|
||
<h3>初始化</h3>
|
||
<code class="cmd">dotlog init</code>
|
||
</article>
|
||
<article class="step card fade-up">
|
||
<div class="num">03</div>
|
||
<h3>指定來源</h3>
|
||
<code class="cmd">dotlog tap nginx</code>
|
||
</article>
|
||
<article class="step card fade-up">
|
||
<div class="num">04</div>
|
||
<h3>串接輸出</h3>
|
||
<code class="cmd">dotlog pipe → s3</code>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Integrations ============ -->
|
||
<section class="section">
|
||
<div class="container">
|
||
<div class="section-head fade-up">
|
||
<div class="section-kicker">Integrations</div>
|
||
<h2>你正在用的工具,它都支援</h2>
|
||
<p class="section-sub">開箱即用 60+ 種資料來源與 20+ 種輸出目標。</p>
|
||
</div>
|
||
<div class="grid-apps">
|
||
<article class="card app-card fade-up">
|
||
<h3>Web 伺服器</h3>
|
||
<div class="tag-list">
|
||
<span class="tag">nginx</span><span class="tag">apache</span><span class="tag">caddy</span><span class="tag">traefik</span>
|
||
</div>
|
||
</article>
|
||
<article class="card app-card fade-up">
|
||
<h3>容器</h3>
|
||
<div class="tag-list">
|
||
<span class="tag">docker</span><span class="tag">kubernetes</span><span class="tag">containerd</span><span class="tag">podman</span>
|
||
</div>
|
||
</article>
|
||
<article class="card app-card fade-up">
|
||
<h3>資料庫</h3>
|
||
<div class="tag-list">
|
||
<span class="tag">postgres</span><span class="tag">mysql</span><span class="tag">redis</span><span class="tag">mongo</span>
|
||
</div>
|
||
</article>
|
||
<article class="card app-card fade-up">
|
||
<h3>雲端服務</h3>
|
||
<div class="tag-list">
|
||
<span class="tag">aws-s3</span><span class="tag">gcs</span><span class="tag">cloudwatch</span><span class="tag">azure-logs</span>
|
||
</div>
|
||
</article>
|
||
<article class="card app-card fade-up">
|
||
<h3>訊息佇列</h3>
|
||
<div class="tag-list">
|
||
<span class="tag">kafka</span><span class="tag">nats</span><span class="tag">rabbitmq</span><span class="tag">sqs</span>
|
||
</div>
|
||
</article>
|
||
<article class="card app-card fade-up">
|
||
<h3>監控</h3>
|
||
<div class="tag-list">
|
||
<span class="tag">loki</span><span class="tag">datadog</span><span class="tag">otel</span><span class="tag">prometheus</span>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ Pipeline ============ -->
|
||
<section class="section">
|
||
<div class="container">
|
||
<div class="section-head fade-up">
|
||
<div class="section-kicker">Core Pipeline</div>
|
||
<h2>七個階段的完整流水線</h2>
|
||
<p class="section-sub">每一階段都能被單獨替換、停用或擴充。</p>
|
||
</div>
|
||
<div class="pipeline-wrap fade-up">
|
||
<div class="pipeline" role="list">
|
||
<div class="stage" role="listitem">
|
||
<div class="dot" aria-hidden="true"></div>
|
||
<div class="stage-meta">
|
||
<span class="num-sm">01</span>
|
||
<span class="label">擷取</span>
|
||
</div>
|
||
</div>
|
||
<div class="stage" role="listitem">
|
||
<div class="dot" aria-hidden="true"></div>
|
||
<div class="stage-meta">
|
||
<span class="num-sm">02</span>
|
||
<span class="label">解析</span>
|
||
</div>
|
||
</div>
|
||
<div class="stage" role="listitem">
|
||
<div class="dot" aria-hidden="true"></div>
|
||
<div class="stage-meta">
|
||
<span class="num-sm">03</span>
|
||
<span class="label">正規化</span>
|
||
</div>
|
||
</div>
|
||
<div class="stage" role="listitem">
|
||
<div class="dot" aria-hidden="true"></div>
|
||
<div class="stage-meta">
|
||
<span class="num-sm">04</span>
|
||
<span class="label">路由</span>
|
||
</div>
|
||
</div>
|
||
<div class="stage" role="listitem">
|
||
<div class="dot" aria-hidden="true"></div>
|
||
<div class="stage-meta">
|
||
<span class="num-sm">05</span>
|
||
<span class="label">過濾</span>
|
||
</div>
|
||
</div>
|
||
<div class="stage" role="listitem">
|
||
<div class="dot" aria-hidden="true"></div>
|
||
<div class="stage-meta">
|
||
<span class="num-sm">06</span>
|
||
<span class="label">聚合</span>
|
||
</div>
|
||
</div>
|
||
<div class="stage" role="listitem">
|
||
<div class="dot" aria-hidden="true"></div>
|
||
<div class="stage-meta">
|
||
<span class="num-sm">07</span>
|
||
<span class="label">輸出</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ FAQ ============ -->
|
||
<section class="section" id="faq">
|
||
<div class="container">
|
||
<div class="section-head fade-up">
|
||
<div class="section-kicker">FAQ</div>
|
||
<h2>常見問題</h2>
|
||
</div>
|
||
<div class="faq fade-up">
|
||
<details>
|
||
<summary>dotlog 的授權是什麼?</summary>
|
||
<div class="answer">採用 MIT 授權,商用、修改、再散布都沒有限制,無需付費。</div>
|
||
</details>
|
||
<details>
|
||
<summary>效能表現如何?</summary>
|
||
<div class="answer">在單一 vCPU 上可處理約 120k events/秒,約為 Fluentd 的 4 倍,記憶體佔用不到 1/5。</div>
|
||
</details>
|
||
<details>
|
||
<summary>與 Fluentd / Vector / Filebeat 有什麼差異?</summary>
|
||
<div class="answer">dotlog 強調 <strong>CLI 優先與零配置</strong>:用熟悉的 shell 就能組裝管線,無需學習自訂 DSL,也不需要部署守護程序。適合需要快速串接或臨時任務的場景。</div>
|
||
</details>
|
||
<details>
|
||
<summary>支援哪些部署方式?</summary>
|
||
<div class="answer">單一靜態二進位檔,直接在 macOS、Linux、Windows 執行;也提供官方 Docker image 與 Helm chart。</div>
|
||
</details>
|
||
<details>
|
||
<summary>資料會經過你們的伺服器嗎?</summary>
|
||
<div class="answer">完全不會。dotlog 是純本地執行的工具,所有日誌只在你指定的來源與輸出之間傳遞,專案本身不收集任何遙測資料(可用 <code>--telemetry=off</code> 再次關閉驗證)。</div>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
<!-- ============ Footer ============ -->
|
||
<footer class="site-footer">
|
||
<div class="container">
|
||
<div class="footer-grid">
|
||
<div class="footer-brand">
|
||
<div class="brand">
|
||
<span class="brand-dot" aria-hidden="true"></span>
|
||
<span>dotlog</span>
|
||
</div>
|
||
<p>把所有日誌管線串成一行。為工程師而生的開源 CLI 工具。</p>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h4>產品</h4>
|
||
<ul>
|
||
<li><a href="#features">功能特性</a></li>
|
||
<li><a href="#steps">快速上手</a></li>
|
||
<li><a href="#">更新日誌</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h4>資源</h4>
|
||
<ul>
|
||
<li><a href="#">文件</a></li>
|
||
<li><a href="#">GitHub</a></li>
|
||
<li><a href="#">社群討論</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h4>法律</h4>
|
||
<ul>
|
||
<li><a href="#">授權條款</a></li>
|
||
<li><a href="#">隱私政策</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="copyright">© 2026 dotlog · MIT License</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
// ==== Theme toggle ====
|
||
(function () {
|
||
const root = document.documentElement;
|
||
const toggle = document.getElementById('themeToggle');
|
||
const stored = localStorage.getItem('dotlog-theme');
|
||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||
if (stored === 'dark' || (!stored && prefersDark)) {
|
||
root.classList.add('dark');
|
||
}
|
||
toggle.addEventListener('click', () => {
|
||
root.classList.toggle('dark');
|
||
localStorage.setItem('dotlog-theme', root.classList.contains('dark') ? 'dark' : 'light');
|
||
});
|
||
})();
|
||
|
||
// ==== Fade-up on scroll ====
|
||
(function () {
|
||
const items = document.querySelectorAll('.fade-up');
|
||
if (!('IntersectionObserver' in window)) {
|
||
items.forEach((el) => el.classList.add('visible'));
|
||
return;
|
||
}
|
||
const io = new IntersectionObserver((entries) => {
|
||
entries.forEach((e) => {
|
||
if (e.isIntersecting) {
|
||
e.target.classList.add('visible');
|
||
io.unobserve(e.target);
|
||
}
|
||
});
|
||
}, { threshold: 0.08, rootMargin: '0px 0px -40px 0px' });
|
||
items.forEach((el) => io.observe(el));
|
||
})();
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|