From 65c18b95b878dfeab0cf3ed3aa7caed2ace1639a Mon Sep 17 00:00:00 2001 From: Tam-Leal Date: Fri, 22 May 2026 13:16:51 -0400 Subject: [PATCH] docs(site): refactor landing SEO, layout, and assets Split landing into external CSS/JS with static manifest and sitemap.xml. Update SEO to dashboard screenshot, security panel, How it works copy, and Octicons. Keep tentacle preview behavior unchanged. Align download page head; remove obsolete sitemap.txt. --- CHANGELOG.md | 3 +- site/css/common.css | 277 +++++++++++++ site/css/index.css | 901 ++++++++++++++++++++++++++++++++++++++++++ site/download.html | 4 +- site/index.html | 776 ++++++++++++------------------------ site/js/common.js | 48 +++ site/js/index-hero.js | 222 +++++++++++ site/manifest.json | 17 + site/robots.txt | 2 +- site/sitemap.txt | 4 - site/sitemap.xml | 23 ++ 11 files changed, 1740 insertions(+), 537 deletions(-) create mode 100644 site/css/common.css create mode 100644 site/css/index.css create mode 100644 site/js/common.js create mode 100644 site/js/index-hero.js create mode 100644 site/manifest.json delete mode 100644 site/sitemap.txt create mode 100644 site/sitemap.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 3735378..c439b15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Download page (`site/download.html`): centered OS picker, clearer prerequisites table, tighter install steps, condensed trust section. +- Landing page (`site/index.html`): external CSS/JS, SEO (dashboard screenshot, manifest, sitemap.xml), security panel, aligned copy and Octicons; tentacle preview unchanged. +- Download page (`site/download.html`): static manifest, shared nav styles via `common.css`, centered OS picker, clearer prerequisites, tighter install steps. - README header uses `site/gitdock-logo-removebg-preview.png` (transparent logo for GitHub light and dark themes). - `server.js` imports validation helpers from `lib/` (behavior preserved; easier to test). - Account name validation now rejects names that require stripping unsafe characters (e.g. `bad name!`, `work;rm`). diff --git a/site/css/common.css b/site/css/common.css new file mode 100644 index 0000000..307e69a --- /dev/null +++ b/site/css/common.css @@ -0,0 +1,277 @@ +:root { + --bg0: #0d1117; + --bg1: #161b22; + --bg2: #21262d; + --bg3: #30363d; + --border: #30363d; + --t1: #e6edf3; + --t2: #8b949e; + --t3: #6e7681; + --blue: #58a6ff; + --green: #3fb950; + --yellow: #d29922; + --red: #f85149; + --purple: #bc8cff; + --orange: #f0883e; + --cyan: #39c5cf; + --grad: linear-gradient(135deg, #58a6ff, #bc8cff); +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background: var(--bg0); + color: var(--t1); + line-height: 1.6; + overflow-x: hidden; +} + +a { + color: var(--blue); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +.skip-link { + position: absolute; + top: -100px; + left: 16px; + z-index: 200; + padding: 8px 16px; + border-radius: 6px; + background: var(--blue); + color: #fff; + font-size: 14px; + font-weight: 600; + text-decoration: none; +} + +.skip-link:focus { + top: 16px; + outline: 2px solid var(--cyan); + outline-offset: 2px; +} + +/* Navigation */ +.nav { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + background: rgba(13, 17, 23, 0.85); + backdrop-filter: blur(12px); + border-bottom: 1px solid var(--border); + padding: 0 24px; +} + +.nav-inner { + max-width: 1200px; + margin: 0 auto; + display: flex; + align-items: center; + justify-content: space-between; + height: 56px; +} + +.nav-brand { + display: flex; + align-items: center; + gap: 10px; + font-weight: 600; + font-size: 15px; + color: var(--t1); + text-decoration: none; +} + +.nav-brand:hover { + text-decoration: none; + color: var(--t1); +} + +.nav-logo { + width: 28px; + height: 28px; + border-radius: 6px; + overflow: hidden; + display: inline-flex; + align-items: center; + justify-content: center; + flex: 0 0 28px; + transform: scale(1.25); + transform-origin: center; +} + +.nav-logo img { + width: 100%; + height: 100%; + object-fit: cover; + transform: scale(1.25); + transform-origin: center; +} + +.nav-links { + display: flex; + gap: 24px; + align-items: center; +} + +.nav-links a { + color: var(--t2); + font-size: 13px; + text-decoration: none; + transition: color 0.2s; +} + +.nav-links a:hover { + color: var(--t1); + text-decoration: none; +} + +.btn-nav { + padding: 6px 16px; + border-radius: 6px; + background: var(--blue); + color: #fff !important; + font-weight: 500; + font-size: 13px; + transition: opacity 0.2s; +} + +.btn-nav:hover { + opacity: 0.9; + text-decoration: none !important; +} + +/* Section base */ +.section { + padding: 100px 24px; +} + +.section-inner { + max-width: 1100px; + margin: 0 auto; +} + +.section-label { + font-size: 11px; + text-transform: uppercase; + letter-spacing: 1.5px; + color: var(--blue); + font-weight: 600; + margin-bottom: 8px; +} + +.section-title { + font-size: clamp(28px, 4vw, 40px); + font-weight: 700; + margin-bottom: 16px; + letter-spacing: -0.01em; +} + +.section-desc { + font-size: 16px; + color: var(--t2); + max-width: 600px; + line-height: 1.6; +} + +.section-header { + margin-bottom: 56px; +} + +/* Buttons */ +.btn-hero { + padding: 12px 28px; + border-radius: 8px; + font-size: 15px; + font-weight: 600; + cursor: pointer; + border: none; + transition: all 0.2s; + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 8px; +} + +.btn-hero:hover { + text-decoration: none; +} + +.btn-primary { + background: var(--blue); + color: #fff; +} + +.btn-primary:hover { + background: #4a96ef; + box-shadow: 0 0 20px rgba(88, 166, 255, 0.3); +} + +.btn-secondary { + background: transparent; + color: var(--t1); + border: 1px solid var(--border); +} + +.btn-secondary:hover { + border-color: var(--t2); + background: var(--bg1); +} + +/* Animations */ +.fade-in { + opacity: 0; + transform: translateY(24px); +} + +.fade-in.visible { + animation: fadeInUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) var(--stagger, 0s) both; +} + +@keyframes fadeInUp { + to { + opacity: 1; + transform: none; + } +} + +/* Footer */ +.footer { + padding: 32px 24px; + border-top: 1px solid var(--border); + text-align: center; +} + +.footer p { + font-size: 12px; + color: var(--t3); +} + +.footer-links { + margin-bottom: 8px; +} + +.footer-links a { + color: var(--t3); + margin: 0 8px; + font-size: 12px; + text-decoration: none; +} + +.footer-links a:hover { + color: var(--t1); +} diff --git a/site/css/index.css b/site/css/index.css new file mode 100644 index 0000000..8aee3a7 --- /dev/null +++ b/site/css/index.css @@ -0,0 +1,901 @@ +/* Hero */ +.hero { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + padding: 120px 24px 80px; + position: relative; + overflow: hidden; +} + +.hero::before { + content: ''; + position: absolute; + top: -40%; + left: 50%; + transform: translateX(-50%); + width: 800px; + height: 800px; + background: radial-gradient(circle, rgba(88, 166, 255, 0.08) 0%, rgba(188, 140, 255, 0.04) 40%, transparent 70%); + pointer-events: none; +} + +#hero-canvas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; +} + +.hero-content { + position: relative; + max-width: 720px; + z-index: 1; +} + +.hero-badge { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 14px; + border-radius: 20px; + border: 1px solid var(--border); + background: var(--bg1); + font-size: 12px; + color: var(--t2); + margin-bottom: 24px; +} + +.hero-badge .dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--green); + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.4; + } +} + +.hero h1 { + font-size: clamp(36px, 6vw, 64px); + font-weight: 700; + line-height: 1.1; + margin-bottom: 20px; + letter-spacing: -0.02em; +} + +.hero h1 .grad { + background: var(--grad); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.hero p { + font-size: clamp(16px, 2vw, 20px); + color: var(--t2); + max-width: 600px; + margin: 0 auto 36px; + line-height: 1.5; +} + +.hero-actions { + display: flex; + gap: 12px; + justify-content: center; + flex-wrap: wrap; +} + +.hero-stats { + display: flex; + gap: 32px; + justify-content: center; + margin-top: 48px; + padding-top: 32px; + border-top: 1px solid var(--border); +} + +.hero-stat { + text-align: center; +} + +.hero-stat .num { + font-size: 28px; + font-weight: 700; + color: var(--t1); +} + +.hero-stat .label { + font-size: 12px; + color: var(--t3); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +/* Dashboard Preview (window only — tentacles in inline CSS) */ +.preview { + padding: 0 24px 80px; + margin-top: -40px; + position: relative; + z-index: 1; +} + +.preview-window { + max-width: 1000px; + margin: 0 auto; + border-radius: 12px; + border: 1px solid var(--border); + overflow: hidden; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), 0 0 40px rgba(88, 166, 255, 0.06); + position: relative; + z-index: 1; +} + +.preview-bar { + display: flex; + gap: 6px; + padding: 10px 14px; + background: var(--bg2); + border-bottom: 1px solid var(--border); +} + +.preview-dot { + width: 10px; + height: 10px; + border-radius: 50%; + opacity: 0.8; +} + +.preview-img { + width: 100%; + display: block; + background: var(--bg0); +} + +/* Problem */ +.problem { + background: var(--bg1); + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} + +.pain-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 20px; + margin-top: 40px; +} + +.pain-card { + padding: 24px; + border-radius: 10px; + border: 1px solid var(--border); + background: var(--bg0); + transition: all 0.25s; + position: relative; + overflow: hidden; +} + +.pain-card:hover { + border-color: rgba(88, 166, 255, 0.25); + box-shadow: 0 4px 24px rgba(0, 0, 0, 0.25); +} + +.pain-icon { + margin-bottom: 12px; + display: flex; + align-items: center; + justify-content: center; +} + +.pain-card h3, +.pain-card h4 { + font-size: 14px; + font-weight: 600; + margin-bottom: 6px; +} + +.hub-grid { + max-width: 900px; + margin-left: auto; + margin-right: auto; +} + +.pain-card p { + font-size: 13px; + color: var(--t2); + line-height: 1.5; +} + +/* Features */ +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 16px; +} + +.feat-card { + padding: 28px; + border-radius: 12px; + border: 1px solid var(--border); + background: var(--bg1); + transition: all 0.25s; + position: relative; + overflow: hidden; +} + +.feat-card:hover { + border-color: var(--blue); + transform: translateY(-2px); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3); +} + +.feat-card::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: var(--grad); + opacity: 0; + transition: opacity 0.25s; + z-index: 3; +} + +.feat-card:hover::after { + opacity: 1; +} + +.feat-card::before, +.pain-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: inherit; + background: radial-gradient(600px circle at var(--mx, 50%) var(--my, 50%), rgba(88, 166, 255, 0.06), transparent 40%); + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; + z-index: 1; +} + +.feat-card:hover::before, +.pain-card:hover::before { + opacity: 1; +} + +.feat-card > *, +.pain-card > * { + position: relative; + z-index: 2; +} + +.feat-icon { + width: 40px; + height: 40px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 16px; + font-size: 18px; +} + +.feat-icon.blue { + background: rgba(88, 166, 255, 0.1); + color: var(--blue); +} + +.feat-icon.green { + background: rgba(63, 185, 80, 0.1); + color: var(--green); +} + +.feat-icon.purple { + background: rgba(188, 140, 255, 0.1); + color: var(--purple); +} + +.feat-icon.orange { + background: rgba(240, 136, 62, 0.1); + color: var(--orange); +} + +.feat-icon.yellow { + background: rgba(210, 153, 34, 0.1); + color: var(--yellow); +} + +.feat-icon.red { + background: rgba(248, 81, 73, 0.1); + color: var(--red); +} + +.feat-icon.cyan { + background: rgba(57, 197, 207, 0.1); + color: var(--cyan); +} + +.feat-card h3 { + font-size: 16px; + font-weight: 600; + margin-bottom: 8px; +} + +.feat-card p { + font-size: 13px; + color: var(--t2); + line-height: 1.5; +} + +.feat-tags { + display: flex; + gap: 6px; + margin-top: 12px; + flex-wrap: wrap; +} + +.feat-tag { + padding: 2px 8px; + border-radius: 4px; + font-size: 10px; + background: var(--bg2); + color: var(--t3); + border: 1px solid var(--border); +} + +/* How it works */ +.steps { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 24px; + margin-top: 48px; +} + +.step { + text-align: center; + padding: 32px 24px; +} + +.step-num { + width: 48px; + height: 48px; + border-radius: 50%; + background: var(--bg2); + border: 2px solid var(--border); + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + font-weight: 700; + color: var(--blue); + margin: 0 auto 16px; +} + +.step h4 { + font-size: 15px; + font-weight: 600; + margin-bottom: 8px; +} + +.step p { + font-size: 13px; + color: var(--t2); + line-height: 1.5; +} + +.step code { + background: var(--bg2); + padding: 2px 6px; + border-radius: 4px; + font-size: 12px; +} + +/* Security panel */ +.security { + background: var(--bg1); + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} + +.security-panel { + max-width: 760px; + margin: 40px auto 0; + border-radius: 12px; + border: 1px solid var(--border); + background: var(--bg0); + overflow: hidden; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.22); +} + +.security-panel-accent { + height: 2px; + background: linear-gradient(90deg, var(--blue), var(--green) 55%, var(--cyan)); +} + +.security-panel-grid { + display: grid; + grid-template-columns: 1fr 1fr; +} + +.security-block { + padding: 22px 24px; + border-right: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} + +.security-block:nth-child(2n) { + border-right: none; +} + +.security-block--wide { + grid-column: 1 / -1; + border-right: none; +} + +.security-block-head { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 14px; +} + +.security-block-icon { + width: 32px; + height: 32px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.security-block-icon.blue { + background: rgba(88, 166, 255, 0.12); + color: var(--blue); +} + +.security-block-icon.green { + background: rgba(63, 185, 80, 0.12); + color: var(--green); +} + +.security-block-icon.purple { + background: rgba(188, 140, 255, 0.12); + color: var(--purple); +} + +.security-block-icon.orange { + background: rgba(240, 136, 62, 0.12); + color: var(--orange); +} + +.security-block h3 { + font-size: 13px; + font-weight: 600; + color: var(--t1); + margin: 0; +} + +.security-list { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 10px; +} + +.security-block--wide .security-list { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 14px 28px; +} + +.security-list li { + font-size: 13px; + line-height: 1.45; +} + +.security-list strong { + display: block; + font-size: 13px; + font-weight: 600; + color: var(--t1); + margin-bottom: 3px; +} + +.security-list span { + display: block; + font-size: 12px; + color: var(--t3); + line-height: 1.45; +} + +.security-list code { + font-size: 11px; + padding: 1px 5px; + border-radius: 4px; + background: var(--bg2); + color: var(--t2); +} + +.security-hub { + display: flex; + align-items: flex-start; + gap: 14px; + padding: 16px 24px; + background: rgba(57, 197, 207, 0.06); + border-top: 1px solid var(--border); +} + +.security-hub-icon { + width: 32px; + height: 32px; + border-radius: 8px; + background: rgba(57, 197, 207, 0.12); + color: var(--cyan); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.security-hub-text { + flex: 1; + min-width: 0; +} + +.security-hub-text strong { + display: block; + font-size: 13px; + font-weight: 600; + color: var(--t1); + margin-bottom: 2px; +} + +.security-hub-text span { + display: block; + font-size: 12px; + color: var(--t3); + line-height: 1.45; +} + +.security-hub-tag { + display: block; + font-size: 10px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--cyan); + margin-top: 2px; +} + +/* Editors */ +.editors { + text-align: center; + padding: 80px 24px; +} + +.editor-logos { + display: flex; + gap: 40px; + justify-content: center; + align-items: center; + margin-top: 32px; + flex-wrap: wrap; +} + +.editor-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + color: var(--t2); + font-size: 12px; +} + +.editor-box { + width: 56px; + height: 56px; + border-radius: 12px; + background: var(--bg1); + border: 1px solid var(--border); + display: flex; + align-items: center; + justify-content: center; + font-size: 24px; + transition: all 0.2s; +} + +.editor-item:hover .editor-box { + border-color: var(--blue); + transform: scale(1.05); +} + +/* CTA */ +.cta { + text-align: center; + padding: 100px 24px; +} + +.cta-box { + max-width: 640px; + margin: 0 auto; + padding: 48px 40px; + border-radius: 16px; + border: 1px solid var(--border); + background: var(--bg1); + position: relative; + overflow: hidden; +} + +.cta-box::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: var(--grad); +} + +.cta-box h2 { + font-size: 28px; + font-weight: 700; + margin-bottom: 12px; +} + +.cta-box > p { + color: var(--t2); + margin-bottom: 28px; + font-size: 15px; +} + +.cta-actions { + margin-top: 24px; + display: flex; + gap: 12px; + flex-wrap: wrap; + justify-content: center; +} + +.cta-footnote { + font-size: 12px; + color: var(--t3); + margin-top: 16px; +} + +.platforms { + display: flex; + gap: 12px; + justify-content: center; + margin-top: 20px; +} + +.plat { + padding: 4px 12px; + border-radius: 6px; + border: 1px solid var(--border); + background: var(--bg2); + font-size: 11px; + color: var(--t2); + display: flex; + align-items: center; + gap: 5px; +} + +/* Responsive */ +@media (max-width: 900px) { + .features-grid { + grid-template-columns: 1fr 1fr; + } +} + +@media (max-width: 768px) { + .nav-links a:not(.btn-nav) { + display: none; + } + + .hero { + min-height: auto; + padding: 100px 20px 60px; + } + + .hero h1 { + font-size: 28px; + } + + .hero p { + font-size: 15px; + } + + .hero-stats { + flex-direction: column; + gap: 16px; + } + + .section { + padding: 60px 0; + } + + .section-inner { + padding: 0 16px; + } + + .section-title { + font-size: 22px; + } + + .features-grid { + grid-template-columns: 1fr; + } + + .feat-card { + padding: 20px; + } + + .pain-grid { + grid-template-columns: 1fr 1fr; + } + + .steps { + grid-template-columns: 1fr; + } + + .security-panel-grid { + grid-template-columns: 1fr; + } + + .security-block { + border-right: none; + } + + .security-block--wide .security-list { + grid-template-columns: 1fr; + } + + .security-hub { + flex-direction: column; + gap: 10px; + } + + .editor-logos { + gap: 24px; + } + + .cta-box { + padding: 48px 20px; + } + + .cta-box h2 { + font-size: 24px; + } + + .platforms { + flex-wrap: wrap; + justify-content: center; + } + + .preview { + padding: 0 16px 60px; + margin-top: -20px; + } + + .tentacle-scene { + padding: 0 24px; + } + + .preview-window { + max-width: 96%; + } + + .t-left { + width: 180px; + left: -60px; + } + + .t-left2 { + width: 190px; + left: -60px; + } + + .t-right { + width: 140px; + right: -15px; + } + + .t-bl { + width: 150px; + bottom: -40px; + } + + .t-bottom { + width: 160px; + bottom: -25px; + } + + .t-top { + width: 90px; + top: -40px; + } +} + +@media (max-width: 480px) { + .t-left { + width: 120px; + left: -45px; + } + + .t-left2 { + width: 130px; + left: -45px; + } + + .t-right { + width: 100px; + right: -10px; + } + + .t-bl { + width: 110px; + bottom: -30px; + } + + .t-bottom { + width: 120px; + bottom: -20px; + } + + .t-top { + width: 70px; + top: -35px; + } + + .hero h1 { + font-size: 24px; + } + + .pain-grid { + grid-template-columns: 1fr; + } + + .pain-card { + padding: 18px; + } + + .nav-inner { + padding: 0 12px; + } + + .editor-logos { + gap: 16px; + } + + .hero-badge { + font-size: 11px; + padding: 6px 14px; + } +} + +@media (prefers-reduced-motion: reduce) { + #hero-canvas { + display: none; + } +} diff --git a/site/download.html b/site/download.html index b2db4c3..1bd1f92 100644 --- a/site/download.html +++ b/site/download.html @@ -7,9 +7,11 @@ - + + + diff --git a/site/index.html b/site/index.html index 231ec87..cd6a7e9 100644 --- a/site/index.html +++ b/site/index.html @@ -1,13 +1,14 @@ - + GitDock | Organize Git Projects, One Dashboard + - + @@ -17,18 +18,22 @@ - - - - - + + + + + - - + + + + + + + + -