Skip to content

Commit edab3f3

Browse files
andrewboldiclaude
andcommitted
refactor: consolidate settings into single-page grid layout
Replace 3-tab settings modal (Options/Colors/Customization) with a single page showing all settings in a 3-column grid. Removes tab navigation and 3 tab component files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2f87090 commit edab3f3

4 files changed

Lines changed: 167 additions & 211 deletions

File tree

Lines changed: 167 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
<script lang="ts">
2-
import SettingsTabOptions from './SettingsTabOptions.svelte';
3-
import SettingsTabColors from './SettingsTabColors.svelte';
4-
import SettingsTabCustomization from './SettingsTabCustomization.svelte';
52
import { settings } from '$lib/stores/settings';
3+
import type { ExamLevel, Subject, TextColor, LogoColor, ToggleOption } from '$lib/types';
64
75
interface Props {
86
onClose: () => void;
97
}
108
119
let { onClose }: Props = $props();
1210
13-
type Tab = 'Options' | 'Colors' | 'Customization';
14-
let activeTab = $state<Tab>('Options');
15-
16-
const tabs: Tab[] = ['Options', 'Colors', 'Customization'];
11+
const FONTS = [
12+
'Poppins', 'Arial', 'Arial Black', 'Verdana', 'Tahoma', 'Trebuchet MS',
13+
'Impact', 'Times New Roman', 'Didot', 'Georgia', 'American Typewriter',
14+
'Andale Mono', 'Courier', 'Lucida Console', 'Monaco', 'Bradley Hand',
15+
'Brush Script MT', 'Luminari', 'Comic Sans MS', 'Roboto'
16+
];
1717
1818
function handleBackdrop(e: MouseEvent) {
1919
if (e.target === e.currentTarget) onClose();
@@ -23,7 +23,7 @@
2323
<!-- svelte-ignore a11y_click_events_have_key_events -->
2424
<!-- svelte-ignore a11y_no_static_element_interactions -->
2525
<div class="modal" style="display: block; position: fixed; z-index: 15;" onclick={handleBackdrop}>
26-
<main class="modalContent animateZoom">
26+
<div class="modalContent animateZoom settings-single">
2727
<span
2828
onclick={onClose}
2929
style="position: absolute; right: 0; top: 0; border-top-right-radius: 12px; border-bottom-left-radius: 12px; font-size: 36px; z-index: 1;"
@@ -33,42 +33,171 @@
3333
&times;
3434
</span>
3535

36-
<div class="settings-navigation">
37-
<div class="logo">
38-
<img class="logoIcon" src="/img/icon.png" alt="AMC Trainer" style="width: 80px; height: 80px; margin-left: 2.5rem; margin-top: 1rem;" />
39-
<h5>AMC Trainer Settings</h5>
36+
<div class="settings-header">
37+
<img class="logoIcon" src="/img/icon.png" alt="AMC Trainer" style="width: 50px; height: 50px;" />
38+
<h3 style="margin: 0;">AMC Trainer Settings</h3>
39+
</div>
40+
41+
<div class="settings-grid">
42+
<!-- Options -->
43+
<div class="settings-section">
44+
<h2>Level</h2>
45+
<select class="ddl button" value={$settings.level}
46+
onchange={(e) => settings.update(s => ({ ...s, level: (e.target as HTMLSelectElement).value as ExamLevel }))}>
47+
<option value="AMC_8">AMC 8</option>
48+
<option value="AMC_10">AMC 10</option>
49+
<option value="AMC_12">AMC 12</option>
50+
<option value="AIME">AIME</option>
51+
<option value="All">All</option>
52+
</select>
53+
</div>
54+
55+
<div class="settings-section">
56+
<h2>Subject</h2>
57+
<select class="ddl button" value={$settings.subject ?? ''}
58+
onchange={(e) => { const val = (e.target as HTMLSelectElement).value; settings.update(s => ({ ...s, subject: val === '' ? null : val as Subject })); }}>
59+
<option value="">All Subjects</option>
60+
<option value="algebra">Algebra</option>
61+
<option value="geometry">Geometry</option>
62+
<option value="combinatorics">Combinatorics</option>
63+
<option value="number_theory">Number Theory</option>
64+
</select>
65+
</div>
66+
67+
<div class="settings-section">
68+
<h2>Difficulty</h2>
69+
<div style="display: flex; align-items: center; gap: 0.5rem;">
70+
<select class="ddl button" style="width: 70px;" value={$settings.difficultyMin}
71+
onchange={(e) => { const val = parseInt((e.target as HTMLSelectElement).value, 10); settings.update(s => ({ ...s, difficultyMin: val, difficultyMax: Math.max(val, s.difficultyMax) })); }}>
72+
{#each Array.from({length: 10}, (_, i) => i + 1) as n}
73+
<option value={n}>{n}</option>
74+
{/each}
75+
</select>
76+
<span style="font-weight: 600;">to</span>
77+
<select class="ddl button" style="width: 70px;" value={$settings.difficultyMax}
78+
onchange={(e) => { const val = parseInt((e.target as HTMLSelectElement).value, 10); settings.update(s => ({ ...s, difficultyMax: val, difficultyMin: Math.min(val, s.difficultyMin) })); }}>
79+
{#each Array.from({length: 10}, (_, i) => i + 1) as n}
80+
<option value={n}>{n}</option>
81+
{/each}
82+
</select>
83+
</div>
84+
</div>
85+
86+
<!-- Colors -->
87+
<div class="settings-section">
88+
<h2>Text Color</h2>
89+
<select class="ddl button" value={$settings.textColor}
90+
onchange={(e) => settings.update(s => ({ ...s, textColor: (e.target as HTMLSelectElement).value as TextColor }))}>
91+
<option value="black">Black</option>
92+
<option value="white">White</option>
93+
</select>
94+
</div>
95+
96+
<div class="settings-section">
97+
<h2>Background</h2>
98+
<div style="display: flex; gap: 0.5rem;">
99+
<input class="button ddl" type="color" value={$settings.bgColor1}
100+
oninput={(e) => settings.update(s => ({ ...s, bgColor1: (e.target as HTMLInputElement).value }))} />
101+
<input class="button ddl" type="color" value={$settings.bgColor2}
102+
oninput={(e) => settings.update(s => ({ ...s, bgColor2: (e.target as HTMLInputElement).value }))} />
103+
</div>
104+
</div>
105+
106+
<div class="settings-section">
107+
<h2>Logo Color</h2>
108+
<select class="ddl button" value={$settings.logoColor}
109+
onchange={(e) => settings.update(s => ({ ...s, logoColor: (e.target as HTMLSelectElement).value as LogoColor }))}>
110+
<option value="red">Red</option>
111+
<option value="orange">Orange</option>
112+
<option value="yellow">Yellow</option>
113+
<option value="green">Green</option>
114+
<option value="blue">Blue</option>
115+
<option value="purple">Purple</option>
116+
<option value="white">White</option>
117+
<option value="black">Black</option>
118+
</select>
119+
</div>
120+
121+
<!-- Customization -->
122+
<div class="settings-section">
123+
<h2>Zen Mode</h2>
124+
<select class="ddl button" value={$settings.zenMode}
125+
onchange={(e) => settings.update(s => ({ ...s, zenMode: (e.target as HTMLSelectElement).value as ToggleOption }))}>
126+
<option value="Off">Off</option>
127+
<option value="On">On</option>
128+
</select>
40129
</div>
41130

42-
<div class="links">
43-
{#each tabs as tab}
44-
<div class="link">
45-
<h1
46-
class="tabButton modalButton"
47-
style={activeTab === tab
48-
? 'background-image: linear-gradient(to right top, #63b7dd, #63ddc7); color: white;'
49-
: 'background: transparent; color: #426696;'}
50-
onclick={() => activeTab = tab}
51-
>
52-
{tab}
53-
</h1>
54-
</div>
55-
{/each}
131+
<div class="settings-section">
132+
<h2>Image Wiggle</h2>
133+
<select class="ddl button" value={$settings.imgWiggle}
134+
onchange={(e) => settings.update(s => ({ ...s, imgWiggle: (e.target as HTMLSelectElement).value as ToggleOption }))}>
135+
<option value="On">On</option>
136+
<option value="Off">Off</option>
137+
</select>
56138
</div>
57139

58-
<br /><br />
59-
<div>
60-
<input class="button saveButton" style="position: relative; background: #ff6b6b; font-size: 0.7em;" type="button" value="reset defaults" onclick={() => settings.reset()} aria-label="Reset settings to defaults." />
140+
<div class="settings-section">
141+
<h2>Font Family</h2>
142+
<select class="ddl button" value={$settings.fontFamily}
143+
onchange={(e) => settings.update(s => ({ ...s, fontFamily: (e.target as HTMLSelectElement).value }))}>
144+
{#each FONTS as font}
145+
<option value={font} style:font-family={font}>{font}</option>
146+
{/each}
147+
</select>
61148
</div>
62149
</div>
63150

64-
<div class="settings-content">
65-
{#if activeTab === 'Options'}
66-
<SettingsTabOptions />
67-
{:else if activeTab === 'Colors'}
68-
<SettingsTabColors />
69-
{:else}
70-
<SettingsTabCustomization />
71-
{/if}
151+
<div style="text-align: center; padding: 1rem;">
152+
<input class="button" style="background: #ff6b6b; color: white; font-size: 0.8em;" type="button" value="Reset Defaults" onclick={() => settings.reset()} />
72153
</div>
73-
</main>
154+
</div>
74155
</div>
156+
157+
<style>
158+
.settings-single {
159+
width: 70%;
160+
max-width: 800px;
161+
height: auto;
162+
max-height: 85vh;
163+
padding: 1.5rem;
164+
}
165+
166+
.settings-header {
167+
display: flex;
168+
align-items: center;
169+
gap: 0.75rem;
170+
margin-bottom: 1rem;
171+
}
172+
173+
.settings-grid {
174+
display: grid;
175+
grid-template-columns: repeat(3, 1fr);
176+
gap: 1.2rem;
177+
}
178+
179+
.settings-section :global(h2) {
180+
font-size: 0.9em;
181+
margin-bottom: 0.4rem;
182+
}
183+
184+
.settings-section :global(.button) {
185+
margin: 0;
186+
width: 100%;
187+
}
188+
189+
@media (max-width: 700px) {
190+
.settings-grid {
191+
grid-template-columns: repeat(2, 1fr);
192+
}
193+
.settings-single {
194+
width: 90%;
195+
}
196+
}
197+
198+
@media (max-width: 450px) {
199+
.settings-grid {
200+
grid-template-columns: 1fr;
201+
}
202+
}
203+
</style>

src/lib/components/SettingsTabColors.svelte

Lines changed: 0 additions & 52 deletions
This file was deleted.

src/lib/components/SettingsTabCustomization.svelte

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)