diff --git a/metro.config.js b/metro.config.js index 40eff0a..f28aedf 100644 --- a/metro.config.js +++ b/metro.config.js @@ -1,5 +1,26 @@ 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); +// 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; diff --git a/package-lock.json b/package-lock.json index e6590ab..bf873ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,10 +16,12 @@ "expo-status-bar": "^3.0.9", "react": "19.1.0", "react-native": "0.81.5", + "react-native-dt-theme": "file:../react-native-dt-theme", "react-native-nfc-manager": "^3.17.2", "react-native-paper": "^5.14.5", "react-native-safe-area-context": "~5.6.0", "react-native-screens": "~4.16.0", + "react-native-svg": "15.12.1", "react-native-vector-icons": "^10.2.0" }, "devDependencies": { @@ -43,6 +45,31 @@ "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": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.2.0.tgz", @@ -4860,6 +4887,12 @@ "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": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", @@ -5430,6 +5463,47 @@ "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": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -5688,6 +5762,61 @@ "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": { "version": "16.4.7", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", @@ -5770,6 +5899,18 @@ "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": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", @@ -9873,6 +10014,12 @@ "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": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -10467,6 +10614,18 @@ "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": { "version": "1.1.1", "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": { "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", @@ -11546,6 +11709,21 @@ "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": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.3.0.tgz", diff --git a/package.json b/package.json index 7991fc9..149ba7c 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "react-native-dt-theme": "file:../react-native-dt-theme", "@react-navigation/native": "^7.1.27", "@react-navigation/native-stack": "^7.9.1", "babel-preset-expo": "~54.0.10", @@ -27,6 +28,7 @@ "react-native-paper": "^5.14.5", "react-native-safe-area-context": "~5.6.0", "react-native-screens": "~4.16.0", + "react-native-svg": "15.12.1", "react-native-vector-icons": "^10.2.0" }, "devDependencies": { diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 52873f5..82f2c9a 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -1,8 +1,8 @@ import React from 'react'; 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 {DTColors} from '../theme'; export function HomeScreen({navigation}: HomeScreenProps) { return ( @@ -21,14 +21,11 @@ export function HomeScreen({navigation}: HomeScreenProps) { Scan any NFC transponder to find compatible Dangerous Things implants. - + @@ -74,21 +71,6 @@ const styles = StyleSheet.create({ opacity: 0.9, 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: { alignItems: 'center', paddingBottom: 20, diff --git a/src/screens/ResultScreen.tsx b/src/screens/ResultScreen.tsx index 19e5d99..19742e5 100644 --- a/src/screens/ResultScreen.tsx +++ b/src/screens/ResultScreen.tsx @@ -1,8 +1,8 @@ import React, { useMemo, useState } from 'react'; import { StyleSheet, View, ScrollView, Linking, TouchableOpacity } from 'react-native'; 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 { DTColors } from '../theme'; import { matchChipToProducts, getMatchSummary, getDesfireEvMismatchWarning, getMifareClassicCapacityWarning } from '../services/matching'; import { Product } from '../types/products'; import { getChipInfo, getChipFamilyInfo, getSecurityLevelDescription } from '../data/chipInfo'; @@ -72,11 +72,7 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) { {/* Chip Identification Card */} {transponder && ( - - - CHIP IDENTIFIED - - + {transponder.chipName} @@ -147,7 +143,7 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) { {transponder.cloneabilityNote} )} - + )} {/* Educational Chip Info Card */} @@ -380,11 +376,7 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) { )} {/* Raw Tag Data Card */} - - - RAW TAG DATA - - + {tagData ? ( <> @@ -444,7 +436,7 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) { No tag data available )} - + {/* No Detection Card (fallback) */} {!transponder && ( @@ -494,13 +486,12 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) { {/* Action Buttons */} - + + )} @@ -230,13 +229,11 @@ export function ScanScreen({ navigation }: ScanScreenProps) { {getErrorHint()} )} - + )} @@ -245,13 +242,11 @@ export function ScanScreen({ navigation }: ScanScreenProps) { READY TO SCAN - + )} @@ -368,32 +363,14 @@ const styles = StyleSheet.create({ paddingHorizontal: 20, fontStyle: 'italic', }, - retryButton: { - borderColor: DTColors.modeNormal, - borderWidth: 2, - }, settingsButton: { - borderColor: DTColors.modeEmphasis, - borderWidth: 2, marginTop: 16, }, - settingsButtonLabel: { - color: DTColors.modeEmphasis, - letterSpacing: 2, - }, readyText: { color: DTColors.modeEmphasis, letterSpacing: 2, marginBottom: 32, }, - startButton: { - borderColor: DTColors.modeNormal, - borderWidth: 2, - }, - buttonLabel: { - color: DTColors.modeNormal, - letterSpacing: 2, - }, processingText: { color: DTColors.modeEmphasis, letterSpacing: 4, diff --git a/tsconfig.json b/tsconfig.json index ca05969..3d5d033 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "strict": true, "target": "ESNext", "lib": [ - "ES2020", + "ES2021", "DOM" ], "module": "ESNext", @@ -21,13 +21,16 @@ ] }, "include": [ - "**/*.ts", - "**/*.tsx" + "src/**/*.ts", + "src/**/*.tsx", + "*.ts", + "*.tsx" ], "exclude": [ "node_modules", "android", - "ios" + "ios", + "../react-native-dt-theme" ], "extends": "expo/tsconfig.base" }