feat: add colorful / accent color mode toggle
- CAT_COLORS: カテゴリ別カラーマップ(ダーク/ライト両対応) - 統一色モード: すべて var(--accent) Teal - カラフルモード: sns=Blue / media=Pink / news=Orange / tools=Slate / nav=Green / shop=Amber / posimai=Teal - カラフル時: アイコン stroke + カード背景・ボーダーに極薄カラーを適用 - セクションラベルもカテゴリ色に追従 - 設定パネルに色ドット付きトグルボタンを追加 - localStorage に設定を保存
This commit is contained in:
parent
9d3cd8510e
commit
d85b825bba
133
index.html
133
index.html
|
|
@ -208,6 +208,44 @@
|
||||||
.empty-title { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
|
.empty-title { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
|
||||||
.empty-sub { font-size: 13px; }
|
.empty-sub { font-size: 13px; }
|
||||||
|
|
||||||
|
/* ── Color mode selector ── */
|
||||||
|
.color-mode-selector {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.color-mode-btn {
|
||||||
|
flex: 1;
|
||||||
|
padding: 7px 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text2);
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.12s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
.color-mode-btn.active {
|
||||||
|
background: var(--surface2);
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.color-dots {
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
.color-dot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Settings extras ── */
|
/* ── Settings extras ── */
|
||||||
.settings-field-label {
|
.settings-field-label {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
@ -293,6 +331,28 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top:20px">
|
||||||
|
<div class="settings-group-label">アイコンカラー</div>
|
||||||
|
<div class="color-mode-selector">
|
||||||
|
<button class="color-mode-btn" data-color-mode="accent" id="colorModeAccent">
|
||||||
|
<span class="color-dots">
|
||||||
|
<span class="color-dot" style="background:#6EE7B7"></span>
|
||||||
|
<span class="color-dot" style="background:#6EE7B7"></span>
|
||||||
|
<span class="color-dot" style="background:#6EE7B7"></span>
|
||||||
|
</span>
|
||||||
|
統一色
|
||||||
|
</button>
|
||||||
|
<button class="color-mode-btn" data-color-mode="colorful" id="colorModeColorful">
|
||||||
|
<span class="color-dots">
|
||||||
|
<span class="color-dot" style="background:#60A5FA"></span>
|
||||||
|
<span class="color-dot" style="background:#F472B6"></span>
|
||||||
|
<span class="color-dot" style="background:#4ADE80"></span>
|
||||||
|
</span>
|
||||||
|
カラフル
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="margin-top:20px">
|
<div style="margin-top:20px">
|
||||||
<div class="settings-group-label">同期(オプション)</div>
|
<div class="settings-group-label">同期(オプション)</div>
|
||||||
<p class="settings-field-label">
|
<p class="settings-field-label">
|
||||||
|
|
@ -355,8 +415,31 @@
|
||||||
|
|
||||||
const ENABLED_KEY = 'posimai-veil-enabled';
|
const ENABLED_KEY = 'posimai-veil-enabled';
|
||||||
const API_KEY_KEY = 'posimai_api_key';
|
const API_KEY_KEY = 'posimai_api_key';
|
||||||
|
const COLOR_MODE_KEY = 'posimai-veil-color-mode';
|
||||||
const API_BASE = 'https://posimai-lab.tail72e846.ts.net/brain/api';
|
const API_BASE = 'https://posimai-lab.tail72e846.ts.net/brain/api';
|
||||||
|
|
||||||
|
// ── カテゴリカラー(ダーク / ライト) ──────────────────────
|
||||||
|
const CAT_COLORS = {
|
||||||
|
dark: {
|
||||||
|
posimai: '#6EE7B7', // Teal(ブランドカラー)
|
||||||
|
sns: '#60A5FA', // Blue
|
||||||
|
media: '#F472B6', // Pink
|
||||||
|
news: '#FB923C', // Orange
|
||||||
|
tools: '#94A3B8', // Slate
|
||||||
|
nav: '#4ADE80', // Green
|
||||||
|
shop: '#FBBF24', // Amber
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
posimai: '#059669', // Emerald-600
|
||||||
|
sns: '#2563EB', // Blue-600
|
||||||
|
media: '#DB2777', // Pink-600
|
||||||
|
news: '#EA580C', // Orange-600
|
||||||
|
tools: '#475569', // Slate-600
|
||||||
|
nav: '#16A34A', // Green-600
|
||||||
|
shop: '#D97706', // Amber-600
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// ── アプリDB ────────────────────────────────────────────────
|
// ── アプリDB ────────────────────────────────────────────────
|
||||||
// android : Androidパッケージ名(_camera/_phone/_settings は特殊intent)
|
// android : Androidパッケージ名(_camera/_phone/_settings は特殊intent)
|
||||||
// ios : iOS URLスキーム
|
// ios : iOS URLスキーム
|
||||||
|
|
@ -501,8 +584,18 @@ let enabledIds = loadEnabled();
|
||||||
let activeCat = 'all';
|
let activeCat = 'all';
|
||||||
let searchQ = '';
|
let searchQ = '';
|
||||||
let editMode = false;
|
let editMode = false;
|
||||||
|
let colorMode = localStorage.getItem(COLOR_MODE_KEY) || 'accent'; // 'accent' | 'colorful'
|
||||||
let apiKey = localStorage.getItem(API_KEY_KEY) || '';
|
let apiKey = localStorage.getItem(API_KEY_KEY) || '';
|
||||||
|
|
||||||
|
function getTheme() {
|
||||||
|
return document.documentElement.getAttribute('data-theme') === 'light' ? 'light' : 'dark';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCatColor(cat) {
|
||||||
|
if (colorMode !== 'colorful') return 'var(--accent)';
|
||||||
|
return CAT_COLORS[getTheme()][cat] || 'var(--accent)';
|
||||||
|
}
|
||||||
|
|
||||||
function loadEnabled() {
|
function loadEnabled() {
|
||||||
try {
|
try {
|
||||||
const raw = localStorage.getItem(ENABLED_KEY);
|
const raw = localStorage.getItem(ENABLED_KEY);
|
||||||
|
|
@ -608,21 +701,36 @@ function renderApps() {
|
||||||
|
|
||||||
container.innerHTML = orderedCats.map(cat => {
|
container.innerHTML = orderedCats.map(cat => {
|
||||||
const apps = groups[cat];
|
const apps = groups[cat];
|
||||||
|
const color = getCatColor(cat);
|
||||||
|
const isColorful = colorMode === 'colorful';
|
||||||
|
|
||||||
|
// カラフルモード時: カードに極薄の色背景+ボーダー
|
||||||
|
const cardColorStyle = isColorful
|
||||||
|
? `--item-color:${color};`
|
||||||
|
: '';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="app-section">
|
<div class="app-section">
|
||||||
<div class="section-label">${CAT_LABELS[cat] || cat}</div>
|
<div class="section-label"
|
||||||
|
style="${isColorful ? `color:${color};opacity:.9` : ''}">${CAT_LABELS[cat] || cat}</div>
|
||||||
<div class="app-grid">
|
<div class="app-grid">
|
||||||
${apps.map(app => {
|
${apps.map(app => {
|
||||||
const on = enabledIds.has(app.id);
|
const on = enabledIds.has(app.id);
|
||||||
const hidden = !editMode && !on ? ' hidden' : '';
|
const hidden = !editMode && !on ? ' hidden' : '';
|
||||||
const editCls = editMode ? ` edit-mode ${on ? 'on' : 'off'}` : '';
|
const editCls = editMode ? ` edit-mode ${on ? 'on' : 'off'}` : '';
|
||||||
|
const bgStyle = isColorful
|
||||||
|
? `background:${color}14;border-color:${color}38;`
|
||||||
|
: '';
|
||||||
return `
|
return `
|
||||||
<div class="app-item${editCls}${hidden}"
|
<div class="app-item${editCls}${hidden}"
|
||||||
data-id="${app.id}" role="button" tabindex="0"
|
data-id="${app.id}" role="button" tabindex="0"
|
||||||
aria-label="${app.label}">
|
aria-label="${app.label}"
|
||||||
<i data-lucide="${app.icon}" class="app-icon"></i>
|
style="${bgStyle}${cardColorStyle}">
|
||||||
|
<i data-lucide="${app.icon}" class="app-icon"
|
||||||
|
style="stroke:${color}"></i>
|
||||||
<span class="app-label">${app.label}</span>
|
<span class="app-label">${app.label}</span>
|
||||||
<span class="check-badge" aria-hidden="true">
|
<span class="check-badge" aria-hidden="true"
|
||||||
|
style="background:${color}">
|
||||||
<i data-lucide="check"
|
<i data-lucide="check"
|
||||||
style="width:9px;height:9px;stroke-width:3;stroke:#0D0D0D"></i>
|
style="width:9px;height:9px;stroke-width:3;stroke:#0D0D0D"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -666,6 +774,23 @@ document.getElementById('searchInput').addEventListener('input', e => {
|
||||||
renderApps();
|
renderApps();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── カラーモード切替 ────────────────────────────────────────
|
||||||
|
function syncColorModeUI() {
|
||||||
|
document.getElementById('colorModeAccent').classList.toggle('active', colorMode === 'accent');
|
||||||
|
document.getElementById('colorModeColorful').classList.toggle('active', colorMode === 'colorful');
|
||||||
|
}
|
||||||
|
|
||||||
|
['colorModeAccent', 'colorModeColorful'].forEach(id => {
|
||||||
|
document.getElementById(id).addEventListener('click', () => {
|
||||||
|
colorMode = id === 'colorModeAccent' ? 'accent' : 'colorful';
|
||||||
|
localStorage.setItem(COLOR_MODE_KEY, colorMode);
|
||||||
|
syncColorModeUI();
|
||||||
|
renderApps();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
syncColorModeUI();
|
||||||
|
|
||||||
// ── API キー保存 ────────────────────────────────────────────
|
// ── API キー保存 ────────────────────────────────────────────
|
||||||
document.getElementById('apiKeyInput').value = apiKey;
|
document.getElementById('apiKeyInput').value = apiKey;
|
||||||
document.getElementById('apiKeySave').addEventListener('click', () => {
|
document.getElementById('apiKeySave').addEventListener('click', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue