mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-03-28 03:29:25 +01:00
Add a warm charcoal dark mode ("Night Ops") using CSS variable swapping
under [data-theme="dark"]. All 23 desert palette variables are overridden
with dark-mode counterparts, and ~313 generic Tailwind classes (bg-white,
text-gray-*, border-gray-*) are replaced with semantic tokens.
Infrastructure:
- CSS variable overrides in app.css for both themes
- ThemeProvider + useTheme hook (localStorage + KV store sync)
- ThemeToggle component (moon/sun icons, "Night Ops"/"Day Ops" labels)
- FOUC prevention script in inertia_layout.edge
- Toggle placed in StyledSidebar and Footer for access on every page
Color replacements across 50 files:
- bg-white → bg-surface-primary
- bg-gray-50/100 → bg-surface-secondary
- text-gray-900/800 → text-text-primary
- text-gray-600/500 → text-text-secondary/text-text-muted
- border-gray-200/300 → border-border-subtle/border-border-default
- text-desert-white → text-white (fixes invisible text on colored bg)
- Button hover/active states use dedicated btn-green-hover/active vars
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
56 lines
2.0 KiB
TypeScript
56 lines
2.0 KiB
TypeScript
/// <reference path="../../adonisrc.ts" />
|
|
/// <reference path="../../config/inertia.ts" />
|
|
|
|
import '../css/app.css'
|
|
import { createRoot } from 'react-dom/client'
|
|
import { createInertiaApp } from '@inertiajs/react'
|
|
import { resolvePageComponent } from '@adonisjs/inertia/helpers'
|
|
import ModalsProvider from '~/providers/ModalProvider'
|
|
import { TransmitProvider } from 'react-adonis-transmit'
|
|
import { generateUUID } from '~/lib/util'
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
|
import NotificationsProvider from '~/providers/NotificationProvider'
|
|
import { ThemeProvider } from '~/providers/ThemeProvider'
|
|
import { UsePageProps } from '../../types/system'
|
|
|
|
const appName = import.meta.env.VITE_APP_NAME || 'Project N.O.M.A.D.'
|
|
const queryClient = new QueryClient()
|
|
|
|
// Patch the global crypto object for non-HTTPS/localhost contexts
|
|
if (!window.crypto?.randomUUID) {
|
|
// @ts-ignore
|
|
if (!window.crypto) window.crypto = {}
|
|
// @ts-ignore
|
|
window.crypto.randomUUID = generateUUID
|
|
}
|
|
|
|
createInertiaApp({
|
|
progress: { color: '#424420' },
|
|
|
|
title: (title) => `${title} - ${appName}`,
|
|
|
|
resolve: (name) => {
|
|
return resolvePageComponent(`../pages/${name}.tsx`, import.meta.glob('../pages/**/*.tsx'))
|
|
},
|
|
|
|
setup({ el, App, props }) {
|
|
const environment = (props.initialPage.props as unknown as UsePageProps).environment
|
|
const showDevtools = ['development', 'staging'].includes(environment)
|
|
createRoot(el).render(
|
|
<QueryClientProvider client={queryClient}>
|
|
<ThemeProvider>
|
|
<TransmitProvider baseUrl={window.location.origin} enableLogging={true}>
|
|
<NotificationsProvider>
|
|
<ModalsProvider>
|
|
<App {...props} />
|
|
{showDevtools && <ReactQueryDevtools initialIsOpen={false} buttonPosition='bottom-left' />}
|
|
</ModalsProvider>
|
|
</NotificationsProvider>
|
|
</TransmitProvider>
|
|
</ThemeProvider>
|
|
</QueryClientProvider>
|
|
)
|
|
},
|
|
})
|