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