diff --git a/web/static/css/components/content.css b/web/static/css/components/content.css index 7525c2a..9240597 100644 --- a/web/static/css/components/content.css +++ b/web/static/css/components/content.css @@ -332,6 +332,18 @@ color: var(--text-primary); cursor: pointer; transition: all 0.2s ease; + min-width: 100px; + height: 32px; + appearance: none; + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 8px center; + background-size: 16px; + padding-right: 28px; +} + +.per-page-select:hover { + border-color: var(--border-dark); } .per-page-select:focus { @@ -340,6 +352,60 @@ box-shadow: 0 0 0 2px var(--accent-100); } +/* 卡片布局控制 */ +.cards-layout-controls { + display: flex; + align-items: center; + gap: 8px; +} + +.cards-per-row-select { + padding: 4px 8px; + border: 1px solid var(--border-medium); + border-radius: var(--radius-sm); + font-size: 14px; + background: var(--bg-primary); + color: var(--text-primary); + cursor: pointer; + transition: all 0.2s ease; + min-width: 80px; + height: 32px; + appearance: none; + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 8px center; + background-size: 16px; + padding-right: 28px; +} + +.cards-per-row-select:hover { + border-color: var(--border-dark); +} + +.cards-per-row-select:focus { + outline: none; + border-color: var(--accent-500); + box-shadow: 0 0 0 2px var(--accent-100); +} + +/* 黑暗模式下的select样式 */ +[data-theme="dark"] .cards-per-row-select, +[data-theme="dark"] .per-page-select { + background-color: var(--bg-secondary); + border-color: var(--border-dark); +} + +[data-theme="dark"] .cards-per-row-select:hover, +[data-theme="dark"] .per-page-select:hover { + border-color: var(--border-light); +} + +[data-theme="dark"] .cards-per-row-select:focus, +[data-theme="dark"] .per-page-select:focus { + border-color: var(--accent-500); + box-shadow: 0 0 0 2px var(--accent-900); +} + /* 主内容区域 */ .content-main { flex: 1; @@ -430,9 +496,30 @@ /* 卡片视图 */ .data-cards { display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; padding: 16px; + transition: all 0.3s ease; +} + +/* 动态列数样式 */ +.data-cards[data-columns="1"] { + grid-template-columns: 1fr; +} + +.data-cards[data-columns="2"] { + grid-template-columns: repeat(2, 1fr); +} + +.data-cards[data-columns="3"] { + grid-template-columns: repeat(3, 1fr); +} + +.data-cards[data-columns="4"] { + grid-template-columns: repeat(4, 1fr); +} + +.data-cards[data-columns="6"] { + grid-template-columns: repeat(6, 1fr); } .data-card { @@ -519,8 +606,15 @@ padding: 16px; } - .data-cards { + .data-cards[data-columns="1"], + .data-cards[data-columns="2"], + .data-cards[data-columns="3"], + .data-cards[data-columns="4"], + .data-cards[data-columns="6"] { grid-template-columns: 1fr; + } + + .data-cards { padding: 12px; } @@ -531,6 +625,26 @@ } } +@media (max-width: 480px) { + .header-tools { + flex-direction: column; + align-items: stretch; + gap: 8px; + } + + .view-controls, + .export-dropdown, + .cards-layout-controls { + width: 100%; + } + + .export-button, + .cards-per-row-select { + width: 100%; + justify-content: center; + } +} + @media (max-width: 480px) { .header-tools { flex-direction: column; diff --git a/web/static/js/app.js b/web/static/js/app.js index f571683..10af151 100644 --- a/web/static/js/app.js +++ b/web/static/js/app.js @@ -295,6 +295,12 @@ class AppState { // 切换数据展示方式 this.switchDataDisplay(mode); + + // 显示/隐藏卡片布局控制 + const cardsLayoutControls = document.getElementById('cardsLayoutControls'); + if (cardsLayoutControls) { + cardsLayoutControls.style.display = mode === 'cards' ? 'flex' : 'none'; + } } switchDataDisplay(mode) { @@ -404,6 +410,15 @@ class AppState { window.location.href = `/?${params.toString()}`; } + // 卡片布局控制 + changeCardsPerRow(columns) { + const cardsContainer = document.querySelector('.data-cards'); + if (cardsContainer) { + cardsContainer.setAttribute('data-columns', columns); + localStorage.setItem('cardsPerRow', columns); + } + } + // 键盘快捷键 setupKeyboardShortcuts() { document.addEventListener('keydown', (e) => { @@ -613,6 +628,15 @@ class AppState { perPageSelect.value = savedPerPage; } } + + // 恢复卡片布局设置 + const savedCardsPerRow = localStorage.getItem('cardsPerRow') || '2'; + this.changeCardsPerRow(savedCardsPerRow); + + const cardsPerRowSelect = document.querySelector('.cards-per-row-select'); + if (cardsPerRowSelect) { + cardsPerRowSelect.value = savedCardsPerRow; + } } openSettings() { @@ -647,6 +671,7 @@ window.setViewMode = (mode) => app.setViewMode(mode); window.toggleExportMenu = () => app.toggleExportMenu(); window.exportData = (format) => app.exportData(format); window.changePerPage = (perPage) => app.changePerPage(perPage); +window.changeCardsPerRow = (columns) => app.changeCardsPerRow(columns); window.showDetail = (id) => app.showDetail(id); window.closeModal = () => app.closeModal(); window.openSettings = () => app.openSettings(); diff --git a/web/templates/list.html b/web/templates/list.html index 4614734..5d14722 100644 --- a/web/templates/list.html +++ b/web/templates/list.html @@ -167,6 +167,19 @@ + + + + @@ -267,7 +280,7 @@