diff --git a/.github/workflows/publish-extension.yaml b/.github/workflows/publish-extension.yaml index 51dceb4c..2366c13b 100644 --- a/.github/workflows/publish-extension.yaml +++ b/.github/workflows/publish-extension.yaml @@ -31,3 +31,4 @@ jobs: VITE_API_URL: ${{secrets.VITE_API_URL}} VITE_LOGOUT_URL: ${{secrets.VITE_LOGOUT_URL}} VITE_AUTH_GOOGLE_URL: ${{secrets.VITE_AUTH_GOOGLE_URL}} + VITE_LINKING_GOOGLE_ACCOUNT_URL: ${{secrets.VITE_LINKING_GOOGLE_ACCOUNT_URL}} diff --git a/apps/dashboard/src/App.tsx b/apps/dashboard/src/App.tsx index 0ee925a5..720b4c43 100644 --- a/apps/dashboard/src/App.tsx +++ b/apps/dashboard/src/App.tsx @@ -10,7 +10,6 @@ import { ScrollToTopButton } from "@repo/ui/components/scroll-to-top-button"; import { SidebarProvider } from "@repo/ui/components/ui/sidebar"; import { Toaster } from "@repo/ui/components/ui/sonner"; import { TooltipProvider } from "@repo/ui/components/ui/tooltip"; -import { ThemeProvider } from "@repo/ui/providers/theme-provider"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { createTRPCClient, httpBatchLink } from "@trpc/client"; @@ -18,6 +17,7 @@ import { createTRPCClient, httpBatchLink } from "@trpc/client"; import { FallBackRender } from "./components/errors/error-boundary"; import { Wrapper } from "./components/layout/navigation-reset-wrapper"; import { useExtensionWebsocket } from "./hooks/use-extension-websocket"; +import { ThemeProvider } from "./providers/theme-provider"; import { TRPCProvider } from "./utils/trpc"; function makeQueryClient() { diff --git a/apps/dashboard/src/components/layout/header/navbar-dropdowns.tsx b/apps/dashboard/src/components/layout/header/navbar-dropdowns.tsx index bccff17b..c72196cb 100644 --- a/apps/dashboard/src/components/layout/header/navbar-dropdowns.tsx +++ b/apps/dashboard/src/components/layout/header/navbar-dropdowns.tsx @@ -1,11 +1,18 @@ +import { useTheme } from "@/providers/theme-provider"; import { ToggleThemeDropDown } from "@repo/ui/components/toggle-theme-dropdown"; import { AuthDropDown } from "./auth-dropdown"; export const NavbarDropDowns = () => { + const { theme: providedTheme, setTheme, resolvedTheme } = useTheme(); + return (
- +
); diff --git a/apps/dashboard/src/providers/theme-provider.tsx b/apps/dashboard/src/providers/theme-provider.tsx new file mode 100644 index 00000000..813248e6 --- /dev/null +++ b/apps/dashboard/src/providers/theme-provider.tsx @@ -0,0 +1,78 @@ +import { createContext, useContext, useEffect, useState } from "react"; + +import { ResolvedTheme, Theme } from "@repo/ui/types-schemas"; + +type ThemeProviderProps = { + children: React.ReactNode; + defaultTheme?: Theme; + storageKey?: string; +}; + +type ThemeProviderState = { + theme: Theme; + setTheme: (theme: Theme) => void; + resolvedTheme: ResolvedTheme; +}; + +const initialState: ThemeProviderState = { + theme: "system", + setTheme: () => null, + resolvedTheme: "light", +}; + +const ThemeProviderContext = createContext(initialState); + +export const ThemeProvider = ({ + children, + defaultTheme = "system", + storageKey = "vite-ui-theme", + ...props +}: ThemeProviderProps) => { + const [theme, setTheme] = useState( + () => (localStorage.getItem(storageKey) as Theme) || defaultTheme, + ); + const [resolvedTheme, setResolvedTheme] = useState("light"); + + useEffect(() => { + const root = window.document.documentElement; + + root.classList.remove("light", "dark"); + + let newTheme: ResolvedTheme; + + if (theme === "system") { + newTheme = window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + } else { + newTheme = theme; + } + + root.classList.add(newTheme); + setResolvedTheme(newTheme); + }, [theme]); + + const value = { + theme, + resolvedTheme, + setTheme: (theme: Theme) => { + localStorage.setItem(storageKey, theme); + setTheme(theme); + }, + }; + + return ( + + {children} + + ); +}; + +export const useTheme = () => { + const context = useContext(ThemeProviderContext); + + if (context === undefined) + throw new Error("useTheme must be used within a ThemeProvider"); + + return context; +}; diff --git a/apps/vscode-extension/package.json b/apps/vscode-extension/package.json index f5c60f42..0c322e4c 100644 --- a/apps/vscode-extension/package.json +++ b/apps/vscode-extension/package.json @@ -2,7 +2,7 @@ "name": "mooncode", "displayName": "MoonCode", "description": "MoonCode is an extension that tracks your coding time (like WakaTime) and gives you a detailed summary about all your coding statistics. With MoonCode, developers get the full history of their coding activity.", - "version": "0.0.52", + "version": "0.0.54", "icon": "./public/moon.png", "publisher": "Friedrich482", "author": { diff --git a/apps/web/.prettierrc b/apps/web/.prettierrc new file mode 100644 index 00000000..b4bfed35 --- /dev/null +++ b/apps/web/.prettierrc @@ -0,0 +1,3 @@ +{ + "plugins": ["prettier-plugin-tailwindcss"] +} diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index 68a6c64d..070adf93 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -2,6 +2,17 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { output: "standalone", + turbopack: { + rules: { + "*.svg": { + loaders: ["turbopack-inline-svg-loader"], + condition: { + content: /^[\s\S]{0,4000}$/, // <-- Inline SVGs smaller than ~4Kb + }, + as: "*.js", + }, + }, + }, }; export default nextConfig; diff --git a/apps/web/package.json b/apps/web/package.json index e047bea8..f6c599d8 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -9,6 +9,7 @@ "lint": "eslint . --fix" }, "dependencies": { + "@icons-pack/react-simple-icons": "^13.11.1", "@repo/common": "*", "@repo/trpc": "*", "@repo/ui": "*", @@ -18,6 +19,7 @@ "react-dom": "^19.2.0" }, "devDependencies": { + "@svgr/webpack": "^8.1.0", "@types/node": "^20.19.32", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", @@ -25,7 +27,10 @@ "eslint": "^9.39.2", "eslint-config-next": "^16.0.3", "postcss": "^8.5.6", + "prettier": "^3.8.1", + "prettier-plugin-tailwindcss": "^0.6.14", "tailwindcss": "^4.1.17", + "turbopack-inline-svg-loader": "^1.0.3", "typescript": "^5.9.3" }, "overrides": { diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index 4e148e8a..941c1996 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -1,7 +1,10 @@ import type { Metadata } from "next"; -import { ThemeProvider } from "next-themes"; import { Inter } from "next/font/google"; +import { Footer } from "@/components/layout/footer"; +import { Header } from "@/components/layout/header/header"; +import { ThemeProvider } from "@/providers/theme-provider"; + import "@repo/ui/globals.css"; const inter = Inter({ subsets: ["latin"] }); @@ -18,9 +21,17 @@ export default function RootLayout({ }>) { return ( - - + + + +
{children} +