commit 6d4368fbd151f41ff4116ad03f8926ee5f8f6f9d Author: Your Name Date: Tue Aug 18 16:05:14 2026 +0800 Initial commit: TechBlog Pro WordPress theme Features: - Modern UI with dark mode support - Code highlighting with copy button - Auto table of contents - Reading time & views counter - Responsive design - Admin settings page - AJAX search diff --git a/404.php b/404.php new file mode 100755 index 0000000..6f48516 --- /dev/null +++ b/404.php @@ -0,0 +1,83 @@ + + +
+
🚀
+

404

+

页面未找到

+
+

抱歉,您访问的页面不存在。可能已被移动或删除。

+
+ +
+ + + + + + 返回首页 + + +
+ + +
+

或者搜索您想要的内容:

+
+
+ + +
+
+
+ + +
+

📖 最近发布的文章

+
+ 3, + 'post_status' => 'publish', + )); + if ($recent->have_posts()) : + while ($recent->have_posts()) : $recent->the_post(); + ?> + +
+ +
+
+ +
+
+ +
+
+
+ + diff --git a/README.md b/README.md new file mode 100755 index 0000000..e03581a --- /dev/null +++ b/README.md @@ -0,0 +1,191 @@ +# TechBlog Pro - WordPress Theme + +一个专为IT技术分享设计的现代化WordPress主题,具有清爽的界面、强大的代码高亮支持和优秀的阅读体验。 + +![TechBlog Pro](screenshot.png) + +## ✨ 特性 + +### 🎨 设计特色 +- **现代化UI** - 清爽简洁的设计风格 +- **暗色模式** - 一键切换深色/浅色主题 +- **响应式布局** - 完美适配各种设备 +- **流畅动画** - 细腻的过渡效果 + +### 📝 博客功能 +- **代码高亮** - 专门优化的代码块样式 +- **一键复制** - 代码块支持快速复制 +- **阅读时间** - 自动计算文章阅读时间 +- **阅读进度** - 顶部进度条显示 +- **文章目录** - 自动生成TOC目录导航 +- **阅读统计** - 记录文章浏览次数 + +### 🔧 技术特性 +- **SEO友好** - 语义化HTML结构 +- **性能优化** - 图片懒加载、平滑滚动 +- **键盘快捷键** - Ctrl+K 搜索、ESC 关闭 +- **AJAX搜索** - 实时搜索建议 +- **自定义小工具** - 分类、标签、最新文章 + +## 📦 安装 + +### 方法一:后台上传 +1. 下载主题zip文件 +2. 进入 WordPress 后台 → 外观 → 主题 +3. 点击「添加」→「上传主题」 +4. 选择下载的zip文件并安装 +5. 激活主题 + +### 方法二:FTP上传 +1. 解压主题文件 +2. 通过FTP上传到 `/wp-content/themes/techblog-wp-theme/` +3. 进入 WordPress 后台 → 外观 → 主题 +4. 激活 TechBlog Pro 主题 + +## ⚙️ 配置 + +### 菜单设置 +进入 **外观 → 菜单**: +- 创建一个新菜单 +- 选择「主导航菜单」位置 +- 添加分类/页面/自定义链接 + +### 小工具设置 +进入 **外观 → 小工具**: +- **主侧边栏** - 文章页面右侧显示 +- **页脚栏 1/2/3** - 页脚三列布局 + +### 自定义设置 +进入 **外观 → 自定义**: +- **首页横幅** - 设置首页标题和描述 +- **社交媒体** - 添加社交链接(GitHub、Twitter等) + +### 代码块语言 +在编辑器中使用代码块时,设置语言可以显示对应的标签: +``` +// 语言会自动显示在代码块左上角 +console.log('Hello World'); +``` + +## 🎯 推荐分类结构 + +适合IT技术博客的分类建议: + +``` +├── Linux +│ ├── 系统管理 +│ ├── Shell脚本 +│ └── 性能优化 +├── DevOps +│ ├── Docker +│ ├── Kubernetes +│ ├── CI/CD +│ └── 监控运维 +├── 编程开发 +│ ├── Python +│ ├── Go +│ ├── JavaScript +│ └── 数据库 +├── 云计算 +│ ├── AWS +│ ├── Azure +│ └── 阿里云 +└── 网络安全 + ├── 防火墙 + └── 渗透测试 +``` + +## 📁 文件结构 + +``` +techblog-wp-theme/ +├── style.css # 主样式表 +├── functions.php # 主题函数 +├── header.php # 页头模板 +├── footer.php # 页脚模板 +├── index.php # 首页模板 +├── single.php # 文章详情模板 +├── page.php # 页面模板 +├── archive.php # 归档模板 +├── search.php # 搜索结果模板 +├── 404.php # 404页面模板 +├── comments.php # 评论模板 +├── js/ +│ └── main.js # 主脚本文件 +└── README.md # 主题说明文档 +``` + +## 🛠️ 开发指南 + +### 添加自定义样式 +在子主题或自定义CSS中添加: + +```css +/* 自定义主色调 */ +:root { + --primary-color: #your-color; + --secondary-color: #your-color; +} + +/* 自定义代码块背景 */ +.post-content pre { + background: #your-code-bg; +} +``` + +### 添加自定义功能 +在子主题的 `functions.php` 中添加: + +```php +// 添加自定义功能 +function my_custom_features() { + // 你的代码 +} +add_action('after_setup_theme', 'my_custom_features'); +``` + +## 🌐 浏览器支持 + +- Chrome (最新) +- Firefox (最新) +- Safari (最新) +- Edge (最新) + +## 📝 更新日志 + +### v1.0.0 (2024) +- 初始版本发布 +- 暗色模式支持 +- 代码高亮和复制功能 +- 目录自动生成 +- 响应式设计 + +## 💡 使用技巧 + +### 快捷键 +- `Ctrl + K` / `Cmd + K` - 打开搜索 +- `ESC` - 关闭搜索/弹窗 + +### Markdown 支持 +主题完美支持 Gutenberg 编辑器中的代码块,建议使用 WordPress 内置的代码块功能。 + +### 图片优化 +- 建议文章图片宽度 780px +- 使用 WebP 格式可提升加载速度 +- 主题自动支持图片懒加载 + +## 🤝 贡献 + +欢迎提交 Issue 和 Pull Request! + +## 📄 许可证 + +GPL v2 or later + +## 👨‍💻 作者 + +TechBlog Team + +--- + +**享受你的技术写作之旅!** 🚀 diff --git a/archive.php b/archive.php new file mode 100755 index 0000000..678192b --- /dev/null +++ b/archive.php @@ -0,0 +1,143 @@ + + + +
+ +

+ 📂 +

+ +

+ +

+ 共 found_posts; ?> 篇文章 +

+ + +

+ 🏷️ 标签: +

+

+ 共 found_posts; ?> 篇文章 +

+ + +

+ 👤 作者: +

+ +

+ + + +

+ 📅 年 +

+ + +

+ 📅 +

+ + +

+ 📅 +

+ + +

+ 🔍 搜索: +

+

+ 找到 found_posts; ?> 个结果 +

+ + +

+ 📄 归档 +

+ +
+ + +
+ + + + + + + 2, + 'prev_text' => '← 上一页', + 'next_text' => '下一页 →', + )); + ?> + + +
+

暂无文章

+
+

该分类下暂无文章。

+
+
+ +
+ + diff --git a/comments.php b/comments.php new file mode 100755 index 0000000..20a26de --- /dev/null +++ b/comments.php @@ -0,0 +1,118 @@ + + +
+ + +

+ + + + +

+ +
    + 'ol', + 'short_ping' => true, + 'avatar_size' => 48, + 'callback' => 'techblog_comment_template', + )); + ?> +
+ + '← 较旧的评论', + 'next_text' => '较新的评论 →', + )); + ?> + + + + +

评论已关闭

+ + + 'comment-form', + 'title_reply' => '', + 'comment_notes_before' => '', + 'comment_field' => ' +
+ + +
', + 'submit_button' => '', + )); + ?> +
+ + + < id="comment-" > +
+
+ +
+ +
+
+ + + + +
+ +
+ +
+ +
+ $depth, + 'max_depth' => $args['max_depth'], + ))); + ?> +
+
+
+ diff --git a/css/admin.css b/css/admin.css new file mode 100644 index 0000000..60538f7 --- /dev/null +++ b/css/admin.css @@ -0,0 +1,194 @@ +/* TechBlog Pro Admin Styles */ + +.techblog-admin-wrapper { + display: grid; + grid-template-columns: 200px 1fr; + gap: 20px; + margin-top: 20px; +} + +.nav-tab-wrapper { + display: flex; + flex-direction: column; + background: #fff; + border: 1px solid #ccd0d4; + border-radius: 4px; + overflow: hidden; + height: fit-content; +} + +.nav-tab-wrapper .nav-tab { + display: block; + padding: 12px 16px; + border: none; + border-bottom: 1px solid #ccd0d4; + border-radius: 0; + margin: 0; + font-size: 14px; + cursor: pointer; + transition: all 0.2s; + text-decoration: none; + color: #2271b1; +} + +.nav-tab-wrapper .nav-tab:last-child { + border-bottom: none; +} + +.nav-tab-wrapper .nav-tab:hover { + background: #f0f0f1; + color: #135e96; +} + +.nav-tab-wrapper .nav-tab.nav-tab-active { + background: #2563eb; + color: #fff; + border-color: #2563eb; +} + +.tab-content { + display: none; + background: #fff; + padding: 20px; + border: 1px solid #ccd0d4; + border-radius: 4px; +} + +.tab-content.active { + display: block; +} + +.tab-content .form-table th { + width: 150px; + padding: 15px 10px; +} + +.tab-content .form-table td { + padding: 15px 10px; +} + +.tab-content .form-table input[type="text"], +.tab-content .form-table input[type="url"], +.tab-content .form-table input[type="email"], +.tab-content .form-table textarea, +.tab-content .form-table select { + min-width: 300px; +} + +.tab-content .form-table input[type="color"] { + width: 60px; + height: 36px; + padding: 2px; + cursor: pointer; +} + +.tab-content .form-table fieldset label { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; + cursor: pointer; +} + +.tab-content .form-table fieldset input[type="checkbox"] { + width: 18px; + height: 18px; +} + +/* About Card */ +.techblog-about-card { + max-width: 600px; +} + +.techblog-about-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 16px; +} + +.techblog-about-header h2 { + margin: 0; + font-size: 24px; +} + +.techblog-about-header .version { + background: #2563eb; + color: #fff; + padding: 4px 12px; + border-radius: 100px; + font-size: 12px; + font-weight: 600; +} + +.techblog-about-card h3 { + margin-top: 24px; + margin-bottom: 12px; + font-size: 16px; +} + +.techblog-about-card ul { + padding-left: 20px; +} + +.techblog-about-card li { + margin-bottom: 8px; + line-height: 1.6; +} + +.techblog-about-card a { + color: #2563eb; + text-decoration: none; +} + +.techblog-about-card a:hover { + text-decoration: underline; +} + +/* Submit Button */ +.submit { + margin-top: 20px; +} + +.submit .button-primary { + background: #2563eb; + border-color: #2563eb; + padding: 0 20px; + height: 40px; + font-size: 14px; + border-radius: 4px; +} + +.submit .button-primary:hover { + background: #1d4ed8; + border-color: #1d4ed8; +} + +/* Responsive */ +@media (max-width: 782px) { + .techblog-admin-wrapper { + grid-template-columns: 1fr; + } + + .nav-tab-wrapper { + flex-direction: row; + flex-wrap: wrap; + } + + .nav-tab-wrapper .nav-tab { + border-bottom: none; + border-right: 1px solid #ccd0d4; + } + + .nav-tab-wrapper .nav-tab:last-child { + border-right: none; + } + + .tab-content .form-table input[type="text"], + .tab-content .form-table input[type="url"], + .tab-content .form-table input[type="email"], + .tab-content .form-table textarea, + .tab-content .form-table select { + min-width: 100%; + } +} diff --git a/footer.php b/footer.php new file mode 100755 index 0000000..16ba9a1 --- /dev/null +++ b/footer.php @@ -0,0 +1,130 @@ + + + + + + + + + + + + diff --git a/functions.php b/functions.php new file mode 100755 index 0000000..85f4e24 --- /dev/null +++ b/functions.php @@ -0,0 +1,459 @@ + 40, + 'width' => 200, + 'flex-height' => true, + 'flex-width' => true, + )); + add_theme_support('html5', array( + 'search-form', + 'comment-form', + 'comment-list', + 'gallery', + 'caption', + 'style', + 'script', + )); + add_theme_support('editor-styles'); + add_theme_support('responsive-embeds'); + add_theme_support('wp-block-styles'); + + // Register Navigation Menus + register_nav_menus(array( + 'primary' => esc_html__('主导航菜单', 'techblog'), + 'footer' => esc_html__('页脚菜单', 'techblog'), + )); + + // Set content width + if (!isset($content_width)) { + $content_width = 780; + } +} +add_action('after_setup_theme', 'techblog_setup'); + +/** + * Enqueue Styles and Scripts + */ +function techblog_scripts() { + // Google Fonts + wp_enqueue_style('techblog-fonts', + 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap', + array(), + null + ); + + // Main Stylesheet + wp_enqueue_style('techblog-style', + get_stylesheet_uri(), + array(), + TECHBLOG_VERSION + ); + + // Main JavaScript + wp_enqueue_script('techblog-main', + TECHBLOG_URI . '/js/main.js', + array(), + TECHBLOG_VERSION, + true + ); + + // Localize script + wp_localize_script('techblog-main', 'techblog', array( + 'ajaxurl' => admin_url('admin-ajax.php'), + 'nonce' => wp_create_nonce('techblog-nonce'), + )); +} +add_action('wp_enqueue_scripts', 'techblog_scripts'); + +/** + * Register Sidebars + */ +function techblog_widgets_init() { + register_sidebar(array( + 'name' => esc_html__('主侧边栏', 'techblog'), + 'id' => 'sidebar-main', + 'description' => esc_html__('文章页面右侧的侧边栏', 'techblog'), + 'before_widget' => '', + 'before_title' => '

', + 'after_title' => '

', + )); + + register_sidebar(array( + 'name' => esc_html__('页脚栏 1', 'techblog'), + 'id' => 'footer-1', + 'description' => esc_html__('页脚第一列', 'techblog'), + 'before_widget' => '', + 'before_title' => '

', + 'after_title' => '

', + )); + + register_sidebar(array( + 'name' => esc_html__('页脚栏 2', 'techblog'), + 'id' => 'footer-2', + 'description' => esc_html__('页脚第二列', 'techblog'), + 'before_widget' => '', + 'before_title' => '

', + 'after_title' => '

', + )); + + register_sidebar(array( + 'name' => esc_html__('页脚栏 3', 'techblog'), + 'id' => 'footer-3', + 'description' => esc_html__('页脚第三列', 'techblog'), + 'before_widget' => '', + 'before_title' => '

', + 'after_title' => '

', + )); +} +add_action('widgets_init', 'techblog_widgets_init'); + +/** + * Custom Excerpt Length + */ +function techblog_excerpt_length($length) { + return 25; +} +add_filter('excerpt_length', 'techblog_excerpt_length'); + +/** + * Custom Excerpt More + */ +function techblog_excerpt_more($more) { + return '...'; +} +add_filter('excerpt_more', 'techblog_excerpt_more'); + +/** + * Add Code Language Class to Pre Tags + */ +function techblog_code_block_attributes($block_content, $block) { + if ($block['blockName'] === 'core/code') { + if (!empty($block['attrs']['language'])) { + $lang = esc_attr($block['attrs']['language']); + $block_content = str_replace( + '
]*>(.*?)<\/h[2-3]>/is', $content, $matches, PREG_SET_ORDER);
+    
+    if (count($matches) < 3) {
+        return $content;
+    }
+    
+    $toc = '
'; + + // Insert TOC after first paragraph or before first heading + $first_p = strpos($content, '

'); + if ($first_p !== false) { + $content = substr($content, 0, $first_p + 4) . $toc . substr($content, $first_p + 4); + } else { + $content = $toc . $content; + } + + return $content; +} +add_filter('the_content', 'techblog_generate_toc', 20); + +/** + * Add Copy Button to Code Blocks + */ +function techblog_add_code_copy_button($content) { + if (!is_single() && !is_page()) { + return $content; + } + + $content = preg_replace_callback( + '/]*)>(.*?)<\/pre>/is', + function($matches) { + $attrs = $matches[1]; + $code = $matches[2]; + + // Extract language if present + $lang = ''; + if (preg_match('/lang-([a-z0-9]+)/', $attrs, $lang_match)) { + $lang = strtoupper($lang_match[1]); + } + + $header = '
'; + $header .= '' . ($lang ?: 'CODE') . ''; + $header .= '
'; + + return '' . $header . $code . '
'; + }, + $content + ); + + return $content; +} +add_filter('the_content', 'techblog_add_code_copy_button', 25); + +/** + * Custom Walker for Navigation Menu + */ +class TechBlog_Nav_Walker extends Walker_Nav_Menu { + function start_el(&$output, $item, $depth = 0, $args = null, $id = 0) { + $classes = empty($item->classes) ? array() : (array) $item->classes; + $class = join(' ', array_filter($classes)); + + if (in_array('current-menu-item', $classes) || in_array('current_page_item', $classes)) { + $class .= ' current'; + } + + $output .= ''; + $output .= esc_html($item->title); + $output .= ''; + } +} + +/** + * Reading Time + */ +function techblog_reading_time() { + $content = get_the_content(); + $word_count = str_word_count(strip_tags($content)); + $reading_time = ceil($word_count / 200); // Average reading speed + return $reading_time; +} + +/** + * Post Views (Simple implementation) + */ +function techblog_get_post_views() { + $count = get_post_meta(get_the_ID(), 'post_views', true); + return $count ? intval($count) : 0; +} + +function techblog_set_post_views() { + if (!is_single()) return; + + $post_id = get_the_ID(); + $count = get_post_meta($post_id, 'post_views', true); + + if ($count == '') { + $count = 0; + delete_post_meta($post_id, 'post_views'); + add_post_meta($post_id, 'post_views', '0'); + } else { + $count++; + update_post_meta($post_id, 'post_views', $count); + } +} +add_action('wp_head', 'techblog_set_post_views'); + +/** + * Format View Count + */ +function techblog_format_views($count) { + if ($count >= 10000) { + return round($count / 10000, 1) . 'w'; + } elseif ($count >= 1000) { + return round($count / 1000, 1) . 'k'; + } + return $count; +} + +/** + * Custom Comment Form + */ +function techblog_comment_form_defaults($defaults) { + $defaults['comment_notes_before'] = ''; + $defaults['comment_field'] = '
+ +
'; + return $defaults; +} +add_filter('comment_form_defaults', 'techblog_comment_form_defaults'); + +/** + * Theme Customizer + */ +function techblog_customize_register($wp_customize) { + // Hero Section + $wp_customize->add_section('techblog_hero', array( + 'title' => esc_html__('首页横幅', 'techblog'), + 'priority' => 30, + )); + + $wp_customize->add_setting('hero_title', array( + 'default' => '探索技术世界', + 'sanitize_callback' => 'sanitize_text_field', + )); + $wp_customize->add_control('hero_title', array( + 'label' => esc_html__('横幅标题', 'techblog'), + 'section' => 'techblog_hero', + 'type' => 'text', + )); + + $wp_customize->add_setting('hero_description', array( + 'default' => '分享最新的IT技术、编程教程、系统运维经验', + 'sanitize_callback' => 'sanitize_textarea_field', + )); + $wp_customize->add_control('hero_description', array( + 'label' => esc_html__('横幅描述', 'techblog'), + 'section' => 'techblog_hero', + 'type' => 'textarea', + )); + + // Social Links + $wp_customize->add_section('techblog_social', array( + 'title' => esc_html__('社交媒体', 'techblog'), + 'priority' => 35, + )); + + $social_platforms = array( + 'github' => 'GitHub', + 'twitter' => 'Twitter / X', + 'gitee' => 'Gitee', + 'email' => '邮箱', + ); + + foreach ($social_platforms as $key => $label) { + $wp_customize->add_setting('social_' . $key, array( + 'default' => '', + 'sanitize_callback' => 'esc_url_raw', + )); + $wp_customize->add_control('social_' . $key, array( + 'label' => $label, + 'section' => 'techblog_social', + 'type' => 'url', + )); + } +} +add_action('customize_register', 'techblog_customize_register'); + +/** + * Custom Post Type for Projects (optional) + */ +function techblog_register_post_types() { + register_post_type('project', array( + 'labels' => array( + 'name' => esc_html__('项目', 'techblog'), + 'singular_name' => esc_html__('项目', 'techblog'), + 'add_new' => esc_html__('添加项目', 'techblog'), + 'add_new_item' => esc_html__('添加新项目', 'techblog'), + 'edit_item' => esc_html__('编辑项目', 'techblog'), + 'all_items' => esc_html__('所有项目', 'techblog'), + 'view_item' => esc_html__('查看项目', 'techblog'), + 'search_items' => esc_html__('搜索项目', 'techblog'), + ), + 'public' => true, + 'has_archive' => true, + 'menu_icon' => 'dashicons-portfolio', + 'supports' => array('title', 'editor', 'thumbnail', 'excerpt'), + 'rewrite' => array('slug' => 'project'), + )); +} +add_action('init', 'techblog_register_post_types'); + +/** + * AJAX Search + */ +function techblog_ajax_search() { + check_ajax_referer('techblog-nonce', 'nonce'); + + $search_term = sanitize_text_field($_POST['search']); + + if (empty($search_term)) { + wp_send_json_error('请输入搜索关键词'); + } + + $query = new WP_Query(array( + 's' => $search_term, + 'posts_per_page' => 5, + 'post_status' => 'publish', + )); + + $results = array(); + + if ($query->have_posts()) { + while ($query->have_posts()) { + $query->the_post(); + $results[] = array( + 'title' => get_the_title(), + 'url' => get_the_permalink(), + 'excerpt' => wp_trim_words(get_the_excerpt(), 20), + 'date' => get_the_date('Y-m-d'), + ); + } + } + + wp_reset_postdata(); + + wp_send_json_success($results); +} +add_action('wp_ajax_techblog_search', 'techblog_ajax_search'); +add_action('wp_ajax_nopriv_techblog_search', 'techblog_ajax_search'); diff --git a/header.php b/header.php new file mode 100755 index 0000000..1034995 --- /dev/null +++ b/header.php @@ -0,0 +1,104 @@ + + data-theme="light"> + + + + + + +> + + + + + +
+
+
+
+ + + + + +
+
+
+ 输入关键词搜索 + ESC 关闭 +
+
+
+ +
+
diff --git a/inc/admin-options.php b/inc/admin-options.php new file mode 100644 index 0000000..b1a5979 --- /dev/null +++ b/inc/admin-options.php @@ -0,0 +1,424 @@ + '#2563eb' + )); + register_setting('techblog_options', 'techblog_code_theme', array( + 'default' => 'dark' + )); + register_setting('techblog_options', 'techblog_show_toc', array( + 'default' => '1' + )); + register_setting('techblog_options', 'techblog_show_reading_time', array( + 'default' => '1' + )); + register_setting('techblog_options', 'techblog_show_views', array( + 'default' => '1' + )); + register_setting('techblog_options', 'techblog_enable_dark_mode', array( + 'default' => '1' + )); +} +add_action('admin_init', 'techblog_register_settings'); + +// Admin page HTML +function techblog_options_page_html() { + if (!current_user_can('manage_options')) { + return; + } + + if (isset($_GET['settings-updated'])) { + add_settings_error('techblog_messages', 'techblog_message', '设置已保存', 'updated'); + } + + settings_errors('techblog_messages'); + ?> +
+

+ +
+ + + +
+ + + +
+ + + + + + + + + + + + + +
首页横幅标题 + +

首页顶部横幅的标题文字

+
首页横幅描述 + +

首页顶部横幅的描述文字

+
页脚文字 + +

页脚显示的描述文字

+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+
+ + +
+ + + + + + + + + + + + + +
主题色 + +

选择主题的主色调

+
代码块主题 + +

代码块的配色方案

+
功能开关 +
+
+
+
+ +
+
+
+ + +
+
+
+

TechBlog Pro

+ v1.0.0 +
+

一个专为IT技术分享设计的现代化WordPress主题。

+ +

✨ 主题特性

+
    +
  • 🎨 现代化UI设计,支持暗色模式
  • +
  • 📝 代码高亮 + 一键复制
  • +
  • 📑 自动生成文章目录
  • +
  • ⏱️ 阅读时间估算
  • +
  • 📊 阅读次数统计
  • +
  • 🔍 AJAX实时搜索
  • +
  • 📱 完美响应式布局
  • +
  • ⚡ 性能优化(懒加载、平滑滚动)
  • +
+ +

🔗 相关链接

+ +
+
+ + +
+
+
+ + + + + + + + +
+

+

+
+ + + +
+ + + + + + + 2, + 'prev_text' => '← 上一页', + 'next_text' => '下一页 →', + )); + ?> + + +
+

暂无文章

+
+

还没有发布任何文章,请稍后再来。

+
+
+ +
+ + diff --git a/js/main.js b/js/main.js new file mode 100755 index 0000000..9b2006b --- /dev/null +++ b/js/main.js @@ -0,0 +1,334 @@ +/** + * TechBlog Pro - Main JavaScript + * + * @package TechBlog Pro + * @version 1.0.0 + */ + +(function() { + 'use strict'; + + // ==================== Theme Toggle ==================== + const ThemeManager = { + init() { + this.toggle = document.getElementById('theme-toggle'); + this.sunIcon = this.toggle?.querySelector('.sun-icon'); + this.moonIcon = this.toggle?.querySelector('.moon-icon'); + + if (!this.toggle) return; + + // Load saved theme + const savedTheme = localStorage.getItem('theme') || 'light'; + this.setTheme(savedTheme); + + // Toggle event + this.toggle.addEventListener('click', () => { + const current = document.documentElement.getAttribute('data-theme'); + this.setTheme(current === 'dark' ? 'light' : 'dark'); + }); + }, + + setTheme(theme) { + document.documentElement.setAttribute('data-theme', theme); + localStorage.setItem('theme', theme); + + if (this.sunIcon && this.moonIcon) { + this.sunIcon.style.display = theme === 'dark' ? 'none' : 'block'; + this.moonIcon.style.display = theme === 'dark' ? 'block' : 'none'; + } + } + }; + + // ==================== Search Overlay ==================== + const SearchManager = { + init() { + this.overlay = document.getElementById('search-overlay'); + this.toggle = document.getElementById('search-toggle'); + this.input = this.overlay?.querySelector('.search-input'); + + if (!this.overlay || !this.toggle) return; + + // Open search + this.toggle.addEventListener('click', () => this.open()); + + // Close on overlay click + this.overlay.addEventListener('click', (e) => { + if (e.target === this.overlay) this.close(); + }); + + // Keyboard shortcuts + document.addEventListener('keydown', (e) => { + // CMD/CTRL + K to open + if ((e.metaKey || e.ctrlKey) && e.key === 'k') { + e.preventDefault(); + this.open(); + } + + // ESC to close + if (e.key === 'Escape') { + this.close(); + } + }); + }, + + open() { + this.overlay.classList.add('active'); + setTimeout(() => this.input?.focus(), 100); + document.body.style.overflow = 'hidden'; + }, + + close() { + this.overlay.classList.remove('active'); + document.body.style.overflow = ''; + } + }; + + // ==================== Mobile Menu ==================== + const MobileMenu = { + init() { + this.toggle = document.getElementById('mobile-menu-toggle'); + this.nav = document.getElementById('main-nav'); + + if (!this.toggle || !this.nav) return; + + this.toggle.addEventListener('click', () => { + this.nav.classList.toggle('active'); + this.toggle.classList.toggle('active'); + }); + + // Close on outside click + document.addEventListener('click', (e) => { + if (!this.nav.contains(e.target) && !this.toggle.contains(e.target)) { + this.nav.classList.remove('active'); + this.toggle.classList.remove('active'); + } + }); + } + }; + + // ==================== Table of Contents ==================== + const TOCManager = { + init() { + this.tocLinks = document.querySelectorAll('.toc-list a'); + this.headings = []; + + if (this.tocLinks.length === 0) return; + + // Collect headings + this.tocLinks.forEach(link => { + const id = link.getAttribute('href')?.slice(1); + const heading = document.getElementById(id); + if (heading) { + this.headings.push({ id, element: heading, link }); + } + }); + + // Scroll spy + this.observer = new IntersectionObserver( + (entries) => this.handleIntersection(entries), + { rootMargin: '-80px 0px -80% 0px' } + ); + + this.headings.forEach(({ element }) => { + this.observer.observe(element); + }); + + // Smooth scroll + this.tocLinks.forEach(link => { + link.addEventListener('click', (e) => { + e.preventDefault(); + const id = link.getAttribute('href')?.slice(1); + const target = document.getElementById(id); + if (target) { + target.scrollIntoView({ behavior: 'smooth' }); + } + }); + }); + }, + + handleIntersection(entries) { + entries.forEach(entry => { + if (entry.isIntersecting) { + // Remove all active states + this.tocLinks.forEach(link => link.classList.remove('active')); + + // Add active to current + const activeLink = this.headings.find(h => h.id === entry.target.id)?.link; + activeLink?.classList.add('active'); + } + }); + } + }; + + // ==================== Code Copy ==================== + window.copyCode = function(button) { + const pre = button.closest('pre'); + const code = pre?.querySelector('code'); + + if (!code) return; + + const text = code.textContent; + + navigator.clipboard.writeText(text).then(() => { + const originalText = button.innerHTML; + button.innerHTML = ` + + + + 已复制 + `; + button.style.color = '#22c55e'; + + setTimeout(() => { + button.innerHTML = originalText; + button.style.color = ''; + }, 2000); + }).catch(err => { + console.error('Failed to copy:', err); + }); + }; + + // ==================== Reading Progress ==================== + const ReadingProgress = { + init() { + this.progressBar = document.createElement('div'); + this.progressBar.style.cssText = ` + position: fixed; + top: 0; + left: 0; + width: 0%; + height: 3px; + background: linear-gradient(90deg, var(--primary-color), var(--accent-color)); + z-index: 9999; + transition: width 0.1s ease; + `; + document.body.appendChild(this.progressBar); + + window.addEventListener('scroll', () => this.update()); + }, + + update() { + const scrollTop = window.scrollY; + const docHeight = document.documentElement.scrollHeight - window.innerHeight; + const progress = (scrollTop / docHeight) * 100; + + this.progressBar.style.width = `${Math.min(progress, 100)}%`; + } + }; + + // ==================== Lazy Load Images ==================== + const LazyLoad = { + init() { + if ('loading' in HTMLImageElement.prototype) { + // Native lazy loading supported + document.querySelectorAll('img[loading="lazy"]').forEach(img => { + img.src = img.dataset.src; + }); + } else { + // Fallback with IntersectionObserver + this.observer = new IntersectionObserver( + (entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + img.src = img.dataset.src; + this.observer.unobserve(img); + } + }); + }, + { rootMargin: '50px' } + ); + + document.querySelectorAll('img[data-src]').forEach(img => { + this.observer.observe(img); + }); + } + } + }; + + // ==================== Copy Link ==================== + window.copyLink = function() { + const url = window.location.href; + navigator.clipboard.writeText(url).then(() => { + const btn = document.querySelector('.share-copy'); + btn.classList.add('copied'); + btn.title = '已复制'; + + setTimeout(() => { + btn.classList.remove('copied'); + btn.title = '复制链接'; + }, 2000); + }); + }; + + // ==================== Back to Top ==================== + const BackToTop = { + init() { + this.button = document.createElement('button'); + this.button.innerHTML = ` + + + + + `; + this.button.style.cssText = ` + position: fixed; + bottom: 24px; + right: 24px; + width: 44px; + height: 44px; + background: var(--bg-primary); + border: 1px solid var(--border-color); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + z-index: 100; + color: var(--text-secondary); + box-shadow: var(--shadow-md); + `; + + this.button.addEventListener('click', () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }); + + document.body.appendChild(this.button); + + window.addEventListener('scroll', () => this.toggle()); + }, + + toggle() { + if (window.scrollY > 300) { + this.button.style.opacity = '1'; + this.button.style.visibility = 'visible'; + } else { + this.button.style.opacity = '0'; + this.button.style.visibility = 'hidden'; + } + } + }; + + // ==================== Initialize ==================== + document.addEventListener('DOMContentLoaded', () => { + ThemeManager.init(); + SearchManager.init(); + MobileMenu.init(); + TOCManager.init(); + ReadingProgress.init(); + LazyLoad.init(); + BackToTop.init(); + + // Add current page class to nav + const currentPath = window.location.pathname; + document.querySelectorAll('.main-nav a').forEach(link => { + if (link.pathname === currentPath) { + link.classList.add('current'); + } + }); + }); + +})(); diff --git a/page.php b/page.php new file mode 100755 index 0000000..9eea5d4 --- /dev/null +++ b/page.php @@ -0,0 +1,25 @@ + + +
> + + +
+

+
+ +
+ +
+ + +
+ + diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..e018772 Binary files /dev/null and b/screenshot.png differ diff --git a/screenshot.svg b/screenshot.svg new file mode 100755 index 0000000..3f4107c --- /dev/null +++ b/screenshot.svg @@ -0,0 +1,68 @@ + + + + + + + + TechBlog Pro + + + 首页 博客 Linux Docker K8s + + + + + + + + + + 探索技术世界 + 分享最新的IT技术、编程教程、系统运维经验 + + + + + LINUX + Ubuntu 24.04 LTS 安装配置指南 + 详细介绍如何在服务器上安装和配置 Ubuntu 24.04 LTS... + ⏱ 8 分钟阅读 👁 1.2k 阅读 + + + + + DOCKER + Docker Compose 实战教程 + 使用 Docker Compose 编排多容器应用... + + + + 📂 文章分类 + Linux (24) + Docker (18) + Kubernetes (15) + Python (12) + + + 🏷️ 热门标签 + + Docker + + Kubernetes + + Linux + + + + 一个专注于IT技术分享的博客 + © 2024 TechBlog Pro. All rights reserved. + + + + + + + + + diff --git a/search.php b/search.php new file mode 100755 index 0000000..868aee0 --- /dev/null +++ b/search.php @@ -0,0 +1,102 @@ + + +
+

+ 🔍 搜索结果: +

+

+ found_posts > 0) : ?> + 找到 found_posts; ?> 个相关结果 + + 未找到相关结果 + +

+
+ +
+ + + + + + 2, + 'prev_text' => '← 上一页', + 'next_text' => '下一页 →', + )); + ?> + + +
+
🔍
+

未找到相关内容

+
+

抱歉,没有找到与 "" 相关的文章。

+

您可以尝试:

+
    +
  • 检查关键词是否正确
  • +
  • 尝试其他关键词
  • +
  • 浏览我们的文章分类
  • +
+
+
+ +
+ + diff --git a/single.php b/single.php new file mode 100755 index 0000000..93f573c --- /dev/null +++ b/single.php @@ -0,0 +1,154 @@ + + + + + diff --git a/style.css b/style.css new file mode 100755 index 0000000..6b3c8f0 --- /dev/null +++ b/style.css @@ -0,0 +1,1475 @@ +/* +Theme Name: TechBlog Pro +Theme URI: https://github.com/techblog-pro +Author: TechBlog Team +Author URI: https://github.com +Description: 一个专为IT技术分享设计的现代化WordPress主题,支持代码高亮、暗色模式、响应式布局 +Version: 1.0.0 +License: GNU General Public License v2 or later +License URI: http://www.gnu.org/licenses/gpl-2.0.html +Text Domain: techblog +Tags: blog, technology, code, dark-mode, responsive +*/ + +/* ==================== CSS Variables ==================== */ +:root { + /* Light Mode Colors */ + --primary-color: #2563eb; + --primary-hover: #1d4ed8; + --secondary-color: #7c3aed; + --accent-color: #06b6d4; + + --bg-primary: #ffffff; + --bg-secondary: #f8fafc; + --bg-tertiary: #f1f5f9; + --bg-code: #1e293b; + + --text-primary: #1e293b; + --text-secondary: #475569; + --text-muted: #94a3b8; + --text-code: #e2e8f0; + + --border-color: #e2e8f0; + --border-hover: #cbd5e1; + + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + + --radius-sm: 6px; + --radius-md: 8px; + --radius-lg: 12px; + --radius-xl: 16px; + + --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace; + + --header-height: 64px; + --sidebar-width: 300px; + --content-max-width: 780px; + --container-max-width: 1280px; + + --transition: all 0.2s ease; +} + +/* Dark Mode */ +[data-theme="dark"] { + --bg-primary: #0f172a; + --bg-secondary: #1e293b; + --bg-tertiary: #334155; + --bg-code: #0d1117; + + --text-primary: #f1f5f9; + --text-secondary: #94a3b8; + --text-muted: #64748b; + --text-code: #e2e8f0; + + --border-color: #334155; + --border-hover: #475569; + + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.4), 0 2px 4px -2px rgb(0 0 0 / 0.3); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.4), 0 4px 6px -4px rgb(0 0 0 / 0.3); +} + +/* ==================== Base Styles ==================== */ +*, *::before, *::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + font-size: 16px; + scroll-behavior: smooth; + scroll-padding-top: calc(var(--header-height) + 20px); +} + +body { + font-family: var(--font-sans); + background-color: var(--bg-primary); + color: var(--text-primary); + line-height: 1.7; + transition: background-color 0.3s ease, color 0.3s ease; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + color: var(--primary-color); + text-decoration: none; + transition: var(--transition); +} + +a:hover { + color: var(--primary-hover); +} + +img { + max-width: 100%; + height: auto; + display: block; +} + +/* ==================== Header ==================== */ +.site-header { + position: sticky; + top: 0; + z-index: 1000; + background: var(--bg-primary); + border-bottom: 1px solid var(--border-color); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); +} + +.header-inner { + max-width: var(--container-max-width); + margin: 0 auto; + padding: 0 24px; + height: var(--header-height); + display: flex; + align-items: center; + justify-content: space-between; +} + +.site-logo { + display: flex; + align-items: center; + gap: 10px; + font-size: 1.25rem; + font-weight: 700; + color: var(--text-primary); +} + +.site-logo svg { + width: 32px; + height: 32px; + fill: var(--primary-color); +} + +/* Navigation */ +.main-nav { + display: flex; + align-items: center; + gap: 8px; +} + +.main-nav a { + padding: 8px 16px; + color: var(--text-secondary); + font-size: 0.9375rem; + font-weight: 500; + border-radius: var(--radius-sm); + transition: var(--transition); +} + +.main-nav a:hover, +.main-nav a.current { + color: var(--text-primary); + background: var(--bg-tertiary); +} + +/* Header Actions */ +.header-actions { + display: flex; + align-items: center; + gap: 8px; +} + +.search-toggle, +.theme-toggle, +.mobile-menu-toggle { + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + background: none; + border: 1px solid var(--border-color); + border-radius: var(--radius-sm); + color: var(--text-secondary); + cursor: pointer; + transition: var(--transition); +} + +.search-toggle:hover, +.theme-toggle:hover, +.mobile-menu-toggle:hover { + background: var(--bg-tertiary); + color: var(--text-primary); + border-color: var(--border-hover); +} + +.theme-toggle svg, +.search-toggle svg { + width: 20px; + height: 20px; +} + +.mobile-menu-toggle { + display: none; +} + +/* ==================== Layout ==================== */ +.site-container { + max-width: var(--container-max-width); + margin: 0 auto; + padding: 32px 24px; + display: grid; + grid-template-columns: 1fr var(--sidebar-width); + gap: 40px; +} + +.content-area { + min-width: 0; +} + +/* ==================== Hero Section ==================== */ +.hero-section { + background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); + border-radius: var(--radius-xl); + padding: 48px; + margin-bottom: 40px; + color: white; + position: relative; + overflow: hidden; +} + +.hero-section::before { + content: ''; + position: absolute; + top: 0; + right: 0; + width: 300px; + height: 300px; + background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%); + transform: translate(30%, -30%); +} + +.hero-title { + font-size: 2rem; + font-weight: 800; + margin-bottom: 12px; + position: relative; +} + +.hero-description { + font-size: 1.0625rem; + opacity: 0.9; + max-width: 600px; + position: relative; +} + +/* ==================== Post Cards ==================== */ +.posts-grid { + display: grid; + gap: 24px; +} + +.post-card { + background: var(--bg-primary); + border: 1px solid var(--border-color); + border-radius: var(--radius-lg); + padding: 28px; + transition: var(--transition); +} + +.post-card:hover { + border-color: var(--primary-color); + box-shadow: var(--shadow-md); + transform: translateY(-2px); +} + +.post-card-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 16px; +} + +.post-category { + display: inline-flex; + align-items: center; + padding: 4px 12px; + background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); + color: white; + font-size: 0.75rem; + font-weight: 600; + border-radius: 100px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.post-date { + font-size: 0.875rem; + color: var(--text-muted); +} + +.post-card-title { + font-size: 1.375rem; + font-weight: 700; + line-height: 1.4; + margin-bottom: 12px; + color: var(--text-primary); +} + +.post-card-title a { + color: inherit; +} + +.post-card-title a:hover { + color: var(--primary-color); +} + +.post-excerpt { + color: var(--text-secondary); + font-size: 0.9375rem; + line-height: 1.6; + margin-bottom: 20px; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.post-card-footer { + display: flex; + align-items: center; + justify-content: space-between; + padding-top: 16px; + border-top: 1px solid var(--border-color); +} + +.post-meta { + display: flex; + align-items: center; + gap: 16px; + font-size: 0.875rem; + color: var(--text-muted); +} + +.post-meta-item { + display: flex; + align-items: center; + gap: 6px; +} + +.post-meta-item svg { + width: 16px; + height: 16px; +} + +.read-more { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 0.875rem; + font-weight: 600; + color: var(--primary-color); +} + +.read-more svg { + width: 16px; + height: 16px; + transition: transform 0.2s ease; +} + +.read-more:hover svg { + transform: translateX(4px); +} + +/* ==================== Single Post ==================== */ +.single-post { + width: 100%; +} + +/* Post Footer - Tags & Share */ +.post-footer { + margin-top: 40px; + padding-top: 32px; + border-top: 1px solid var(--border-color); +} + +.post-tags { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 24px; + flex-wrap: wrap; +} + +.post-tags svg { + color: var(--text-muted); + flex-shrink: 0; +} + +.post-tags a { + display: inline-block; + padding: 6px 14px; + background: var(--bg-secondary); + color: var(--text-secondary); + border-radius: 100px; + font-size: 0.8125rem; + font-weight: 500; + transition: var(--transition); + border: 1px solid var(--border-color); +} + +.post-tags a:hover { + background: var(--primary-color); + color: white; + border-color: var(--primary-color); + transform: translateY(-1px); +} + +.share-section { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20px 24px; + background: var(--bg-secondary); + border-radius: var(--radius-lg); + border: 1px solid var(--border-color); +} + +.share-label { + display: flex; + align-items: center; + gap: 10px; + font-weight: 600; + color: var(--text-primary); + font-size: 0.9375rem; +} + +.share-label svg { + color: var(--text-muted); +} + +.share-buttons { + display: flex; + gap: 10px; +} + +.share-btn { + display: flex; + align-items: center; + justify-content: center; + width: 44px; + height: 44px; + border-radius: var(--radius-md); + border: 1px solid var(--border-color); + background: var(--bg-primary); + color: var(--text-secondary); + cursor: pointer; + transition: var(--transition); +} + +.share-btn:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} + +.share-twitter:hover { + background: #000; + color: white; + border-color: #000; +} + +.share-linkedin:hover { + background: #0077b5; + color: white; + border-color: #0077b5; +} + +.share-copy:hover { + background: var(--primary-color); + color: white; + border-color: var(--primary-color); +} + +.share-copy.copied { + background: #22c55e; + color: white; + border-color: #22c55e; +} + +/* ==================== Comments Area ==================== */ +.comments-area { + margin-top: 48px; + padding-top: 40px; + border-top: 1px solid var(--border-color); +} + +.comments-title { + display: flex; + align-items: center; + gap: 12px; + font-size: 1.25rem; + font-weight: 700; + margin-bottom: 32px; + color: var(--text-primary); +} + +.comments-title svg { + color: var(--primary-color); +} + +.comment-list { + list-style: none; + padding: 0; + margin: 0; +} + +.comment-item { + margin-bottom: 24px; +} + +.comment-item .children { + list-style: none; + padding-left: 48px; + margin-top: 24px; +} + +.comment-body { + display: flex; + gap: 16px; + padding: 24px; + background: var(--bg-primary); + border: 1px solid var(--border-color); + border-radius: var(--radius-lg); + transition: var(--transition); +} + +.comment-body:hover { + border-color: var(--border-hover); + box-shadow: var(--shadow-sm); +} + +.comment-avatar { + flex-shrink: 0; +} + +.comment-avatar img { + width: 48px; + height: 48px; + border-radius: 50%; + border: 2px solid var(--bg-secondary); +} + +.comment-content { + flex: 1; + min-width: 0; +} + +.comment-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 10px; +} + +.comment-author { + font-weight: 600; + color: var(--text-primary); + font-size: 0.9375rem; +} + +.comment-author a { + color: var(--text-primary); + text-decoration: none; +} + +.comment-author a:hover { + color: var(--primary-color); +} + +.comment-header time { + font-size: 0.8125rem; + color: var(--text-muted); +} + +.comment-text { + color: var(--text-secondary); + line-height: 1.7; + font-size: 0.9375rem; +} + +.comment-text p:last-child { + margin-bottom: 0; +} + +.comment-actions { + margin-top: 12px; +} + +.comment-actions a { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 0.8125rem; + color: var(--text-muted); + font-weight: 500; + padding: 4px 10px; + border-radius: var(--radius-sm); + transition: var(--transition); +} + +.comment-actions a:hover { + color: var(--primary-color); + background: rgba(37, 99, 235, 0.05); +} + +/* Comment Form */ +.comment-form { + margin-top: 40px; + padding: 32px; + background: var(--bg-secondary); + border-radius: var(--radius-xl); + border: 1px solid var(--border-color); +} + +.comment-form-group { + margin-bottom: 20px; +} + +.comment-form-group label { + display: flex; + align-items: center; + gap: 8px; + font-weight: 600; + color: var(--text-primary); + margin-bottom: 12px; + font-size: 0.9375rem; +} + +.comment-form-group label svg { + color: var(--primary-color); +} + +.comment-form-group textarea { + width: 100%; + padding: 16px; + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + font-size: 1rem; + font-family: var(--font-sans); + background: var(--bg-primary); + color: var(--text-primary); + resize: vertical; + min-height: 120px; + transition: var(--transition); +} + +.comment-form-group textarea:focus { + outline: none; + border-color: var(--primary-color); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); +} + +.comment-form-group textarea::placeholder { + color: var(--text-muted); +} + +.comment-form .comment-form-cookies-consent { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 20px; + font-size: 0.875rem; + color: var(--text-secondary); +} + +.comment-form .comment-form-cookies-consent input[type="checkbox"] { + width: 18px; + height: 18px; + accent-color: var(--primary-color); +} + +.comment-form .submit-btn { + display: inline-flex; + align-items: center; + gap: 10px; + padding: 14px 28px; + background: var(--primary-color); + color: white; + border: none; + border-radius: var(--radius-md); + font-size: 1rem; + font-weight: 600; + font-family: var(--font-sans); + cursor: pointer; + transition: var(--transition); +} + +.comment-form .submit-btn:hover { + background: var(--primary-hover); + transform: translateY(-1px); + box-shadow: var(--shadow-md); +} + +.comment-form .submit-btn svg { + transition: transform 0.2s ease; +} + +.comment-form .submit-btn:hover svg { + transform: translateX(2px) translateY(-2px); +} + +.no-comments { + text-align: center; + padding: 32px; + color: var(--text-muted); + font-size: 0.9375rem; +} + +.post-header { + margin-bottom: 32px; + padding-bottom: 24px; + border-bottom: 1px solid var(--border-color); +} + +.post-header .post-category { + margin-bottom: 16px; +} + +.post-title { + font-size: 2.25rem; + font-weight: 800; + line-height: 1.3; + margin-bottom: 16px; + letter-spacing: -0.02em; +} + +.post-meta-full { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 20px; + color: var(--text-muted); + font-size: 0.9375rem; +} + +.post-meta-full a { + color: var(--text-muted); +} + +.post-meta-full a:hover { + color: var(--primary-color); +} + +.author-avatar { + width: 40px; + height: 40px; + border-radius: 50%; + background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 600; + font-size: 1rem; +} + +/* ==================== Post Content ==================== */ +.post-content { + font-size: 1.0625rem; + line-height: 1.8; + color: var(--text-primary); +} + +.post-content h2 { + font-size: 1.75rem; + font-weight: 700; + margin-top: 48px; + margin-bottom: 20px; + padding-bottom: 12px; + border-bottom: 2px solid var(--border-color); + letter-spacing: -0.01em; +} + +.post-content h3 { + font-size: 1.375rem; + font-weight: 600; + margin-top: 36px; + margin-bottom: 16px; +} + +.post-content h4 { + font-size: 1.125rem; + font-weight: 600; + margin-top: 28px; + margin-bottom: 12px; +} + +.post-content p { + margin-bottom: 20px; +} + +.post-content a { + color: var(--primary-color); + text-decoration: underline; + text-decoration-color: rgba(37, 99, 235, 0.3); + text-underline-offset: 3px; +} + +.post-content a:hover { + text-decoration-color: var(--primary-color); +} + +.post-content ul, +.post-content ol { + margin-bottom: 20px; + padding-left: 28px; +} + +.post-content li { + margin-bottom: 8px; +} + +.post-content li::marker { + color: var(--primary-color); +} + +.post-content blockquote { + margin: 24px 0; + padding: 20px 24px; + border-left: 4px solid var(--primary-color); + background: var(--bg-secondary); + border-radius: 0 var(--radius-md) var(--radius-md) 0; + font-style: italic; + color: var(--text-secondary); +} + +.post-content blockquote p:last-child { + margin-bottom: 0; +} + +.post-content img { + border-radius: var(--radius-md); + margin: 24px 0; + box-shadow: var(--shadow-md); +} + +.post-content hr { + border: none; + height: 1px; + background: var(--border-color); + margin: 40px 0; +} + +.post-content table { + width: 100%; + border-collapse: collapse; + margin: 24px 0; + font-size: 0.9375rem; +} + +.post-content th, +.post-content td { + padding: 12px 16px; + text-align: left; + border: 1px solid var(--border-color); +} + +.post-content th { + background: var(--bg-secondary); + font-weight: 600; + color: var(--text-primary); +} + +.post-content tr:hover { + background: var(--bg-secondary); +} + +/* Inline Code */ +.post-content code:not(pre code) { + background: var(--bg-tertiary); + color: var(--secondary-color); + padding: 2px 8px; + border-radius: 4px; + font-family: var(--font-mono); + font-size: 0.875em; + font-weight: 500; +} + +/* Code Blocks */ +.post-content pre { + background: var(--bg-code); + color: var(--text-code); + padding: 24px; + border-radius: var(--radius-md); + overflow-x: auto; + margin: 24px 0; + position: relative; + font-family: var(--font-mono); + font-size: 0.9375rem; + line-height: 1.6; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.post-content pre code { + background: none; + padding: 0; + color: inherit; + font-size: inherit; +} + +.code-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 16px; + background: rgba(0, 0, 0, 0.3); + border-radius: var(--radius-md) var(--radius-md) 0 0; + margin: -24px -24px 16px -24px; + font-size: 0.8125rem; +} + +.code-lang { + color: var(--accent-color); + font-weight: 600; + text-transform: uppercase; +} + +.copy-btn { + display: flex; + align-items: center; + gap: 6px; + background: none; + border: 1px solid rgba(255, 255, 255, 0.2); + color: rgba(255, 255, 255, 0.6); + padding: 6px 12px; + border-radius: var(--radius-sm); + cursor: pointer; + font-size: 0.75rem; + transition: var(--transition); +} + +.copy-btn:hover { + background: rgba(255, 255, 255, 0.1); + color: white; +} + +.copy-btn svg { + width: 14px; + height: 14px; +} + +/* ==================== Table of Contents ==================== */ +.toc-container { + position: sticky; + top: calc(var(--header-height) + 32px); +} + +.toc { + background: var(--bg-primary); + border: 1px solid var(--border-color); + border-radius: var(--radius-lg); + padding: 24px; + max-height: calc(100vh - var(--header-height) - 64px); + overflow-y: auto; +} + +.toc-title { + font-size: 0.875rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--text-muted); + margin-bottom: 16px; + display: flex; + align-items: center; + gap: 8px; +} + +.toc-title svg { + width: 16px; + height: 16px; +} + +.toc-list { + list-style: none; + padding: 0; +} + +.toc-list li { + margin-bottom: 4px; +} + +.toc-list a { + display: block; + padding: 8px 12px; + color: var(--text-secondary); + font-size: 0.875rem; + border-radius: var(--radius-sm); + border-left: 2px solid transparent; + transition: var(--transition); +} + +.toc-list a:hover { + color: var(--text-primary); + background: var(--bg-secondary); +} + +.toc-list a.active { + color: var(--primary-color); + background: rgba(37, 99, 235, 0.05); + border-left-color: var(--primary-color); + font-weight: 500; +} + +.toc-list .toc-h3 { + padding-left: 24px; + font-size: 0.8125rem; +} + +/* ==================== Sidebar ==================== */ +.sidebar { + position: sticky; + top: calc(var(--header-height) + 32px); + height: fit-content; +} + +.sidebar-widget { + background: var(--bg-primary); + border: 1px solid var(--border-color); + border-radius: var(--radius-lg); + padding: 24px; + margin-bottom: 24px; +} + +.widget-title { + font-size: 0.875rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--text-muted); + margin-bottom: 20px; + padding-bottom: 12px; + border-bottom: 2px solid var(--border-color); +} + +/* Categories Widget */ +.category-list { + list-style: none; +} + +.category-list li { + margin-bottom: 8px; +} + +.category-list a { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 14px; + color: var(--text-secondary); + background: var(--bg-secondary); + border-radius: var(--radius-sm); + font-size: 0.9375rem; + transition: var(--transition); +} + +.category-list a:hover { + background: var(--primary-color); + color: white; +} + +.category-count { + background: var(--bg-primary); + padding: 2px 10px; + border-radius: 100px; + font-size: 0.75rem; + font-weight: 600; +} + +.category-list a:hover .category-count { + background: rgba(255, 255, 255, 0.2); + color: white; +} + +/* Tags Widget */ +.tag-cloud { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.tag-cloud a { + display: inline-block; + padding: 6px 14px; + background: var(--bg-secondary); + color: var(--text-secondary); + border-radius: 100px; + font-size: 0.8125rem; + transition: var(--transition); +} + +.tag-cloud a:hover { + background: var(--primary-color); + color: white; +} + +/* Recent Posts Widget */ +.recent-posts-list { + list-style: none; +} + +.recent-posts-list li { + padding: 16px 0; + border-bottom: 1px solid var(--border-color); +} + +.recent-posts-list li:last-child { + border-bottom: none; + padding-bottom: 0; +} + +.recent-posts-list li:first-child { + padding-top: 0; +} + +.recent-post-title { + display: block; + font-size: 0.9375rem; + font-weight: 500; + color: var(--text-primary); + line-height: 1.4; + margin-bottom: 6px; +} + +.recent-post-title:hover { + color: var(--primary-color); +} + +.recent-post-date { + font-size: 0.8125rem; + color: var(--text-muted); +} + +/* ==================== Pagination ==================== */ +.pagination { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + margin-top: 48px; + padding-top: 32px; + border-top: 1px solid var(--border-color); +} + +.pagination a, +.pagination span { + display: flex; + align-items: center; + justify-content: center; + min-width: 40px; + height: 40px; + padding: 0 12px; + border: 1px solid var(--border-color); + border-radius: var(--radius-sm); + font-size: 0.9375rem; + font-weight: 500; + transition: var(--transition); +} + +.pagination a { + color: var(--text-secondary); +} + +.pagination a:hover { + background: var(--bg-secondary); + color: var(--text-primary); + border-color: var(--border-hover); +} + +.pagination .current { + background: var(--primary-color); + color: white; + border-color: var(--primary-color); +} + +.pagination .dots { + border: none; + color: var(--text-muted); +} + +/* ==================== Search Overlay ==================== */ +.search-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(8px); + z-index: 2000; + display: flex; + align-items: flex-start; + justify-content: center; + padding-top: 20vh; + opacity: 0; + visibility: hidden; + transition: var(--transition); +} + +.search-overlay.active { + opacity: 1; + visibility: visible; +} + +.search-container { + background: var(--bg-primary); + border-radius: var(--radius-xl); + padding: 24px; + width: 90%; + max-width: 640px; + box-shadow: var(--shadow-lg); + transform: translateY(-20px); + transition: transform 0.3s ease; +} + +.search-overlay.active .search-container { + transform: translateY(0); +} + +.search-input-wrapper { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 16px; + background: var(--bg-secondary); + border-radius: var(--radius-md); + border: 2px solid var(--border-color); + transition: var(--transition); +} + +.search-input-wrapper:focus-within { + border-color: var(--primary-color); +} + +.search-input-wrapper svg { + width: 20px; + height: 20px; + color: var(--text-muted); + flex-shrink: 0; +} + +.search-input { + flex: 1; + border: none; + background: none; + font-size: 1.0625rem; + color: var(--text-primary); + outline: none; +} + +.search-input::placeholder { + color: var(--text-muted); +} + +.search-hint { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 12px; + font-size: 0.8125rem; + color: var(--text-muted); +} + +.search-hint kbd { + background: var(--bg-tertiary); + padding: 2px 8px; + border-radius: 4px; + font-family: var(--font-mono); + font-size: 0.75rem; +} + +/* ==================== Footer ==================== */ +.site-footer { + background: var(--bg-secondary); + border-top: 1px solid var(--border-color); + padding: 48px 24px; + margin-top: 64px; +} + +.footer-inner { + max-width: var(--container-max-width); + margin: 0 auto; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 48px; +} + +.footer-section h3 { + font-size: 1rem; + font-weight: 600; + margin-bottom: 20px; + color: var(--text-primary); +} + +.footer-section p { + color: var(--text-secondary); + font-size: 0.9375rem; + line-height: 1.6; +} + +.footer-links { + list-style: none; +} + +.footer-links li { + margin-bottom: 10px; +} + +.footer-links a { + color: var(--text-secondary); + font-size: 0.9375rem; +} + +.footer-links a:hover { + color: var(--primary-color); +} + +.footer-bottom { + max-width: var(--container-max-width); + margin: 32px auto 0; + padding-top: 24px; + border-top: 1px solid var(--border-color); + display: flex; + align-items: center; + justify-content: space-between; + color: var(--text-muted); + font-size: 0.875rem; +} + +/* ==================== Responsive ==================== */ +@media (max-width: 1024px) { + .site-container { + grid-template-columns: 1fr; + } + + .sidebar { + position: static; + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 24px; + } + + .sidebar-widget { + margin-bottom: 0; + } + + .toc-container { + display: none; + } +} + +@media (max-width: 768px) { + :root { + --header-height: 56px; + } + + .header-inner { + padding: 0 16px; + } + + .main-nav { + display: none; + } + + .mobile-menu-toggle { + display: flex; + } + + .main-nav.active { + display: flex; + flex-direction: column; + position: absolute; + top: var(--header-height); + left: 0; + right: 0; + background: var(--bg-primary); + border-bottom: 1px solid var(--border-color); + padding: 16px; + box-shadow: var(--shadow-md); + } + + .main-nav.active a { + padding: 12px 16px; + } + + .site-container { + padding: 20px 16px; + gap: 24px; + } + + .hero-section { + padding: 32px 24px; + } + + .hero-title { + font-size: 1.5rem; + } + + .post-card { + padding: 20px; + } + + .post-title { + font-size: 1.75rem; + } + + .post-content pre { + padding: 16px; + margin-left: -16px; + margin-right: -16px; + border-radius: 0; + } + + .sidebar { + grid-template-columns: 1fr; + } + + .footer-inner { + grid-template-columns: 1fr; + gap: 32px; + } + + .footer-bottom { + flex-direction: column; + gap: 12px; + text-align: center; + } +} + +/* ==================== Animations ==================== */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } +} + +.post-card { + animation: fadeIn 0.5s ease forwards; +} + +.post-card:nth-child(2) { animation-delay: 0.1s; } +.post-card:nth-child(3) { animation-delay: 0.2s; } +.post-card:nth-child(4) { animation-delay: 0.3s; } + +/* ==================== Print Styles ==================== */ +@media print { + .site-header, + .sidebar, + .toc-container, + .post-card-footer, + .pagination { + display: none !important; + } + + .site-container { + grid-template-columns: 1fr; + } + + .post-content pre { + white-space: pre-wrap; + word-wrap: break-word; + } +}