Files
ns2.0/templates/new_apps.html

784 lines
18 KiB
HTML
Executable File
Raw Permalink 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.

{% extends "base.html" %}
{% block content %}
<!--<div id="wishlist-announcement" class="wishlist-announcement">-->
<!-- <div class="announcement-content">-->
<!-- <span class="announcement-text">🎉 心愿单功能全新上线</span>-->
<!-- <button onclick="window.location.href='{{ url_for('more') }}'" class="goto-btn">立即体验</button>-->
<!-- <button onclick="closeAnnouncement()" class="close-btn">×</button>-->
<!-- </div>-->
<!-- <div class="countdown-bar"></div>-->
<!--</div>-->
<!-- 添加水印容器 -->
<div class="watermark-container">
<div class="watermark-content"></div>
</div>
<div class="new-apps-page">
<div class="header">
<a href="{{ url_for('explore') }}" class="back-link" title="返回首页" onclick="handleBackClick(event)">
<i class="fas fa-arrow-left"></i>
</a>
<h1>{{ date_text }}</h1>
</div>
<div class="date-switcher">
<a href="{{ url_for('new_apps', date='today') }}" class="date-btn {{ 'active' if date == 'today' }}">今日</a>
<a href="{{ url_for('new_apps', date='yesterday') }}" class="date-btn {{ 'active' if date == 'yesterday' }}">昨日</a>
<a href="{{ url_for('new_apps', date='before_yesterday') }}" class="date-btn {{ 'active' if date == 'before_yesterday' }}">前日</a>
</div>
{% if today_apps %}
<div class="apps-grid">
{% for app in today_apps %}
<div class="app-tile" onclick="handleAppClick(event, '{{ app.id }}')">
<div class="app-tile-content">
<div class="app-tile-icon">
{% if 'http' in app.icon_path %}
<img src="{{ app.icon_path }}" alt="{{ app.name }}">
{% else %}
<img src="{{ url_for('static', filename='uploads/' + app.icon_path) }}" alt="{{ app.name }}">
{% endif %}
</div>
<div class="app-tile-info">
<div class="app-tile-header">
<h3>{{ app.name }}</h3>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="empty-state">
<i class="fas fa-inbox"></i>
<p>今日无上新应用</p>
</div>
{% endif %}
</div>
<style>
.goto-btn {
background: rgba(255, 255, 255, 0.2);
color: white;
border: 1px solid rgba(255, 255, 255, 0.3);
padding: 6px 14px;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: 500;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
}
.goto-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-1px);
border-color: rgba(255, 255, 255, 0.5);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.close-btn {
background: none;
border: none;
color: white;
font-size: 20px;
cursor: pointer;
padding: 0 6px;
opacity: 0.8;
transition: opacity 0.3s ease;
}
.close-btn:hover {
opacity: 1;
}
.countdown-bar {
height: 3px;
background: rgba(255, 255, 255, 0.2);
border-radius: 0;
overflow: hidden;
position: relative;
margin: 0 -12px;
width: calc(100% + 24px);
}
.countdown-bar::after {
content: '';
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background: linear-gradient(90deg, rgba(255,255,255,0.8), rgba(255,255,255,1));
animation: countdown 5s linear forwards;
}
@keyframes slideDown {
from {
transform: translate(-50%, -100%);
opacity: 0;
}
to {
transform: translate(-50%, 0);
opacity: 1;
}
}
@keyframes countdown {
from {
width: 100%;
}
to {
width: 0;
}
}
/* 暗色模式适配 */
[data-theme="dark"] .wishlist-announcement {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
/* 心愿单通知弹窗样式 */
.wishlist-announcement {
position: fixed;
top: 60px;
left: 50%;
transform: translateX(-50%);
width: 90%;
max-width: 400px;
background: linear-gradient(135deg, #4F46E5, #7C3AED);
border-radius: 12px;
padding: 12px 12px 0 12px;
box-shadow: 0 8px 20px rgba(124, 58, 237, 0.25);
z-index: 1000;
overflow: hidden;
animation: slideDown 0.5s ease-out;
touch-action: pan-x; /* 允许水平滑动 */
user-select: none; /* 防止文本选择 */
transition: transform 0.3s ease; /* 添加平滑过渡 */
}
/* 添加滑动时的动画效果 */
.wishlist-announcement.swiping {
transition: transform 0.1s ease;
}
/* 添加滑动完成后的动画效果 */
.wishlist-announcement.swipe-out {
transform: translate(calc(-50% - 150%), 0);
opacity: 0;
}
.announcement-content {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.announcement-text {
color: white;
font-size: 16px;
font-weight: 600;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
/* 添加水印相关样式 */
.watermark-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
z-index: 1000;
overflow: hidden;
}
.watermark-content {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
height: 100vh;
background-repeat: repeat;
opacity: 0.2;
transform: rotate(-15deg);
pointer-events: none;
will-change: transform;
backface-visibility: hidden;
-webkit-font-smoothing: antialiased;
}
/* 保持原有样式不变 */
.new-apps-page {
max-width: 1200px;
margin: 60px auto 20px;
padding: 0 15px;
position: relative;
z-index: 1;
}
.header {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 15px;
background: white;
padding: 5px 20px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
transform: none !important;
transition: none !important;
animation: none !important;
}
.header * {
transform: none !important;
transition: none !important;
animation: none !important;
}
.back-link {
color: #666;
text-decoration: none;
padding: 8px;
border-radius: 50%;
background: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
}
.header h1 {
margin: 0;
font-size: 20px;
color: #333;
font-weight: 500;
font-family: "SimHei", "黑体", sans-serif;
text-align: left;
}
/* 添加空状态样式 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-top: 20px;
}
.empty-state i {
font-size: 48px;
color: #ccc;
margin-bottom: 16px;
}
.empty-state p {
font-size: 16px;
color: #666;
margin: 0;
font-family: "SimHei", "黑体", sans-serif;
}
/* 添加网格布局样式 */
.apps-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
gap: 12px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin: 0;
padding: 0;
}
/* 修改应用图标容器样式 */
.app-tile {
cursor: pointer;
transition: transform 0.2s;
text-align: center;
padding: 8px;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
}
.app-tile:hover {
transform: translateY(-2px);
background: #f5f5f5;
}
/* 修改图标容器样式 */
.app-tile-icon {
width: 60px;
height: 60px;
margin: 0 auto 6px;
}
.app-tile-icon img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 14px;
}
/* 修改应用名称样式 */
.app-tile-header h3 {
margin: 0;
font-size: 12px;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-height: 1.3;
max-height: 2.6em;
width: 100%;
text-align: center;
}
/* 修改响应式布局 */
@media (max-width: 768px) {
.apps-grid {
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
gap: 10px;
}
.app-tile-icon {
width: 52px;
height: 52px;
}
.app-tile-header h3 {
font-size: 11px;
}
}
@media (max-width: 480px) {
.apps-grid {
grid-template-columns: repeat(4, 1fr); /* 强制一行4个 */
gap: 8px;
}
.app-tile {
padding: 6px;
}
.app-tile-icon {
width: 48px;
height: 48px;
}
.app-tile-header h3 {
font-size: 11px;
}
}
/* 暗色模式样式 */
[data-theme="dark"] .new-apps-page {
background: #1a1a1a;
}
[data-theme="dark"] .header {
background: #242424;
}
[data-theme="dark"] .header h1 {
color: #fff;
}
[data-theme="dark"] .back-link {
color: #ccc;
background: #333;
}
[data-theme="dark"] .back-link:hover {
background: #444;
color: #fff;
}
[data-theme="dark"] .apps-grid {
background: #242424;
}
[data-theme="dark"] .app-tile {
background: #242424;
}
[data-theme="dark"] .app-tile:hover {
background: #333;
}
[data-theme="dark"] .app-tile-header h3 {
color: #fff;
}
[data-theme="dark"] .empty-state {
background: #242424;
}
[data-theme="dark"] .empty-state i {
color: #666;
}
[data-theme="dark"] .empty-state p {
color: #ccc;
}
/* 修改水印在暗色模式下的样式 */
[data-theme="dark"] .watermark-content {
opacity: 0.1;
}
/* 修改水印文字在暗色模式下的颜色 */
[data-theme="dark"] .watermark-content canvas {
filter: invert(1); /* 反转颜色 */
}
/* 日期切换器样式 */
.date-switcher {
display: flex;
gap: 8px;
margin-bottom: 8px;
background: white;
padding: 10px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
justify-content: center;
}
.date-btn {
padding: 6px 16px;
border-radius: 6px;
background: #f0f0f0;
color: #666;
text-decoration: none;
font-size: 14px;
transition: all 0.2s;
}
.date-btn:hover {
background: #e0e0e0;
}
.date-btn.active {
background: #007aff;
color: white;
}
/* 暗色模式样式 */
[data-theme="dark"] .date-switcher {
background: #242424;
}
[data-theme="dark"] .date-btn {
background: #333;
color: #ccc;
}
[data-theme="dark"] .date-btn:hover {
background: #444;
}
[data-theme="dark"] .date-btn.active {
background: #0056b3;
color: white;
}
/* 响应式布局调整 */
@media (max-width: 480px) {
.header {
padding: 10px;
}
.date-switcher {
padding: 8px;
}
.date-btn {
padding: 4px 12px;
font-size: 12px;
}
}
/* 修复暗色模式切换按钮在 PC 端的显示问题 */
.floating-buttons {
position: fixed;
bottom: 40px;
right: 20px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 10px;
}
.theme-toggle {
width: 40px;
height: 40px;
border-radius: 50%;
border: none;
background: #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
padding: 0;
}
.theme-toggle:hover {
transform: scale(1.1);
}
/* 暗色模式样式 */
[data-theme="dark"] .theme-toggle {
background: #333;
color: #fff;
}
/* 响应式调整 */
@media (max-width: 768px) {
.floating-buttons {
bottom: 30px;
right: 15px;
gap: 8px;
}
.theme-toggle {
width: 36px;
height: 36px;
}
}
/* 添加关闭动画 */
@keyframes slideUp {
from {
transform: translate(-50%, 0);
opacity: 1;
}
to {
transform: translate(-50%, -100%);
opacity: 0;
}
}
</style>
<script>
function handleAppClick(event, appId) {
window.location.href = '/app/' + appId;
}
function handleBackClick(event) {
event.preventDefault();
// 检查是否是从explore页面来的
if (sessionStorage.getItem('fromExplore')) {
window.location.href = '/explore';
} else {
window.location.href = '/';
}
}
// 心愿单通知弹窗相关函数
function closeAnnouncement() {
const announcement = document.getElementById('wishlist-announcement');
if (!announcement) return;
announcement.style.animation = 'slideUp 0.5s ease-out forwards';
setTimeout(() => {
announcement.remove();
}, 500);
}
// 添加自动关闭功能
document.addEventListener('DOMContentLoaded', () => {
setTimeout(closeAnnouncement, 5000);
});
let touchStartX = 0;
let touchEndX = 0;
let currentTranslateX = 0;
let isDragging = false;
document.addEventListener('DOMContentLoaded', () => {
const announcement = document.getElementById('wishlist-announcement');
if (!announcement) return;
// 触摸开始
announcement.addEventListener('touchstart', (e) => {
touchStartX = e.touches[0].clientX;
isDragging = true;
announcement.classList.add('swiping');
});
// 触摸移动
announcement.addEventListener('touchmove', (e) => {
if (!isDragging) return;
touchEndX = e.touches[0].clientX;
const diffX = touchEndX - touchStartX;
// 只允许左滑
if (diffX > 0) {
currentTranslateX = 0;
} else {
currentTranslateX = diffX;
}
// 应用变换
announcement.style.transform = `translate(calc(-50% + ${currentTranslateX}px), 0)`;
});
// 触摸结束
announcement.addEventListener('touchend', () => {
isDragging = false;
announcement.classList.remove('swiping');
// 如果滑动距离超过阈值,则关闭通知
if (currentTranslateX < -100) {
announcement.classList.add('swipe-out');
setTimeout(() => {
announcement.remove();
}, 300);
} else {
// 否则回弹
announcement.style.transform = 'translateX(-50%)';
}
// 重置状态
currentTranslateX = 0;
touchStartX = 0;
touchEndX = 0;
});
// 鼠标事件支持
announcement.addEventListener('mousedown', (e) => {
touchStartX = e.clientX;
isDragging = true;
announcement.classList.add('swiping');
});
announcement.addEventListener('mousemove', (e) => {
if (!isDragging) return;
touchEndX = e.clientX;
const diffX = touchEndX - touchStartX;
if (diffX > 0) {
currentTranslateX = 0;
} else {
currentTranslateX = diffX;
}
announcement.style.transform = `translate(calc(-50% + ${currentTranslateX}px), 0)`;
});
announcement.addEventListener('mouseup', () => {
if (!isDragging) return;
isDragging = false;
announcement.classList.remove('swiping');
if (currentTranslateX < -100) {
announcement.classList.add('swipe-out');
setTimeout(() => {
announcement.remove();
}, 300);
} else {
announcement.style.transform = 'translateX(-50%)';
}
currentTranslateX = 0;
touchStartX = 0;
touchEndX = 0;
});
// 处理鼠标离开窗口的情况
announcement.addEventListener('mouseleave', () => {
if (isDragging) {
isDragging = false;
announcement.classList.remove('swiping');
announcement.style.transform = 'translateX(-50%)';
currentTranslateX = 0;
touchStartX = 0;
touchEndX = 0;
}
});
});
// 监听浏览器返回按钮
window.addEventListener('popstate', function(event) {
if (sessionStorage.getItem('fromExplore')) {
window.location.href = '/explore';
}
});
// 修改水印相关脚本
document.addEventListener('DOMContentLoaded', function() {
const watermarkContent = document.querySelector('.watermark-content');
const settings = {{ settings|tojson|safe }};
function createWatermark() {
const text1 = settings.watermark_text_1 || '';
const text2 = settings.watermark_text_2 || '';
if (!text1 && !text2) return;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 160;
ctx.font = '16px Arial';
// 根据主题设置颜色
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
ctx.fillStyle = isDark ? '#ffffff' : '#333333';
ctx.textAlign = 'center';
ctx.lineWidth = 0.6;
if (text1) {
ctx.fillText(text1, canvas.width/2, canvas.height/2 - 8);
ctx.strokeText(text1, canvas.width/2, canvas.height/2 - 8);
}
if (text2) {
ctx.fillText(text2, canvas.width/2, canvas.height/2 + 8);
ctx.strokeText(text2, canvas.width/2, canvas.height/2 + 8);
}
const pattern = ctx.createPattern(canvas, 'repeat');
watermarkContent.style.backgroundImage = `url(${canvas.toDataURL()})`;
}
createWatermark();
// 监听主题变化,重新创建水印
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.attributeName === 'data-theme') {
createWatermark();
}
});
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-theme']
});
});
</script>
{% endblock %}