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:
- Remove dependencies:
npm uninstall tailwindcss @tailwindcss/vite
- 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(),
]
});
- 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
- SmartCommon - Component List
- Hooks - Hook Documentation
- Themes - Theme Customization