diff --git a/src/renderer/components/SettingsView/SettingsView.css b/src/renderer/components/SettingsView/SettingsView.css
index e6ae3e4..9bc43c7 100644
--- a/src/renderer/components/SettingsView/SettingsView.css
+++ b/src/renderer/components/SettingsView/SettingsView.css
@@ -79,69 +79,43 @@
opacity: 1;
}
-/* Body layout */
-.settings-body {
- display: flex;
- flex: 1;
- overflow: hidden;
-}
-
-/* Category navigation */
-.settings-nav {
- display: flex;
- flex-direction: column;
- width: 180px;
- min-width: 180px;
- padding: 12px 0;
- border-right: 1px solid var(--vscode-panel-border);
- overflow-y: auto;
-}
-
-.settings-nav-item {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 8px 16px;
- background: transparent;
- border: none;
- border-left: 2px solid transparent;
- color: var(--vscode-foreground);
- font-size: 13px;
- cursor: pointer;
- text-align: left;
- transition: background-color 0.1s;
-}
-
-.settings-nav-item:hover {
- background-color: var(--vscode-list-hoverBackground);
-}
-
-.settings-nav-item.active {
- background-color: var(--vscode-list-activeSelectionBackground);
- border-left-color: var(--vscode-focusBorder);
- font-weight: 500;
-}
-
-.settings-nav-icon {
- font-size: 16px;
- width: 20px;
- text-align: center;
- flex-shrink: 0;
-}
-
-.settings-nav-label {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-/* Settings content area */
+/* Body layout - simplified, no internal sidebar */
.settings-content {
flex: 1;
overflow-y: auto;
padding: 16px 24px 40px;
}
+/* No results message */
+.settings-no-results {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 16px;
+ padding: 48px 24px;
+ color: var(--vscode-descriptionForeground);
+}
+
+.settings-no-results p {
+ margin: 0;
+ font-size: 14px;
+}
+
+.settings-no-results button {
+ padding: 6px 14px;
+ font-size: 12px;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ background-color: var(--vscode-button-secondaryBackground);
+ color: var(--vscode-button-secondaryForeground);
+}
+
+.settings-no-results button:hover {
+ background-color: var(--vscode-button-secondaryHoverBackground);
+}
+
/* Setting section */
.setting-section {
margin-bottom: 32px;
@@ -431,23 +405,4 @@
color: var(--vscode-input-placeholderForeground);
}
-/* Responsive - narrow sidebar */
-@media (max-width: 600px) {
- .settings-nav {
- width: 48px;
- min-width: 48px;
- }
- .settings-nav-label {
- display: none;
- }
-
- .settings-nav-item {
- justify-content: center;
- padding: 10px;
- }
-
- .settings-nav-icon {
- width: auto;
- }
-}
diff --git a/src/renderer/components/SettingsView/SettingsView.tsx b/src/renderer/components/SettingsView/SettingsView.tsx
index 5e34461..f3ce90b 100644
--- a/src/renderer/components/SettingsView/SettingsView.tsx
+++ b/src/renderer/components/SettingsView/SettingsView.tsx
@@ -1,10 +1,20 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useRef, useCallback } from 'react';
import { useAppStore } from '../../store';
import { showToast } from '../Toast';
import './SettingsView.css';
-// Settings categories matching VS Code style
-type SettingsCategory = 'editor' | 'content' | 'sync' | 'publishing' | 'data';
+// Export category IDs for sidebar navigation
+export type SettingsCategory = 'editor' | 'content' | 'sync' | 'publishing' | 'data';
+
+// Scroll to a settings section by category ID
+export const scrollToSettingsSection = (category: SettingsCategory) => {
+ const element = document.getElementById(`settings-section-${category}`);
+ if (element) {
+ element.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ }
+};
+
+// Settings categories
interface Credentials {
// Turso Cloud Sync
@@ -48,15 +58,6 @@ const SearchIcon = () => (
// Default post categories based on VISION.md
const DEFAULT_POST_CATEGORIES = ['article', 'picture', 'aside', 'page'];
-// Category definitions
-const categories: { id: SettingsCategory; label: string; icon: string }[] = [
- { id: 'editor', label: 'Editor', icon: '📝' },
- { id: 'content', label: 'Content', icon: '📋' },
- { id: 'sync', label: 'Sync', icon: '🔄' },
- { id: 'publishing', label: 'Publishing', icon: '🚀' },
- { id: 'data', label: 'Data Management', icon: '🗄️' },
-];
-
// Individual setting row component (VS Code style)
const SettingRow: React.FC<{
id: string;
@@ -75,36 +76,55 @@ const SettingRow: React.FC<{
);
-// Section header component
+// Section header component with optional ID for scrolling
const SettingSection: React.FC<{
+ id?: string;
title: string;
description?: string;
children: React.ReactNode;
-}> = ({ title, description, children }) => (
-
-
-
{title}
- {description &&
{description}
}
+ hidden?: boolean;
+}> = ({ id, title, description, children, hidden }) => {
+ if (hidden) return null;
+ return (
+
+
+
{title}
+ {description &&
{description}
}
+
+
+ {children}
+
-
- {children}
-
-
-);
+ );
+};
export const SettingsView: React.FC = () => {
const { preferredEditorMode, setPreferredEditorMode, syncConfigured } = useAppStore();
- const [activeCategory, setActiveCategory] = useState
('editor');
const [searchQuery, setSearchQuery] = useState('');
const [credentials, setCredentials] = useState(defaultCredentials);
const [showSecrets, setShowSecrets] = useState(false);
const [dropboxConfigured, setDropboxConfigured] = useState(false);
const [dropboxLastSync, setDropboxLastSync] = useState(null);
+ const contentRef = useRef(null);
// Post categories management
const [postCategories, setPostCategories] = useState(DEFAULT_POST_CATEGORIES);
const [newCategoryInput, setNewCategoryInput] = useState('');
+ // Check if a setting matches the search query
+ const matchesSearch = useCallback((text: string) => {
+ if (!searchQuery) return true;
+ return text.toLowerCase().includes(searchQuery.toLowerCase());
+ }, [searchQuery]);
+
+ // Check if a section has any matching settings
+ const sectionHasMatches = useCallback((sectionKeywords: string[]) => {
+ if (!searchQuery) return true;
+ return sectionKeywords.some(keyword =>
+ keyword.toLowerCase().includes(searchQuery.toLowerCase())
+ );
+ }, [searchQuery]);
+
// Load saved credentials and categories
useEffect(() => {
const loadSettings = async () => {
@@ -261,34 +281,36 @@ export const SettingsView: React.FC = () => {
}
};
- // Filter categories if searching
- const filteredCategories = searchQuery
- ? categories.filter(c => c.label.toLowerCase().includes(searchQuery.toLowerCase()))
- : categories;
+ // Keywords for each section for search filtering
+ const editorKeywords = ['editor', 'mode', 'wysiwyg', 'markdown', 'preview', 'visual'];
+ const contentKeywords = ['content', 'categories', 'post', 'article', 'picture', 'aside', 'page'];
+ const syncKeywords = ['sync', 'turso', 'libsql', 'cloud', 'database', 'dropbox', 'file', 'backup', 'token', 'remote'];
+ const publishingKeywords = ['publishing', 'ftp', 'ssh', 'deploy', 'server', 'host', 'upload'];
+ const dataKeywords = ['data', 'database', 'rebuild', 'maintenance', 'posts', 'media', 'links', 'folder', 'filesystem'];
const renderEditorSettings = () => (
- <>
-
+
- setPreferredEditorMode(e.target.value as 'wysiwyg' | 'markdown' | 'preview')}
>
-
-
-
- >
+
+
+
+
+
+
);
// Handlers for post categories management
@@ -323,11 +345,12 @@ export const SettingsView: React.FC = () => {
};
const renderContentSettings = () => (
- <>
-
+
{postCategories.map((cat) => (
@@ -366,15 +389,16 @@ export const SettingsView: React.FC = () => {
Reset to Defaults
-
- >
+
);
const renderSyncSettings = () => (
<>
{
{
const renderPublishingSettings = () => (
<>
{
{
const renderDataSettings = () => (
<>
{
{
>
);
- const renderContent = () => {
- if (searchQuery) {
- // Show all matching settings when searching
- return (
- <>
- {renderEditorSettings()}
- {renderContentSettings()}
- {renderSyncSettings()}
- {renderPublishingSettings()}
- {renderDataSettings()}
- >
- );
- }
-
- switch (activeCategory) {
- case 'editor':
- return renderEditorSettings();
- case 'content':
- return renderContentSettings();
- case 'sync':
- return renderSyncSettings();
- case 'publishing':
- return renderPublishingSettings();
- case 'data':
- return renderDataSettings();
- default:
- return renderEditorSettings();
- }
- };
+ // Check if any results match the search
+ const hasAnyMatches = !searchQuery ||
+ sectionHasMatches(editorKeywords) ||
+ sectionHasMatches(contentKeywords) ||
+ sectionHasMatches(syncKeywords) ||
+ sectionHasMatches(publishingKeywords) ||
+ sectionHasMatches(dataKeywords);
return (
@@ -791,28 +800,22 @@ export const SettingsView: React.FC = () => {
-
- {/* Category navigation sidebar */}
-
-
- {/* Settings content */}
-
- {renderContent()}
-
+ {/* Settings content - all sections in scrollable list */}
+
+ {hasAnyMatches ? (
+ <>
+ {renderEditorSettings()}
+ {renderContentSettings()}
+ {renderSyncSettings()}
+ {renderPublishingSettings()}
+ {renderDataSettings()}
+ >
+ ) : (
+
+
No settings found matching "{searchQuery}"
+
+
+ )}
);
diff --git a/src/renderer/components/SettingsView/index.ts b/src/renderer/components/SettingsView/index.ts
index 686c3d8..6b25c6e 100644
--- a/src/renderer/components/SettingsView/index.ts
+++ b/src/renderer/components/SettingsView/index.ts
@@ -1 +1,2 @@
-export { SettingsView } from './SettingsView';
+export { SettingsView, scrollToSettingsSection } from './SettingsView';
+export type { SettingsCategory } from './SettingsView';
diff --git a/src/renderer/components/Sidebar/Sidebar.css b/src/renderer/components/Sidebar/Sidebar.css
index 3c8321f..71b8e87 100644
--- a/src/renderer/components/Sidebar/Sidebar.css
+++ b/src/renderer/components/Sidebar/Sidebar.css
@@ -216,6 +216,21 @@
font-size: 12px;
color: var(--vscode-sideBar-foreground);
border-radius: 3px;
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ text-align: left;
+ width: 100%;
+ transition: background-color 0.1s;
+}
+
+.settings-nav-entry:hover {
+ background-color: var(--vscode-list-hoverBackground);
+}
+
+.settings-nav-entry.active {
+ background-color: var(--vscode-list-activeSelectionBackground);
+ color: var(--vscode-list-activeSelectionForeground);
}
.settings-nav-entry-icon {
diff --git a/src/renderer/components/Sidebar/Sidebar.tsx b/src/renderer/components/Sidebar/Sidebar.tsx
index f751209..bb5edbe 100644
--- a/src/renderer/components/Sidebar/Sidebar.tsx
+++ b/src/renderer/components/Sidebar/Sidebar.tsx
@@ -578,8 +578,16 @@ const MediaList: React.FC = () => {
);
};
+import { scrollToSettingsSection, SettingsCategory } from '../SettingsView/SettingsView';
+
const SettingsNav: React.FC = () => {
const { syncConfigured } = useAppStore();
+ const [activeSection, setActiveSection] = useState(null);
+
+ const handleNavClick = (category: SettingsCategory) => {
+ setActiveSection(category);
+ scrollToSettingsSection(category);
+ };
return (
@@ -590,26 +598,43 @@ const SettingsNav: React.FC = () => {
-
+
-
+
+
+
-
+
+
-
+
+
+
-
- Configure settings in the main editor area.
);
};