@buoy-gg/time-machine 7.0.22 → 7.0.23

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 (160) hide show
  1. package/lib/commonjs/components/TimeMachineBody.js +147 -677
  2. package/lib/commonjs/components/TimeMachineBody.js.map +1 -1
  3. package/lib/commonjs/components/TimeMachineModal.js +10 -11
  4. package/lib/commonjs/components/TimeMachineModal.js.map +1 -1
  5. package/lib/commonjs/components/confirm.js +39 -0
  6. package/lib/commonjs/components/confirm.js.map +1 -0
  7. package/lib/commonjs/components/format.js +24 -0
  8. package/lib/commonjs/components/format.js.map +1 -0
  9. package/lib/commonjs/components/list/CaptureBar.js +95 -0
  10. package/lib/commonjs/components/list/CaptureBar.js.map +1 -0
  11. package/lib/commonjs/components/list/RestoreOutcomeCard.js +162 -0
  12. package/lib/commonjs/components/list/RestoreOutcomeCard.js.map +1 -0
  13. package/lib/commonjs/components/list/SnapshotRow.js +141 -0
  14. package/lib/commonjs/components/list/SnapshotRow.js.map +1 -0
  15. package/lib/commonjs/components/list/SourcesStrip.js +126 -0
  16. package/lib/commonjs/components/list/SourcesStrip.js.map +1 -0
  17. package/lib/commonjs/components/list/UndoDeleteBar.js +81 -0
  18. package/lib/commonjs/components/list/UndoDeleteBar.js.map +1 -0
  19. package/lib/commonjs/components/list/WipeAllRow.js +46 -0
  20. package/lib/commonjs/components/list/WipeAllRow.js.map +1 -0
  21. package/lib/commonjs/components/preview/ItemDiffPanel.js +77 -0
  22. package/lib/commonjs/components/preview/ItemDiffPanel.js.map +1 -0
  23. package/lib/commonjs/components/preview/PreviewFlow.js +51 -0
  24. package/lib/commonjs/components/preview/PreviewFlow.js.map +1 -0
  25. package/lib/commonjs/components/preview/RestorePointNameRow.js +83 -0
  26. package/lib/commonjs/components/preview/RestorePointNameRow.js.map +1 -0
  27. package/lib/commonjs/components/preview/RestorePreviewScreen.js +549 -635
  28. package/lib/commonjs/components/preview/RestorePreviewScreen.js.map +1 -1
  29. package/lib/commonjs/components/preview/verdictMeta.js +8 -8
  30. package/lib/commonjs/components/preview/verdictMeta.js.map +1 -1
  31. package/lib/commonjs/components/sources.js +72 -0
  32. package/lib/commonjs/components/sources.js.map +1 -0
  33. package/lib/commonjs/store/snapshotVault.js +93 -9
  34. package/lib/commonjs/store/snapshotVault.js.map +1 -1
  35. package/lib/commonjs/store/timeMachineStore.js +125 -6
  36. package/lib/commonjs/store/timeMachineStore.js.map +1 -1
  37. package/lib/commonjs/sync/timeMachineSyncAdapter.js +41 -0
  38. package/lib/commonjs/sync/timeMachineSyncAdapter.js.map +1 -1
  39. package/lib/commonjs/ui/SwipeActionsRow.js +167 -0
  40. package/lib/commonjs/ui/SwipeActionsRow.js.map +1 -0
  41. package/lib/commonjs/ui/primitives.js +164 -0
  42. package/lib/commonjs/ui/primitives.js.map +1 -0
  43. package/lib/commonjs/ui/tmTheme.js +103 -0
  44. package/lib/commonjs/ui/tmTheme.js.map +1 -0
  45. package/lib/module/components/TimeMachineBody.js +150 -680
  46. package/lib/module/components/TimeMachineBody.js.map +1 -1
  47. package/lib/module/components/TimeMachineModal.js +11 -12
  48. package/lib/module/components/TimeMachineModal.js.map +1 -1
  49. package/lib/module/components/confirm.js +34 -0
  50. package/lib/module/components/confirm.js.map +1 -0
  51. package/lib/module/components/format.js +19 -0
  52. package/lib/module/components/format.js.map +1 -0
  53. package/lib/module/components/list/CaptureBar.js +90 -0
  54. package/lib/module/components/list/CaptureBar.js.map +1 -0
  55. package/lib/module/components/list/RestoreOutcomeCard.js +156 -0
  56. package/lib/module/components/list/RestoreOutcomeCard.js.map +1 -0
  57. package/lib/module/components/list/SnapshotRow.js +138 -0
  58. package/lib/module/components/list/SnapshotRow.js.map +1 -0
  59. package/lib/module/components/list/SourcesStrip.js +121 -0
  60. package/lib/module/components/list/SourcesStrip.js.map +1 -0
  61. package/lib/module/components/list/UndoDeleteBar.js +78 -0
  62. package/lib/module/components/list/UndoDeleteBar.js.map +1 -0
  63. package/lib/module/components/list/WipeAllRow.js +41 -0
  64. package/lib/module/components/list/WipeAllRow.js.map +1 -0
  65. package/lib/module/components/preview/ItemDiffPanel.js +72 -0
  66. package/lib/module/components/preview/ItemDiffPanel.js.map +1 -0
  67. package/lib/module/components/preview/PreviewFlow.js +46 -0
  68. package/lib/module/components/preview/PreviewFlow.js.map +1 -0
  69. package/lib/module/components/preview/RestorePointNameRow.js +78 -0
  70. package/lib/module/components/preview/RestorePointNameRow.js.map +1 -0
  71. package/lib/module/components/preview/RestorePreviewScreen.js +552 -638
  72. package/lib/module/components/preview/RestorePreviewScreen.js.map +1 -1
  73. package/lib/module/components/preview/verdictMeta.js +9 -8
  74. package/lib/module/components/preview/verdictMeta.js.map +1 -1
  75. package/lib/module/components/sources.js +66 -0
  76. package/lib/module/components/sources.js.map +1 -0
  77. package/lib/module/store/snapshotVault.js +87 -9
  78. package/lib/module/store/snapshotVault.js.map +1 -1
  79. package/lib/module/store/timeMachineStore.js +125 -7
  80. package/lib/module/store/timeMachineStore.js.map +1 -1
  81. package/lib/module/sync/timeMachineSyncAdapter.js +41 -0
  82. package/lib/module/sync/timeMachineSyncAdapter.js.map +1 -1
  83. package/lib/module/ui/SwipeActionsRow.js +162 -0
  84. package/lib/module/ui/SwipeActionsRow.js.map +1 -0
  85. package/lib/module/ui/primitives.js +156 -0
  86. package/lib/module/ui/primitives.js.map +1 -0
  87. package/lib/module/ui/tmTheme.js +99 -0
  88. package/lib/module/ui/tmTheme.js.map +1 -0
  89. package/lib/typescript/components/TimeMachineBody.d.ts.map +1 -1
  90. package/lib/typescript/components/TimeMachineModal.d.ts.map +1 -1
  91. package/lib/typescript/components/confirm.d.ts +2 -0
  92. package/lib/typescript/components/confirm.d.ts.map +1 -0
  93. package/lib/typescript/components/format.d.ts +4 -0
  94. package/lib/typescript/components/format.d.ts.map +1 -0
  95. package/lib/typescript/components/list/CaptureBar.d.ts +6 -0
  96. package/lib/typescript/components/list/CaptureBar.d.ts.map +1 -0
  97. package/lib/typescript/components/list/RestoreOutcomeCard.d.ts +11 -0
  98. package/lib/typescript/components/list/RestoreOutcomeCard.d.ts.map +1 -0
  99. package/lib/typescript/components/list/SnapshotRow.d.ts +12 -0
  100. package/lib/typescript/components/list/SnapshotRow.d.ts.map +1 -0
  101. package/lib/typescript/components/list/SourcesStrip.d.ts +5 -0
  102. package/lib/typescript/components/list/SourcesStrip.d.ts.map +1 -0
  103. package/lib/typescript/components/list/UndoDeleteBar.d.ts +8 -0
  104. package/lib/typescript/components/list/UndoDeleteBar.d.ts.map +1 -0
  105. package/lib/typescript/components/list/WipeAllRow.d.ts +5 -0
  106. package/lib/typescript/components/list/WipeAllRow.d.ts.map +1 -0
  107. package/lib/typescript/components/preview/ItemDiffPanel.d.ts +5 -0
  108. package/lib/typescript/components/preview/ItemDiffPanel.d.ts.map +1 -0
  109. package/lib/typescript/components/preview/PreviewFlow.d.ts +9 -0
  110. package/lib/typescript/components/preview/PreviewFlow.d.ts.map +1 -0
  111. package/lib/typescript/components/preview/RestorePointNameRow.d.ts +5 -0
  112. package/lib/typescript/components/preview/RestorePointNameRow.d.ts.map +1 -0
  113. package/lib/typescript/components/preview/RestorePreviewScreen.d.ts +1 -5
  114. package/lib/typescript/components/preview/RestorePreviewScreen.d.ts.map +1 -1
  115. package/lib/typescript/components/preview/verdictMeta.d.ts +5 -0
  116. package/lib/typescript/components/preview/verdictMeta.d.ts.map +1 -1
  117. package/lib/typescript/components/sources.d.ts +36 -0
  118. package/lib/typescript/components/sources.d.ts.map +1 -0
  119. package/lib/typescript/store/snapshotVault.d.ts +48 -0
  120. package/lib/typescript/store/snapshotVault.d.ts.map +1 -1
  121. package/lib/typescript/store/timeMachineStore.d.ts +35 -1
  122. package/lib/typescript/store/timeMachineStore.d.ts.map +1 -1
  123. package/lib/typescript/sync/timeMachineSyncAdapter.d.ts +17 -0
  124. package/lib/typescript/sync/timeMachineSyncAdapter.d.ts.map +1 -1
  125. package/lib/typescript/ui/SwipeActionsRow.d.ts +32 -0
  126. package/lib/typescript/ui/SwipeActionsRow.d.ts.map +1 -0
  127. package/lib/typescript/ui/primitives.d.ts +57 -0
  128. package/lib/typescript/ui/primitives.d.ts.map +1 -0
  129. package/lib/typescript/ui/tmTheme.d.ts +67 -0
  130. package/lib/typescript/ui/tmTheme.d.ts.map +1 -0
  131. package/package.json +7 -7
  132. package/src/components/TimeMachineBody.tsx +183 -817
  133. package/src/components/TimeMachineModal.tsx +10 -11
  134. package/src/components/confirm.ts +35 -0
  135. package/src/components/format.ts +17 -0
  136. package/src/components/list/CaptureBar.tsx +100 -0
  137. package/src/components/list/RestoreOutcomeCard.tsx +159 -0
  138. package/src/components/list/SnapshotRow.tsx +155 -0
  139. package/src/components/list/SourcesStrip.tsx +124 -0
  140. package/src/components/list/UndoDeleteBar.tsx +76 -0
  141. package/src/components/list/WipeAllRow.tsx +42 -0
  142. package/src/components/preview/ItemDiffPanel.tsx +77 -0
  143. package/src/components/preview/PreviewFlow.tsx +70 -0
  144. package/src/components/preview/RestorePointNameRow.tsx +80 -0
  145. package/src/components/preview/RestorePreviewScreen.tsx +535 -535
  146. package/src/components/preview/verdictMeta.ts +8 -8
  147. package/src/components/sources.ts +92 -0
  148. package/src/store/snapshotVault.ts +131 -9
  149. package/src/store/timeMachineStore.ts +136 -5
  150. package/src/sync/timeMachineSyncAdapter.ts +30 -0
  151. package/src/ui/SwipeActionsRow.tsx +199 -0
  152. package/src/ui/primitives.tsx +157 -0
  153. package/src/ui/tmTheme.ts +107 -0
  154. package/lib/commonjs/components/preview/ItemDetailScreen.js +0 -189
  155. package/lib/commonjs/components/preview/ItemDetailScreen.js.map +0 -1
  156. package/lib/module/components/preview/ItemDetailScreen.js +0 -184
  157. package/lib/module/components/preview/ItemDetailScreen.js.map +0 -1
  158. package/lib/typescript/components/preview/ItemDetailScreen.d.ts +0 -11
  159. package/lib/typescript/components/preview/ItemDetailScreen.d.ts.map +0 -1
  160. package/src/components/preview/ItemDetailScreen.tsx +0 -172
@@ -7,725 +7,195 @@ exports.TimeMachineBody = TimeMachineBody;
7
7
  var _react = require("react");
8
8
  var _reactNative = require("react-native");
9
9
  var _sharedUi = require("@buoy-gg/shared-ui");
10
- var _floatingToolsCore = require("@buoy-gg/floating-tools-core");
11
10
  var _core = require("@buoy-gg/core");
12
11
  var _license = require("@buoy-gg/license");
13
12
  var _useTimeMachine = require("../hooks/useTimeMachine");
14
13
  var _timeMachineStore = require("../store/timeMachineStore");
15
- var _routeRestore = require("../store/routeRestore");
16
- var _RestorePreviewScreen = require("./preview/RestorePreviewScreen");
17
- var _ItemDetailScreen = require("./preview/ItemDetailScreen");
14
+ var _primitives = require("../ui/primitives");
15
+ var _tmTheme = require("../ui/tmTheme");
16
+ var _sources = require("./sources");
17
+ var _confirm = require("./confirm");
18
+ var _CaptureBar = require("./list/CaptureBar");
19
+ var _RestoreOutcomeCard = require("./list/RestoreOutcomeCard");
20
+ var _SnapshotRow = require("./list/SnapshotRow");
21
+ var _UndoDeleteBar = require("./list/UndoDeleteBar");
22
+ var _SourcesStrip = require("./list/SourcesStrip");
23
+ var _WipeAllRow = require("./list/WipeAllRow");
24
+ var _PreviewFlow = require("./preview/PreviewFlow");
18
25
  var _jsxRuntime = require("react/jsx-runtime");
19
26
  /**
20
- * Time Machine body — snapshot list, capture bar, provider status strip and
21
- * the Restore Preview flow (tap a snapshot row → item-level diff of what a
22
- * restore would change; tap an item → tree/split detail).
27
+ * Time Machine body — the screen router plus the restore-point list.
23
28
  *
24
- * Shared by the RN modal and the inline (desktop) tool view. The host must
25
- * NOT wrap this in a scroll view — each screen owns its scrolling (the
26
- * preview is a virtualized FlatList; wrapping it would defeat that).
27
- */
28
-
29
- const FREE_SNAPSHOT_LIMIT = 2;
30
- const SOURCE_ICONS = {
31
- storage: _floatingToolsCore.StorageIcon,
32
- redux: _floatingToolsCore.ReduxIcon,
33
- zustand: _floatingToolsCore.ZustandIcon,
34
- jotai: _floatingToolsCore.JotaiIcon,
35
- query: _floatingToolsCore.QueryIcon,
36
- route: _floatingToolsCore.RoutesIcon
37
- };
38
-
39
- /** Id of the route tile — a device capability, not a snapshot provider. */
40
- const ROUTE_SOURCE_ID = "route";
41
- function timeAgo(ts) {
42
- const s = Math.max(0, Math.round((Date.now() - ts) / 1000));
43
- if (s < 60) return `${s}s ago`;
44
- const m = Math.round(s / 60);
45
- if (m < 60) return `${m}m ago`;
46
- const h = Math.round(m / 60);
47
- if (h < 24) return `${h}h ago`;
48
- return `${Math.round(h / 24)}d ago`;
49
- }
50
- function formatBytes(bytes) {
51
- if (bytes < 1024) return `${bytes} B`;
52
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
53
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
54
- }
55
- function warningCount(meta) {
56
- return Object.values(meta.sources).reduce((sum, s) => sum + s.warnings.length, 0);
57
- }
58
-
59
- /** RN-web's Alert renders no buttons — fall back to the browser dialog there. */
60
- function confirmDestructive(title, message, confirmLabel, onConfirm) {
61
- if (_reactNative.Platform.OS === "web") {
62
- const confirmFn = globalThis.confirm;
63
- if (!confirmFn || confirmFn(`${title}\n\n${message}`)) onConfirm();
64
- return;
65
- }
66
- _reactNative.Alert.alert(title, message, [{
67
- text: "Cancel",
68
- style: "cancel"
69
- }, {
70
- text: confirmLabel,
71
- style: "destructive",
72
- onPress: onConfirm
73
- }]);
74
- }
75
-
76
- /**
77
- * "Also go back to the screen this was captured on?"
29
+ * Screens: list → preview. Each is its own component that mounts and
30
+ * unmounts whole (no branching inside a single tree), and each owns its own
31
+ * scrolling — the host must NOT wrap this in a scroll view, or the preview's
32
+ * virtualized FlatList is defeated. Item diffs expand inline in that list
33
+ * rather than being a third screen.
78
34
  *
79
- * Asked BEFORE the restore runs, because a reload-mode restore has to park the
80
- * route in storage before the JS realm dies — there is no "after" to ask in.
81
- * `onChoose(withRoute)` runs the restore; dismissing cancels it entirely.
82
- *
83
- * RN-web's Alert renders no buttons, so the web (Buoy Desktop) path uses the
84
- * browser dialog: OK = state + route, Cancel = state only.
35
+ * The list follows the grouped-inset surface in ../ui: capture bar, the
36
+ * Sources strip, one card of restore points with swipe-to-delete, and the
37
+ * app-wide wipe kept last and understated.
85
38
  */
86
- function confirmRestoreRoute(snapshotName, href, onChoose) {
87
- const message = `“${snapshotName}” was captured on ${href}. Go back to that screen too, or restore state only?`;
88
- if (_reactNative.Platform.OS === "web") {
89
- const confirmFn = globalThis.confirm;
90
- onChoose(confirmFn ? confirmFn(`Also return to ${href}?\n\n${message}`) : false);
91
- return;
92
- }
93
- _reactNative.Alert.alert("Restore route too?", message, [{
94
- text: "Cancel",
95
- style: "cancel"
96
- }, {
97
- text: "State only",
98
- onPress: () => onChoose(false)
99
- }, {
100
- text: `Go to ${href}`,
101
- onPress: () => onChoose(true)
102
- }]);
103
- }
104
39
 
105
- /**
106
- * Route leg of a restore: prompt when the snapshot has a captured route we
107
- * aren't already sitting on, otherwise restore straight away. On Buoy Desktop
108
- * the device's live route is unknown (no local router), so we always ask.
109
- */
110
- function restoreWithRoutePrompt(meta, run) {
111
- const route = meta.route;
112
- if (!route) {
113
- run(false);
114
- return;
115
- }
116
- if ((0, _routeRestore.currentRoute)()?.href === route.href) {
117
- run(false); // already on that screen — nothing to ask
118
- return;
119
- }
120
- confirmRestoreRoute(meta.name, route.href, run);
121
- }
122
- function OutcomePanel({
123
- outcome
124
- }) {
125
- const entries = Object.entries(outcome.results);
126
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
127
- style: styles.outcomePanel,
128
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
129
- style: styles.outcomeHeaderRow,
130
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
131
- style: styles.outcomeTitle,
132
- children: ["Restored \u201C", outcome.snapshotName, "\u201D", outcome.mode === "reload" || outcome.willReload ? " · reloading" : ""]
133
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
134
- onPress: () => _timeMachineStore.timeMachineStore.clearLastOutcome(),
135
- hitSlop: {
136
- top: 8,
137
- bottom: 8,
138
- left: 8,
139
- right: 8
140
- },
141
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
142
- style: styles.outcomeDismiss,
143
- children: "\u2715"
144
- })
145
- })]
146
- }), entries.length === 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
147
- style: styles.outcomeLine,
148
- children: "no sources restored"
149
- }), outcome.route && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
150
- style: [styles.outcomeLine, (outcome.route.status === "failed" || outcome.route.status === "unavailable") && styles.outcomeLineBad],
151
- children: outcome.route.status === "navigated" ? `✓ route — ${outcome.route.href}` : outcome.route.status === "deferred" ? `↻ route — ${outcome.route.href} after reload` : `✕ route — ${outcome.route.error ?? outcome.route.status}`
152
- }), entries.map(([sourceId, r]) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
153
- style: styles.outcomeSource,
154
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
155
- style: [styles.outcomeLine, !r.ok && styles.outcomeLineBad],
156
- children: [r.ok ? "✓" : "✕", " ", sourceId, " \u2014 applied ", r.applied, r.skipped.length > 0 ? `, skipped ${r.skipped.length}` : ""]
157
- }), r.skipped.slice(0, 3).map(skip => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
158
- style: styles.outcomeDetail,
159
- children: ["\xB7 ", skip.id, ": ", skip.reason]
160
- }, skip.id)), r.warnings.slice(0, 3).map(warning => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
161
- style: styles.outcomeDetail,
162
- children: ["\u26A0 ", warning]
163
- }, warning))]
164
- }, sourceId))]
40
+ function TimeMachineBody() {
41
+ const [screen, setScreen] = (0, _react.useState)({
42
+ kind: "list"
43
+ });
44
+ const {
45
+ snapshots,
46
+ busy,
47
+ preview
48
+ } = (0, _useTimeMachine.useTimeMachineState)();
49
+ const sources = (0, _sources.useSourceStatuses)();
50
+ const backToList = () => {
51
+ _timeMachineStore.timeMachineStore.clearPreview();
52
+ setScreen({
53
+ kind: "list"
54
+ });
55
+ };
56
+
57
+ // The preview can't render without a built diff (clearPreview races a
58
+ // back-navigation) — fall through to the list rather than an empty shell.
59
+ if (screen.kind === "preview" && preview) return /*#__PURE__*/(0, _jsxRuntime.jsx)(_PreviewFlow.PreviewScreen, {
60
+ preview: preview,
61
+ snapshots: snapshots,
62
+ busy: busy !== null,
63
+ onClose: backToList
64
+ });
65
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(RestorePointList, {
66
+ sources: sources,
67
+ onOpenPreview: meta => {
68
+ void _timeMachineStore.timeMachineStore.buildPreview({
69
+ snapshotId: meta.id
70
+ });
71
+ setScreen({
72
+ kind: "preview"
73
+ });
74
+ }
165
75
  });
166
76
  }
167
- function TimeMachineBody() {
77
+ function RestorePointList({
78
+ sources,
79
+ onOpenPreview
80
+ }) {
168
81
  const {
169
82
  snapshots,
170
83
  hasLoaded,
171
84
  busy,
172
85
  lastOutcome,
173
- preview,
174
- remoteProviders,
175
- remoteRoute
86
+ recentlyDeleted
176
87
  } = (0, _useTimeMachine.useTimeMachineState)();
177
- const localProviders = (0, _useTimeMachine.useSnapshotProviders)();
178
88
  const isPro = (0, _license.useIsPro)();
89
+ const snapshotLimit = (0, _sharedUi.useLimit)("timeMachine.snapshots");
179
90
  const host = (0, _core.useToolHost)();
180
- const [name, setName] = (0, _react.useState)("");
181
- const [screen, setScreen] = (0, _react.useState)({
182
- kind: "list"
91
+ const insets = (0, _sharedUi.useSafeAreaInsets)({
92
+ minBottom: 16
183
93
  });
184
- const [picker, setPicker] = (0, _react.useState)(null);
185
94
 
186
- // Header search (when hosted by the core shell) filters the snapshot list.
187
- const listQuery = host.search.trim().toLowerCase();
188
- const visibleSnapshots = listQuery ? snapshots.filter(s => s.name.toLowerCase().includes(listQuery)) : snapshots;
95
+ // Header search (when hosted by the core shell) filters the list.
96
+ const query = host.search.trim().toLowerCase();
97
+ const visible = query ? snapshots.filter(s => s.name.toLowerCase().includes(query)) : snapshots;
189
98
 
190
- // On-device: live registry probes. Buoy Desktop: statuses mirrored from
191
- // the device's sync payload.
192
- const providers = remoteProviders ?? localProviders.map(p => ({
193
- id: p.id,
194
- label: p.label,
195
- ...p.status()
196
- }));
99
+ // Infinity for Pro, so this is simply false for them.
100
+ const atCaptureLimit = snapshots.length >= snapshotLimit;
101
+ const captureDisabled = busy !== null || atCaptureLimit;
197
102
 
198
- // Route sits in the same strip as the state sources so its availability is
199
- // visible before you ever open a restore point — but it's a device
200
- // capability, not a registered provider, so it's derived separately (from
201
- // the live router here, from the device's payload on Buoy Desktop).
202
- const routeAvailable = remoteProviders ? remoteRoute?.available === true : (0, _routeRestore.canNavigate)();
203
- const routeSource = {
204
- id: ROUTE_SOURCE_ID,
205
- label: "Route",
206
- canCapture: routeAvailable,
207
- canRestore: routeAvailable,
208
- // No live route in the caption: this screen only re-renders on store
209
- // changes, so a pathname printed here goes stale the moment you navigate
210
- // with the tool still open. Each restore point shows the route it holds.
211
- detail: routeAvailable ? "recorded with every snapshot — restore can take you back" : "no Expo Router detected — snapshots record no route"
212
- };
213
- const sourceTiles = [...providers, routeSource];
214
- const atFreeLimit = !isPro && snapshots.length >= FREE_SNAPSHOT_LIMIT;
215
- const captureDisabled = busy !== null || atFreeLimit;
216
- const capture = () => {
217
- if (captureDisabled) return;
218
- void _timeMachineStore.timeMachineStore.capture(name);
219
- setName("");
220
- };
221
- const restore = (meta, mode, excludeKeys) => {
103
+ /**
104
+ * Restoring is the last thing anyone wants from this screen, so the tool
105
+ * gets out of the way the moment it worked — with no toast and no banner.
106
+ * The restored app IS the confirmation, and anything announcing it is one
107
+ * more thing to dismiss on a flow people run dozens of times an hour.
108
+ *
109
+ * It MINIMIZES rather than closes: the list, the search and the screen you
110
+ * were on all survive, and coming back is one tap on the dock. A partial
111
+ * restore stays open instead, because the outcome card is the only place
112
+ * the per-source failures are reported.
113
+ */
114
+ const restore = meta => {
222
115
  if (busy) return;
223
116
  if (meta.baseline) {
224
- confirmDestructive("Restore fresh install?", "This wipes all app storage and reloads the app.", "Wipe & reload", () => void _timeMachineStore.timeMachineStore.restore(meta.id, "reload"));
117
+ (0, _confirm.confirmDestructive)("Restore fresh install?", "This wipes all app storage and reloads the app.", "Wipe & reload", () => void _timeMachineStore.timeMachineStore.restore(meta.id, "reload"));
225
118
  return;
226
119
  }
227
- restoreWithRoutePrompt(meta, restoreRoute => {
228
- void _timeMachineStore.timeMachineStore.restore(meta.id, mode, excludeKeys, {
229
- restoreRoute
230
- });
120
+ void _timeMachineStore.timeMachineStore.restore(meta.id, "live").then(outcome => {
121
+ const clean = Object.values(outcome.results).every(r => r.ok);
122
+ if (!clean || outcome.willReload) return;
123
+ host.minimize();
231
124
  });
232
125
  };
233
- const remove = meta => {
234
- confirmDestructive("Delete snapshot?", `“${meta.name}” cannot be recovered.`, "Delete", () => void _timeMachineStore.timeMachineStore.delete(meta.id));
235
- };
236
- const wipeAll = () => {
237
- if (busy) return;
238
- confirmDestructive("Wipe all app state?", "This deletes all app storage and reloads the app — like a fresh install.", "Wipe & reload", () => void _timeMachineStore.timeMachineStore.wipeAll());
239
- };
240
- const openPreview = meta => {
241
- void _timeMachineStore.timeMachineStore.buildPreview({
242
- snapshotId: meta.id
243
- });
244
- setScreen({
245
- kind: "preview"
246
- });
247
- };
248
- const closePreview = () => {
249
- _timeMachineStore.timeMachineStore.clearPreview();
250
- setScreen({
251
- kind: "list"
252
- });
253
- };
254
-
255
- // ── Preview / item screens ──
256
- if (screen.kind === "item" && preview) {
257
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ItemDetailScreen.ItemDetailScreen, {
258
- sourceLabel: screen.sourceLabel,
259
- item: screen.item,
260
- leftLabel: preview.left === "current" ? "CURRENT" : snapshots.find(s => s.id === preview.left.snapshotId)?.name ?? "snapshot",
261
- rightLabel: preview.right === "current" ? "CURRENT" : snapshots.find(s => s.id === preview.right.snapshotId)?.name ?? "snapshot",
262
- onBack: () => setScreen({
263
- kind: "preview"
264
- })
265
- });
266
- }
267
- if (screen.kind === "preview" && preview) {
268
- const rightMeta = preview.right === "current" ? undefined : snapshots.find(s => s.id === preview.right.snapshotId);
269
- const pickerItems = [];
270
- if (picker) {
271
- const otherRef = picker === "left" ? preview.right : preview.left;
272
- const otherId = otherRef === "current" ? null : otherRef.snapshotId;
273
- if (picker === "left") {
274
- pickerItems.push({
275
- index: 0,
276
- label: "Current state",
277
- timestamp: "live",
278
- relativeTime: "now",
279
- selected: preview.left === "current"
280
- });
281
- }
282
- snapshots.forEach((s, i) => {
283
- const ref = {
284
- snapshotId: s.id
285
- };
286
- const current = picker === "left" ? preview.left : preview.right;
287
- pickerItems.push({
288
- index: picker === "left" ? i + 1 : i,
289
- label: s.baseline ? `⌂ ${s.name}` : s.name,
290
- timestamp: new Date(s.createdAt).toLocaleTimeString(),
291
- relativeTime: timeAgo(s.createdAt),
292
- disabled: s.id === otherId || picker === "right" && s.baseline,
293
- selected: current !== "current" && current.snapshotId === s.id
294
- });
295
- });
296
- }
297
- const onPickerSelect = index => {
298
- const side = picker;
299
- setPicker(null);
300
- if (!side) return;
301
- let ref;
302
- if (side === "left") {
303
- ref = index === 0 ? "current" : {
304
- snapshotId: snapshots[index - 1].id
305
- };
306
- void _timeMachineStore.timeMachineStore.buildPreview(preview.right, ref);
307
- } else {
308
- ref = {
309
- snapshotId: snapshots[index].id
310
- };
311
- void _timeMachineStore.timeMachineStore.buildPreview(ref, preview.left);
312
- }
313
- };
314
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
315
- style: styles.screenFill,
316
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_RestorePreviewScreen.RestorePreviewScreen, {
317
- preview: preview,
318
- snapshots: snapshots,
319
- busy: busy !== null,
320
- onBack: closePreview,
321
- onOpenItem: (sourceId, item) => {
322
- const source = preview.sources.find(s => s.id === sourceId);
323
- setScreen({
324
- kind: "item",
325
- sourceId,
326
- sourceLabel: source?.label ?? sourceId,
327
- item
328
- });
329
- },
330
- onRestore: (mode, excludeKeys) => {
331
- if (!rightMeta || busy) return;
332
- if (rightMeta.baseline) {
333
- confirmDestructive("Restore fresh install?", "This wipes all app storage and reloads the app.", "Wipe & reload", () => void _timeMachineStore.timeMachineStore.restore(rightMeta.id, "reload"));
334
- return;
335
- }
336
- // Land back on the list, where the outcome panel reports the
337
- // results — the preview's diff is stale the moment restore runs.
338
- restoreWithRoutePrompt(rightMeta, restoreRoute => {
339
- void _timeMachineStore.timeMachineStore.restore(rightMeta.id, mode, excludeKeys, {
340
- restoreRoute
341
- }).then(() => closePreview());
342
- });
343
- },
344
- onPickSide: setPicker,
345
- onRefresh: () => void _timeMachineStore.timeMachineStore.buildPreview(preview.right, preview.left)
346
- }), picker && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventPickerModal, {
347
- isOpen: true,
348
- onClose: () => setPicker(null),
349
- title: picker === "left" ? "Compare from" : "Compare to",
350
- position: picker,
351
- items: pickerItems,
352
- onSelect: onPickerSelect
353
- })]
354
- });
355
- }
356
-
357
- // ── List screen ──
358
- const unavailable = sourceTiles.filter(p => p.detail && (!p.canCapture || !p.canRestore));
359
126
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
360
- style: styles.screenFill,
361
- contentContainerStyle: styles.container,
362
- children: [lastOutcome && /*#__PURE__*/(0, _jsxRuntime.jsx)(OutcomePanel, {
127
+ style: styles.fill,
128
+ contentContainerStyle: [styles.content, {
129
+ paddingBottom: insets.bottom
130
+ }],
131
+ children: [lastOutcome && (0, _RestoreOutcomeCard.restoreNeedsAttention)(lastOutcome) ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_RestoreOutcomeCard.RestoreOutcomeCard, {
363
132
  outcome: lastOutcome
364
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
365
- style: styles.captureCard,
366
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
367
- style: styles.captureField,
368
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Plus, {
369
- size: 14,
370
- color: _sharedUi.buoyColors.textMuted
371
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
372
- style: styles.captureInput,
373
- value: name,
374
- onChangeText: setName,
375
- placeholder: "Name this restore point\u2026",
376
- placeholderTextColor: _sharedUi.buoyColors.textMuted,
377
- editable: !captureDisabled,
378
- onSubmitEditing: capture,
379
- returnKeyType: "done",
380
- testID: "time-machine-name-input"
381
- })]
382
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
383
- style: [styles.captureButton, captureDisabled && styles.buttonDisabled],
384
- onPress: capture,
133
+ }) : null, recentlyDeleted ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_UndoDeleteBar.UndoDeleteBar, {
134
+ name: recentlyDeleted.stored.meta.name,
135
+ at: recentlyDeleted.at,
136
+ onUndo: () => void _timeMachineStore.timeMachineStore.undoDelete(),
137
+ onExpire: () => _timeMachineStore.timeMachineStore.clearRecentlyDeleted()
138
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
139
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CaptureBar.CaptureBar, {
385
140
  disabled: captureDisabled,
386
- testID: "time-machine-capture",
387
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
388
- style: styles.captureButtonText,
389
- children: busy === "capture" ? "…" : "CAPTURE"
390
- })
391
- })]
392
- }), atFreeLimit && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
393
- style: styles.freeLimitNote,
394
- children: ["Free plan: ", FREE_SNAPSHOT_LIMIT, " restore points. Upgrade to Pro for unlimited snapshots."]
395
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
396
- style: styles.sectionRow,
397
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
398
- style: styles.sectionTitle,
399
- children: "Sources"
400
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
401
- style: styles.sourceTiles,
402
- children: [sourceTiles.map(p => {
403
- const IconComp = SOURCE_ICONS[p.id] ?? _floatingToolsCore.TimeMachineIcon;
404
- const dotColor = !p.canCapture ? _sharedUi.buoyColors.textMuted : p.canRestore ? _sharedUi.buoyColors.success : _sharedUi.buoyColors.warning;
405
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
406
- style: styles.sourceTile,
407
- testID: `time-machine-source-${p.id}`,
408
- accessibilityLabel: `${p.label}: ${p.canCapture ? p.canRestore ? "capture and restore" : "capture only" : "unavailable"}`,
409
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(IconComp, {
410
- size: 16
411
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
412
- style: [styles.sourceTileDot, {
413
- backgroundColor: dotColor
414
- }]
415
- })]
416
- }, p.id);
417
- }), providers.length === 0 && !routeAvailable && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
418
- style: styles.emptyText,
419
- children: "none registered"
420
- })]
421
- })]
422
- }), unavailable.map(p => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
423
- style: styles.providerDetail,
424
- children: [p.label, ": ", p.detail]
425
- }, p.id)), routeAvailable && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
426
- style: styles.providerDetail,
427
- numberOfLines: 1,
428
- children: [routeSource.label, ": ", routeSource.detail]
429
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
430
- style: [styles.sectionTitle, styles.sectionSpacing],
431
- children: "Restore points"
432
- }), hasLoaded && snapshots.length === 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
433
- style: styles.emptyText,
434
- children: "No restore points yet. Set up the state you want to return to, then capture it."
435
- }), visibleSnapshots.map(meta => {
436
- const warnings = warningCount(meta);
437
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
438
- style: styles.snapshotCard,
439
- onPress: () => openPreview(meta),
440
- testID: `time-machine-snap-${meta.id}`,
441
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
442
- style: styles.snapshotIconTile,
443
- children: meta.baseline ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Home, {
444
- size: 17,
445
- color: _sharedUi.buoyColors.textSecondary
446
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.TimeMachineIcon, {
447
- size: 18
448
- })
449
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
450
- style: styles.snapshotInfo,
451
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
452
- style: styles.snapshotName,
453
- numberOfLines: 1,
454
- children: meta.name
455
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
456
- style: styles.snapshotMeta,
457
- numberOfLines: 1,
458
- children: [meta.baseline ? "wipes to fresh install" : `${timeAgo(meta.createdAt)} · ${formatBytes(meta.sizeBytes)} · ${Object.keys(meta.sources).length} sources`, meta.scope?.length ? ` · scoped (${meta.scope.length})` : "", warnings > 0 ? ` · ⚠ ${warnings}` : ""]
459
- }), !meta.baseline && meta.route && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
460
- style: styles.snapshotRoute,
461
- numberOfLines: 1,
462
- children: ["\u2316 ", meta.route.href]
463
- })]
464
- }), !meta.baseline ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
465
- style: [styles.rowAction, busy && styles.buttonDisabled],
466
- onPress: () => restore(meta, "live"),
467
- disabled: busy !== null,
468
- accessibilityLabel: "Restore",
469
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
470
- style: styles.rowActionLabel,
471
- children: "RESTORE"
472
- })
473
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
474
- style: [styles.rowAction, busy && styles.buttonDisabled],
475
- onPress: () => restore(meta, "reload"),
476
- disabled: busy !== null,
477
- accessibilityLabel: "Wipe and reload",
478
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
479
- style: styles.rowActionLabelDanger,
480
- children: "WIPE"
481
- })
482
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
483
- style: styles.rowAction,
484
- onPress: () => remove(meta),
485
- hitSlop: {
486
- top: 8,
487
- bottom: 8,
488
- left: 4,
489
- right: 8
490
- },
491
- accessibilityLabel: "Delete",
492
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
493
- size: 14,
494
- color: _sharedUi.buoyColors.error
495
- })
496
- })]
497
- }, meta.id);
498
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
499
- style: [styles.wipeAllButton, busy && styles.buttonDisabled],
500
- onPress: wipeAll,
501
- disabled: busy !== null,
502
- testID: "time-machine-wipe-all",
503
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
504
- size: 13,
505
- color: _sharedUi.buoyColors.error
506
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
507
- style: styles.wipeAllText,
508
- children: "Wipe all app state\u2026"
509
- })]
510
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
511
- style: styles.wipeAllCaption,
141
+ busy: busy === "capture",
142
+ onCapture: name => void _timeMachineStore.timeMachineStore.capture(name)
143
+ })
144
+ }), atCaptureLimit ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_primitives.Footnote, {
145
+ tone: "warning",
146
+ children: ["Free plan keeps ", snapshotLimit, " restore points. Upgrade to Pro for unlimited snapshots."]
147
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.SectionLabel, {
148
+ children: "Sources"
149
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_SourcesStrip.SourcesStrip, {
150
+ sources: sources
151
+ }), sources.filter(s => s.detail && !(s.canCapture && s.canRestore)).map(s => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_primitives.Footnote, {
152
+ children: [s.label, ": ", s.detail]
153
+ }, s.id)), /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.SectionLabel, {
154
+ children: "Restore Points"
155
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_primitives.Group, {
156
+ children: [visible.map(meta => /*#__PURE__*/(0, _jsxRuntime.jsx)(_SnapshotRow.SnapshotRow, {
157
+ meta: meta,
158
+ busy: busy !== null,
159
+ onOpen: () => onOpenPreview(meta),
160
+ onRestore: () => restore(meta),
161
+ onDelete: () => void _timeMachineStore.timeMachineStore.delete(meta.id),
162
+ onDuplicate: () => void _timeMachineStore.timeMachineStore.duplicate(meta.id)
163
+ }, meta.id)), visible.length === 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
164
+ style: styles.empty,
165
+ children: !hasLoaded ? "Loading restore points…" : snapshots.length > 0 ? "No restore point matches that name." : "Set up the state you want to come back to, then capture it."
166
+ }) : null]
167
+ }), visible.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.Footnote, {
168
+ children: "Swipe a restore point to rename, copy or delete it."
169
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
170
+ style: styles.spacer
171
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.Group, {
172
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_WipeAllRow.WipeAllRow, {
173
+ disabled: busy !== null,
174
+ onWipe: () => (0, _confirm.confirmDestructive)("Wipe all app state?", "This deletes all app storage and reloads the app — like a fresh install.", "Wipe & reload", () => void _timeMachineStore.timeMachineStore.wipeAll())
175
+ })
176
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_primitives.Footnote, {
177
+ centered: true,
512
178
  children: "Deletes all app storage and reloads \u2014 like a fresh install."
513
179
  })]
514
180
  });
515
181
  }
516
182
  const styles = _reactNative.StyleSheet.create({
517
- screenFill: {
518
- flex: 1
519
- },
520
- container: {
521
- padding: 12,
522
- gap: 8
523
- },
524
- captureCard: {
525
- flexDirection: "row",
526
- alignItems: "center",
527
- gap: 8
528
- },
529
- captureField: {
183
+ fill: {
530
184
  flex: 1,
531
- flexDirection: "row",
532
- alignItems: "center",
533
- gap: 8,
534
- backgroundColor: _sharedUi.buoyColors.card,
535
- borderColor: _sharedUi.buoyColors.border,
536
- borderWidth: 1,
537
- borderRadius: 10,
538
- paddingHorizontal: 10
539
- },
540
- captureInput: {
541
- flex: 1,
542
- color: _sharedUi.buoyColors.text,
543
- fontSize: 13,
544
- paddingVertical: 9
545
- },
546
- captureButton: {
547
- backgroundColor: _sharedUi.buoyColors.primary,
548
- borderRadius: 10,
549
- paddingHorizontal: 16,
550
- paddingVertical: 10,
551
- justifyContent: "center"
552
- },
553
- captureButtonText: {
554
- color: "#0A0A0A",
555
- fontSize: 12,
556
- fontWeight: "700",
557
- letterSpacing: 0.5
558
- },
559
- buttonDisabled: {
560
- opacity: 0.4
561
- },
562
- freeLimitNote: {
563
- color: _sharedUi.buoyColors.warning,
564
- fontSize: 11
565
- },
566
- sectionRow: {
567
- flexDirection: "row",
568
- alignItems: "center",
569
- justifyContent: "space-between",
570
- marginTop: 12,
571
- gap: 10
572
- },
573
- sectionTitle: {
574
- color: _sharedUi.buoyColors.text,
575
- fontSize: 14,
576
- fontWeight: "700"
577
- },
578
- sectionSpacing: {
579
- marginTop: 14
580
- },
581
- sourceTiles: {
582
- flexDirection: "row",
583
- gap: 6,
584
- flexWrap: "wrap",
585
- justifyContent: "flex-end",
586
- flex: 1
587
- },
588
- sourceTile: {
589
- width: 32,
590
- height: 32,
591
- borderRadius: 9,
592
- backgroundColor: _sharedUi.buoyColors.card,
593
- borderColor: _sharedUi.buoyColors.border,
594
- borderWidth: 1,
595
- alignItems: "center",
596
- justifyContent: "center"
597
- },
598
- sourceTileDot: {
599
- position: "absolute",
600
- top: 3,
601
- right: 3,
602
- width: 6,
603
- height: 6,
604
- borderRadius: 3
605
- },
606
- providerDetail: {
607
- color: _sharedUi.buoyColors.textMuted,
608
- fontSize: 10,
609
- marginTop: 4
610
- },
611
- emptyText: {
612
- color: _sharedUi.buoyColors.textMuted,
613
- fontSize: 12,
614
- marginTop: 8
615
- },
616
- snapshotCard: {
617
- flexDirection: "row",
618
- alignItems: "center",
619
- backgroundColor: _sharedUi.buoyColors.card,
620
- borderColor: _sharedUi.buoyColors.border,
621
- borderWidth: 1,
622
- borderRadius: 12,
623
- paddingHorizontal: 12,
624
- paddingVertical: 10,
625
- marginTop: 8,
626
- gap: 10
627
- },
628
- snapshotIconTile: {
629
- width: 36,
630
- height: 36,
631
- borderRadius: 10,
632
- backgroundColor: _sharedUi.buoyColors.hover,
633
- alignItems: "center",
634
- justifyContent: "center"
635
- },
636
- snapshotInfo: {
637
- flex: 1,
638
- minWidth: 0,
639
- gap: 2
640
- },
641
- snapshotName: {
642
- color: _sharedUi.buoyColors.text,
643
- fontSize: 14,
644
- fontWeight: "700"
645
- },
646
- snapshotMeta: {
647
- color: _sharedUi.buoyColors.textMuted,
648
- fontSize: 10,
649
- fontVariant: ["tabular-nums"]
650
- },
651
- snapshotRoute: {
652
- color: _sharedUi.buoyColors.textSecondary,
653
- fontSize: 10
654
- },
655
- rowAction: {
656
- padding: 4,
657
- justifyContent: "center",
658
- alignItems: "center"
659
- },
660
- rowActionLabel: {
661
- color: _sharedUi.buoyColors.primary,
662
- fontSize: 12,
663
- fontWeight: "600"
664
- },
665
- rowActionLabelDanger: {
666
- color: _sharedUi.buoyColors.error,
667
- fontSize: 12,
668
- fontWeight: "600"
669
- },
670
- wipeAllButton: {
671
- flexDirection: "row",
672
- alignItems: "center",
673
- justifyContent: "center",
674
- gap: 7,
675
- borderColor: `${_sharedUi.buoyColors.error}55`,
676
- borderWidth: 1,
677
- borderRadius: 10,
678
- paddingVertical: 10,
679
- marginTop: 18
680
- },
681
- wipeAllText: {
682
- color: _sharedUi.buoyColors.error,
683
- fontSize: 12.5,
684
- fontWeight: "600"
685
- },
686
- wipeAllCaption: {
687
- color: _sharedUi.buoyColors.textMuted,
688
- fontSize: 10,
689
- textAlign: "center",
690
- marginTop: 6
691
- },
692
- outcomePanel: {
693
- backgroundColor: _sharedUi.buoyColors.card,
694
- borderColor: _sharedUi.buoyColors.borderStrong,
695
- borderWidth: 1,
696
- borderRadius: 8,
697
- padding: 10,
698
- gap: 4
699
- },
700
- outcomeHeaderRow: {
701
- flexDirection: "row",
702
- justifyContent: "space-between",
703
- alignItems: "center"
704
- },
705
- outcomeTitle: {
706
- color: _sharedUi.buoyColors.text,
707
- fontSize: 12,
708
- fontWeight: "700",
709
- flex: 1
710
- },
711
- outcomeDismiss: {
712
- color: _sharedUi.buoyColors.textMuted,
713
- fontSize: 13
714
- },
715
- outcomeSource: {
716
- gap: 2
185
+ backgroundColor: _tmTheme.tm.color.sheet
717
186
  },
718
- outcomeLine: {
719
- color: _sharedUi.buoyColors.success,
720
- fontSize: 11
187
+ content: {
188
+ paddingTop: 14
721
189
  },
722
- outcomeLineBad: {
723
- color: _sharedUi.buoyColors.warning
190
+ empty: {
191
+ color: _tmTheme.tm.color.labelSecondary,
192
+ fontSize: _tmTheme.tm.font.footnote,
193
+ lineHeight: _tmTheme.tm.font.footnote * 1.4,
194
+ paddingHorizontal: _tmTheme.tm.textInset,
195
+ paddingVertical: 16
724
196
  },
725
- outcomeDetail: {
726
- color: _sharedUi.buoyColors.textMuted,
727
- fontSize: 10,
728
- paddingLeft: 12
197
+ spacer: {
198
+ height: 24
729
199
  }
730
200
  });
731
201
  //# sourceMappingURL=TimeMachineBody.js.map