Theme has been updated to be more inline with the storefront.

This commit is contained in:
michael
2026-01-26 15:50:46 -08:00
parent 2409ec3625
commit 199146d0b9
7 changed files with 236 additions and 82 deletions

View File

@@ -1,5 +1,26 @@
const {getDefaultConfig} = require('expo/metro-config'); const {getDefaultConfig} = require('expo/metro-config');
const path = require('path');
const themePackagePath = path.resolve(__dirname, '../react-native-dt-theme');
const appNodeModules = path.resolve(__dirname, 'node_modules');
const config = getDefaultConfig(__dirname); const config = getDefaultConfig(__dirname);
// Watch the external theme package
config.watchFolders = [themePackagePath];
// Redirect all imports to use app's node_modules (avoids duplicates)
config.resolver.extraNodeModules = {
'react': path.resolve(appNodeModules, 'react'),
'react-native': path.resolve(appNodeModules, 'react-native'),
'react-native-paper': path.resolve(appNodeModules, 'react-native-paper'),
'react-native-svg': path.resolve(appNodeModules, 'react-native-svg'),
'react-native-safe-area-context': path.resolve(appNodeModules, 'react-native-safe-area-context'),
};
// Block theme package's node_modules entirely
config.resolver.blockList = [
new RegExp(`${themePackagePath.replace(/[/\\]/g, '[/\\\\]')}/node_modules/.*`),
];
module.exports = config; module.exports = config;

178
package-lock.json generated
View File

@@ -16,10 +16,12 @@
"expo-status-bar": "^3.0.9", "expo-status-bar": "^3.0.9",
"react": "19.1.0", "react": "19.1.0",
"react-native": "0.81.5", "react-native": "0.81.5",
"react-native-dt-theme": "file:../react-native-dt-theme",
"react-native-nfc-manager": "^3.17.2", "react-native-nfc-manager": "^3.17.2",
"react-native-paper": "^5.14.5", "react-native-paper": "^5.14.5",
"react-native-safe-area-context": "~5.6.0", "react-native-safe-area-context": "~5.6.0",
"react-native-screens": "~4.16.0", "react-native-screens": "~4.16.0",
"react-native-svg": "15.12.1",
"react-native-vector-icons": "^10.2.0" "react-native-vector-icons": "^10.2.0"
}, },
"devDependencies": { "devDependencies": {
@@ -43,6 +45,31 @@
"node": ">=20" "node": ">=20"
} }
}, },
"../react-native-dt-theme": {
"version": "0.1.0",
"license": "MIT",
"devDependencies": {
"@types/react": "^18.2.0",
"@types/react-native": "^0.72.0",
"react-native-paper": "^5.14.5",
"react-native-safe-area-context": "^5.6.2",
"react-native-svg": "^15.0.0",
"typescript": "^5.0.0"
},
"peerDependencies": {
"expo-font": ">=11.0.0",
"react": ">=18.0.0",
"react-native": ">=0.72.0",
"react-native-paper": ">=5.0.0",
"react-native-safe-area-context": ">=4.0.0",
"react-native-svg": ">=13.0.0"
},
"peerDependenciesMeta": {
"expo-font": {
"optional": true
}
}
},
"node_modules/@0no-co/graphql.web": { "node_modules/@0no-co/graphql.web": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.2.0.tgz",
@@ -4860,6 +4887,12 @@
"node": ">=0.6" "node": ">=0.6"
} }
}, },
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"license": "ISC"
},
"node_modules/bplist-creator": { "node_modules/bplist-creator": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
@@ -5430,6 +5463,47 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/css-select": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css-tree": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
"license": "MIT",
"dependencies": {
"mdn-data": "2.0.14",
"source-map": "^0.6.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/css-what": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
"license": "BSD-2-Clause",
"engines": {
"node": ">= 6"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/csstype": { "node_modules/csstype": {
"version": "3.2.3", "version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
@@ -5688,6 +5762,61 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "BSD-2-Clause"
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
"license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/dotenv": { "node_modules/dotenv": {
"version": "16.4.7", "version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
@@ -5770,6 +5899,18 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/env-editor": { "node_modules/env-editor": {
"version": "0.4.2", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz",
@@ -9873,6 +10014,12 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/mdn-data": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
"license": "CC0-1.0"
},
"node_modules/memoize-one": { "node_modules/memoize-one": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
@@ -10467,6 +10614,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "^1.0.0"
},
"funding": {
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/nullthrows": { "node_modules/nullthrows": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
@@ -11452,6 +11611,10 @@
} }
} }
}, },
"node_modules/react-native-dt-theme": {
"resolved": "../react-native-dt-theme",
"link": true
},
"node_modules/react-native-is-edge-to-edge": { "node_modules/react-native-is-edge-to-edge": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz", "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz",
@@ -11546,6 +11709,21 @@
"react-native": "*" "react-native": "*"
} }
}, },
"node_modules/react-native-svg": {
"version": "15.12.1",
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.12.1.tgz",
"integrity": "sha512-vCuZJDf8a5aNC2dlMovEv4Z0jjEUET53lm/iILFnFewa15b4atjVxU6Wirm6O9y6dEsdjDZVD7Q3QM4T1wlI8g==",
"license": "MIT",
"dependencies": {
"css-select": "^5.1.0",
"css-tree": "^1.1.3",
"warn-once": "0.1.1"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-vector-icons": { "node_modules/react-native-vector-icons": {
"version": "10.3.0", "version": "10.3.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.3.0.tgz", "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.3.0.tgz",

View File

@@ -15,6 +15,7 @@
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"react-native-dt-theme": "file:../react-native-dt-theme",
"@react-navigation/native": "^7.1.27", "@react-navigation/native": "^7.1.27",
"@react-navigation/native-stack": "^7.9.1", "@react-navigation/native-stack": "^7.9.1",
"babel-preset-expo": "~54.0.10", "babel-preset-expo": "~54.0.10",
@@ -27,6 +28,7 @@
"react-native-paper": "^5.14.5", "react-native-paper": "^5.14.5",
"react-native-safe-area-context": "~5.6.0", "react-native-safe-area-context": "~5.6.0",
"react-native-screens": "~4.16.0", "react-native-screens": "~4.16.0",
"react-native-svg": "15.12.1",
"react-native-vector-icons": "^10.2.0" "react-native-vector-icons": "^10.2.0"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import {StyleSheet, View} from 'react-native'; import {StyleSheet, View} from 'react-native';
import {Button, Text, Surface} from 'react-native-paper'; import {Text, Surface} from 'react-native-paper';
import {DTButton, DTColors} from 'react-native-dt-theme';
import type {HomeScreenProps} from '../types/navigation'; import type {HomeScreenProps} from '../types/navigation';
import {DTColors} from '../theme';
export function HomeScreen({navigation}: HomeScreenProps) { export function HomeScreen({navigation}: HomeScreenProps) {
return ( return (
@@ -21,14 +21,11 @@ export function HomeScreen({navigation}: HomeScreenProps) {
Scan any NFC transponder to find compatible Dangerous Things implants. Scan any NFC transponder to find compatible Dangerous Things implants.
</Text> </Text>
<Button <DTButton
mode="outlined" variant="normal"
onPress={() => navigation.navigate('Scan')} onPress={() => navigation.navigate('Scan')}>
style={styles.scanButton}
labelStyle={styles.scanButtonLabel}
contentStyle={styles.scanButtonContent}>
START SCAN START SCAN
</Button> </DTButton>
</View> </View>
<View style={styles.footer}> <View style={styles.footer}>
@@ -74,21 +71,6 @@ const styles = StyleSheet.create({
opacity: 0.9, opacity: 0.9,
paddingHorizontal: 20, paddingHorizontal: 20,
}, },
scanButton: {
borderColor: DTColors.modeNormal,
borderWidth: 2,
borderRadius: 4,
},
scanButtonLabel: {
color: DTColors.modeNormal,
fontSize: 18,
fontWeight: '600',
letterSpacing: 2,
},
scanButtonContent: {
paddingVertical: 12,
paddingHorizontal: 32,
},
footer: { footer: {
alignItems: 'center', alignItems: 'center',
paddingBottom: 20, paddingBottom: 20,

View File

@@ -1,8 +1,8 @@
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import { StyleSheet, View, ScrollView, Linking, TouchableOpacity } from 'react-native'; import { StyleSheet, View, ScrollView, Linking, TouchableOpacity } from 'react-native';
import { Button, Text, Surface, Divider, Chip } from 'react-native-paper'; import { Button, Text, Surface, Divider, Chip } from 'react-native-paper';
import { DTCard, DTButton, DTColors } from 'react-native-dt-theme';
import type { ResultScreenProps } from '../types/navigation'; import type { ResultScreenProps } from '../types/navigation';
import { DTColors } from '../theme';
import { matchChipToProducts, getMatchSummary, getDesfireEvMismatchWarning, getMifareClassicCapacityWarning } from '../services/matching'; import { matchChipToProducts, getMatchSummary, getDesfireEvMismatchWarning, getMifareClassicCapacityWarning } from '../services/matching';
import { Product } from '../types/products'; import { Product } from '../types/products';
import { getChipInfo, getChipFamilyInfo, getSecurityLevelDescription } from '../data/chipInfo'; import { getChipInfo, getChipFamilyInfo, getSecurityLevelDescription } from '../data/chipInfo';
@@ -72,11 +72,7 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) {
<View style={styles.content}> <View style={styles.content}>
{/* Chip Identification Card */} {/* Chip Identification Card */}
{transponder && ( {transponder && (
<Surface style={styles.identificationCard} elevation={1}> <DTCard mode="success" title="CHIP IDENTIFIED" style={{marginBottom: 20}}>
<Text variant="labelLarge" style={styles.identificationLabel}>
CHIP IDENTIFIED
</Text>
<Divider style={styles.divider} />
<Text variant="headlineMedium" style={styles.chipName}> <Text variant="headlineMedium" style={styles.chipName}>
{transponder.chipName} {transponder.chipName}
@@ -147,7 +143,7 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) {
{transponder.cloneabilityNote} {transponder.cloneabilityNote}
</Text> </Text>
)} )}
</Surface> </DTCard>
)} )}
{/* Educational Chip Info Card */} {/* Educational Chip Info Card */}
@@ -380,11 +376,7 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) {
)} )}
{/* Raw Tag Data Card */} {/* Raw Tag Data Card */}
<Surface style={styles.resultCard} elevation={1}> <DTCard mode="normal" title="RAW TAG DATA" style={{marginBottom: 20}}>
<Text variant="labelLarge" style={styles.cardLabel}>
RAW TAG DATA
</Text>
<Divider style={styles.divider} />
{tagData ? ( {tagData ? (
<> <>
@@ -444,7 +436,7 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) {
No tag data available No tag data available
</Text> </Text>
)} )}
</Surface> </DTCard>
{/* No Detection Card (fallback) */} {/* No Detection Card (fallback) */}
{!transponder && ( {!transponder && (
@@ -494,13 +486,12 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) {
{/* Action Buttons */} {/* Action Buttons */}
<View style={styles.actions}> <View style={styles.actions}>
<Button <DTButton
mode="outlined" variant="normal"
onPress={() => navigation.navigate('Scan')} onPress={() => navigation.navigate('Scan')}
style={styles.actionButton} style={{width: '100%'}}>
labelStyle={styles.actionButtonLabel}>
SCAN ANOTHER SCAN ANOTHER
</Button> </DTButton>
<Button <Button
mode="text" mode="text"

View File

@@ -1,8 +1,8 @@
import React, { useCallback, useEffect } from 'react'; import React, { useCallback, useEffect } from 'react';
import { StyleSheet, View, Platform } from 'react-native'; import { StyleSheet, View, Platform } from 'react-native';
import { Button, Text } from 'react-native-paper'; import { Button, Text } from 'react-native-paper';
import { DTButton, DTColors } from 'react-native-dt-theme';
import type { ScanScreenProps } from '../types/navigation'; import type { ScanScreenProps } from '../types/navigation';
import { DTColors } from '../theme';
import { useScan } from '../hooks'; import { useScan } from '../hooks';
import { getScanInstructions } from '../services/nfc'; import { getScanInstructions } from '../services/nfc';
import { ScanAnimation } from '../components'; import { ScanAnimation } from '../components';
@@ -155,13 +155,12 @@ export function ScanScreen({ navigation }: ScanScreenProps) {
: 'Enable NFC in your device settings to scan tags.'} : 'Enable NFC in your device settings to scan tags.'}
</Text> </Text>
{Platform.OS === 'android' && ( {Platform.OS === 'android' && (
<Button <DTButton
mode="outlined" variant="emphasis"
onPress={openSettings} onPress={openSettings}
style={styles.settingsButton} style={styles.settingsButton}>
labelStyle={styles.settingsButtonLabel}>
OPEN SETTINGS OPEN SETTINGS
</Button> </DTButton>
)} )}
</View> </View>
<View style={styles.footer}> <View style={styles.footer}>
@@ -230,13 +229,11 @@ export function ScanScreen({ navigation }: ScanScreenProps) {
{getErrorHint()} {getErrorHint()}
</Text> </Text>
)} )}
<Button <DTButton
mode="outlined" variant="normal"
onPress={handleRetry} onPress={handleRetry}>
style={styles.retryButton}
labelStyle={styles.buttonLabel}>
TRY AGAIN TRY AGAIN
</Button> </DTButton>
</> </>
)} )}
@@ -245,13 +242,11 @@ export function ScanScreen({ navigation }: ScanScreenProps) {
<Text variant="headlineMedium" style={styles.readyText}> <Text variant="headlineMedium" style={styles.readyText}>
READY TO SCAN READY TO SCAN
</Text> </Text>
<Button <DTButton
mode="outlined" variant="normal"
onPress={startScan} onPress={startScan}>
style={styles.startButton}
labelStyle={styles.buttonLabel}>
START START
</Button> </DTButton>
</> </>
)} )}
@@ -368,32 +363,14 @@ const styles = StyleSheet.create({
paddingHorizontal: 20, paddingHorizontal: 20,
fontStyle: 'italic', fontStyle: 'italic',
}, },
retryButton: {
borderColor: DTColors.modeNormal,
borderWidth: 2,
},
settingsButton: { settingsButton: {
borderColor: DTColors.modeEmphasis,
borderWidth: 2,
marginTop: 16, marginTop: 16,
}, },
settingsButtonLabel: {
color: DTColors.modeEmphasis,
letterSpacing: 2,
},
readyText: { readyText: {
color: DTColors.modeEmphasis, color: DTColors.modeEmphasis,
letterSpacing: 2, letterSpacing: 2,
marginBottom: 32, marginBottom: 32,
}, },
startButton: {
borderColor: DTColors.modeNormal,
borderWidth: 2,
},
buttonLabel: {
color: DTColors.modeNormal,
letterSpacing: 2,
},
processingText: { processingText: {
color: DTColors.modeEmphasis, color: DTColors.modeEmphasis,
letterSpacing: 4, letterSpacing: 4,

View File

@@ -3,7 +3,7 @@
"strict": true, "strict": true,
"target": "ESNext", "target": "ESNext",
"lib": [ "lib": [
"ES2020", "ES2021",
"DOM" "DOM"
], ],
"module": "ESNext", "module": "ESNext",
@@ -21,13 +21,16 @@
] ]
}, },
"include": [ "include": [
"**/*.ts", "src/**/*.ts",
"**/*.tsx" "src/**/*.tsx",
"*.ts",
"*.tsx"
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",
"android", "android",
"ios" "ios",
"../react-native-dt-theme"
], ],
"extends": "expo/tsconfig.base" "extends": "expo/tsconfig.base"
} }