initial commit
This commit is contained in:
80
packages/react-native/src/theme/DTThemeProvider.tsx
Normal file
80
packages/react-native/src/theme/DTThemeProvider.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* DT Theme Provider
|
||||
*
|
||||
* Wraps your app with the Dangerous Things theme.
|
||||
* Combines React Native Paper's PaperProvider with
|
||||
* custom theme context for extended DT colors.
|
||||
*/
|
||||
|
||||
import { createContext, useContext, ReactNode } from 'react';
|
||||
import { PaperProvider } from 'react-native-paper';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import { StatusBar } from 'react-native';
|
||||
import { DTExtendedDarkTheme, DTExtendedTheme } from './paperTheme';
|
||||
|
||||
/**
|
||||
* Context for accessing extended theme properties
|
||||
*/
|
||||
const DTThemeContext = createContext<DTExtendedTheme>(DTExtendedDarkTheme);
|
||||
|
||||
/**
|
||||
* Hook to access the full DT theme including custom properties
|
||||
*
|
||||
* @example
|
||||
* const theme = useDTTheme();
|
||||
* const successColor = theme.custom.success;
|
||||
*/
|
||||
export function useDTTheme(): DTExtendedTheme {
|
||||
return useContext(DTThemeContext);
|
||||
}
|
||||
|
||||
interface DTThemeProviderProps {
|
||||
children: ReactNode;
|
||||
/**
|
||||
* Override the default theme (useful for testing or custom variants)
|
||||
*/
|
||||
theme?: DTExtendedTheme;
|
||||
/**
|
||||
* Include SafeAreaProvider wrapper (default: true)
|
||||
* Set to false if you already have SafeAreaProvider higher in tree
|
||||
*/
|
||||
includeSafeArea?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme provider component
|
||||
*
|
||||
* @example
|
||||
* // In your App.tsx
|
||||
* import { DTThemeProvider } from '@anthropic-dangerous-things/react-native-theme';
|
||||
*
|
||||
* export default function App() {
|
||||
* return (
|
||||
* <DTThemeProvider>
|
||||
* <NavigationContainer>
|
||||
* <YourApp />
|
||||
* </NavigationContainer>
|
||||
* </DTThemeProvider>
|
||||
* );
|
||||
* }
|
||||
*/
|
||||
export function DTThemeProvider({
|
||||
children,
|
||||
theme = DTExtendedDarkTheme,
|
||||
includeSafeArea = true,
|
||||
}: DTThemeProviderProps) {
|
||||
const content = (
|
||||
<DTThemeContext.Provider value={theme}>
|
||||
<PaperProvider theme={theme}>
|
||||
<StatusBar barStyle="light-content" backgroundColor="#000000" />
|
||||
{children}
|
||||
</PaperProvider>
|
||||
</DTThemeContext.Provider>
|
||||
);
|
||||
|
||||
if (includeSafeArea) {
|
||||
return <SafeAreaProvider>{content}</SafeAreaProvider>;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
69
packages/react-native/src/theme/colors.ts
Normal file
69
packages/react-native/src/theme/colors.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Dangerous Things Color Palette
|
||||
*
|
||||
* Based on the dt-shopify-storefront design system.
|
||||
* Cyberpunk aesthetic with high-contrast neon colors on dark backgrounds.
|
||||
*/
|
||||
|
||||
export const DTColors = {
|
||||
// Base colors
|
||||
dark: '#000000',
|
||||
light: '#FFFFFF',
|
||||
|
||||
// Mode colors (primary semantic palette)
|
||||
modeNormal: '#00FFFF', // Cyan - primary actions, links, borders
|
||||
modeNormalSelected: 'rgba(0, 255, 255, 0.7)',
|
||||
modeEmphasis: '#FFFF00', // Yellow - highlights, emphasis, headers
|
||||
modeEmphasisSelected: 'rgba(255, 255, 0, 0.7)',
|
||||
modeWarning: '#FF0000', // Red - errors, warnings, destructive actions
|
||||
modeSuccess: '#00FF00', // Green - success states, confirmations
|
||||
modeOther: '#FF00FF', // Magenta - miscellaneous, secondary info
|
||||
|
||||
// Semantic aliases
|
||||
primary: '#00FFFF',
|
||||
primaryVariant: 'rgba(0, 255, 255, 0.7)',
|
||||
secondary: '#FFFF00',
|
||||
secondaryVariant: 'rgba(255, 255, 0, 0.7)',
|
||||
error: '#FF0000',
|
||||
success: '#00FF00',
|
||||
|
||||
// Surface colors
|
||||
background: '#000000',
|
||||
surface: '#000000',
|
||||
surfaceVariant: '#070707',
|
||||
|
||||
// Text colors
|
||||
onBackground: '#FFFFFF',
|
||||
onSurface: '#FFFFFF',
|
||||
onPrimary: '#000000',
|
||||
onSecondary: '#000000',
|
||||
onError: '#000000',
|
||||
|
||||
// Border colors
|
||||
border: '#00FFFF',
|
||||
borderEmphasis: '#FFFF00',
|
||||
|
||||
// Transparency variants (for overlays, disabled states)
|
||||
overlay: 'rgba(0, 0, 0, 0.7)',
|
||||
disabled: 'rgba(255, 255, 255, 0.3)',
|
||||
disabledBackground: 'rgba(255, 255, 255, 0.1)',
|
||||
} as const;
|
||||
|
||||
export type DTColorKey = keyof typeof DTColors;
|
||||
|
||||
/**
|
||||
* Get a color with optional opacity override
|
||||
*/
|
||||
export function getColor(color: DTColorKey, opacity?: number): string {
|
||||
const baseColor = DTColors[color];
|
||||
if (opacity === undefined || baseColor.startsWith('rgba')) {
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
// Convert hex to rgba
|
||||
const hex = baseColor.replace('#', '');
|
||||
const r = parseInt(hex.substring(0, 2), 16);
|
||||
const g = parseInt(hex.substring(2, 4), 16);
|
||||
const b = parseInt(hex.substring(4, 6), 16);
|
||||
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
||||
}
|
||||
149
packages/react-native/src/theme/paperTheme.ts
Normal file
149
packages/react-native/src/theme/paperTheme.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* React Native Paper MD3 Theme Configuration
|
||||
*
|
||||
* This creates a Material Design 3 compliant theme that follows
|
||||
* the Dangerous Things cyberpunk aesthetic while respecting
|
||||
* React Native Paper's design principles.
|
||||
*/
|
||||
|
||||
import { MD3DarkTheme, MD3Theme, configureFonts } from 'react-native-paper';
|
||||
import { DTColors } from './colors';
|
||||
import { DTTypography, DTFonts } from './typography';
|
||||
|
||||
/**
|
||||
* MD3 Font configuration for React Native Paper
|
||||
* Maps our typography to RNP's expected font config
|
||||
*/
|
||||
const fontConfig = {
|
||||
fontFamily: DTFonts.regular,
|
||||
displayLarge: DTTypography.displayLarge,
|
||||
displayMedium: DTTypography.displayMedium,
|
||||
displaySmall: DTTypography.displaySmall,
|
||||
headlineLarge: DTTypography.headlineLarge,
|
||||
headlineMedium: DTTypography.headlineMedium,
|
||||
headlineSmall: DTTypography.headlineSmall,
|
||||
titleLarge: DTTypography.titleLarge,
|
||||
titleMedium: DTTypography.titleMedium,
|
||||
titleSmall: DTTypography.titleSmall,
|
||||
bodyLarge: DTTypography.bodyLarge,
|
||||
bodyMedium: DTTypography.bodyMedium,
|
||||
bodySmall: DTTypography.bodySmall,
|
||||
labelLarge: DTTypography.labelLarge,
|
||||
labelMedium: DTTypography.labelMedium,
|
||||
labelSmall: DTTypography.labelSmall,
|
||||
};
|
||||
|
||||
/**
|
||||
* Dangerous Things Dark Theme
|
||||
*
|
||||
* Based on MD3DarkTheme with cyberpunk color overrides.
|
||||
* Primary = Cyan, Secondary = Yellow (following DT brand)
|
||||
*/
|
||||
export const DTDarkTheme: MD3Theme = {
|
||||
...MD3DarkTheme,
|
||||
dark: true,
|
||||
roundness: 4, // Slightly rounded, but we use custom clip-path for bevels
|
||||
|
||||
fonts: configureFonts({ config: fontConfig }),
|
||||
|
||||
colors: {
|
||||
...MD3DarkTheme.colors,
|
||||
|
||||
// Primary (Cyan)
|
||||
primary: DTColors.modeNormal,
|
||||
onPrimary: DTColors.dark,
|
||||
primaryContainer: DTColors.modeNormalSelected,
|
||||
onPrimaryContainer: DTColors.dark,
|
||||
|
||||
// Secondary (Yellow)
|
||||
secondary: DTColors.modeEmphasis,
|
||||
onSecondary: DTColors.dark,
|
||||
secondaryContainer: DTColors.modeEmphasisSelected,
|
||||
onSecondaryContainer: DTColors.dark,
|
||||
|
||||
// Tertiary (Magenta)
|
||||
tertiary: DTColors.modeOther,
|
||||
onTertiary: DTColors.dark,
|
||||
tertiaryContainer: 'rgba(255, 0, 255, 0.3)',
|
||||
onTertiaryContainer: DTColors.light,
|
||||
|
||||
// Error (Red)
|
||||
error: DTColors.modeWarning,
|
||||
onError: DTColors.dark,
|
||||
errorContainer: 'rgba(255, 0, 0, 0.3)',
|
||||
onErrorContainer: DTColors.light,
|
||||
|
||||
// Background & Surface
|
||||
background: DTColors.background,
|
||||
onBackground: DTColors.onBackground,
|
||||
surface: DTColors.surface,
|
||||
onSurface: DTColors.onSurface,
|
||||
surfaceVariant: DTColors.surfaceVariant,
|
||||
onSurfaceVariant: DTColors.light,
|
||||
|
||||
// Surface elevation (MD3 uses tonal elevation)
|
||||
elevation: {
|
||||
level0: 'transparent',
|
||||
level1: DTColors.surfaceVariant,
|
||||
level2: '#0a0a0a',
|
||||
level3: '#0f0f0f',
|
||||
level4: '#121212',
|
||||
level5: '#151515',
|
||||
},
|
||||
|
||||
// Outline (borders)
|
||||
outline: DTColors.modeNormal,
|
||||
outlineVariant: 'rgba(0, 255, 255, 0.5)',
|
||||
|
||||
// Inverse (for snackbars, etc.)
|
||||
inverseSurface: DTColors.light,
|
||||
inverseOnSurface: DTColors.dark,
|
||||
inversePrimary: '#008B8B', // Darker cyan for light backgrounds
|
||||
|
||||
// Misc
|
||||
shadow: DTColors.dark,
|
||||
scrim: DTColors.overlay,
|
||||
surfaceDisabled: DTColors.disabledBackground,
|
||||
onSurfaceDisabled: DTColors.disabled,
|
||||
backdrop: DTColors.overlay,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Extended theme with DT-specific custom properties
|
||||
* Use this when you need access to non-MD3 colors
|
||||
*/
|
||||
export interface DTExtendedTheme extends MD3Theme {
|
||||
custom: {
|
||||
success: string;
|
||||
warning: string;
|
||||
modeNormal: string;
|
||||
modeEmphasis: string;
|
||||
modeWarning: string;
|
||||
modeSuccess: string;
|
||||
modeOther: string;
|
||||
border: string;
|
||||
borderEmphasis: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const DTExtendedDarkTheme: DTExtendedTheme = {
|
||||
...DTDarkTheme,
|
||||
custom: {
|
||||
success: DTColors.modeSuccess,
|
||||
warning: DTColors.modeWarning,
|
||||
modeNormal: DTColors.modeNormal,
|
||||
modeEmphasis: DTColors.modeEmphasis,
|
||||
modeWarning: DTColors.modeWarning,
|
||||
modeSuccess: DTColors.modeSuccess,
|
||||
modeOther: DTColors.modeOther,
|
||||
border: DTColors.border,
|
||||
borderEmphasis: DTColors.borderEmphasis,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to access extended theme properties
|
||||
* Usage: const { custom } = useDTTheme();
|
||||
*/
|
||||
export { useTheme as usePaperTheme } from 'react-native-paper';
|
||||
190
packages/react-native/src/theme/typography.ts
Normal file
190
packages/react-native/src/theme/typography.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* Dangerous Things Typography
|
||||
*
|
||||
* Primary font: Tektur (variable font)
|
||||
* Fallback: System default sans-serif
|
||||
*
|
||||
* Note: To use Tektur, you must:
|
||||
* 1. Download Tektur from Google Fonts
|
||||
* 2. Add to your project's assets/fonts/
|
||||
* 3. Link fonts in react-native.config.js or use expo-font
|
||||
*/
|
||||
|
||||
import { Platform, TextStyle } from 'react-native';
|
||||
|
||||
/**
|
||||
* Font family configuration
|
||||
* Tektur is a variable font with weights 100-900
|
||||
*/
|
||||
export const DTFonts = {
|
||||
regular: Platform.select({
|
||||
ios: 'Tektur',
|
||||
android: 'Tektur-Regular',
|
||||
default: 'Tektur',
|
||||
}),
|
||||
medium: Platform.select({
|
||||
ios: 'Tektur',
|
||||
android: 'Tektur-Medium',
|
||||
default: 'Tektur',
|
||||
}),
|
||||
bold: Platform.select({
|
||||
ios: 'Tektur',
|
||||
android: 'Tektur-Bold',
|
||||
default: 'Tektur',
|
||||
}),
|
||||
// Fallback when Tektur is not available
|
||||
fallback: Platform.select({
|
||||
ios: 'System',
|
||||
android: 'sans-serif',
|
||||
default: 'sans-serif',
|
||||
}),
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Font weights for variable font
|
||||
*/
|
||||
export const DTFontWeights = {
|
||||
thin: '100' as const,
|
||||
light: '300' as const,
|
||||
regular: '400' as const,
|
||||
medium: '500' as const,
|
||||
semibold: '600' as const,
|
||||
bold: '700' as const,
|
||||
extrabold: '800' as const,
|
||||
black: '900' as const,
|
||||
};
|
||||
|
||||
/**
|
||||
* Base text styles
|
||||
*/
|
||||
const baseTextStyle: TextStyle = {
|
||||
fontFamily: DTFonts.regular,
|
||||
color: '#FFFFFF',
|
||||
letterSpacing: 0.5,
|
||||
};
|
||||
|
||||
/**
|
||||
* Typography scale following Material Design 3 naming
|
||||
*/
|
||||
export const DTTypography = {
|
||||
// Display styles (large headlines)
|
||||
displayLarge: {
|
||||
...baseTextStyle,
|
||||
fontSize: 57,
|
||||
fontWeight: DTFontWeights.bold,
|
||||
lineHeight: 64,
|
||||
letterSpacing: -0.25,
|
||||
} as TextStyle,
|
||||
|
||||
displayMedium: {
|
||||
...baseTextStyle,
|
||||
fontSize: 45,
|
||||
fontWeight: DTFontWeights.bold,
|
||||
lineHeight: 52,
|
||||
} as TextStyle,
|
||||
|
||||
displaySmall: {
|
||||
...baseTextStyle,
|
||||
fontSize: 36,
|
||||
fontWeight: DTFontWeights.bold,
|
||||
lineHeight: 44,
|
||||
} as TextStyle,
|
||||
|
||||
// Headline styles
|
||||
headlineLarge: {
|
||||
...baseTextStyle,
|
||||
fontSize: 32,
|
||||
fontWeight: DTFontWeights.semibold,
|
||||
lineHeight: 40,
|
||||
} as TextStyle,
|
||||
|
||||
headlineMedium: {
|
||||
...baseTextStyle,
|
||||
fontSize: 28,
|
||||
fontWeight: DTFontWeights.semibold,
|
||||
lineHeight: 36,
|
||||
} as TextStyle,
|
||||
|
||||
headlineSmall: {
|
||||
...baseTextStyle,
|
||||
fontSize: 24,
|
||||
fontWeight: DTFontWeights.semibold,
|
||||
lineHeight: 32,
|
||||
} as TextStyle,
|
||||
|
||||
// Title styles
|
||||
titleLarge: {
|
||||
...baseTextStyle,
|
||||
fontSize: 22,
|
||||
fontWeight: DTFontWeights.medium,
|
||||
lineHeight: 28,
|
||||
} as TextStyle,
|
||||
|
||||
titleMedium: {
|
||||
...baseTextStyle,
|
||||
fontSize: 16,
|
||||
fontWeight: DTFontWeights.medium,
|
||||
lineHeight: 24,
|
||||
letterSpacing: 0.15,
|
||||
} as TextStyle,
|
||||
|
||||
titleSmall: {
|
||||
...baseTextStyle,
|
||||
fontSize: 14,
|
||||
fontWeight: DTFontWeights.medium,
|
||||
lineHeight: 20,
|
||||
letterSpacing: 0.1,
|
||||
} as TextStyle,
|
||||
|
||||
// Body styles
|
||||
bodyLarge: {
|
||||
...baseTextStyle,
|
||||
fontSize: 16,
|
||||
fontWeight: DTFontWeights.regular,
|
||||
lineHeight: 24,
|
||||
letterSpacing: 0.5,
|
||||
} as TextStyle,
|
||||
|
||||
bodyMedium: {
|
||||
...baseTextStyle,
|
||||
fontSize: 14,
|
||||
fontWeight: DTFontWeights.regular,
|
||||
lineHeight: 20,
|
||||
letterSpacing: 0.25,
|
||||
} as TextStyle,
|
||||
|
||||
bodySmall: {
|
||||
...baseTextStyle,
|
||||
fontSize: 12,
|
||||
fontWeight: DTFontWeights.regular,
|
||||
lineHeight: 16,
|
||||
letterSpacing: 0.4,
|
||||
} as TextStyle,
|
||||
|
||||
// Label styles
|
||||
labelLarge: {
|
||||
...baseTextStyle,
|
||||
fontSize: 14,
|
||||
fontWeight: DTFontWeights.medium,
|
||||
lineHeight: 20,
|
||||
letterSpacing: 0.1,
|
||||
} as TextStyle,
|
||||
|
||||
labelMedium: {
|
||||
...baseTextStyle,
|
||||
fontSize: 12,
|
||||
fontWeight: DTFontWeights.medium,
|
||||
lineHeight: 16,
|
||||
letterSpacing: 0.5,
|
||||
} as TextStyle,
|
||||
|
||||
labelSmall: {
|
||||
...baseTextStyle,
|
||||
fontSize: 11,
|
||||
fontWeight: DTFontWeights.medium,
|
||||
lineHeight: 16,
|
||||
letterSpacing: 0.5,
|
||||
} as TextStyle,
|
||||
} as const;
|
||||
|
||||
export type DTTypographyKey = keyof typeof DTTypography;
|
||||
Reference in New Issue
Block a user