diff --git a/src/renderer/components/modals/SettingsSheet.tsx b/src/renderer/components/modals/SettingsSheet.tsx
new file mode 100644
index 0000000..6d2f436
--- /dev/null
+++ b/src/renderer/components/modals/SettingsSheet.tsx
@@ -0,0 +1,45 @@
+import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/components/ui/sheet';
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
+import { Button } from '@/components/ui/button';
+import { useAppStore } from '@/stores/app-store';
+import { useSettingsStore } from '@/stores/settings-store';
+import { EditorSettings } from './EditorSettings';
+import { ThemeSettings } from './ThemeSettings';
+import { ExportSettings } from './ExportSettings';
+import { PluginsSettings } from './PluginsSettings';
+import { AboutSettings } from './AboutSettings';
+
+export function SettingsSheet() {
+ const closeModal = useAppStore((s) => s.closeModal);
+ const resetToDefaults = useSettingsStore((s) => s.resetToDefaults);
+
+ return (
+ !o && closeModal()}>
+
+
+ Settings
+ Editor, theme, and export preferences
+
+
+
+ Editor
+ Theme
+ Export
+ Plugins
+ About
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/tests/component/modals/SettingsSheet.test.tsx b/tests/component/modals/SettingsSheet.test.tsx
new file mode 100644
index 0000000..3c24324
--- /dev/null
+++ b/tests/component/modals/SettingsSheet.test.tsx
@@ -0,0 +1,58 @@
+import { describe, it, expect, beforeEach } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { SettingsSheet } from '@/components/modals/SettingsSheet';
+import { useSettingsStore } from '@/stores/settings-store';
+
+describe('SettingsSheet', () => {
+ beforeEach(() => {
+ localStorage.clear();
+ useSettingsStore.setState(useSettingsStore.getInitialState());
+ });
+
+ it('renders 5 tab triggers', () => {
+ render();
+ expect(screen.getByRole('tab', { name: /editor/i })).toBeInTheDocument();
+ expect(screen.getByRole('tab', { name: /theme/i })).toBeInTheDocument();
+ expect(screen.getByRole('tab', { name: /export/i })).toBeInTheDocument();
+ expect(screen.getByRole('tab', { name: /plugins/i })).toBeInTheDocument();
+ expect(screen.getByRole('tab', { name: /about/i })).toBeInTheDocument();
+ });
+
+ it('editor tab is open by default and shows font size', () => {
+ render();
+ expect(screen.getByText(/font size/i)).toBeInTheDocument();
+ });
+
+ it('theme tab shows theme radio group', async () => {
+ render();
+ await userEvent.click(screen.getByRole('tab', { name: /theme/i }));
+ expect(screen.getByText(/accent color/i)).toBeInTheDocument();
+ });
+
+ it('export tab shows ascii toggle and template picker', async () => {
+ render();
+ await userEvent.click(screen.getByRole('tab', { name: /export/i }));
+ expect(screen.getByText(/render tables as ascii by default/i)).toBeInTheDocument();
+ expect(screen.getByText(/default docx template/i)).toBeInTheDocument();
+ });
+
+ it('plugins tab shows coming soon message', async () => {
+ render();
+ await userEvent.click(screen.getByRole('tab', { name: /plugins/i }));
+ expect(screen.getByText(/coming soon/i)).toBeInTheDocument();
+ });
+
+ it('about tab shows version', async () => {
+ render();
+ await userEvent.click(screen.getByRole('tab', { name: /about/i }));
+ expect(screen.getByText(/markdownconverter/i)).toBeInTheDocument();
+ });
+
+ it('reset to defaults button clears all settings', async () => {
+ useSettingsStore.getState().setSetting('fontSize', 22);
+ render();
+ await userEvent.click(screen.getByRole('button', { name: /reset/i }));
+ expect(useSettingsStore.getState().fontSize).toBe(14);
+ });
+});
\ No newline at end of file