This commit is contained in:
+1
-1
@@ -39,7 +39,7 @@
|
||||
}
|
||||
|
||||
html { background: #ffffff; }
|
||||
html[data-theme="dark"] { background: #0a0a0c; }
|
||||
html[data-theme="dark"] { background: #18181c; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
|
||||
@@ -453,17 +453,24 @@ export function ChatPane({ task, comments, onSubmit, onCancel, onOpenDetail }: C
|
||||
<button
|
||||
disabled={submitting || (!draft.trim() && attachments.length === 0)}
|
||||
onClick={handleSubmit}
|
||||
className="px-3 h-9 bg-amber-500 text-white rounded-md text-xs font-semibold disabled:opacity-50 hover:bg-amber-600 flex-shrink-0 transition-colors"
|
||||
className="inline-flex items-center gap-1.5 px-3 h-9 rounded-md text-xs font-semibold flex-shrink-0 transition-colors bg-amber-100 text-amber-800 border border-amber-300 hover:bg-amber-200 dark:bg-amber-500/15 dark:text-amber-300 dark:border-amber-500/30 dark:hover:bg-amber-500/25 disabled:opacity-50"
|
||||
>
|
||||
<svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||
<polyline points="15 10 20 15 15 20" />
|
||||
<path d="M4 4v7a4 4 0 0 0 4 4h12" />
|
||||
</svg>
|
||||
割り込み
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
disabled={cancelling}
|
||||
onClick={() => void handleCancel()}
|
||||
className="px-3 h-9 bg-canvas border border-red-200 text-red-700 dark:text-red-300 rounded-md text-xs font-semibold disabled:opacity-50 hover:bg-red-50 dark:hover:bg-red-500/15 flex-shrink-0 transition-colors"
|
||||
className="inline-flex items-center gap-1.5 px-3 h-9 rounded-md text-xs font-semibold flex-shrink-0 transition-colors bg-canvas border border-red-200 text-red-700 hover:bg-red-50 dark:border-red-500/40 dark:text-red-300 dark:hover:bg-red-500/15 disabled:opacity-50"
|
||||
title="エージェントの実行を停止"
|
||||
>
|
||||
<svg className="w-3 h-3" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<rect x="6" y="6" width="12" height="12" rx="2.5" fill="currentColor" />
|
||||
</svg>
|
||||
{cancelling ? '停止中...' : '停止'}
|
||||
</button>
|
||||
</div>
|
||||
@@ -471,8 +478,12 @@ export function ChatPane({ task, comments, onSubmit, onCancel, onOpenDetail }: C
|
||||
<button
|
||||
disabled={submitting || inputLocked || (!draft.trim() && attachments.length === 0)}
|
||||
onClick={handleSubmit}
|
||||
className="px-3 h-9 bg-accent text-accent-fg rounded-md text-xs font-semibold disabled:opacity-50 hover:bg-accent-deep flex-shrink-0 transition-colors"
|
||||
className="inline-flex items-center gap-1.5 px-3 h-9 bg-accent text-accent-fg rounded-md text-xs font-semibold disabled:opacity-50 hover:bg-accent-deep flex-shrink-0 transition-colors"
|
||||
>
|
||||
<svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||
<path d="M22 2 11 13" />
|
||||
<path d="M22 2 15 22 11 13 2 9 22 2Z" />
|
||||
</svg>
|
||||
送信
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -48,6 +48,28 @@ export function BrowserSettingsForm({ config, onChange }: SectionFormProps) {
|
||||
|
||||
<h3 className="text-sm font-medium text-slate-600 mt-4 pt-3 border-t border-slate-200">Sessions (CDP)</h3>
|
||||
|
||||
<div>
|
||||
<FieldLabel>CAPTCHA Solve Mode</FieldLabel>
|
||||
<select value={browser.captchaSolve ?? 'skip'}
|
||||
onChange={e => onChange('browser.captchaSolve', e.target.value)}
|
||||
className="w-full h-9 px-2 text-[13px] border border-hairline rounded-md">
|
||||
<option value="skip">skip (headless fallback, default)</option>
|
||||
<option value="novnc">novnc (shared CAPTCHA Pool, solve in CAPTCHA tab)</option>
|
||||
</select>
|
||||
<HelpText>
|
||||
<code>novnc</code> にすると WebSearch 等が CAPTCHA を踏んだとき共有 noVNC セッション(CAPTCHA Pool)を立て、
|
||||
<strong>CAPTCHA タブで手動解決</strong>できる。ホストに <code>Xvfb</code> / <code>x11vnc</code> / <code>websockify</code> が必要。
|
||||
未インストールなら自動的に headless にフォールバックする。<code>skip</code>(既定)では CAPTCHA は手動解決されない。
|
||||
</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Max CAPTCHA Pages</FieldLabel>
|
||||
<FieldInput type="number" value={browser.maxCaptchaPages ?? 5}
|
||||
onChange={v => onChange('browser.maxCaptchaPages', Number(v))} />
|
||||
<HelpText>CAPTCHA Pool が同時に開けるページ数の上限(<code>novnc</code> モード時のみ有効)。デフォルト: 5</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FieldLabel>VNC Base Port</FieldLabel>
|
||||
<FieldInput type="number" value={browser.vncBasePort ?? 5900}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useEffect } from 'react';
|
||||
import { THEME_CHANGE_EVENT } from '../lib/theme';
|
||||
|
||||
export interface Branding {
|
||||
appName: string;
|
||||
@@ -115,9 +116,18 @@ function applyBrandColors(primary: string): void {
|
||||
const { h, s, l } = rgbToHsl(rgb);
|
||||
// Hover: 12% darker, clamp
|
||||
const deepL = Math.max(0.05, l - 0.12);
|
||||
// Soft background: very light but keep some hue. Lower saturation so it stays neutral-ish.
|
||||
const softL = Math.min(0.96, Math.max(0.92, 1 - l * 0.05));
|
||||
const softS = Math.min(s, 0.55);
|
||||
// Soft background (selected/active rows). Light tint in light mode; in dark
|
||||
// mode a DEEP brand tint. Lightness is kept low (~0.15) so BOTH near-white row
|
||||
// text (~12:1) AND brand-colored `text-accent` labels (~3.4:1, on par with the
|
||||
// light-mode pairing) stay legible. Saturation is never forced up, so a
|
||||
// neutral brand (white/black/gray → s≈0) yields a neutral gray tint, not red.
|
||||
// Dark softL=0.10 keeps brand `text-accent` on the soft bg at >= the light-mode
|
||||
// pairing (~3.9:1 for the default blue — that pattern is inherently sub-AA in
|
||||
// BOTH themes since a mid-bright brand color can't reach 4.5:1 on any visible
|
||||
// tint; this just ensures dark is not a regression). Near-white row titles ~15:1.
|
||||
const isDark = document.documentElement.dataset.theme === 'dark';
|
||||
const softL = isDark ? 0.1 : Math.min(0.96, Math.max(0.92, 1 - l * 0.05));
|
||||
const softS = isDark ? Math.min(s, 0.5) : Math.min(s, 0.55);
|
||||
// Luminance for contrast decision (BT.601).
|
||||
const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
|
||||
const fg = luminance > 0.65 ? '#0f172a' : '#ffffff';
|
||||
@@ -145,8 +155,17 @@ export function useBranding(): Branding {
|
||||
|
||||
useEffect(() => {
|
||||
document.title = branding.appName;
|
||||
applyBrandColors(branding.primaryColor);
|
||||
applyFavicon(branding.faviconUrl);
|
||||
const applyColors = () => applyBrandColors(branding.primaryColor);
|
||||
applyColors();
|
||||
// The soft tint is theme-dependent → re-derive when the theme changes.
|
||||
window.addEventListener(THEME_CHANGE_EVENT, applyColors);
|
||||
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
mq.addEventListener('change', applyColors);
|
||||
return () => {
|
||||
window.removeEventListener(THEME_CHANGE_EVENT, applyColors);
|
||||
mq.removeEventListener('change', applyColors);
|
||||
};
|
||||
}, [branding.appName, branding.primaryColor, branding.faviconUrl]);
|
||||
|
||||
return branding;
|
||||
|
||||
+14
-8
@@ -25,6 +25,9 @@
|
||||
/* Dark accent fallback (used only when /api/branding hasn't set
|
||||
--brand-primary*). Full runtime-branding + WCAG pairing is Phase 2. */
|
||||
--accent-on-dark: #fafafa; --accent-on-dark-fg: #18181b;
|
||||
/* Selected/active soft tint default (no-branding case). useBranding sets
|
||||
--brand-primary-soft inline when configured (theme-aware, see hook). */
|
||||
--brand-primary-soft: #f4f4f5;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
@@ -32,18 +35,21 @@
|
||||
/* Inverted neutral ramp (zinc-tuned). TUNE ON A REAL DISPLAY — dense UI
|
||||
borders rely on hairline; verify surface/surface-2/hairline separation
|
||||
and WCAG AA text contrast before shipping (spec §4.1 #6). */
|
||||
--slate-50: #0a0a0c; --slate-100: #131316; --slate-200: #202024;
|
||||
/* slate-400/500 lifted to clear WCAG AA on canvas (#0a0a0c): secondary
|
||||
text (timestamps, version, meta) was ~3:1 at #52525b — too dim. */
|
||||
--slate-300: #383840; --slate-400: #7a7a85; --slate-500: #9b9ba5;
|
||||
--slate-600: #a1a1aa; --slate-700: #c4c4cc; --slate-800: #dedee2;
|
||||
--slate-900: #f1f1f3; --slate-950: #fafafa;
|
||||
/* Dark backgrounds lifted a notch (was #0a0a0c/#16161a/#202024) for a
|
||||
softer, less pitch-black feel per user feedback. */
|
||||
--slate-50: #18181c; --slate-100: #202024; --slate-200: #2a2a30;
|
||||
/* slate-400/500 lifted to clear WCAG AA on the (now brighter) canvas. */
|
||||
--slate-300: #44444d; --slate-400: #8a8a95; --slate-500: #a6a6b0;
|
||||
--slate-600: #b4b4bd; --slate-700: #c8c8d0; --slate-800: #e0e0e4;
|
||||
--slate-900: #f2f2f4; --slate-950: #fafafa;
|
||||
--gray-400: #6b7280; --gray-500: #9ca3af; --gray-700: #d1d5db;
|
||||
--canvas: #0a0a0c; --surface: #16161a; --surface-2: #202024;
|
||||
--hairline: #2e2e34; --hairline-soft: #202024;
|
||||
--canvas: #18181c; --surface: #202024; --surface-2: #2a2a30;
|
||||
--hairline: #3a3a42; --hairline-soft: #2a2a30;
|
||||
--ink: #e7e7ea; --muted: #a1a1aa;
|
||||
--scrollbar-thumb: #3f3f46; --scrollbar-thumb-hover: #52525b;
|
||||
--accent-on-dark: #fafafa; --accent-on-dark-fg: #18181b;
|
||||
/* Dark default for the selected/active soft tint (no-branding case). */
|
||||
--brand-primary-soft: #2c2c34;
|
||||
}
|
||||
|
||||
/* When stored pref is 'system' the inline script sets data-theme already,
|
||||
|
||||
Reference in New Issue
Block a user