6 Commits

Author SHA1 Message Date
浪子 33175a8951 0.8 2025-07-23 16:26:09 +08:00
浪子 0ed7e7b5e8 0.7.3
解决类名相同的问题
2025-06-11 17:15:57 +08:00
浪子 6f37575943 0.7.2
fix 翻页样式
2025-06-06 09:01:26 +08:00
浪子 6b8f758dcf 0.7.2
友好时间显示
2025-06-04 10:33:16 +08:00
浪子 1f535bb9d6 0.7.2
修复置顶文章问题
2025-05-24 18:55:25 +08:00
浪子 a42f5f41ca 0.7.2
更新预览
2025-05-22 19:24:20 +08:00
14 changed files with 442 additions and 153 deletions
+1
View File
@@ -1,3 +1,4 @@
tooot.php
Parsedown.php
/assets/images/covers
+11 -2
View File
@@ -6,8 +6,17 @@
## 更新日志 & 预览
### 0.8
- 兼容 Typecho 1.3.0
- 自动裁切封面并保存在主题目录 `usr/cache/covers` 下,使用前必须开启 `php``GD拓展``usr`目录的写权限.
- 站点统计
### 0.7.2
- 优化页面加载速度,自动裁切封面,并压缩为`webp`格式,并保存在主题目录`assets`-`images`-`covers`下,使用前必须开启`php``GD拓展`和主题目录的写入权限
- ~~优化页面加载速度,自动裁切封面,并压缩为`webp`格式,并保存在主题目录`assets`-`images`-`covers`下,使用前必须开启`php``GD拓展`和主题目录的写入权限~~
- 修复了置顶文章和翻页的问题
### 0.7.1
@@ -40,7 +49,7 @@
[预览](https://www.imsun.org/)
[预览](https://blog.imsun.org/)
https://www.imsun.org/archives/1640.html
+4 -3
View File
@@ -17,7 +17,7 @@
is_single = false;
post_id = 0;
is_archive = false;
VERSION = "0.7.2";
VERSION = "0.8";
constructor() {
super();
this.initCopyright();
@@ -45,8 +45,9 @@
}
}
initCopyright() {
const copyright = `<div class="site--footer__info">由<a href="https://www.typecho.org" target="_blank">Typecho</a> 驱动 <br>
Theme <a href="https://fatesinger.com/101971" target="_blank">farallon</a> by bigfa &nbsp;<br>Made with&nbsp;<a href="https://www.imsun.org" target="_blank">老孙博客</a> / version ${this.VERSION}
const copyright = `<div class="site--footer__info">
Theme <a href="https://github.com/jkjoy/typecho-theme-farallon" target="_blank">farallon</a> Designed by <a href="https://fatesinger.com/" target="_blank">bigfa</a> &nbsp;
<p><a href="https://www.imsun.org" target="_blank"> 老孙博客</a> 移植 / version ${this.VERSION}</p>
</div>`;
document.querySelector(".site--footer__content").insertAdjacentHTML("afterend", copyright);
document.querySelector(".icon--copryrights").addEventListener("click", () => {
+1 -1
View File
@@ -35,7 +35,7 @@ document.addEventListener('DOMContentLoaded', function() {
});
}
// 给所有复制链接添加点击事件
document.querySelectorAll('.text').forEach(link => {
document.querySelectorAll('.copy').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const textToCopy = this.getAttribute('data-copy') || this.textContent;
+5 -4
View File
@@ -5,16 +5,17 @@
<?php $this->need('./module/sns.php'); ?>
<?php //sitemap填入
if($this->options->sitemapurl): ?>
<a href="<?php $this->options->sitemapurl() ?>" target="_blank" aria-label="网站地图">💗</a>
<a href="<?php $this->options->sitemapurl() ?>" target="_blank" aria-label="网站地图"></a>
<?php endif; ?>
</div>
<?php //添加加载时间控制
if ($this->options->showtime): ?>
&nbsp;页面加载耗时<?php echo timer_stop();?>
<?php endif; ?>
<?php $this->options->tongji(); ?>
<div class="copyright"> © <?php echo date('Y'); ?>
<?php $this->options->title(); ?>
<?php $this->options->tongji(); ?>
<?php $stats = getSiteStatsWithCache(); ?>
<div class="copyright"> © <?php echo $stats['siteCreateYear']; ?>-<?php echo date('Y'); ?>
<?php $this->options->title(); ?> 💗 由 <a href="https://www.typecho.org" target="_blank"> Typecho </a> 驱动
<svg class="icon icon--copryrights" viewBox="0 0 1040 1024" width="16" height="16">
<path
d="M717.056236 383.936299l-51.226708 0c-28.2893 0-51.226708 22.936385-51.226708 51.225685l0 128.062678c0 28.2893 22.937408 51.225685 51.226708 51.225685l51.226708 0c28.2893 0 51.225685-22.936385 51.225685-51.225685L768.281921 435.161984C768.281921 406.872684 745.345536 383.936299 717.056236 383.936299zM717.056236 537.611308c0 14.158465-11.480472 25.612331-25.613354 25.612331-14.132882 0-25.612331-11.453866-25.612331-25.612331l0-76.835969c0-14.158465 11.480472-25.613354 25.612331-25.613354 14.133905 0 25.613354 11.453866 25.613354 25.613354L717.056236 537.611308zM1013.977739 426.580538 859.776751 165.30079c-8.888438-15.063067-22.294772-25.975605-37.57171-32.080649-32.708959-34.856879-79.187527-56.638975-130.762159-56.638975L332.862064 76.581166c-51.575656 0-98.0532 21.782096-130.761136 56.639998-15.276938 6.105045-28.683273 17.017582-37.572734 32.079626L10.327206 426.580538c-21.26021 36.069497-8.655124 82.217537 28.239158 103.028515l115.00836 64.967664 0 199.163015c0 99.024318 80.264045 153.678078 179.287339 153.678078l358.580818 0c99.024318 0 179.290409-80.266092 179.290409-179.290409L870.733291 594.575694l115.00836-64.966641C1022.63184 508.798075 1035.238972 462.650035 1013.977739 426.580538zM153.574724 536.518417l-67.058278-37.875632c-24.589025-13.907755-33.019021-44.647873-18.809391-68.684312l85.86767-145.555074L153.574724 536.518417zM646.620024 127.807874c0 56.5786-60.205197 102.45137-134.467551 102.45137-74.261331 0-134.466528-45.873794-134.466528-102.45137L646.620024 127.807874zM819.507606 742.515071c0 84.893482-68.810179 153.677055-153.678078 153.677055L358.475418 896.192126c-84.8679 0-153.675008-68.783573-153.675008-153.677055l0-461.030142c0-76.150354 55.402821-139.361001 128.093377-151.545508 1.332345 83.883479 81.06734 151.545508 179.258687 151.545508 98.19237 0 177.926342-67.662029 179.25971-151.545508 72.690556 12.183484 128.096447 75.394131 128.096447 151.545508L819.508629 742.515071zM937.791569 498.642784l-67.058278 37.875632 0-252.111948 85.86767 145.552004C970.807521 453.995935 962.377524 484.736053 937.791569 498.642784z"
+306 -68
View File
@@ -22,6 +22,11 @@ function themeConfig($form) {
$form->addInput($twitterurl);
$mastodonurl = new Typecho_Widget_Helper_Form_Element_Text('mastodonurl', NULL, NULL, _t('mastodon'), _t('会在个人信息显示'));
$form->addInput($mastodonurl);
$friendlyTime = new Typecho_Widget_Helper_Form_Element_Radio('friendlyTime',
array('0' => _t('否'),
'1' => _t('是')),
'0', _t('是否显示友好时间'), _t('默认不显示友好时间,显示标准时间格式'));
$form->addInput($friendlyTime);
$showProfile = new Typecho_Widget_Helper_Form_Element_Radio('showProfile',
array('0'=> _t('否'), '1'=> _t('是')),
'0', _t('是否在文章页面显示作者信息'), _t('选择"是"将在文章页面包含显示作者信息。'));
@@ -114,7 +119,7 @@ define('__TYPECHO_GRAVATAR_PREFIX__', $gravatarPrefix);
// 初始化主题
function init_theme() {
// 检查并创建封面图片目录
$coversDir = dirname(__FILE__) . '/assets/images/covers';
$coversDir = __TYPECHO_ROOT_DIR__ . '/usr/cache/covers';
if (!is_dir($coversDir)) {
@mkdir($coversDir, 0755, true);
}
@@ -193,22 +198,15 @@ function getPermalinkFromCoid($coid) {
*/
class ImageStructureProcessor {
public static function processContent($content, $widget, $lastResult = null) {
// 首先应用之前的过滤器结果
$content = empty($lastResult) ? $content : $lastResult;
// 检查内容是否为空
if (empty($content) || !is_string($content)) {
return $content;
}
if ($widget instanceof Widget_Archive) {
try {
// 使用 DOM 操作确保结构完整性
$dom = new DOMDocument('1.0', 'UTF-8');
// 添加错误处理
libxml_use_internal_errors(true);
// 添加基础 HTML 结构以确保正确解析
$content = '<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><div>' . $content . '</div></body></html>';
// 直接加载内容到 DOM
$dom->loadHTML($content,
LIBXML_HTML_NOIMPLIED |
LIBXML_HTML_NODEFDTD |
@@ -216,7 +214,6 @@ class ImageStructureProcessor {
LIBXML_NOWARNING
);
$xpath = new DOMXPath($dom);
// 查找所有没有父 figure 的图片,排除 SVG
$images = $xpath->query("//img[not(ancestor::figure) and not(contains(@src, '.svg'))]");
if ($images->length > 0) {
foreach ($images as $img) {
@@ -270,10 +267,6 @@ class ImageStructureProcessor {
return $content;
}
}
// u6ce8u91cau6389u8fd9u884cuff0cu9632u6b62u8986u76d6u8fd9u4e2au94a9u5b50u7684u5176u4ed6u6ce8u518c
// Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = function($content, $widget) {
// return ImageStructureProcessor::processContent($content, $widget);
// };
/**
* 处理图片为封面图(裁剪为5:3,最大宽度500px,转换为webp
@@ -297,10 +290,9 @@ function process_cover_image($imageUrl) {
$filename = md5($imageUrl) . '.webp';
// 处理后图片的保存路径
$themeDir = dirname(__FILE__);
$savePath = $themeDir . '/assets/images/covers/' . $filename;
$webPath = Helper::options()->themeUrl . '/assets/images/covers/' . $filename;
$savePath = __TYPECHO_ROOT_DIR__ . '/usr/cache/covers/' . $filename;
$webPath = Helper::options()->siteUrl . '/usr/cache/covers/' . $filename;
// 如果缓存文件已存在,直接返回
if (file_exists($savePath)) {
return $webPath;
@@ -373,8 +365,8 @@ function process_cover_image($imageUrl) {
if (!function_exists('imagewebp')) {
// 如果不支持webp,保存为png
$filename = md5($imageUrl) . '.png';
$savePath = $themeDir . '/assets/images/covers/' . $filename;
$webPath = Helper::options()->themeUrl . '/assets/images/covers/' . $filename;
$savePath = __TYPECHO_ROOT_DIR__ . '/usr/cache/covers/' . $filename;
$webPath = Helper::options()->siteUrl . '/usr/cache/covers/' . $filename;
imagepng($targetImage, $savePath, 9); // 9是最高压缩质量
} else {
// 保存为webp
@@ -394,23 +386,60 @@ function process_cover_image($imageUrl) {
*
*/
function get_article_summary($post) {
// 首先尝试从自定义字段获取摘要
// 优先从自定义字段获取摘要
$db = Typecho_Db::get();
// 查询自定义字段表
$row = $db->fetchRow($db->select()
$row = $db->fetchRow($db->select('str_value')
->from('table.fields')
->where('cid = ?', $post['cid'])
->where('name = ?', 'summary'));
// 如果找到自定义摘要字段
if ($row && !empty($row['str_value'])) {
return $row['str_value'];
}
// 如果没有自定义摘要,截取文章内容
// 去除HTML标签
// 确保自定义摘要不超过 100 字节
$text = $row['str_value'];
$byte_limit = 280;
$summary = '';
$byte_count = 0;
$length = mb_strlen($text, 'UTF-8');
for ($i = 0; $i < $length; $i++) {
$char = mb_substr($text, $i, 1, 'UTF-8');
$char_bytes = strlen($char);
if ($byte_count + $char_bytes > $byte_limit) {
break;
}
$summary .= $char;
$byte_count += $char_bytes;
}
return $summary;
}
// 没有自定义摘要,处理文章内容
if (empty($post['text']) || !is_string($post['text'])) {
return '';
}
$text = strip_tags($post['text']);
// 截取指定长度的摘要
return Typecho_Common::subStr($text, 0, 100, '...');
$byte_limit = 277; // 预留 3 字节给省略号
$summary = '';
$byte_count = 0;
$length = mb_strlen($text, 'UTF-8');
for ($i = 0; $i < $length; $i++) {
$char = mb_substr($text, $i, 1, 'UTF-8');
$char_bytes = strlen($char);
if ($byte_count + $char_bytes > $byte_limit) {
break;
}
$summary .= $char;
$byte_count += $char_bytes;
}
// 如果截断了,添加省略号
if ($byte_count < strlen($text)) {
$summary .= '...';
}
return $summary;
}
// 在原函数中使用
function get_article_info($atts) {
@@ -494,8 +523,6 @@ class ContentFilter
return $atts;
}
}
// 注册钩子
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('ContentFilter', 'filterContent');
// 编辑器按钮类
class EditorButton {
public static function render()
@@ -605,60 +632,271 @@ function commentApprove($widget, $email = NULL)
}
/**
* 修改附件插入功能
* Typecho后台附件增强:图片预览、批量插入、保留官方删除按钮与逻辑
* @author 老孙博客
* @date 2025-04-25
*/
// 添加批量插入按钮的JavaScript
// 避免重复注册,使用条件判断
if (!Typecho_Plugin::exists('admin/write-post.php', 'bottom')) {
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('MyHelper', 'addBatchInsertButton');
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('MyHelper', 'addBatchInsertButton');
}
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('AttachmentHelper', 'addEnhancedFeatures');
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('AttachmentHelper', 'addEnhancedFeatures');
class MyHelper {
public static function addBatchInsertButton() {
class AttachmentHelper {
public static function addEnhancedFeatures() {
?>
<style>
#file-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:15px;padding:15px;list-style:none;margin:0;}
#file-list li{position:relative;border:1px solid #e0e0e0;border-radius:4px;padding:10px;background:#fff;transition:all 0.3s ease;list-style:none;margin:0;}
#file-list li:hover{box-shadow:0 2px 8px rgba(0,0,0,0.1);}
#file-list li.loading{opacity:0.7;pointer-events:none;}
.att-enhanced-thumb{position:relative;width:100%;height:150px;margin-bottom:8px;background:#f5f5f5;overflow:hidden;border-radius:3px;display:flex;align-items:center;justify-content:center;}
.att-enhanced-thumb img{width:100%;height:100%;object-fit:contain;display:block;}
.att-enhanced-thumb .file-icon{display:flex;align-items:center;justify-content:center;width:100%;height:100%;font-size:40px;color:#999;}
.att-enhanced-finfo{padding:5px 0;}
.att-enhanced-fname{font-size:13px;margin-bottom:5px;word-break:break-all;color:#333;}
.att-enhanced-fsize{font-size:12px;color:#999;}
.att-enhanced-factions{display:flex;justify-content:space-between;align-items:center;margin-top:8px;gap:8px;}
.att-enhanced-factions button{flex:1;padding:4px 8px;border:none;border-radius:3px;background:#e0e0e0;color:#333;cursor:pointer;font-size:12px;transition:all 0.2s ease;}
.att-enhanced-factions button:hover{background:#d0d0d0;}
.att-enhanced-factions .btn-insert{background:#467B96;color:white;}
.att-enhanced-factions .btn-insert:hover{background:#3c6a81;}
.att-enhanced-checkbox{position:absolute;top:5px;right:5px;z-index:2;width:18px;height:18px;cursor:pointer;}
.batch-actions{margin:15px;display:flex;gap:10px;align-items:center;}
.btn-batch{padding:8px 15px;border-radius:4px;border:none;cursor:pointer;transition:all 0.3s ease;font-size:10px;display:inline-flex;align-items:center;justify-content:center;}
.btn-batch.primary{background:#467B96;color:white;}
.btn-batch.primary:hover{background:#3c6a81;}
.btn-batch.secondary{background:#e0e0e0;color:#333;}
.btn-batch.secondary:hover{background:#d0d0d0;}
.upload-progress{position:absolute;bottom:0;left:0;width:100%;height:2px;background:#467B96;transition:width 0.3s ease;}
</style>
<script>
$(document).ready(function() {
// 添加批量插入按钮
var batchButton = $('<button type="button" class="btn primary" id="batch-insert">批量插入所有附件</button>');
$('#file-list').before(batchButton);
// 修改单个附件的插入格式
// 批量操作UI按钮
var $batchActions = $('<div class="batch-actions"></div>')
.append('<button type="button" class="btn-batch primary" id="batch-insert">批量插入</button>')
.append('<button type="button" class="btn-batch secondary" id="select-all">全选</button>')
.append('<button type="button" class="btn-batch secondary" id="unselect-all">取消全选</button>');
$('#file-list').before($batchActions);
// 插入格式
Typecho.insertFileToEditor = function(title, url, isImage) {
var textarea = $('#text'), sel = textarea.getSelection(),
var textarea = $('#text'),
sel = textarea.getSelection(),
insertContent = isImage ? '![' + title + '](' + url + ')' :
'[' + title + '](' + url + ')';
textarea.replaceSelection(insertContent);
textarea.replaceSelection(insertContent + '\n');
textarea.focus();
};
// 批量插入功能
$('#batch-insert').click(function() {
// 批量插入
$('#batch-insert').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var content = '';
$('#file-list li').each(function() {
var $this = $(this),
title = $this.find('.insert').text(),
url = $this.data('url'),
isImage = $this.data('image') == 1;
content += isImage ? '![' + title + '](' + url + ')\n' :
'[' + title + '](' + url + ')\n';
if ($(this).find('.att-enhanced-checkbox').is(':checked')) {
var $li = $(this);
var title = $li.find('.att-enhanced-fname').text();
var url = $li.data('url');
var isImage = $li.data('image') == 1;
content += isImage ? '![' + title + '](' + url + ')\n' : '[' + title + '](' + url + ')\n';
}
});
var textarea = $('#text');
var pos = textarea.getSelection();
var newContent = textarea.val();
if (pos.start === pos.end) {
newContent = newContent.substring(0, pos.start) + content + newContent.substring(pos.start);
} else {
if (content) {
var textarea = $('#text');
var pos = textarea.getSelection();
var newContent = textarea.val();
newContent = newContent.substring(0, pos.start) + content + newContent.substring(pos.end);
textarea.val(newContent);
textarea.focus();
}
textarea.val(newContent);
textarea.focus();
});
$('#select-all').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$('#file-list .att-enhanced-checkbox').prop('checked', true);
return false;
});
$('#unselect-all').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$('#file-list .att-enhanced-checkbox').prop('checked', false);
return false;
});
// 防止复选框冒泡
$(document).on('click', '.att-enhanced-checkbox', function(e) {e.stopPropagation();});
// 增强文件列表样式,但不破坏li原结构和官方按钮
function enhanceFileList() {
$('#file-list li').each(function() {
var $li = $(this);
if ($li.hasClass('att-enhanced')) return;
$li.addClass('att-enhanced');
// 只增强,不清空li
// 增加批量选择框
if ($li.find('.att-enhanced-checkbox').length === 0) {
$li.prepend('<input type="checkbox" class="att-enhanced-checkbox" />');
}
// 增加图片预览(如已有则不重复加)
if ($li.find('.att-enhanced-thumb').length === 0) {
var url = $li.data('url');
var isImage = $li.data('image') == 1;
var fileName = $li.find('.insert').text();
var $thumbContainer = $('<div class="att-enhanced-thumb"></div>');
if (isImage) {
var $img = $('<img src="' + url + '" alt="' + fileName + '" />');
$img.on('error', function() {
$(this).replaceWith('<div class="file-icon">🖼️</div>');
});
$thumbContainer.append($img);
} else {
$thumbContainer.append('<div class="file-icon">📄</div>');
}
// 插到插入按钮之前
$li.find('.insert').before($thumbContainer);
}
});
}
// 插入按钮事件
$(document).on('click', '.btn-insert', function(e) {
e.preventDefault();
e.stopPropagation();
var $li = $(this).closest('li');
var title = $li.find('.att-enhanced-fname').text();
Typecho.insertFileToEditor(title, $li.data('url'), $li.data('image') == 1);
});
// 上传完成后增强新项
var originalUploadComplete = Typecho.uploadComplete;
Typecho.uploadComplete = function(attachment) {
setTimeout(function() {
enhanceFileList();
}, 200);
if (typeof originalUploadComplete === 'function') {
originalUploadComplete(attachment);
}
};
// 首次增强
enhanceFileList();
});
</script>
<?php
}
}
?>
<?php
/**
* 友好时间显示函数
* @param int $time 时间戳
* @param int $threshold 阈值(秒),超过此值则显示标准日期格式(Y-m-d)
* @return string
*/
function time_ago($time, $threshold = 31536000) { // 31536000秒 = 1年
$now = time();
$difference = $now - $time;
// 如果时间差超过阈值(默认1年),则返回标准日期格式(不带时间)
if ($difference >= $threshold) {
return date('Y-m-d', $time);
}
// 1年以内的时间,返回友好格式(如 "3天前"
$periods = array("秒", "分钟", "小时", "天", "周", "个月", "年");
$lengths = array("60", "60", "24", "7", "4.35", "12");
for ($j = 0; $difference >= $lengths[$j] && $j < count($lengths); $j++) {
$difference /= $lengths[$j];
}
$difference = round($difference);
return $difference . $periods[$j] . "前";
}
/***
* 获取站点统计信息(带缓存)
*/
function getSiteStatsWithCache() {
$cacheFile = __TYPECHO_ROOT_DIR__ . '/usr/cache/site_stats.cache';
$cacheTime = 3600; // 1小时缓存
$currentVersion = '1.1'; // 当前版本号
// 检查缓存
if (file_exists($cacheFile)) {
$cacheData = json_decode(file_get_contents($cacheFile), true);
if ($cacheData &&
isset($cacheData['cache_time']) &&
time() - $cacheData['cache_time'] < $cacheTime &&
isset($cacheData['cache_version']) &&
$cacheData['cache_version'] === $currentVersion) {
return $cacheData;
}
}
$db = Typecho_Db::get();
$stats = [];
// 1. 总分类数
$stats['totalCategories'] = $db->fetchObject($db->select('COUNT(*) AS cnt')
->from('table.metas')
->where('type = ?', 'category'))->cnt;
// 2. 总标签数
$stats['totalTags'] = $db->fetchObject($db->select('COUNT(*) AS cnt')
->from('table.metas')
->where('type = ?', 'tag'))->cnt;
// 3. 总文章数
$stats['totalPosts'] = $db->fetchObject($db->select('COUNT(*) AS cnt')
->from('table.contents')
->where('type = ?', 'post')
->where('status = ?', 'publish'))->cnt;
// 4. 总文章字数
$stats['totalWords'] = $db->fetchObject($db->select('SUM(LENGTH(text)) AS total')
->from('table.contents')
->where('type = ?', 'post')
->where('status = ?', 'publish'))->total ?: 0;
// 5. 建站时间
$oldestPost = $db->fetchObject($db->select('MIN(created) AS created')
->from('table.contents')
->where('type = ?', 'post')
->where('status = ?', 'publish'));
if ($oldestPost && !empty($oldestPost->created)) {
$stats['siteCreationDate'] = date('Y-m-d', $oldestPost->created);
$stats['siteCreateYear'] = date('Y', $oldestPost->created);
$stats['siteDays'] = ceil((time() - $oldestPost->created) / 86400);
} else {
$stats['siteCreationDate'] = 'N/A';
$stats['siteCreateYear'] = 'N/A';
$stats['siteDays'] = 0;
}
// 6. 友情链接数量
$stats['totalLinks'] = 0;
if (class_exists('Links_Plugin')) {
$stats['totalLinks'] = $db->fetchObject($db->select('COUNT(*) AS cnt')
->from('table.links'))->cnt ?: 0;
}
// 7. 总留言数量
$stats['totalComments'] = $db->fetchObject($db->select('COUNT(*) AS cnt')
->from('table.comments')
->where('status != ?', 'spam'))->cnt;
// 保存缓存
$stats['cache_time'] = time();
$stats['cache_version'] = $currentVersion; // 设置版本号
if (!is_dir(dirname($cacheFile))) {
mkdir(dirname($cacheFile), 0755, true);
}
if (!file_put_contents($cacheFile, json_encode($stats))) {
error_log('Failed to write site stats cache to ' . $cacheFile);
}
return $stats;
}
+27 -32
View File
@@ -39,42 +39,37 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
</script>
<div class="main">
<header class="site--header">
<?php if ($this->options->logoUrl): ?>
<a href="<?php $this->options->siteUrl(); ?>" class="site--url">
<img src="<?php $this->options->logoUrl() ?>" class="avatar" alt="<?php $this->options->title() ?>" />
</a>
<span class="u-xs-show">
<a href="<?php $this->options->siteUrl(); ?>"><?php $this->options->title() ?></a>
</span>
<?php else: ?>
<span class="u-xs-show">
<a href="<?php $this->options->siteUrl(); ?>"><?php $this->options->title() ?></a>
</span>
<?php endif; ?>
<div class="site--header__center">
<div class="inner">
<nav>
<ul>
<?php $this->widget('Widget_Contents_Page_List')->to($pages); ?>
<?php while($pages->next()): ?>
<li><a <?php if($this->is('page', $pages->slug)): ?> class="current"<?php endif; ?> href="<?php $pages->permalink(); ?>" title="<?php $pages->title(); ?>"><?php $pages->title(); ?></a></li>
<?php endwhile; ?>
</ul>
</nav>
<!-- 这年头谁会用站内的搜索啊 -->
<div class="search--area">
<?php if ($this->options->logoUrl): ?>
<a href="<?php $this->options->siteUrl(); ?>" class="site--url">
<img src="<?php $this->options->logoUrl() ?>" class="avatar" alt="<?php $this->options->title() ?>" />
</a>
<span class="u-xs-show">
<a href="<?php $this->options->siteUrl(); ?>"><?php $this->options->title() ?></a>
</span>
<?php else: ?>
<span class="u-xs-show">
<a href="<?php $this->options->siteUrl(); ?>"><?php $this->options->title() ?></a>
</span>
<?php endif; ?>
<div class="site--header__center">
<div class="inner">
<nav>
<ul>
<?php $this->widget('Widget_Contents_Page_List')->to($pages); ?>
<?php while($pages->next()): ?>
<li><a <?php if($this->is('page', $pages->slug)): ?> class="current"<?php endif; ?> href="<?php $pages->permalink(); ?>" title="<?php $pages->title(); ?>"><?php $pages->title(); ?></a></li>
<?php endwhile; ?>
</ul>
</nav>
<div class="search--area">
<form id="search" method="post" action="./" role="search" class="search-form">
<label>
<input type="text" name="s" class="search-field text" placeholder="Search" required/>
</label>
<button type="submit" class="search-submit submit">搜索</button>
</form>
</div>
</div>
</div>
<svg class="svgIcon" width="25" height="25" data-action="show-search">
<path
d="M20.067 18.933l-4.157-4.157a6 6 0 1 0-.884.884l4.157 4.157a.624.624 0 1 0 .884-.884zM6.5 11c0-2.62 2.13-4.75 4.75-4.75S16 8.38 16 11s-2.13 4.75-4.75 4.75S6.5 13.62 6.5 11z">
</path>
</svg>
</div>
</div>
</div>
<svg class="svgIcon" width="25" height="25" data-action="show-search"><path d="M20.067 18.933l-4.157-4.157a6 6 0 1 0-.884.884l4.157 4.157a.624.624 0 1 0 .884-.884zM6.5 11c0-2.62 2.13-4.75 4.75-4.75S16 8.38 16 11s-2.13 4.75-4.75 4.75S6.5 13.62 6.5 11z"></path></svg>
</header>
+5 -2
View File
@@ -1,9 +1,12 @@
<?php
/**
* 一款单栏主题. 移植自HUGO主题 Farallon 原作者 bigfa
* 一款单栏主题.
* 移植自HUGO主题 <a href="https://github.com/bigfa/Farallon">Farallon</a>
* 原作者 bigfa
* * 适配Typecho 1.3.0
* @package Farallon
* @author 老孙
* @version 0.7.2
* @version 0.8
* @link https://www.imsun.org
*/
if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
+1 -1
View File
@@ -7,7 +7,7 @@
<img src="<?php $this->options->logoUrl() ?>" class="avatar" width="48" height="48" />
<a datetime='<?php $this->date('Y-m-d'); ?>' class="humane--time" href="<?php $this->permalink() ?>"
itemprop="datePublished">
<?php $this->date('Y-m-d'); ?>
<?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?>
</a>
</header>
<div class="description" itemprop="about">
+1 -1
View File
@@ -7,7 +7,7 @@
'...',
array(
'wrapTag' => 'nav',
'wrapClass' => 'nav-links nav-links__comment',
'wrapClass' => 'nav-links',
'itemTag' => '',
'textTag' => 'span',
'itemClass' => 'page-numbers',
+3 -3
View File
@@ -22,7 +22,7 @@
<img src="<?php $this->options->logoUrl() ?>" class="avatar" width="48" height="48" />
<a datetime='<?php $this->date('Y-m-d'); ?>' class="humane--time" href="<?php $this->permalink() ?>"
itemprop="datePublished">
<?php $this->date('Y-m-d H:i'); ?>
<?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?>
</a>
</header>
<div class="description" itemprop="about">
@@ -37,7 +37,7 @@
<div class="content">
<h2 class="post--title">
<a href="<?php $this->permalink() ?>">
<?php $this->title() ?>
<?php $this->title() ?><?php if (isset($this->isSticky) && $this->isSticky): ?><?php echo $this->stickyHtml; ?><?php endif; ?>
<?php if((time() - $this->created) < 60*60*24*3): ?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
class="icon--sticky" stroke="currentColor" stroke-width="2" stroke-linecap="round"
@@ -58,7 +58,7 @@
<div class="meta">
<svg class="icon" viewBox="0 0 1024 1024" width="16" height="16"><path d="M512 97.52381c228.912762 0 414.47619 185.563429 414.47619 414.47619s-185.563429 414.47619-414.47619 414.47619S97.52381 740.912762 97.52381 512 283.087238 97.52381 512 97.52381z m0 73.142857C323.486476 170.666667 170.666667 323.486476 170.666667 512s152.81981 341.333333 341.333333 341.333333 341.333333-152.81981 341.333333-341.333333S700.513524 170.666667 512 170.666667z m36.571429 89.697523v229.86362h160.865523v73.142857H512a36.571429 36.571429 0 0 1-36.571429-36.571429V260.388571h73.142858z"></path></svg>
<time>
<?php $this->date('Y-m-d'); ?>
<?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?>
</time>
<svg class="icon" viewBox="0 0 1024 1024" width="16" height="16"><path d="M408.551619 97.52381a73.142857 73.142857 0 0 1 51.736381 21.430857L539.306667 197.973333A73.142857 73.142857 0 0 0 591.067429 219.428571H804.571429a73.142857 73.142857 0 0 1 73.142857 73.142858v560.761904a73.142857 73.142857 0 0 1-73.142857 73.142857H219.428571a73.142857 73.142857 0 0 1-73.142857-73.142857V170.666667a73.142857 73.142857 0 0 1 73.142857-73.142857h189.123048z m0 73.142857H219.428571v682.666666h585.142858V292.571429h-213.504a146.285714 146.285714 0 0 1-98.499048-38.13181L487.619048 249.734095 408.551619 170.666667zM365.714286 633.904762v73.142857h-73.142857v-73.142857h73.142857z m365.714285 0v73.142857H414.47619v-73.142857h316.952381z m-365.714285-195.047619v73.142857h-73.142857v-73.142857h73.142857z m365.714285 0v73.142857H414.47619v-73.142857h316.952381z"></path></svg>
<?php $this->category(','); ?>
+70 -31
View File
@@ -1,23 +1,25 @@
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php
/** 文章置顶 */
$sticky = $this->options->sticky; // 置顶的文章id,多个用|隔开
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit;
$sticky = $this->options->sticky;
$db = Typecho_Db::get();
$pageSize = $this->options->pageSize;
if ($sticky && !empty(trim($sticky))) {
$sticky_cids = array_filter(explode('|', $sticky)); // 分割文本并过滤空值
$sticky_cids = array_filter(explode('|', $sticky));
if (!empty($sticky_cids)) {
$sticky_html = " <span class='sticky--post'> 置顶 </span> "; // 置顶标题的 html
// 清空原有文章的队列
$sticky_html = " <span class='sticky--post'> 置顶 </span>";
// 保存原始对象状态
$originalRows = $this->row;
$originalStack = $this->stack;
$originalLength = $this->length;
$totalOriginal = $this->getTotal();
// 重置当前对象状态
$this->row = [];
$this->stack = [];
$this->length = 0;
// 获取总数,并排除置顶文章数量
$this->length = 0;
// 关键修改:不再减少总文章数
// 保持原始总数,这样分页逻辑不会受影响
// $this->setTotal(max($totalOriginal - $stickyCount, 0));
if (isset($this->currentPage) && $this->currentPage == 1) {
$totalOriginal = $this->getTotal();
$stickyCount = count($sticky_cids);
$this->setTotal(max($totalOriginal - $stickyCount, 0));
// 构建置顶文章的查询
// 查询置顶文章
$selectSticky = $this->select()->where('type = ?', 'post');
foreach ($sticky_cids as $i => $cid) {
if ($i == 0)
@@ -25,29 +27,65 @@ if ($sticky && !empty(trim($sticky))) {
else
$selectSticky->orWhere('cid = ?', $cid);
}
// 获取置顶文章
$stickyPosts = $db->fetchAll($selectSticky);
// 压入置顶文章到文章队列
// 添加置顶文章到结果集
foreach ($stickyPosts as &$stickyPost) {
$stickyPost['title'] .= $sticky_html;
$stickyPost['isSticky'] = true;
$stickyPost['stickyHtml'] = $sticky_html;
$this->push($stickyPost);
}
// 计算当前页应显示的普通文章数量
$standardPageSize = $pageSize - count($stickyPosts);
// 确保第一页不会显示太多文章
if ($standardPageSize <= 0) {
$standardPageSize = 0; // 如果置顶文章已经填满或超过一页,则不显示普通文章
}
} else {
// 非第一页显示正常数量的文章
$standardPageSize = $pageSize;
}
// 构建正常文章查询,排除置顶文章
$selectNormal = $this->select()
->where('type = ?', 'post')
->where('status = ?', 'publish')
->where('created < ?', time())
->order('created', Typecho_Db::SORT_DESC)
->page(isset($this->currentPage) ? $this->currentPage : 1, $standardPageSize);
foreach ($sticky_cids as $cid) {
$selectNormal->where('table.contents.cid != ?', $cid);
}
// 查询普通文章
if ($this->currentPage == 1) {
// 第一页需要排除置顶文章并限制数量
$selectNormal = $this->select()
->where('type = ?', 'post')
->where('status = ?', 'publish')
->where('created < ?', time());
// 排除所有置顶文章
foreach ($sticky_cids as $cid) {
$selectNormal->where('table.contents.cid != ?', $cid);
}
$selectNormal->order('created', Typecho_Db::SORT_DESC)
->limit($standardPageSize)
->offset(0);
} else {
// 非第一页的查询
// 计算正确的偏移量:(当前页码-1) * 每页数量 - 置顶文章数
// 这样可以确保不会漏掉文章
$offset = ($this->currentPage - 1) * $pageSize - count($sticky_cids);
$offset = max($offset, 0); // 确保偏移量不为负
$selectNormal = $this->select()
->where('type = ?', 'post')
->where('status = ?', 'publish')
->where('created < ?', time());
// 排除所有置顶文章
foreach ($sticky_cids as $cid) {
$selectNormal->where('table.contents.cid != ?', $cid);
}
$selectNormal->order('created', Typecho_Db::SORT_DESC)
->limit($pageSize)
->offset($offset);
}
} else {
// 如果sticky_cids为空,使用默认查询
// 没有有效的置顶文章ID,正常查询
$selectNormal = $this->select()
->where('type = ?', 'post')
->where('status = ?', 'publish')
@@ -56,7 +94,7 @@ if ($sticky && !empty(trim($sticky))) {
->page(isset($this->currentPage) ? $this->currentPage : 1, $pageSize);
}
} else {
// 如果没有置顶文章,使用默认查询
// 没有设置置顶文章,正常查询
$selectNormal = $this->select()
->where('type = ?', 'post')
->where('status = ?', 'publish')
@@ -64,21 +102,22 @@ if ($sticky && !empty(trim($sticky))) {
->order('created', Typecho_Db::SORT_DESC)
->page(isset($this->currentPage) ? $this->currentPage : 1, $pageSize);
}
// 登录用户显示私密文章
// 添加私有文章查询条件
if ($this->user->hasLogin()) {
$uid = $this->user->uid;
if ($uid) {
$selectNormal->orWhere('authorId = ? AND status = ?', $uid, 'private');
}
}
// 获取普通文章
$normalPosts = $db->fetchAll($selectNormal);
// 如果之前没有清空队列(没有置顶文章的情况),现在清空
// 如果没有置顶文章或在前面的代码中没有重置对象状态,则在这里重置
if (empty($sticky) || empty(trim($sticky)) || empty($sticky_cids)) {
$this->row = [];
$this->stack = [];
$this->length = 0;
}
// 压入正常文章到文章队列
// 将普通文章添加到结果集
foreach ($normalPosts as $normalPost) {
$this->push($normalPost);
}
+2 -2
View File
@@ -16,7 +16,7 @@
$imageToDisplay = process_cover_image($imageToDisplay);
}
?>
<article class="post--card" id="loadpost" itemscope itemtype="http://schema.org/Article">
<article class="post--card" id="loadpost">
<img src="<?php echo $imageToDisplay; ?>" alt="<?php $this->title() ?>" class="cover" itemprop="image"/>
<div class="content">
<h2 class="post--title">
@@ -32,7 +32,7 @@
<path d="M512 97.52381c228.912762 0 414.47619 185.563429 414.47619 414.47619s-185.563429 414.47619-414.47619 414.47619S97.52381 740.912762 97.52381 512 283.087238 97.52381 512 97.52381z m0 73.142857C323.486476 170.666667 170.666667 323.486476 170.666667 512s152.81981 341.333333 341.333333 341.333333 341.333333-152.81981 341.333333-341.333333S700.513524 170.666667 512 170.666667z m36.571429 89.697523v229.86362h160.865523v73.142857H512a36.571429 36.571429 0 0 1-36.571429-36.571429V260.388571h73.142858z"></path>
</svg>
<time datetime='<?php $this->date('Y-m-d'); ?>' class="humane--time">
<?php $this->date('Y-m-d'); ?>
<?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?>
</time>
</div>
</div>
+5 -3
View File
@@ -9,7 +9,7 @@
<path
d="M512 97.52381c228.912762 0 414.47619 185.563429 414.47619 414.47619s-185.563429 414.47619-414.47619 414.47619S97.52381 740.912762 97.52381 512 283.087238 97.52381 512 97.52381z m0 73.142857C323.486476 170.666667 170.666667 323.486476 170.666667 512s152.81981 341.333333 341.333333 341.333333 341.333333-152.81981 341.333333-341.333333S700.513524 170.666667 512 170.666667z m36.571429 89.697523v229.86362h160.865523v73.142857H512a36.571429 36.571429 0 0 1-36.571429-36.571429V260.388571h73.142858z">
</path>
</svg><time class="humane--time"><?php $this->date('Y-m-d'); ?></time>
</svg><time class="humane--time"><?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?></time>
<svg class="icon" viewBox="0 0 1024 1024" width="16" height="16">
<path
d="M408.551619 97.52381a73.142857 73.142857 0 0 1 51.736381 21.430857L539.306667 197.973333A73.142857 73.142857 0 0 0 591.067429 219.428571H804.571429a73.142857 73.142857 0 0 1 73.142857 73.142858v560.761904a73.142857 73.142857 0 0 1-73.142857 73.142857H219.428571a73.142857 73.142857 0 0 1-73.142857-73.142857V170.666667a73.142857 73.142857 0 0 1 73.142857-73.142857h189.123048z m0 73.142857H219.428571v682.666666h585.142858V292.571429h-213.504a146.285714 146.285714 0 0 1-98.499048-38.13181L487.619048 249.734095 408.551619 170.666667zM365.714286 633.904762v73.142857h-73.142857v-73.142857h73.142857z m365.714285 0v73.142857H414.47619v-73.142857h316.952381z m-365.714285-195.047619v73.142857h-73.142857v-73.142857h73.142857z m365.714285 0v73.142857H414.47619v-73.142857h316.952381z">
@@ -37,7 +37,7 @@
<?php endif; ?>
</div>
<h2 class="post--single__title"><?php $this->title() ?></h2>
<div class="post--single__content graph" ><?php $this->content(); ?></div>
<div class="post--single__content graph" ><?php //$this->content(); ?><?php echo ContentFilter::filterContent($this->content, $this, null); ?></div>
<?php if($this->options->wxpay): ?>
<!--打赏 -->
<div class="post--single__action">
@@ -61,7 +61,9 @@
<?php if($this->options->showshare): ?>
<div class="post--share">
<svg viewBox="0 0 24 24" aria-hidden="true"><g><path d="M18.36 5.64c-1.95-1.96-5.11-1.96-7.07 0L9.88 7.05 8.46 5.64l1.42-1.42c2.73-2.73 7.16-2.73 9.9 0 2.73 2.74 2.73 7.17 0 9.9l-1.42 1.42-1.41-1.42 1.41-1.41c1.96-1.96 1.96-5.12 0-7.07zm-2.12 3.53l-7.07 7.07-1.41-1.41 7.07-7.07 1.41 1.41zm-12.02.71l1.42-1.42 1.41 1.42-1.41 1.41c-1.96 1.96-1.96 5.12 0 7.07 1.95 1.96 5.11 1.96 7.07 0l1.41-1.41 1.42 1.41-1.42 1.42c-2.73 2.73-7.16 2.73-9.9 0-2.73-2.74-2.73-7.17 0-9.9z"></path></g></svg>
<span class="text" data-copy="<?php $this->permalink(); ?>">复制链接</span><span class="link text"><?php $this->permalink(); ?></span><div class="notice--wrapper" id="copyTooltip" style="display: none;">复制成功!</div>
<span class="cpoy" data-copy="<?php $this->permalink(); ?>">复制链接</span>
<span class="link copy"><?php $this->permalink(); ?></span>
<div class="notice--wrapper" id="copyTooltip" style="display: none;">复制成功!</div>
</div>
<?php endif; ?>
<!-- TAG -->