feat: toolbar統合 — カテゴリタブ+検索+編集を1行に、検索は折りたたみ式

This commit is contained in:
posimai 2026-03-21 20:49:14 +09:00
parent 10fdb8785c
commit 5b65455b26
1 changed files with 92 additions and 71 deletions

View File

@ -90,50 +90,25 @@
} }
.veil-settings-btn:active { background: var(--surface2); } .veil-settings-btn:active { background: var(--surface2); }
/* ── Search ── */ /* ── Toolbar (カテゴリ + アクションボタン統合行) ── */
.search-wrap { .toolbar-wrap {
padding: 8px 16px 4px;
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 10; z-index: 9;
background: var(--bg); background: var(--bg);
} }
.search-wrap-inner { position: relative; } .toolbar {
.search-icon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--text3);
pointer-events: none;
display: flex; display: flex;
align-items: center;
gap: 6px;
padding: 6px 16px;
} }
.search-input {
width: 100%;
box-sizing: border-box;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text);
font-size: 14px;
padding: 9px 14px 9px 38px;
outline: none;
font-family: inherit;
transition: border-color 0.15s;
}
.search-input:focus { border-color: var(--accent); }
/* ── Category tabs ── */
.cat-scroll { .cat-scroll {
display: flex; display: flex;
gap: 6px; gap: 6px;
padding: 8px 16px;
overflow-x: auto; overflow-x: auto;
scrollbar-width: none; scrollbar-width: none;
position: sticky; flex: 1;
top: 52px;
z-index: 9;
background: var(--bg);
} }
.cat-scroll::-webkit-scrollbar { display: none; } .cat-scroll::-webkit-scrollbar { display: none; }
.cat-btn { .cat-btn {
@ -155,23 +130,57 @@
border-color: var(--accent); border-color: var(--accent);
font-weight: 600; font-weight: 600;
} }
.toolbar-actions {
display: flex;
align-items: center;
gap: 6px;
flex-shrink: 0;
}
.toolbar-search-btn {
width: 30px;
height: 30px;
border-radius: 50%;
border: 1px solid var(--border);
background: transparent;
color: var(--text2);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
flex-shrink: 0;
transition: color 0.12s, border-color 0.12s;
}
.toolbar-search-btn.active {
color: var(--accent);
border-color: var(--accent);
}
/* ── Edit bar ── */ /* ── Search expand (折りたたみ) ── */
.edit-bar { .search-expand {
display: flex; overflow: hidden;
align-items: center; max-height: 0;
justify-content: space-between; padding: 0 16px;
padding: 8px 16px 0; transition: max-height 0.2s cubic-bezier(0.2, 0.9, 0.2, 1),
min-height: 36px; padding 0.2s cubic-bezier(0.2, 0.9, 0.2, 1);
gap: 8px;
} }
.edit-bar-left { .search-expand.open {
display: flex; max-height: 56px;
align-items: center; padding: 4px 16px 8px;
gap: 8px;
flex: 1;
} }
.edit-bar-hint { font-size: 11px; color: var(--text3); } .search-input {
width: 100%;
box-sizing: border-box;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text);
font-size: 14px;
padding: 9px 14px;
outline: none;
font-family: inherit;
transition: border-color 0.15s;
}
.search-input:focus { border-color: var(--accent); }
.edit-toggle-btn { .edit-toggle-btn {
font-size: 12px; font-size: 12px;
padding: 5px 12px; padding: 5px 12px;
@ -749,28 +758,25 @@
</button> </button>
</div> </div>
<div class="search-wrap"> <div class="toolbar-wrap">
<div class="search-wrap-inner"> <div class="toolbar">
<span class="search-icon">
<i data-lucide="search" style="width:16px;height:16px;stroke-width:1.75"></i>
</span>
<input class="search-input" id="searchInput" type="search"
placeholder="アプリを検索" autocomplete="off" autocorrect="off" autocapitalize="off">
</div>
</div>
<div class="cat-scroll" id="catScroll" role="tablist" aria-label="カテゴリフィルタ"></div> <div class="cat-scroll" id="catScroll" role="tablist" aria-label="カテゴリフィルタ"></div>
<div class="toolbar-actions">
<div class="edit-bar"> <button class="toolbar-search-btn" id="searchBtn" aria-label="検索">
<div class="edit-bar-left"> <i data-lucide="search" style="width:15px;height:15px;stroke-width:1.75"></i>
</button>
<button class="add-app-btn" id="addAppBtn" aria-label="アプリを追加"> <button class="add-app-btn" id="addAppBtn" aria-label="アプリを追加">
<i data-lucide="plus" style="width:13px;height:13px;stroke-width:2.5"></i> <i data-lucide="plus" style="width:13px;height:13px;stroke-width:2.5"></i>
アプリを追加 アプリを追加
</button> </button>
<span class="edit-bar-hint" id="editBarHint"></span>
</div>
<button class="edit-toggle-btn" id="editToggleBtn">編集</button> <button class="edit-toggle-btn" id="editToggleBtn">編集</button>
</div> </div>
</div>
<div class="search-expand" id="searchExpand">
<input class="search-input" id="searchInput" type="search"
placeholder="アプリを検索" autocomplete="off" autocorrect="off" autocapitalize="off">
</div>
</div>
<div id="appSections"></div> <div id="appSections"></div>
@ -1083,12 +1089,10 @@ function renderCatTabs() {
// ── アプリグリッド描画 ────────────────────────────────────── // ── アプリグリッド描画 ──────────────────────────────────────
function renderApps() { function renderApps() {
const container = document.getElementById('appSections'); const container = document.getElementById('appSections');
const hint = document.getElementById('editBarHint');
const editBtn = document.getElementById('editToggleBtn'); const editBtn = document.getElementById('editToggleBtn');
const addBtn = document.getElementById('addAppBtn'); const addBtn = document.getElementById('addAppBtn');
editBtn.classList.toggle('active', editMode); editBtn.classList.toggle('active', editMode);
hint.textContent = editMode ? 'タップで表示/非表示を切り替え' : '';
addBtn.classList.toggle('visible', editMode); addBtn.classList.toggle('visible', editMode);
const q = searchQ.toLowerCase(); const q = searchQ.toLowerCase();
@ -1198,8 +1202,25 @@ document.getElementById('editToggleBtn').addEventListener('click', () => {
renderApps(); renderApps();
}); });
// ── 検索 ──────────────────────────────────────────────────── // ── 検索(折りたたみ) ──────────────────────────────────────
document.getElementById('searchInput').addEventListener('input', e => { const searchBtn = document.getElementById('searchBtn');
const searchExpand = document.getElementById('searchExpand');
const searchInput = document.getElementById('searchInput');
searchBtn.addEventListener('click', () => {
const open = searchExpand.classList.toggle('open');
searchBtn.classList.toggle('active', open);
if (open) {
searchInput.focus();
} else {
searchInput.value = '';
searchQ = '';
renderCatTabs();
renderApps();
}
});
searchInput.addEventListener('input', e => {
searchQ = e.target.value; searchQ = e.target.value;
if (searchQ) activeCat = 'all'; if (searchQ) activeCat = 'all';
renderCatTabs(); renderCatTabs();