@kylincloud/flamegraph 0.35.27 → 0.35.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/FlameGraph/FlameGraphComponent/DiffLegend.d.ts.map +1 -1
  3. package/dist/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.d.ts.map +1 -1
  4. package/dist/FlameGraph/FlameGraphComponent/Flamegraph.d.ts +16 -2
  5. package/dist/FlameGraph/FlameGraphComponent/Flamegraph.d.ts.map +1 -1
  6. package/dist/FlameGraph/FlameGraphComponent/Flamegraph_render.d.ts +15 -2
  7. package/dist/FlameGraph/FlameGraphComponent/Flamegraph_render.d.ts.map +1 -1
  8. package/dist/FlameGraph/FlameGraphComponent/Highlight.d.ts.map +1 -1
  9. package/dist/FlameGraph/FlameGraphComponent/index.d.ts.map +1 -1
  10. package/dist/FlameGraph/normalize.d.ts.map +1 -1
  11. package/dist/FlameGraph/uniqueness.d.ts.map +1 -1
  12. package/dist/Icons.d.ts.map +1 -1
  13. package/dist/ProfilerTable.d.ts.map +1 -1
  14. package/dist/SharedQueryInput.d.ts.map +1 -1
  15. package/dist/Toolbar.d.ts.map +1 -1
  16. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  17. package/dist/flamegraphRenderWorker.js +2 -0
  18. package/dist/flamegraphRenderWorker.js.map +1 -0
  19. package/dist/index.cjs.js +4 -4
  20. package/dist/index.cjs.js.map +1 -1
  21. package/dist/index.esm.js +4 -4
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/index.node.cjs.js +4 -4
  24. package/dist/index.node.cjs.js.map +1 -1
  25. package/dist/index.node.esm.js +4 -4
  26. package/dist/index.node.esm.js.map +1 -1
  27. package/dist/shims/Table.d.ts +15 -1
  28. package/dist/shims/Table.d.ts.map +1 -1
  29. package/dist/shims/Tooltip.d.ts.map +1 -1
  30. package/dist/workers/createFlamegraphRenderWorker.d.ts +2 -0
  31. package/dist/workers/createFlamegraphRenderWorker.d.ts.map +1 -0
  32. package/dist/workers/flamegraphRenderWorker.d.ts +2 -0
  33. package/dist/workers/flamegraphRenderWorker.d.ts.map +1 -0
  34. package/dist/workers/profilerTableWorker.d.ts +73 -0
  35. package/dist/workers/profilerTableWorker.d.ts.map +1 -0
  36. package/package.json +1 -1
  37. package/src/FlameGraph/FlameGraphComponent/DiffLegend.module.css +8 -2
  38. package/src/FlameGraph/FlameGraphComponent/DiffLegend.tsx +12 -1
  39. package/src/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.module.css +93 -10
  40. package/src/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.tsx +9 -4
  41. package/src/FlameGraph/FlameGraphComponent/Flamegraph.ts +33 -8
  42. package/src/FlameGraph/FlameGraphComponent/Flamegraph_render.ts +289 -85
  43. package/src/FlameGraph/FlameGraphComponent/Highlight.tsx +43 -17
  44. package/src/FlameGraph/FlameGraphComponent/index.tsx +208 -57
  45. package/src/FlameGraph/FlameGraphComponent/styles.module.scss +8 -0
  46. package/src/FlameGraph/normalize.ts +9 -7
  47. package/src/FlameGraph/uniqueness.ts +69 -59
  48. package/src/Icons.tsx +18 -9
  49. package/src/ProfilerTable.tsx +463 -33
  50. package/src/SharedQueryInput.module.scss +50 -0
  51. package/src/SharedQueryInput.tsx +18 -3
  52. package/src/Toolbar.module.scss +90 -0
  53. package/src/Toolbar.tsx +30 -16
  54. package/src/Tooltip/Tooltip.tsx +49 -16
  55. package/src/i18n.tsx +1 -1
  56. package/src/sass/_common.scss +22 -3
  57. package/src/sass/_css-variables.scss +5 -1
  58. package/src/sass/flamegraph.scss +26 -23
  59. package/src/shims/Table.module.scss +91 -13
  60. package/src/shims/Table.tsx +202 -7
  61. package/src/shims/Tooltip.module.scss +40 -0
  62. package/src/shims/Tooltip.tsx +31 -3
  63. package/src/workers/createFlamegraphRenderWorker.ts +7 -0
  64. package/src/workers/flamegraphRenderWorker.ts +198 -0
  65. package/src/workers/profilerTableWorker.ts +368 -0
@@ -128,3 +128,93 @@ $buttonHeight: 37px;
128
128
  padding: 4px;
129
129
  z-index: 1;
130
130
  }
131
+
132
+ :global([data-theme='kylin']) {
133
+ .navbar {
134
+ height: 40px;
135
+ padding: 4px 0;
136
+ background-color: transparent;
137
+ border-color: transparent;
138
+ }
139
+
140
+ .searchWrapper {
141
+ width: 180px;
142
+ }
143
+
144
+ .navbar button {
145
+ color: #595959;
146
+ }
147
+
148
+ .toggleViewButton,
149
+ .fitModeButton,
150
+ .collapseNodeButton,
151
+ .resetViewButton {
152
+ height: 28px;
153
+ width: 28px;
154
+ border: 1px solid #d9d9d9;
155
+ background-color: #ffffff;
156
+ border-radius: 4px;
157
+ }
158
+
159
+ .toggleViewButton:hover,
160
+ .fitModeButton:hover,
161
+ .collapseNodeButton:hover,
162
+ .resetViewButton:hover {
163
+ border-color: #3c7150;
164
+ color: #3c7150;
165
+ background-color: #e6f4ea;
166
+ }
167
+
168
+ .collapseNodeButton,
169
+ .resetViewButton {
170
+ background-color: #fafafa;
171
+ }
172
+
173
+ .collapseNodeButton:disabled,
174
+ .resetViewButton:disabled {
175
+ color: #bfbfbf;
176
+ border-color: #d9d9d9;
177
+ background-color: #f5f5f5;
178
+ cursor: not-allowed;
179
+ }
180
+
181
+ .toggleViewButton.selected,
182
+ .fitModeButton.selected {
183
+ background-color: #3c7150;
184
+ border-color: #3c7150;
185
+ }
186
+
187
+ .toggleViewButton.selected svg {
188
+ color: #ffffff;
189
+ }
190
+
191
+ .fitModeButton.selected svg {
192
+ color: #ffffff;
193
+ }
194
+
195
+ .toggleViewButton svg,
196
+ .fitModeButton svg,
197
+ .collapseNodeButton svg,
198
+ .resetViewButton svg {
199
+ width: 16px;
200
+ height: 16px;
201
+ }
202
+
203
+ .divider {
204
+ height: 28px;
205
+ background-color: #e5e5e5;
206
+ }
207
+
208
+ .moreButton {
209
+ height: 28px;
210
+ border: 1px solid #d9d9d9;
211
+ border-radius: 4px;
212
+ background-color: #ffffff;
213
+ }
214
+
215
+ .moreButton:hover {
216
+ border-color: #3c7150;
217
+ color: #3c7150;
218
+ background-color: #e6f4ea;
219
+ }
220
+ }
package/src/Toolbar.tsx CHANGED
@@ -7,6 +7,7 @@ import React, {
7
7
  useLayoutEffect,
8
8
  isValidElement,
9
9
  memo,
10
+ useEffect,
10
11
  } from 'react';
11
12
  import classNames from 'classnames/bind';
12
13
  import { faUndo } from '@fortawesome/free-solid-svg-icons/faUndo';
@@ -170,8 +171,21 @@ const Toolbar = memo(
170
171
  setPalette,
171
172
  }: ProfileHeaderProps) => {
172
173
  const toolbarRef = useRef<HTMLDivElement>(null);
174
+ const [isKylin, setIsKylin] = useState(false);
173
175
  const i18n = useFlamegraphI18n();
174
176
 
177
+ useEffect(() => {
178
+ const el = toolbarRef.current;
179
+ if (!el) return;
180
+ const kylinEl = el.closest(
181
+ "[data-theme='kylin'], [data-flamegraph-color-mode='kylin']"
182
+ );
183
+ setIsKylin(!!kylinEl);
184
+ }, []);
185
+
186
+ const toolbarSquareWidth = isKylin ? 32 : TOOLBAR_SQUARE_WIDTH;
187
+ const queryInputWidth = isKylin ? 220 : QUERY_INPUT_WIDTH;
188
+
175
189
  // 是否显示调色板选择器(仅在 diff 模式且有 palette 时显示)
176
190
  const showPaletteDropdown = flamegraphType === 'double' && palette && setPalette;
177
191
 
@@ -182,11 +196,11 @@ const Toolbar = memo(
182
196
  <Divider />
183
197
  </>
184
198
  ),
185
- width: TOOLBAR_SQUARE_WIDTH * 2 + DIVIDER_WIDTH,
199
+ width: toolbarSquareWidth * 2 + DIVIDER_WIDTH,
186
200
  };
187
201
  const resetItem = {
188
202
  el: <ResetView isFlamegraphDirty={isFlamegraphDirty} reset={reset} />,
189
- width: TOOLBAR_SQUARE_WIDTH,
203
+ width: toolbarSquareWidth,
190
204
  };
191
205
  const focusOnSubtree = {
192
206
  el: (
@@ -198,7 +212,7 @@ const Toolbar = memo(
198
212
  <Divider />
199
213
  </>
200
214
  ),
201
- width: TOOLBAR_SQUARE_WIDTH + DIVIDER_WIDTH,
215
+ width: toolbarSquareWidth + DIVIDER_WIDTH,
202
216
  };
203
217
 
204
218
  const viewSectionItem = enableChangingDisplay
@@ -210,7 +224,7 @@ const Toolbar = memo(
210
224
  updateView={updateView}
211
225
  />
212
226
  ),
213
- width: TOOLBAR_SQUARE_WIDTH * (flamegraphType === 'single' ? 5 : 3),
227
+ width: toolbarSquareWidth * (flamegraphType === 'single' ? 5 : 3),
214
228
  }
215
229
  : null;
216
230
  const exportDataItem = isValidElement(ExportData)
@@ -221,7 +235,7 @@ const Toolbar = memo(
221
235
  {ExportData}
222
236
  </>
223
237
  ),
224
- width: TOOLBAR_SQUARE_WIDTH + DIVIDER_WIDTH,
238
+ width: toolbarSquareWidth + DIVIDER_WIDTH,
225
239
  }
226
240
  : null;
227
241
 
@@ -261,7 +275,7 @@ const Toolbar = memo(
261
275
  {/* 左侧:搜索框 */}
262
276
  <div className={styles.searchWrapper}>
263
277
  <SharedQueryInput
264
- width={QUERY_INPUT_WIDTH}
278
+ width={queryInputWidth}
265
279
  onHighlightChange={handleSearchChange}
266
280
  highlightQuery={highlightQuery}
267
281
  sharedQuery={sharedQuery}
@@ -430,17 +444,17 @@ const getViewOptions = (
430
444
  }> =>
431
445
  flamegraphType === 'single'
432
446
  ? [
447
+ {
448
+ label: messages.viewFlamegraph,
449
+ value: 'flamegraph',
450
+ Icon: FlamegraphIcon,
451
+ },
433
452
  { label: messages.viewTable, value: 'table', Icon: TableIcon },
434
453
  {
435
454
  label: messages.viewTableAndFlamegraph,
436
455
  value: 'both',
437
456
  Icon: TablePlusFlamegraphIcon,
438
457
  },
439
- {
440
- label: messages.viewFlamegraph,
441
- value: 'flamegraph',
442
- Icon: FlamegraphIcon,
443
- },
444
458
  { label: messages.viewSandwich, value: 'sandwich', Icon: SandwichIcon },
445
459
  {
446
460
  label: messages.viewGraphviz,
@@ -449,17 +463,17 @@ const getViewOptions = (
449
463
  },
450
464
  ]
451
465
  : [
466
+ {
467
+ label: messages.viewFlamegraph,
468
+ value: 'flamegraph',
469
+ Icon: FlamegraphIcon,
470
+ },
452
471
  { label: messages.viewTable, value: 'table', Icon: TableIcon },
453
472
  {
454
473
  label: messages.viewTableAndFlamegraph,
455
474
  value: 'both',
456
475
  Icon: TablePlusFlamegraphIcon,
457
476
  },
458
- {
459
- label: messages.viewFlamegraph,
460
- value: 'flamegraph',
461
- Icon: FlamegraphIcon,
462
- },
463
477
  ];
464
478
 
465
479
  function ViewSection({
@@ -193,6 +193,8 @@ export function Tooltip({
193
193
  }: TooltipProps) {
194
194
  const tooltipRef = useRef<HTMLDivElement>(null);
195
195
  const lastPosRef = useRef<{ x: number; y: number } | null>(null);
196
+ const rafRef = useRef<number | null>(null);
197
+ const lastMeasureRef = useRef<{ w: number; h: number } | null>(null);
196
198
 
197
199
  const [content, setContent] = React.useState({
198
200
  title: {
@@ -216,22 +218,29 @@ export function Tooltip({
216
218
 
217
219
  const memoizedOnMouseMove = useCallback(
218
220
  (e: MouseEvent) => {
219
- if (!tooltipRef.current) {
220
- throw new Error('Missing tooltipElement');
221
+ if (rafRef.current) {
222
+ cancelAnimationFrame(rafRef.current);
221
223
  }
222
-
223
- // 记录最后鼠标位置(给 useLayoutEffect 二次校正用)
224
- lastPosRef.current = { x: e.clientX, y: e.clientY };
225
-
226
- // 先更新内容(tooltip 高度可能因此变化)
227
- setTooltipContent(setContent, onMouseOut, e);
228
-
229
- // 用当前已渲染的尺寸先算一次位置(内容变化后的真实尺寸会在 useLayoutEffect 再校正)
230
- const w = tooltipRef.current.clientWidth || 0;
231
- const h = tooltipRef.current.clientHeight || 0;
232
-
233
- const { left, top } = computeSafeTooltipPos(e.clientX, e.clientY, w, h);
234
- setStyle({ top, left, visibility: 'visible' });
224
+ const x = e.clientX;
225
+ const y = e.clientY;
226
+ rafRef.current = requestAnimationFrame(() => {
227
+ if (!tooltipRef.current) {
228
+ throw new Error('Missing tooltipElement');
229
+ }
230
+
231
+ // 记录最后鼠标位置(给 useLayoutEffect 二次校正用)
232
+ lastPosRef.current = { x, y };
233
+
234
+ // 先更新内容(tooltip 高度可能因此变化)
235
+ setTooltipContent(setContent, onMouseOut, e);
236
+
237
+ // 用当前已渲染的尺寸先算一次位置(内容变化后的真实尺寸会在 useLayoutEffect 再校正)
238
+ const w = tooltipRef.current.clientWidth || 0;
239
+ const h = tooltipRef.current.clientHeight || 0;
240
+
241
+ const { left, top } = computeSafeTooltipPos(x, y, w, h);
242
+ setStyle({ top, left, visibility: 'visible' });
243
+ });
235
244
  },
236
245
  [setTooltipContent]
237
246
  );
@@ -241,12 +250,23 @@ export function Tooltip({
241
250
  if (!dataSourceEl) {
242
251
  return () => { };
243
252
  }
253
+ const onMouseLeave = () => {
254
+ onMouseOut();
255
+ };
256
+ const onWindowMove = (e: MouseEvent) => {
257
+ if (!dataSourceEl.contains(e.target as Node)) {
258
+ onMouseOut();
259
+ }
260
+ };
244
261
 
245
262
  dataSourceEl.addEventListener(
246
263
  'mousemove',
247
264
  memoizedOnMouseMove as EventListener
248
265
  );
249
266
  dataSourceEl.addEventListener('mouseout', onMouseOut);
267
+ dataSourceEl.addEventListener('mouseleave', onMouseLeave);
268
+ window.addEventListener('mousemove', onWindowMove, { passive: true });
269
+ window.addEventListener('blur', onMouseLeave);
250
270
 
251
271
  return () => {
252
272
  dataSourceEl.removeEventListener(
@@ -254,6 +274,12 @@ export function Tooltip({
254
274
  memoizedOnMouseMove as EventListener
255
275
  );
256
276
  dataSourceEl.removeEventListener('mouseout', onMouseOut);
277
+ dataSourceEl.removeEventListener('mouseleave', onMouseLeave);
278
+ window.removeEventListener('mousemove', onWindowMove as EventListener);
279
+ window.removeEventListener('blur', onMouseLeave);
280
+ if (rafRef.current) {
281
+ cancelAnimationFrame(rafRef.current);
282
+ }
257
283
  };
258
284
  }, [dataSourceRef.current, memoizedOnMouseMove]);
259
285
 
@@ -265,7 +291,14 @@ export function Tooltip({
265
291
 
266
292
  const { x, y } = lastPosRef.current;
267
293
  const rect = tooltipRef.current.getBoundingClientRect();
268
- const { left, top } = computeSafeTooltipPos(x, y, rect.width, rect.height);
294
+ const w = rect.width;
295
+ const h = rect.height;
296
+ const last = lastMeasureRef.current;
297
+ if (last && Math.abs(last.w - w) < 1 && Math.abs(last.h - h) < 1) {
298
+ return;
299
+ }
300
+ lastMeasureRef.current = { w, h };
301
+ const { left, top } = computeSafeTooltipPos(x, y, w, h);
269
302
 
270
303
  setStyle((prev) => {
271
304
  if (prev && prev.left === left && prev.top === top && prev.visibility === 'visible') {
package/src/i18n.tsx CHANGED
@@ -296,7 +296,7 @@ export const zhCNMessages: FlamegraphMessages = {
296
296
  diffLegendAddedLabel: '增加 (+)',
297
297
  diffLegendSelectPalette: '选择颜色方案',
298
298
  paletteDefaultName: '默认',
299
- paletteColorBlindName: '色盲模式',
299
+ paletteColorBlindName: '色盲',
300
300
  // 调色板补充描述(中文)
301
301
  paletteDefaultDesc: '(绿色 → 红色)',
302
302
  paletteColorBlindDesc: '(蓝色 → 红色)',
@@ -131,9 +131,8 @@ tt {
131
131
  padding: 6px 10px;
132
132
  }
133
133
 
134
- tr th,
135
- tr:nth-child(2n) td {
136
- background: var(--ps-neutral-9);
134
+ thead th {
135
+ background: var(--ps-table-header-bg, var(--ps-ui-foreground, #ffffff));
137
136
  }
138
137
 
139
138
  td {
@@ -182,3 +181,23 @@ tt {
182
181
  }
183
182
  }
184
183
  }
184
+
185
+ // Kylin theme table density tweaks to match Insights UI
186
+ :global([data-theme='kylin']) {
187
+ .flamegraph-table {
188
+ font-size: 12px;
189
+ border-color: #d9d9d9;
190
+ }
191
+
192
+ .flamegraph-table th {
193
+ padding: 6px 8px;
194
+ border-left-color: #d9d9d9;
195
+ border-bottom-color: #d9d9d9;
196
+ }
197
+
198
+ .flamegraph-table td {
199
+ padding: 4px 8px;
200
+ border-left-color: #f0f0f0;
201
+ border-bottom-color: #f0f0f0;
202
+ }
203
+ }
@@ -57,6 +57,8 @@
57
57
  // 表头(使用实心背景,避免 sticky 时透出内容)
58
58
  --ps-table-header-bg: #212124;
59
59
  --ps-table-header-text: #d8d8d8;
60
+ --ps-table-sort-icon: #9a9aa0;
61
+ --ps-table-sort-icon-active: var(--ps-button-switch-bg-highlight);
60
62
 
61
63
  // 选择器
62
64
  --ps-selected-app: #df8b53;
@@ -209,6 +211,8 @@
209
211
  --ps-tooltip-header-bg: #f0f0f0;
210
212
 
211
213
  // 表头专用:完全不透明的白色
212
- --ps-table-header-bg: #ffffff;
214
+ --ps-table-header-bg: #fafafa;
213
215
  --ps-table-header-text: #000000;
216
+ --ps-table-sort-icon: #bfbfbf;
217
+ --ps-table-sort-icon-active: #5d976f;
214
218
  }
@@ -29,43 +29,41 @@ pyro-flamegraph {
29
29
 
30
30
  /* 只在差分火焰图(double)模式下启用滚动限制 */
31
31
  /* 把滚动交给 tbody,表头固定在表格上方 */
32
- .flamegraph-table-wrapper--double .flamegraph-table-scroll {
32
+ .flamegraph-table-wrapper--double {
33
+ border: 1px solid var(--ps-ui-border);
34
+ border-radius: 6px;
33
35
  overflow: hidden;
34
- position: relative;
35
- }
36
-
37
- .flamegraph-table-wrapper--double .flamegraph-table-scroll table {
38
- width: 100%;
39
- table-layout: fixed;
36
+ background-color: var(--ps-ui-foreground, #fff);
37
+ min-height: var(--kylin-flamegraph-pane-min-height, 320px);
40
38
  }
41
39
 
42
- .flamegraph-table-wrapper--double .flamegraph-table-scroll thead {
43
- display: table;
44
- width: calc(100% - var(--kylin-flamegraph-scrollbar-size, 0px));
45
- table-layout: fixed;
40
+ .flamegraph-table-wrapper--double .flamegraph-table {
41
+ border: none;
46
42
  }
47
43
 
48
- .flamegraph-table-wrapper--double .flamegraph-table-scroll tbody {
49
- display: block;
50
- max-height: var(--kylin-flamegraph-table-max-height, 1000px);
51
- overflow-y: scroll;
44
+ .flamegraph-table-wrapper--double .flamegraph-table-scroll {
52
45
  overflow-x: hidden;
53
- scrollbar-gutter: stable;
46
+ overflow-y: auto;
47
+ position: relative;
48
+ max-height: var(--kylin-flamegraph-table-max-height, 1000px);
54
49
  }
55
50
 
56
- .flamegraph-table-wrapper--double .flamegraph-table-scroll tbody tr {
57
- display: table;
51
+ .flamegraph-table-wrapper--double .flamegraph-table-scroll table {
58
52
  width: 100%;
59
53
  table-layout: fixed;
60
54
  }
61
55
 
62
- /* 表头固定 + 不透明背景,避免内容透出来 */
63
56
  .flamegraph-table-wrapper--double .flamegraph-table-scroll thead {
57
+ display: table-header-group;
64
58
  position: sticky;
65
59
  top: 0;
66
60
  z-index: 3; // 比下面的行和 tooltip 都高一点
67
61
  }
68
62
 
63
+ .flamegraph-table-wrapper--double .flamegraph-table-scroll tbody {
64
+ display: table-row-group;
65
+ }
66
+
69
67
  /* 整行都有底色,避免列间缝隙透出内容 */
70
68
  .flamegraph-table-wrapper--double .flamegraph-table-scroll thead tr {
71
69
  background-color: var(--ps-table-header-bg, var(--ps-ui-foreground, #ffffff));
@@ -85,14 +83,19 @@ pyro-flamegraph {
85
83
 
86
84
  /* 可选:稍微美化一下内部滚动条,轨道透明,避免太抢眼 */
87
85
  .flamegraph-table-wrapper--double .flamegraph-table-scroll::-webkit-scrollbar {
88
- width: 8px;
86
+ width: 6px;
89
87
  }
90
88
 
91
89
  .flamegraph-table-wrapper--double .flamegraph-table-scroll::-webkit-scrollbar-track {
92
- background: transparent;
90
+ background: #f5f5f5;
91
+ border-radius: 6px;
93
92
  }
94
93
 
95
94
  .flamegraph-table-wrapper--double .flamegraph-table-scroll::-webkit-scrollbar-thumb {
96
- background-color: rgba(0, 0, 0, 0.18);
97
- border-radius: 4px;
95
+ background-color: #bfbfbf;
96
+ border-radius: 6px;
97
+ }
98
+
99
+ .flamegraph-table-wrapper--double .flamegraph-table-scroll::-webkit-scrollbar-thumb:hover {
100
+ background-color: #8c8c8c;
98
101
  }
@@ -21,23 +21,23 @@
21
21
  top: 3px;
22
22
  position: relative;
23
23
  margin-left: 7px;
24
+ }
24
25
 
25
- &.asc {
26
- border-top-color: transparent;
27
- border-bottom-color: var(--ps-button-switch-bg-highlight);
28
- top: -2px;
29
- }
26
+ .sortArrowUp,
27
+ .sortArrowDown {
28
+ display: none;
29
+ }
30
30
 
31
- &.desc {
32
- border-top-color: var(--ps-button-switch-bg-highlight);
33
- top: 3px;
34
- }
31
+ .sortArrow.asc {
32
+ border-top-color: transparent;
33
+ border-bottom-color: var(--ps-button-switch-bg-highlight);
34
+ top: -2px;
35
35
  }
36
- }
37
36
 
38
- /* 斑马纹只应用在 tbody 行,不再影响 thead */
39
- tbody tr:nth-child(2n) {
40
- background-color: var(--ps-neutral-9);
37
+ .sortArrow.desc {
38
+ border-top-color: var(--ps-button-switch-bg-highlight);
39
+ top: 3px;
40
+ }
41
41
  }
42
42
 
43
43
  tbody {
@@ -73,6 +73,11 @@
73
73
  background: var(--ps-ui-element-bg-highlight);
74
74
  }
75
75
  }
76
+
77
+ &.virtualSpacer {
78
+ pointer-events: none;
79
+ background: transparent !important;
80
+ }
76
81
  }
77
82
 
78
83
  td,
@@ -83,6 +88,79 @@
83
88
  }
84
89
  }
85
90
 
91
+ :global([data-theme='kylin']) {
92
+ .table {
93
+ thead th {
94
+ text-align: left;
95
+ background: #fafafa;
96
+ border-color: #d9d9d9;
97
+ }
98
+
99
+ tbody td {
100
+ border-color: #f0f0f0;
101
+ }
102
+
103
+ tbody tr:not(.isRowSelected):hover {
104
+ background: #f5f5f5;
105
+ color: var(--ps-neutral-2);
106
+ }
107
+
108
+ thead th {
109
+ &.sortable {
110
+ position: relative;
111
+ padding-right: 18px;
112
+ }
113
+
114
+ .sortArrow {
115
+ display: inline-flex;
116
+ flex-direction: column;
117
+ margin-left: 6px;
118
+ line-height: 1;
119
+ border: 0;
120
+ position: absolute;
121
+ right: 6px;
122
+ top: 50%;
123
+ transform: translateY(-50%);
124
+ vertical-align: middle;
125
+ }
126
+
127
+ .sortArrowUp,
128
+ .sortArrowDown {
129
+ display: inline-block;
130
+ width: 0;
131
+ height: 0;
132
+ border-left: 4px solid transparent;
133
+ border-right: 4px solid transparent;
134
+ opacity: 0.35;
135
+ }
136
+
137
+ .sortArrowUp {
138
+ border-bottom: 5px solid var(--ps-table-sort-icon, var(--ps-ui-foreground-text));
139
+ margin-bottom: 2px;
140
+ }
141
+
142
+ .sortArrowDown {
143
+ border-top: 5px solid var(--ps-table-sort-icon, var(--ps-ui-foreground-text));
144
+ }
145
+
146
+ .sortArrow.active .sortArrowUp,
147
+ .sortArrow.active .sortArrowDown {
148
+ opacity: 0.45;
149
+ }
150
+
151
+ .sortArrow.asc .sortArrowUp {
152
+ border-bottom-color: var(--ps-table-sort-icon-active, var(--ps-button-switch-bg-highlight));
153
+ opacity: 1;
154
+ }
155
+
156
+ .sortArrow.desc .sortArrowDown {
157
+ border-top-color: var(--ps-table-sort-icon-active, var(--ps-button-switch-bg-highlight));
158
+ opacity: 1;
159
+ }
160
+ }
161
+ }
162
+ }
163
+
86
164
  .table:global(.flamegraph-table-doubles) {
87
165
  th:first-child,
88
166
  td:first-child {