parent
7bdc119371
commit
d21bd5ffc5
@ -0,0 +1 @@
|
||||
# 文章推荐插件
|
||||
@ -0,0 +1,166 @@
|
||||
/* 文章推荐插件样式 - 与网站风格保持一致 */
|
||||
|
||||
/* 文章底部推荐样式 */
|
||||
.article-recommendations {
|
||||
margin: 30px 0;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border: 1px solid #e1e1e1;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.recommendations-title {
|
||||
margin: 0 0 15px 0;
|
||||
font-size: 18px;
|
||||
color: #444;
|
||||
font-weight: bold;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #21759b;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.recommendations-icon {
|
||||
margin-right: 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.recommendations-grid {
|
||||
display: grid;
|
||||
gap: 15px;
|
||||
grid-template-columns: 1fr;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.recommendation-card {
|
||||
background: #fff;
|
||||
border: 1px solid #e1e1e1;
|
||||
border-radius: 3px;
|
||||
transition: all 0.2s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.recommendation-card:hover {
|
||||
border-color: #21759b;
|
||||
box-shadow: 0 2px 5px rgba(33, 117, 155, 0.1);
|
||||
}
|
||||
|
||||
.recommendation-link {
|
||||
display: block;
|
||||
padding: 15px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.recommendation-title {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
color: #444;
|
||||
line-height: 1.4;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.recommendation-card:hover .recommendation-title {
|
||||
color: #21759b;
|
||||
}
|
||||
|
||||
.recommendation-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
.recommendation-category {
|
||||
background: #ebebeb;
|
||||
color: #5e5e5e;
|
||||
padding: 2px 6px;
|
||||
border-radius: 2px;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.recommendation-date {
|
||||
font-weight: normal;
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
/* 侧边栏推荐样式 */
|
||||
.widget_recommendations {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.widget_recommendations .widget-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #007cba;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.recommendations-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.recommendations-list .recommendation-item {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.recommendations-list .recommendation-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.recommendations-list .recommendation-item a {
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.recommendations-list .recommendation-item a:hover {
|
||||
color: #007cba;
|
||||
}
|
||||
|
||||
.recommendations-list .recommendation-meta {
|
||||
font-size: 11px;
|
||||
color: #999;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.recommendations-list .recommendation-meta span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* 响应式设计 - 分栏显示 */
|
||||
@media (min-width: 768px) {
|
||||
.recommendations-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.recommendations-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.recommendations-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 15px;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 文章推荐插件JavaScript
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// 等待DOM加载完成
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initRecommendations();
|
||||
});
|
||||
|
||||
function initRecommendations() {
|
||||
// 添加点击统计
|
||||
trackRecommendationClicks();
|
||||
|
||||
// 懒加载优化(如果需要)
|
||||
lazyLoadRecommendations();
|
||||
}
|
||||
|
||||
function trackRecommendationClicks() {
|
||||
const recommendationLinks = document.querySelectorAll('.recommendation-item a');
|
||||
|
||||
recommendationLinks.forEach(function(link) {
|
||||
link.addEventListener('click', function(e) {
|
||||
// 可以在这里添加点击统计逻辑
|
||||
const articleTitle = this.textContent.trim();
|
||||
const articleUrl = this.href;
|
||||
|
||||
// 发送统计数据到后端(可选)
|
||||
if (typeof gtag !== 'undefined') {
|
||||
gtag('event', 'click', {
|
||||
'event_category': 'recommendation',
|
||||
'event_label': articleTitle,
|
||||
'value': 1
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Recommendation clicked:', articleTitle, articleUrl);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function lazyLoadRecommendations() {
|
||||
// 如果推荐内容很多,可以实现懒加载
|
||||
const recommendationContainer = document.querySelector('.article-recommendations');
|
||||
|
||||
if (!recommendationContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否在视窗中
|
||||
const observer = new IntersectionObserver(function(entries) {
|
||||
entries.forEach(function(entry) {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('loaded');
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, {
|
||||
threshold: 0.1
|
||||
});
|
||||
|
||||
const recommendationItems = document.querySelectorAll('.recommendation-item');
|
||||
recommendationItems.forEach(function(item) {
|
||||
observer.observe(item);
|
||||
});
|
||||
}
|
||||
|
||||
// 添加一些动画效果
|
||||
function addAnimations() {
|
||||
const recommendationItems = document.querySelectorAll('.recommendation-item');
|
||||
|
||||
recommendationItems.forEach(function(item, index) {
|
||||
item.style.opacity = '0';
|
||||
item.style.transform = 'translateY(20px)';
|
||||
item.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
|
||||
|
||||
setTimeout(function() {
|
||||
item.style.opacity = '1';
|
||||
item.style.transform = 'translateY(0)';
|
||||
}, index * 100);
|
||||
});
|
||||
}
|
||||
|
||||
// 如果需要,可以在这里添加更多功能
|
||||
window.ArticleRecommendation = {
|
||||
init: initRecommendations,
|
||||
track: trackRecommendationClicks,
|
||||
animate: addAnimations
|
||||
};
|
||||
|
||||
})();
|
||||
@ -0,0 +1 @@
|
||||
# 插件模板目录
|
||||
@ -0,0 +1,23 @@
|
||||
{% load i18n %}
|
||||
<div class="article-recommendations">
|
||||
<h3 class="recommendations-title">
|
||||
<span class="recommendations-icon">📖</span>{{ title }}
|
||||
</h3>
|
||||
<div class="recommendations-grid">
|
||||
{% for article in recommendations %}
|
||||
{% if article.title and article.title|length > 0 %}
|
||||
<div class="recommendation-card">
|
||||
<a href="{{ article.get_absolute_url }}" class="recommendation-link" title="{{ article.title }}">
|
||||
<div class="recommendation-title">{{ article.title|truncatechars:45 }}</div>
|
||||
<div class="recommendation-meta">
|
||||
{% if article.category %}
|
||||
<span class="recommendation-category">{{ article.category.name }}</span>
|
||||
{% endif %}
|
||||
<span class="recommendation-date">{{ article.pub_time|date:"m-d" }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,17 @@
|
||||
{% load i18n %}
|
||||
<aside class="widget widget_recommendations">
|
||||
<p class="widget-title">{{ title }}</p>
|
||||
<ul class="recommendations-list">
|
||||
{% for article in recommendations %}
|
||||
<li class="recommendation-item">
|
||||
<a href="{{ article.get_absolute_url }}" title="{{ article.title }}">
|
||||
{{ article.title|truncatechars:35 }}
|
||||
</a>
|
||||
<div class="recommendation-meta">
|
||||
<span class="recommendation-views">{{ article.views }} {% trans 'views' %}</span>
|
||||
<span class="recommendation-date">{{ article.pub_time|date:"m-d" }}</span>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</aside>
|
||||
@ -0,0 +1,4 @@
|
||||
{% comment %}插件CSS文件包含模板 - 用于压缩{% endcomment %}
|
||||
{% for css_file in css_files %}
|
||||
<link rel="stylesheet" href="{{ css_file }}" type="text/css">
|
||||
{% endfor %}
|
||||
@ -0,0 +1,4 @@
|
||||
{% comment %}插件JS文件包含模板 - 用于压缩{% endcomment %}
|
||||
{% for js_file in js_files %}
|
||||
<script src="{{ js_file }}"></script>
|
||||
{% endfor %}
|
||||
Loading…
Reference in new issue