diff --git a/templates/react-javascript/babel.config.js b/templates/react-javascript/babel.config.cjs
similarity index 100%
rename from templates/react-javascript/babel.config.js
rename to templates/react-javascript/babel.config.cjs
diff --git a/templates/react-javascript/docs/theming.md b/templates/react-javascript/docs/theming.md
new file mode 100644
index 00000000..21f7ef16
--- /dev/null
+++ b/templates/react-javascript/docs/theming.md
@@ -0,0 +1,278 @@
+# RADFish Theming Guide
+
+This guide explains how to customize the look and feel of your RADFish application using USWDS, react-uswds, and RADFish theming.
+
+## Quick Start
+
+All theme customization happens in a single file:
+
+```
+themes/noaa-theme/styles/theme.scss
+```
+
+This file contains three sections:
+1. **USWDS Token Variables** - Design system colors (`$primary`, `$secondary`, etc.)
+2. **CSS Custom Properties** - Additional CSS variables (`:root { --noaa-* }`)
+3. **Component Overrides** - Custom styles for USWDS components
+
+## How It Works
+
+The RADFish theme plugin:
+
+1. **Parses `theme.scss`** and extracts SCSS `$variables` for USWDS configuration
+2. **Pre-compiles USWDS** with your color tokens
+3. **Compiles theme.scss** to CSS for custom properties and component overrides
+4. **Injects CSS** into your app via `` tags in `index.html`
+5. **Watches for changes** and auto-recompiles on save
+
+### Architecture
+
+```
+themes/noaa-theme/
+├── assets/ # Icons and logos
+│ ├── logo.png # Header logo
+│ ├── favicon.ico # Browser favicon
+│ ├── icon-144.png # PWA icon
+│ ├── icon-192.png # PWA icon
+│ └── icon-512.png # PWA icon
+└── styles/
+ └── theme.scss # All theme configuration (edit this)
+
+node_modules/.cache/radfish-theme/noaa-theme/ # Auto-generated (don't edit)
+├── _uswds-entry.scss # Generated USWDS config
+├── uswds-precompiled.css # Compiled USWDS styles
+├── theme.css # Compiled theme overrides
+└── .uswds-cache.json # Cache manifest
+```
+
+## Section 1: USWDS Token Variables
+
+At the top of `theme.scss`, define SCSS variables that configure the USWDS design system:
+
+```scss
+/* themes/noaa-theme/styles/theme.scss */
+
+// Primary colors
+$primary: #0055a4;
+$primary-dark: #00467f;
+$primary-light: #59b9e0;
+
+// Secondary colors
+$secondary: #007eb5;
+$secondary-dark: #006a99;
+
+// State colors
+$error: #d02c2f;
+$success: #4c9c2e;
+$warning: #ff8300;
+$info: #1ecad3;
+
+// Base/neutral colors
+$base-lightest: #ffffff;
+$base-lighter: #e8e8e8;
+$base: #71767a;
+$base-darkest: #333333;
+```
+
+### Available USWDS Tokens
+
+- **Base**: `base-lightest`, `base-lighter`, `base-light`, `base`, `base-dark`, `base-darker`, `base-darkest`
+- **Primary**: `primary-lighter`, `primary-light`, `primary`, `primary-vivid`, `primary-dark`, `primary-darker`
+- **Secondary**: `secondary-lighter`, `secondary-light`, `secondary`, `secondary-vivid`, `secondary-dark`, `secondary-darker`
+- **Accent Cool**: `accent-cool-lighter`, `accent-cool-light`, `accent-cool`, `accent-cool-dark`, `accent-cool-darker`
+- **Accent Warm**: `accent-warm-lighter`, `accent-warm-light`, `accent-warm`, `accent-warm-dark`, `accent-warm-darker`
+- **State**: `info`, `error`, `warning`, `success` (with `-lighter`, `-light`, `-dark`, `-darker` variants)
+- **Disabled**: `disabled-light`, `disabled`, `disabled-dark`
+
+See [USWDS Design Tokens](https://designsystem.digital.gov/design-tokens/color/theme-tokens/) for complete list.
+
+## Section 2: CSS Custom Properties
+
+Add custom CSS variables in the `:root` block for agency-specific colors:
+
+```scss
+/* themes/noaa-theme/styles/theme.scss */
+
+:root {
+ // Brand colors
+ --noaa-process-blue: #0093D0;
+ --noaa-reflex-blue: #0055A4;
+
+ // Regional colors
+ --noaa-region-alaska: #FF8300;
+ --noaa-region-west-coast: #4C9C2E;
+ --noaa-region-southeast: #B2292E;
+}
+```
+
+Use these in your application CSS:
+```css
+.region-badge--alaska {
+ background-color: var(--noaa-region-alaska);
+}
+```
+
+### Auto-Generated CSS Variables
+
+The plugin also auto-generates `--radfish-color-*` variables from your USWDS tokens:
+
+- `--radfish-color-primary`
+- `--radfish-color-secondary`
+- `--radfish-color-error`
+- `--radfish-color-success`
+- etc.
+
+## Section 3: Component Overrides
+
+At the bottom of `theme.scss`, add custom CSS for USWDS components:
+
+```scss
+/* themes/noaa-theme/styles/theme.scss */
+
+/* Header Background */
+.usa-header.header-container,
+header.usa-header {
+ background-color: var(--radfish-color-primary);
+}
+
+/* Custom button styles */
+.usa-button {
+ border-radius: 8px;
+ font-weight: 600;
+}
+
+/* Custom card styles */
+.usa-card {
+ border-color: #ddd;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+```
+
+### Available USWDS Components
+
+**Layout & Navigation**: `usa-header`, `usa-footer`, `usa-sidenav`, `usa-breadcrumb`, `usa-banner`
+
+**Forms & Inputs**: `usa-button`, `usa-input`, `usa-checkbox`, `usa-radio`, `usa-select`, `usa-form`
+
+**Content & Display**: `usa-card`, `usa-alert`, `usa-table`, `usa-list`, `usa-accordion`, `usa-tag`
+
+**Interactive**: `usa-modal`, `usa-tooltip`, `usa-pagination`
+
+## Developer Styles
+
+For application-specific styles (not theme-related), use:
+
+```
+src/styles/style.css
+```
+
+This file is loaded after theme styles, so you can override anything:
+
+```css
+/* src/styles/style.css */
+
+.dashboard-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 2rem;
+}
+
+.fish-data-card {
+ background: var(--radfish-color-base-lightest);
+ border: 1px solid #ddd;
+ padding: 1.5rem;
+}
+```
+
+## Configuration
+
+In `vite.config.js`, configure the app name and description:
+
+```javascript
+const configOverrides = {
+ app: {
+ name: "My App Name",
+ shortName: "MyApp",
+ description: "App description for PWA",
+ },
+};
+
+radFishThemePlugin("noaa-theme", configOverrides)
+```
+
+The theme name matches the folder in `themes/` directory.
+
+## Changing Assets
+
+Replace files in `themes/noaa-theme/assets/` to customize:
+
+| File | Purpose | Recommended Size |
+|------|---------|------------------|
+| `logo.png` | Header logo | Height ~48-72px |
+| `favicon.ico` | Browser tab icon | 64x64, 32x32, 16x16 |
+| `icon-144.png` | PWA icon | 144x144 |
+| `icon-192.png` | PWA icon | 192x192 |
+| `icon-512.png` | PWA icon/splash | 512x512 |
+
+## Creating a New Theme
+
+1. Create theme folder:
+ ```bash
+ mkdir -p themes/my-agency/assets themes/my-agency/styles
+ ```
+
+2. Add assets to `themes/my-agency/assets/`:
+ - `logo.png`, `favicon.ico`, `icon-144.png`, `icon-192.png`, `icon-512.png`
+
+3. Copy and customize the theme file:
+ ```bash
+ cp themes/noaa-theme/styles/theme.scss themes/my-agency/styles/
+ ```
+
+4. Update `vite.config.js`:
+ ```javascript
+ radFishThemePlugin("my-agency", {
+ app: { name: "My Agency App" }
+ })
+ ```
+
+5. Restart the dev server
+
+## CSS Load Order
+
+Styles are loaded in this order:
+
+1. **uswds-precompiled.css** - USWDS with your color tokens
+2. **theme.css** - Your CSS custom properties and component overrides
+3. **src/styles/style.css** - Your application styles
+
+This ensures correct CSS cascade: USWDS base → Theme overrides → App styles
+
+## Troubleshooting
+
+### Changes not appearing?
+
+- Save `theme.scss` - the dev server auto-restarts on changes
+- Clear browser cache: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac)
+- Restart dev server: `npm start`
+
+### Styles not applying?
+
+- Check CSS specificity - you may need more specific selectors
+- Inspect element in DevTools to see which styles are being applied
+- Ensure your selectors match USWDS class names exactly
+
+### Cache issues?
+
+Delete the cache folder and restart:
+```bash
+rm -rf node_modules/.cache/radfish-theme
+npm start
+```
+
+## Additional Resources
+
+- [USWDS Design System](https://designsystem.digital.gov/)
+- [USWDS Design Tokens](https://designsystem.digital.gov/design-tokens/)
+- [USWDS Components](https://designsystem.digital.gov/components/)
+- [React USWDS (Trussworks)](https://trussworks.github.io/react-uswds/)
diff --git a/templates/react-javascript/index.html b/templates/react-javascript/index.html
index 565b3820..2a69826e 100644
--- a/templates/react-javascript/index.html
+++ b/templates/react-javascript/index.html
@@ -2,16 +2,16 @@
-
+
-
-
+
+
-
+
+
+ `;
+
+ // Generate CSS variables from config
+ const cssVariables = `
+ `;
+
+ return html
+ .replace("", `${cssImports}\n${cssVariables}\n `)
+ .replace(
+ /.*?<\/title>/,
+ `${config.app.shortName}`,
+ )
+ .replace(
+ //,
+ ``,
+ )
+ .replace(
+ //,
+ ``,
+ )
+ .replace(
+ //,
+ ``,
+ )
+ .replace(
+ //,
+ ``,
+ );
+ },
+
+ // Write manifest.json after build completes
+ closeBundle() {
+ if (!config || !resolvedViteConfig) return;
+
+ // Only write manifest for build, not serve
+ const outDir = resolvedViteConfig.build?.outDir || "dist";
+ const outDirPath = path.resolve(resolvedViteConfig.root, outDir);
+ const manifestPath = path.resolve(outDirPath, "manifest.json");
+
+ // Ensure output directory exists
+ if (!fs.existsSync(outDirPath)) {
+ return; // Build hasn't created output dir yet
+ }
+
+ // Copy theme assets to dist/icons if using theme directory
+ if (themeDir) {
+ const themeAssetsDir = path.join(themeDir, "assets");
+ const distIconsDir = path.join(outDirPath, "icons");
+ if (fs.existsSync(themeAssetsDir)) {
+ copyDirSync(themeAssetsDir, distIconsDir);
+ console.log("[radfish-theme] Copied theme assets to:", distIconsDir);
+ }
+
+ // Copy pre-compiled CSS files to dist/radfish-theme/
+ const cacheDir = getCacheDir(themeName);
+ const distThemeDir = path.join(outDirPath, "radfish-theme");
+ if (fs.existsSync(cacheDir)) {
+ if (!fs.existsSync(distThemeDir)) {
+ fs.mkdirSync(distThemeDir, { recursive: true });
+ }
+ const cssFiles = ["uswds-precompiled.css", "theme.css"];
+ for (const cssFile of cssFiles) {
+ const srcPath = path.join(cacheDir, cssFile);
+ const destPath = path.join(distThemeDir, cssFile);
+ if (fs.existsSync(srcPath)) {
+ fs.copyFileSync(srcPath, destPath);
+ }
+ }
+ console.log("[radfish-theme] Copied CSS files to:", distThemeDir);
+ }
+ }
+
+ const manifest = {
+ short_name: config.app.shortName,
+ name: config.app.name,
+ description: config.app.description,
+ icons: getManifestIcons(),
+ start_url: ".",
+ display: "standalone",
+ theme_color: config.pwa.themeColor,
+ background_color: config.pwa.backgroundColor,
+ };
+
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
+ console.log("[radfish-theme] Wrote manifest.json to", manifestPath);
+ },
+ };
+}
diff --git a/templates/react-javascript/src/App.jsx b/templates/react-javascript/src/App.jsx
index d333f639..4c8c0543 100644
--- a/templates/react-javascript/src/App.jsx
+++ b/templates/react-javascript/src/App.jsx
@@ -1,10 +1,31 @@
+/**
+ * App.jsx - Main Application Component
+ *
+ * Welcome to RADFish! This is the entry point for your application.
+ *
+ * This file sets up:
+ * - The Application wrapper (provides offline storage, state management)
+ * - Header with navigation
+ * - React Router for page routing
+ *
+ * Quick Start:
+ * 1. Add new pages in src/pages/
+ * 2. Add routes in the section below
+ * 3. Add navigation links in the PrimaryNav items array
+ *
+ * Theme customization:
+ * - Edit themes/noaa-theme/styles/theme.scss for colors and styles
+ * - App name and icons are configured in the theme plugin (vite.config.js)
+ *
+ * Learn more: https://nmfs-radfish.github.io/radfish/
+ */
+
import "./index.css";
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
import { useState } from "react";
import { Application } from "@nmfs-radfish/react-radfish";
import {
GridContainer,
- Title,
NavMenuButton,
PrimaryNav,
Header,
@@ -14,6 +35,7 @@ import HomePage from "./pages/Home";
function App({ application }) {
const [isExpanded, setExpanded] = useState(false);
+
return (
@@ -21,6 +43,7 @@ function App({ application }) {
+ {/* Header - Uses USWDS Header component */}
+
+ {/* Main Content Area */}
} />
+ {/* Add more routes here:
+ } />
+ */}
diff --git a/templates/react-javascript/src/index.css b/templates/react-javascript/src/index.css
index 3bfaa65a..2b4fe62f 100644
--- a/templates/react-javascript/src/index.css
+++ b/templates/react-javascript/src/index.css
@@ -1,6 +1,13 @@
-/* trussworks component styles */
-@import "@trussworks/react-uswds/lib/uswds.css";
-@import "@trussworks/react-uswds/lib/index.css";
+/* Main CSS Entry Point */
+/*
+ * Theme CSS imports (USWDS, theme-components, theme-overrides) are
+ * automatically injected by the RADFish Vite plugin into index.html.
+ *
+ * This file is for developer-specific styles only.
+ */
+
+/* Developer's page-level custom styles */
+@import "./styles/style.css";
/* normalize css */
body {
@@ -21,6 +28,24 @@ body {
width: 100%;
}
+.header-logo-link {
+ display: flex;
+ align-items: center;
+}
+
+.header-logo {
+ height: 48px;
+ width: auto;
+}
+
+/* Keep menu button on the right on mobile/tablet */
+.usa-navbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+}
+
@media (min-width: 64em) {
.usa-nav__primary button[aria-expanded=false] span:after {
background: white;
diff --git a/templates/react-javascript/src/index.jsx b/templates/react-javascript/src/index.jsx
index 5ed01d1f..bd0efb23 100644
--- a/templates/react-javascript/src/index.jsx
+++ b/templates/react-javascript/src/index.jsx
@@ -1,12 +1,15 @@
import React from "react";
import ReactDOM from "react-dom/client";
-import "./styles/theme.css";
import App from "./App";
import { Application } from "@nmfs-radfish/radfish";
const root = ReactDOM.createRoot(document.getElementById("root"));
-const app = new Application();
+const app = new Application({
+ serviceWorker: {
+ url: "/service-worker.js",
+ },
+});
app.on("ready", async () => {
root.render(
diff --git a/templates/react-javascript/src/pages/Home.jsx b/templates/react-javascript/src/pages/Home.jsx
index 2a993a26..85dc0bd0 100644
--- a/templates/react-javascript/src/pages/Home.jsx
+++ b/templates/react-javascript/src/pages/Home.jsx
@@ -1,24 +1,81 @@
+/**
+ * Home.jsx - Welcome Page
+ *
+ * This is the default home page for your RADFish application.
+ * Replace this content with your own!
+ */
+
import "../index.css";
-import React from "react";
import { Button } from "@trussworks/react-uswds";
import { Link } from "react-router-dom";
function HomePage() {
return (
-
-

-
- Edit src/App.js and save to reload.
-
-
-
-
-
-
-
+
+
Welcome to RADFish
+
+
+ You're ready to start building your fisheries data collection application.
+ This template includes everything you need to get started.
+
+
+
Quick Start
+
+ -
+ Edit
vite.config.js to change app name and description
+
+ -
+ Edit
src/App.jsx to modify the header and navigation
+
+ -
+ Edit
src/pages/Home.jsx to change this page
+
+ -
+ Replace images in
themes/noaa-theme/assets/ to change logo and favicon
+
+
+
+
What's Included
+
+ -
+ USWDS Components - U.S. Web Design System via react-uswds
+
+ -
+ Offline Storage - IndexedDB for offline-first data collection
+
+ -
+ Theming - Customizable NOAA brand colors and styles
+
+ -
+ PWA Ready - Progressive Web App support for mobile deployment
+
+
+
+
Resources
+
+
+
+ {" "}
+
+
+ {" "}
+
+
+ {" "}
+
+
+
+
+
);
}
diff --git a/templates/react-javascript/src/styles/style.css b/templates/react-javascript/src/styles/style.css
new file mode 100644
index 00000000..4d9fdea9
--- /dev/null
+++ b/templates/react-javascript/src/styles/style.css
@@ -0,0 +1,37 @@
+/**
+ * Developer Page-Level Custom Styles
+ *
+ * Add your application-specific page and layout styles here.
+ * This file is for styling YOUR OWN pages/layouts, NOT theme config or component overrides.
+ *
+ * For different types of customization:
+ * - USWDS theme colors → themes//styles/theme.scss (Section 1)
+ * - RADFish components → themes//styles/theme.scss (Section 2)
+ * - react-uswds overrides → themes//styles/theme.scss (Section 3)
+ * - Page/layout styles → THIS FILE
+ *
+ * Examples:
+ */
+
+/* Page-specific layouts
+.dashboard-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 2rem;
+}
+*/
+
+/* Custom application components
+.fish-data-card {
+ background: var(--radfish-background);
+ border: 1px solid var(--radfish-border-light);
+ padding: 1.5rem;
+}
+
+.catch-summary-badge {
+ background-color: var(--radfish-primary);
+ color: white;
+ padding: 0.25rem 0.75rem;
+ border-radius: 4px;
+}
+*/
\ No newline at end of file
diff --git a/templates/react-javascript/src/styles/theme.css b/templates/react-javascript/src/styles/theme.css
deleted file mode 100644
index 92b1e2d3..00000000
--- a/templates/react-javascript/src/styles/theme.css
+++ /dev/null
@@ -1,37 +0,0 @@
-:root {
- --noaa-dark-blue: #0054a4;
- --noaa-light-blue: #0093d0;
- --noaa-yellow-one: #fff3cd;
- --noaa-yellow-two: #ffeeba;
- --noaa-yellow-three: #856404;
- --noaa-accent-color: #00467f;
- --noaa-text-color: #333;
- --noaa-error-color: #af292e;
- --noaa-button-hover: #0073b6;
- --noaa-label-color: #0054a4;
- --noaa-border-dark: #565c65;
- --noaa-border-light: #ddd;
-}
-
-body {
- font-family:
- Arial Narrow,
- sans-serif;
- color: var(--noaa-text-color);
- background-color: #f4f4f4;
- line-height: 1.6;
- border-radius: 4px;
-}
-
-.header-container {
- background: var(--noaa-dark-blue);
-}
-
-.header-title {
- color: white;
-}
-
-/* Minimum size for NOAA logo must be 72px (0.75 in) */
-.header-logo {
- width: 72px;
-}
diff --git a/templates/react-javascript/themes/noaa-theme/assets/favicon.ico b/templates/react-javascript/themes/noaa-theme/assets/favicon.ico
new file mode 100644
index 00000000..b3daf0af
Binary files /dev/null and b/templates/react-javascript/themes/noaa-theme/assets/favicon.ico differ
diff --git a/templates/react-javascript/themes/noaa-theme/assets/icon-144.png b/templates/react-javascript/themes/noaa-theme/assets/icon-144.png
new file mode 100644
index 00000000..e82b34ba
Binary files /dev/null and b/templates/react-javascript/themes/noaa-theme/assets/icon-144.png differ
diff --git a/templates/react-javascript/themes/noaa-theme/assets/icon-192.png b/templates/react-javascript/themes/noaa-theme/assets/icon-192.png
new file mode 100644
index 00000000..0457a794
Binary files /dev/null and b/templates/react-javascript/themes/noaa-theme/assets/icon-192.png differ
diff --git a/templates/react-javascript/themes/noaa-theme/assets/icon-512.png b/templates/react-javascript/themes/noaa-theme/assets/icon-512.png
new file mode 100644
index 00000000..3bb3ed58
Binary files /dev/null and b/templates/react-javascript/themes/noaa-theme/assets/icon-512.png differ
diff --git a/templates/react-javascript/themes/noaa-theme/assets/logo.png b/templates/react-javascript/themes/noaa-theme/assets/logo.png
new file mode 100644
index 00000000..3c797585
Binary files /dev/null and b/templates/react-javascript/themes/noaa-theme/assets/logo.png differ
diff --git a/templates/react-javascript/themes/noaa-theme/styles/theme.scss b/templates/react-javascript/themes/noaa-theme/styles/theme.scss
new file mode 100644
index 00000000..f002e472
--- /dev/null
+++ b/templates/react-javascript/themes/noaa-theme/styles/theme.scss
@@ -0,0 +1,244 @@
+/**
+ * NOAA Fisheries Brand Theme
+ *
+ * This single file contains all theme configuration:
+ * 1. USWDS Token Variables ($variables) - extracted by the RADFish plugin for USWDS configuration
+ * 2. CSS Custom Properties (:root) - additional NOAA-specific variables
+ * 3. Component Overrides - custom styles for USWDS/RADFish components
+ *
+ * NOAA Palette → USWDS Token Mapping:
+ * NOAA Dark Blue (Reflex Blue #0055A4) → primary-*
+ * NOAA Light Blue (Process Blue #0093D0) → secondary-*
+ * URCHIN (Purples) → accent-cool-*
+ * CRUSTACEAN (Orange) → accent-warm-*
+ * SEAGRASS (Greens) → success-*
+ * CORAL (Reds) → error-*
+ * Neutrals → base-*
+ */
+
+// =============================================================================
+// SECTION 1: USWDS TOKEN VARIABLES
+// These $variables are extracted by the RADFish plugin and fed to USWDS.
+// They configure the design system colors but don't produce CSS output directly.
+// =============================================================================
+
+// -----------------------------------------------------------------------------
+// BASE COLORS - NOAA Neutrals
+// -----------------------------------------------------------------------------
+$base-lightest: #ffffff;
+$base-lighter: #e8e8e8;
+$base-light: #d0d0d0;
+$base: #71767a; // USWDS gray-50 (better contrast)
+$base-dark: #7b7b7b;
+$base-darker: #4a4a4a; // Darkened for AA contrast with base-lighter links
+$base-darkest: #333333;
+
+// -----------------------------------------------------------------------------
+// PRIMARY - NOAA Dark Blue (Reflex Blue)
+// Main brand color from NOAA Fisheries Primary Palette
+// -----------------------------------------------------------------------------
+$primary-lighter: #b2def1; // 15% tint
+$primary-light: #59b9e0; // 30% tint
+$primary: #0055a4; // Reflex Blue - NOAA Dark Blue (main brand)
+$primary-vivid: #0055a4; // Reflex Blue
+$primary-dark: #00467f; // Navy Blue (Pantone 541)
+$primary-darker: #002d4d; // Darker Navy
+
+// -----------------------------------------------------------------------------
+// SECONDARY - NOAA Light Blue (Process Blue)
+// From NOAA Fisheries Primary Palette
+// -----------------------------------------------------------------------------
+$secondary-lighter: #d9eff8; // 15% tint
+$secondary-light: #59b9e0; // 30% tint
+$secondary: #007eb5; // Darkened Process Blue for AA contrast
+$secondary-vivid: #0093d0; // Process Blue (original)
+$secondary-dark: #006a99; // Darker for AA contrast with white text
+$secondary-darker: #00557a; // Darkest Process Blue
+
+// -----------------------------------------------------------------------------
+// ACCENT-COOL - URCHIN (Purples)
+// -----------------------------------------------------------------------------
+$accent-cool-lighter: #c9c9ff; // Light tint
+$accent-cool-light: #9f9fff; // Mid tint
+$accent-cool: #5a5ae6; // Darkened for AA contrast with white text
+$accent-cool-dark: #625bc4; // PMS 2725
+$accent-cool-darker: #575195; // PMS 7670
+
+// -----------------------------------------------------------------------------
+// ACCENT-WARM - CRUSTACEAN (Oranges)
+// -----------------------------------------------------------------------------
+$accent-warm-lighter: #ffd9b3; // Light tint
+$accent-warm-light: #ffb366; // Mid tint
+$accent-warm: #ff8300; // PMS 151
+$accent-warm-dark: #b54d00; // Darkened for AA contrast with white text
+$accent-warm-darker: #bc4700; // PMS 1525
+
+// -----------------------------------------------------------------------------
+// STATE COLORS
+// -----------------------------------------------------------------------------
+
+// INFO - WAVES (Teal)
+$info-lighter: #e0f7f8;
+$info-light: #5de0e6;
+$info: #1ecad3; // PMS 319
+$info-dark: #008998; // PMS 321
+$info-darker: #007078; // PMS 322
+
+// ERROR - CORAL (Red)
+$error-lighter: #ffe5e4;
+$error-light: #ff7a73;
+$error: #d02c2f; // PMS 711
+$error-dark: #b2292e; // PMS 1805
+$error-darker: #8b1f24;
+
+// WARNING - CRUSTACEAN (Orange)
+$warning-lighter: #fff3e0;
+$warning-light: #ffd9b3;
+$warning: #ff8300; // PMS 151
+$warning-dark: #d65f00; // PMS 717
+$warning-darker: #bc4700; // PMS 1525
+
+// SUCCESS - SEAGRASS (Greens)
+$success-lighter: #e8f5d6; // Light tint
+$success-light: #b8e67d; // Mid tint
+$success: #93d500; // PMS 375
+$success-dark: #4c9c2e; // PMS 362
+$success-darker: #007934; // PMS 356
+
+// -----------------------------------------------------------------------------
+// DISABLED STATE
+// -----------------------------------------------------------------------------
+$disabled-light: #e8e8e8;
+$disabled: #d0d0d0;
+$disabled-dark: #9a9a9a;
+
+
+// =============================================================================
+// SECTION 2: CSS CUSTOM PROPERTIES
+// These extend the USWDS theme tokens for NOAA-specific needs.
+// Available throughout your application via var(--noaa-*).
+// =============================================================================
+
+:root {
+ // ---------------------------------------------------------------------------
+ // NOAA PRIMARY BRAND COLORS (Direct Access)
+ // For cases where you need exact brand colors
+ // ---------------------------------------------------------------------------
+ --noaa-process-blue: #0093D0; // NOAA Light Blue
+ --noaa-reflex-blue: #0055A4; // NOAA Dark Blue
+ --noaa-navy-blue: #00467F; // PMS 541
+
+ // ---------------------------------------------------------------------------
+ // REGIONAL WEB COLORS
+ // For region-specific styling, badges, and indicators
+ // ---------------------------------------------------------------------------
+ --noaa-region-national: #0055A4; // Blue (Reflex Blue)
+ --noaa-region-west-coast: #4C9C2E; // Green (PMS 362)
+ --noaa-region-southeast: #B2292E; // Red (PMS 1805)
+ --noaa-region-alaska: #FF8300; // Orange (PMS 151)
+ --noaa-region-pacific-islands: #625BC4; // Purple (PMS 2725)
+ --noaa-region-mid-atlantic: #625BC4; // Purple (PMS 2725)
+
+ // ---------------------------------------------------------------------------
+ // THEME PALETTE QUICK ACCESS
+ // All six NOAA theme palettes for easy reference
+ // ---------------------------------------------------------------------------
+
+ // OCEANS (mapped to primary-*)
+ --noaa-oceans-light: #0093D0;
+ --noaa-oceans: #0055A4;
+ --noaa-oceans-dark: #00467F;
+
+ // WAVES (mapped to accent-cool-*)
+ --noaa-waves-light: #1ECAD3;
+ --noaa-waves: #008998;
+ --noaa-waves-dark: #007078;
+
+ // SEAGRASS (mapped to success-*)
+ --noaa-seagrass-light: #93D500;
+ --noaa-seagrass: #4C9C2E;
+ --noaa-seagrass-dark: #007934;
+
+ // CRUSTACEAN (mapped to accent-warm-*)
+ --noaa-crustacean-light: #FF8300;
+ --noaa-crustacean: #D65F00;
+ --noaa-crustacean-dark: #BC4700;
+
+ // CORAL (mapped to secondary-*)
+ --noaa-coral-light: #FF4438;
+ --noaa-coral: #D02C2F;
+ --noaa-coral-dark: #B2292E;
+}
+
+
+// =============================================================================
+// SECTION 3: COMPONENT OVERRIDES
+// Customize RADFish and USWDS components here.
+//
+// Available CSS variables (injected by RADFish plugin):
+// var(--radfish-color-primary) - Primary brand color
+// var(--radfish-color-primary-dark) - Darker primary
+// var(--radfish-color-secondary) - Secondary color
+// var(--radfish-color-secondary-dark) - Darker secondary
+// var(--radfish-color-accent-cool) - Cool accent (teal)
+// var(--radfish-color-accent-warm) - Warm accent (orange)
+// var(--radfish-color-base-lightest) - Lightest gray
+// var(--radfish-color-error) - Error red
+// var(--radfish-color-success) - Success green
+// var(--radfish-color-warning) - Warning orange
+//
+// Available react-uswds components to override:
+// Layout & Navigation: usa-header, usa-footer, usa-sidenav, usa-breadcrumb
+// Forms & Inputs: usa-button, usa-input, usa-checkbox, usa-radio, usa-select
+// Content & Display: usa-card, usa-alert, usa-table, usa-list, usa-accordion
+// Interactive: usa-modal, usa-tooltip, usa-pagination, usa-language-selector
+//
+// See: https://designsystem.digital.gov/components/overview/
+// =============================================================================
+
+// -----------------------------------------------------------------------------
+// HEADER
+// -----------------------------------------------------------------------------
+
+/* Header Background */
+.usa-header.usa-header--basic.header-container,
+.usa-header.header-container,
+header.usa-header {
+ background-color: var(--radfish-color-primary);
+}
+
+/* Header Logo Width - Minimum 72px for agency logos */
+
+// -----------------------------------------------------------------------------
+// EXAMPLE OVERRIDES (uncomment to use)
+// -----------------------------------------------------------------------------
+
+/* Example: Regional badge styling */
+/*
+.region-badge {
+ padding: 0.25rem 0.75rem;
+ border-radius: 4px;
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: white;
+}
+
+.region-badge--national { background-color: var(--noaa-region-national); }
+.region-badge--west-coast { background-color: var(--noaa-region-west-coast); }
+.region-badge--southeast { background-color: var(--noaa-region-southeast); }
+.region-badge--alaska { background-color: var(--noaa-region-alaska); }
+.region-badge--pacific-islands { background-color: var(--noaa-region-pacific-islands); }
+.region-badge--mid-atlantic { background-color: var(--noaa-region-mid-atlantic); }
+*/
+
+/* Example: Custom button styles */
+/* .usa-button {
+ border-radius: 8px;
+ font-weight: 600;
+} */
+
+/* Example: Custom card styles */
+/* .usa-card {
+ border-color: color("base-light");
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+} */
diff --git a/templates/react-javascript/vite.config.js b/templates/react-javascript/vite.config.js
index e5d836a4..66cfc900 100644
--- a/templates/react-javascript/vite.config.js
+++ b/templates/react-javascript/vite.config.js
@@ -1,11 +1,75 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { VitePWA } from "vite-plugin-pwa";
+import path from "path";
+import { radFishThemePlugin, getDefaultConfig } from "./plugins/vite-plugin-radfish-theme.js";
-export default defineConfig((env) => ({
+/**
+ * RADFish Theme Configuration
+ *
+ * IMPORTANT: Change theme settings in ONE place:
+ * themes/noaa-theme/styles/theme.scss
+ *
+ * The radFishThemePlugin automatically:
+ * - Parses theme.scss and generates _uswds-generated.scss
+ * - Injects CSS variables into index.html
+ * - Updates index.html meta tags
+ * - Provides values to PWA manifest (below)
+ *
+ * Usage:
+ * radFishThemePlugin("noaa-theme") // Use default NOAA theme
+ * radFishThemePlugin("noaa-theme", { app: {...} }) // With app config overrides
+ *
+ * Available themes (in themes/ folder):
+ * - noaa-theme: Default NOAA branding with USWDS colors
+ */
+
+// Get default config (includes parsed colors as fallback)
+const defaultConfig = getDefaultConfig();
+
+// Define config overrides here (app name, description)
+// NOTE: Colors automatically come from themes//styles/theme.scss (Section 1)
+const configOverrides = {
+ app: {
+ name: "RADFish App",
+ shortName: "RADFish",
+ description: "Offline-first fisheries data collection built with RADFish",
+ },
+ pwa: {
+ // NOTE: The PWA manifest theme_color is dynamically generated by radFishThemePlugin
+ // It reads the actual color from themes//styles/theme.scss (Section 1)
+ // The defaultConfig.colors.primary below is just a fallback used during config parsing
+ // In dev mode: manifest.json is served via configureServer hook with parsed colors
+ // In build: manifest.json is written via closeBundle hook with parsed colors
+ themeColor: defaultConfig.colors.primary,
+ },
+};
+
+export default defineConfig({
base: "/",
+ resolve: {
+ alias: {
+ '@theme': path.resolve(__dirname, 'themes/noaa-theme/styles'),
+ },
+ },
+ css: {
+ preprocessorOptions: {
+ scss: {
+ includePaths: ["node_modules/@uswds/uswds/packages"],
+ // Suppress USWDS deprecation warnings about global built-in functions
+ // These are from USWDS using map-merge() which will be fixed in Dart Sass 3.0.0
+ quietDeps: true,
+ },
+ },
+ },
plugins: [
+ // RADFish theme plugin - provides:
+ // - import.meta.env.RADFISH_* constants
+ // - CSS variable injection
+ // - manifest.json generation on build
+ radFishThemePlugin("noaa-theme", configOverrides),
react(),
+ // VitePWA for service worker
VitePWA({
devOptions: {
enabled: process.env.NODE_ENV === "development",
@@ -16,66 +80,15 @@ export default defineConfig((env) => ({
strategies: "injectManifest",
srcDir: "src",
filename: "service-worker.js",
+ // Manifest configuration (synced with radFishThemePlugin configOverrides)
manifest: {
- short_name: "RADFish",
- name: "RADFish React Boilerplate",
- icons: [
- {
- src: "icons/radfish.ico",
- sizes: "512x512 256x256 144x144 64x64 32x32 24x24 16x16",
- type: "image/x-icon",
- },
- {
- src: "icons/radfish-144.ico",
- sizes: "144x144 64x64 32x32 24x24 16x16",
- type: "image/x-icon",
- },
- {
- src: "icons/radfish-144.ico",
- type: "image/icon",
- sizes: "144x144",
- purpose: "any",
- },
- {
- src: "icons/radfish-192.ico",
- type: "image/icon",
- sizes: "192x192",
- purpose: "any",
- },
- {
- src: "icons/radfish-512.ico",
- type: "image/icon",
- sizes: "512x512",
- purpose: "any",
- },
- {
- src: "icons/144.png",
- type: "image/png",
- sizes: "144x144",
- purpose: "any",
- },
- {
- src: "icons/144.png",
- type: "image/png",
- sizes: "144x144",
- purpose: "maskable",
- },
- {
- src: "icons/192.png",
- type: "image/png",
- sizes: "192x192",
- purpose: "maskable",
- },
- {
- src: "icons/512.png",
- type: "image/png",
- sizes: "512x512",
- purpose: "maskable",
- },
- ],
- start_url: ".",
+ short_name: configOverrides.app.shortName,
+ name: configOverrides.app.name,
+ description: configOverrides.app.description,
+ start_url: "/",
display: "standalone",
- theme_color: "#000000",
+ scope: "/",
+ theme_color: configOverrides.pwa.themeColor,
background_color: "#ffffff",
},
}),
@@ -89,4 +102,4 @@ export default defineConfig((env) => ({
setupFiles: "./src/__tests__/setup.js",
environment: "jsdom",
},
-}));
+});