Skip to content

feat(settings): add settings page with theme, stream mode, and path configuration#10

Open
leavraell wants to merge 1 commit intoStoryForgeApp:releasefrom
leavraell:feature/settings-page
Open

feat(settings): add settings page with theme, stream mode, and path configuration#10
leavraell wants to merge 1 commit intoStoryForgeApp:releasefrom
leavraell:feature/settings-page

Conversation

@leavraell
Copy link

markdown

Description

Adds a settings page to the StoryForge UI with three sections:

Appearance — theme picker (Light / Dark / System) saved immediately via the existing theme context

Privacy — stream mode toggle that hides server IP addresses in the UI

Paths — configurable locations for game versions, installations, and mods cache

Stream mode and path settings are persisted to ~/.config/storyforge/config.json via two new RPC handlers (getConfig, setConfig) added to the utils controller. The backend config path helpers in utils.ts were refactored from module-level constants into factory functions to avoid initialization ordering issues with Utils.paths.appData.

The UI shows "Unsaved changes" when the form is dirty and "Saved ✓" after a successful save. Values persist across app restarts and the dirty state is preserved when navigating between routes.

Changes

  • src/mainview/routes/settings/index.tsx — new settings page
  • src/bun/utils.ts — lazy config file helpers
  • src/bun/controllers/utils.tsgetConfig and setConfig RPC handlers
  • package.json / bun.lock — adds Vitest for test infrastructure. Unit tests for the config layer (src/bun/__tests__/config.test.ts) are included but currently skipped in CI — vi.mock("electrobun/bun") is unreliable in the Vitest 4.x + Bun runtime combination due to the module's native side effects at import time. The test file and config are committed as a foundation for when this is resolved.

Screenshots

Screenshot 2026-03-17 at 8 54 53 PM Screenshot 2026-03-17 at 8 55 28 PM Screenshot 2026-03-17 at 8 55 11 PM

Checklist

  • I have verified backward compatibility — no breaking changes, new feature only
  • I have run linters/formatters and addressed warnings

Reviewers

Comment on lines +157 to +159
<Label htmlFor="modsCachePath">Mods cache</Label>
<Input
id="modsCachePath"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the htmlFor and id you can usually use field.name, those are unique too.

}: {
form: SettingsFormApi;
version?: string;
electroview: ElectroViewContext;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't pass electroview into components, instead use the useRPC hook to use rpc.
Prop drilling is not really a good way to go about it.


function RouteComponent() {
return <div className="p-2">WIP</div>;
const { electroview } = useRouteContext({ from: "/settings/" });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the useRPC hook instead.

Comment on lines +218 to +220
const form = useForm({
defaultValues: config ?? emptyConfig,
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be moved into the component, since it doesn't do anything here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants