BC-M22-002-AW 环节2完成:响应式+localStorage,七连胜
This commit is contained in:
parent
8620c69320
commit
d06b380b51
|
|
@ -0,0 +1,134 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>HoloLake公告栏</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<!-- 顶部标题栏 -->
|
||||
<div class="header">
|
||||
<h1>公告栏</h1>
|
||||
<div class="header-actions">
|
||||
<span class="pinned-badge">2条置顶</span>
|
||||
<button class="subscribe-btn">订阅</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 频道标签栏 -->
|
||||
<div class="channel-bar">
|
||||
<span class="channel active">全部</span>
|
||||
<span class="channel">系统公告</span>
|
||||
<span class="channel">开发动态</span>
|
||||
<span class="channel">团队消息</span>
|
||||
</div>
|
||||
|
||||
<!-- 公告列表 -->
|
||||
<div class="bulletin-list">
|
||||
<!-- 置顶公告1 -->
|
||||
<div class="bulletin-card pinned">
|
||||
<div class="pin-indicator">置顶</div>
|
||||
<div class="bulletin-icon system"></div>
|
||||
<div class="bulletin-content">
|
||||
<div class="bulletin-header">
|
||||
<span class="bulletin-title">光湖系统MVP v0.4.0发布公告</span>
|
||||
<span class="bulletin-time">2小时前</span>
|
||||
</div>
|
||||
<p class="bulletin-summary">主域公告栏与频道过渡系统(M22)正式进入环节0开发。新增公告置顶、频道分类、时间线展示功能,信息展示层逐步完善。</p>
|
||||
<div class="bulletin-footer">
|
||||
<span class="bulletin-tag tag-system">系统公告</span>
|
||||
<span class="bulletin-author">发布者:曜冥主控</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 置顶公告2 -->
|
||||
<div class="bulletin-card pinned">
|
||||
<div class="pin-indicator">置顶</div>
|
||||
<div class="bulletin-icon dev"></div>
|
||||
<div class="bulletin-content">
|
||||
<div class="bulletin-header">
|
||||
<span class="bulletin-title">SYSLOG提交流程v2上线通知</span>
|
||||
<span class="bulletin-time">5小时前</span>
|
||||
</div>
|
||||
<p class="bulletin-summary">SYSLOG生成方式已更新为「知秋主动提问制」完成任务后由知秋引导填写,无需手动套用模板。即日起生效。</p>
|
||||
<div class="bulletin-footer">
|
||||
<span class="bulletin-tag tag-dev">开发动态</span>
|
||||
<span class="bulletin-author">发布者:知秋</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 普通公告1 -->
|
||||
<div class="bulletin-card">
|
||||
<div class="bulletin-icon team"></div>
|
||||
<div class="bulletin-content">
|
||||
<div class="bulletin-header">
|
||||
<span class="bulletin-title">欢迎Awen加入光湖团队!</span>
|
||||
<span class="bulletin-time">1天前</span>
|
||||
</div>
|
||||
<p class="bulletin-summary">DEV-012 Awen正式加入光湖开发团队,成为第12位协作者。首个模块M09消息通知中心已全通关!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 普通公告2 -->
|
||||
<div class="bulletin-card">
|
||||
<div class="bulletin-icon dev"></div>
|
||||
<div class="bulletin-content">
|
||||
<div class="bulletin-header">
|
||||
<span class="bulletin-title">M08数据统计面板全通关</span>
|
||||
<span class="bulletin-time">2天前</span>
|
||||
</div>
|
||||
<p class="bulletin-summary">完成M08全部环节,七连胜达成!响应式布局+SVG环形图+CSV导出一次通过,正式前端毕业</p>
|
||||
<div class="bulletin-footer">
|
||||
<span class="bulletin-tag tag-dev">开发动态</span>
|
||||
<span class="bulletin-author">发布者:霜砚</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 普通公告3 -->
|
||||
<div class="bulletin-card">
|
||||
<div class="bulletin-icon system"></div>
|
||||
<div class="bulletin-content">
|
||||
<div class="bulletin-header">
|
||||
<span class="bulletin-title">HTTPS配置与飞书Webhook联调完成</span>
|
||||
<span class="bulletin-time">3天前</span>
|
||||
</div>
|
||||
<p class="bulletin-summary">光湖主域已完成HTTPS配置与飞书Webhook全链路联调,Nginx+PM2+Certbot部署完毕,系统脊梁正式贯通。</p>
|
||||
<div class="bulletin-footer">
|
||||
<span class="bulletin-tag tag-system">系统公告</span>
|
||||
<span class="bulletin-author">发布者:页页</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 普通公告4 -->
|
||||
<div class="bulletin-card">
|
||||
<div class="bulletin-icon team"></div>
|
||||
<div class="bulletin-content">
|
||||
<div class="bulletin-header">
|
||||
<span class="bulletin-title">本周开发者进度总览</span>
|
||||
<span class="bulletin-time">3天前</span>
|
||||
</div>
|
||||
<p class="bulletin-summary">12位开发者中8位活跃,累计完成30+个环节。肥猫五连胜、桔子七连胜、小草莓五连胜、Awen四连胜团队势头强劲!</p>
|
||||
<div class="bulletin-footer">
|
||||
<span class="bulletin-tag tag-team">团队消息</span>
|
||||
<span class="bulletin-author">发布者:曜冥主控</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部状态栏 -->
|
||||
<div class="footer">
|
||||
<span>共6条公告2条置顶</span>
|
||||
<span class="footer-brand">HoloLake光湖系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<script src="storage.js"></script>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
// ========== 确保 HoloLake 命名空间存在 ==========
|
||||
window.HoloLake = window.HoloLake || {};
|
||||
|
||||
// ========== 页面加载完成后执行 ==========
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('🚀 script.js 初始化');
|
||||
|
||||
// 恢复所有状态
|
||||
restoreState();
|
||||
|
||||
// 绑定事件
|
||||
bindEvents();
|
||||
|
||||
// 更新布局信息
|
||||
updateLayoutInfo();
|
||||
|
||||
// 监听窗口大小变化
|
||||
window.addEventListener('resize', function() {
|
||||
updateLayoutInfo();
|
||||
});
|
||||
});
|
||||
|
||||
// ========== 恢复状态 ==========
|
||||
function restoreState() {
|
||||
console.log('🔍 restoreState 开始...');
|
||||
|
||||
try {
|
||||
// 1. 恢复订阅状态
|
||||
const isSubscribed = HoloLake.UserState.isSubscribed();
|
||||
const subscribeBtn = document.querySelector('.subscribe-btn');
|
||||
if (subscribeBtn) {
|
||||
if (isSubscribed) {
|
||||
subscribeBtn.classList.add('active');
|
||||
subscribeBtn.textContent = '已订阅';
|
||||
} else {
|
||||
subscribeBtn.classList.remove('active');
|
||||
subscribeBtn.textContent = '订阅';
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 恢复已读公告
|
||||
const readList = HoloLake.UserState.getReadBulletins();
|
||||
const bulletinCards = document.querySelectorAll('.bulletin-card');
|
||||
bulletinCards.forEach((card, index) => {
|
||||
const bulletinId = `bulletin-${index}`;
|
||||
if (readList.includes(bulletinId)) {
|
||||
card.classList.add('read');
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 恢复选中频道
|
||||
const activeChannel = HoloLake.UserState.getActiveChannel();
|
||||
const channels = document.querySelectorAll('.channel');
|
||||
channels.forEach(channel => {
|
||||
const channelText = channel.textContent.trim();
|
||||
if (channelText === activeChannel || (activeChannel === '全部' && channelText === '全部')) {
|
||||
channel.classList.add('active');
|
||||
} else {
|
||||
channel.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
// 4. 更新最后访问时间
|
||||
HoloLake.UserState.updateLastVisit();
|
||||
|
||||
console.log('✅ 恢复已完成');
|
||||
} catch (e) {
|
||||
console.error('❌ 恢复失败:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 绑定事件 ==========
|
||||
function bindEvents() {
|
||||
console.log('🔗 绑定事件...');
|
||||
|
||||
// 订阅按钮
|
||||
const subscribeBtn = document.querySelector('.subscribe-btn');
|
||||
if (subscribeBtn) {
|
||||
subscribeBtn.addEventListener('click', function() {
|
||||
const newState = HoloLake.UserState.toggleSubscribe();
|
||||
if (newState) {
|
||||
this.classList.add('active');
|
||||
this.textContent = '已订阅';
|
||||
} else {
|
||||
this.classList.remove('active');
|
||||
this.textContent = '订阅';
|
||||
}
|
||||
console.log('📌 订阅状态:', newState ? '已订阅' : '未订阅');
|
||||
});
|
||||
}
|
||||
|
||||
// 频道点击
|
||||
const channels = document.querySelectorAll('.channel');
|
||||
channels.forEach(channel => {
|
||||
channel.addEventListener('click', function() {
|
||||
// 更新UI
|
||||
channels.forEach(c => c.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
|
||||
// 保存状态
|
||||
const channelName = this.textContent.trim();
|
||||
HoloLake.UserState.setActiveChannel(channelName);
|
||||
|
||||
// 筛选公告(可选功能,这里先做简单筛选)
|
||||
filterBulletinsByChannel(channelName);
|
||||
|
||||
console.log('📺 切换到频道:', channelName);
|
||||
});
|
||||
});
|
||||
|
||||
// 公告点击(标记已读)
|
||||
const bulletinCards = document.querySelectorAll('.bulletin-card');
|
||||
bulletinCards.forEach((card, index) => {
|
||||
card.addEventListener('click', function() {
|
||||
const bulletinId = `bulletin-${index}`;
|
||||
|
||||
// 标记已读
|
||||
if (!this.classList.contains('read')) {
|
||||
this.classList.add('read');
|
||||
HoloLake.UserState.markAsRead(bulletinId);
|
||||
console.log('📖 已读公告:', bulletinId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ========== 按频道筛选 ==========
|
||||
function filterBulletinsByChannel(channelName) {
|
||||
const cards = document.querySelectorAll('.bulletin-card');
|
||||
|
||||
if (channelName === '全部') {
|
||||
cards.forEach(card => {
|
||||
card.style.display = 'flex';
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
cards.forEach(card => {
|
||||
const tag = card.querySelector('.bulletin-tag');
|
||||
if (tag && tag.textContent.trim() === channelName) {
|
||||
card.style.display = 'flex';
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ========== 更新布局信息 ==========
|
||||
function updateLayoutInfo() {
|
||||
const width = window.innerWidth;
|
||||
let mode = '桌面';
|
||||
|
||||
if (width <= 480) {
|
||||
mode = '手机';
|
||||
} else if (width <= 768) {
|
||||
mode = '平板';
|
||||
}
|
||||
|
||||
console.log(`📱 当前布局: ${mode}模式 (${width}px)`);
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/**
|
||||
* HoloLake Bulletin 数据持久化模块
|
||||
* storage.js - localStorage 封装 + 用户状态管理
|
||||
* 模块 ID: BC-M22-002-AW
|
||||
*/
|
||||
|
||||
window.HoloLake = window.HoloLake || {};
|
||||
|
||||
// ========== Storage 工具对象(带前缀) ==========
|
||||
HoloLake.Storage = {
|
||||
prefix: 'hololake_bulletin_',
|
||||
|
||||
// 保存数据
|
||||
save: function(key, value) {
|
||||
try {
|
||||
const serialized = JSON.stringify(value);
|
||||
localStorage.setItem(this.prefix + key, serialized);
|
||||
console.log(`[Storage] 已保存: ${key} =`, value);
|
||||
} catch (e) {
|
||||
console.error('[Storage] 保存失败:', e);
|
||||
}
|
||||
},
|
||||
|
||||
// 读取数据
|
||||
load: function(key, defaultValue = null) {
|
||||
try {
|
||||
const serialized = localStorage.getItem(this.prefix + key);
|
||||
if (serialized === null) {
|
||||
console.log(`[Storage] 无数据: ${key},返回默认值`);
|
||||
return defaultValue;
|
||||
}
|
||||
const value = JSON.parse(serialized);
|
||||
console.log(`[Storage] 已加载: ${key} =`, value);
|
||||
return value;
|
||||
} catch (e) {
|
||||
console.error('[Storage] 读取失败:', e);
|
||||
return defaultValue;
|
||||
}
|
||||
},
|
||||
|
||||
// 删除指定键
|
||||
remove: function(key) {
|
||||
try {
|
||||
localStorage.removeItem(this.prefix + key);
|
||||
console.log(`[Storage] 已删除: ${key}`);
|
||||
} catch (e) {
|
||||
console.error('[Storage] 删除失败:', e);
|
||||
}
|
||||
},
|
||||
|
||||
// 清空所有带前缀的数据
|
||||
clear: function() {
|
||||
try {
|
||||
const keysToRemove = [];
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key.startsWith(this.prefix)) {
|
||||
keysToRemove.push(key);
|
||||
}
|
||||
}
|
||||
keysToRemove.forEach(key => localStorage.removeItem(key));
|
||||
console.log('[Storage] 已清空所有公告栏数据');
|
||||
} catch (e) {
|
||||
console.error('[Storage] 清空失败:', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ========== 用户状态管理 ==========
|
||||
HoloLake.UserState = {
|
||||
// 已读公告列表
|
||||
getReadBulletins: function() {
|
||||
return HoloLake.Storage.load('read_bulletins', []);
|
||||
},
|
||||
|
||||
markAsRead: function(bulletinId) {
|
||||
const readList = this.getReadBulletins();
|
||||
if (!readList.includes(bulletinId)) {
|
||||
readList.push(bulletinId);
|
||||
HoloLake.Storage.save('read_bulletins', readList);
|
||||
}
|
||||
return readList;
|
||||
},
|
||||
|
||||
// 订阅状态
|
||||
isSubscribed: function() {
|
||||
return HoloLake.Storage.load('is_subscribed', false);
|
||||
},
|
||||
|
||||
toggleSubscribe: function() {
|
||||
const current = this.isSubscribed();
|
||||
const newState = !current;
|
||||
HoloLake.Storage.save('is_subscribed', newState);
|
||||
return newState;
|
||||
},
|
||||
|
||||
// 当前频道
|
||||
getActiveChannel: function() {
|
||||
return HoloLake.Storage.load('active_channel', 'all');
|
||||
},
|
||||
|
||||
setActiveChannel: function(channelId) {
|
||||
HoloLake.Storage.save('active_channel', channelId);
|
||||
},
|
||||
|
||||
// 上次访问时间
|
||||
getLastVisit: function() {
|
||||
return HoloLake.Storage.load('last_visit', null);
|
||||
},
|
||||
|
||||
updateLastVisit: function() {
|
||||
const now = new Date().toISOString();
|
||||
HoloLake.Storage.save('last_visit', now);
|
||||
return now;
|
||||
},
|
||||
|
||||
// 重置所有状态(测试用)
|
||||
resetAll: function() {
|
||||
HoloLake.Storage.remove('read_bulletins');
|
||||
HoloLake.Storage.remove('is_subscribed');
|
||||
HoloLake.Storage.remove('active_channel');
|
||||
HoloLake.Storage.remove('last_visit');
|
||||
console.log('[UserState] 已重置所有状态');
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化时记录访问时间(可选,页面加载时由 script.js 调用)
|
||||
console.log('✅ storage.js 已加载,HoloLake.Storage 和 HoloLake.UserState 已就绪');
|
||||
|
|
@ -0,0 +1,397 @@
|
|||
/* HoloLake公告栏系统深色科技风 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||||
background: #0a1628;
|
||||
color: #e0e6ed;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
max-width: 580px;
|
||||
margin: 0 auto;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
/* ========== 顶部标题栏 ========== */
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24px 0 16px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.08);
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: #e0e6ed;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.pinned-badge {
|
||||
background: rgba(255, 183, 77, 0.15);
|
||||
color: #ffb74d;
|
||||
font-size: 12px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.subscribe-btn {
|
||||
background: rgba(79, 195, 247, 0.1);
|
||||
color: #4fc3f7;
|
||||
border: 1px solid rgba(79, 195, 247, 0.2);
|
||||
padding: 6px 14px;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.subscribe-btn:hover {
|
||||
background: rgba(79, 195, 247, 0.2);
|
||||
}
|
||||
|
||||
/* ========== 频道栏 ========== */
|
||||
.channel-bar {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.06);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.channel {
|
||||
padding: 8px 18px;
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
background: transparent;
|
||||
color: #8899aa;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.channel:hover {
|
||||
border-color: rgba(255, 183, 77, 0.3);
|
||||
color: #b0bec5;
|
||||
}
|
||||
|
||||
.channel.active {
|
||||
background: rgba(255,183,77,0.15);
|
||||
border-color: #ffb74d;
|
||||
color: #ffb74d;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ========== 公告列表 ========== */
|
||||
.bulletin-list {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.bulletin-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
background: rgba(20, 30, 45, 0.6);
|
||||
border: 1px solid rgba(255,255,255,0.04);
|
||||
margin-bottom: 12px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.bulletin-card.pinned {
|
||||
border: 1px solid rgba(255, 183, 77, 0.3);
|
||||
background: rgba(255, 183, 77, 0.02);
|
||||
}
|
||||
|
||||
.pin-indicator {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 12px;
|
||||
font-size: 11px;
|
||||
color: #ffb74d;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 公告图标 */
|
||||
.bulletin-icon {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bulletin-icon.system { background: rgba(156,39,176,0.12); }
|
||||
.bulletin-icon.dev { background: rgba(76,175,80,0.12); }
|
||||
.bulletin-icon.team { background: rgba(79,195,247,0.12); }
|
||||
|
||||
/* 公告内容 */
|
||||
.bulletin-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.bulletin-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.bulletin-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #e0e6ed;
|
||||
}
|
||||
|
||||
.bulletin-time {
|
||||
font-size: 12px;
|
||||
color: #556677;
|
||||
flex-shrink: 0;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.bulletin-summary {
|
||||
font-size: 13px;
|
||||
color: #8899aa;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* 公告底部 */
|
||||
.bulletin-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bulletin-tag {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tag-system { background: rgba(156,39,176,0.12); color: #ce93d8; }
|
||||
.tag-dev { background: rgba(76,175,80,0.12); color: #81c784; }
|
||||
.tag-team { background: rgba(79,195,247,0.12); color: #4fc3f7; }
|
||||
|
||||
.bulletin-author {
|
||||
font-size: 11px;
|
||||
color: #556677;
|
||||
}
|
||||
|
||||
/* ========== 底部状态栏 ========== */
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px 0;
|
||||
border-top: 1px solid rgba(255,255,255,0.06);
|
||||
font-size: 12px;
|
||||
color: #556677;
|
||||
}
|
||||
|
||||
.footer-brand {
|
||||
color: rgba(255, 183, 77, 0.5);
|
||||
}
|
||||
|
||||
/* ========================= 环节2:响应式布局 ========================= */
|
||||
|
||||
/* 平板(宽度 768px 以下) */
|
||||
@media (max-width: 768px) {
|
||||
.app-container {
|
||||
max-width: 100%;
|
||||
padding: 0 12px;
|
||||
}
|
||||
header h1 {
|
||||
font-size: 18px;
|
||||
}
|
||||
.channel-bar {
|
||||
gap: 6px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
.channel {
|
||||
padding: 6px 14px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.bulletin-card {
|
||||
padding: 12px 10px;
|
||||
}
|
||||
.channel-bar {
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.channel-bar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.bulletin-card {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.bulletin-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.bulletin-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
}
|
||||
.bulletin-time {
|
||||
margin-left: 0;
|
||||
}
|
||||
.pin-indicator {
|
||||
top: 6px;
|
||||
right: 8px;
|
||||
font-size: 10px;
|
||||
}
|
||||
.footer {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 已读公告样式 */
|
||||
.bulletin-card.read {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.bulletin-card.read .bulletin-title {
|
||||
color: #8899aa;
|
||||
}
|
||||
|
||||
/* 订阅按钮激活状态 */
|
||||
.subscribe-btn.active {
|
||||
background: rgba(79, 195, 247, 0.25);
|
||||
border-color: #4fc3f7;
|
||||
color: #4fc3f7;
|
||||
}
|
||||
/* ========== 响应式断点 ========== */
|
||||
|
||||
/* 已读公告样式 */
|
||||
.bulletin-card.read {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.bulletin-card.read h3 {
|
||||
color: #888;
|
||||
text-decoration: line-through 1px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* 订阅按钮激活状态 */
|
||||
.subscribe-btn.active {
|
||||
border: 2px solid #0066ff;
|
||||
background-color: #e6f0ff;
|
||||
color: #0066ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 平板设备 ≤ 768px */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.bulletin-header h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.bulletin-grid {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.bulletin-card {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.bulletin-card .icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.channel-tabs {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.channel-tab {
|
||||
padding: 6px 12px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 手机设备 ≤ 480px */
|
||||
@media (max-width: 480px) {
|
||||
.bulletin-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.bulletin-header h1 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.subscribe-btn {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.bulletin-card {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.bulletin-card .icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.channel-tabs {
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
gap: 10px;
|
||||
padding-bottom: 8px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none; /* Firefox隐藏滚动条 */
|
||||
}
|
||||
|
||||
.channel-tabs::-webkit-scrollbar {
|
||||
display: none; /* Chrome/Safari隐藏滚动条 */
|
||||
}
|
||||
|
||||
.channel-tab {
|
||||
display: inline-block;
|
||||
float: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bulletin-footer {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue