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 = () => ( - <> - - + + + + + + ); // Handlers for post categories management @@ -323,11 +345,12 @@ export const SettingsView: React.FC = () => { }; const renderContentSettings = () => ( - <> - +
); };