136 changed files with 1011 additions and 1075 deletions
@ -0,0 +1,36 @@ |
|||||
|
{ |
||||
|
"imports": { |
||||
|
"@meshtastic/core": "jsr:@meshtastic/core@^2.6.0", |
||||
|
"@meshtastic/js": "jsr:@meshtastic/js@^2.3.4", |
||||
|
"@meshtastic/transport-http": "jsr:@meshtastic/transport-http@^0.2.1", |
||||
|
"@meshtastic/transport-web-serial": "jsr:@meshtastic/transport-web-serial@^0.2.1", |
||||
|
"@app/": "./src/", |
||||
|
"@pages/": "./src/pages/", |
||||
|
"@components/": "./src/components/", |
||||
|
"@core/": "./src/core/", |
||||
|
"@layouts/": "./src/layouts/" |
||||
|
}, |
||||
|
"compilerOptions": { |
||||
|
"lib": [ |
||||
|
"DOM", |
||||
|
"DOM.Iterable", |
||||
|
"ESNext" |
||||
|
], |
||||
|
"jsx": "react-jsx", |
||||
|
"strict": true, |
||||
|
"noUnusedLocals": true, |
||||
|
"noUnusedParameters": true, |
||||
|
"noFallthroughCasesInSwitch": true, |
||||
|
"strictNullChecks": true, |
||||
|
"types": [ |
||||
|
"vite/client", |
||||
|
"node", |
||||
|
"@types/web-bluetooth", |
||||
|
"@types/w3c-web-serial" |
||||
|
], |
||||
|
"strictPropertyInitialization": false |
||||
|
}, |
||||
|
"unstable": [ |
||||
|
"sloppy-imports" |
||||
|
] |
||||
|
} |
||||
@ -1,25 +0,0 @@ |
|||||
export interface ModalProps { |
|
||||
title: string; |
|
||||
actions?: JSX.Element[]; |
|
||||
children: React.ReactNode; |
|
||||
} |
|
||||
|
|
||||
export const Modal = ({ |
|
||||
title, |
|
||||
actions, |
|
||||
children, |
|
||||
}: ModalProps): JSX.Element => { |
|
||||
return ( |
|
||||
<div className="rounded-md overflow-hidden w-full"> |
|
||||
<div className="flex h-12 px-3 bg-slate-200 dark:bg-slate-700 justify-between"> |
|
||||
<h2 className="my-auto font-semibold text-lg">{title}</h2> |
|
||||
{actions && ( |
|
||||
<div className="my-auto">{actions.map((action) => action)}</div> |
|
||||
)} |
|
||||
</div> |
|
||||
<div className="h-full border border-slate-200 dark:border-slate-700"> |
|
||||
{children} |
|
||||
</div> |
|
||||
</div> |
|
||||
); |
|
||||
}; |
|
||||
@ -1,67 +0,0 @@ |
|||||
import type React from "react"; |
|
||||
import { createContext, useContext, useEffect, useState } from "react"; |
|
||||
|
|
||||
type Theme = "light" | "dark" | "system"; |
|
||||
|
|
||||
interface ThemeContextType { |
|
||||
theme: Theme; |
|
||||
setTheme: (theme: Theme) => void; |
|
||||
} |
|
||||
|
|
||||
const ThemeContext = createContext<ThemeContextType | undefined>(undefined); |
|
||||
|
|
||||
export function ThemeProvider({ children }: { children: React.ReactNode }) { |
|
||||
const [theme, setTheme] = useState<Theme>(() => { |
|
||||
if (typeof window !== "undefined") { |
|
||||
const savedTheme = localStorage.getItem("theme") as Theme; |
|
||||
return savedTheme || "system"; |
|
||||
} |
|
||||
return "system"; |
|
||||
}); |
|
||||
|
|
||||
useEffect(() => { |
|
||||
const root = window.document.documentElement; |
|
||||
root.classList.remove("light", "dark"); |
|
||||
|
|
||||
if (theme === "system") { |
|
||||
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") |
|
||||
.matches |
|
||||
? "dark" |
|
||||
: "light"; |
|
||||
root.classList.add(systemTheme); |
|
||||
} else { |
|
||||
root.classList.add(theme); |
|
||||
} |
|
||||
|
|
||||
localStorage.setItem("theme", theme); |
|
||||
}, [theme]); |
|
||||
|
|
||||
useEffect(() => { |
|
||||
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); |
|
||||
|
|
||||
const handleChange = () => { |
|
||||
if (theme === "system") { |
|
||||
const root = window.document.documentElement; |
|
||||
root.classList.remove("light", "dark"); |
|
||||
root.classList.add(mediaQuery.matches ? "dark" : "light"); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
mediaQuery.addEventListener("change", handleChange); |
|
||||
return () => mediaQuery.removeEventListener("change", handleChange); |
|
||||
}, [theme]); |
|
||||
|
|
||||
return ( |
|
||||
<ThemeContext.Provider value={{ theme, setTheme }}> |
|
||||
{children} |
|
||||
</ThemeContext.Provider> |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
export function useTheme() { |
|
||||
const context = useContext(ThemeContext); |
|
||||
if (context === undefined) { |
|
||||
throw new Error("useTheme must be used within a ThemeProvider"); |
|
||||
} |
|
||||
return context; |
|
||||
} |
|
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue