feat: redesign settings pages to match canonical flat UI patterns (#493)
* refactor(settings): new IA shell + projects section + skills catalog discoverability * chore(settings): split providers list by scope; show user before project * fix: navigation flow in mobile Settings * feat: redesign settings pages to use modern elevated surface patterns * feat: replace helper text with tooltips in settings * ui: redesign update dialog and fix external link routing - Restructures UpdateDialog to focus on changelog readability with a wider max-w-4xl canvas - Highlights @username contributor mentions with theme primary color - Strips excessive vertical padding and right-aligns compact action buttons - Disables streamdown's internal link safety dialog in favor of direct Tauri shell routing * feat: refactor Git identities into dedicated Git settings page * feat: unify sidebar background styling across VS Code and web/mobile * fix: adjust button styling and layout for mobile settings pages * feat: add MCP settings page and sidebar * feat: hide models in provider view (thanks to @nguyenngothuong) * feat: add "Add new provider" option to model selector dropdown * fix: local evroc logo + provider dropdown icons * fix: increase width of provider menu * fix: dark theme background color for better contrast * feat: update @opencode-ai/sdk dependency to v1.2.10 * fix: restore session sorting to only use updated time * fix: added settings for sessions deletion dialog * fix: adjust padding on settings pages for better layout * fix: standardize select dropdown height across UI * fix: agent selector UI and notification settings * fix: remove redundant helper text from settings pages * fix: update UI layout for description fields * fix: remove border-none and shadow-none from textarea classes * fix: enable context menu on sidebar items * feat: refactor UI controls and layout patterns across settings pages * fix: use headerless blocks when page title already provides context * fix: remove subtask option from command settings * fix: refactor mcp page settings * fix: reduce spacing in skills configuration pages * feat: refactor voice settings * feat: refactor settings sidebar sections
This commit is contained in:
committed by
GitHub
parent
d2d39c48ac
commit
d2358c2c03
@@ -733,10 +733,11 @@ export const SimpleMarkdownRenderer: React.FC<{
|
||||
content: string;
|
||||
className?: string;
|
||||
variant?: MarkdownVariant;
|
||||
disableLinkSafety?: boolean;
|
||||
onShowPopup?: (content: ToolPopupContent) => void;
|
||||
mermaidControls?: MermaidControlOptions;
|
||||
allowMermaidWheelZoom?: boolean;
|
||||
}> = ({ content, className, variant = 'assistant', onShowPopup, mermaidControls, allowMermaidWheelZoom = false }) => {
|
||||
}> = ({ content, className, variant = 'assistant', disableLinkSafety, onShowPopup, mermaidControls, allowMermaidWheelZoom = false }) => {
|
||||
const streamdownContainerRef = React.useRef<HTMLDivElement>(null);
|
||||
const mermaidBlocks = React.useMemo(() => extractMermaidBlocks(content), [content]);
|
||||
useMermaidInlineInteractions({
|
||||
@@ -767,6 +768,8 @@ export const SimpleMarkdownRenderer: React.FC<{
|
||||
plugins={streamdownPlugins}
|
||||
mermaid={mermaidOptions}
|
||||
components={streamdownComponents}
|
||||
// @ts-expect-error Streamdown type missing linkSafety in older minor
|
||||
linkSafety={disableLinkSafety ? { enabled: false } : undefined}
|
||||
>
|
||||
{content}
|
||||
</Streamdown>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import type { ComponentType } from 'react';
|
||||
import {
|
||||
RiAddLine,
|
||||
RiAiAgentLine,
|
||||
RiArrowDownSLine,
|
||||
RiArrowGoBackLine,
|
||||
@@ -187,6 +188,8 @@ const CURRENCY_FORMATTER = new Intl.NumberFormat('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
});
|
||||
|
||||
const ADD_PROVIDER_ID = '__add_provider__';
|
||||
|
||||
const formatTokens = (value?: number | null) => {
|
||||
if (typeof value !== 'number' || Number.isNaN(value)) {
|
||||
return '—';
|
||||
@@ -297,6 +300,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
settingsDefaultVariant,
|
||||
settingsDefaultAgent,
|
||||
setProvider,
|
||||
setSelectedProvider,
|
||||
setModel,
|
||||
setCurrentVariant,
|
||||
getCurrentModelVariants,
|
||||
@@ -362,7 +366,10 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
addRecentEffort,
|
||||
isModelSelectorOpen,
|
||||
setModelSelectorOpen,
|
||||
setSettingsDialogOpen,
|
||||
setSettingsPage,
|
||||
} = useUIStore();
|
||||
const hiddenModels = useUIStore((state) => state.hiddenModels);
|
||||
|
||||
// Separate state for agent selector to avoid conflict with model selector
|
||||
const [isAgentSelectorOpen, setIsAgentSelectorOpen] = React.useState(false);
|
||||
@@ -393,6 +400,13 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
// Use global state for model selector (allows Ctrl+M shortcut)
|
||||
const agentMenuOpen = isModelSelectorOpen;
|
||||
const setAgentMenuOpen = setModelSelectorOpen;
|
||||
const openAddProviderSettings = React.useCallback(() => {
|
||||
setSelectedProvider(ADD_PROVIDER_ID);
|
||||
setSettingsPage('providers');
|
||||
setSettingsDialogOpen(true);
|
||||
setAgentMenuOpen(false);
|
||||
closeMobilePanel();
|
||||
}, [setSelectedProvider, setSettingsPage, setSettingsDialogOpen, setAgentMenuOpen, closeMobilePanel]);
|
||||
const [desktopModelQuery, setDesktopModelQuery] = React.useState('');
|
||||
const [modelSelectedIndex, setModelSelectedIndex] = React.useState(0);
|
||||
const modelItemRefs = React.useRef<(HTMLDivElement | null)[]>([]);
|
||||
@@ -535,6 +549,21 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
const currentProvider = getCurrentProvider();
|
||||
const models = Array.isArray(currentProvider?.models) ? currentProvider.models : [];
|
||||
|
||||
const visibleProviders = React.useMemo(() => {
|
||||
return providers
|
||||
.map((provider) => {
|
||||
const providerModels = Array.isArray(provider.models) ? provider.models : [];
|
||||
const visibleModels = providerModels.filter((model: ProviderModel) => {
|
||||
const modelId = typeof model?.id === 'string' ? model.id : '';
|
||||
return !hiddenModels.some(
|
||||
(item) => item.providerID === String(provider.id) && item.modelID === modelId
|
||||
);
|
||||
});
|
||||
return { ...provider, models: visibleModels };
|
||||
})
|
||||
.filter((provider) => provider.models.length > 0);
|
||||
}, [providers, hiddenModels]);
|
||||
|
||||
const currentMetadata =
|
||||
currentProviderId && currentModelId ? getModelMetadata(currentProviderId, currentModelId) : undefined;
|
||||
const currentCapabilityIcons = getCapabilityIcons(currentMetadata);
|
||||
@@ -1439,7 +1468,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
if (!isCompact) return null;
|
||||
|
||||
const normalizedQuery = mobileModelQuery.trim();
|
||||
const filteredProviders = providers
|
||||
const filteredProviders = visibleProviders
|
||||
.map((provider) => {
|
||||
const providerModels = Array.isArray(provider.models) ? provider.models : [];
|
||||
const matchesProvider = normalizedQuery.length === 0
|
||||
@@ -2092,7 +2121,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
});
|
||||
|
||||
// Filter providers and their models
|
||||
const filteredProviders = providers
|
||||
const filteredProviders = visibleProviders
|
||||
.map((provider) => {
|
||||
const providerModels = Array.isArray(provider.models) ? provider.models : [];
|
||||
const filteredModels = providerModels.filter((model: ProviderModel) => {
|
||||
@@ -2218,6 +2247,26 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
{/* Scrollable content */}
|
||||
<ScrollableOverlay outerClassName="max-h-[min(400px,calc(100dvh-12rem))] flex-1">
|
||||
<div className="p-1">
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={openAddProviderSettings}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
openAddProviderSettings();
|
||||
}
|
||||
}}
|
||||
className="typography-meta group flex items-center gap-1 rounded-md px-2 py-1.5 cursor-pointer hover:bg-interactive-hover/50"
|
||||
>
|
||||
<span className="flex h-4 w-4 items-center justify-center text-muted-foreground">
|
||||
<RiAddLine className="h-4 w-4 -mr-0.5" />
|
||||
</span>
|
||||
<span className="font-medium text-foreground">Add new provider</span>
|
||||
</div>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
{!hasResults && (
|
||||
<div className="px-2 py-4 text-center typography-meta text-muted-foreground">
|
||||
No models found
|
||||
|
||||
Reference in New Issue
Block a user