Skip to content

Commit 064ef7b

Browse files
committed
feat: add reset settings feature
1 parent 1336082 commit 064ef7b

File tree

3 files changed

+227
-7
lines changed

3 files changed

+227
-7
lines changed

src-tauri/src/lib.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ impl Default for AppSettings {
1717
fn default() -> Self {
1818
Self {
1919
indent_type: "space".to_string(),
20-
indent_width: 2,
21-
theme: "vs-dark".to_string(),
20+
indent_width: 4,
21+
theme: "".to_string(),
2222
font_size: 14,
2323
}
2424
}
@@ -104,6 +104,24 @@ async fn write_file(path: String, content: String) -> Result<(), String> {
104104
std::fs::write(&path, content).map_err(|e| format!("Failed to write file '{}': {}", path, e))
105105
}
106106

107+
#[tauri::command]
108+
async fn reset_app_data(app: tauri::AppHandle) -> Result<(), String> {
109+
let store = app
110+
.store_builder("app_data.json")
111+
.build()
112+
.map_err(|e| e.to_string())?;
113+
114+
let default_data = AppData::default();
115+
store.set(
116+
"app_data",
117+
serde_json::to_value(&default_data).map_err(|e| e.to_string())?,
118+
);
119+
120+
store.save().map_err(|e| e.to_string())?;
121+
122+
Ok(())
123+
}
124+
107125
#[cfg_attr(mobile, tauri::mobile_entry_point)]
108126
pub fn run() {
109127
tauri::Builder::default()
@@ -115,7 +133,8 @@ pub fn run() {
115133
save_app_data,
116134
load_app_data,
117135
read_file,
118-
write_file
136+
write_file,
137+
reset_app_data
119138
])
120139
.run(tauri::generate_context!())
121140
.expect("error while running tauri application");

src/App.css

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,3 +555,78 @@ body {
555555
border-color: #dc3545;
556556
color: #ffffff;
557557
}
558+
559+
.reset-settings-section {
560+
margin-top: var(--spacing-xl);
561+
margin-bottom: 0;
562+
border-top: 1px solid var(--color-border-primary);
563+
padding-top: var(--spacing-xl);
564+
}
565+
566+
.reset-confirmation {
567+
text-align: center;
568+
}
569+
570+
.reset-confirmation-text {
571+
margin-bottom: var(--spacing-lg);
572+
font-size: 0.875em;
573+
color: var(--color-text-secondary);
574+
line-height: 1.5;
575+
}
576+
577+
.reset-button-group {
578+
display: flex;
579+
gap: var(--spacing-md);
580+
justify-content: center;
581+
align-items: center;
582+
}
583+
584+
.reset-button {
585+
border: none;
586+
padding: var(--spacing-sm) var(--spacing-lg);
587+
border-radius: var(--spacing-sm);
588+
cursor: pointer;
589+
font-size: 0.875em;
590+
font-family: inherit;
591+
transition: all 0.2s ease;
592+
font-weight: 500;
593+
min-width: 120px;
594+
}
595+
596+
.reset-button-danger {
597+
background-color: #dc3545;
598+
color: white;
599+
}
600+
601+
.reset-button-danger:hover {
602+
background-color: #c82333;
603+
}
604+
605+
.reset-button-secondary {
606+
background-color: var(--color-background-tertiary);
607+
color: var(--color-text-secondary);
608+
border: 1px solid var(--color-border-secondary);
609+
}
610+
611+
.reset-button-secondary:hover {
612+
background-color: var(--color-button-hover-bg);
613+
border-color: var(--color-button-hover-border);
614+
}
615+
616+
.reset-button-full {
617+
width: 100%;
618+
padding: var(--spacing-md) var(--spacing-xl);
619+
margin-bottom: 0;
620+
}
621+
622+
.dark-theme .reset-button-danger {
623+
background-color: #e53e3e;
624+
}
625+
626+
.dark-theme .reset-button-danger:hover {
627+
background-color: #dc3545;
628+
}
629+
630+
.modal-settings-content > *:last-child {
631+
margin-bottom: 0;
632+
}

src/App.tsx

Lines changed: 130 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ interface ModalProps {
3939
theme: string;
4040
}
4141

42+
interface ConfirmModalProps {
43+
isOpen: boolean;
44+
onClose: () => void;
45+
onConfirm: () => void;
46+
theme: string;
47+
title: string;
48+
message: string;
49+
confirmText: string;
50+
cancelText: string;
51+
fontSize: number;
52+
}
53+
4254
const Modal: React.FC<ModalProps> = ({ isOpen, onClose, children, theme }) => {
4355
if (!isOpen) return null;
4456
const isDarkTheme = darkThemes.includes(theme);
@@ -61,6 +73,59 @@ const Modal: React.FC<ModalProps> = ({ isOpen, onClose, children, theme }) => {
6173
);
6274
};
6375

76+
const ConfirmModal: React.FC<ConfirmModalProps> = ({
77+
isOpen,
78+
onClose,
79+
onConfirm,
80+
theme,
81+
title,
82+
message,
83+
confirmText,
84+
cancelText,
85+
fontSize,
86+
}) => {
87+
if (!isOpen) return null;
88+
const isDarkTheme = darkThemes.includes(theme);
89+
90+
return (
91+
<div
92+
className={`modal-overlay ${isDarkTheme ? 'dark-theme' : ''}`}
93+
onClick={onClose}
94+
style={{ zIndex: 1100 }}>
95+
<div
96+
className={`modal-content ${isDarkTheme ? 'dark-theme' : ''}`}
97+
onClick={e => e.stopPropagation()}
98+
style={{ maxWidth: '25em' }}>
99+
<button
100+
className={`modal-close-button ${isDarkTheme ? 'dark-theme' : ''}`}
101+
onClick={onClose}>
102+
&times;
103+
</button>
104+
<div
105+
className="modal-settings-content"
106+
style={{ fontSize: `${fontSize}px` }}>
107+
<h2>{title}</h2>
108+
<div className="reset-confirmation">
109+
<p className="reset-confirmation-text">{message}</p>
110+
<div className="reset-button-group">
111+
<button
112+
onClick={onConfirm}
113+
className="reset-button reset-button-danger">
114+
{confirmText}
115+
</button>
116+
<button
117+
onClick={onClose}
118+
className="reset-button reset-button-secondary">
119+
{cancelText}
120+
</button>
121+
</div>
122+
</div>
123+
</div>
124+
</div>
125+
</div>
126+
);
127+
};
128+
64129
function App() {
65130
const [formattedString, setFormattedString] = useState('');
66131
const [isError, setIsError] = useState(false);
@@ -74,15 +139,31 @@ function App() {
74139
const [isCopied, setIsCopied] = useState(false);
75140
const [canUndo, setCanUndo] = useState(false);
76141
const [canRedo, setCanRedo] = useState(false);
142+
const [isResetConfirmOpen, setIsResetConfirmOpen] = useState(false);
77143
const editorRef = useRef<any>(null);
78144

145+
const getSystemTheme = () => {
146+
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
147+
return 'vs-dark';
148+
}
149+
return 'vs-light';
150+
};
151+
79152
useEffect(() => {
80153
const loadData = async () => {
81154
try {
82155
const appData = (await invoke('load_app_data')) as AppData;
83156

84157
setFontSize(appData.settings.font_size);
85-
setTheme(appData.settings.theme);
158+
159+
const savedTheme = appData.settings.theme;
160+
if (savedTheme && savedTheme !== '') {
161+
setTheme(savedTheme);
162+
} else {
163+
const systemTheme = getSystemTheme();
164+
setTheme(systemTheme);
165+
}
166+
86167
setIndentType(appData.settings.indent_type as 'space' | 'tab');
87168
setIndentWidth(appData.settings.indent_width);
88169

@@ -96,6 +177,8 @@ function App() {
96177
}
97178
} catch (error) {
98179
console.error('Failed to load data:', error);
180+
const systemTheme = getSystemTheme();
181+
setTheme(systemTheme);
99182
}
100183
};
101184

@@ -187,6 +270,27 @@ function App() {
187270

188271
const openAboutModal = () => setIsAboutModalOpen(true);
189272
const closeAboutModal = () => setIsAboutModalOpen(false);
273+
const handleResetSettings = async () => {
274+
try {
275+
await invoke('reset_app_data');
276+
const systemTheme = getSystemTheme();
277+
278+
setFontSize(14);
279+
setTheme(systemTheme);
280+
setIndentType('space');
281+
setIndentWidth(4);
282+
setIsError(false);
283+
284+
if (inputString.trim() !== '') {
285+
formatString(inputString, { indentType: 'space', indentWidth: 4 });
286+
}
287+
288+
setIsResetConfirmOpen(false);
289+
closeModal();
290+
} catch (error) {
291+
console.error('Failed to reset settings:', error);
292+
}
293+
};
190294

191295
const handleCopy = async () => {
192296
try {
@@ -299,7 +403,9 @@ function App() {
299403
useEffect(() => {
300404
const handleEsc = (event: KeyboardEvent) => {
301405
if (event.key === 'Escape') {
302-
if (isAboutModalOpen) {
406+
if (isResetConfirmOpen) {
407+
setIsResetConfirmOpen(false);
408+
} else if (isAboutModalOpen) {
303409
closeAboutModal();
304410
} else if (isModalOpen) {
305411
closeModal();
@@ -310,7 +416,7 @@ function App() {
310416
return () => {
311417
window.removeEventListener('keydown', handleEsc);
312418
};
313-
}, [isModalOpen, isAboutModalOpen]);
419+
}, [isModalOpen, isAboutModalOpen, isResetConfirmOpen]);
314420

315421
const isDarkTheme = darkThemes.includes(theme);
316422

@@ -581,7 +687,7 @@ function App() {
581687
<div
582688
className="modal-settings-content"
583689
style={{ fontSize: `${fontSize}px` }}>
584-
<h2>Editor Settings</h2>
690+
<h2>Settings</h2>
585691
<div className="setting-item">
586692
<label htmlFor="font-size-select">Font Size</label>
587693
<select
@@ -636,8 +742,28 @@ function App() {
636742
</select>
637743
</div>
638744
)}
745+
746+
<div className="reset-settings-section">
747+
<button
748+
onClick={() => setIsResetConfirmOpen(true)}
749+
className="reset-button reset-button-danger reset-button-full">
750+
Reset All Settings
751+
</button>
752+
</div>
639753
</div>
640754
</Modal>
755+
756+
<ConfirmModal
757+
isOpen={isResetConfirmOpen}
758+
onClose={() => setIsResetConfirmOpen(false)}
759+
onConfirm={handleResetSettings}
760+
theme={theme}
761+
title="Reset Settings"
762+
message="This will reset font size, theme, and formatting settings to defaults."
763+
confirmText="Yes, Reset Settings"
764+
cancelText="Cancel"
765+
fontSize={fontSize}
766+
/>
641767
</main>
642768
);
643769
}

0 commit comments

Comments
 (0)