nuxt-devtools-observatory 0.1.28 → 0.1.30

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.
@@ -1,7 +1,8 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, defineComponent, h, ref, watch, type VNode } from 'vue'
3
- import { useObservatoryData, openInEditor as openInEditorFromStore } from '../stores/observatory'
4
- import type { RenderEntry, RenderEvent } from '../../../src/types/snapshot'
3
+ import { useResizablePane } from '@observatory-client/composables/useResizablePane'
4
+ import { useObservatoryData, openInEditor as openInEditorFromStore } from '@observatory-client/stores/observatory'
5
+ import type { RenderEntry, RenderEvent } from '@observatory/types/snapshot'
5
6
 
6
7
  interface ComponentNode {
7
8
  id: string
@@ -171,6 +172,7 @@ const TreeNode = defineComponent({
171
172
  })
172
173
 
173
174
  const { renders, connected } = useObservatoryData()
175
+ const { paneWidth: detailWidth, onHandleMouseDown: onDetailHandleMouseDown } = useResizablePane(280, 'observatory:heatmap:detailWidth')
174
176
 
175
177
  const activeMode = ref<'count' | 'time'>('count')
176
178
  // Route filter — '' means show all routes
@@ -706,13 +708,13 @@ function formatTimestamp(t: number): string {
706
708
  </script>
707
709
 
708
710
  <template>
709
- <div class="view">
710
- <div class="controls">
711
- <div class="mode-group">
711
+ <div class="render-heatmap tracker-view">
712
+ <div class="render-heatmap__controls tracker-toolbar">
713
+ <div class="render-heatmap__mode-group">
712
714
  <button :class="{ active: activeMode === 'count' }" @click="activeMode = 'count'">render count</button>
713
715
  <button :class="{ active: activeMode === 'time' }" @click="activeMode = 'time'">render time</button>
714
716
  </div>
715
- <div class="threshold-group">
717
+ <div class="render-heatmap__threshold-group">
716
718
  <span class="muted text-sm">threshold</span>
717
719
  <input
718
720
  v-model.number="activeThreshold"
@@ -720,7 +722,7 @@ function formatTimestamp(t: number): string {
720
722
  :min="activeMode === 'count' ? 2 : 4"
721
723
  :max="activeMode === 'count' ? 20 : 100"
722
724
  :step="activeMode === 'count' ? 1 : 4"
723
- style="width: 90px"
725
+ class="render-heatmap__threshold-range"
724
726
  />
725
727
  <span class="mono text-sm">{{ activeThreshold }}{{ activeMode === 'count' ? '+ renders' : 'ms+' }}</span>
726
728
  </div>
@@ -729,12 +731,12 @@ function formatTimestamp(t: number): string {
729
731
  <option value="">all routes</option>
730
732
  <option v-for="r in knownRoutes" :key="r" :value="r">{{ r }}</option>
731
733
  </select>
732
- <button :class="{ active: frozen }" style="margin-left: auto" @click="toggleFreeze">
734
+ <button :class="{ active: frozen }" class="render-heatmap__freeze tracker-toolbar__spacer" @click="toggleFreeze">
733
735
  {{ frozen ? 'unfreeze' : 'freeze snapshot' }}
734
736
  </button>
735
737
  </div>
736
738
 
737
- <div class="stats-row">
739
+ <div class="render-heatmap__stats tracker-stats-row">
738
740
  <div class="stat-card">
739
741
  <div class="stat-label">components</div>
740
742
  <div class="stat-val">{{ allComponents.length }}</div>
@@ -745,7 +747,7 @@ function formatTimestamp(t: number): string {
745
747
  </div>
746
748
  <div class="stat-card">
747
749
  <div class="stat-label">hot</div>
748
- <div class="stat-val" style="color: var(--red)">{{ hotCount }}</div>
750
+ <div class="stat-val stat-val--error">{{ hotCount }}</div>
749
751
  </div>
750
752
  <div class="stat-card">
751
753
  <div class="stat-label">avg time</div>
@@ -753,32 +755,37 @@ function formatTimestamp(t: number): string {
753
755
  </div>
754
756
  </div>
755
757
 
756
- <div class="inspector">
757
- <aside class="roots-panel">
758
- <div class="panel-title">apps</div>
758
+ <div class="render-heatmap__inspector">
759
+ <aside class="render-heatmap__roots-panel">
760
+ <div class="render-heatmap__panel-title tracker-section-label">apps</div>
759
761
  <button
760
762
  v-for="entry in appEntries"
761
763
  :key="entry.id"
762
- class="root-item"
764
+ class="render-heatmap__root-item"
763
765
  :class="{ active: activeRootId === entry.id }"
764
766
  @click="selectRoot(entry.root)"
765
767
  >
766
- <div class="root-copy">
767
- <span class="root-label mono">{{ entry.label }}</span>
768
- <span class="root-sub muted mono">{{ entry.root.label }}</span>
768
+ <div class="render-heatmap__root-copy">
769
+ <span class="render-heatmap__root-label mono">{{ entry.label }}</span>
770
+ <span class="render-heatmap__root-sub muted mono">{{ entry.root.label }}</span>
769
771
  </div>
770
- <span class="root-meta mono">{{ entry.meta }}</span>
772
+ <span class="render-heatmap__root-meta mono">{{ entry.meta }}</span>
771
773
  </button>
772
- <div v-if="!appEntries.length" class="detail-empty">no apps match</div>
774
+ <div v-if="!appEntries.length" class="render-heatmap__detail-empty">no apps match</div>
773
775
  </aside>
774
776
 
775
- <section class="tree-panel">
776
- <div class="tree-toolbar">
777
- <input :value="search" class="search-input mono" placeholder="Find components..." @input="updateSearch" />
777
+ <section class="render-heatmap__tree-panel">
778
+ <div class="render-heatmap__tree-toolbar">
779
+ <input
780
+ :value="search"
781
+ class="render-heatmap__search-input mono"
782
+ placeholder="Find components..."
783
+ @input="updateSearch"
784
+ />
778
785
  </div>
779
786
 
780
- <div class="tree-frame">
781
- <div class="tree-canvas">
787
+ <div class="render-heatmap__tree-frame">
788
+ <div class="render-heatmap__tree-canvas tree-canvas">
782
789
  <TreeNode
783
790
  v-for="root in visibleTreeRoots"
784
791
  :key="root.id"
@@ -791,47 +798,62 @@ function formatTimestamp(t: number): string {
791
798
  @toggle="toggleNode"
792
799
  />
793
800
  </div>
794
- <div v-if="!visibleTreeRoots.length" class="detail-empty">
801
+ <div v-if="!visibleTreeRoots.length" class="render-heatmap__detail-empty">
795
802
  {{ connected ? 'No render activity recorded yet.' : 'Waiting for connection to the Nuxt app…' }}
796
803
  </div>
797
804
  </div>
798
805
  </section>
799
806
 
800
- <aside class="detail-panel">
807
+ <div class="tracker-resize-handle" @mousedown="onDetailHandleMouseDown" />
808
+
809
+ <aside class="render-heatmap__detail-panel tracker-detail-panel" :style="{ width: detailWidth + 'px' }">
801
810
  <template v-if="activeSelected">
802
- <div class="detail-header">
803
- <span class="mono bold" style="font-size: 12px">{{ activeSelected.label }}</span>
811
+ <div class="render-heatmap__detail-header">
812
+ <span class="render-heatmap__detail-title mono bold">{{ activeSelected.label }}</span>
804
813
  <button @click="activeSelectedId = null">×</button>
805
814
  </div>
806
815
 
807
- <div class="detail-pill-row">
808
- <span class="detail-pill mono">
816
+ <div class="render-heatmap__detail-pill-row">
817
+ <span class="render-heatmap__detail-pill mono">
809
818
  {{ activeSelected.rerenders + activeSelected.mountCount }} render{{
810
819
  activeSelected.rerenders + activeSelected.mountCount !== 1 ? 's' : ''
811
820
  }}
812
821
  </span>
813
- <span class="detail-pill mono muted">
822
+ <span class="render-heatmap__detail-pill render-heatmap__detail-pill--muted mono muted">
814
823
  {{ activeSelected.mountCount }} mount{{ activeSelected.mountCount !== 1 ? 's' : '' }}
815
824
  </span>
816
- <span v-if="activeSelected.rerenders" class="detail-pill mono">
825
+ <span v-if="activeSelected.rerenders" class="render-heatmap__detail-pill mono">
817
826
  {{ activeSelected.rerenders }} re-render{{ activeSelected.rerenders !== 1 ? 's' : '' }}
818
827
  </span>
819
- <span v-if="activeSelected.isPersistent" class="detail-pill mono persistent">persistent</span>
820
- <span v-if="activeSelected.isHydrationMount" class="detail-pill mono hydrated">hydrated</span>
821
- <span class="detail-pill mono">{{ activeSelected.avgMs.toFixed(1) }}ms avg</span>
822
- <span class="detail-pill mono" :class="{ hot: isHot(activeSelected) }">
828
+ <span
829
+ v-if="activeSelected.isPersistent"
830
+ class="render-heatmap__detail-pill render-heatmap__detail-pill--persistent mono"
831
+ >
832
+ persistent
833
+ </span>
834
+ <span
835
+ v-if="activeSelected.isHydrationMount"
836
+ class="render-heatmap__detail-pill render-heatmap__detail-pill--hydrated mono"
837
+ >
838
+ hydrated
839
+ </span>
840
+ <span class="render-heatmap__detail-pill mono">{{ activeSelected.avgMs.toFixed(1) }}ms avg</span>
841
+ <span
842
+ class="render-heatmap__detail-pill mono"
843
+ :class="{ 'render-heatmap__detail-pill--hot': isHot(activeSelected) }"
844
+ >
823
845
  {{ isHot(activeSelected) ? 'hot' : 'cool' }}
824
846
  </span>
825
847
  </div>
826
848
 
827
- <div class="section-label">identity</div>
828
- <div class="meta-grid">
849
+ <div class="tracker-section-label render-heatmap__section-label">identity</div>
850
+ <div class="render-heatmap__meta-grid">
829
851
  <span class="muted text-sm">label</span>
830
852
  <span class="mono text-sm">{{ activeSelected.label }}</span>
831
853
  <span class="muted text-sm">path</span>
832
854
  <span class="mono text-sm">{{ pathLabel(activeSelected) }}</span>
833
855
  <span class="muted text-sm">file</span>
834
- <span class="mono text-sm muted" style="display: flex; align-items: center; gap: 6px">
856
+ <span class="render-heatmap__file-row mono text-sm muted">
835
857
  {{ activeSelected.file }}
836
858
  <button
837
859
  v-if="activeSelected.file && activeSelected.file !== 'unknown'"
@@ -850,8 +872,8 @@ function formatTimestamp(t: number): string {
850
872
  <span class="mono text-sm">{{ activeSelected.children.length }}</span>
851
873
  </div>
852
874
 
853
- <div class="section-label">rendering</div>
854
- <div class="meta-grid">
875
+ <div class="tracker-section-label render-heatmap__section-label">rendering</div>
876
+ <div class="render-heatmap__meta-grid">
855
877
  <span class="muted text-sm">total renders</span>
856
878
  <span class="mono text-sm">{{ activeSelected.rerenders + activeSelected.mountCount }}</span>
857
879
  <span class="muted text-sm">re-renders</span>
@@ -859,7 +881,7 @@ function formatTimestamp(t: number): string {
859
881
  <span class="muted text-sm">mounts</span>
860
882
  <span class="mono text-sm">{{ activeSelected.mountCount }}</span>
861
883
  <span class="muted text-sm">persistent</span>
862
- <span class="mono text-sm" :style="{ color: activeSelected.isPersistent ? 'var(--amber)' : 'inherit' }">
884
+ <span class="mono text-sm" :class="{ 'render-heatmap__persistent-value': activeSelected.isPersistent }">
863
885
  {{ activeSelected.isPersistent ? 'yes — survives navigation' : 'no' }}
864
886
  </span>
865
887
  <span class="muted text-sm">hydration mount</span>
@@ -872,47 +894,42 @@ function formatTimestamp(t: number): string {
872
894
  <span class="mono text-sm">{{ activeMode === 'count' ? 're-render count' : 'render time' }}</span>
873
895
  </div>
874
896
 
875
- <div class="section-label">triggers</div>
876
- <div v-for="trigger in activeSelected.triggers" :key="trigger" class="trigger-item mono text-sm">{{ trigger }}</div>
897
+ <div class="tracker-section-label render-heatmap__section-label">triggers</div>
898
+ <div v-for="trigger in activeSelected.triggers" :key="trigger" class="render-heatmap__trigger-item mono text-sm">
899
+ {{ trigger }}
900
+ </div>
877
901
  <div v-if="!activeSelected.triggers.length" class="muted text-sm">no triggers recorded</div>
878
902
 
879
- <div class="section-label" style="margin-top: 8px">
903
+ <div class="tracker-section-label render-heatmap__section-label render-heatmap__section-label--timeline">
880
904
  render timeline
881
- <span class="muted" style="font-weight: 400; text-transform: none; letter-spacing: 0">
882
- ({{ activeSelected.timeline.length }})
883
- </span>
905
+ <span class="render-heatmap__section-label-meta muted">({{ activeSelected.timeline.length }})</span>
884
906
  </div>
885
907
  <div v-if="!activeSelected.timeline.length" class="muted text-sm">no timeline events yet</div>
886
- <div v-else class="timeline-list">
887
- <div v-for="(event, idx) in [...activeSelected.timeline].reverse().slice(0, 30)" :key="idx" class="timeline-row">
888
- <span class="timeline-kind mono" :class="event.kind">{{ event.kind }}</span>
889
- <span class="timeline-time mono muted">{{ formatTimestamp(event.t) }}</span>
890
- <span class="timeline-dur mono">{{ formatMs(event.durationMs) }}</span>
891
- <span v-if="event.triggerKey" class="timeline-trigger mono muted">{{ event.triggerKey }}</span>
892
- <span class="timeline-route mono muted" style="margin-left: auto">{{ event.route }}</span>
908
+ <div v-else class="render-heatmap__timeline-list">
909
+ <div
910
+ v-for="(event, idx) in [...activeSelected.timeline].reverse().slice(0, 30)"
911
+ :key="idx"
912
+ class="render-heatmap__timeline-row"
913
+ >
914
+ <span class="render-heatmap__timeline-kind mono" :class="event.kind">{{ event.kind }}</span>
915
+ <span class="render-heatmap__timeline-time mono muted">{{ formatTimestamp(event.t) }}</span>
916
+ <span class="render-heatmap__timeline-dur mono">{{ formatMs(event.durationMs) }}</span>
917
+ <span v-if="event.triggerKey" class="render-heatmap__timeline-trigger mono muted">{{ event.triggerKey }}</span>
918
+ <span class="render-heatmap__timeline-route mono muted">{{ event.route }}</span>
893
919
  </div>
894
- <div v-if="activeSelected.timeline.length > 30" class="muted text-sm" style="padding: 2px 0">
920
+ <div v-if="activeSelected.timeline.length > 30" class="render-heatmap__compact-muted muted text-sm">
895
921
  … {{ activeSelected.timeline.length - 30 }} earlier events
896
922
  </div>
897
923
  </div>
898
924
  </template>
899
- <div v-else class="detail-empty">click a component to inspect</div>
925
+ <div v-else class="render-heatmap__detail-empty">click a component to inspect</div>
900
926
  </aside>
901
927
  </div>
902
928
  </div>
903
929
  </template>
904
930
 
905
931
  <style scoped>
906
- .view {
907
- display: flex;
908
- flex-direction: column;
909
- height: 100%;
910
- overflow: hidden;
911
- padding: 12px;
912
- gap: 10px;
913
- }
914
-
915
- .controls {
932
+ .render-heatmap__controls {
916
933
  display: flex;
917
934
  align-items: center;
918
935
  gap: 8px;
@@ -920,65 +937,67 @@ function formatTimestamp(t: number): string {
920
937
  flex-wrap: wrap;
921
938
  }
922
939
 
923
- .mode-group {
940
+ .render-heatmap__mode-group {
924
941
  display: flex;
925
942
  gap: 2px;
926
943
  }
927
944
 
928
- .threshold-group {
945
+ .render-heatmap__threshold-group {
929
946
  display: flex;
930
947
  align-items: center;
931
948
  gap: 6px;
932
949
  }
933
950
 
934
- .stats-row {
935
- display: grid;
936
- grid-template-columns: repeat(4, minmax(0, 1fr));
937
- gap: 8px;
938
- flex-shrink: 0;
951
+ .render-heatmap__threshold-range {
952
+ width: 90px;
939
953
  }
940
954
 
941
955
  .stat-sub {
942
- margin-top: 4px;
943
- font-size: 11px;
956
+ margin-top: var(--tracker-space-1);
957
+ font-size: var(--tracker-font-size-sm);
944
958
  color: var(--text3);
945
959
  }
946
960
 
947
- .inspector {
948
- display: grid;
949
- grid-template-columns: minmax(220px, 280px) minmax(0, 1fr) minmax(260px, 320px);
950
- gap: 12px;
961
+ .render-heatmap__inspector {
962
+ display: flex;
963
+ gap: 0;
951
964
  flex: 1;
952
965
  min-height: 0;
953
966
  }
954
967
 
955
- .roots-panel,
956
- .tree-panel,
957
- .detail-panel {
958
- border: 0.5px solid var(--border);
968
+ .render-heatmap__roots-panel,
969
+ .render-heatmap__detail-panel {
970
+ flex-shrink: 0;
971
+ }
972
+
973
+ .render-heatmap__roots-panel {
974
+ width: 240px;
975
+ margin-right: 12px;
976
+ }
977
+
978
+ .render-heatmap__roots-panel,
979
+ .render-heatmap__tree-panel,
980
+ .render-heatmap__detail-panel {
981
+ border: var(--tracker-border-width) solid var(--border);
959
982
  border-radius: var(--radius-lg);
960
983
  background: var(--bg3);
961
984
  min-height: 0;
962
985
  }
963
986
 
964
- .roots-panel,
965
- .detail-panel {
987
+ .render-heatmap__roots-panel,
988
+ .render-heatmap__detail-panel {
966
989
  display: flex;
967
990
  flex-direction: column;
968
991
  overflow: auto;
969
- padding: 12px;
970
- gap: 8px;
992
+ padding: var(--tracker-space-3);
993
+ gap: var(--tracker-space-2);
971
994
  }
972
995
 
973
- .panel-title {
974
- font-size: 10px;
975
- font-weight: 500;
976
- text-transform: uppercase;
977
- letter-spacing: 0.4px;
978
- color: var(--text3);
996
+ .render-heatmap__panel-title {
997
+ margin: 0;
979
998
  }
980
999
 
981
- .root-item {
1000
+ .render-heatmap__root-item {
982
1001
  display: flex;
983
1002
  align-items: center;
984
1003
  justify-content: space-between;
@@ -992,44 +1011,46 @@ function formatTimestamp(t: number): string {
992
1011
  text-align: left;
993
1012
  }
994
1013
 
995
- .root-item.active {
1014
+ .render-heatmap__root-item.active {
996
1015
  border-color: var(--teal);
997
1016
  background: color-mix(in srgb, var(--teal) 16%, var(--bg2));
998
1017
  }
999
1018
 
1000
- .root-label {
1019
+ .render-heatmap__root-label {
1001
1020
  overflow: hidden;
1002
1021
  text-overflow: ellipsis;
1003
1022
  white-space: nowrap;
1004
1023
  }
1005
1024
 
1006
- .root-copy {
1025
+ .render-heatmap__root-copy {
1007
1026
  display: flex;
1008
1027
  flex-direction: column;
1009
1028
  min-width: 0;
1010
1029
  }
1011
1030
 
1012
- .root-sub {
1013
- font-size: 11px;
1031
+ .render-heatmap__root-sub {
1032
+ font-size: var(--tracker-font-size-sm);
1014
1033
  }
1015
1034
 
1016
- .root-meta {
1035
+ .render-heatmap__root-meta {
1017
1036
  color: var(--text3);
1018
- font-size: 11px;
1037
+ font-size: var(--tracker-font-size-sm);
1019
1038
  }
1020
1039
 
1021
- .tree-panel {
1040
+ .render-heatmap__tree-panel {
1022
1041
  display: flex;
1023
1042
  flex-direction: column;
1024
1043
  overflow: hidden;
1044
+ flex: 1;
1045
+ min-width: 0;
1025
1046
  }
1026
1047
 
1027
- .tree-toolbar {
1028
- padding: 12px;
1029
- border-bottom: 0.5px solid var(--border);
1048
+ .render-heatmap__tree-toolbar {
1049
+ padding: var(--tracker-space-3);
1050
+ border-bottom: var(--tracker-border-width) solid var(--border);
1030
1051
  }
1031
1052
 
1032
- .search-input {
1053
+ .render-heatmap__search-input {
1033
1054
  width: 100%;
1034
1055
  padding: 10px 12px;
1035
1056
  border: 1px solid var(--border);
@@ -1038,14 +1059,14 @@ function formatTimestamp(t: number): string {
1038
1059
  color: var(--text);
1039
1060
  }
1040
1061
 
1041
- .tree-frame {
1062
+ .render-heatmap__tree-frame {
1042
1063
  flex: 1;
1043
1064
  min-height: 0;
1044
1065
  overflow: auto;
1045
- padding: 12px;
1066
+ padding: var(--tracker-space-3);
1046
1067
  }
1047
1068
 
1048
- :deep(.tree-canvas) {
1069
+ .render-heatmap__tree-canvas {
1049
1070
  display: inline-block;
1050
1071
  min-width: 100%;
1051
1072
  width: max-content;
@@ -1197,72 +1218,77 @@ function formatTimestamp(t: number): string {
1197
1218
  border-left: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
1198
1219
  }
1199
1220
 
1200
- .detail-empty {
1221
+ .render-heatmap__detail-empty {
1201
1222
  display: flex;
1202
1223
  align-items: center;
1203
1224
  justify-content: center;
1204
1225
  height: 100%;
1205
1226
  color: var(--text3);
1206
- font-size: 12px;
1227
+ font-size: var(--tracker-font-size-md);
1207
1228
  }
1208
1229
 
1209
- .detail-header {
1230
+ .render-heatmap__detail-header {
1210
1231
  display: flex;
1211
1232
  align-items: center;
1212
1233
  justify-content: space-between;
1213
1234
  }
1214
1235
 
1215
- .meta-grid {
1236
+ .render-heatmap__detail-title {
1237
+ font-size: var(--tracker-font-size-md);
1238
+ }
1239
+
1240
+ .render-heatmap__meta-grid {
1216
1241
  display: grid;
1217
1242
  grid-template-columns: auto 1fr;
1218
- gap: 4px 12px;
1243
+ gap: var(--tracker-space-1) var(--tracker-space-3);
1219
1244
  }
1220
1245
 
1221
- .detail-pill-row {
1246
+ .render-heatmap__detail-pill-row {
1222
1247
  display: flex;
1223
1248
  flex-wrap: wrap;
1224
1249
  gap: 6px;
1225
1250
  }
1226
1251
 
1227
- .detail-pill {
1252
+ .render-heatmap__detail-pill {
1228
1253
  border: 1px solid var(--border);
1229
1254
  border-radius: 999px;
1230
1255
  padding: 4px 8px;
1231
1256
  background: var(--bg2);
1232
- font-size: 11px;
1257
+ font-size: var(--tracker-font-size-sm);
1233
1258
  }
1234
1259
 
1235
- .detail-pill.hot {
1260
+ .render-heatmap__detail-pill--hot {
1236
1261
  border-color: color-mix(in srgb, var(--red) 50%, var(--border));
1237
1262
  color: var(--red);
1238
1263
  }
1239
1264
 
1240
- .detail-pill.persistent {
1265
+ .render-heatmap__detail-pill--persistent {
1241
1266
  border-color: color-mix(in srgb, var(--amber) 55%, var(--border));
1242
1267
  color: color-mix(in srgb, var(--amber) 80%, var(--text));
1243
1268
  }
1244
1269
 
1245
- .detail-pill.hydrated {
1270
+ .render-heatmap__detail-pill--hydrated {
1246
1271
  border-color: color-mix(in srgb, var(--teal) 55%, var(--border));
1247
1272
  color: color-mix(in srgb, var(--teal) 80%, var(--text));
1248
1273
  }
1249
1274
 
1250
- .detail-pill.muted {
1275
+ .render-heatmap__detail-pill--muted {
1251
1276
  color: var(--text3);
1252
1277
  border-color: var(--border);
1253
1278
  }
1254
1279
 
1255
- .section-label {
1256
- font-size: 10px;
1257
- font-weight: 500;
1258
- text-transform: uppercase;
1259
- letter-spacing: 0.4px;
1260
- color: var(--text3);
1280
+ .render-heatmap__section-label {
1261
1281
  margin-top: 8px;
1262
1282
  margin-bottom: 4px;
1263
1283
  }
1264
1284
 
1265
- .trigger-item {
1285
+ .render-heatmap__file-row {
1286
+ display: flex;
1287
+ align-items: center;
1288
+ gap: 6px;
1289
+ }
1290
+
1291
+ .render-heatmap__trigger-item {
1266
1292
  background: var(--bg2);
1267
1293
  border-radius: var(--radius);
1268
1294
  padding: 4px 8px;
@@ -1270,6 +1296,20 @@ function formatTimestamp(t: number): string {
1270
1296
  color: var(--text2);
1271
1297
  }
1272
1298
 
1299
+ .render-heatmap__persistent-value {
1300
+ color: color-mix(in srgb, var(--amber) 80%, var(--text));
1301
+ }
1302
+
1303
+ .render-heatmap__section-label--timeline {
1304
+ margin-top: var(--tracker-space-2);
1305
+ }
1306
+
1307
+ .render-heatmap__section-label-meta {
1308
+ font-weight: 400;
1309
+ text-transform: none;
1310
+ letter-spacing: 0;
1311
+ }
1312
+
1273
1313
  :deep(.tree-jump-btn) {
1274
1314
  display: none;
1275
1315
  padding: 0 4px;
@@ -1320,7 +1360,7 @@ function formatTimestamp(t: number): string {
1320
1360
  max-width: 140px;
1321
1361
  }
1322
1362
 
1323
- .timeline-list {
1363
+ .render-heatmap__timeline-list {
1324
1364
  display: flex;
1325
1365
  flex-direction: column;
1326
1366
  gap: 1px;
@@ -1332,49 +1372,49 @@ function formatTimestamp(t: number): string {
1332
1372
  min-height: fit-content;
1333
1373
  }
1334
1374
 
1335
- .timeline-row {
1375
+ .render-heatmap__timeline-row {
1336
1376
  display: flex;
1337
1377
  align-items: center;
1338
1378
  gap: 6px;
1339
1379
  padding: 2px 0;
1340
- font-size: 11px;
1341
- border-bottom: 0.5px solid var(--border);
1380
+ font-size: var(--tracker-font-size-sm);
1381
+ border-bottom: var(--tracker-border-width) solid var(--border);
1342
1382
  min-width: 0;
1343
1383
  min-height: fit-content;
1344
1384
  }
1345
1385
 
1346
- .timeline-row:last-child {
1386
+ .render-heatmap__timeline-row:last-child {
1347
1387
  border-bottom: none;
1348
1388
  }
1349
1389
 
1350
- .timeline-kind {
1390
+ .render-heatmap__timeline-kind {
1351
1391
  flex-shrink: 0;
1352
- font-size: 10px;
1392
+ font-size: var(--tracker-font-size-xs);
1353
1393
  font-weight: 500;
1354
1394
  min-width: 40px;
1355
1395
  }
1356
1396
 
1357
- .timeline-kind.mount {
1397
+ .render-heatmap__timeline-kind.mount {
1358
1398
  color: var(--teal);
1359
1399
  }
1360
1400
 
1361
- .timeline-kind.update {
1401
+ .render-heatmap__timeline-kind.update {
1362
1402
  color: var(--amber);
1363
1403
  }
1364
1404
 
1365
- .timeline-time {
1405
+ .render-heatmap__timeline-time {
1366
1406
  flex-shrink: 0;
1367
1407
  min-width: 52px;
1368
1408
  color: var(--text3);
1369
1409
  }
1370
1410
 
1371
- .timeline-dur {
1411
+ .render-heatmap__timeline-dur {
1372
1412
  flex-shrink: 0;
1373
1413
  min-width: 38px;
1374
1414
  color: var(--text2);
1375
1415
  }
1376
1416
 
1377
- .timeline-trigger {
1417
+ .render-heatmap__timeline-trigger {
1378
1418
  overflow: hidden;
1379
1419
  text-overflow: ellipsis;
1380
1420
  white-space: nowrap;
@@ -1383,19 +1423,23 @@ function formatTimestamp(t: number): string {
1383
1423
  min-width: 0;
1384
1424
  }
1385
1425
 
1386
- .timeline-route {
1426
+ .render-heatmap__timeline-route {
1387
1427
  flex-shrink: 0;
1428
+ margin-left: auto;
1388
1429
  color: var(--text3);
1389
- font-size: 10px;
1430
+ font-size: var(--tracker-font-size-xs);
1431
+ }
1432
+
1433
+ .render-heatmap__compact-muted {
1434
+ padding: 2px 0;
1390
1435
  }
1391
1436
 
1392
1437
  @media (width <= 1180px) {
1393
- .inspector {
1394
- grid-template-columns: minmax(200px, 240px) minmax(0, 1fr);
1438
+ .render-heatmap__roots-panel {
1439
+ display: none;
1395
1440
  }
1396
1441
 
1397
- .detail-panel {
1398
- grid-column: 1 / -1;
1442
+ .render-heatmap__detail-panel {
1399
1443
  max-height: 220px;
1400
1444
  }
1401
1445
  }