diff --git a/web/static/logo.png b/web/static/logo.png new file mode 100644 index 0000000..01483e2 Binary files /dev/null and b/web/static/logo.png differ diff --git a/web/static/style.css b/web/static/style.css new file mode 100644 index 0000000..e5eb7dd --- /dev/null +++ b/web/static/style.css @@ -0,0 +1,924 @@ +:root { + --bg-color: #09090b; + --card-bg: #18181b; + --border-color: #27272a; + --accent-color: #6366f1; + --accent-hover: #4f46e5; + --text-primary: #f4f4f5; + --text-secondary: #a1a1aa; + --text-muted: #71717a; + + --nav-height: 0px; + /* -------------------------------------------------------------------------- */ + /* Sidebar */ + /* -------------------------------------------------------------------------- */ + --sidebar-width: 290px; +} + +/* -------------------------------------------------------------------------- */ +/* Base Styles */ +/* -------------------------------------------------------------------------- */ +/* Modern Aesthetics - GitHub Layout */ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + background-color: var(--bg-color); + color: var(--text-primary); + font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; + line-height: 1.6; + display: flex; + flex-direction: column; + min-height: 100vh; +} + +a { + color: inherit; + text-decoration: none; + transition: color 0.2s; +} + +a:hover { + color: var(--accent-color); +} + +.footer { + text-align: center; + padding: 2rem; + color: var(--text-muted); + font-size: 0.85rem; + border-top: 1px solid var(--border-color); + margin-top: 3rem; + background: var(--bg-color); +} + +/* -------------------------------------------------------------------------- */ +/* Main Layout Grid */ +/* -------------------------------------------------------------------------- */ +.container { + max-width: 1280px; + width: 100%; + margin: 0 auto; + padding: 2rem; + display: grid; + grid-template-columns: var(--sidebar-width) 1fr; + gap: 3rem; + flex: 1; +} + +@media (max-width: 768px) { + .container { + grid-template-columns: 1fr; + gap: 2rem; + } +} + +.sidebar { + position: sticky; + top: calc(var(--nav-height) + 2rem); + height: fit-content; +} + +@media (max-width: 768px) { + .sidebar { + position: static; + margin-bottom: 2rem; + } +} + +.avatar-wrapper { + width: 100%; + aspect-ratio: 1/1; + border-radius: 50%; + border: 2px solid var(--border-color); + overflow: hidden; + margin-bottom: 1.5rem; + background-color: var(--card-bg); +} + +.avatar-wrapper img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.profile-names { + margin-bottom: 1rem; +} + +.full-name { + font-size: 1.75rem; + font-weight: 800; + line-height: 1.2; + display: block; +} + +.username { + font-size: 1.25rem; + color: var(--text-secondary); + font-weight: 400; + display: block; +} + +.bio { + font-size: 1rem; + color: var(--text-primary); + margin-bottom: 1.5rem; +} + +.btn-edit { + width: 100%; + padding: 0.6rem; + background: transparent; + border: 1px solid var(--border-color); + border-radius: 8px; + color: var(--text-primary); + font-weight: 600; + cursor: pointer; + transition: all 0.2s; + text-align: center; + display: block; +} + +.btn-edit:hover { + background: var(--border-color); + border-color: var(--text-secondary); +} + +.profile-details { + margin-top: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.detail-item { + display: flex; + align-items: center; + gap: 0.75rem; + color: var(--text-secondary); + font-size: 0.9rem; +} + +.detail-item svg { + width: 16px; + height: 16px; + fill: currentColor; +} + +/* -------------------------------------------------------------------------- */ +/* Main Content */ +/* -------------------------------------------------------------------------- */ +.main-content { + min-width: 0; +} + +/* -------------------------------------------------------------------------- */ +/* Settings Page */ +/* -------------------------------------------------------------------------- */ +.settings-nav { + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.settings-nav-item { + padding: 0.5rem 1rem; + border-radius: 6px; + color: var(--text-primary); + font-size: 0.9rem; + font-weight: 500; + transition: background 0.2s; + cursor: pointer; +} + +.settings-nav-item:hover { + background: var(--card-bg); + text-decoration: none; +} + +.settings-nav-item.active { + background: var(--card-bg); + font-weight: 600; + border-left: 3px solid var(--accent-color); + border-radius: 0 6px 6px 0; +} + +.settings-nav-item.disabled { + color: var(--text-muted); + cursor: default; +} + +.settings-nav-item.disabled:hover { + background: transparent; +} + +.tabs-nav { + display: flex; + border-bottom: 1px solid var(--border-color); + margin-bottom: 2rem; + gap: 2rem; + position: sticky; + top: 0; + background: var(--bg-color); + z-index: 100; + padding-top: 1rem; + overflow-x: auto; + /* Allow horizontal scrolling */ + white-space: nowrap; + /* Prevent wrapping */ + -webkit-overflow-scrolling: touch; + /* Smooth scrolling on iOS */ +} + +/* Hide scrollbar for cleaner look but keep functionality */ +.tabs-nav::-webkit-scrollbar { + display: none; +} + +.tabs-nav { + -ms-overflow-style: none; + /* IE and Edge */ + scrollbar-width: none; + /* Firefox */ +} + +.tab-link { + padding: 0.75rem 0; + font-weight: 600; + color: var(--text-secondary); + border-bottom: 2px solid transparent; + transition: all 0.2s; + display: flex; + align-items: center; + gap: 8px; +} + +.tab-link:hover { + color: var(--text-primary); +} + +.tab-link.active { + color: var(--text-primary); + border-bottom-color: var(--accent-color); +} + +.badge { + background: var(--card-bg); + padding: 2px 8px; + border-radius: 12px; + font-size: 0.75rem; + border: 1px solid var(--border-color); +} + +.section-title { + font-size: 1rem; + font-weight: 600; + margin-bottom: 1rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +/* -------------------------------------------------------------------------- */ +/* Repository Cards */ +/* -------------------------------------------------------------------------- */ +.repo-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.5rem; +} + +@media (max-width: 768px) { + .repo-grid { + grid-template-columns: 1fr; + } +} + +.repo-card { + background: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: 10px; + padding: 1.25rem; + display: flex; + flex-direction: column; + transition: transform 0.2s, border-color 0.2s; +} + +.repo-card:hover { + transform: translateY(-2px); + border-color: var(--accent-color); +} + +.repo-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 0.5rem; +} + +.repo-name { + font-weight: 700; + color: var(--accent-color); + font-size: 1.1rem; +} + +.repo-tag { + font-size: 0.7rem; + border: 1px solid var(--border-color); + padding: 2px 8px; + border-radius: 12px; + color: var(--text-secondary); +} + +.repo-desc { + font-size: 0.9rem; + color: var(--text-secondary); + flex: 1; + margin-bottom: 1rem; + line-height: 1.5; +} + +.repo-meta { + display: flex; + align-items: center; + gap: 1rem; + font-size: 0.8rem; + color: var(--text-muted); +} + +.lang-circle { + width: 10px; + height: 10px; + border-radius: 50%; + display: inline-block; + background: var(--accent-color); + margin-right: 4px; +} + +/* -------------------------------------------------------------------------- */ +/* Forms */ +/* -------------------------------------------------------------------------- */ +.center-wrapper { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 1rem; +} + +.form-card { + background: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: 16px; + padding: 2.5rem; + width: 100%; + max-width: 480px; +} + +.form-group { + margin-bottom: 1.5rem; +} + +.form-group label { + display: block; + font-size: 0.9rem; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.form-control { + width: 100%; + padding: 0.75rem; + background: var(--bg-color); + border: 1px solid var(--border-color); + border-radius: 8px; + color: var(--text-primary); + font-family: inherit; + transition: all 0.2s; +} + +.form-control:focus { + outline: none; + border-color: var(--accent-color); + box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2); +} + +.btn-primary { + width: 100%; + padding: 0.8rem; + background: var(--accent-color); + color: var(--btn-text, white); + border: none; + border-radius: 8px; + font-weight: 600; + cursor: pointer; + font-size: 1rem; + transition: all 0.2s; +} + +.btn-primary:hover { + color: var(--btn-text, white) !important; + background: var(--accent-color); +} + +/* -------------------------------------------------------------------------- */ +/* Avatar Upload */ +/* -------------------------------------------------------------------------- */ +.upload-avatar-preview { + width: 100px; + height: 100px; + border-radius: 50%; + border: 2px dashed var(--border-color); + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto 1rem; + overflow: hidden; + cursor: pointer; +} + +.upload-avatar-preview:hover { + border-color: var(--accent-color); +} + +.upload-avatar-preview img { + width: 100%; + height: 100%; + object-fit: cover; +} + +/* -------------------------------------------------------------------------- */ +/* Markdown / Readme */ +/* -------------------------------------------------------------------------- */ +.readme-content { + padding: 2rem; + background: var(--bg-color); + border: 1px solid var(--border-color); + border-radius: 6px; + margin-bottom: 2rem; + overflow-wrap: break-word; + word-wrap: break-word; +} + +.readme-content img { + max-width: 100%; + height: auto; + display: inline-block; + vertical-align: middle; + margin: 1rem 0; +} + +.readme-content pre { + background: #1e1e1e; + padding: 1rem; + border-radius: 6px; + overflow-x: auto; +} + +.readme-header { + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--border-color); + background: var(--card-bg); + font-weight: 600; + display: flex; + align-items: center; + border-radius: 6px 6px 0 0; +} + +/* -------------------------------------------------------------------------- */ +/* Setup Page */ +/* -------------------------------------------------------------------------- */ +.setup-container { + max-width: 800px; + display: flex; + gap: 2rem; + align-items: stretch; + padding: 2rem; + width: 90%; +} + +.setup-column { + flex: 1; + display: flex; + flex-direction: column; +} + +.setup-divider { + width: 1px; + background: var(--border-color); + position: relative; + display: flex; + align-items: center; + justify-content: center; +} + +.setup-divider span { + background: var(--card-bg); + padding: 0.5rem; + color: var(--text-muted); + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 1px; +} + +.avatar-preview-box { + width: 80px; + height: 80px; + border-radius: 50%; + background: var(--bg-color); + border: 1px dashed var(--border-color); + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} + +/* -------------------------------------------------------------------------- */ +/* Loading Overlay */ +/* -------------------------------------------------------------------------- */ +.loading-overlay { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--bg-color); + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 2000; +} + +.loading-content { + width: 400px; + max-width: 90%; + text-align: center; +} + +.progress-track { + background: var(--card-bg); + height: 8px; + width: 100%; + border-radius: 4px; + overflow: hidden; + position: relative; +} + +.progress-bar { + background: var(--accent-color); + height: 100%; + width: 0%; + transition: width 0.3s ease; +} + +.progress-meta { + display: flex; + justify-content: space-between; + margin-top: 0.5rem; + font-size: 0.8rem; + color: var(--text-muted); +} + +@keyframes pulse { + 0% { + opacity: 1; + transform: scale(1); + } + + 50% { + opacity: 0.7; + transform: scale(0.95); + } + + 100% { + opacity: 1; + transform: scale(1); + } +} + +.animate-pulse { + animation: pulse 2s infinite; +} + +.avatar-placeholder { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + font-size: 4rem; + background: #27272a; + color: #71717a; +} + +.empty-state-card { + grid-column: 1 / -1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 3rem; + border-style: dashed; + color: var(--text-muted); +} + +.search-bar-container { + display: flex; + gap: 0.5rem; + margin-bottom: 1rem; +} + +.empty-repos-container { + text-align: center; + padding: 4rem 0; +} + +.footer-icon { + display: inline-block; + width: 20px; + height: 20px; + background-color: var(--text-muted); + -webkit-mask: url(/static/logo.png) no-repeat center; + mask: url(/static/logo.png) no-repeat center; + -webkit-mask-size: contain; + mask-size: contain; + vertical-align: middle; + margin: 0 -4px; +} + +/* -------------------------------------------------------------------------- */ +/* Contribution Graph */ +/* -------------------------------------------------------------------------- */ +.contribution-graph-container { + border: 1px solid var(--border-color); + border-radius: 6px; + padding: 1rem; + background: var(--bg-color); +} + +.calendar-graph { + margin: 0 auto; + width: 100%; + overflow-x: auto; +} + +.contrib-grid { + display: grid; + grid-template-rows: repeat(7, 10px); + grid-auto-flow: column; + gap: 3px; + width: max-content; +} + +.contrib-day { + width: 10px; + height: 10px; + border-radius: 2px; + background-color: var(--card-bg); + outline: 1px solid rgba(255, 255, 255, 0.05); + outline-offset: -1px; +} + +.contrib-level-0 { + background-color: var(--card-bg); +} + +.contrib-level-1 { + background-color: var(--accent-color); + opacity: 0.2; +} + +.contrib-level-2 { + background-color: var(--accent-color); + opacity: 0.4; +} + +.contrib-level-3 { + background-color: var(--accent-color); + opacity: 0.6; +} + +.contrib-level-4 { + background-color: var(--accent-color); + opacity: 1.0; +} + +.contrib-footer { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 5px; + font-size: 0.75rem; + color: var(--text-muted); + margin-top: 5px; +} + +.contrib-legend { + display: flex; + gap: 2px; +} + +.graph-tooltip { + position: fixed; + background: rgba(0, 0, 0, 0.8); + color: white; + padding: 0.4rem 0.8rem; + border-radius: 4px; + font-size: 0.75rem; + pointer-events: none; + z-index: 1000; + display: none; + white-space: nowrap; +} + +.activity-layout { + display: flex; + gap: 2rem; + margin-top: 2rem; + align-items: flex-start; +} + +.activity-content { + flex: 1; +} + +.year-sidebar { + width: 150px; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.year-btn { + display: block; + padding: 8px 16px; + font-size: 14px; + color: var(--text-muted); + text-decoration: none; + border-radius: 6px; + transition: background-color 0.2s, color 0.2s; +} + +.year-btn:hover { + background-color: var(--bg-body); + color: var(--text-primary); +} + +.year-btn.active { + background-color: var(--accent-color); + color: white; + font-weight: 600; +} + +.activity-header { + border-bottom: 1px solid var(--border-color); + padding-bottom: 0.5rem; + margin-bottom: 1rem; + font-weight: 600; + font-size: 1.1rem; +} + +.activity-timeline { + position: relative; + padding-left: 2rem; + border-left: 2px solid var(--border-color); + margin-left: 16px; + padding-bottom: 2rem; +} + +.activity-month-group { + margin-bottom: 2rem; +} + +.activity-month { + font-size: 0.85rem; + color: var(--text-muted); + margin-bottom: 0.5rem; + position: relative; + left: -1.3rem; + background: var(--bg-body); + display: inline-block; + padding-right: 0.5rem; + line-height: 1; + margin-top: 0.5rem; +} + +.activity-entry { + position: relative; + margin-bottom: 1.5rem; +} + +.timeline-icon { + position: absolute; + left: -3rem; + top: 0; + width: 2rem; + height: 2rem; + background: var(--card-bg); + border: 2px solid var(--border-color); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-muted); + font-size: 1rem; + z-index: 2; +} + +.activity-details { + margin-top: 0.5rem; +} + +.activity-group-header { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 1rem; + font-weight: 500; + color: var(--text-primary); + margin-bottom: 0.5rem; +} + +.activity-group-header span { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.activity-list { + background: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: 6px; + padding: 0.5rem 0; +} + +.activity-list-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.5rem 1rem; + text-decoration: none; + color: inherit; + transition: background 0.1s; +} + +.activity-list-item:hover { + background: var(--bg-color); +} + +.activity-repo-name { + font-weight: 600; + color: var(--accent-color); +} + +.activity-stats { + display: flex; + align-items: center; + gap: 1rem; +} + +.activity-show-more { + margin-left: -2rem; + margin-top: 1rem; + text-align: left; + padding-left: 2rem; +} + +.btn-activity-toggle { + width: 100%; + padding: 0.5rem; + background: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: 6px; + color: var(--text-primary); + cursor: pointer; + font-size: 0.9rem; + font-weight: 600; + transition: background 0.2s; +} + +.btn-activity-toggle:hover { + background: var(--bg-color); +} + +@media (max-width: 768px) { + .activity-layout { + flex-direction: column-reverse; + } + + .year-sidebar { + width: 100%; + flex-direction: row; + overflow-x: auto; + padding-bottom: 0.5rem; + } + + .year-btn { + white-space: nowrap; + } +} \ No newline at end of file