@buoy-gg/assets 7.0.41 → 7.0.42
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.
- package/README.md +12 -73
- package/bundlers/vite.mjs +1 -53
- package/lib/commonjs/autoCapture.js +1 -5
- package/lib/commonjs/autoCapture.web.js +1 -6
- package/lib/commonjs/capture/assetLifecycle.js +1 -11
- package/lib/commonjs/capture/assetLifecycle.web.js +1 -20
- package/lib/commonjs/capture/browserAssets.js +1 -83
- package/lib/commonjs/capture/expo.js +1 -46
- package/lib/commonjs/capture/expo.web.js +1 -19
- package/lib/commonjs/capture/install.js +1 -91
- package/lib/commonjs/capture/install.web.js +1 -75
- package/lib/commonjs/capture/isBuoyAsset.js +1 -23
- package/lib/commonjs/capture/measure.js +1 -187
- package/lib/commonjs/capture/metroGraph.js +1 -175
- package/lib/commonjs/capture/metroGraph.web.js +1 -27
- package/lib/commonjs/capture/registry.js +1 -127
- package/lib/commonjs/components/AssetDetail.js +1 -211
- package/lib/commonjs/components/AssetImage.js +1 -66
- package/lib/commonjs/components/AssetRow.js +1 -232
- package/lib/commonjs/components/AssetsFilterBar.js +1 -105
- package/lib/commonjs/components/AssetsHeader.js +1 -73
- package/lib/commonjs/components/AssetsIcon.js +1 -19
- package/lib/commonjs/components/AssetsListControls.js +1 -81
- package/lib/commonjs/components/AssetsModal.js +1 -378
- package/lib/commonjs/components/ScanNotice.js +1 -86
- package/lib/commonjs/components/optionalExpoImage.js +1 -16
- package/lib/commonjs/components/optionalExpoImage.web.js +1 -10
- package/lib/commonjs/export.js +1 -62
- package/lib/commonjs/format.js +1 -59
- package/lib/commonjs/hooks/useAssetRecords.js +1 -22
- package/lib/commonjs/hooks/useAssetScanStatus.js +1 -28
- package/lib/commonjs/index.js +1 -294
- package/lib/commonjs/preset.js +1 -39
- package/lib/commonjs/remote.js +1 -68
- package/lib/commonjs/state.js +1 -51
- package/lib/commonjs/store/assetStore.js +1 -256
- package/lib/commonjs/store/baseline.js +1 -175
- package/lib/commonjs/store/insights.js +1 -120
- package/lib/commonjs/sync/assetsSyncAdapter.js +1 -157
- package/lib/commonjs/types.js +0 -1
- package/lib/commonjs/utils/deviceScale.js +1 -50
- package/lib/commonjs/utils/testIDs.js +1 -110
- package/lib/module/autoCapture.js +1 -5
- package/lib/module/autoCapture.web.js +1 -5
- package/lib/module/capture/assetLifecycle.js +1 -7
- package/lib/module/capture/assetLifecycle.web.js +1 -16
- package/lib/module/capture/browserAssets.js +1 -75
- package/lib/module/capture/expo.js +1 -41
- package/lib/module/capture/expo.web.js +1 -14
- package/lib/module/capture/install.js +1 -85
- package/lib/module/capture/install.web.js +1 -68
- package/lib/module/capture/isBuoyAsset.js +1 -18
- package/lib/module/capture/measure.js +1 -180
- package/lib/module/capture/metroGraph.js +1 -168
- package/lib/module/capture/metroGraph.web.js +1 -21
- package/lib/module/capture/registry.js +1 -120
- package/lib/module/components/AssetDetail.js +1 -207
- package/lib/module/components/AssetImage.js +1 -62
- package/lib/module/components/AssetRow.js +1 -228
- package/lib/module/components/AssetsFilterBar.js +1 -101
- package/lib/module/components/AssetsHeader.js +1 -69
- package/lib/module/components/AssetsIcon.js +1 -12
- package/lib/module/components/AssetsListControls.js +1 -77
- package/lib/module/components/AssetsModal.js +1 -373
- package/lib/module/components/ScanNotice.js +1 -82
- package/lib/module/components/optionalExpoImage.js +1 -12
- package/lib/module/components/optionalExpoImage.web.js +1 -6
- package/lib/module/export.js +1 -57
- package/lib/module/format.js +1 -51
- package/lib/module/hooks/useAssetRecords.js +1 -18
- package/lib/module/hooks/useAssetScanStatus.js +1 -23
- package/lib/module/index.js +1 -64
- package/lib/module/preset.js +1 -35
- package/lib/module/remote.js +1 -61
- package/lib/module/state.js +1 -47
- package/lib/module/store/assetStore.js +1 -240
- package/lib/module/store/baseline.js +1 -167
- package/lib/module/store/insights.js +1 -116
- package/lib/module/sync/assetsSyncAdapter.js +1 -153
- package/lib/module/types.js +0 -1
- package/lib/module/utils/deviceScale.js +1 -46
- package/lib/module/utils/testIDs.js +1 -99
- package/lib/web/index.mjs +3 -4
- package/package.json +2 -2
- package/lib/commonjs/autoCapture.js.map +0 -1
- package/lib/commonjs/autoCapture.web.js.map +0 -1
- package/lib/commonjs/capture/assetLifecycle.js.map +0 -1
- package/lib/commonjs/capture/assetLifecycle.web.js.map +0 -1
- package/lib/commonjs/capture/browserAssets.js.map +0 -1
- package/lib/commonjs/capture/expo.js.map +0 -1
- package/lib/commonjs/capture/expo.web.js.map +0 -1
- package/lib/commonjs/capture/install.js.map +0 -1
- package/lib/commonjs/capture/install.web.js.map +0 -1
- package/lib/commonjs/capture/isBuoyAsset.js.map +0 -1
- package/lib/commonjs/capture/measure.js.map +0 -1
- package/lib/commonjs/capture/metroGraph.js.map +0 -1
- package/lib/commonjs/capture/metroGraph.web.js.map +0 -1
- package/lib/commonjs/capture/registry.js.map +0 -1
- package/lib/commonjs/components/AssetDetail.js.map +0 -1
- package/lib/commonjs/components/AssetImage.js.map +0 -1
- package/lib/commonjs/components/AssetRow.js.map +0 -1
- package/lib/commonjs/components/AssetsFilterBar.js.map +0 -1
- package/lib/commonjs/components/AssetsHeader.js.map +0 -1
- package/lib/commonjs/components/AssetsIcon.js.map +0 -1
- package/lib/commonjs/components/AssetsListControls.js.map +0 -1
- package/lib/commonjs/components/AssetsModal.js.map +0 -1
- package/lib/commonjs/components/ScanNotice.js.map +0 -1
- package/lib/commonjs/components/optionalExpoImage.js.map +0 -1
- package/lib/commonjs/components/optionalExpoImage.web.js.map +0 -1
- package/lib/commonjs/export.js.map +0 -1
- package/lib/commonjs/format.js.map +0 -1
- package/lib/commonjs/hooks/useAssetRecords.js.map +0 -1
- package/lib/commonjs/hooks/useAssetScanStatus.js.map +0 -1
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/preset.js.map +0 -1
- package/lib/commonjs/remote.js.map +0 -1
- package/lib/commonjs/state.js.map +0 -1
- package/lib/commonjs/store/assetStore.js.map +0 -1
- package/lib/commonjs/store/baseline.js.map +0 -1
- package/lib/commonjs/store/insights.js.map +0 -1
- package/lib/commonjs/sync/assetsSyncAdapter.js.map +0 -1
- package/lib/commonjs/types.js.map +0 -1
- package/lib/commonjs/utils/deviceScale.js.map +0 -1
- package/lib/commonjs/utils/testIDs.js.map +0 -1
- package/lib/module/autoCapture.js.map +0 -1
- package/lib/module/autoCapture.web.js.map +0 -1
- package/lib/module/capture/assetLifecycle.js.map +0 -1
- package/lib/module/capture/assetLifecycle.web.js.map +0 -1
- package/lib/module/capture/browserAssets.js.map +0 -1
- package/lib/module/capture/expo.js.map +0 -1
- package/lib/module/capture/expo.web.js.map +0 -1
- package/lib/module/capture/install.js.map +0 -1
- package/lib/module/capture/install.web.js.map +0 -1
- package/lib/module/capture/isBuoyAsset.js.map +0 -1
- package/lib/module/capture/measure.js.map +0 -1
- package/lib/module/capture/metroGraph.js.map +0 -1
- package/lib/module/capture/metroGraph.web.js.map +0 -1
- package/lib/module/capture/registry.js.map +0 -1
- package/lib/module/components/AssetDetail.js.map +0 -1
- package/lib/module/components/AssetImage.js.map +0 -1
- package/lib/module/components/AssetRow.js.map +0 -1
- package/lib/module/components/AssetsFilterBar.js.map +0 -1
- package/lib/module/components/AssetsHeader.js.map +0 -1
- package/lib/module/components/AssetsIcon.js.map +0 -1
- package/lib/module/components/AssetsListControls.js.map +0 -1
- package/lib/module/components/AssetsModal.js.map +0 -1
- package/lib/module/components/ScanNotice.js.map +0 -1
- package/lib/module/components/optionalExpoImage.js.map +0 -1
- package/lib/module/components/optionalExpoImage.web.js.map +0 -1
- package/lib/module/export.js.map +0 -1
- package/lib/module/format.js.map +0 -1
- package/lib/module/hooks/useAssetRecords.js.map +0 -1
- package/lib/module/hooks/useAssetScanStatus.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/preset.js.map +0 -1
- package/lib/module/remote.js.map +0 -1
- package/lib/module/state.js.map +0 -1
- package/lib/module/store/assetStore.js.map +0 -1
- package/lib/module/store/baseline.js.map +0 -1
- package/lib/module/store/insights.js.map +0 -1
- package/lib/module/sync/assetsSyncAdapter.js.map +0 -1
- package/lib/module/types.js.map +0 -1
- package/lib/module/utils/deviceScale.js.map +0 -1
- package/lib/module/utils/testIDs.js.map +0 -1
- package/lib/typescript/autoCapture.d.ts.map +0 -1
- package/lib/typescript/autoCapture.web.d.ts.map +0 -1
- package/lib/typescript/capture/assetLifecycle.d.ts.map +0 -1
- package/lib/typescript/capture/assetLifecycle.web.d.ts.map +0 -1
- package/lib/typescript/capture/browserAssets.d.ts.map +0 -1
- package/lib/typescript/capture/expo.d.ts.map +0 -1
- package/lib/typescript/capture/expo.web.d.ts.map +0 -1
- package/lib/typescript/capture/install.d.ts.map +0 -1
- package/lib/typescript/capture/install.web.d.ts.map +0 -1
- package/lib/typescript/capture/isBuoyAsset.d.ts.map +0 -1
- package/lib/typescript/capture/measure.d.ts.map +0 -1
- package/lib/typescript/capture/metroGraph.d.ts.map +0 -1
- package/lib/typescript/capture/metroGraph.web.d.ts.map +0 -1
- package/lib/typescript/capture/registry.d.ts.map +0 -1
- package/lib/typescript/components/AssetDetail.d.ts.map +0 -1
- package/lib/typescript/components/AssetImage.d.ts.map +0 -1
- package/lib/typescript/components/AssetRow.d.ts.map +0 -1
- package/lib/typescript/components/AssetsFilterBar.d.ts.map +0 -1
- package/lib/typescript/components/AssetsHeader.d.ts.map +0 -1
- package/lib/typescript/components/AssetsIcon.d.ts.map +0 -1
- package/lib/typescript/components/AssetsListControls.d.ts.map +0 -1
- package/lib/typescript/components/AssetsModal.d.ts.map +0 -1
- package/lib/typescript/components/ScanNotice.d.ts.map +0 -1
- package/lib/typescript/components/optionalExpoImage.d.ts.map +0 -1
- package/lib/typescript/components/optionalExpoImage.web.d.ts.map +0 -1
- package/lib/typescript/export.d.ts.map +0 -1
- package/lib/typescript/format.d.ts.map +0 -1
- package/lib/typescript/hooks/useAssetRecords.d.ts.map +0 -1
- package/lib/typescript/hooks/useAssetScanStatus.d.ts.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/remote.d.ts.map +0 -1
- package/lib/typescript/state.d.ts.map +0 -1
- package/lib/typescript/store/assetStore.d.ts.map +0 -1
- package/lib/typescript/store/baseline.d.ts.map +0 -1
- package/lib/typescript/store/insights.d.ts.map +0 -1
- package/lib/typescript/sync/assetsSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/types.d.ts.map +0 -1
- package/lib/typescript/utils/deviceScale.d.ts.map +0 -1
- package/lib/typescript/utils/testIDs.d.ts.map +0 -1
|
@@ -1,207 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* AssetDetail — full metadata for one asset: preview, identity, dimensions,
|
|
5
|
-
* per-scale sizes, resolution info, and which audit findings apply.
|
|
6
|
-
*
|
|
7
|
-
* Image previews use registry ids or asset URLs, with optional expo-image for
|
|
8
|
-
* native SVGs; fonts render a pangram with fontFamily set to the asset name
|
|
9
|
-
* — a best-effort guess (family ≠ filename for many fonts) that falls back
|
|
10
|
-
* to the system font silently when it misses.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { ScrollView, StyleSheet, Text, View } from "react-native";
|
|
14
|
-
import { night } from "@buoy-gg/shared-ui";
|
|
15
|
-
import { AssetImage } from "./AssetImage";
|
|
16
|
-
import { formatBytes, formatDimensions, formatScales } from "../format";
|
|
17
|
-
import { estDecodedBytes } from "../store/assetStore";
|
|
18
|
-
import { ASSETS_TEST_IDS, assetDetailRowTestID, assetFindingTestID } from "../utils/testIDs";
|
|
19
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
20
|
-
function Row({
|
|
21
|
-
label,
|
|
22
|
-
value
|
|
23
|
-
}) {
|
|
24
|
-
const testID = assetDetailRowTestID(label);
|
|
25
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
26
|
-
style: styles.kvRow,
|
|
27
|
-
testID: testID,
|
|
28
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
29
|
-
style: styles.kvLabel,
|
|
30
|
-
children: label
|
|
31
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
32
|
-
style: styles.kvValue,
|
|
33
|
-
selectable: true,
|
|
34
|
-
testID: `${testID}-value`,
|
|
35
|
-
children: value
|
|
36
|
-
})]
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function Preview({
|
|
40
|
-
record
|
|
41
|
-
}) {
|
|
42
|
-
if (record.kind === "image") {
|
|
43
|
-
return /*#__PURE__*/_jsx(View, {
|
|
44
|
-
style: styles.previewBox,
|
|
45
|
-
testID: ASSETS_TEST_IDS.detailPreview,
|
|
46
|
-
children: /*#__PURE__*/_jsx(AssetImage, {
|
|
47
|
-
testID: "buoy-internal-assets-preview",
|
|
48
|
-
record: record,
|
|
49
|
-
style: styles.previewImage
|
|
50
|
-
})
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
if (record.kind === "font") {
|
|
54
|
-
return /*#__PURE__*/_jsx(View, {
|
|
55
|
-
style: styles.previewBox,
|
|
56
|
-
testID: ASSETS_TEST_IDS.detailFontPreview,
|
|
57
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
58
|
-
style: [styles.fontPreview, {
|
|
59
|
-
fontFamily: record.name
|
|
60
|
-
}],
|
|
61
|
-
children: "The quick brown fox jumps over the lazy dog 0123456789"
|
|
62
|
-
})
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
export function AssetDetail({
|
|
68
|
-
record,
|
|
69
|
-
insights
|
|
70
|
-
}) {
|
|
71
|
-
const findings = [];
|
|
72
|
-
if (insights.neverLoaded.includes(record.id)) {
|
|
73
|
-
findings.push("Not observed in the runtime registry this app run. This does not prove the asset is unused.");
|
|
74
|
-
}
|
|
75
|
-
if (insights.scaleGaps.includes(record.id)) {
|
|
76
|
-
findings.push("Scale gap — no variant covers this device's pixel ratio");
|
|
77
|
-
}
|
|
78
|
-
if (insights.webpCandidates.includes(record.id)) {
|
|
79
|
-
findings.push("WebP candidate — large png/jpeg, converting typically saves 20–40%");
|
|
80
|
-
}
|
|
81
|
-
const duplicate = insights.duplicates.find(d => d.ids.includes(record.id));
|
|
82
|
-
if (duplicate) {
|
|
83
|
-
findings.push(`Duplicate content — identical bytes shipped ${duplicate.ids.length} times`);
|
|
84
|
-
}
|
|
85
|
-
if (insights.overDecode.includes(record.id)) {
|
|
86
|
-
findings.push("Decodes larger than 2× this entire screen — resize the source, no view can need this many pixels");
|
|
87
|
-
}
|
|
88
|
-
if (insights.heavyGifs.includes(record.id)) {
|
|
89
|
-
findings.push("Heavy GIF — every frame decodes into memory; a video or Lottie is typically ~90% smaller");
|
|
90
|
-
}
|
|
91
|
-
if (insights.heavyFonts.includes(record.id)) {
|
|
92
|
-
findings.push("Heavy font — likely an unsubset icon font; subsetting to used glyphs usually saves most of it");
|
|
93
|
-
}
|
|
94
|
-
if (insights.scaleAnomalies.includes(record.id)) {
|
|
95
|
-
findings.push("Scale anomaly — a higher-resolution variant is smaller in bytes than a lower one; check the exports");
|
|
96
|
-
}
|
|
97
|
-
const estimate = estDecodedBytes(record);
|
|
98
|
-
return /*#__PURE__*/_jsxs(ScrollView, {
|
|
99
|
-
style: styles.scroll,
|
|
100
|
-
contentContainerStyle: styles.content,
|
|
101
|
-
testID: ASSETS_TEST_IDS.detailScroll,
|
|
102
|
-
children: [/*#__PURE__*/_jsx(Preview, {
|
|
103
|
-
record: record
|
|
104
|
-
}), findings.length > 0 ? /*#__PURE__*/_jsx(View, {
|
|
105
|
-
style: styles.findings,
|
|
106
|
-
testID: ASSETS_TEST_IDS.detailFindings,
|
|
107
|
-
children: findings.map((finding, index) => /*#__PURE__*/_jsx(Text, {
|
|
108
|
-
style: styles.findingText,
|
|
109
|
-
testID: assetFindingTestID(index),
|
|
110
|
-
children: finding
|
|
111
|
-
}, finding))
|
|
112
|
-
}) : null, /*#__PURE__*/_jsx(Row, {
|
|
113
|
-
label: "Name",
|
|
114
|
-
value: `${record.name}.${record.type}`
|
|
115
|
-
}), /*#__PURE__*/_jsx(Row, {
|
|
116
|
-
label: "Kind",
|
|
117
|
-
value: record.kind
|
|
118
|
-
}), /*#__PURE__*/_jsx(Row, {
|
|
119
|
-
label: "Status",
|
|
120
|
-
value: record.loaded ? "Loaded (registered at runtime)" : "Not observed in the runtime registry"
|
|
121
|
-
}), record.kind === "image" ? /*#__PURE__*/_jsx(Row, {
|
|
122
|
-
label: "Dimensions",
|
|
123
|
-
value: `${formatDimensions(record)} (logical)`
|
|
124
|
-
}) : null, record.kind === "image" && record.scales.length ? /*#__PURE__*/_jsx(Row, {
|
|
125
|
-
label: "Scales",
|
|
126
|
-
value: formatScales(record.scales)
|
|
127
|
-
}) : null, record.sizesByScale ? Object.entries(record.sizesByScale).map(([scale, bytes]) => /*#__PURE__*/_jsx(Row, {
|
|
128
|
-
label: `Size @${scale}x`,
|
|
129
|
-
value: formatBytes(bytes)
|
|
130
|
-
}, scale)) : null, record.sizeBytes != null && record.sizeSource === "measured" ? /*#__PURE__*/_jsx(Row, {
|
|
131
|
-
label: "Total size",
|
|
132
|
-
value: formatBytes(record.sizeBytes)
|
|
133
|
-
}) : null, estimate > 0 ? /*#__PURE__*/_jsx(Row, {
|
|
134
|
-
label: "Decoded memory",
|
|
135
|
-
value: `~${formatBytes(estimate)} (RGBA)`
|
|
136
|
-
}) : null, record.registryId != null ? /*#__PURE__*/_jsx(Row, {
|
|
137
|
-
label: "Registry id",
|
|
138
|
-
value: String(record.registryId)
|
|
139
|
-
}) : null, record.hash ? /*#__PURE__*/_jsx(Row, {
|
|
140
|
-
label: "Hash",
|
|
141
|
-
value: record.hash
|
|
142
|
-
}) : null, record.httpServerLocation ? /*#__PURE__*/_jsx(Row, {
|
|
143
|
-
label: "Location",
|
|
144
|
-
value: record.httpServerLocation
|
|
145
|
-
}) : null, record.fileSystemLocation ? /*#__PURE__*/_jsx(Row, {
|
|
146
|
-
label: "Source dir",
|
|
147
|
-
value: record.fileSystemLocation
|
|
148
|
-
}) : null, record.resolvedUri ? /*#__PURE__*/_jsx(Row, {
|
|
149
|
-
label: "Resolved URI",
|
|
150
|
-
value: record.resolvedUri
|
|
151
|
-
}) : null]
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
const styles = StyleSheet.create({
|
|
155
|
-
scroll: {
|
|
156
|
-
flex: 1
|
|
157
|
-
},
|
|
158
|
-
content: {
|
|
159
|
-
padding: 12,
|
|
160
|
-
gap: 8
|
|
161
|
-
},
|
|
162
|
-
previewBox: {
|
|
163
|
-
borderRadius: 8,
|
|
164
|
-
backgroundColor: night.color.bg,
|
|
165
|
-
padding: 12,
|
|
166
|
-
alignItems: "center",
|
|
167
|
-
justifyContent: "center",
|
|
168
|
-
minHeight: 96
|
|
169
|
-
},
|
|
170
|
-
previewImage: {
|
|
171
|
-
width: "100%",
|
|
172
|
-
height: 140
|
|
173
|
-
},
|
|
174
|
-
fontPreview: {
|
|
175
|
-
color: night.color.text,
|
|
176
|
-
fontSize: 16,
|
|
177
|
-
textAlign: "center"
|
|
178
|
-
},
|
|
179
|
-
findings: {
|
|
180
|
-
borderRadius: 8,
|
|
181
|
-
borderWidth: 1,
|
|
182
|
-
borderColor: night.color.border,
|
|
183
|
-
backgroundColor: night.color.surface,
|
|
184
|
-
padding: 10,
|
|
185
|
-
gap: 6
|
|
186
|
-
},
|
|
187
|
-
findingText: {
|
|
188
|
-
color: night.color.textSecondary,
|
|
189
|
-
fontSize: 11,
|
|
190
|
-
lineHeight: 15
|
|
191
|
-
},
|
|
192
|
-
kvRow: {
|
|
193
|
-
gap: 2
|
|
194
|
-
},
|
|
195
|
-
kvLabel: {
|
|
196
|
-
color: night.color.textTertiary,
|
|
197
|
-
fontSize: 9,
|
|
198
|
-
fontWeight: "700",
|
|
199
|
-
letterSpacing: 0.5,
|
|
200
|
-
textTransform: "uppercase"
|
|
201
|
-
},
|
|
202
|
-
kvValue: {
|
|
203
|
-
color: night.color.text,
|
|
204
|
-
fontSize: 12
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
//# sourceMappingURL=AssetDetail.js.map
|
|
1
|
+
"use strict";import{ScrollView as h,StyleSheet as f,Text as u,View as r}from"react-native";import{night as o}from"@buoy-gg/shared-ui";import{AssetImage as g}from"./AssetImage";import{formatBytes as p,formatDimensions as b,formatScales as S}from"../format";import{estDecodedBytes as x}from"../store/assetStore";import{ASSETS_TEST_IDS as d,assetDetailRowTestID as w,assetFindingTestID as D}from"../utils/testIDs";import{jsx as t,jsxs as y}from"react/jsx-runtime";function i({label:e,value:n}){const l=w(e);return y(r,{style:s.kvRow,testID:l,children:[t(u,{style:s.kvLabel,children:e}),t(u,{style:s.kvValue,selectable:true,testID:`${l}-value`,children:n})]})}function I({record:e}){if(e.kind==="image"){return t(r,{style:s.previewBox,testID:d.detailPreview,children:t(g,{testID:"buoy-internal-assets-preview",record:e,style:s.previewImage})})}if(e.kind==="font"){return t(r,{style:s.previewBox,testID:d.detailFontPreview,children:t(u,{style:[s.fontPreview,{fontFamily:e.name}],children:"The quick brown fox jumps over the lazy dog 0123456789"})})}return null}export function AssetDetail({record:e,insights:n}){const l=[];if(n.neverLoaded.includes(e.id)){l.push("Not observed in the runtime registry this app run. This does not prove the asset is unused.")}if(n.scaleGaps.includes(e.id)){l.push("Scale gap \u2014 no variant covers this device's pixel ratio")}if(n.webpCandidates.includes(e.id)){l.push("WebP candidate \u2014 large png/jpeg, converting typically saves 20\u201340%")}const v=n.duplicates.find(a=>a.ids.includes(e.id));if(v){l.push(`Duplicate content \u2014 identical bytes shipped ${v.ids.length} times`)}if(n.overDecode.includes(e.id)){l.push("Decodes larger than 2\xD7 this entire screen \u2014 resize the source, no view can need this many pixels")}if(n.heavyGifs.includes(e.id)){l.push("Heavy GIF \u2014 every frame decodes into memory; a video or Lottie is typically ~90% smaller")}if(n.heavyFonts.includes(e.id)){l.push("Heavy font \u2014 likely an unsubset icon font; subsetting to used glyphs usually saves most of it")}if(n.scaleAnomalies.includes(e.id)){l.push("Scale anomaly \u2014 a higher-resolution variant is smaller in bytes than a lower one; check the exports")}const m=x(e);return y(h,{style:s.scroll,contentContainerStyle:s.content,testID:d.detailScroll,children:[t(I,{record:e}),l.length>0?t(r,{style:s.findings,testID:d.detailFindings,children:l.map((a,c)=>t(u,{style:s.findingText,testID:D(c),children:a},a))}):null,t(i,{label:"Name",value:`${e.name}.${e.type}`}),t(i,{label:"Kind",value:e.kind}),t(i,{label:"Status",value:e.loaded?"Loaded (registered at runtime)":"Not observed in the runtime registry"}),e.kind==="image"?t(i,{label:"Dimensions",value:`${b(e)} (logical)`}):null,e.kind==="image"&&e.scales.length?t(i,{label:"Scales",value:S(e.scales)}):null,e.sizesByScale?Object.entries(e.sizesByScale).map(([a,c])=>t(i,{label:`Size @${a}x`,value:p(c)},a)):null,e.sizeBytes!=null&&e.sizeSource==="measured"?t(i,{label:"Total size",value:p(e.sizeBytes)}):null,m>0?t(i,{label:"Decoded memory",value:`~${p(m)} (RGBA)`}):null,e.registryId!=null?t(i,{label:"Registry id",value:String(e.registryId)}):null,e.hash?t(i,{label:"Hash",value:e.hash}):null,e.httpServerLocation?t(i,{label:"Location",value:e.httpServerLocation}):null,e.fileSystemLocation?t(i,{label:"Source dir",value:e.fileSystemLocation}):null,e.resolvedUri?t(i,{label:"Resolved URI",value:e.resolvedUri}):null]})}const s=f.create({scroll:{flex:1},content:{padding:12,gap:8},previewBox:{borderRadius:8,backgroundColor:o.color.bg,padding:12,alignItems:"center",justifyContent:"center",minHeight:96},previewImage:{width:"100%",height:140},fontPreview:{color:o.color.text,fontSize:16,textAlign:"center"},findings:{borderRadius:8,borderWidth:1,borderColor:o.color.border,backgroundColor:o.color.surface,padding:10,gap:6},findingText:{color:o.color.textSecondary,fontSize:11,lineHeight:15},kvRow:{gap:2},kvLabel:{color:o.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.5,textTransform:"uppercase"},kvValue:{color:o.color.text,fontSize:12}});
|
|
@@ -1,62 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { Image, Platform, StyleSheet, Text, View } from "react-native";
|
|
5
|
-
import { night } from "@buoy-gg/shared-ui";
|
|
6
|
-
import { displaySource } from "../capture/measure";
|
|
7
|
-
import { getExpoPreviewImage } from "./optionalExpoImage";
|
|
8
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
-
export function AssetImage({
|
|
10
|
-
record,
|
|
11
|
-
style,
|
|
12
|
-
testID,
|
|
13
|
-
compact = false
|
|
14
|
-
}) {
|
|
15
|
-
const source = displaySource(record);
|
|
16
|
-
const svg = record.type.toLowerCase() === "svg";
|
|
17
|
-
const ExpoImage = svg && Platform.OS !== "web" ? getExpoPreviewImage() : null;
|
|
18
|
-
const sourceKey = `${record.key}:${record.hash ?? ""}:${typeof source === "number" ? source : source?.uri ?? ""}`;
|
|
19
|
-
const [failedSource, setFailedSource] = useState(null);
|
|
20
|
-
const unavailable = source == null || failedSource === sourceKey || svg && Platform.OS !== "web" && !ExpoImage;
|
|
21
|
-
if (unavailable) {
|
|
22
|
-
const label = svg ? "SVG preview unavailable" : "Image preview unavailable";
|
|
23
|
-
return /*#__PURE__*/_jsx(View, {
|
|
24
|
-
style: [style, styles.fallback],
|
|
25
|
-
accessibilityLabel: label,
|
|
26
|
-
testID: `${testID}-unavailable`,
|
|
27
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
28
|
-
style: styles.text,
|
|
29
|
-
children: compact ? svg ? "SVG" : "IMG" : label
|
|
30
|
-
})
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
const onError = () => setFailedSource(sourceKey);
|
|
34
|
-
if (ExpoImage) {
|
|
35
|
-
return /*#__PURE__*/_jsx(ExpoImage, {
|
|
36
|
-
source: source,
|
|
37
|
-
style: style,
|
|
38
|
-
contentFit: "contain",
|
|
39
|
-
onError: onError,
|
|
40
|
-
testID: testID
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
return /*#__PURE__*/_jsx(Image, {
|
|
44
|
-
source: source,
|
|
45
|
-
style: style,
|
|
46
|
-
resizeMode: "contain",
|
|
47
|
-
onError: onError,
|
|
48
|
-
testID: testID
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
const styles = StyleSheet.create({
|
|
52
|
-
fallback: {
|
|
53
|
-
alignItems: "center",
|
|
54
|
-
justifyContent: "center"
|
|
55
|
-
},
|
|
56
|
-
text: {
|
|
57
|
-
color: night.color.textSecondary,
|
|
58
|
-
fontSize: 10,
|
|
59
|
-
textAlign: "center"
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
//# sourceMappingURL=AssetImage.js.map
|
|
1
|
+
"use strict";import{useState as S}from"react";import{Image as g,Platform as u,StyleSheet as x,Text as v,View as I}from"react-native";import{night as w}from"@buoy-gg/shared-ui";import{displaySource as h}from"../capture/measure";import{getExpoPreviewImage as E}from"./optionalExpoImage";import{jsx as r}from"react/jsx-runtime";export function AssetImage({record:t,style:n,testID:a,compact:f=false}){const e=h(t);const o=t.type.toLowerCase()==="svg";const s=o&&u.OS!=="web"?E():null;const l=`${t.key}:${t.hash??""}:${typeof e==="number"?e:e?.uri??""}`;const[p,b]=S(null);const y=e==null||p===l||o&&u.OS!=="web"&&!s;if(y){const c=o?"SVG preview unavailable":"Image preview unavailable";return r(I,{style:[n,m.fallback],accessibilityLabel:c,testID:`${a}-unavailable`,children:r(v,{style:m.text,children:f?o?"SVG":"IMG":c})})}const i=()=>b(l);if(s){return r(s,{source:e,style:n,contentFit:"contain",onError:i,testID:a})}return r(g,{source:e,style:n,resizeMode:"contain",onError:i,testID:a})}const m=x.create({fallback:{alignItems:"center",justifyContent:"center"},text:{color:w.color.textSecondary,fontSize:10,textAlign:"center"}});
|
|
@@ -1,228 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* AssetRow — one bundled asset as a family-style card (matching the network
|
|
5
|
-
* tool's rows): rounded card, colored accent edge per kind, thumbnail, name,
|
|
6
|
-
* quiet metadata, bold right-aligned size, and finding badges ONLY when a
|
|
7
|
-
* finding exists. A thin proportional bar along the card bottom makes the
|
|
8
|
-
* heavy assets feel heavy at a glance.
|
|
9
|
-
*
|
|
10
|
-
* Thumbnails render through the NUMERIC registry id when available — that
|
|
11
|
-
* routes through resolveAssetSource natively, so it works in dev, iOS
|
|
12
|
-
* release (file://) and Android release (bare resource id) alike. They carry
|
|
13
|
-
* the buoy-internal testID so the images tool never records our own UI.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
17
|
-
import { macOSColors, night, Pill } from "@buoy-gg/shared-ui";
|
|
18
|
-
import { AssetImage } from "./AssetImage";
|
|
19
|
-
import { formatDimensions, formatScales, formatSize, KIND_COLORS, KIND_LABELS } from "../format";
|
|
20
|
-
import { estDecodedBytes } from "../store/assetStore";
|
|
21
|
-
import { assetBadgeTestID, assetRowTestID } from "../utils/testIDs";
|
|
22
|
-
|
|
23
|
-
/** Which audit findings apply to this record (drives the row badges). */
|
|
24
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
25
|
-
function Badge({
|
|
26
|
-
label,
|
|
27
|
-
color,
|
|
28
|
-
testID
|
|
29
|
-
}) {
|
|
30
|
-
// Quiet chip: legibility from light-gray text on a neutral fill. Only the
|
|
31
|
-
// serious tiers (red) and WEBP (blue) carry a small dot; the rest are plain.
|
|
32
|
-
return /*#__PURE__*/_jsx(Pill, {
|
|
33
|
-
label: label,
|
|
34
|
-
color: color,
|
|
35
|
-
variant: "quiet",
|
|
36
|
-
dot: Boolean(color),
|
|
37
|
-
style: {
|
|
38
|
-
paddingVertical: 2.5
|
|
39
|
-
},
|
|
40
|
-
testID: testID
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
export function AssetRow({
|
|
44
|
-
record,
|
|
45
|
-
flags,
|
|
46
|
-
sizeFraction,
|
|
47
|
-
onPress
|
|
48
|
-
}) {
|
|
49
|
-
const accent = KIND_COLORS[record.kind];
|
|
50
|
-
const badges = [];
|
|
51
|
-
if (!record.loaded) badges.push({
|
|
52
|
-
label: "NOT OBSERVED"
|
|
53
|
-
});
|
|
54
|
-
if (flags.oversize) badges.push({
|
|
55
|
-
label: "OVERSIZE",
|
|
56
|
-
color: macOSColors.semantic.error
|
|
57
|
-
});
|
|
58
|
-
if (flags.duplicate) badges.push({
|
|
59
|
-
label: "DUP"
|
|
60
|
-
});
|
|
61
|
-
if (flags.heavy) badges.push({
|
|
62
|
-
label: "HEAVY"
|
|
63
|
-
});
|
|
64
|
-
if (flags.scaleAnomaly) badges.push({
|
|
65
|
-
label: "BAD SCALE",
|
|
66
|
-
color: macOSColors.semantic.error
|
|
67
|
-
});else if (flags.scaleGap) badges.push({
|
|
68
|
-
label: "LOW-RES"
|
|
69
|
-
});
|
|
70
|
-
if (flags.webp) badges.push({
|
|
71
|
-
label: "WEBP",
|
|
72
|
-
color: macOSColors.semantic.info
|
|
73
|
-
});
|
|
74
|
-
return /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
75
|
-
style: styles.card,
|
|
76
|
-
testID: assetRowTestID(record.name, record.type),
|
|
77
|
-
onPress: () => onPress(record.id),
|
|
78
|
-
activeOpacity: 0.7,
|
|
79
|
-
children: [/*#__PURE__*/_jsxs(View, {
|
|
80
|
-
style: styles.body,
|
|
81
|
-
children: [/*#__PURE__*/_jsx(View, {
|
|
82
|
-
style: styles.thumbBox,
|
|
83
|
-
children: record.kind === "image" ? /*#__PURE__*/_jsx(AssetImage
|
|
84
|
-
// buoy-internal- prefix: the images tool skips its own toolchain's
|
|
85
|
-
// views, so previewing an asset never records a render of itself.
|
|
86
|
-
, {
|
|
87
|
-
testID: "buoy-internal-assets-thumb",
|
|
88
|
-
record: record,
|
|
89
|
-
style: styles.thumb,
|
|
90
|
-
compact: true
|
|
91
|
-
}) : /*#__PURE__*/_jsx(Text, {
|
|
92
|
-
style: [styles.thumbFallback, {
|
|
93
|
-
color: accent
|
|
94
|
-
}],
|
|
95
|
-
children: KIND_LABELS[record.kind]
|
|
96
|
-
})
|
|
97
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
98
|
-
style: styles.main,
|
|
99
|
-
children: [/*#__PURE__*/_jsxs(Text, {
|
|
100
|
-
style: styles.name,
|
|
101
|
-
numberOfLines: 1,
|
|
102
|
-
testID: `${assetRowTestID(record.name, record.type)}-name`,
|
|
103
|
-
children: [record.name, /*#__PURE__*/_jsxs(Text, {
|
|
104
|
-
style: styles.ext,
|
|
105
|
-
children: [".", record.type]
|
|
106
|
-
})]
|
|
107
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
108
|
-
style: styles.metaRow,
|
|
109
|
-
children: [record.kind === "image" && record.width != null ? /*#__PURE__*/_jsx(Text, {
|
|
110
|
-
style: styles.meta,
|
|
111
|
-
children: formatDimensions(record)
|
|
112
|
-
}) : null, record.kind === "image" && record.scales.length ? /*#__PURE__*/_jsx(Text, {
|
|
113
|
-
style: styles.meta,
|
|
114
|
-
children: formatScales(record.scales)
|
|
115
|
-
}) : null]
|
|
116
|
-
})]
|
|
117
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
118
|
-
style: styles.right,
|
|
119
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
120
|
-
style: styles.size,
|
|
121
|
-
testID: `${assetRowTestID(record.name, record.type)}-size`,
|
|
122
|
-
children: formatSize(record, estDecodedBytes(record))
|
|
123
|
-
}), badges.length ? /*#__PURE__*/_jsx(View, {
|
|
124
|
-
style: styles.badgeRow,
|
|
125
|
-
children: badges.slice(0, 3).map(b => /*#__PURE__*/_jsx(Badge, {
|
|
126
|
-
label: b.label,
|
|
127
|
-
color: b.color,
|
|
128
|
-
testID: assetBadgeTestID(record.name, record.type, b.label)
|
|
129
|
-
}, b.label))
|
|
130
|
-
}) : null]
|
|
131
|
-
})]
|
|
132
|
-
}), sizeFraction > 0 ? /*#__PURE__*/_jsx(View, {
|
|
133
|
-
style: styles.sizeTrack,
|
|
134
|
-
children: /*#__PURE__*/_jsx(View, {
|
|
135
|
-
style: [styles.sizeFill, {
|
|
136
|
-
backgroundColor: accent,
|
|
137
|
-
width: `${Math.max(2, Math.round(sizeFraction * 100))}%`
|
|
138
|
-
}]
|
|
139
|
-
})
|
|
140
|
-
}) : null]
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
const styles = StyleSheet.create({
|
|
144
|
-
card: {
|
|
145
|
-
marginHorizontal: 10,
|
|
146
|
-
marginTop: 6,
|
|
147
|
-
borderRadius: 10,
|
|
148
|
-
backgroundColor: night.color.surface,
|
|
149
|
-
borderWidth: 1,
|
|
150
|
-
borderColor: night.color.border,
|
|
151
|
-
overflow: "hidden"
|
|
152
|
-
},
|
|
153
|
-
body: {
|
|
154
|
-
flexDirection: "row",
|
|
155
|
-
alignItems: "center",
|
|
156
|
-
paddingVertical: 8,
|
|
157
|
-
paddingHorizontal: 12,
|
|
158
|
-
gap: 10
|
|
159
|
-
},
|
|
160
|
-
thumbBox: {
|
|
161
|
-
width: 40,
|
|
162
|
-
height: 40,
|
|
163
|
-
borderRadius: 8,
|
|
164
|
-
// Light plate so dark glyph assets stay visible on the dark card.
|
|
165
|
-
backgroundColor: "rgba(255,255,255,0.10)",
|
|
166
|
-
borderWidth: 1,
|
|
167
|
-
borderColor: night.color.border,
|
|
168
|
-
alignItems: "center",
|
|
169
|
-
justifyContent: "center",
|
|
170
|
-
overflow: "hidden"
|
|
171
|
-
},
|
|
172
|
-
thumb: {
|
|
173
|
-
width: 34,
|
|
174
|
-
height: 34
|
|
175
|
-
},
|
|
176
|
-
thumbFallback: {
|
|
177
|
-
fontSize: 9,
|
|
178
|
-
fontWeight: "700",
|
|
179
|
-
letterSpacing: 0.5
|
|
180
|
-
},
|
|
181
|
-
main: {
|
|
182
|
-
flex: 1,
|
|
183
|
-
gap: 3
|
|
184
|
-
},
|
|
185
|
-
name: {
|
|
186
|
-
color: night.color.text,
|
|
187
|
-
fontSize: 12,
|
|
188
|
-
fontWeight: "600"
|
|
189
|
-
},
|
|
190
|
-
ext: {
|
|
191
|
-
color: night.color.textTertiary,
|
|
192
|
-
fontWeight: "400"
|
|
193
|
-
},
|
|
194
|
-
metaRow: {
|
|
195
|
-
flexDirection: "row",
|
|
196
|
-
alignItems: "center",
|
|
197
|
-
gap: 8
|
|
198
|
-
},
|
|
199
|
-
meta: {
|
|
200
|
-
color: night.color.textSecondary,
|
|
201
|
-
fontSize: 10,
|
|
202
|
-
fontVariant: ["tabular-nums"]
|
|
203
|
-
},
|
|
204
|
-
right: {
|
|
205
|
-
alignItems: "flex-end",
|
|
206
|
-
gap: 4
|
|
207
|
-
},
|
|
208
|
-
size: {
|
|
209
|
-
color: night.color.text,
|
|
210
|
-
fontSize: 12,
|
|
211
|
-
fontWeight: "700",
|
|
212
|
-
fontVariant: ["tabular-nums"]
|
|
213
|
-
},
|
|
214
|
-
badgeRow: {
|
|
215
|
-
flexDirection: "row",
|
|
216
|
-
gap: 4
|
|
217
|
-
},
|
|
218
|
-
sizeTrack: {
|
|
219
|
-
height: 2,
|
|
220
|
-
backgroundColor: "transparent"
|
|
221
|
-
},
|
|
222
|
-
sizeFill: {
|
|
223
|
-
height: 2,
|
|
224
|
-
opacity: 0.45,
|
|
225
|
-
borderTopRightRadius: 2
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
//# sourceMappingURL=AssetRow.js.map
|
|
1
|
+
"use strict";import{StyleSheet as p,Text as r,TouchableOpacity as g,View as o}from"react-native";import{macOSColors as c,night as n,Pill as y}from"@buoy-gg/shared-ui";import{AssetImage as f}from"./AssetImage";import{formatDimensions as x,formatScales as D,formatSize as w,KIND_COLORS as S,KIND_LABELS as I}from"../format";import{estDecodedBytes as z}from"../store/assetStore";import{assetBadgeTestID as R,assetRowTestID as d}from"../utils/testIDs";import{jsx as l,jsxs as s}from"react/jsx-runtime";function k({label:e,color:i,testID:m}){return l(y,{label:e,color:i,variant:"quiet",dot:Boolean(i),style:{paddingVertical:2.5},testID:m})}export function AssetRow({record:e,flags:i,sizeFraction:m,onPress:b}){const u=S[e.kind];const a=[];if(!e.loaded)a.push({label:"NOT OBSERVED"});if(i.oversize)a.push({label:"OVERSIZE",color:c.semantic.error});if(i.duplicate)a.push({label:"DUP"});if(i.heavy)a.push({label:"HEAVY"});if(i.scaleAnomaly)a.push({label:"BAD SCALE",color:c.semantic.error});else if(i.scaleGap)a.push({label:"LOW-RES"});if(i.webp)a.push({label:"WEBP",color:c.semantic.info});return s(g,{style:t.card,testID:d(e.name,e.type),onPress:()=>b(e.id),activeOpacity:.7,children:[s(o,{style:t.body,children:[l(o,{style:t.thumbBox,children:e.kind==="image"?l(f,{testID:"buoy-internal-assets-thumb",record:e,style:t.thumb,compact:true}):l(r,{style:[t.thumbFallback,{color:u}],children:I[e.kind]})}),s(o,{style:t.main,children:[s(r,{style:t.name,numberOfLines:1,testID:`${d(e.name,e.type)}-name`,children:[e.name,s(r,{style:t.ext,children:[".",e.type]})]}),s(o,{style:t.metaRow,children:[e.kind==="image"&&e.width!=null?l(r,{style:t.meta,children:x(e)}):null,e.kind==="image"&&e.scales.length?l(r,{style:t.meta,children:D(e.scales)}):null]})]}),s(o,{style:t.right,children:[l(r,{style:t.size,testID:`${d(e.name,e.type)}-size`,children:w(e,z(e))}),a.length?l(o,{style:t.badgeRow,children:a.slice(0,3).map(h=>l(k,{label:h.label,color:h.color,testID:R(e.name,e.type,h.label)},h.label))}):null]})]}),m>0?l(o,{style:t.sizeTrack,children:l(o,{style:[t.sizeFill,{backgroundColor:u,width:`${Math.max(2,Math.round(m*100))}%`}]})}):null]})}const t=p.create({card:{marginHorizontal:10,marginTop:6,borderRadius:10,backgroundColor:n.color.surface,borderWidth:1,borderColor:n.color.border,overflow:"hidden"},body:{flexDirection:"row",alignItems:"center",paddingVertical:8,paddingHorizontal:12,gap:10},thumbBox:{width:40,height:40,borderRadius:8,backgroundColor:"rgba(255,255,255,0.10)",borderWidth:1,borderColor:n.color.border,alignItems:"center",justifyContent:"center",overflow:"hidden"},thumb:{width:34,height:34},thumbFallback:{fontSize:9,fontWeight:"700",letterSpacing:.5},main:{flex:1,gap:3},name:{color:n.color.text,fontSize:12,fontWeight:"600"},ext:{color:n.color.textTertiary,fontWeight:"400"},metaRow:{flexDirection:"row",alignItems:"center",gap:8},meta:{color:n.color.textSecondary,fontSize:10,fontVariant:["tabular-nums"]},right:{alignItems:"flex-end",gap:4},size:{color:n.color.text,fontSize:12,fontWeight:"700",fontVariant:["tabular-nums"]},badgeRow:{flexDirection:"row",gap:4},sizeTrack:{height:2,backgroundColor:"transparent"},sizeFill:{height:2,opacity:.45,borderTopRightRadius:2}});
|
|
@@ -1,101 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* AssetsFilterBar — kind filter pills with counts, styled like the network
|
|
5
|
-
* tool's bordered pills: outlined, kind-accent-colored when active. Wrapping
|
|
6
|
-
* row, not a horizontal ScrollView (same height-measurement pitfall the
|
|
7
|
-
* images tool documents).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
11
|
-
import { night } from "@buoy-gg/shared-ui";
|
|
12
|
-
import { KIND_COLORS, KIND_LABELS } from "../format";
|
|
13
|
-
import { ASSETS_TEST_IDS, assetFilterTestID } from "../utils/testIDs";
|
|
14
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
15
|
-
export function AssetsFilterBar({
|
|
16
|
-
stats,
|
|
17
|
-
duplicateCount,
|
|
18
|
-
filter,
|
|
19
|
-
onChange
|
|
20
|
-
}) {
|
|
21
|
-
const chips = [{
|
|
22
|
-
key: "all",
|
|
23
|
-
label: `ALL ${stats.total}`,
|
|
24
|
-
accent: night.color.textSecondary
|
|
25
|
-
}, {
|
|
26
|
-
key: "duplicates",
|
|
27
|
-
label: `DUPLICATES ${duplicateCount}`,
|
|
28
|
-
accent: "#FF9F1C"
|
|
29
|
-
}];
|
|
30
|
-
for (const kind of Object.keys(stats.byKind)) {
|
|
31
|
-
const entry = stats.byKind[kind];
|
|
32
|
-
if (entry.count > 0) {
|
|
33
|
-
chips.push({
|
|
34
|
-
key: kind,
|
|
35
|
-
label: `${KIND_LABELS[kind]} ${entry.count}`,
|
|
36
|
-
accent: KIND_COLORS[kind]
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (stats.neverLoaded > 0) {
|
|
41
|
-
// Amber, not semantic.warning — the bright yellow reads as an alarm.
|
|
42
|
-
chips.push({
|
|
43
|
-
key: "unused",
|
|
44
|
-
label: `NOT OBSERVED ${stats.neverLoaded}`,
|
|
45
|
-
accent: "#FF9F1C"
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
if (chips.length <= 1) return null;
|
|
49
|
-
return /*#__PURE__*/_jsx(View, {
|
|
50
|
-
style: styles.bar,
|
|
51
|
-
testID: ASSETS_TEST_IDS.filterBar,
|
|
52
|
-
children: chips.map(chip => {
|
|
53
|
-
const active = chip.key === filter;
|
|
54
|
-
return /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
55
|
-
accessibilityRole: "button",
|
|
56
|
-
accessibilityState: {
|
|
57
|
-
selected: active
|
|
58
|
-
},
|
|
59
|
-
testID: assetFilterTestID(chip.key),
|
|
60
|
-
style: [styles.chip, active && {
|
|
61
|
-
borderColor: chip.accent,
|
|
62
|
-
backgroundColor: `${chip.accent}1A`
|
|
63
|
-
}]
|
|
64
|
-
// Tapping the active chip again untoggles back to ALL.
|
|
65
|
-
,
|
|
66
|
-
onPress: () => onChange(active ? "all" : chip.key),
|
|
67
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
68
|
-
testID: `${assetFilterTestID(chip.key)}-label`,
|
|
69
|
-
style: [styles.chipText, {
|
|
70
|
-
color: active ? chip.accent : night.color.textSecondary
|
|
71
|
-
}],
|
|
72
|
-
children: chip.label
|
|
73
|
-
})
|
|
74
|
-
}, chip.key);
|
|
75
|
-
})
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
const styles = StyleSheet.create({
|
|
79
|
-
bar: {
|
|
80
|
-
flexDirection: "row",
|
|
81
|
-
flexWrap: "wrap",
|
|
82
|
-
gap: 6,
|
|
83
|
-
paddingHorizontal: 10,
|
|
84
|
-
paddingVertical: 8
|
|
85
|
-
},
|
|
86
|
-
chip: {
|
|
87
|
-
borderWidth: 1,
|
|
88
|
-
borderColor: night.color.border,
|
|
89
|
-
backgroundColor: night.color.surface,
|
|
90
|
-
borderRadius: 999,
|
|
91
|
-
paddingHorizontal: 10,
|
|
92
|
-
paddingVertical: 5
|
|
93
|
-
},
|
|
94
|
-
chipText: {
|
|
95
|
-
fontSize: 10,
|
|
96
|
-
fontWeight: "700",
|
|
97
|
-
letterSpacing: 0.4,
|
|
98
|
-
lineHeight: 13
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
//# sourceMappingURL=AssetsFilterBar.js.map
|
|
1
|
+
"use strict";import{StyleSheet as y,Text as b,TouchableOpacity as u,View as f}from"react-native";import{night as l}from"@buoy-gg/shared-ui";import{KIND_COLORS as p,KIND_LABELS as S}from"../format";import{ASSETS_TEST_IDS as k,assetFilterTestID as a}from"../utils/testIDs";import{jsx as n}from"react/jsx-runtime";export function AssetsFilterBar({stats:r,duplicateCount:i,filter:d,onChange:s}){const o=[{key:"all",label:`ALL ${r.total}`,accent:l.color.textSecondary},{key:"duplicates",label:`DUPLICATES ${i}`,accent:"#FF9F1C"}];for(const e of Object.keys(r.byKind)){const t=r.byKind[e];if(t.count>0){o.push({key:e,label:`${S[e]} ${t.count}`,accent:p[e]})}}if(r.neverLoaded>0){o.push({key:"unused",label:`NOT OBSERVED ${r.neverLoaded}`,accent:"#FF9F1C"})}if(o.length<=1)return null;return n(f,{style:c.bar,testID:k.filterBar,children:o.map(e=>{const t=e.key===d;return n(u,{accessibilityRole:"button",accessibilityState:{selected:t},testID:a(e.key),style:[c.chip,t&&{borderColor:e.accent,backgroundColor:`${e.accent}1A`}],onPress:()=>s(t?"all":e.key),children:n(b,{testID:`${a(e.key)}-label`,style:[c.chipText,{color:t?e.accent:l.color.textSecondary}],children:e.label})},e.key)})})}const c=y.create({bar:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:10,paddingVertical:8},chip:{borderWidth:1,borderColor:l.color.border,backgroundColor:l.color.surface,borderRadius:999,paddingHorizontal:10,paddingVertical:5},chipText:{fontSize:10,fontWeight:"700",letterSpacing:.4,lineHeight:13}});
|
|
@@ -1,69 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* AssetsHeader — shared ModalHeader wiring, matching the Images/Console
|
|
5
|
-
* header pattern. List mode shows inventory totals plus the shared
|
|
6
|
-
* ToolbarCopyButton (full markdown report); detail mode shows back
|
|
7
|
-
* navigation and the single-asset report.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { ModalHeader, ToolbarClearButton, ToolbarCopyButton } from "@buoy-gg/shared-ui";
|
|
11
|
-
import { formatBytes } from "../format";
|
|
12
|
-
import { ASSETS_TEST_IDS } from "../utils/testIDs";
|
|
13
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
-
export function AssetsHeader({
|
|
15
|
-
stats,
|
|
16
|
-
measuring,
|
|
17
|
-
discovering = false,
|
|
18
|
-
detailOpen,
|
|
19
|
-
detailIndex = -1,
|
|
20
|
-
detailTotal = 0,
|
|
21
|
-
onCloseDetail,
|
|
22
|
-
onClear,
|
|
23
|
-
getReport,
|
|
24
|
-
onBack
|
|
25
|
-
}) {
|
|
26
|
-
if (detailOpen) {
|
|
27
|
-
const counter = detailIndex >= 0 && detailTotal > 0 ? `${detailIndex + 1} of ${detailTotal}` : undefined;
|
|
28
|
-
return /*#__PURE__*/_jsxs(ModalHeader, {
|
|
29
|
-
children: [/*#__PURE__*/_jsx(ModalHeader.Navigation, {
|
|
30
|
-
onBack: onCloseDetail
|
|
31
|
-
}), /*#__PURE__*/_jsx(ModalHeader.Content, {
|
|
32
|
-
title: "Asset detail",
|
|
33
|
-
subtitle: counter,
|
|
34
|
-
testID: ASSETS_TEST_IDS.title
|
|
35
|
-
}), /*#__PURE__*/_jsx(ModalHeader.Actions, {
|
|
36
|
-
children: /*#__PURE__*/_jsx(ToolbarCopyButton, {
|
|
37
|
-
value: getReport,
|
|
38
|
-
testID: ASSETS_TEST_IDS.copy
|
|
39
|
-
})
|
|
40
|
-
})]
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
const subtitleParts = [`${stats.total} assets${discovering ? " so far" : ""}`];
|
|
44
|
-
// A mid-measure byte total reads as nonsense ("653 B+") — wait it out.
|
|
45
|
-
if (stats.totalBytes > 0 && !measuring && !discovering) {
|
|
46
|
-
const partial = stats.measuredCount < stats.total ? "+" : "";
|
|
47
|
-
subtitleParts.push(`${formatBytes(stats.totalBytes)}${partial}`);
|
|
48
|
-
}
|
|
49
|
-
if (stats.neverLoaded > 0) subtitleParts.push(`${stats.neverLoaded} not observed`);
|
|
50
|
-
if (stats.fontFamilies > 0) subtitleParts.push(`${stats.fontFamilies} fonts`);
|
|
51
|
-
return /*#__PURE__*/_jsxs(ModalHeader, {
|
|
52
|
-
children: [onBack ? /*#__PURE__*/_jsx(ModalHeader.Navigation, {
|
|
53
|
-
onBack: onBack
|
|
54
|
-
}) : null, /*#__PURE__*/_jsx(ModalHeader.Content, {
|
|
55
|
-
title: "Assets",
|
|
56
|
-
subtitle: subtitleParts.join(" · "),
|
|
57
|
-
testID: ASSETS_TEST_IDS.title
|
|
58
|
-
}), /*#__PURE__*/_jsxs(ModalHeader.Actions, {
|
|
59
|
-
children: [/*#__PURE__*/_jsx(ToolbarCopyButton, {
|
|
60
|
-
value: getReport,
|
|
61
|
-
testID: ASSETS_TEST_IDS.copy
|
|
62
|
-
}), /*#__PURE__*/_jsx(ToolbarClearButton, {
|
|
63
|
-
onPress: onClear,
|
|
64
|
-
testID: ASSETS_TEST_IDS.clear
|
|
65
|
-
})]
|
|
66
|
-
})]
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
//# sourceMappingURL=AssetsHeader.js.map
|
|
1
|
+
"use strict";import{ModalHeader as e,ToolbarClearButton as b,ToolbarCopyButton as d}from"@buoy-gg/shared-ui";import{formatBytes as v}from"../format";import{ASSETS_TEST_IDS as n}from"../utils/testIDs";import{jsx as o,jsxs as i}from"react/jsx-runtime";export function AssetsHeader({stats:t,measuring:m,discovering:l=false,detailOpen:p,detailIndex:a=-1,detailTotal:u=0,onCloseDetail:$,onClear:h,getReport:f,onBack:c}){if(p){const r=a>=0&&u>0?`${a+1} of ${u}`:void 0;return i(e,{children:[o(e.Navigation,{onBack:$}),o(e.Content,{title:"Asset detail",subtitle:r,testID:n.title}),o(e.Actions,{children:o(d,{value:f,testID:n.copy})})]})}const s=[`${t.total} assets${l?" so far":""}`];if(t.totalBytes>0&&!m&&!l){const r=t.measuredCount<t.total?"+":"";s.push(`${v(t.totalBytes)}${r}`)}if(t.neverLoaded>0)s.push(`${t.neverLoaded} not observed`);if(t.fontFamilies>0)s.push(`${t.fontFamilies} fonts`);return i(e,{children:[c?o(e.Navigation,{onBack:c}):null,o(e.Content,{title:"Assets",subtitle:s.join(" \xB7 "),testID:n.title}),i(e.Actions,{children:[o(d,{value:f,testID:n.copy}),o(b,{onPress:h,testID:n.clear})]})]})}
|