Add dark mode (#199)
* Add passive dark mode to everything but codemirror * Add dark theme support for Codemirror * Make theme a user setting * Fix button text size * guard against undefined window * Formatting and test fix
This commit is contained in:
@ -55,6 +55,7 @@ export function App() {
|
|||||||
token,
|
token,
|
||||||
formatCode,
|
formatCode,
|
||||||
debugPanel,
|
debugPanel,
|
||||||
|
theme,
|
||||||
} = useStore((s) => ({
|
} = useStore((s) => ({
|
||||||
editorView: s.editorView,
|
editorView: s.editorView,
|
||||||
setEditorView: s.setEditorView,
|
setEditorView: s.setEditorView,
|
||||||
@ -85,6 +86,7 @@ export function App() {
|
|||||||
formatCode: s.formatCode,
|
formatCode: s.formatCode,
|
||||||
debugPanel: s.debugPanel,
|
debugPanel: s.debugPanel,
|
||||||
addKCLError: s.addKCLError,
|
addKCLError: s.addKCLError,
|
||||||
|
theme: s.theme,
|
||||||
}))
|
}))
|
||||||
const showTauriTokenInput = isTauri() && !token
|
const showTauriTokenInput = isTauri() && !token
|
||||||
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
|
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
|
||||||
@ -268,6 +270,7 @@ export function App() {
|
|||||||
}
|
}
|
||||||
asyncWrap()
|
asyncWrap()
|
||||||
}, [code, isStreamReady])
|
}, [code, isStreamReady])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen">
|
<div className="h-screen">
|
||||||
<AppHeader />
|
<AppHeader />
|
||||||
@ -293,6 +296,7 @@ export function App() {
|
|||||||
extensions={[javascript({ jsx: true }), lineHighlightField]}
|
extensions={[javascript({ jsx: true }), lineHighlightField]}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onUpdate={onUpdate}
|
onUpdate={onUpdate}
|
||||||
|
theme={theme}
|
||||||
onCreateEditor={(_editorView) => setEditorView(_editorView)}
|
onCreateEditor={(_editorView) => setEditorView(_editorView)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,7 +39,6 @@ export const Toolbar = () => {
|
|||||||
sketchMode: 'selectFace',
|
sketchMode: 'selectFace',
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
className="border m-1 px-1 rounded text-xs"
|
|
||||||
>
|
>
|
||||||
Start Sketch
|
Start Sketch
|
||||||
</button>
|
</button>
|
||||||
@ -59,7 +58,6 @@ export const Toolbar = () => {
|
|||||||
)
|
)
|
||||||
updateAst(modifiedAst)
|
updateAst(modifiedAst)
|
||||||
}}
|
}}
|
||||||
className="border m-1 px-1 rounded text-xs"
|
|
||||||
>
|
>
|
||||||
SketchOnFace
|
SketchOnFace
|
||||||
</button>
|
</button>
|
||||||
@ -75,7 +73,6 @@ export const Toolbar = () => {
|
|||||||
position: guiMode.position,
|
position: guiMode.position,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
className="border m-1 px-1 rounded text-xs"
|
|
||||||
>
|
>
|
||||||
Edit Sketch
|
Edit Sketch
|
||||||
</button>
|
</button>
|
||||||
@ -95,7 +92,6 @@ export const Toolbar = () => {
|
|||||||
)
|
)
|
||||||
updateAst(modifiedAst, { focusPath: pathToExtrudeArg })
|
updateAst(modifiedAst, { focusPath: pathToExtrudeArg })
|
||||||
}}
|
}}
|
||||||
className="border m-1 px-1 rounded text-xs"
|
|
||||||
>
|
>
|
||||||
ExtrudeSketch
|
ExtrudeSketch
|
||||||
</button>
|
</button>
|
||||||
@ -113,7 +109,6 @@ export const Toolbar = () => {
|
|||||||
)
|
)
|
||||||
updateAst(modifiedAst, { focusPath: pathToExtrudeArg })
|
updateAst(modifiedAst, { focusPath: pathToExtrudeArg })
|
||||||
}}
|
}}
|
||||||
className="border m-1 px-1 rounded text-xs"
|
|
||||||
>
|
>
|
||||||
ExtrudeSketch (w/o pipe)
|
ExtrudeSketch (w/o pipe)
|
||||||
</button>
|
</button>
|
||||||
@ -121,10 +116,7 @@ export const Toolbar = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{guiMode.mode === 'sketch' && (
|
{guiMode.mode === 'sketch' && (
|
||||||
<button
|
<button onClick={() => setGuiMode({ mode: 'default' })}>
|
||||||
onClick={() => setGuiMode({ mode: 'default' })}
|
|
||||||
className="border m-1 px-1 rounded text-xs"
|
|
||||||
>
|
|
||||||
Exit sketch
|
Exit sketch
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@ -142,9 +134,6 @@ export const Toolbar = () => {
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
key={sketchFnName}
|
key={sketchFnName}
|
||||||
className={`border m-0.5 px-0.5 rounded text-xs ${
|
|
||||||
guiMode.sketchMode === sketchFnName && 'bg-gray-400'
|
|
||||||
}`}
|
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setGuiMode({
|
setGuiMode({
|
||||||
...guiMode,
|
...guiMode,
|
||||||
|
@ -21,7 +21,7 @@ export const ActionButton = ({
|
|||||||
Element = 'button',
|
Element = 'button',
|
||||||
children,
|
children,
|
||||||
}: ActionButtonProps) => {
|
}: ActionButtonProps) => {
|
||||||
const classNames = `group mono flex items-center gap-2 text-chalkboard-110 rounded-sm border border-chalkboard-40 hover:border-liquid-40 p-[3px] ${
|
const classNames = `group mono text-base flex items-center gap-2 rounded-sm border border-chalkboard-40 dark:border-chalkboard-60 hover:border-liquid-40 p-[3px] ${
|
||||||
icon ? 'pr-2' : 'px-2'
|
icon ? 'pr-2' : 'px-2'
|
||||||
} ${className}`
|
} ${className}`
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ export const ActionIcon = ({
|
|||||||
className={
|
className={
|
||||||
'p-1 w-fit inline-grid place-content-center ' +
|
'p-1 w-fit inline-grid place-content-center ' +
|
||||||
(bgClassName ||
|
(bgClassName ||
|
||||||
'bg-chalkboard-100 group-hover:bg-chalkboard-90 hover:bg-chalkboard-90')
|
'bg-chalkboard-100 group-hover:bg-chalkboard-90 hover:bg-chalkboard-90 dark:bg-liquid-20 dark:group-hover:bg-liquid-10 dark:hover:bg-liquid-10')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{children || (
|
{children || (
|
||||||
@ -39,7 +39,7 @@ export const ActionIcon = ({
|
|||||||
height={iconSizes[size]}
|
height={iconSizes[size]}
|
||||||
className={
|
className={
|
||||||
iconClassName ||
|
iconClassName ||
|
||||||
'text-liquid-20 group-hover:text-liquid-10 hover:text-liquid-10'
|
'text-liquid-20 group-hover:text-liquid-10 hover:text-liquid-10 dark:text-liquid-100 dark:group-hover:text-liquid-100 dark:hover:text-liquid-100'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -13,7 +13,7 @@ export const AppHeader = ({ showToolbar = true, children }: AppHeaderProps) => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="py-1 px-5 bg-chalkboard-10 border-b border-chalkboard-30 flex justify-between items-center">
|
<header className="py-1 px-5 bg-chalkboard-10 dark:bg-chalkboard-100 border-b dark:border-b-2 border-chalkboard-30 dark:border-chalkboard-70 flex justify-between items-center">
|
||||||
<Link to="/">
|
<Link to="/">
|
||||||
<img
|
<img
|
||||||
src="/kitt-arcade-winking.svg"
|
src="/kitt-arcade-winking.svg"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export const PanelHeader = ({ title }: { title: string }) => {
|
export const PanelHeader = ({ title }: { title: string }) => {
|
||||||
return (
|
return (
|
||||||
<div className="font-mono text-[11px] bg-stone-100 w-full pl-4 h-[20px] text-stone-700 flex items-center">
|
<div className="font-mono text-[11px] bg-chalkboard-20 dark:bg-chalkboard-110 dark:border-b-2 dark:border-b-chalkboard-90 w-full pl-4 h-[20px] flex items-center">
|
||||||
<span className="pt-1">{title}</span>
|
<span className="pt-1">{title}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
height: calc(var(--toggle-size) + var(--padding));
|
height: calc(var(--toggle-size) + var(--padding));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.dark) .toggle > span {
|
||||||
|
@apply border-chalkboard-40;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle > span::after {
|
.toggle > span::after {
|
||||||
content: '';
|
content: '';
|
||||||
@apply absolute w-4 h-4 rounded-sm bg-chalkboard-110;
|
@apply absolute w-4 h-4 rounded-sm bg-chalkboard-110;
|
||||||
@ -27,6 +31,10 @@
|
|||||||
transition: translate 0.08s ease-out;
|
transition: translate 0.08s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.dark) .toggle > span::after {
|
||||||
|
@apply bg-chalkboard-10;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle input:checked + span::after {
|
.toggle input:checked + span::after {
|
||||||
translate: calc(50% - var(--padding)) -50%;
|
translate: calc(50% - var(--padding)) -50%;
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,6 @@ export const ConvertToVariable = () => {
|
|||||||
console.log('e', e)
|
console.log('e', e)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enableAngLen ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enableAngLen}
|
disabled={!enableAngLen}
|
||||||
>
|
>
|
||||||
ConvertToVariable
|
ConvertToVariable
|
||||||
|
@ -86,9 +86,6 @@ export const EqualAngle = () => {
|
|||||||
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
|
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enableEqual ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enableEqual}
|
disabled={!enableEqual}
|
||||||
title="yo dawg"
|
title="yo dawg"
|
||||||
>
|
>
|
||||||
|
@ -86,9 +86,6 @@ export const EqualLength = () => {
|
|||||||
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
|
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enableEqual ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enableEqual}
|
disabled={!enableEqual}
|
||||||
title="yo dawg"
|
title="yo dawg"
|
||||||
>
|
>
|
||||||
|
@ -65,9 +65,6 @@ export const HorzVert = ({
|
|||||||
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
|
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enableHorz ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enableHorz}
|
disabled={!enableHorz}
|
||||||
title="yo dawg"
|
title="yo dawg"
|
||||||
>
|
>
|
||||||
|
@ -187,9 +187,6 @@ export const Intersect = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enable ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enable}
|
disabled={!enable}
|
||||||
>
|
>
|
||||||
perpendicularDistance
|
perpendicularDistance
|
||||||
|
@ -69,9 +69,6 @@ export const RemoveConstrainingValues = () => {
|
|||||||
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
|
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enableHorz ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enableHorz}
|
disabled={!enableHorz}
|
||||||
title="yo dawg"
|
title="yo dawg"
|
||||||
>
|
>
|
||||||
|
@ -131,9 +131,6 @@ export const SetAbsDistance = ({
|
|||||||
console.log('e', e)
|
console.log('e', e)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enableAngLen ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enableAngLen}
|
disabled={!enableAngLen}
|
||||||
>
|
>
|
||||||
{buttonType}
|
{buttonType}
|
||||||
|
@ -146,9 +146,6 @@ export const SetAngleBetween = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enable ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enable}
|
disabled={!enable}
|
||||||
>
|
>
|
||||||
angleBetween
|
angleBetween
|
||||||
|
@ -168,9 +168,6 @@ export const SetHorzVertDistance = ({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enable ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enable}
|
disabled={!enable}
|
||||||
>
|
>
|
||||||
{buttonType}
|
{buttonType}
|
||||||
|
@ -143,9 +143,6 @@ export const SetAngleLength = ({
|
|||||||
console.log('e', e)
|
console.log('e', e)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`border m-1 px-1 rounded text-xs ${
|
|
||||||
enableAngLen ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
|
|
||||||
}`}
|
|
||||||
disabled={!enableAngLen}
|
disabled={!enableAngLen}
|
||||||
>
|
>
|
||||||
{angleOrLength}
|
{angleOrLength}
|
||||||
|
@ -12,6 +12,23 @@ body {
|
|||||||
sans-serif;
|
sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
@apply text-chalkboard-110 bg-chalkboard-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark {
|
||||||
|
@apply bg-chalkboard-100 text-chalkboard-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@apply border m-0.5 px-3 rounded text-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark button {
|
||||||
|
@apply border-chalkboard-20 hover:border-chalkboard-10 hover:bg-chalkboard-90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark button:disabled {
|
||||||
|
@apply bg-chalkboard-90 text-chalkboard-40 border-chalkboard-70;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mono {
|
.mono {
|
||||||
|
@ -2,13 +2,31 @@ import ReactDOM from 'react-dom/client'
|
|||||||
import './index.css'
|
import './index.css'
|
||||||
import reportWebVitals from './reportWebVitals'
|
import reportWebVitals from './reportWebVitals'
|
||||||
import { Toaster } from 'react-hot-toast'
|
import { Toaster } from 'react-hot-toast'
|
||||||
|
import { useStore } from './useStore'
|
||||||
import { Router } from './Router'
|
import { Router } from './Router'
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
|
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
|
||||||
|
function setThemeClass(state: Partial<{ theme: string }>) {
|
||||||
|
if (state.theme === 'dark') {
|
||||||
|
document.body.classList.add('dark')
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove('dark')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { theme } = useStore.getState()
|
||||||
|
setThemeClass({ theme })
|
||||||
|
useStore.subscribe(setThemeClass)
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<>
|
<>
|
||||||
<Router />
|
<Router />
|
||||||
<Toaster position="bottom-center" />
|
<Toaster
|
||||||
|
position="bottom-center"
|
||||||
|
toastOptions={{
|
||||||
|
className:
|
||||||
|
'bg-chalkboard-10 dark:bg-chalkboard-90 text-chalkboard-110 dark:text-chalkboard-10',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,10 +10,10 @@ const Units = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="fixed grid justify-center items-end inset-0 bg-chalkboard-110/50 z-50"
|
className="fixed grid justify-center items-end inset-0 bg-chalkboard-110/50 dark:bg-chalkboard-110/80 z-50"
|
||||||
style={{ clipPath }}
|
style={{ clipPath }}
|
||||||
>
|
>
|
||||||
<div className="max-w-2xl flex flex-col justify-center bg-white p-8 rounded">
|
<div className="max-w-2xl flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded">
|
||||||
<h1 className="text-2xl font-bold">Camera</h1>
|
<h1 className="text-2xl font-bold">Camera</h1>
|
||||||
<p className="mt-6">
|
<p className="mt-6">
|
||||||
Moving the camera is easy. Just click and drag anywhere in the scene
|
Moving the camera is easy. Just click and drag anywhere in the scene
|
||||||
|
@ -8,7 +8,7 @@ const Introduction = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
||||||
<div className="max-w-3xl bg-white p-8 rounded">
|
<div className="max-w-3xl bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded">
|
||||||
<h1 className="text-2xl font-bold">
|
<h1 className="text-2xl font-bold">
|
||||||
Welcome to the KittyCAD Modeling App
|
Welcome to the KittyCAD Modeling App
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -7,7 +7,7 @@ const Sketching = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-center items-end inset-0 bg-chalkboard-110/50 z-50">
|
<div className="fixed grid justify-center items-end inset-0 bg-chalkboard-110/50 z-50">
|
||||||
<div className="max-w-2xl flex flex-col justify-center bg-white p-8 rounded">
|
<div className="max-w-2xl flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded">
|
||||||
<h1 className="text-2xl font-bold">Sketching</h1>
|
<h1 className="text-2xl font-bold">Sketching</h1>
|
||||||
<p className="mt-6">
|
<p className="mt-6">
|
||||||
We still have to implement this step, and the rest of the tutorial!
|
We still have to implement this step, and the rest of the tutorial!
|
||||||
|
@ -32,7 +32,7 @@ const Units = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
<div className="fixed grid place-content-center inset-0 bg-chalkboard-110/50 z-50">
|
||||||
<div className="max-w-3xl bg-white p-8 rounded">
|
<div className="max-w-3xl bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded">
|
||||||
<h1 className="text-2xl font-bold">Set your units</h1>
|
<h1 className="text-2xl font-bold">Set your units</h1>
|
||||||
<SettingsSection
|
<SettingsSection
|
||||||
title="Unit System"
|
title="Unit System"
|
||||||
|
@ -26,8 +26,9 @@ export const Settings = () => {
|
|||||||
setDefaultBaseUnit: saveDefaultBaseUnit,
|
setDefaultBaseUnit: saveDefaultBaseUnit,
|
||||||
saveDebugPanel,
|
saveDebugPanel,
|
||||||
originalDebugPanel,
|
originalDebugPanel,
|
||||||
onboardingStatus: ogOnboardingStatus,
|
setOnboardingStatus,
|
||||||
setOnboardingStatus: saveOnboardingStatus,
|
theme: ogTheme,
|
||||||
|
setTheme: saveTheme,
|
||||||
} = useStore((s) => ({
|
} = useStore((s) => ({
|
||||||
defaultDir: s.defaultDir,
|
defaultDir: s.defaultDir,
|
||||||
setDefaultDir: s.setDefaultDir,
|
setDefaultDir: s.setDefaultDir,
|
||||||
@ -39,8 +40,9 @@ export const Settings = () => {
|
|||||||
setDefaultBaseUnit: s.setDefaultBaseUnit,
|
setDefaultBaseUnit: s.setDefaultBaseUnit,
|
||||||
saveDebugPanel: s.setDebugPanel,
|
saveDebugPanel: s.setDebugPanel,
|
||||||
originalDebugPanel: s.debugPanel,
|
originalDebugPanel: s.debugPanel,
|
||||||
onboardingStatus: s.onboardingStatus,
|
|
||||||
setOnboardingStatus: s.setOnboardingStatus,
|
setOnboardingStatus: s.setOnboardingStatus,
|
||||||
|
theme: s.theme,
|
||||||
|
setTheme: s.setTheme,
|
||||||
}))
|
}))
|
||||||
const [defaultDir, setDefaultDir] = useState(ogDefaultDir)
|
const [defaultDir, setDefaultDir] = useState(ogDefaultDir)
|
||||||
const [defaultProjectName, setDefaultProjectName] =
|
const [defaultProjectName, setDefaultProjectName] =
|
||||||
@ -49,7 +51,7 @@ export const Settings = () => {
|
|||||||
useState(ogDefaultUnitSystem)
|
useState(ogDefaultUnitSystem)
|
||||||
const [defaultBaseUnit, setDefaultBaseUnit] = useState(ogDefaultBaseUnit)
|
const [defaultBaseUnit, setDefaultBaseUnit] = useState(ogDefaultBaseUnit)
|
||||||
const [debugPanel, setDebugPanel] = useState(originalDebugPanel)
|
const [debugPanel, setDebugPanel] = useState(originalDebugPanel)
|
||||||
const [onboardingStatus, setOnboardingStatus] = useState(ogOnboardingStatus)
|
const [theme, setTheme] = useState(ogTheme)
|
||||||
|
|
||||||
async function handleDirectorySelection() {
|
async function handleDirectorySelection() {
|
||||||
const newDirectory = await open({
|
const newDirectory = await open({
|
||||||
@ -69,7 +71,7 @@ export const Settings = () => {
|
|||||||
saveDefaultUnitSystem(defaultUnitSystem)
|
saveDefaultUnitSystem(defaultUnitSystem)
|
||||||
saveDefaultBaseUnit(defaultBaseUnit)
|
saveDefaultBaseUnit(defaultBaseUnit)
|
||||||
saveDebugPanel(debugPanel)
|
saveDebugPanel(debugPanel)
|
||||||
saveOnboardingStatus(onboardingStatus)
|
saveTheme(theme)
|
||||||
toast.success('Settings saved!')
|
toast.success('Settings saved!')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,13 +178,25 @@ export const Settings = () => {
|
|||||||
onChange={(e) => setDebugPanel(e.target.checked)}
|
onChange={(e) => setDebugPanel(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
<SettingsSection
|
||||||
|
title="Editor Theme"
|
||||||
|
description="Apply a light or dark theme to the editor"
|
||||||
|
>
|
||||||
|
<Toggle
|
||||||
|
name="settings-theme"
|
||||||
|
offLabel="Dark"
|
||||||
|
onLabel="Light"
|
||||||
|
checked={theme === 'light'}
|
||||||
|
onChange={(e) => setTheme(e.target.checked ? 'light' : 'dark')}
|
||||||
|
/>
|
||||||
|
</SettingsSection>
|
||||||
<SettingsSection
|
<SettingsSection
|
||||||
title="Onboarding"
|
title="Onboarding"
|
||||||
description="Replay the onboarding process"
|
description="Replay the onboarding process"
|
||||||
>
|
>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
saveOnboardingStatus('')
|
setOnboardingStatus('')
|
||||||
navigate('/')
|
navigate('/')
|
||||||
}}
|
}}
|
||||||
icon={{ icon: faArrowRotateBack }}
|
icon={{ icon: faArrowRotateBack }}
|
||||||
|
@ -189,6 +189,8 @@ export interface StoreState {
|
|||||||
setHomeShowMenu: (showMenu: boolean) => void
|
setHomeShowMenu: (showMenu: boolean) => void
|
||||||
onboardingStatus: string
|
onboardingStatus: string
|
||||||
setOnboardingStatus: (status: string) => void
|
setOnboardingStatus: (status: string) => void
|
||||||
|
theme: 'light' | 'dark'
|
||||||
|
setTheme: (theme: 'light' | 'dark') => void
|
||||||
homeMenuItems: {
|
homeMenuItems: {
|
||||||
name: string
|
name: string
|
||||||
path: string
|
path: string
|
||||||
@ -365,6 +367,13 @@ export const useStore = create<StoreState>()(
|
|||||||
setDefaultBaseUnit: (defaultBaseUnit) => set({ defaultBaseUnit }),
|
setDefaultBaseUnit: (defaultBaseUnit) => set({ defaultBaseUnit }),
|
||||||
onboardingStatus: '',
|
onboardingStatus: '',
|
||||||
setOnboardingStatus: (onboardingStatus) => set({ onboardingStatus }),
|
setOnboardingStatus: (onboardingStatus) => set({ onboardingStatus }),
|
||||||
|
theme:
|
||||||
|
typeof window !== 'undefined' &&
|
||||||
|
'matchMedia' in window &&
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
? 'dark'
|
||||||
|
: 'light',
|
||||||
|
setTheme: (theme) => set({ theme }),
|
||||||
showHomeMenu: true,
|
showHomeMenu: true,
|
||||||
setHomeShowMenu: (showHomeMenu) => set({ showHomeMenu }),
|
setHomeShowMenu: (showHomeMenu) => set({ showHomeMenu }),
|
||||||
homeMenuItems: [],
|
homeMenuItems: [],
|
||||||
@ -390,6 +399,7 @@ export const useStore = create<StoreState>()(
|
|||||||
'token',
|
'token',
|
||||||
'debugPanel',
|
'debugPanel',
|
||||||
'onboardingStatus',
|
'onboardingStatus',
|
||||||
|
'theme',
|
||||||
].includes(key)
|
].includes(key)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -38,5 +38,6 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
darkMode: 'class',
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user