Tips and Tricks

This page collects tips and best practices for developing with SmartMaker.

Using the Configuration

SmartCommon uses LibConfigProvider to centralize the application configuration.

// src/appConfig.js

export const appConfig = {
  debug: true, // Enable debug logs
  api: {
    prefixUrl: import.meta.env.VITE_API_URL,
    timeout: 30000,
    debug: true
  }
};
// src/App.jsx

import { Provider } from '@cap-rel/smartcommon';
import { appConfig } from './appConfig';

export const App = () => {
  return (
    <Provider config={appConfig}>
      {/* Your application */}
    </Provider>
  );
};

To access the configuration in a component:

import { useLibConfig } from '@cap-rel/smartcommon';

const MyComponent = () => {
  const config = useLibConfig();
  console.log(config.debug); // true
};

Head Component

To modify the page title and meta tags, use react-helmet:

import { Helmet } from 'react-helmet';

export const MyPage = () => {
  return (
    <>
      <Helmet>
        <title>My Page - My App</title>
        <meta name="description" content="My page description" />
      </Helmet>
      {/* Page content */}
    </>
  );
};

Toaster Component

SmartCommon integrates react-hot-toast for notifications.

import toast from 'react-hot-toast';

// Success notification
toast.success('Saved successfully!');

// Error notification
toast.error('An error occurred');

// Custom notification
toast('Neutral message', {
  icon: '👋',
  duration: 4000,
});

// Notification with promise
toast.promise(
  saveData(),
  {
    loading: 'Saving...',
    success: 'Data saved',
    error: 'Save failed',
  }
);

The Toaster is automatically included in SmartCommon's Provider.

Using Environment Variables

In a Vite environment, environment variables must be prefixed with VITE_.

# .env

VITE_API_URL=https://api.example.com
VITE_APP_VERSION=1.0.0
VITE_APP_NAME=My Application

They can then be imported with import.meta.env:

// src/utils/constants/vite.js

export const API_URL     = import.meta.env.VITE_API_URL;
export const APP_VERSION = import.meta.env.VITE_APP_VERSION;
export const APP_NAME    = import.meta.env.VITE_APP_NAME;

Important

Never commit the .env file. Use .env.example as a template.

Public Translation Files

Translation files can be dynamically loaded from the public folder:

public/
  locales/
    fr.json
    en.json
    es.json

i18next Configuration:

// src/i18n/index.js

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import HttpBackend from 'i18next-http-backend';

i18n
  .use(HttpBackend)
  .use(initReactI18next)
  .init({
    fallbackLng: 'fr',
    backend: {
      loadPath: '/locales/{{lng}}.json',
    },
  });

export { i18n };

Namespace Translation Files

To organize translations by feature:

public/
  locales/
    fr/
      common.json
      login.json
      dashboard.json
    en/
      common.json
      login.json
      dashboard.json

Configuration:

i18n.init({
  ns: ['common', 'login', 'dashboard'],
  defaultNS: 'common',
  backend: {
    loadPath: '/locales/{{lng}}/{{ns}}.json',
  },
});

Usage:

const { t } = useTranslation('login');
// or
const { t } = useTranslation(['login', 'common']);

Using Prefixes with useTranslation

To avoid repeating key paths:

// Without prefix
const { t } = useTranslation();
t('loginPage.form.emailInput.label');
t('loginPage.form.emailInput.placeholder');
t('loginPage.form.passwordInput.label');

// With prefix
const { t } = useTranslation('translation', { keyPrefix: 'loginPage.form' });
t('emailInput.label');
t('emailInput.placeholder');
t('passwordInput.label');

Public CSS Files

CSS files in public/ are not processed by Vite and are served as-is:

public/
  css/
    custom-theme.css

To load them dynamically:

// Load a CSS theme at runtime
const loadTheme = (themeName) => {
  const link = document.createElement('link');
  link.rel = 'stylesheet';
  link.href = `/css/${themeName}.css`;
  document.head.appendChild(link);
};

Removing Tailwind CSS

If you do not want to use Tailwind CSS:

  1. Remove dependencies:
npm uninstall tailwindcss @tailwindcss/vite
  1. Modify vite.config.js:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// Remove: import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [
    react(),
    // Remove: tailwindcss(),
  ]
});
  1. Remove Tailwind imports from your CSS files:
/* Remove: @import "tailwindcss"; */

Importing CSS Files Between Each Other

With Tailwind CSS 4

/* src/assets/styles/style.css */

@import "tailwindcss";

@layer theme, base, components;

@import "./theme.css" layer(theme);
@import "./base.css" layer(base);
@import "./components.css" layer(components);

With Classic CSS

/* src/assets/styles/style.css */

@import "./variables.css";
@import "./base.css";
@import "./components.css";

Creating a Theme Change Listener

To detect and react to theme changes (light/dark):

import { useEffect, useState } from 'react';

export const useThemeDetector = () => {
  const [isDark, setIsDark] = useState(
    window.matchMedia('(prefers-color-scheme: dark)').matches
  );

  useEffect(() => {
    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

    const handleChange = (e) => {
      setIsDark(e.matches);
    };

    mediaQuery.addEventListener('change', handleChange);

    return () => mediaQuery.removeEventListener('change', handleChange);
  }, []);

  return isDark;
};

Usage:

const MyComponent = () => {
  const isDarkMode = useThemeDetector();

  return (
    <div className={isDarkMode ? 'dark-theme' : 'light-theme'}>
      Current mode: {isDarkMode ? 'Dark' : 'Light'}
    </div>
  );
};

To manually change the theme with useGlobalStates:

import { useGlobalStates } from '@cap-rel/smartcommon';

const ThemeSwitcher = () => {
  const gst = useGlobalStates();
  const theme = gst.get('settings.theme') || 'light';

  const toggleTheme = () => {
    gst.local.set('settings.theme', theme === 'light' ? 'dark' : 'light');
  };

  useEffect(() => {
    document.documentElement.setAttribute('data-theme', theme);
  }, [theme]);

  return (
    <button onClick={toggleTheme}>
      Switch to {theme === 'light' ? 'dark' : 'light'} mode
    </button>
  );
};

See Also