Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/main/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ function defaultConfig(): Config {
watchFolder: false,
transcriptsOnly: false,
demoMode: false,
autoHideSidebar: true
autoHideSidebar: true,
devTools: false
}
}

Expand Down Expand Up @@ -71,7 +72,8 @@ export function getConfig(): Config {
demoMode: parsed.demoMode === true,
// Default ON when absent — first-launch behaviour is auto-hide on
// narrow windows, which matches the plan's UX intent.
autoHideSidebar: parsed.autoHideSidebar !== false
autoHideSidebar: parsed.autoHideSidebar !== false,
devTools: parsed.devTools === true
}
} catch (err) {
console.warn('[config] failed to read config.json, falling back to defaults:', err)
Expand Down
2 changes: 2 additions & 0 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { registerIpcHandlers } from './ipc'
import { registerSwProtocolHandler, registerSwSchemeAsPrivileged } from './protocol'
import { initAutoUpdater } from './updater'
import { disableWatch } from './watcher'
import { getConfig } from './config'

// Privileged scheme registration must happen BEFORE app.whenReady — the
// renderer's session inherits these privileges at startup. Doing this at
Expand All @@ -32,6 +33,7 @@ function createWindow(): void {

mainWindow.on('ready-to-show', () => {
mainWindow.show()
if (getConfig().devTools) mainWindow.webContents.openDevTools()
})

mainWindow.webContents.setWindowOpenHandler((details) => {
Expand Down
14 changes: 13 additions & 1 deletion src/main/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ function buildStatus(): ConfigStatus {
watchFolder: config.watchFolder,
transcriptsOnly: config.transcriptsOnly,
demoMode: config.demoMode,
autoHideSidebar: config.autoHideSidebar
autoHideSidebar: config.autoHideSidebar,
devTools: config.devTools
}
}

Expand Down Expand Up @@ -95,6 +96,17 @@ export function registerIpcHandlers(): void {
return buildStatus()
})

ipcMain.handle('config:setDevTools', (event, enabled: unknown): ConfigStatus => {
if (!validBool(enabled)) return buildStatus()
setConfig({ devTools: enabled })
const win = BrowserWindow.fromWebContents(event.sender)
if (win) {
if (enabled) win.webContents.openDevTools()
else win.webContents.closeDevTools()
}
return buildStatus()
})

// Reset everything — wipes config.json back to defaults so the
// welcome flow shows again on next hydrate. Used by the "Reset app"
// affordance in Settings → About.
Expand Down
6 changes: 6 additions & 0 deletions src/preload/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export interface Config {
* navbar PanelLeft icon; widening the window again does NOT auto-
* expand, so user intent always wins. Default true. */
autoHideSidebar: boolean
/** When true, DevTools open on launch. Equivalent to Cmd+Option+I. */
devTools: boolean
}

/**
Expand All @@ -65,6 +67,7 @@ export interface ConfigStatus {
transcriptsOnly: boolean
demoMode: boolean
autoHideSidebar: boolean
devTools: boolean
}

/** Wire callback type for main → renderer push when the indexed dataset
Expand Down Expand Up @@ -104,6 +107,9 @@ export const api = {
* it entirely via Cmd-B / the navbar icon. */
setAutoHideSidebar: (enabled: boolean): Promise<ConfigStatus> =>
ipcRenderer.invoke('config:setAutoHideSidebar', enabled),
/** Toggle DevTools open/close. Persists across restarts. */
setDevTools: (enabled: boolean): Promise<ConfigStatus> =>
ipcRenderer.invoke('config:setDevTools', enabled),
/** Wipe the persisted config back to defaults — clears the saved
* folder, demo flag, custom filler dictionary, etc. The renderer
* follows up by triggering a fresh hydrate so the dataStore picks
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/components/charts/ActivityArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ function ActivityAreaInner<T extends object>({
const effectiveTickFormatter = monthTicks ? monthLabel : formatTick

return (
<ResponsiveContainer width="100%" height="100%">
<ResponsiveContainer width="100%" height="100%" initialDimension={{ width: 1, height: 1 }}>
<AreaChart
data={filtered as ReadonlyArray<Record<string, unknown>>}
margin={{ top: 8, right: 8, left: -4, bottom: 0 }}
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/components/charts/DistBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface DistBarProps<T extends object> {
*/
function DistBarInner<T extends object>({ data, xKey, yKey }: DistBarProps<T>): React.JSX.Element {
return (
<ResponsiveContainer width="100%" height="100%">
<ResponsiveContainer width="100%" height="100%" initialDimension={{ width: 1, height: 1 }}>
<BarChart
data={data as ReadonlyArray<Record<string, unknown>>}
margin={{ top: 8, right: 8, left: 0, bottom: 0 }}
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/components/charts/LineTrend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function LineTrendInner<T extends object>({
}: LineTrendProps<T>): React.JSX.Element {
const yTick = formatYTick ?? ((v: number) => formatCompact(v))
return (
<ResponsiveContainer width="100%" height="100%">
<ResponsiveContainer width="100%" height="100%" initialDimension={{ width: 1, height: 1 }}>
<LineChart
data={data as ReadonlyArray<Record<string, unknown>>}
margin={{ top: 8, right: 8, left: -4, bottom: 0 }}
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/components/charts/PaceTrend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function PaceTrendInner<T extends object>({
const dotRows = dots.map((d) => ({ [xKey]: d.period, dotValue: d.value }))

return (
<ResponsiveContainer width="100%" height="100%">
<ResponsiveContainer width="100%" height="100%" initialDimension={{ width: 1, height: 1 }}>
<ComposedChart
data={[...merged, ...dotRows]}
margin={{ top: 8, right: 8, left: -4, bottom: 0 }}
Expand Down
19 changes: 19 additions & 0 deletions src/renderer/src/screens/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useUiPrefsStore } from '@renderer/state/uiPrefsStore'
import {
AlignLeft,
BookOpen,
Code2,
ExternalLink,
Folder,
Info,
Expand Down Expand Up @@ -78,6 +79,7 @@ export function Settings(): React.JSX.Element {
<>
<AboutCard />
<ResetAppCard />
<DeveloperCard />
</>
)}
</div>
Expand Down Expand Up @@ -629,6 +631,23 @@ function ResetAppCard(): React.JSX.Element {
)
}

// ---------- Developer ----------------------------------------------------

function DeveloperCard(): React.JSX.Element {
const devTools = useConfigStore((s) => s.devTools)
const setDevTools = useConfigStore((s) => s.setDevTools)
return (
<SettingsCard icon={Code2} title="Developer" subtitle="Tools for debugging and development.">
<ToggleRow
label="Enable DevTools"
description="Open the Chromium DevTools panel. Equivalent to Cmd+Option+I — persists across restarts."
checked={devTools}
onChange={(next) => void setDevTools(next)}
/>
</SettingsCard>
)
}

/** Plain-language summary of the updater state, shown next to the
* "Check now" button. */
function describeStatus(s: UpdaterStatus): string {
Expand Down
12 changes: 12 additions & 0 deletions src/renderer/src/state/configStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ interface ConfigState {
demoMode: boolean
/** When true, sidebar auto-collapses on narrow windows. */
autoHideSidebar: boolean
/** When true, DevTools are open. Persisted across restarts. */
devTools: boolean
/** Has the initial round-trip completed? Gates the first-run modal. */
hydrated: boolean
/** Transient flag — when true, force the welcome modal regardless
Expand All @@ -60,6 +62,8 @@ interface ConfigState {
setDemoMode: (enabled: boolean) => Promise<void>
/** Toggle the auto-hide sidebar behaviour. */
setAutoHideSidebar: (enabled: boolean) => Promise<void>
/** Toggle DevTools open/close. Persists across restarts. */
setDevTools: (enabled: boolean) => Promise<void>
/** Wipe the persisted config back to defaults and force the welcome
* modal to re-appear. Used by Settings → About → Reset app. */
resetApp: () => Promise<void>
Expand All @@ -79,6 +83,7 @@ function applyStatus(status: ConfigStatus): Partial<ConfigState> {
transcriptsOnly: status.transcriptsOnly,
demoMode: status.demoMode,
autoHideSidebar: status.autoHideSidebar,
devTools: status.devTools,
hydrated: true
}
}
Expand All @@ -93,6 +98,7 @@ export const useConfigStore = create<ConfigState>((set, get) => ({
transcriptsOnly: false,
demoMode: false,
autoHideSidebar: true,
devTools: false,
hydrated: false,
welcomeForceShow: false,

Expand Down Expand Up @@ -160,6 +166,12 @@ export const useConfigStore = create<ConfigState>((set, get) => ({
set(applyStatus(updated))
},

setDevTools: async (enabled) => {
set({ devTools: enabled })
const updated = await window.api.config.setDevTools(enabled)
set(applyStatus(updated))
},

resetApp: async () => {
const status = await window.api.config.reset()
// Apply the cleared status AND flip the force-show flag so the
Expand Down
Loading