Files
SimpleBreadcrumb/Plugin.php
2026-02-23 19:57:05 +08:00

429 lines
13 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 面包屑导航(没有适配版)
*
* @package SimpleBreadcrumb
* @author 石头厝
* @version 3.0.0
* @link https://www.shitoucuo.com/
*/
class SimpleBreadcrumb_Plugin implements Typecho_Plugin_Interface
{
/**
* 激活插件
*/
public static function activate()
{
Typecho_Plugin::factory('Widget_Archive')->footer = array('SimpleBreadcrumb_Plugin', 'footer');
return _t('面包屑导航插件已激活,请在文章页面使用 SimpleBreadcrumb_Plugin::show() 调用');
}
/**
* 禁用插件
*/
public static function deactivate()
{
return _t('面包屑导航插件已禁用');
}
/**
* 插件配置面板(简化版)
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
// 是否显示面包屑
$showBreadcrumb = new Typecho_Widget_Helper_Form_Element_Radio(
'showBreadcrumb',
array(
'1' => _t('显示'),
'0' => _t('不显示')
),
'1',
_t('是否显示面包屑导航')
);
$form->addInput($showBreadcrumb);
// 首页文字
$homeText = new Typecho_Widget_Helper_Form_Element_Text(
'homeText',
NULL,
'首页',
_t('首页显示文字')
);
$form->addInput($homeText);
// 分隔符
$separator = new Typecho_Widget_Helper_Form_Element_Select(
'separator',
array(
'»' => '»',
'>' => '>',
'/' => '/',
'→' => '→'
),
'»',
_t('分隔符样式')
);
$form->addInput($separator);
// 是否显示当前页面
$showCurrent = new Typecho_Widget_Helper_Form_Element_Radio(
'showCurrent',
array(
'1' => _t('显示'),
'0' => _t('不显示')
),
'1',
_t('是否显示当前页面')
);
$form->addInput($showCurrent);
// 是否显示分类
$showCategory = new Typecho_Widget_Helper_Form_Element_Radio(
'showCategory',
array(
'1' => _t('显示'),
'0' => _t('不显示')
),
'1',
_t('文章页面是否显示分类')
);
$form->addInput($showCategory);
}
/**
* 个人配置面板
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form) {}
/**
* 输出面包屑导航(前端调用方法)
*/
public static function show($widget = null)
{
$options = Helper::options();
$config = $options->plugin('SimpleBreadcrumb');
// 检查是否显示
if (!$config->showBreadcrumb) {
return;
}
// 如果没有传递widget使用全局
if ($widget === null) {
$widget = Typecho_Widget::widget('Widget_Archive');
}
// 检查是否在首页且需要显示
if ($widget->is('index')) {
return;
}
// 获取面包屑HTML
$breadcrumb = self::generateBreadcrumb($widget, $config);
if (!empty($breadcrumb)) {
// 输出CSS和面包屑HTML
$html = '<style>' . self::getStyles() . '</style>';
$html .= '<div class="simple-breadcrumb">' . $breadcrumb . '</div>';
echo $html;
}
}
/**
* 生成面包屑HTML
*/
private static function generateBreadcrumb($widget, $config)
{
$breadcrumbs = array();
$options = Helper::options();
// 添加首页
$homeText = isset($config->homeText) ? $config->homeText : '首页';
$breadcrumbs[] = '<a href="' . $options->siteUrl . '" class="breadcrumb-home">' .
htmlspecialchars($homeText) . '</a>';
$separator = isset($config->separator) ? $config->separator : '»';
$showCurrent = isset($config->showCurrent) ? $config->showCurrent : '1';
$showCategory = isset($config->showCategory) ? $config->showCategory : '1';
// 分类页面
if ($widget->is('category')) {
$category = $widget->getArchiveTitle();
if ($showCurrent) {
$breadcrumbs[] = '<span class="breadcrumb-current">' . htmlspecialchars($category) . '</span>';
}
}
// 文章页面
elseif ($widget->is('post')) {
// 添加分类
if ($showCategory) {
$categories = $widget->categories;
if ($categories && count($categories) > 0) {
$category = current($categories);
$breadcrumbs[] = '<a href="' . $category['permalink'] . '" class="breadcrumb-category">' .
htmlspecialchars($category['name']) . '</a>';
}
}
// 添加当前文章
if ($showCurrent) {
$breadcrumbs[] = '<span class="breadcrumb-current">' . htmlspecialchars($widget->title) . '</span>';
}
}
// 独立页面
elseif ($widget->is('page')) {
// 处理父页面(如果有)
if ($widget->parent > 0) {
$parent = $widget->widget('Widget_Archive', "type=page&pageId={$widget->parent}");
if ($parent->have()) {
$breadcrumbs[] = '<a href="' . $parent->permalink . '" class="breadcrumb-parent">' .
htmlspecialchars($parent->title) . '</a>';
}
}
if ($showCurrent) {
$breadcrumbs[] = '<span class="breadcrumb-current">' . htmlspecialchars($widget->title) . '</span>';
}
}
// 标签页面
elseif ($widget->is('tag')) {
if ($showCurrent) {
$tag = $widget->getArchiveTitle();
$breadcrumbs[] = '<span class="breadcrumb-current">标签: ' . htmlspecialchars($tag) . '</span>';
}
}
// 作者页面
elseif ($widget->is('author')) {
if ($showCurrent) {
$author = $widget->getArchiveTitle();
$breadcrumbs[] = '<span class="breadcrumb-current">作者: ' . htmlspecialchars($author) . '</span>';
}
}
// 日期归档
elseif ($widget->is('archive') && !$widget->is('category') && !$widget->is('tag') && !$widget->is('author')) {
if ($showCurrent) {
$archive = $widget->getArchiveTitle();
$breadcrumbs[] = '<span class="breadcrumb-current">' . htmlspecialchars($archive) . '</span>';
}
}
// 搜索页面
elseif ($widget->is('search')) {
if ($showCurrent) {
$keywords = $widget->keywords;
$breadcrumbs[] = '<span class="breadcrumb-current">搜索: ' . htmlspecialchars($keywords) . '</span>';
}
}
// 如果没有面包屑内容(只有首页),根据设置决定是否显示
if (count($breadcrumbs) <= 1) {
return ''; // 只显示首页时不输出
}
// 组合HTML
$html = '<nav class="breadcrumb-nav" aria-label="面包屑导航">';
$html .= '<ol class="breadcrumb-list">';
$count = count($breadcrumbs);
foreach ($breadcrumbs as $index => $crumb) {
$html .= '<li class="breadcrumb-item">';
$html .= $crumb;
if ($index < $count - 1) {
$html .= '<span class="breadcrumb-separator">' . htmlspecialchars($separator) . '</span>';
}
$html .= '</li>';
}
$html .= '</ol>';
$html .= '</nav>';
return $html;
}
/**
* 输出CSS样式到footer保持空避免重复加载
*/
public static function footer()
{
// CSS已经在show()方法中内联输出
}
/**
* 获取CSS样式 - 简化版,专门适配.dark夜间模式
*/
private static function getStyles()
{
return '
/* Simple Breadcrumb Navigation CSS - v3.0.0 */
/* 基础样式 */
.simple-breadcrumb {
margin: 20px 0;
padding: 15px 0;
font-size: 14px;
line-height: 1.5;
clear: both;
text-align: center;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
/* 导航结构 */
.breadcrumb-nav {
display: inline-block;
max-width: 100%;
}
.breadcrumb-list {
list-style: none;
padding: 0;
margin: 0;
display: inline-flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
.breadcrumb-item {
display: inline-flex;
align-items: center;
margin: 5px 0;
}
.breadcrumb-item a {
text-decoration: none;
padding: 4px 8px;
border-radius: 4px;
transition: all 0.2s ease;
font-weight: 500;
color: #1e87f0;
background-color: rgba(30, 135, 240, 0.1);
}
.breadcrumb-item a:hover {
color: #0d6efd;
background-color: rgba(30, 135, 240, 0.2);
transform: translateY(-1px);
}
.breadcrumb-item span.breadcrumb-current {
font-weight: 600;
padding: 4px 8px;
border-radius: 4px;
color: #333;
background-color: rgba(0, 0, 0, 0.05);
}
.breadcrumb-separator {
margin: 0 10px;
opacity: 0.6;
font-weight: 300;
color: #666;
}
/* ========== .dark 夜间模式适配 ========== */
.dark .simple-breadcrumb {
background-color: #1a1d21;
border-radius: 8px;
padding: 15px 20px;
border: 1px solid #343a40;
}
.dark .breadcrumb-item a {
color: #4dabf7;
background-color: rgba(77, 171, 247, 0.1);
}
.dark .breadcrumb-item a:hover {
color: #339af0;
background-color: rgba(77, 171, 247, 0.2);
}
.dark .breadcrumb-item span.breadcrumb-current {
color: #e9ecef;
background-color: rgba(255, 255, 255, 0.05);
}
.dark .breadcrumb-separator {
color: #adb5bd;
}
/* ========== 响应式设计 ========== */
@media (max-width: 768px) {
.simple-breadcrumb {
margin: 15px 0;
padding: 12px 15px;
font-size: 13px;
text-align: left;
}
.breadcrumb-list {
justify-content: flex-start;
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
padding-bottom: 5px;
}
.breadcrumb-item {
flex-shrink: 0;
}
.breadcrumb-separator {
margin: 0 8px;
}
.dark .simple-breadcrumb {
padding: 12px 15px;
}
}
@media (max-width: 480px) {
.simple-breadcrumb {
margin: 10px 0;
padding: 10px 12px;
font-size: 12px;
}
.breadcrumb-item a,
.breadcrumb-item span.breadcrumb-current {
padding: 3px 6px;
}
.breadcrumb-separator {
margin: 0 6px;
}
.dark .simple-breadcrumb {
padding: 10px 12px;
border-radius: 6px;
}
}
/* ========== 打印样式 ========== */
@media print {
.simple-breadcrumb {
display: none;
}
}
/* ========== 无障碍支持 ========== */
.breadcrumb-item a:focus {
outline: 2px solid #1e87f0;
outline-offset: 2px;
}
.dark .breadcrumb-item a:focus {
outline-color: #4dabf7;
}
';
}
}
?>