/* ============================================ 组件样式 - 按钮、卡片、模态框、加载器等 ============================================ */ /* 加载器 */ #app-loader { position: fixed; inset: 0; background: var(--bg-primary); display: flex; align-items: center; justify-content: center; z-index: 9999; transition: opacity var(--transition-slow), visibility var(--transition-slow); } #app-loader.fade-out { opacity: 0; visibility: hidden; } .loader-content { text-align: center; } .ink-drop { width: 60px; height: 60px; margin: 0 auto 20px; background: radial-gradient(circle, var(--primary) 0%, transparent 70%); border-radius: 50%; animation: inkDrop 1.5s ease-in-out infinite; } .loader-text { font-family: var(--font-display); font-size: var(--font-size-2xl); color: var(--primary); letter-spacing: 4px; } /* 头部导航 */ #app-header { position: fixed; top: 0; left: 0; right: 0; height: calc(var(--header-height) + var(--safe-area-top)); padding-top: var(--safe-area-top); background: var(--bg-secondary); border-bottom: 1px solid var(--border-color); display: flex; align-items: center; justify-content: space-between; padding-left: max(var(--spacing-md), var(--safe-area-left)); padding-right: max(var(--spacing-md), var(--safe-area-right)); z-index: 100; transition: transform var(--transition-normal), background var(--transition-normal); } #app-header.header-hidden { transform: translateY(-100%); } .header-left, .header-right { display: flex; align-items: center; gap: var(--spacing-xs); min-width: 80px; } .header-right { justify-content: flex-end; } .header-title { font-family: var(--font-display); font-size: var(--font-size-xl); color: var(--primary); letter-spacing: 2px; text-align: center; flex: 1; } .header-btn { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-full); transition: background var(--transition-fast); } .header-btn:active { background: var(--bg-hover); } .header-btn svg { width: 24px; height: 24px; min-width: 24px; min-height: 24px; max-width: 24px; max-height: 24px; fill: var(--text-primary); } /* 底部导航 */ #app-nav { position: fixed; bottom: 0; left: 0; right: 0; height: calc(var(--nav-height) + var(--safe-area-bottom)); padding-bottom: var(--safe-area-bottom); background: var(--bg-secondary); border-top: 1px solid var(--border-color); display: flex; align-items: stretch; justify-content: space-around; padding-left: var(--safe-area-left); padding-right: var(--safe-area-right); z-index: 100; transition: transform var(--transition-normal); } #app-nav.nav-hidden { transform: translateY(100%); } .nav-item { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; padding-top: var(--spacing-sm); color: var(--text-muted); transition: color var(--transition-fast); } .nav-item svg { width: 24px; height: 24px; min-width: 24px; min-height: 24px; max-width: 24px; max-height: 24px; fill: currentColor; transition: transform var(--transition-fast); } .nav-item span { font-size: var(--font-size-xs); } .nav-item.active { color: var(--primary); } .nav-item.active svg { transform: scale(1.1); } /* 主内容区 */ #app-content { min-height: 100vh; min-height: 100dvh; padding-top: calc(var(--header-height) + var(--safe-area-top)); padding-bottom: calc(var(--nav-height) + var(--safe-area-bottom)); padding-left: var(--safe-area-left); padding-right: var(--safe-area-right); transition: padding var(--transition-normal); } #app-content.reader-mode { padding: 0; } #app-content.detail-mode { padding-bottom: 0; /* 详情页有自己的底部操作栏 */ } /* Toast 提示 */ #toast { position: fixed; bottom: calc(var(--nav-height) + var(--safe-area-bottom) + 20px); left: 50%; transform: translateX(-50%) translateY(20px); background: rgba(0, 0, 0, 0.8); color: #fff; padding: var(--spacing-sm) var(--spacing-lg); border-radius: var(--radius-full); box-shadow: var(--shadow-lg); font-size: var(--font-size-sm); opacity: 0; transition: opacity var(--transition-fast), transform var(--transition-fast); z-index: 1000; max-width: 80%; text-align: center; white-space: nowrap; } /* 阅读模式下Toast位置调整 */ .reader-mode ~ #toast, body:has(.reader-mode) #toast { bottom: calc(100px + var(--safe-area-bottom)); } #toast.show { opacity: 1; transform: translateX(-50%) translateY(0); } /* 模态框 */ .modal { position: fixed; inset: 0; z-index: 500; display: flex; align-items: center; justify-content: center; padding: var(--spacing-lg); } .modal-overlay { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(4px); } .modal-content { position: relative; width: 100%; max-width: 340px; background: var(--bg-card); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); animation: fadeInUp var(--transition-normal) ease; } .modal-header { display: flex; align-items: center; justify-content: space-between; padding: var(--spacing-md); border-bottom: 1px solid var(--border-color); } .modal-header span { font-size: var(--font-size-lg); font-weight: 600; } .modal-close { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-full); } .modal-close svg { width: 20px; height: 20px; fill: var(--text-secondary); } .modal-body { padding: var(--spacing-md); } .modal-body textarea { width: 100%; min-height: 100px; padding: var(--spacing-md); background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: var(--radius-md); resize: none; } .modal-body textarea::placeholder { color: var(--text-muted); } .modal-footer { display: flex; gap: var(--spacing-sm); padding: var(--spacing-md); border-top: 1px solid var(--border-color); } .modal-footer button { flex: 1; padding: var(--spacing-sm) var(--spacing-md); border-radius: var(--radius-md); font-weight: 500; transition: background var(--transition-fast); } .btn-cancel { background: var(--bg-hover); } .btn-confirm { background: var(--primary); color: var(--bg-primary); } /* 小说卡片 */ .novel-card { display: flex; gap: var(--spacing-md); padding: var(--spacing-md); background: var(--bg-card); border-radius: var(--radius-md); transition: transform var(--transition-fast), box-shadow var(--transition-fast); } .novel-card:active { transform: scale(0.98); } .novel-cover { width: 80px; height: 110px; border-radius: var(--radius-sm); overflow: hidden; flex-shrink: 0; background: var(--bg-hover); } .novel-cover img { width: 100%; height: 100%; object-fit: cover; } .novel-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--spacing-xs); } .novel-title { font-size: var(--font-size-md); font-weight: 600; color: var(--text-primary); } .novel-author { font-size: var(--font-size-sm); color: var(--text-secondary); } .novel-synopsis { font-size: var(--font-size-sm); color: var(--text-muted); line-height: 1.5; } .novel-tags { display: flex; flex-wrap: wrap; gap: var(--spacing-xs); margin-top: auto; } .tag { display: inline-block; padding: 2px 8px; background: var(--bg-hover); border-radius: var(--radius-full); font-size: var(--font-size-xs); color: var(--primary); } /* 网格布局卡片 */ .novel-grid-card { display: flex; flex-direction: column; background: var(--bg-card); border-radius: var(--radius-md); overflow: hidden; transition: transform var(--transition-fast); } .novel-grid-card:active { transform: scale(0.96); } .novel-grid-card .novel-cover { width: 100%; height: 0; padding-bottom: 140%; position: relative; } .novel-grid-card .novel-cover img { position: absolute; inset: 0; width: 100%; height: 100%; } .novel-grid-card .novel-info { padding: var(--spacing-sm); } .novel-grid-card .novel-title { font-size: var(--font-size-sm); } .novel-grid-card .novel-author { font-size: var(--font-size-xs); } /* 章节列表项 */ .chapter-item { display: flex; align-items: center; padding: var(--spacing-md); border-bottom: 1px solid var(--border-color); transition: background var(--transition-fast); } .chapter-item:active { background: var(--bg-hover); } .chapter-item.current { color: var(--primary); background: rgba(212, 165, 116, 0.1); } .chapter-index { width: 50px; font-size: var(--font-size-sm); color: var(--text-muted); flex-shrink: 0; } .chapter-title { flex: 1; font-size: var(--font-size-md); } /* 历史/书签列表项 */ .history-item, .bookmark-item { display: flex; gap: var(--spacing-md); padding: var(--spacing-md); background: var(--bg-card); border-radius: var(--radius-md); position: relative; } .history-item .novel-cover, .bookmark-item .novel-cover { width: 60px; height: 80px; } .history-info, .bookmark-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--spacing-xs); } .history-chapter, .bookmark-chapter { font-size: var(--font-size-sm); color: var(--text-secondary); } .history-time, .bookmark-note { font-size: var(--font-size-xs); color: var(--text-muted); } .item-actions { position: absolute; top: var(--spacing-sm); right: var(--spacing-sm); } .item-actions button { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-full); } .item-actions svg { width: 18px; height: 18px; fill: var(--text-muted); } /* 空状态 */ .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: var(--spacing-xl) var(--spacing-lg); text-align: center; min-height: 300px; } .empty-state svg { width: 80px; height: 80px; fill: var(--text-muted); margin-bottom: var(--spacing-lg); opacity: 0.5; } .empty-state h3 { font-size: var(--font-size-lg); color: var(--text-secondary); margin-bottom: var(--spacing-sm); } .empty-state p { font-size: var(--font-size-sm); color: var(--text-muted); } /* 加载更多 */ .load-more { display: flex; align-items: center; justify-content: center; padding: var(--spacing-lg); } .load-more-btn { padding: var(--spacing-sm) var(--spacing-xl); background: var(--bg-card); border-radius: var(--radius-full); color: var(--text-secondary); font-size: var(--font-size-sm); } .loading-spinner { width: 24px; height: 24px; border: 2px solid var(--border-color); border-top-color: var(--primary); border-radius: 50%; animation: spin 0.8s linear infinite; } /* 骨架屏 */ .skeleton { background: linear-gradient(90deg, var(--bg-hover) 25%, var(--bg-card) 50%, var(--bg-hover) 75%); background-size: 200% 100%; animation: skeleton-loading 1.5s infinite; border-radius: var(--radius-sm); } @keyframes skeleton-loading { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } .skeleton-card { display: flex; gap: var(--spacing-md); padding: var(--spacing-md); } .skeleton-cover { width: 80px; height: 110px; } .skeleton-info { flex: 1; display: flex; flex-direction: column; gap: var(--spacing-sm); } .skeleton-title { height: 20px; width: 70%; } .skeleton-text { height: 14px; width: 40%; } .skeleton-desc { height: 40px; width: 100%; }