another step for constructing base project
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { COOKIE_NAMES } from '@/lib/cookies';
|
||||
|
||||
/**
|
||||
* Inline synchronous script placed in <head> — runs before any paint.
|
||||
*
|
||||
* Two jobs:
|
||||
* 1. Set data-mui-color-scheme on <html> from our cookie, so the server-set
|
||||
* attribute and the first-paint attribute always agree (no flash).
|
||||
* 2. Patch Storage.prototype so MUI v9's internal localStorage reads for key
|
||||
* 'mode' return null (forcing MUI to use the defaultMode prop we derive
|
||||
* from the cookie on the server) and writes to 'mode' are routed to our
|
||||
* cookie instead of localStorage.
|
||||
*
|
||||
* Why patch Storage.prototype instead of storageWindow={null}?
|
||||
* In MUI v9 localStorageManager: `if (!storageWindow && typeof window !== 'undefined') {
|
||||
* storageWindow = window; }` — null is falsy, so storageWindow={null} is silently
|
||||
* overridden to window in the browser. The prototype patch is the only reliable way.
|
||||
*/
|
||||
export function ColorSchemeScript() {
|
||||
const cookieName = COOKIE_NAMES.COLOR_SCHEME; // 'color-scheme'
|
||||
const maxAge = 60 * 60 * 24 * 365;
|
||||
// MUI v9 default modeStorageKey (InitColorSchemeScript.mjs: DEFAULT_MODE_STORAGE_KEY = 'mode')
|
||||
const muiModeKey = 'mode';
|
||||
|
||||
const script =
|
||||
`(function(){` +
|
||||
// ── 1. Set attribute from cookie before first paint ─────────────────────
|
||||
`var m=document.cookie.match(/(^|;)\\s*${cookieName}=([^;]*)/);` +
|
||||
`var s=m?decodeURIComponent(m[2]):(window.matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light');` +
|
||||
`document.documentElement.setAttribute('data-mui-color-scheme',s==='dark'?'dark':'light');` +
|
||||
// ── 2. Intercept Storage so MUI never touches localStorage ───────────────
|
||||
`try{` +
|
||||
`var _s=Storage.prototype.setItem,_g=Storage.prototype.getItem,_r=Storage.prototype.removeItem;` +
|
||||
`Storage.prototype.setItem=function(k,v){` +
|
||||
`if(this===window.localStorage&&k==='${muiModeKey}'){` +
|
||||
`if(v==='dark'||v==='light')document.cookie='${cookieName}='+v+';path=/;max-age=${maxAge};samesite=lax';` +
|
||||
`else document.cookie='${cookieName}=;path=/;max-age=0';` +
|
||||
`return;}` +
|
||||
`_s.call(this,k,v);};` +
|
||||
`Storage.prototype.getItem=function(k){` +
|
||||
`if(this===window.localStorage&&k==='${muiModeKey}')return null;` +
|
||||
`return _g.call(this,k);};` +
|
||||
`Storage.prototype.removeItem=function(k){` +
|
||||
`if(this===window.localStorage&&k==='${muiModeKey}'){` +
|
||||
`document.cookie='${cookieName}=;path=/;max-age=0';return;}` +
|
||||
`_r.call(this,k);};` +
|
||||
`}catch(e){}` +
|
||||
`})();`;
|
||||
|
||||
// eslint-disable-next-line react/no-danger
|
||||
return <script dangerouslySetInnerHTML={{ __html: script }} />;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { AppRouterCacheProvider } from '@mui/material-nextjs/v13-appRouter';
|
||||
import { FunctionComponent, PropsWithChildren } from 'react';
|
||||
|
||||
/**
|
||||
* Platform-specific ThemeProvider for Next.js
|
||||
* @component MuiThemeProviderForNextJs
|
||||
*/
|
||||
const MuiThemeProviderForNextJs: FunctionComponent<PropsWithChildren> = ({ children }) => {
|
||||
return <AppRouterCacheProvider>{children}</AppRouterCacheProvider>;
|
||||
};
|
||||
|
||||
export default MuiThemeProviderForNextJs;
|
||||
@@ -1,42 +1,67 @@
|
||||
'use client';
|
||||
import { FunctionComponent, PropsWithChildren, useEffect, useMemo, useState } from 'react';
|
||||
import { ThemeProvider as MuiThemeProvider, createTheme } from '@mui/material/styles';
|
||||
|
||||
import { useAppStore } from '../store';
|
||||
import DARK_THEME from './dark';
|
||||
import LIGHT_THEME from './light';
|
||||
import MuiThemeProviderForNextJs from './MuiThemeProviderForNextJs';
|
||||
import { FunctionComponent, PropsWithChildren, useEffect } from 'react';
|
||||
import { ThemeProvider as MuiThemeProvider, useColorScheme } from '@mui/material/styles';
|
||||
import { AppRouterCacheProvider } from '@mui/material-nextjs/v16-appRouter';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
|
||||
function getThemeByDarkMode(darkMode: boolean) {
|
||||
return darkMode ? createTheme(DARK_THEME) : createTheme(LIGHT_THEME);
|
||||
}
|
||||
// @ts-ignore — stylis-plugin-rtl ships CJS without bundled TS declarations
|
||||
import rtlPlugin from 'stylis-plugin-rtl';
|
||||
import { COOKIE_NAMES, COLOR_SCHEME_COOKIE_OPTIONS } from '@/lib/cookies';
|
||||
import { setClientCookie } from '@/lib/cookies/client';
|
||||
import { APP_THEME_LTR, APP_THEME_RTL } from './theme';
|
||||
|
||||
/**
|
||||
* Renders composition of Emotion's CacheProvider + MUI's ThemeProvider to wrap content of entire App
|
||||
* The Light or Dark themes applied depending on global .darkMode state
|
||||
* @component AppThemeProvider
|
||||
* Writes the resolved color scheme to our cookie whenever MUI's state changes.
|
||||
* Acts as a safety net for the first-visit / system-mode case where the
|
||||
* Storage.prototype intercept in ColorSchemeScript has nothing to intercept yet
|
||||
* (no setItem call fires until the user explicitly toggles).
|
||||
*/
|
||||
const AppThemeProvider: FunctionComponent<PropsWithChildren> = ({ children }) => {
|
||||
const [state] = useAppStore();
|
||||
const [loading, setLoading] = useState(true);
|
||||
function ColorSchemeCookieSync() {
|
||||
const { colorScheme } = useColorScheme();
|
||||
|
||||
const currentTheme = useMemo(
|
||||
() => getThemeByDarkMode(state.darkMode),
|
||||
[state.darkMode] // Observe AppStore and re-create the theme when .darkMode changes
|
||||
);
|
||||
useEffect(() => {
|
||||
if (colorScheme === 'dark' || colorScheme === 'light') {
|
||||
setClientCookie(COOKIE_NAMES.COLOR_SCHEME, colorScheme, COLOR_SCHEME_COOKIE_OPTIONS);
|
||||
}
|
||||
}, [colorScheme]);
|
||||
|
||||
useEffect(() => setLoading(false), []); // Set .loading to false when the component is mounted
|
||||
return null;
|
||||
}
|
||||
|
||||
if (loading) return null; // Don't render anything until the component is mounted
|
||||
interface AppThemeProviderProps extends PropsWithChildren {
|
||||
/** Text direction derived from the active locale. Defaults to 'ltr'. */
|
||||
dir?: 'ltr' | 'rtl';
|
||||
/**
|
||||
* Initial color-scheme mode passed from the server after reading our cookie.
|
||||
* 'dark' | 'light' when the cookie exists; 'system' on first ever visit so
|
||||
* the OS preference is respected before the user makes an explicit choice.
|
||||
*/
|
||||
defaultMode?: 'light' | 'dark' | 'system';
|
||||
}
|
||||
|
||||
const AppThemeProvider: FunctionComponent<AppThemeProviderProps> = ({
|
||||
children,
|
||||
dir = 'ltr',
|
||||
defaultMode = 'system',
|
||||
}) => {
|
||||
const isRtl = dir === 'rtl';
|
||||
return (
|
||||
<MuiThemeProviderForNextJs>
|
||||
<MuiThemeProvider theme={currentTheme}>
|
||||
<CssBaseline /* MUI Styles */ />
|
||||
<AppRouterCacheProvider
|
||||
options={
|
||||
isRtl
|
||||
? { key: 'muirtl', stylisPlugins: [rtlPlugin] }
|
||||
: { key: 'muiltr' }
|
||||
}
|
||||
>
|
||||
<MuiThemeProvider
|
||||
theme={isRtl ? APP_THEME_RTL : APP_THEME_LTR}
|
||||
defaultMode={defaultMode}
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<CssBaseline enableColorScheme />
|
||||
<ColorSchemeCookieSync />
|
||||
{children}
|
||||
</MuiThemeProvider>
|
||||
</MuiThemeProviderForNextJs>
|
||||
</AppRouterCacheProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+72
-24
@@ -1,27 +1,75 @@
|
||||
import { PaletteOptions, SimplePaletteColorOptions } from '@mui/material';
|
||||
import { PaletteOptions } from '@mui/material';
|
||||
|
||||
const COLOR_PRIMARY: SimplePaletteColorOptions = {
|
||||
main: '#64B5F6',
|
||||
contrastText: '#000000',
|
||||
// light: '#64B5F6',
|
||||
// dark: '#64B5F6',
|
||||
};
|
||||
|
||||
const COLOR_SECONDARY: SimplePaletteColorOptions = {
|
||||
main: '#EF9A9A',
|
||||
contrastText: '#000000',
|
||||
// light: '#EF9A9A',
|
||||
// dark: '#EF9A9A',
|
||||
};
|
||||
|
||||
/**
|
||||
* MUI colors set to use in theme.palette
|
||||
/*
|
||||
* Raw hex values that mirror tokens.css.
|
||||
* Keep these in sync: tokens.css is what the browser renders,
|
||||
* BRAND + LIGHT/DARK_PALETTE are what MUI uses to generate --mui-palette-* variables.
|
||||
*/
|
||||
export const PALETTE_COLORS: Partial<PaletteOptions> = {
|
||||
primary: COLOR_PRIMARY,
|
||||
secondary: COLOR_SECONDARY,
|
||||
// error: COLOR_ERROR,
|
||||
// warning: COLOR_WARNING;
|
||||
// info: COLOR_INFO;
|
||||
// success: COLOR_SUCCESS;
|
||||
export const BRAND = {
|
||||
teal: '#1d4a40',
|
||||
tealLight: '#2f6b5e',
|
||||
tealDark: '#123029',
|
||||
tealContrast: '#f3efe9',
|
||||
terracotta: '#d98c6a',
|
||||
terracottaLight: '#e6a98a',
|
||||
terracottaDark: '#bf6f4d',
|
||||
terracottaContrast:'#2a1a12',
|
||||
cream: '#faf9f5',
|
||||
creamSoft: '#f3efe9',
|
||||
ink: '#1b2521',
|
||||
// Dark-mode surface & lifted brand
|
||||
tealOnDark: '#6fc0ac',
|
||||
tealOnDarkLight: '#8fd2c1',
|
||||
tealOnDarkDark: '#3f8a78',
|
||||
tealOnDarkContrast:'#06120f',
|
||||
tealDeep: '#0f1c19',
|
||||
tealSurface: '#16302a',
|
||||
} as const;
|
||||
|
||||
export const LIGHT_PALETTE: PaletteOptions = {
|
||||
primary: {
|
||||
main: BRAND.teal,
|
||||
light: BRAND.tealLight,
|
||||
dark: BRAND.tealDark,
|
||||
contrastText: BRAND.tealContrast,
|
||||
},
|
||||
secondary: {
|
||||
main: BRAND.terracotta,
|
||||
light: BRAND.terracottaLight,
|
||||
dark: BRAND.terracottaDark,
|
||||
contrastText: BRAND.terracottaContrast,
|
||||
},
|
||||
background: {
|
||||
default: BRAND.cream,
|
||||
paper: '#ffffff',
|
||||
},
|
||||
text: {
|
||||
primary: BRAND.ink,
|
||||
secondary: '#5b655f',
|
||||
},
|
||||
divider: 'rgba(29, 74, 64, 0.14)',
|
||||
};
|
||||
|
||||
export const DARK_PALETTE: PaletteOptions = {
|
||||
primary: {
|
||||
main: BRAND.tealOnDark,
|
||||
light: BRAND.tealOnDarkLight,
|
||||
dark: BRAND.tealOnDarkDark,
|
||||
contrastText: BRAND.tealOnDarkContrast,
|
||||
},
|
||||
secondary: {
|
||||
main: BRAND.terracottaLight,
|
||||
light: '#f0bfa3',
|
||||
dark: BRAND.terracotta,
|
||||
contrastText: BRAND.terracottaContrast,
|
||||
},
|
||||
background: {
|
||||
default: BRAND.tealDeep,
|
||||
paper: BRAND.tealSurface,
|
||||
},
|
||||
text: {
|
||||
primary: BRAND.creamSoft,
|
||||
secondary: '#9fb0a9',
|
||||
},
|
||||
divider: 'rgba(243, 239, 233, 0.14)',
|
||||
};
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
import { ThemeOptions } from '@mui/material';
|
||||
import { PALETTE_COLORS } from './colors';
|
||||
import { DARK_PALETTE } from './colors';
|
||||
import { TYPOGRAPHY } from './typography';
|
||||
|
||||
/**
|
||||
* MUI theme options for "Dark Mode"
|
||||
*/
|
||||
export const DARK_THEME: ThemeOptions = {
|
||||
palette: {
|
||||
mode: 'dark',
|
||||
// background: {
|
||||
// paper: '#424242', // Gray 800 - Background of "Paper" based component
|
||||
// default: '#121212',
|
||||
// },
|
||||
...PALETTE_COLORS,
|
||||
},
|
||||
palette: { mode: 'dark', ...DARK_PALETTE },
|
||||
typography: TYPOGRAPHY,
|
||||
shape: { borderRadius: 10 },
|
||||
};
|
||||
|
||||
export default DARK_THEME;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
const RTL_LOCALES = ['fa', 'ar', 'he', 'ur'];
|
||||
|
||||
export function getDirection(locale: string): 'ltr' | 'rtl' {
|
||||
return RTL_LOCALES.includes(locale) ? 'rtl' : 'ltr';
|
||||
}
|
||||
@@ -1,10 +1,18 @@
|
||||
import AppThemeProvider from './ThemeProvider';
|
||||
import DARK_THEME from './dark';
|
||||
import LIGHT_THEME from './light';
|
||||
import { LIGHT_THEME } from './light';
|
||||
import { DARK_THEME } from './dark';
|
||||
import APP_THEME, { APP_THEME_LTR, APP_THEME_RTL } from './theme';
|
||||
import { getDirection } from './direction';
|
||||
import { ColorSchemeScript } from './ColorSchemeScript';
|
||||
|
||||
export {
|
||||
LIGHT_THEME as default, // Change to DARK_THEME if you want to use dark theme as default
|
||||
DARK_THEME,
|
||||
APP_THEME,
|
||||
APP_THEME_LTR,
|
||||
APP_THEME_RTL,
|
||||
LIGHT_THEME,
|
||||
DARK_THEME,
|
||||
LIGHT_THEME as default,
|
||||
AppThemeProvider as ThemeProvider,
|
||||
getDirection,
|
||||
ColorSchemeScript,
|
||||
};
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
import { ThemeOptions } from '@mui/material';
|
||||
import { PALETTE_COLORS } from './colors';
|
||||
import { LIGHT_PALETTE } from './colors';
|
||||
import { TYPOGRAPHY } from './typography';
|
||||
|
||||
/**
|
||||
* MUI theme options for "Light Mode"
|
||||
*/
|
||||
export const LIGHT_THEME: ThemeOptions = {
|
||||
palette: {
|
||||
mode: 'light',
|
||||
// background: {
|
||||
// paper: '#f5f5f5', // Gray 100 - Background of "Paper" based component
|
||||
// default: '#FFFFFF',
|
||||
// },
|
||||
...PALETTE_COLORS,
|
||||
},
|
||||
palette: { mode: 'light', ...LIGHT_PALETTE },
|
||||
typography: TYPOGRAPHY,
|
||||
shape: { borderRadius: 10 },
|
||||
};
|
||||
|
||||
export default LIGHT_THEME;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { createTheme } from '@mui/material/styles';
|
||||
import { LIGHT_PALETTE, DARK_PALETTE } from './colors';
|
||||
import { TYPOGRAPHY_LTR, TYPOGRAPHY_RTL } from './typography';
|
||||
|
||||
/*
|
||||
* Theme factory — called twice at module load (ltr + rtl) so components can
|
||||
* pick the right theme without re-creating it on every render.
|
||||
*
|
||||
* cssVariables.colorSchemeSelector: 'data-mui-color-scheme'
|
||||
* → MUI v9 sets data-mui-color-scheme="dark"|"light" on <html>.
|
||||
* (The shorthand 'data' produces boolean attrs data-dark/data-light which
|
||||
* our CSS selectors never match — must use the explicit attribute name.)
|
||||
*
|
||||
* direction
|
||||
* → MUI flips inline-start/end padding for components that care.
|
||||
* → ThemeProvider pairs this with a direction-aware Emotion cache that
|
||||
* runs stylis-plugin-rtl so all generated CSS is mirrored correctly.
|
||||
*/
|
||||
function createAppTheme(direction: 'ltr' | 'rtl') {
|
||||
return createTheme({
|
||||
cssVariables: {
|
||||
// MUI v9: 'data' produces boolean attrs (data-dark / data-light) which our
|
||||
// CSS never matches. An explicit attribute name produces the keyed form:
|
||||
// data-mui-color-scheme="dark" — matching tokens.css selectors exactly.
|
||||
colorSchemeSelector: 'data-mui-color-scheme',
|
||||
},
|
||||
colorSchemes: {
|
||||
light: { palette: LIGHT_PALETTE },
|
||||
dark: { palette: DARK_PALETTE },
|
||||
},
|
||||
defaultColorScheme: 'light',
|
||||
typography: direction === 'rtl' ? TYPOGRAPHY_RTL : TYPOGRAPHY_LTR,
|
||||
shape: { borderRadius: 10 },
|
||||
direction,
|
||||
});
|
||||
}
|
||||
|
||||
export const APP_THEME_LTR = createAppTheme('ltr');
|
||||
export const APP_THEME_RTL = createAppTheme('rtl');
|
||||
|
||||
export default APP_THEME_LTR;
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Balinyaar brand color tokens — source of truth for all colors.
|
||||
*
|
||||
* Palette extracted from the seed-deck proposal (balinyaar.html):
|
||||
* #1d4a40 deep teal / forest-green → brand primary
|
||||
* #d98c6a terracotta → brand accent (secondary)
|
||||
* #f3efe9 soft cream → text-on-dark / glyph fill
|
||||
* #faf9f5 cream → page surface
|
||||
*
|
||||
* MUI sets data-mui-color-scheme="dark" on <html> when dark mode is active
|
||||
* (colorSchemeSelector: 'data' in createTheme). The same attribute drives
|
||||
* every custom CSS rule in this file. You never need to read or write
|
||||
* this attribute manually — MUI's useColorScheme() does it for you.
|
||||
*
|
||||
* Usage in custom CSS outside MUI:
|
||||
* color: var(--bal-primary); ← resolves to the active scheme value
|
||||
* background: var(--bal-bg-default);
|
||||
*/
|
||||
|
||||
/* ── Light scheme (default) ────────────────────────────────────────────── */
|
||||
:root,
|
||||
[data-mui-color-scheme='light'] {
|
||||
/* Primary — deep teal */
|
||||
--bal-primary: #1d4a40;
|
||||
--bal-primary-light: #2f6b5e;
|
||||
--bal-primary-dark: #123029;
|
||||
--bal-primary-contrast: #f3efe9;
|
||||
|
||||
/* Secondary — terracotta */
|
||||
--bal-secondary: #d98c6a;
|
||||
--bal-secondary-light: #e6a98a;
|
||||
--bal-secondary-dark: #bf6f4d;
|
||||
--bal-secondary-contrast: #2a1a12;
|
||||
|
||||
/* Surfaces */
|
||||
--bal-bg-default: #faf9f5;
|
||||
--bal-bg-paper: #ffffff;
|
||||
|
||||
/* Text */
|
||||
--bal-text-primary: #1b2521;
|
||||
--bal-text-secondary: #5b655f;
|
||||
|
||||
/* Divider */
|
||||
--bal-divider: rgba(29, 74, 64, 0.14);
|
||||
}
|
||||
|
||||
/* ── Dark scheme ────────────────────────────────────────────────────────── */
|
||||
[data-mui-color-scheme='dark'] {
|
||||
/* Primary — lifted teal (readable on dark surfaces) */
|
||||
--bal-primary: #6fc0ac;
|
||||
--bal-primary-light: #8fd2c1;
|
||||
--bal-primary-dark: #3f8a78;
|
||||
--bal-primary-contrast: #06120f;
|
||||
|
||||
/* Secondary — warm terracotta-light */
|
||||
--bal-secondary: #e6a98a;
|
||||
--bal-secondary-light: #f0bfa3;
|
||||
--bal-secondary-dark: #d98c6a;
|
||||
--bal-secondary-contrast: #2a1a12;
|
||||
|
||||
/* Surfaces — deep teal */
|
||||
--bal-bg-default: #0f1c19;
|
||||
--bal-bg-paper: #16302a;
|
||||
|
||||
/* Text */
|
||||
--bal-text-primary: #f3efe9;
|
||||
--bal-text-secondary: #9fb0a9;
|
||||
|
||||
/* Divider */
|
||||
--bal-divider: rgba(243, 239, 233, 0.14);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { TypographyVariantsOptions } from '@mui/material';
|
||||
|
||||
/** CSS variable injected by next/font/google (Space Grotesk) in src/app/layout.tsx */
|
||||
export const BRAND_FONT_VARIABLE_EN = '--font-space-grotesk';
|
||||
|
||||
/** CSS variable injected by next/font/local (Mikhak) in src/app/layout.tsx */
|
||||
export const BRAND_FONT_VARIABLE_FA = '--font-mikhak';
|
||||
|
||||
const SYSTEM_FONT_STACK = [
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
'"Segoe UI"',
|
||||
'Roboto',
|
||||
'"Helvetica Neue"',
|
||||
'Arial',
|
||||
'sans-serif',
|
||||
].join(', ');
|
||||
|
||||
/** Brand display font with graceful fallbacks. */
|
||||
const DISPLAY_FONT_LTR = `var(${BRAND_FONT_VARIABLE_EN}), "Space Grotesk", ${SYSTEM_FONT_STACK}`;
|
||||
|
||||
/** Persian display + body font with graceful fallbacks. */
|
||||
const DISPLAY_FONT_RTL = `var(${BRAND_FONT_VARIABLE_FA}), "Mikhak", "Tahoma", "Arial Unicode MS", sans-serif`;
|
||||
|
||||
const displayHeadingLtr = { fontFamily: DISPLAY_FONT_LTR, fontWeight: 700 } as const;
|
||||
const displayHeadingRtl = { fontFamily: DISPLAY_FONT_RTL, fontWeight: 700 } as const;
|
||||
|
||||
/** LTR typography — Space Grotesk headings, system font body. */
|
||||
export const TYPOGRAPHY_LTR: TypographyVariantsOptions = {
|
||||
fontFamily: SYSTEM_FONT_STACK,
|
||||
h1: displayHeadingLtr,
|
||||
h2: displayHeadingLtr,
|
||||
h3: displayHeadingLtr,
|
||||
h4: displayHeadingLtr,
|
||||
h5: displayHeadingLtr,
|
||||
h6: { ...displayHeadingLtr, fontWeight: 600 },
|
||||
button: { fontWeight: 600, textTransform: 'none' },
|
||||
};
|
||||
|
||||
/** RTL typography — Mikhak for all text (headings + body) to ensure full Persian glyph coverage. */
|
||||
export const TYPOGRAPHY_RTL: TypographyVariantsOptions = {
|
||||
fontFamily: DISPLAY_FONT_RTL,
|
||||
h1: displayHeadingRtl,
|
||||
h2: displayHeadingRtl,
|
||||
h3: displayHeadingRtl,
|
||||
h4: displayHeadingRtl,
|
||||
h5: displayHeadingRtl,
|
||||
h6: { ...displayHeadingRtl, fontWeight: 600 },
|
||||
button: { fontWeight: 600, textTransform: 'none' },
|
||||
};
|
||||
|
||||
/** @deprecated use TYPOGRAPHY_LTR or TYPOGRAPHY_RTL */
|
||||
export const TYPOGRAPHY = TYPOGRAPHY_LTR;
|
||||
Reference in New Issue
Block a user