diff --git a/assets/css/content.css b/assets/css/content.css new file mode 100644 index 0000000..58abe86 --- /dev/null +++ b/assets/css/content.css @@ -0,0 +1,383 @@ +/* ========================================= + GitHub "Pro" Blog Style Layout + ========================================= */ + +.single-post-gh-pro { + padding-bottom: 4rem; +} + +/* --- Pro Header (Clean Geek Style) --- */ +.gh-pro-header { + padding-bottom: 24px; + margin-bottom: 24px; + text-align: center; /* Center alignment looks more like a blog title */ +} + +.gh-pro-meta-top { + margin-bottom: 16px; +} + +.gh-label-category { + display: inline-block; + font-size: 13px; + font-weight: 600; + color: var(--color-primary); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.gh-pro-header .entry-title { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 16px; + line-height: 1.25; +} + +.gh-pro-meta-bar { + display: flex; + justify-content: center; + align-items: center; + gap: 24px; + font-size: 14px; + color: var(--text-secondary); + font-family: var(--font-mono); +} + +.gh-author-lockup { + display: flex; + align-items: center; + gap: 8px; +} + +.gh-author-lockup img { + width: 24px; + height: 24px; + border-radius: 50%; + border: 1px solid var(--border-muted); +} + +.gh-author-lockup .author-name { + font-weight: 600; + color: var(--text-primary); +} + +.meta-divider { + color: var(--border-default); +} + +/* --- File Box Body (The Article) --- */ +.gh-pro-body-container { + max-width: 900px; /* Slightly wider read area */ + margin: 0 auto 48px; +} + +.gh-file-box { + border: 1px solid var(--border-default); + border-radius: 6px; + background-color: var(--bg-card); + overflow: hidden; +} + +.gh-file-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 16px; + background-color: var(--bg-surface); + border-bottom: 1px solid var(--border-default); + font-family: var(--font-mono); + font-size: 13px; + color: var(--text-secondary); +} + +.gh-file-header .file-info { + display: flex; + align-items: center; + gap: 8px; +} + +.gh-file-header .octicon { + fill: currentColor; +} + +.gh-file-header strong { + color: var(--text-primary); + font-weight: 600; +} + +.gh-file-content { + padding: 32px 40px; + background-color: var(--bg-card); +} + +/* Entry Content Typography (Markdown Style) */ +.gh-file-content { + font-size: 16px; + line-height: 1.7; + color: var(--text-primary); + overflow-wrap: break-word; /* 自动换行 */ + word-wrap: break-word; +} + +.gh-file-content p { margin-bottom: 1.5em; } +.gh-file-content h2 { border-bottom: 1px solid var(--border-muted); padding-bottom: 0.3em; margin-top: 1.5em; margin-bottom: 1em; } +.gh-file-content code { background-color: rgba(175, 184, 193, 0.2); padding: 0.2em 0.4em; border-radius: 6px; font-size: 85%; font-family: var(--font-mono); } +.gh-file-content pre { padding: 16px; overflow: auto; line-height: 1.45; background-color: var(--bg-surface); border-radius: 6px; } + +.gh-file-footer { + margin-top: 32px; + padding-top: 16px; + border-top: 1px solid var(--border-muted); +} + +/* --- Comments Section (Pro Timeline) --- */ +.gh-pro-comments { + max-width: 900px; + margin: 0 auto; +} + +.timeline-header h3 { + font-size: 1.25rem; + margin-bottom: 24px; + border-bottom: 1px solid var(--border-default); + padding-bottom: 8px; +} + +/* Reuse existing gh-timeline styles from previous step but center align */ +.gh-timeline { + margin-top: 0; + margin-left: 0; /* Clear previous offset */ +} + +/* Vertical Timeline Line - NEW FIX */ +.gh-timeline::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 20px; /* Center of 40px avatar */ + width: 2px; + background-color: var(--border-muted); + z-index: 0; + display: block; /* Ensure it is displayed */ +} + +/* Fix z-index for items so line is behind */ +.gh-timeline-item { + position: relative; + z-index: 1; +} + +ol.comment-list { + list-style: none; /* 去掉列表默认样式 */ + padding: 0; + margin: 0; +} + +/* Timeline Item (Main Post & Comments) */ +.gh-timeline-item, +.gh-comment-item { + display: flex; + gap: 16px; + margin-bottom: 24px; + position: relative; + z-index: 1; +} + +/* Avatar Column */ +.gh-avatar, +.gh-comment-avatar { + flex-shrink: 0; + width: 40px; +} + +.gh-avatar img, +.gh-comment-avatar img { + width: 40px; + height: 40px; + border-radius: 50%; + border: 1px solid var(--border-muted); +} + +/* Content Box (Speech Bubble) */ +.gh-item-box, +.gh-comment-box { + flex-grow: 1; + min-width: 0; + border: 1px solid var(--border-default); + border-radius: 6px; + background-color: var(--bg-card); + position: relative; +} + +/* Speech Bubble Beak (Arrow) - Desktop Only */ +@media (min-width: 768px) { + .gh-item-box::before, .gh-item-box::after, + .gh-comment-box::before, .gh-comment-box::after { + content: " "; + position: absolute; + top: 11px; + right: 100%; + height: 0; + width: 0; + border: solid transparent; + pointer-events: none; + } + + .gh-item-box::after, + .gh-comment-box::after { + border-right-color: var(--bg-surface); /* Header BG color */ + border-width: 7px; + margin-top: -7px; + } + + .gh-item-box::before, + .gh-comment-box::before { + border-right-color: var(--border-default); + border-width: 8px; + margin-top: -8px; + } +} + +/* Box Header */ +.gh-box-header, +.gh-comment-header { + padding: 8px 16px; + background-color: var(--bg-surface); + border-bottom: 1px solid var(--border-default); + border-top-left-radius: 6px; + border-top-right-radius: 6px; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; + color: var(--text-secondary); +} + +.gh-header-meta { + display: flex; + align-items: center; + gap: 4px; + flex-wrap: wrap; +} + +.gh-comment-meta, +.gh-header-meta { + display: flex; + align-items: center; + gap: 4px; + flex-wrap: wrap; +} + +.gh-header-meta strong, +.gh-author-name a { + color: var(--text-primary); + font-weight: 600; + text-decoration: none; +} + +.gh-header-meta a, +.gh-comment-meta time, +.gh-comment-meta a { + color: var(--text-secondary); + text-decoration: none; + font-size: 0.85rem; +} + +.gh-header-meta a:hover, +.gh-comment-meta time:hover, +.gh-comment-meta a:hover { + color: var(--color-primary); + text-decoration: underline; +} + +/* Badge (Author/Member) */ +.gh-badge { + display: inline-block; + padding: 2px 7px; + font-size: 12px; + font-weight: 500; + line-height: 18px; + border-radius: 2em; + border: 1px solid var(--border-default); + color: var(--text-secondary); + margin-left: 8px; +} + +/* Box Body */ +.gh-box-body, +.gh-comment-body { + padding: 16px; + background-color: var(--bg-card); + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + overflow-wrap: break-word; +} + +.gh-box-body .entry-content, +.gh-comment-body { + font-size: 15px; + line-height: 1.6; +} + +/* Comment Form Styles */ +.gh-comment-form textarea { + display: block; + width: 100%; + padding: 8px 12px; + border: 1px solid var(--border-default); + border-radius: 6px; + background-color: var(--bg-surface); + color: var(--text-primary); + font-family: inherit; + resize: vertical; + min-height: 100px; +} + +.gh-comment-form textarea:focus { + border-color: var(--color-primary); + outline: none; + box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.3); +} + +.form-submit { + text-align: right; + margin-top: 10px; +} + +.gh-comment-form input[type="submit"] { + background-color: var(--color-success); + color: #fff; + border: 1px solid rgba(27, 31, 36, 0.15); + border-radius: 6px; + padding: 5px 16px; + font-size: 14px; + font-weight: 600; + cursor: pointer; +} + +.gh-comment-form input[type="submit"]:hover { + background-color: #2c974b; +} + +/* Buttons */ +.btn-sm { + font-size: 12px; + padding: 3px 8px; + border: 1px solid var(--border-default); + border-radius: 6px; + color: var(--text-secondary); + background-color: var(--bg-body); + font-weight: 500; +} +.btn-sm:hover { + background-color: var(--bg-surface); + color: var(--color-primary); + text-decoration: none; +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + .gh-file-content { padding: 20px; } + .gh-pro-header .entry-title { font-size: 1.75rem; } +} diff --git a/assets/css/footer.css b/assets/css/footer.css new file mode 100644 index 0000000..d2ca653 --- /dev/null +++ b/assets/css/footer.css @@ -0,0 +1,66 @@ +/* ========================================= + 页脚布局 (Footer) + ========================================= */ + +.site-footer { + background-color: var(--bg-surface); + border-top: 1px solid var(--border-default); + padding: 4rem 0 2rem; + margin-top: auto; /* 确保置底 */ + flex-shrink: 0; /* 防止Footer被压缩 */ +} + +/* --- 页脚内容网格 --- */ +.footer-content { + display: grid; + grid-template-columns: repeat(4, 1fr); /* 4列布局 */ + gap: 2rem; + margin-bottom: 3rem; +} + +.footer-section h3 { + font-size: 1rem; + font-weight: 600; + margin-bottom: 1rem; + color: var(--text-primary); +} + +.footer-links li { + margin-bottom: 0.5rem; +} + +.footer-links a { + color: var(--text-secondary); + font-size: 0.9rem; +} + +.footer-links a:hover { + color: var(--color-primary); + text-decoration: underline; +} + +/* --- 底部版权区 --- */ +.footer-bottom { + border-top: 1px solid var(--border-muted); + padding-top: 2rem; + text-align: center; + color: var(--text-secondary); + font-size: 0.85rem; +} + +/* --- 响应式适配 --- */ +@media (max-width: 768px) { + .footer-content { + grid-template-columns: repeat(2, 1fr); /* 平板 2列 */ + } +} + +@media (max-width: 480px) { + .footer-content { + grid-template-columns: 1fr; /* 手机 1列 */ + } + + .site-footer { + padding: 3rem 0 1.5rem; + } +} diff --git a/assets/css/front-page.css b/assets/css/front-page.css new file mode 100644 index 0000000..6ff7221 --- /dev/null +++ b/assets/css/front-page.css @@ -0,0 +1,158 @@ +/* ========================================= + 首页独有样式 (Front Page / Hero) + ========================================= */ + +/* --- Hero 区域 --- */ +.hero-section { + padding: 120px 0 80px; + background-color: var(--bg-body); + position: relative; + overflow: hidden; + + /* 科技网格背景 */ + background-image: + linear-gradient(var(--border-muted) 1px, transparent 1px), + linear-gradient(90deg, var(--border-muted) 1px, transparent 1px); + background-size: 40px 40px; + background-position: center top; +} + +/* 底部渐变遮罩 */ +.hero-section::after { + content: ""; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 120px; + background: linear-gradient(to bottom, transparent, var(--bg-body)); + pointer-events: none; +} + +.hero-content { + max-width: 800px; + margin: 0 auto; + text-align: center; + position: relative; + z-index: 1; +} + +/* 大标题 */ +.hero-content h1 { + font-size: 3.5rem; + font-weight: 800; + letter-spacing: -0.02em; + margin-bottom: 1.5rem; + background: linear-gradient(135deg, var(--text-primary) 0%, var(--color-primary) 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + line-height: 1.2; +} + +/* 描述文本 (代码风格) */ +.hero-description { + font-size: 1.25rem; + color: var(--text-secondary); + margin-bottom: 3rem; + font-family: var(--font-mono); + min-height: 3.6em; /* 预留高度防止抖动 */ +} + +/* --- 流式输出字符样式 --- */ +.stream-char { + transition: opacity 0.4s ease; /* 平滑淡入 */ +} + +/* --- 服务展示区 (Services) --- */ +.services-provided { + margin-top: 5rem; + position: relative; + z-index: 2; +} + +/* 标题带有命令提示符风格 */ +.services-provided h2 { + font-size: 1.5rem; + margin-bottom: 1.5rem; + padding-bottom: 1rem; + border-bottom: none; + color: var(--text-primary); + display: flex; /* 改为 flex 以支持全宽下划线 */ + align-items: center; +} + +.services-provided h2::before { + content: "$"; + color: var(--color-primary); /* 统一使用蓝色,保持与 blog h2 风格一致 */ + margin-right: 10px; /* 保持与 blog h2 一致的间距 */ + font-family: var(--font-mono); + font-weight: 800; +} + +/* 服务卡片网格 */ +.services-grid-box { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 24px; + padding: 0 10px; +} + +.service-item { + background: var(--bg-card); + border: 1px solid var(--border-default); + border-radius: var(--radius-md); + padding: 32px 24px; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + transition: all var(--duration-fast); + text-decoration: none; +} + +.service-item:hover { + transform: translateY(-4px); + border-color: var(--color-primary-light); + box-shadow: var(--shadow-lg); +} + +.service-icon { + margin-bottom: 1.5rem; + color: var(--color-primary); + /* 确保 SVG 继承颜色 */ +} + +.service-icon svg { + width: 80px; + height: 80px; + display: block; +} + +.service-item span { + font-weight: 600; + color: var(--text-primary); + font-size: 1.1rem; +} + +/* --- 响应式适配 --- */ +@media (max-width: 1100px) { + .services-grid-box { + grid-template-columns: repeat(2, 1fr); /* 平板/小屏变 2 列 */ + } +} + +@media (max-width: 768px) { + .hero-content h1 { + font-size: 2.25rem; + } + + .hero-description { + font-size: 1rem; + } +} + +@media (max-width: 600px) { + .services-grid-box { + grid-template-columns: 1fr; /* 手机端单列 */ + } +} diff --git a/assets/css/header.css b/assets/css/header.css new file mode 100644 index 0000000..d88494b --- /dev/null +++ b/assets/css/header.css @@ -0,0 +1,244 @@ +/* ========================================= + 页眉布局 (Header & Navigation) + ========================================= */ + +.site-header { + height: 70px; + background-color: var(--bg-body); + border-bottom: 1px solid var(--border-muted); + position: sticky; /* 粘性定位,确保始终置顶 */ + top: 0; + z-index: 1000; + backdrop-filter: blur(12px); /* 毛玻璃效果 */ + -webkit-backdrop-filter: blur(12px); + /* 使用半透明背景以增强毛玻璃效果 */ + background-color: rgba(255, 255, 255, 0.85); + transition: background-color var(--duration-normal), border-color var(--duration-normal); + flex-shrink: 0; /* 防止被父容器 Flex 布局压缩 */ +} + +.site-header .container { + height: 100%; /* 关键修复:让容器撑满 Header 高度,使内部 flex 垂直居中生效 */ +} + +[data-theme="dark"] .site-header { + background-color: rgba(13, 17, 23, 0.85); +} + +.header-content { + display: flex; + justify-content: space-between; + align-items: center; + height: 100%; +} + +/* --- Logo 区域 --- */ +.logo-container, +.logo-link { + display: flex; + align-items: center; + height: 100%; +} + +.logo-main { + height: 52px; /* 增大 Logo 尺寸 */ + width: auto; + color: var(--text-primary); +} + +/* --- 主导航 (Navigation) --- */ +.main-navigation { + display: flex; + align-items: center; + gap: 24px; +} + +.nav-menu { + display: flex; + list-style: none; + gap: 8px; /* 菜单项间距 */ + margin: 0; + padding: 0; +} + +.nav-menu a { + color: var(--text-secondary); + font-weight: 500; + font-size: 15px; + padding: 8px 16px; + border-radius: var(--radius-sm); + transition: all var(--duration-fast); + display: flex; + align-items: center; +} + +.nav-menu a:hover, +.nav-menu a:focus { + color: var(--text-primary); + background-color: var(--bg-surface); +} + +/* --- 社交链接与工具 (Social & Tools) --- */ +.social-links { + display: flex; + align-items: center; + gap: 12px; + padding-left: 12px; + margin-left: 12px; + border-left: 1px solid var(--border-muted); +} + +.social-links a, +.theme-toggle, +.lang-toggle { + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-secondary); + background: transparent; + border: 1px solid transparent; /* 预留边框位置防止抖动 */ + border-radius: var(--radius-sm); + cursor: pointer; + transition: all var(--duration-fast); +} + +.social-links a:hover, +.theme-toggle:hover, +.lang-toggle:hover { + background-color: var(--bg-surface); + color: var(--color-primary); + border-color: var(--border-default); +} + +/* --- 主题切换动画 (Theme Toggle) --- */ +.theme-toggle { + position: relative; /* 为内部 SVG 绝对定位做准备 */ + overflow: hidden; +} + +.theme-toggle svg { + position: absolute; + transition: transform 0.5s var(--ease-in-out), opacity 0.5s; +} + +/* 默认 / 浅色模式状态: 显示月亮 (提示切换到深色) */ +/* 修正逻辑:通常浅色模式下,按钮为了表示“点击切换到深色”,会显示月亮; + 但也有一种逻辑是显示“当前是太阳”。 + 根据之前的代码意图,我们从 CSS 变量来看: + 浅色模式下,.moon-icon 显示,.sun-icon 隐藏 */ + +/* 浅色模式下:太阳隐藏 */ +html:not([data-theme="dark"]) .sun-icon { + opacity: 0; + transform: rotate(90deg) scale(0); +} + +/* 浅色模式下:月亮显示 */ +html:not([data-theme="dark"]) .moon-icon { + opacity: 1; + transform: rotate(0) scale(1); +} + +/* 深色模式下:太阳显示 */ +[data-theme="dark"] .sun-icon { + opacity: 1; + transform: rotate(0) scale(1); +} + +/* 深色模式下:月亮隐藏 */ +[data-theme="dark"] .moon-icon { + opacity: 0; + transform: rotate(-90deg) scale(0); +} + +/* 语言切换按钮文字 */ +.lang-toggle { + font-weight: 600; + font-size: 14px; + width: auto; + padding: 0 10px; +} + +/* --- 移动端菜单开关 (Hamburger) --- */ +.mobile-menu-toggle { + display: none; /* 默认隐藏 */ + flex-direction: column; + justify-content: space-between; + width: 24px; + height: 18px; + background: transparent; + border: none; + cursor: pointer; + z-index: 1100; + padding: 0; +} + +.mobile-menu-toggle span { + display: block; + width: 100%; + height: 2px; + background-color: var(--text-secondary); + border-radius: 2px; + transition: all 0.3s var(--ease-in-out); + transform-origin: left center; +} + +/* 激活状态 (X 形状) */ +.mobile-menu-toggle.active span:nth-child(1) { + transform: rotate(45deg) translate(0px, -2px); + width: 115%; +} +.mobile-menu-toggle.active span:nth-child(2) { + opacity: 0; + transform: translateX(-10px); +} +.mobile-menu-toggle.active span:nth-child(3) { + transform: rotate(-45deg) translate(0px, 2px); + width: 115%; +} + +/* --- 响应式适配 --- */ +@media (max-width: 900px) { + .mobile-menu-toggle { + display: flex; + } + + .nav-menu { + position: absolute; + top: 100%; + left: 0; + right: 0; + background-color: var(--bg-body); + border-bottom: 1px solid var(--border-default); + flex-direction: column; + padding: 1rem; + gap: 0; + + /* 默认收起状态 */ + opacity: 0; + transform: translateY(-10px); + pointer-events: none; + transition: all var(--duration-normal) var(--ease-in-out); + box-shadow: var(--shadow-md); + } + + .nav-menu.active { + opacity: 1; + transform: translateY(0); + pointer-events: auto; + } + + .nav-menu a { + width: 100%; + padding: 12px 16px; + justify-content: flex-start; + } + + /* 移动端隐藏社交分割线 */ + .social-links { + border-left: none; + margin-left: auto; /* 推到右侧 */ + } +} diff --git a/assets/css/main.css b/assets/css/main.css deleted file mode 100644 index 5fab968..0000000 --- a/assets/css/main.css +++ /dev/null @@ -1,832 +0,0 @@ -.site-header { - background-color: var(--header-bg); - border-bottom: 1px solid var(--border-color); - position: absolute; - top: 0; - left: 0; - right: 0; - z-index: 1000; - transition: background-color var(--transition-speed), border-color var(--transition-speed); -} - -.site-header .container { - max-width: 100%; - padding: 0 40px; -} - -.header-content { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.75rem 0; - width: 100%; -} - -.logo-container { - display: flex; - align-items: center; - gap: 1rem; -} - -.logo-main { - height: 60px; - width: auto; - color: var(--text-color); -} - -.main-navigation { - display: flex; - align-items: center; - gap: 2rem; -} - -.nav-menu { - display: flex; - list-style: none; - gap: 2rem; - margin: 0; - padding: 0; -} - -.nav-menu a { - color: var(--text-color); - font-weight: 500; - transition: color var(--transition-speed); -} - -.nav-menu a:hover { - color: var(--accent-color); -} - -.social-links { - display: flex; - align-items: center; - gap: 1rem; -} - -.social-links a, -.theme-toggle, -.lang-toggle { - display: flex; - align-items: center; - justify-content: center; - width: 36px; - height: 36px; - color: var(--text-color); - background: transparent; - border: none; - cursor: pointer; - border-radius: 50%; - transition: background-color var(--transition-speed), color var(--transition-speed); -} - -.lang-toggle { - width: 40px; - font-weight: 600; - font-size: 14px; -} - -.social-links a:hover, -.theme-toggle:hover, -.lang-toggle:hover { - background-color: var(--gray-200); -} - -[data-theme="dark"] .social-links a:hover, -[data-theme="dark"] .theme-toggle:hover, -[data-theme="dark"] .lang-toggle:hover { - background-color: var(--gray-700); -} - -.theme-toggle .sun-icon { - display: none; -} - -.theme-toggle .moon-icon { - display: block; -} - -[data-theme="dark"] .theme-toggle .sun-icon { - display: block; -} - -[data-theme="dark"] .theme-toggle .moon-icon { - display: none; -} - -.mobile-menu-toggle { - display: none; - flex-direction: column; - gap: 4px; - background: transparent; - border: none; - cursor: pointer; - padding: 8px; -} - -.mobile-menu-toggle span { - display: block; - width: 24px; - height: 2px; - background-color: var(--text-color); - transition: all var(--transition-speed); -} - -.hero-section { - padding: 4rem 0; - text-align: center; -} - -.hero-content h1 { - font-size: 3rem; - margin-bottom: 1.5rem; - color: var(--accent-color); -} - -body[lang="en"] .hero-content h1::before { - content: attr(data-en); -} - -body:not([lang="en"]) .hero-content h1::before { - content: attr(data-cn); -} - -.hero-content h1 { - font-size: 0; -} - -.hero-content h1::before { - font-size: 3rem; -} - -.hero-description { - font-size: 1.125rem; - line-height: 1.8; - max-width: 800px; - margin: 0 auto; - color: var(--text-color); -} - -body[lang="en"] .hero-description::before { - content: attr(data-en); -} - -body:not([lang="en"]) .hero-description::before { - content: attr(data-cn); -} - -.hero-description { - font-size: 0; -} - -.hero-description::before { - font-size: 1.125rem; -} - -.services-provided { - margin-top: 4rem; - margin-bottom: 2rem; -} - -.services-provided h2 { - font-size: 1.75rem; - margin-bottom: 1.5rem; - color: var(--text-color); - text-align: left; -} - -body[lang="en"] .services-provided h2::before { - content: attr(data-en); -} - -body:not([lang="en"]) .services-provided h2::before { - content: attr(data-cn); -} - -.services-provided h2 { - font-size: 0; -} - -.services-provided h2::before { - font-size: 1.75rem; -} - -.services-grid-box { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 2rem; -} - -.service-item { - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - padding: 1.5rem; - text-decoration: none; -} - - -.service-icon { - margin-bottom: 1rem; -} - -.service-icon svg { - width: 96px; - height: 96px; -} - -.service-item span { - font-size: 1.5rem; - font-weight: 500; - color: var(--text-color); -} - -body[lang="en"] .service-item span::before { - content: attr(data-en); -} - -body:not([lang="en"]) .service-item span::before { - content: attr(data-cn); -} - -.service-item span { - font-size: 0; -} - -.service-item span::before { - font-size: 1.5rem; -} - -@media (max-width: 1024px) { - .services-grid-box { - grid-template-columns: repeat(3, 1fr); - gap: 1.5rem; - } -} - -@media (max-width: 768px) { - .services-grid-box { - grid-template-columns: repeat(2, 1fr); - gap: 1rem; - } - - .service-icon svg { - width: 80px; - height: 80px; - } -} - -@media (max-width: 480px) { - .services-grid-box { - grid-template-columns: 1fr; - } -} - -.content-section { - padding: 3rem 0; -} - -.content-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 3rem; -} - -.announcements-column h2, -.blog-column h2 { - font-size: 1.75rem; - margin-bottom: 1.5rem; - color: var(--text-color); -} - -body[lang="en"] .nav-menu a::before, -body[lang="en"] h2[data-en]::before { - content: attr(data-en); -} - -body:not([lang="en"]) .nav-menu a::before, -body:not([lang="en"]) h2[data-cn]::before { - content: attr(data-cn); -} - -.nav-menu a { - font-size: 0; -} - -.nav-menu a::before { - font-size: 1rem; -} - -.post-list { - display: flex; - flex-direction: column; - gap: 1.25rem; -} - -.post-item { - padding: 1.25rem; - background-color: var(--header-bg); - border-radius: 8px; - border: 1px solid var(--border-color); - transition: transform var(--transition-speed), box-shadow var(--transition-speed); -} - -.post-item:hover { - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -.post-item h3 { - font-size: 1.125rem; - margin-bottom: 0.5rem; -} - -.post-item h3 a { - color: var(--text-color); -} - -.post-item time { - font-size: 0.875rem; - color: var(--gray-500); -} - -.site-main { - background-color: var(--bg-color); - flex: 1; - min-height: calc(100vh - 100px); - padding-top: 70px; -} - -.site-footer { - background-color: var(--footer-bg); - border-top: 1px solid var(--border-color); - padding: 3rem 0 1.5rem; - margin-top: 4rem; -} - -.footer-content { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 2rem; - margin-bottom: 2rem; -} - -.footer-section h3 { - font-size: 1.125rem; - margin-bottom: 1rem; - color: var(--text-color); -} - -body[lang="en"] .footer-section h3::before { - content: attr(data-en); -} - -body:not([lang="en"]) .footer-section h3::before { - content: attr(data-cn); -} - -.footer-section h3 { - font-size: 0; -} - -.footer-section h3::before { - font-size: 1.125rem; -} - -.footer-links { - list-style: none; -} - -.footer-links li { - margin-bottom: 0.5rem; -} - -.footer-links a { - color: var(--text-color); - font-size: 0.9rem; -} - -body[lang="en"] .footer-links a::before { - content: attr(data-en); -} - -body:not([lang="en"]) .footer-links a::before { - content: attr(data-cn); -} - -.footer-links a[data-cn] { - font-size: 0; -} - -.footer-links a[data-cn]::before { - font-size: 0.9rem; -} - -.footer-bottom { - text-align: center; - padding-top: 2rem; - border-top: 1px solid var(--border-color); -} - -.footer-bottom p { - font-size: 0.875rem; - color: var(--gray-500); -} - -body[lang="en"] .footer-bottom p::before { - content: attr(data-en); -} - -body:not([lang="en"]) .footer-bottom p::before { - content: attr(data-cn); -} - -.footer-bottom p { - font-size: 0; -} - -.footer-bottom p::before { - font-size: 0.875rem; -} - -@media (max-width: 1024px) { - .nav-menu { - gap: 1.5rem; - } - - .content-grid { - gap: 2rem; - } - - .footer-content { - grid-template-columns: repeat(2, 1fr); - } -} - -@media (max-width: 768px) { - .mobile-menu-toggle { - display: flex; - } - - .site-header .container { - padding: 0 20px; - } - - .main-navigation { - position: relative; - } - - .nav-menu { - position: absolute; - top: 100%; - right: 0; - background-color: var(--header-bg); - flex-direction: column; - padding: 1rem; - border-radius: 8px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - display: none; - min-width: 200px; - } - - .nav-menu.active { - display: flex; - } - - .hero-content h1 { - font-size: 2rem; - } - - .hero-description { - font-size: 1rem; - } - - .content-grid { - grid-template-columns: 1fr; - gap: 2rem; - } - - .footer-content { - grid-template-columns: 1fr; - gap: 1.5rem; - } -} - -@media (max-width: 480px) { - .logo-main { - height: 50px; - } - - .hero-content h1 { - font-size: 1.5rem; - } - - .social-links a, - .theme-toggle { - width: 32px; - height: 32px; - } -} - -.single-post, -.page-content { - padding: 3rem 0; -} - -.entry-header { - margin-bottom: 2rem; - padding-bottom: 1.5rem; - border-bottom: 1px solid var(--border-color); -} - -.entry-title { - font-size: 2.5rem; - line-height: 1.2; - margin-bottom: 1rem; - color: var(--text-color); -} - -.entry-meta { - font-size: 0.9rem; - color: var(--gray-500); -} - -.entry-meta .separator { - margin: 0 0.5rem; -} - -.entry-thumbnail { - margin-bottom: 2rem; -} - -.entry-thumbnail img { - width: 100%; - height: auto; - border-radius: 8px; -} - -.entry-content { - font-size: 1.125rem; - line-height: 1.8; - color: var(--text-color); -} - -.entry-content h2, -.entry-content h3, -.entry-content h4 { - margin-top: 2rem; - margin-bottom: 1rem; - color: var(--text-color); -} - -.entry-content p { - margin-bottom: 1.5rem; -} - -.entry-content a { - color: var(--accent-color); - text-decoration: underline; -} - -.entry-content img { - max-width: 100%; - height: auto; - border-radius: 8px; - margin: 1.5rem 0; -} - -.entry-content ul, -.entry-content ol { - margin-bottom: 1.5rem; - padding-left: 2rem; -} - -.entry-content li { - margin-bottom: 0.5rem; -} - -.entry-content code { - background-color: var(--gray-200); - padding: 0.2rem 0.4rem; - border-radius: 4px; - font-size: 0.9em; - font-family: 'Consolas', 'Monaco', monospace; -} - -[data-theme="dark"] .entry-content code { - background-color: var(--gray-700); -} - -.entry-content pre { - background-color: var(--gray-200); - padding: 1rem; - border-radius: 8px; - overflow-x: auto; - margin-bottom: 1.5rem; -} - -[data-theme="dark"] .entry-content pre { - background-color: var(--gray-800); -} - -.entry-content pre code { - background-color: transparent; - padding: 0; -} - -.entry-footer { - margin-top: 3rem; - padding-top: 2rem; - border-top: 1px solid var(--border-color); -} - -.entry-categories, -.entry-tags { - margin-bottom: 1rem; -} - -.entry-categories a, -.entry-tags a { - display: inline-block; - padding: 0.25rem 0.75rem; - margin-right: 0.5rem; - background-color: var(--gray-200); - border-radius: 4px; - font-size: 0.9rem; - color: var(--text-color); -} - -[data-theme="dark"] .entry-categories a, -[data-theme="dark"] .entry-tags a { - background-color: var(--gray-700); -} - -.archive-header { - margin-bottom: 3rem; - text-align: center; -} - -.archive-title { - font-size: 2.5rem; - margin-bottom: 1rem; - color: var(--text-color); -} - -.archive-description { - font-size: 1.125rem; - color: var(--gray-500); -} - -.posts-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 2rem; - margin-bottom: 3rem; -} - -.archive-item { - background-color: var(--header-bg); - border-radius: 8px; - border: 1px solid var(--border-color); - overflow: hidden; - transition: transform var(--transition-speed), box-shadow var(--transition-speed); -} - -.archive-item:hover { - transform: translateY(-4px); - box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); -} - -.archive-thumbnail img { - width: 100%; - height: 200px; - object-fit: cover; -} - -.archive-content { - padding: 1.5rem; -} - -.archive-item-title { - font-size: 1.25rem; - margin-bottom: 0.75rem; -} - -.archive-item-title a { - color: var(--text-color); -} - -.archive-meta { - font-size: 0.875rem; - color: var(--gray-500); - margin-bottom: 1rem; -} - -.archive-meta .separator { - margin: 0 0.5rem; -} - -.archive-excerpt { - font-size: 0.95rem; - line-height: 1.6; - color: var(--text-color); - margin-bottom: 1rem; -} - -.read-more { - color: var(--accent-color); - font-weight: 500; - font-size: 0.9rem; -} - -.pagination { - display: flex; - justify-content: center; - gap: 0.5rem; -} - -.pagination .nav-links { - display: flex; - gap: 0.5rem; -} - -.pagination a, -.pagination span { - padding: 0.5rem 1rem; - background-color: var(--header-bg); - border: 1px solid var(--border-color); - border-radius: 4px; - color: var(--text-color); - transition: background-color var(--transition-speed); -} - -.pagination a:hover { - background-color: var(--accent-color); - color: var(--white); -} - -.pagination .current { - background-color: var(--accent-color); - color: var(--white); -} - -.error-404 { - padding: 6rem 0; -} - -.error-content { - text-align: center; - max-width: 600px; - margin: 0 auto; -} - -.error-title { - font-size: 8rem; - color: var(--accent-color); - margin-bottom: 1rem; -} - -.error-content h2 { - font-size: 2rem; - margin-bottom: 1rem; - color: var(--text-color); -} - -.error-content p { - font-size: 1.125rem; - color: var(--gray-500); - margin-bottom: 2rem; -} - -.btn-home { - display: inline-block; - padding: 0.75rem 2rem; - background-color: var(--accent-color); - color: var(--white); - border-radius: 8px; - font-weight: 500; - transition: opacity var(--transition-speed); -} - -.btn-home:hover { - opacity: 0.9; -} - -@media (max-width: 768px) { - .entry-title { - font-size: 2rem; - } - - .archive-title { - font-size: 2rem; - } - - .posts-grid { - grid-template-columns: 1fr; - } - - .error-title { - font-size: 5rem; - } -} diff --git a/assets/js/lang-toggle.js b/assets/js/lang-toggle.js new file mode 100644 index 0000000..b6abca8 --- /dev/null +++ b/assets/js/lang-toggle.js @@ -0,0 +1,43 @@ +const langToggle = document.querySelector('.lang-toggle'); +const body = document.body; + +function getPreferredLang() { + const savedLang = localStorage.getItem('language'); + if (savedLang) { + return savedLang; + } + return 'zh'; +} + +function setLang(lang) { + if (lang === 'en') { + body.setAttribute('lang', 'en'); + if (langToggle) { + langToggle.querySelector('.lang-text').textContent = '中'; + } + } else { + body.setAttribute('lang', 'zh'); + if (langToggle) { + langToggle.querySelector('.lang-text').textContent = 'EN'; + } + } + + // 处理 Input 元素的值切换 (input[type=submit] cannot use CSS content replacement) + const inputs = document.querySelectorAll('input[type="submit"][data-cn][data-en]'); + inputs.forEach(input => { + input.value = lang === 'en' ? input.getAttribute('data-en') : input.getAttribute('data-cn'); + }); + + localStorage.setItem('language', lang); +} + +const initialLang = getPreferredLang(); +setLang(initialLang); + +if (langToggle) { + langToggle.addEventListener('click', () => { + const currentLang = body.getAttribute('lang'); + const newLang = currentLang === 'en' ? 'zh' : 'en'; + setLang(newLang); + }); +} diff --git a/assets/js/stream.js b/assets/js/stream.js new file mode 100644 index 0000000..bd23e40 --- /dev/null +++ b/assets/js/stream.js @@ -0,0 +1,100 @@ +document.addEventListener('DOMContentLoaded', function() { + const container = document.querySelector('.hero-description'); + if (!container) return; + + const cnText = container.getAttribute('data-cn') || ''; + const enText = container.getAttribute('data-en') || ''; + + // 标记动画是否已经完整播放过一次 + let hasPlayedOnce = false; + // 存储当前的定时器,以便清理 + let timeouts = []; + + function getCurrentText() { + return document.body.getAttribute('lang') === 'en' ? enText : cnText; + } + + function clearTimeouts() { + timeouts.forEach(t => clearTimeout(t)); + timeouts = []; + } + + // 渲染文本的核心函数 + // text: 要显示的文本 + // animate: 是否需要逐字流式动画 + function render(text, animate) { + clearTimeouts(); + + // 使用 Array.from 正确处理 Unicode 字符 + const chars = Array.from(text); + + // 生成 HTML:每个字符包裹在 span 中 + // 如果需要动画,初始透明度为 0 + // 如果不需要动画(切换语言时),初始透明度直接为 1 + const initialOpacity = animate ? '0' : '1'; + + // 生成 spans 字符串 + const html = chars.map(char => { + // 对空格也可以处理,虽然空格看不见 + return `${char}`; + }).join(''); + + // 一次性插入 DOM,这时容器会被透明字符撑开,布局位置固定 + container.innerHTML = html; + + // 如果不需要动画,直接结束 + if (!animate) { + return; + } + + // 开始执行流式淡入动画 + const spans = container.querySelectorAll('.stream-char'); + + // 基础延迟累加器 + let accumulatedDelay = 0; + + spans.forEach((span, index) => { + // 模拟流式生成的随机节奏 + // 基础 20ms,随机增加 0-30ms + const step = 20 + Math.random() * 30; + accumulatedDelay += step; + + // 遇到标点符号稍微停顿一下 + if (/[,,.。;;!!??::]/.test(span.textContent)) { + accumulatedDelay += 100; + } + + const t = setTimeout(() => { + span.style.opacity = '1'; + + // 当最后一个字符显示完毕,标记动画已播放 + if (index === spans.length - 1) { + hasPlayedOnce = true; + } + }, accumulatedDelay); + + timeouts.push(t); + }); + } + + // 监听语言切换 + const observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.type === 'attributes' && mutation.attributeName === 'lang') { + const newText = getCurrentText(); + // 需求:如果动画已经播放完成过一次,切换语言就不再播放 + // 注意:如果用户在动画还没播放完时就切换语言,为了体验,通常也应该直接显示新语言(视为打断),防止混乱 + // 所以只要是切换语言,我们将动画设为 false (除非你想每次刷新页面都看) + // 既然用户强调 "如果动画已经播放完成过一次...就不应该再播放",隐含初次加载要播放。 + // 我们这里处理逻辑:切换语言时,强制不播放动画 (直接显示),并标记 hasPlayedOnce = true (以防万一) + hasPlayedOnce = true; + render(newText, false); + } + }); + }); + + observer.observe(document.body, { attributes: true }); + + // 页面首次加载:播放动画 + render(getCurrentText(), true); +}); diff --git a/comments.php b/comments.php new file mode 100644 index 0000000..cdae5c0 --- /dev/null +++ b/comments.php @@ -0,0 +1,66 @@ + + +
diff --git a/functions.php b/functions.php index 636a9c9..40548b5 100644 --- a/functions.php +++ b/functions.php @@ -21,12 +21,25 @@ function itstudio_theme_setup() { add_action('after_setup_theme', 'itstudio_theme_setup'); function itstudio_enqueue_scripts() { - wp_enqueue_style('itstudio-style', get_stylesheet_uri(), array(), '1.0.0'); - wp_enqueue_style('itstudio-main', get_template_directory_uri() . '/assets/css/main.css', array(), '1.0.0'); + // 基础样式 (Style.css) + wp_enqueue_style('itstudio-style', get_stylesheet_uri(), array(), '2.1.2'); + wp_enqueue_style('itstudio-header', get_template_directory_uri() . '/assets/css/header.css', array('itstudio-style'), '2.1.2'); + wp_enqueue_style('itstudio-footer', get_template_directory_uri() . '/assets/css/footer.css', array('itstudio-style'), '2.1.2'); + wp_enqueue_style('itstudio-content', get_template_directory_uri() . '/assets/css/content.css', array('itstudio-style'), '2.1.2'); + + // 仅在首页加载 Hero 样式 + if (is_front_page() || is_home()) { + wp_enqueue_style('itstudio-front-page', get_template_directory_uri() . '/assets/css/front-page.css', array('itstudio-style'), '2.1.2'); + } + + // Scripts wp_enqueue_script('itstudio-theme-toggle', get_template_directory_uri() . '/assets/js/theme-toggle.js', array(), '1.0.0', true); wp_enqueue_script('itstudio-lang-toggle', get_template_directory_uri() . '/assets/js/lang-toggle.js', array(), '1.0.0', true); - wp_enqueue_script('itstudio-footer-slide', get_template_directory_uri() . '/assets/js/footer-slide.js', array(), '1.0.0', true); + // 注册并加载打字机效果脚本 - 仅在首页 + if (is_front_page() || is_home()) { + wp_enqueue_script('itstudio-stream', get_template_directory_uri() . '/assets/js/stream.js', array(), '1.0.0', true); + } wp_enqueue_script('itstudio-main', get_template_directory_uri() . '/assets/js/main.js', array(), '1.0.0', true); } add_action('wp_enqueue_scripts', 'itstudio_enqueue_scripts'); @@ -68,3 +81,78 @@ function itstudio_custom_post_types() { )); } add_action('init', 'itstudio_custom_post_types'); + +/** + * GitHub 风格评论 + */ +function itstudio_comment_callback($comment, $args, $depth) { + ?> +
+ +
++ 'ol', + 'short_ping' => true, + 'avatar_size' => 48, + 'callback' => 'itstudio_comment_callback' // We will need to define this in functions.php or handle logic here if simple + )); + ?> +
+ + + + + +', + 'title_reply_after' => '
', + 'title_reply' => '', // Handled by data-cn/en in before tag + 'label_submit' => __('发表评论', 'itstudio'), // This submits button text, harder to change via attr, usually needs JS or just leave as is if acceptable + 'submit_button' => '', + 'comment_notes_before' => '', + 'comment_field' => '', + )); + ?> +