rn-backstage 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +2 -0
  2. package/lib/commonjs/Backstage.js +40 -33
  3. package/lib/commonjs/Backstage.js.map +1 -1
  4. package/lib/commonjs/ThemeContext.js +43 -0
  5. package/lib/commonjs/ThemeContext.js.map +1 -0
  6. package/lib/commonjs/components/BackstagePanel.js +17 -10
  7. package/lib/commonjs/components/BackstagePanel.js.map +1 -1
  8. package/lib/commonjs/components/FlagsTab.js +50 -49
  9. package/lib/commonjs/components/FlagsTab.js.map +1 -1
  10. package/lib/commonjs/components/FloatingPill.js +4 -2
  11. package/lib/commonjs/components/FloatingPill.js.map +1 -1
  12. package/lib/commonjs/components/InfoTab.js +73 -107
  13. package/lib/commonjs/components/InfoTab.js.map +1 -1
  14. package/lib/commonjs/components/JsonTreeView.js +39 -34
  15. package/lib/commonjs/components/JsonTreeView.js.map +1 -1
  16. package/lib/commonjs/components/LogItem.js +33 -29
  17. package/lib/commonjs/components/LogItem.js.map +1 -1
  18. package/lib/commonjs/components/LogsTab.js +37 -42
  19. package/lib/commonjs/components/LogsTab.js.map +1 -1
  20. package/lib/commonjs/components/NetworkItem.js +111 -135
  21. package/lib/commonjs/components/NetworkItem.js.map +1 -1
  22. package/lib/commonjs/components/NetworkTab.js +48 -49
  23. package/lib/commonjs/components/NetworkTab.js.map +1 -1
  24. package/lib/commonjs/components/TabBar.js +8 -5
  25. package/lib/commonjs/components/TabBar.js.map +1 -1
  26. package/lib/commonjs/constants.js +24 -1
  27. package/lib/commonjs/constants.js.map +1 -1
  28. package/lib/commonjs/index.js +19 -0
  29. package/lib/commonjs/index.js.map +1 -1
  30. package/lib/commonjs/types.js.map +1 -1
  31. package/lib/module/Backstage.js +40 -33
  32. package/lib/module/Backstage.js.map +1 -1
  33. package/lib/module/ThemeContext.js +37 -0
  34. package/lib/module/ThemeContext.js.map +1 -0
  35. package/lib/module/components/BackstagePanel.js +19 -12
  36. package/lib/module/components/BackstagePanel.js.map +1 -1
  37. package/lib/module/components/FlagsTab.js +51 -50
  38. package/lib/module/components/FlagsTab.js.map +1 -1
  39. package/lib/module/components/FloatingPill.js +5 -3
  40. package/lib/module/components/FloatingPill.js.map +1 -1
  41. package/lib/module/components/InfoTab.js +73 -107
  42. package/lib/module/components/InfoTab.js.map +1 -1
  43. package/lib/module/components/JsonTreeView.js +42 -38
  44. package/lib/module/components/JsonTreeView.js.map +1 -1
  45. package/lib/module/components/LogItem.js +35 -31
  46. package/lib/module/components/LogItem.js.map +1 -1
  47. package/lib/module/components/LogsTab.js +38 -43
  48. package/lib/module/components/LogsTab.js.map +1 -1
  49. package/lib/module/components/NetworkItem.js +113 -137
  50. package/lib/module/components/NetworkItem.js.map +1 -1
  51. package/lib/module/components/NetworkTab.js +49 -50
  52. package/lib/module/components/NetworkTab.js.map +1 -1
  53. package/lib/module/components/TabBar.js +10 -7
  54. package/lib/module/components/TabBar.js.map +1 -1
  55. package/lib/module/constants.js +23 -0
  56. package/lib/module/constants.js.map +1 -1
  57. package/lib/module/index.js +1 -0
  58. package/lib/module/index.js.map +1 -1
  59. package/lib/module/types.js.map +1 -1
  60. package/lib/typescript/Backstage.d.ts.map +1 -1
  61. package/lib/typescript/ThemeContext.d.ts +11 -0
  62. package/lib/typescript/ThemeContext.d.ts.map +1 -0
  63. package/lib/typescript/components/BackstagePanel.d.ts +1 -0
  64. package/lib/typescript/components/BackstagePanel.d.ts.map +1 -1
  65. package/lib/typescript/components/FlagsTab.d.ts.map +1 -1
  66. package/lib/typescript/components/FloatingPill.d.ts.map +1 -1
  67. package/lib/typescript/components/InfoTab.d.ts +1 -0
  68. package/lib/typescript/components/InfoTab.d.ts.map +1 -1
  69. package/lib/typescript/components/JsonTreeView.d.ts.map +1 -1
  70. package/lib/typescript/components/LogItem.d.ts +1 -0
  71. package/lib/typescript/components/LogItem.d.ts.map +1 -1
  72. package/lib/typescript/components/LogsTab.d.ts +1 -0
  73. package/lib/typescript/components/LogsTab.d.ts.map +1 -1
  74. package/lib/typescript/components/NetworkItem.d.ts +1 -0
  75. package/lib/typescript/components/NetworkItem.d.ts.map +1 -1
  76. package/lib/typescript/components/NetworkTab.d.ts +1 -0
  77. package/lib/typescript/components/NetworkTab.d.ts.map +1 -1
  78. package/lib/typescript/components/TabBar.d.ts.map +1 -1
  79. package/lib/typescript/constants.d.ts +1 -0
  80. package/lib/typescript/constants.d.ts.map +1 -1
  81. package/lib/typescript/index.d.ts +2 -0
  82. package/lib/typescript/index.d.ts.map +1 -1
  83. package/lib/typescript/types.d.ts +4 -0
  84. package/lib/typescript/types.d.ts.map +1 -1
  85. package/package.json +1 -1
  86. package/src/Backstage.tsx +39 -33
  87. package/src/ThemeContext.tsx +38 -0
  88. package/src/components/BackstagePanel.tsx +66 -57
  89. package/src/components/FlagsTab.tsx +123 -174
  90. package/src/components/FloatingPill.tsx +6 -3
  91. package/src/components/InfoTab.tsx +152 -186
  92. package/src/components/JsonTreeView.tsx +53 -73
  93. package/src/components/LogItem.tsx +55 -100
  94. package/src/components/LogsTab.tsx +110 -132
  95. package/src/components/NetworkItem.tsx +306 -417
  96. package/src/components/NetworkTab.tsx +129 -163
  97. package/src/components/TabBar.tsx +51 -47
  98. package/src/constants.ts +23 -0
  99. package/src/index.ts +2 -0
  100. package/src/types.ts +6 -0
@@ -1,8 +1,9 @@
1
- import React, { useCallback, useState } from 'react'
1
+ import React, { useCallback, useMemo, useState } from 'react'
2
2
  import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'
3
- import { DarkTheme, MonospaceFont } from '../constants'
3
+ import { MonospaceFont } from '../constants'
4
+ import { useBackstageTheme } from '../ThemeContext'
4
5
  import { LogLevel } from '../types'
5
- import type { LogEntry, BackstageStyleOverrides } from '../types'
6
+ import type { LogEntry, BackstageStyleOverrides, BackstageTheme } from '../types'
6
7
  import { formatTimestamp } from '../utils/formatTimestamp'
7
8
  import { JsonTreeView } from './JsonTreeView'
8
9
 
@@ -11,50 +12,39 @@ import { JsonTreeView } from './JsonTreeView'
11
12
  interface LogItemProps {
12
13
  item: LogEntry
13
14
  onCopy?: (text: string) => void
15
+ jsonMaxDepth?: number
14
16
  styles?: BackstageStyleOverrides
15
17
  }
16
18
 
17
19
  // ─── Badge Colors ────────────────────────────────────────────────────────────
18
20
 
19
- function getBadgeConfig(level: LogLevel): {
20
- label: string
21
- color: string
22
- bgColor: string
23
- rowBg: string
24
- } {
21
+ function getBadgeConfig(
22
+ level: LogLevel,
23
+ t: BackstageTheme,
24
+ ): { label: string; color: string; bgColor: string; rowBg: string } {
25
25
  switch (level) {
26
26
  case LogLevel.error:
27
27
  return {
28
28
  label: 'ERROR',
29
- color: DarkTheme.error,
30
- bgColor: DarkTheme.errorDim,
29
+ color: t.error,
30
+ bgColor: t.errorDim,
31
31
  rowBg: 'rgba(255, 77, 106, 0.06)',
32
32
  }
33
33
  case LogLevel.warn:
34
34
  return {
35
35
  label: 'WARN',
36
- color: DarkTheme.warning,
37
- bgColor: DarkTheme.warningDim,
36
+ color: t.warning,
37
+ bgColor: t.warningDim,
38
38
  rowBg: 'rgba(255, 178, 36, 0.06)',
39
39
  }
40
40
  case LogLevel.info:
41
- return {
42
- label: 'INFO',
43
- color: DarkTheme.info,
44
- bgColor: DarkTheme.infoDim,
45
- rowBg: 'transparent',
46
- }
41
+ return { label: 'INFO', color: t.info, bgColor: t.infoDim, rowBg: 'transparent' }
47
42
  case LogLevel.debug:
48
- return {
49
- label: 'DEBUG',
50
- color: DarkTheme.debugColor,
51
- bgColor: DarkTheme.debugDim,
52
- rowBg: 'transparent',
53
- }
43
+ return { label: 'DEBUG', color: t.debugColor, bgColor: t.debugDim, rowBg: 'transparent' }
54
44
  default:
55
45
  return {
56
46
  label: 'LOG',
57
- color: DarkTheme.textSecondary,
47
+ color: t.textSecondary,
58
48
  bgColor: 'rgba(160, 160, 176, 0.1)',
59
49
  rowBg: 'transparent',
60
50
  }
@@ -64,9 +54,11 @@ function getBadgeConfig(level: LogLevel): {
64
54
  // ─── Component ───────────────────────────────────────────────────────────────
65
55
 
66
56
  export const LogItem: React.FC<LogItemProps> = React.memo(
67
- ({ item, onCopy, styles: propStyles }) => {
57
+ ({ item, onCopy, jsonMaxDepth, styles: propStyles }) => {
58
+ const theme = useBackstageTheme()
59
+ const s = useMemo(() => createStyles(theme), [theme])
68
60
  const [expanded, setExpanded] = useState(false)
69
- const badge = getBadgeConfig(item.level)
61
+ const badge = getBadgeConfig(item.level, theme)
70
62
  const hasData = item.data !== undefined
71
63
 
72
64
  const toggleExpand = useCallback(() => {
@@ -82,47 +74,43 @@ export const LogItem: React.FC<LogItemProps> = React.memo(
82
74
 
83
75
  return (
84
76
  <TouchableOpacity
85
- style={[styles.container, { backgroundColor: badge.rowBg }]}
77
+ style={[s.container, { backgroundColor: badge.rowBg }]}
86
78
  onPress={hasData ? toggleExpand : undefined}
87
79
  onLongPress={handleCopy}
88
80
  activeOpacity={hasData ? 0.7 : 1}
89
81
  >
90
- {/* Header row: badge + timestamp + copy */}
91
- <View style={styles.headerRow}>
92
- <View style={[styles.badge, { backgroundColor: badge.bgColor }]}>
93
- <Text style={[styles.badgeText, { color: badge.color }]}>{badge.label}</Text>
82
+ <View style={s.headerRow}>
83
+ <View style={[s.badge, { backgroundColor: badge.bgColor }]}>
84
+ <Text style={[s.badgeText, { color: badge.color }]}>{badge.label}</Text>
94
85
  </View>
95
- <Text style={[styles.timestamp, propStyles?.logTimestampStyle]}>
86
+ <Text style={[s.timestamp, propStyles?.logTimestampStyle]}>
96
87
  {formatTimestamp(item.timestamp)}
97
88
  </Text>
98
89
  {onCopy && (
99
90
  <TouchableOpacity
100
- style={styles.copyButton}
91
+ style={s.copyButton}
101
92
  onPress={handleCopy}
102
93
  hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
103
94
  >
104
- <Text style={styles.copyButtonText}>⧉</Text>
95
+ <Text style={s.copyButtonText}>⧉</Text>
105
96
  </TouchableOpacity>
106
97
  )}
107
98
  </View>
108
99
 
109
- {/* Message */}
110
100
  <Text
111
- style={[styles.message, propStyles?.logMessageStyle]}
101
+ style={[s.message, propStyles?.logMessageStyle]}
112
102
  numberOfLines={expanded ? undefined : 3}
113
103
  >
114
104
  {item.message}
115
105
  </Text>
116
106
 
117
- {/* Expandable data */}
118
107
  {expanded && hasData && (
119
- <View style={styles.dataContainer}>
120
- <JsonTreeView data={item.data} hideRoot maxDepth={5} />
108
+ <View style={s.dataContainer}>
109
+ <JsonTreeView data={item.data} hideRoot maxDepth={jsonMaxDepth} />
121
110
  </View>
122
111
  )}
123
112
 
124
- {/* Expand hint */}
125
- {hasData && !expanded && <Text style={styles.expandHint}>tap to expand ▾</Text>}
113
+ {hasData && !expanded && <Text style={s.expandHint}>tap to expand ▾</Text>}
126
114
  </TouchableOpacity>
127
115
  )
128
116
  },
@@ -130,60 +118,27 @@ export const LogItem: React.FC<LogItemProps> = React.memo(
130
118
 
131
119
  // ─── Styles ──────────────────────────────────────────────────────────────────
132
120
 
133
- const styles = StyleSheet.create({
134
- container: {
135
- paddingHorizontal: 14,
136
- paddingVertical: 10,
137
- borderBottomWidth: 1,
138
- borderBottomColor: DarkTheme.border,
139
- },
140
- headerRow: {
141
- flexDirection: 'row',
142
- alignItems: 'center',
143
- marginBottom: 4,
144
- },
145
- badge: {
146
- borderRadius: 4,
147
- paddingHorizontal: 6,
148
- paddingVertical: 2,
149
- marginRight: 8,
150
- },
151
- badgeText: {
152
- fontFamily: MonospaceFont,
153
- fontSize: 10,
154
- fontWeight: '800',
155
- letterSpacing: 0.5,
156
- },
157
- timestamp: {
158
- fontFamily: MonospaceFont,
159
- fontSize: 11,
160
- color: DarkTheme.textMuted,
161
- flex: 1,
162
- },
163
- copyButton: {
164
- padding: 4,
165
- },
166
- copyButtonText: {
167
- fontSize: 16,
168
- color: DarkTheme.textMuted,
169
- },
170
- message: {
171
- fontFamily: MonospaceFont,
172
- fontSize: 12,
173
- color: DarkTheme.text,
174
- lineHeight: 18,
175
- },
176
- dataContainer: {
177
- marginTop: 8,
178
- paddingTop: 8,
179
- borderTopWidth: 1,
180
- borderTopColor: DarkTheme.border,
181
- },
182
- expandHint: {
183
- fontFamily: MonospaceFont,
184
- fontSize: 10,
185
- color: DarkTheme.textMuted,
186
- marginTop: 4,
187
- fontStyle: 'italic',
188
- },
189
- })
121
+ const createStyles = (t: BackstageTheme) =>
122
+ StyleSheet.create({
123
+ container: {
124
+ paddingHorizontal: 14,
125
+ paddingVertical: 10,
126
+ borderBottomWidth: 1,
127
+ borderBottomColor: t.border,
128
+ },
129
+ headerRow: { flexDirection: 'row', alignItems: 'center', marginBottom: 4 },
130
+ badge: { borderRadius: 4, paddingHorizontal: 6, paddingVertical: 2, marginRight: 8 },
131
+ badgeText: { fontFamily: MonospaceFont, fontSize: 10, fontWeight: '800', letterSpacing: 0.5 },
132
+ timestamp: { fontFamily: MonospaceFont, fontSize: 11, color: t.textMuted, flex: 1 },
133
+ copyButton: { padding: 4 },
134
+ copyButtonText: { fontSize: 16, color: t.textMuted },
135
+ message: { fontFamily: MonospaceFont, fontSize: 12, color: t.text, lineHeight: 18 },
136
+ dataContainer: { marginTop: 8, paddingTop: 8, borderTopWidth: 1, borderTopColor: t.border },
137
+ expandHint: {
138
+ fontFamily: MonospaceFont,
139
+ fontSize: 10,
140
+ color: t.textMuted,
141
+ marginTop: 4,
142
+ fontStyle: 'italic',
143
+ },
144
+ })
@@ -1,7 +1,8 @@
1
1
  import React, { useCallback, useMemo, useState } from 'react'
2
2
  import { FlatList, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'
3
- import { DarkTheme, MonospaceFont, TestIDs } from '../constants'
4
- import type { LogEntry, BackstageStyleOverrides } from '../types'
3
+ import { MonospaceFont, TestIDs } from '../constants'
4
+ import { useBackstageTheme } from '../ThemeContext'
5
+ import type { LogEntry, BackstageStyleOverrides, BackstageTheme } from '../types'
5
6
  import { LogItem } from './LogItem'
6
7
  import { formatTimestamp } from '../utils/formatTimestamp'
7
8
 
@@ -11,6 +12,7 @@ interface LogsTabProps {
11
12
  logs: LogEntry[]
12
13
  onRefresh: () => void
13
14
  onCopyLogs?: (logs: string) => void
15
+ jsonMaxDepth?: number
14
16
  styles?: BackstageStyleOverrides
15
17
  }
16
18
 
@@ -20,31 +22,29 @@ export const LogsTab: React.FC<LogsTabProps> = ({
20
22
  logs,
21
23
  onRefresh,
22
24
  onCopyLogs,
25
+ jsonMaxDepth,
23
26
  styles: propStyles,
24
27
  }) => {
28
+ const theme = useBackstageTheme()
29
+ const s = useMemo(() => createStyles(theme), [theme])
25
30
  const [searchText, setSearchText] = useState('')
26
31
 
27
- // Filter logs based on search text
28
32
  const filteredLogs = useMemo(() => {
29
33
  if (!searchText.trim()) return logs
30
-
31
34
  const query = searchText.toLowerCase()
32
35
  return logs.filter(log => {
33
36
  return log.message.toLowerCase().includes(query) || log.level.toLowerCase().includes(query)
34
37
  })
35
38
  }, [logs, searchText])
36
39
 
37
- // Copy all visible logs to text
38
40
  const handleCopyAll = useCallback(() => {
39
41
  if (!onCopyLogs) return
40
-
41
42
  const text = filteredLogs
42
43
  .map(log => `[${log.level.toUpperCase()}] ${formatTimestamp(log.timestamp)} ${log.message}`)
43
44
  .join('\n')
44
45
  onCopyLogs(text)
45
46
  }, [filteredLogs, onCopyLogs])
46
47
 
47
- // Copy individual log
48
48
  const handleCopyItem = useCallback(
49
49
  (text: string) => {
50
50
  if (onCopyLogs) {
@@ -54,10 +54,14 @@ export const LogsTab: React.FC<LogsTabProps> = ({
54
54
  [onCopyLogs],
55
55
  )
56
56
 
57
- // Render log item
58
57
  const renderItem = useCallback(
59
58
  ({ item }: { item: LogEntry }) => (
60
- <LogItem item={item} onCopy={onCopyLogs ? handleCopyItem : undefined} styles={propStyles} />
59
+ <LogItem
60
+ item={item}
61
+ onCopy={onCopyLogs ? handleCopyItem : undefined}
62
+ jsonMaxDepth={jsonMaxDepth}
63
+ styles={propStyles}
64
+ />
61
65
  ),
62
66
  [handleCopyItem, onCopyLogs, propStyles],
63
67
  )
@@ -65,16 +69,15 @@ export const LogsTab: React.FC<LogsTabProps> = ({
65
69
  const keyExtractor = useCallback((item: LogEntry) => item.id, [])
66
70
 
67
71
  return (
68
- <View style={styles.container}>
69
- {/* Search Bar */}
70
- <View style={styles.searchContainer}>
71
- <View style={styles.searchInputWrapper}>
72
- <Text style={styles.searchIcon}>⌕</Text>
72
+ <View style={s.container}>
73
+ <View style={s.searchContainer}>
74
+ <View style={s.searchInputWrapper}>
75
+ <Text style={s.searchIcon}>⌕</Text>
73
76
  <TextInput
74
77
  testID={TestIDs.logsTab.searchInput}
75
- style={styles.searchInput}
78
+ style={s.searchInput}
76
79
  placeholder="Filter logs..."
77
- placeholderTextColor={DarkTheme.textMuted}
80
+ placeholderTextColor={theme.textMuted}
78
81
  value={searchText}
79
82
  onChangeText={setSearchText}
80
83
  autoCapitalize="none"
@@ -86,26 +89,24 @@ export const LogsTab: React.FC<LogsTabProps> = ({
86
89
  {onCopyLogs && (
87
90
  <TouchableOpacity
88
91
  testID={TestIDs.logsTab.copyButton}
89
- style={styles.copyAllButton}
92
+ style={s.copyAllButton}
90
93
  onPress={handleCopyAll}
91
94
  activeOpacity={0.7}
92
95
  >
93
- <Text style={styles.copyAllText}>Copy All</Text>
96
+ <Text style={s.copyAllText}>Copy All</Text>
94
97
  </TouchableOpacity>
95
98
  )}
96
99
  </View>
97
100
 
98
- {/* Log Count */}
99
- <View style={styles.countBar}>
100
- <Text style={styles.countText}>
101
+ <View style={s.countBar}>
102
+ <Text style={s.countText}>
101
103
  {filteredLogs.length === logs.length
102
104
  ? `${logs.length} log${logs.length !== 1 ? 's' : ''}`
103
105
  : `${filteredLogs.length} of ${logs.length} logs`}
104
106
  </Text>
105
- <Text style={styles.pullHint}>↓ pull to refresh</Text>
107
+ <Text style={s.pullHint}>↓ pull to refresh</Text>
106
108
  </View>
107
109
 
108
- {/* Log List */}
109
110
  <FlatList
110
111
  testID={TestIDs.logsTab.list}
111
112
  data={filteredLogs}
@@ -113,16 +114,15 @@ export const LogsTab: React.FC<LogsTabProps> = ({
113
114
  keyExtractor={keyExtractor}
114
115
  refreshing={false}
115
116
  onRefresh={onRefresh}
116
- style={styles.list}
117
- contentContainerStyle={filteredLogs.length === 0 ? styles.emptyContainer : undefined}
117
+ style={s.list}
118
+ contentContainerStyle={filteredLogs.length === 0 ? s.emptyContainer : undefined}
118
119
  ListEmptyComponent={
119
- <View style={styles.emptyState}>
120
- <Text style={styles.emptyIcon}>📋</Text>
121
- <Text style={styles.emptyTitle}>No logs yet</Text>
122
- <Text style={styles.emptySubtitle}>Console output will appear here</Text>
120
+ <View style={s.emptyState}>
121
+ <Text style={s.emptyIcon}>📋</Text>
122
+ <Text style={s.emptyTitle}>No logs yet</Text>
123
+ <Text style={s.emptySubtitle}>Console output will appear here</Text>
123
124
  </View>
124
125
  }
125
- // Perf optimizations
126
126
  maxToRenderPerBatch={20}
127
127
  windowSize={10}
128
128
  initialNumToRender={20}
@@ -135,105 +135,83 @@ export const LogsTab: React.FC<LogsTabProps> = ({
135
135
 
136
136
  // ─── Styles ──────────────────────────────────────────────────────────────────
137
137
 
138
- const styles = StyleSheet.create({
139
- container: {
140
- flex: 1,
141
- },
142
- searchContainer: {
143
- flexDirection: 'row',
144
- alignItems: 'center',
145
- paddingHorizontal: 14,
146
- paddingVertical: 10,
147
- gap: 10,
148
- borderBottomWidth: 1,
149
- borderBottomColor: DarkTheme.border,
150
- },
151
- searchInputWrapper: {
152
- flex: 1,
153
- flexDirection: 'row',
154
- alignItems: 'center',
155
- backgroundColor: DarkTheme.surfaceElevated,
156
- borderRadius: 10,
157
- borderWidth: 1,
158
- borderColor: DarkTheme.border,
159
- paddingHorizontal: 12,
160
- height: 38,
161
- },
162
- searchIcon: {
163
- fontSize: 16,
164
- color: DarkTheme.textMuted,
165
- marginRight: 8,
166
- },
167
- searchInput: {
168
- flex: 1,
169
- fontFamily: MonospaceFont,
170
- fontSize: 13,
171
- color: DarkTheme.text,
172
- padding: 0,
173
- },
174
- copyAllButton: {
175
- backgroundColor: DarkTheme.accentDim,
176
- borderRadius: 8,
177
- borderWidth: 1,
178
- borderColor: DarkTheme.accent,
179
- paddingHorizontal: 14,
180
- height: 38,
181
- justifyContent: 'center',
182
- },
183
- copyAllText: {
184
- fontFamily: MonospaceFont,
185
- fontSize: 12,
186
- fontWeight: '700',
187
- color: DarkTheme.accent,
188
- letterSpacing: 0.5,
189
- },
190
- countBar: {
191
- flexDirection: 'row',
192
- justifyContent: 'space-between',
193
- alignItems: 'center',
194
- paddingHorizontal: 16,
195
- paddingVertical: 6,
196
- backgroundColor: DarkTheme.surface,
197
- },
198
- countText: {
199
- fontFamily: MonospaceFont,
200
- fontSize: 11,
201
- color: DarkTheme.textMuted,
202
- },
203
- pullHint: {
204
- fontFamily: MonospaceFont,
205
- fontSize: 10,
206
- color: DarkTheme.textMuted,
207
- fontStyle: 'italic',
208
- },
209
- list: {
210
- flex: 1,
211
- },
212
- emptyContainer: {
213
- flex: 1,
214
- justifyContent: 'center',
215
- },
216
- emptyState: {
217
- alignItems: 'center',
218
- justifyContent: 'center',
219
- padding: 40,
220
- },
221
- emptyIcon: {
222
- fontSize: 48,
223
- marginBottom: 16,
224
- opacity: 0.5,
225
- },
226
- emptyTitle: {
227
- fontFamily: MonospaceFont,
228
- fontSize: 16,
229
- fontWeight: '700',
230
- color: DarkTheme.textSecondary,
231
- marginBottom: 8,
232
- },
233
- emptySubtitle: {
234
- fontFamily: MonospaceFont,
235
- fontSize: 13,
236
- color: DarkTheme.textMuted,
237
- textAlign: 'center',
238
- },
239
- })
138
+ const createStyles = (t: BackstageTheme) =>
139
+ StyleSheet.create({
140
+ container: { flex: 1 },
141
+ searchContainer: {
142
+ flexDirection: 'row',
143
+ alignItems: 'center',
144
+ paddingHorizontal: 14,
145
+ paddingVertical: 10,
146
+ gap: 10,
147
+ borderBottomWidth: 1,
148
+ borderBottomColor: t.border,
149
+ },
150
+ searchInputWrapper: {
151
+ flex: 1,
152
+ flexDirection: 'row',
153
+ alignItems: 'center',
154
+ backgroundColor: t.surfaceElevated,
155
+ borderRadius: 10,
156
+ borderWidth: 1,
157
+ borderColor: t.border,
158
+ paddingHorizontal: 12,
159
+ height: 38,
160
+ },
161
+ searchIcon: { fontSize: 16, color: t.textMuted, marginRight: 8 },
162
+ searchInput: {
163
+ flex: 1,
164
+ fontFamily: MonospaceFont,
165
+ fontSize: 13,
166
+ color: t.text,
167
+ padding: 0,
168
+ },
169
+ copyAllButton: {
170
+ backgroundColor: t.accentDim,
171
+ borderRadius: 8,
172
+ borderWidth: 1,
173
+ borderColor: t.accent,
174
+ paddingHorizontal: 14,
175
+ height: 38,
176
+ justifyContent: 'center',
177
+ },
178
+ copyAllText: {
179
+ fontFamily: MonospaceFont,
180
+ fontSize: 12,
181
+ fontWeight: '700',
182
+ color: t.accent,
183
+ letterSpacing: 0.5,
184
+ },
185
+ countBar: {
186
+ flexDirection: 'row',
187
+ justifyContent: 'space-between',
188
+ alignItems: 'center',
189
+ paddingHorizontal: 16,
190
+ paddingVertical: 6,
191
+ backgroundColor: t.surface,
192
+ },
193
+ countText: { fontFamily: MonospaceFont, fontSize: 11, color: t.textMuted },
194
+ pullHint: {
195
+ fontFamily: MonospaceFont,
196
+ fontSize: 10,
197
+ color: t.textMuted,
198
+ fontStyle: 'italic',
199
+ },
200
+ list: { flex: 1 },
201
+ emptyContainer: { flex: 1, justifyContent: 'center' },
202
+ emptyState: { alignItems: 'center', justifyContent: 'center', padding: 40 },
203
+ emptyIcon: { fontSize: 48, marginBottom: 16, opacity: 0.5 },
204
+ emptyTitle: {
205
+ fontFamily: MonospaceFont,
206
+ fontSize: 16,
207
+ fontWeight: '700',
208
+ color: t.textSecondary,
209
+ marginBottom: 8,
210
+ },
211
+ emptySubtitle: {
212
+ fontFamily: MonospaceFont,
213
+ fontSize: 13,
214
+ color: t.textMuted,
215
+ textAlign: 'center',
216
+ },
217
+ })