@hef2024/llmasaservice-ui 0.23.2 → 0.24.0

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/dist/index.css CHANGED
@@ -1114,6 +1114,23 @@ button[data-pending=true]::after {
1114
1114
  align-items: center;
1115
1115
  gap: 8px;
1116
1116
  }
1117
+ .thinking-block__icon-wrapper {
1118
+ display: flex;
1119
+ align-items: center;
1120
+ justify-content: center;
1121
+ flex-shrink: 0;
1122
+ }
1123
+ .thinking-block__icon-wrapper--spinning {
1124
+ animation: thinkingIconSpin 1.5s linear infinite;
1125
+ }
1126
+ @keyframes thinkingIconSpin {
1127
+ from {
1128
+ transform: rotate(0deg);
1129
+ }
1130
+ to {
1131
+ transform: rotate(360deg);
1132
+ }
1133
+ }
1117
1134
  .thinking-block__icon {
1118
1135
  width: 16px;
1119
1136
  height: 16px;
@@ -1124,6 +1141,30 @@ button[data-pending=true]::after {
1124
1141
  font-weight: 600;
1125
1142
  font-size: 13px;
1126
1143
  color: var(--thinking-block-text, var(--title-text-color));
1144
+ position: relative;
1145
+ }
1146
+ .thinking-block__title--shimmer {
1147
+ background:
1148
+ linear-gradient(
1149
+ 90deg,
1150
+ var(--thinking-block-text, var(--title-text-color)) 0%,
1151
+ var(--thinking-block-text, var(--title-text-color)) 40%,
1152
+ var(--thinking-block-accent, var(--ai-chat-thinking-icon)) 50%,
1153
+ var(--thinking-block-text, var(--title-text-color)) 60%,
1154
+ var(--thinking-block-text, var(--title-text-color)) 100%);
1155
+ background-size: 200% 100%;
1156
+ -webkit-background-clip: text;
1157
+ background-clip: text;
1158
+ -webkit-text-fill-color: transparent;
1159
+ animation: titleShimmer 2s ease-in-out infinite;
1160
+ }
1161
+ @keyframes titleShimmer {
1162
+ 0% {
1163
+ background-position: 100% 0;
1164
+ }
1165
+ 100% {
1166
+ background-position: -100% 0;
1167
+ }
1127
1168
  }
1128
1169
  .thinking-block__chevron {
1129
1170
  width: 16px;
@@ -1295,6 +1336,107 @@ button[data-pending=true]::after {
1295
1336
  .thinking-block:not(.thinking-block--collapsed) {
1296
1337
  border-left-width: 3px;
1297
1338
  }
1339
+ .thinking-block--collapsed {
1340
+ margin-bottom: 4px;
1341
+ border-radius: 6px;
1342
+ border-width: 0;
1343
+ background-color: transparent;
1344
+ }
1345
+ .thinking-block--collapsed .thinking-block__header {
1346
+ padding: 4px 8px;
1347
+ }
1348
+ .thinking-block--collapsed .thinking-block__header-left {
1349
+ gap: 6px;
1350
+ flex: 1;
1351
+ min-width: 0;
1352
+ }
1353
+ .thinking-block--collapsed .thinking-block__icon-wrapper {
1354
+ flex-shrink: 0;
1355
+ }
1356
+ .thinking-block--collapsed .thinking-block__icon {
1357
+ width: 14px;
1358
+ height: 14px;
1359
+ opacity: 0.6;
1360
+ }
1361
+ .thinking-block--collapsed .thinking-block__title {
1362
+ font-size: 12px;
1363
+ font-weight: 500;
1364
+ opacity: 0.7;
1365
+ flex-shrink: 0;
1366
+ }
1367
+ .thinking-block__preview {
1368
+ font-size: 11px;
1369
+ font-weight: 400;
1370
+ opacity: 0.5;
1371
+ color: var(--thinking-block-text, var(--title-text-color));
1372
+ white-space: nowrap;
1373
+ overflow: hidden;
1374
+ text-overflow: ellipsis;
1375
+ flex: 1;
1376
+ min-width: 0;
1377
+ }
1378
+ .thinking-block--collapsed .thinking-block__chevron {
1379
+ width: 12px;
1380
+ height: 12px;
1381
+ opacity: 0.4;
1382
+ flex-shrink: 0;
1383
+ }
1384
+ .thinking-block--collapsed:hover {
1385
+ background-color: rgba(0, 0, 0, 0.04);
1386
+ }
1387
+ .thinking-block--collapsed:hover .thinking-block__icon,
1388
+ .thinking-block--collapsed:hover .thinking-block__title {
1389
+ opacity: 0.9;
1390
+ }
1391
+ .thinking-block--collapsed:hover .thinking-block__preview {
1392
+ opacity: 0.7;
1393
+ }
1394
+ .thinking-block--collapsed:hover .thinking-block__chevron {
1395
+ opacity: 0.6;
1396
+ }
1397
+ .dark-theme .thinking-block--collapsed:hover {
1398
+ background-color: rgba(255, 255, 255, 0.06);
1399
+ }
1400
+ .thinking-block:not(.thinking-block--collapsed) {
1401
+ margin-bottom: 8px;
1402
+ border-radius: 6px;
1403
+ border: none;
1404
+ background-color: transparent;
1405
+ opacity: 0.75;
1406
+ }
1407
+ .thinking-block:not(.thinking-block--collapsed):hover {
1408
+ opacity: 0.9;
1409
+ }
1410
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__header {
1411
+ padding: 4px 10px;
1412
+ }
1413
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__icon {
1414
+ width: 14px;
1415
+ height: 14px;
1416
+ opacity: 0.7;
1417
+ }
1418
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__title {
1419
+ font-size: 12px;
1420
+ opacity: 0.8;
1421
+ }
1422
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__chevron {
1423
+ opacity: 0.5;
1424
+ }
1425
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__content {
1426
+ padding: 0 10px 6px 10px;
1427
+ font-size: 11px;
1428
+ line-height: 1.5;
1429
+ opacity: 0.7;
1430
+ max-height: 120px;
1431
+ overflow-y: auto;
1432
+ }
1433
+ .thinking-block--streaming:not(.thinking-block--collapsed) {
1434
+ opacity: 0.85;
1435
+ background-color: rgba(0, 0, 0, 0.015);
1436
+ }
1437
+ .dark-theme .thinking-block--streaming:not(.thinking-block--collapsed) {
1438
+ background-color: rgba(255, 255, 255, 0.02);
1439
+ }
1298
1440
  .thinking-block {
1299
1441
  animation: thinkingBlockAppear 0.2s ease-out;
1300
1442
  }
@@ -4457,6 +4599,23 @@ button[data-pending=true]::after {
4457
4599
  align-items: center;
4458
4600
  gap: 8px;
4459
4601
  }
4602
+ .thinking-block__icon-wrapper {
4603
+ display: flex;
4604
+ align-items: center;
4605
+ justify-content: center;
4606
+ flex-shrink: 0;
4607
+ }
4608
+ .thinking-block__icon-wrapper--spinning {
4609
+ animation: thinkingIconSpin 1.5s linear infinite;
4610
+ }
4611
+ @keyframes thinkingIconSpin {
4612
+ from {
4613
+ transform: rotate(0deg);
4614
+ }
4615
+ to {
4616
+ transform: rotate(360deg);
4617
+ }
4618
+ }
4460
4619
  .thinking-block__icon {
4461
4620
  width: 16px;
4462
4621
  height: 16px;
@@ -4467,6 +4626,30 @@ button[data-pending=true]::after {
4467
4626
  font-weight: 600;
4468
4627
  font-size: 13px;
4469
4628
  color: var(--thinking-block-text, var(--ai-chat-thinking-text));
4629
+ position: relative;
4630
+ }
4631
+ .thinking-block__title--shimmer {
4632
+ background:
4633
+ linear-gradient(
4634
+ 90deg,
4635
+ var(--thinking-block-text, var(--ai-chat-thinking-text)) 0%,
4636
+ var(--thinking-block-text, var(--ai-chat-thinking-text)) 40%,
4637
+ var(--thinking-block-accent, var(--ai-chat-thinking-icon)) 50%,
4638
+ var(--thinking-block-text, var(--ai-chat-thinking-text)) 60%,
4639
+ var(--thinking-block-text, var(--ai-chat-thinking-text)) 100%);
4640
+ background-size: 200% 100%;
4641
+ -webkit-background-clip: text;
4642
+ background-clip: text;
4643
+ -webkit-text-fill-color: transparent;
4644
+ animation: titleShimmer 2s ease-in-out infinite;
4645
+ }
4646
+ @keyframes titleShimmer {
4647
+ 0% {
4648
+ background-position: 100% 0;
4649
+ }
4650
+ 100% {
4651
+ background-position: -100% 0;
4652
+ }
4470
4653
  }
4471
4654
  .thinking-block__chevron {
4472
4655
  width: 16px;
@@ -4638,6 +4821,107 @@ button[data-pending=true]::after {
4638
4821
  .thinking-block:not(.thinking-block--collapsed) {
4639
4822
  border-left-width: 3px;
4640
4823
  }
4824
+ .thinking-block--collapsed {
4825
+ margin-bottom: 4px;
4826
+ border-radius: 6px;
4827
+ border-width: 0;
4828
+ background-color: transparent;
4829
+ }
4830
+ .thinking-block--collapsed .thinking-block__header {
4831
+ padding: 4px 8px;
4832
+ }
4833
+ .thinking-block--collapsed .thinking-block__header-left {
4834
+ gap: 6px;
4835
+ flex: 1;
4836
+ min-width: 0;
4837
+ }
4838
+ .thinking-block--collapsed .thinking-block__icon-wrapper {
4839
+ flex-shrink: 0;
4840
+ }
4841
+ .thinking-block--collapsed .thinking-block__icon {
4842
+ width: 14px;
4843
+ height: 14px;
4844
+ opacity: 0.6;
4845
+ }
4846
+ .thinking-block--collapsed .thinking-block__title {
4847
+ font-size: 12px;
4848
+ font-weight: 500;
4849
+ opacity: 0.7;
4850
+ flex-shrink: 0;
4851
+ }
4852
+ .thinking-block__preview {
4853
+ font-size: 11px;
4854
+ font-weight: 400;
4855
+ opacity: 0.5;
4856
+ color: var(--thinking-block-text, var(--ai-chat-thinking-text));
4857
+ white-space: nowrap;
4858
+ overflow: hidden;
4859
+ text-overflow: ellipsis;
4860
+ flex: 1;
4861
+ min-width: 0;
4862
+ }
4863
+ .thinking-block--collapsed .thinking-block__chevron {
4864
+ width: 12px;
4865
+ height: 12px;
4866
+ opacity: 0.4;
4867
+ flex-shrink: 0;
4868
+ }
4869
+ .thinking-block--collapsed:hover {
4870
+ background-color: rgba(0, 0, 0, 0.04);
4871
+ }
4872
+ .thinking-block--collapsed:hover .thinking-block__icon,
4873
+ .thinking-block--collapsed:hover .thinking-block__title {
4874
+ opacity: 0.9;
4875
+ }
4876
+ .thinking-block--collapsed:hover .thinking-block__preview {
4877
+ opacity: 0.7;
4878
+ }
4879
+ .thinking-block--collapsed:hover .thinking-block__chevron {
4880
+ opacity: 0.6;
4881
+ }
4882
+ .dark-theme .thinking-block--collapsed:hover {
4883
+ background-color: rgba(255, 255, 255, 0.06);
4884
+ }
4885
+ .thinking-block:not(.thinking-block--collapsed) {
4886
+ margin-bottom: 8px;
4887
+ border-radius: 6px;
4888
+ border: none;
4889
+ background-color: transparent;
4890
+ opacity: 0.75;
4891
+ }
4892
+ .thinking-block:not(.thinking-block--collapsed):hover {
4893
+ opacity: 0.9;
4894
+ }
4895
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__header {
4896
+ padding: 4px 10px;
4897
+ }
4898
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__icon {
4899
+ width: 14px;
4900
+ height: 14px;
4901
+ opacity: 0.7;
4902
+ }
4903
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__title {
4904
+ font-size: 12px;
4905
+ opacity: 0.8;
4906
+ }
4907
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__chevron {
4908
+ opacity: 0.5;
4909
+ }
4910
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__content {
4911
+ padding: 0 10px 6px 10px;
4912
+ font-size: 11px;
4913
+ line-height: 1.5;
4914
+ opacity: 0.7;
4915
+ max-height: 120px;
4916
+ overflow-y: auto;
4917
+ }
4918
+ .thinking-block--streaming:not(.thinking-block--collapsed) {
4919
+ opacity: 0.85;
4920
+ background-color: rgba(0, 0, 0, 0.015);
4921
+ }
4922
+ .dark-theme .thinking-block--streaming:not(.thinking-block--collapsed) {
4923
+ background-color: rgba(255, 255, 255, 0.02);
4924
+ }
4641
4925
  .thinking-block {
4642
4926
  animation: thinkingBlockAppear 0.2s ease-out;
4643
4927
  }
package/dist/index.d.mts CHANGED
@@ -596,6 +596,11 @@ interface ThinkingBlockProps {
596
596
  /**
597
597
  * ThinkingBlock - A collapsible block for displaying thinking/reasoning/searching content
598
598
  * with streaming support. Content streams in naturally as it arrives.
599
+ *
600
+ * Features Cursor-style effects:
601
+ * - Spinning icon when streaming
602
+ * - Shimmer highlight effect on title text
603
+ * - Compact collapsed state with content preview
599
604
  */
600
605
  declare const ThinkingBlock: React__default.FC<ThinkingBlockProps>;
601
606
 
package/dist/index.d.ts CHANGED
@@ -596,6 +596,11 @@ interface ThinkingBlockProps {
596
596
  /**
597
597
  * ThinkingBlock - A collapsible block for displaying thinking/reasoning/searching content
598
598
  * with streaming support. Content streams in naturally as it arrives.
599
+ *
600
+ * Features Cursor-style effects:
601
+ * - Spinning icon when streaming
602
+ * - Shimmer highlight effect on title text
603
+ * - Compact collapsed state with content preview
599
604
  */
600
605
  declare const ThinkingBlock: React__default.FC<ThinkingBlockProps>;
601
606
 
package/dist/index.js CHANGED
@@ -668,10 +668,15 @@ var ThinkingBlock = ({
668
668
  }) => {
669
669
  const displayTitle = title || getDefaultTitle(type);
670
670
  const icon = getIcon(type);
671
+ const getPreview = (text, maxLength = 60) => {
672
+ const cleaned = text.replace(/\s+/g, " ").trim();
673
+ if (cleaned.length <= maxLength) return cleaned;
674
+ return cleaned.substring(0, maxLength).trim() + "...";
675
+ };
671
676
  return /* @__PURE__ */ import_react10.default.createElement(
672
677
  "div",
673
678
  {
674
- className: `thinking-block thinking-block--${type} ${isCollapsed ? "thinking-block--collapsed" : ""}`
679
+ className: `thinking-block thinking-block--${type} ${isCollapsed ? "thinking-block--collapsed" : ""} ${isStreaming ? "thinking-block--streaming" : ""}`
675
680
  },
676
681
  /* @__PURE__ */ import_react10.default.createElement(
677
682
  "button",
@@ -681,7 +686,7 @@ var ThinkingBlock = ({
681
686
  type: "button",
682
687
  "aria-expanded": !isCollapsed
683
688
  },
684
- /* @__PURE__ */ import_react10.default.createElement("div", { className: "thinking-block__header-left" }, icon, /* @__PURE__ */ import_react10.default.createElement("span", { className: "thinking-block__title" }, displayTitle), isStreaming && /* @__PURE__ */ import_react10.default.createElement("span", { className: "thinking-block__streaming-indicator" }, /* @__PURE__ */ import_react10.default.createElement("span", { className: "thinking-block__streaming-dot" }), /* @__PURE__ */ import_react10.default.createElement("span", { className: "thinking-block__streaming-dot" }), /* @__PURE__ */ import_react10.default.createElement("span", { className: "thinking-block__streaming-dot" }))),
689
+ /* @__PURE__ */ import_react10.default.createElement("div", { className: "thinking-block__header-left" }, /* @__PURE__ */ import_react10.default.createElement("span", { className: `thinking-block__icon-wrapper ${isStreaming ? "thinking-block__icon-wrapper--spinning" : ""}` }, icon), /* @__PURE__ */ import_react10.default.createElement("span", { className: `thinking-block__title ${isStreaming ? "thinking-block__title--shimmer" : ""}` }, displayTitle), isCollapsed && content && /* @__PURE__ */ import_react10.default.createElement("span", { className: "thinking-block__preview" }, getPreview(content))),
685
690
  /* @__PURE__ */ import_react10.default.createElement(ChevronIcon, { isCollapsed })
686
691
  ),
687
692
  /* @__PURE__ */ import_react10.default.createElement("div", { className: "thinking-block__content-wrapper" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "thinking-block__content" }, content, isStreaming && /* @__PURE__ */ import_react10.default.createElement("span", { className: "thinking-block__cursor" }, "|")))
package/dist/index.mjs CHANGED
@@ -627,10 +627,15 @@ var ThinkingBlock = ({
627
627
  }) => {
628
628
  const displayTitle = title || getDefaultTitle(type);
629
629
  const icon = getIcon(type);
630
+ const getPreview = (text, maxLength = 60) => {
631
+ const cleaned = text.replace(/\s+/g, " ").trim();
632
+ if (cleaned.length <= maxLength) return cleaned;
633
+ return cleaned.substring(0, maxLength).trim() + "...";
634
+ };
630
635
  return /* @__PURE__ */ React10.createElement(
631
636
  "div",
632
637
  {
633
- className: `thinking-block thinking-block--${type} ${isCollapsed ? "thinking-block--collapsed" : ""}`
638
+ className: `thinking-block thinking-block--${type} ${isCollapsed ? "thinking-block--collapsed" : ""} ${isStreaming ? "thinking-block--streaming" : ""}`
634
639
  },
635
640
  /* @__PURE__ */ React10.createElement(
636
641
  "button",
@@ -640,7 +645,7 @@ var ThinkingBlock = ({
640
645
  type: "button",
641
646
  "aria-expanded": !isCollapsed
642
647
  },
643
- /* @__PURE__ */ React10.createElement("div", { className: "thinking-block__header-left" }, icon, /* @__PURE__ */ React10.createElement("span", { className: "thinking-block__title" }, displayTitle), isStreaming && /* @__PURE__ */ React10.createElement("span", { className: "thinking-block__streaming-indicator" }, /* @__PURE__ */ React10.createElement("span", { className: "thinking-block__streaming-dot" }), /* @__PURE__ */ React10.createElement("span", { className: "thinking-block__streaming-dot" }), /* @__PURE__ */ React10.createElement("span", { className: "thinking-block__streaming-dot" }))),
648
+ /* @__PURE__ */ React10.createElement("div", { className: "thinking-block__header-left" }, /* @__PURE__ */ React10.createElement("span", { className: `thinking-block__icon-wrapper ${isStreaming ? "thinking-block__icon-wrapper--spinning" : ""}` }, icon), /* @__PURE__ */ React10.createElement("span", { className: `thinking-block__title ${isStreaming ? "thinking-block__title--shimmer" : ""}` }, displayTitle), isCollapsed && content && /* @__PURE__ */ React10.createElement("span", { className: "thinking-block__preview" }, getPreview(content))),
644
649
  /* @__PURE__ */ React10.createElement(ChevronIcon, { isCollapsed })
645
650
  ),
646
651
  /* @__PURE__ */ React10.createElement("div", { className: "thinking-block__content-wrapper" }, /* @__PURE__ */ React10.createElement("div", { className: "thinking-block__content" }, content, isStreaming && /* @__PURE__ */ React10.createElement("span", { className: "thinking-block__cursor" }, "|")))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hef2024/llmasaservice-ui",
3
- "version": "0.23.2",
3
+ "version": "0.24.0",
4
4
  "description": "Prebuilt UI components for LLMAsAService.io",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -2499,6 +2499,23 @@
2499
2499
  gap: 8px;
2500
2500
  }
2501
2501
 
2502
+ /* Icon Wrapper - for spinning animation */
2503
+ .thinking-block__icon-wrapper {
2504
+ display: flex;
2505
+ align-items: center;
2506
+ justify-content: center;
2507
+ flex-shrink: 0;
2508
+ }
2509
+
2510
+ .thinking-block__icon-wrapper--spinning {
2511
+ animation: thinkingIconSpin 1.5s linear infinite;
2512
+ }
2513
+
2514
+ @keyframes thinkingIconSpin {
2515
+ from { transform: rotate(0deg); }
2516
+ to { transform: rotate(360deg); }
2517
+ }
2518
+
2502
2519
  /* Icon */
2503
2520
  .thinking-block__icon {
2504
2521
  width: 16px;
@@ -2512,6 +2529,33 @@
2512
2529
  font-weight: 600;
2513
2530
  font-size: 13px;
2514
2531
  color: var(--thinking-block-text, var(--ai-chat-thinking-text));
2532
+ position: relative;
2533
+ }
2534
+
2535
+ /* Shimmer effect on title when streaming */
2536
+ .thinking-block__title--shimmer {
2537
+ background: linear-gradient(
2538
+ 90deg,
2539
+ var(--thinking-block-text, var(--ai-chat-thinking-text)) 0%,
2540
+ var(--thinking-block-text, var(--ai-chat-thinking-text)) 40%,
2541
+ var(--thinking-block-accent, var(--ai-chat-thinking-icon)) 50%,
2542
+ var(--thinking-block-text, var(--ai-chat-thinking-text)) 60%,
2543
+ var(--thinking-block-text, var(--ai-chat-thinking-text)) 100%
2544
+ );
2545
+ background-size: 200% 100%;
2546
+ -webkit-background-clip: text;
2547
+ background-clip: text;
2548
+ -webkit-text-fill-color: transparent;
2549
+ animation: titleShimmer 2s ease-in-out infinite;
2550
+ }
2551
+
2552
+ @keyframes titleShimmer {
2553
+ 0% {
2554
+ background-position: 100% 0;
2555
+ }
2556
+ 100% {
2557
+ background-position: -100% 0;
2558
+ }
2515
2559
  }
2516
2560
 
2517
2561
  /* Chevron (collapse indicator) */
@@ -2703,6 +2747,140 @@
2703
2747
  border-left-width: 3px;
2704
2748
  }
2705
2749
 
2750
+ /* ============================================================================
2751
+ Collapsed State - Compact Line Style with Preview
2752
+ ============================================================================ */
2753
+
2754
+ .thinking-block--collapsed {
2755
+ margin-bottom: 4px;
2756
+ border-radius: 6px;
2757
+ border-width: 0;
2758
+ background-color: transparent;
2759
+ }
2760
+
2761
+ .thinking-block--collapsed .thinking-block__header {
2762
+ padding: 4px 8px;
2763
+ }
2764
+
2765
+ .thinking-block--collapsed .thinking-block__header-left {
2766
+ gap: 6px;
2767
+ flex: 1;
2768
+ min-width: 0;
2769
+ }
2770
+
2771
+ .thinking-block--collapsed .thinking-block__icon-wrapper {
2772
+ flex-shrink: 0;
2773
+ }
2774
+
2775
+ .thinking-block--collapsed .thinking-block__icon {
2776
+ width: 14px;
2777
+ height: 14px;
2778
+ opacity: 0.6;
2779
+ }
2780
+
2781
+ .thinking-block--collapsed .thinking-block__title {
2782
+ font-size: 12px;
2783
+ font-weight: 500;
2784
+ opacity: 0.7;
2785
+ flex-shrink: 0;
2786
+ }
2787
+
2788
+ /* Preview text in collapsed state */
2789
+ .thinking-block__preview {
2790
+ font-size: 11px;
2791
+ font-weight: 400;
2792
+ opacity: 0.5;
2793
+ color: var(--thinking-block-text, var(--ai-chat-thinking-text));
2794
+ white-space: nowrap;
2795
+ overflow: hidden;
2796
+ text-overflow: ellipsis;
2797
+ flex: 1;
2798
+ min-width: 0;
2799
+ }
2800
+
2801
+ .thinking-block--collapsed .thinking-block__chevron {
2802
+ width: 12px;
2803
+ height: 12px;
2804
+ opacity: 0.4;
2805
+ flex-shrink: 0;
2806
+ }
2807
+
2808
+ /* Hover state for collapsed - subtle highlight */
2809
+ .thinking-block--collapsed:hover {
2810
+ background-color: rgba(0, 0, 0, 0.04);
2811
+ }
2812
+
2813
+ .thinking-block--collapsed:hover .thinking-block__icon,
2814
+ .thinking-block--collapsed:hover .thinking-block__title {
2815
+ opacity: 0.9;
2816
+ }
2817
+
2818
+ .thinking-block--collapsed:hover .thinking-block__preview {
2819
+ opacity: 0.7;
2820
+ }
2821
+
2822
+ .thinking-block--collapsed:hover .thinking-block__chevron {
2823
+ opacity: 0.6;
2824
+ }
2825
+
2826
+ .dark-theme .thinking-block--collapsed:hover {
2827
+ background-color: rgba(255, 255, 255, 0.06);
2828
+ }
2829
+
2830
+ /* ============================================================================
2831
+ Expanded State - Subtle, Transient Content
2832
+ ============================================================================ */
2833
+
2834
+ .thinking-block:not(.thinking-block--collapsed) {
2835
+ margin-bottom: 8px;
2836
+ border-radius: 6px;
2837
+ border: none;
2838
+ background-color: transparent;
2839
+ opacity: 0.75;
2840
+ }
2841
+
2842
+ .thinking-block:not(.thinking-block--collapsed):hover {
2843
+ opacity: 0.9;
2844
+ }
2845
+
2846
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__header {
2847
+ padding: 4px 10px;
2848
+ }
2849
+
2850
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__icon {
2851
+ width: 14px;
2852
+ height: 14px;
2853
+ opacity: 0.7;
2854
+ }
2855
+
2856
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__title {
2857
+ font-size: 12px;
2858
+ opacity: 0.8;
2859
+ }
2860
+
2861
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__chevron {
2862
+ opacity: 0.5;
2863
+ }
2864
+
2865
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__content {
2866
+ padding: 0 10px 6px 10px;
2867
+ font-size: 11px;
2868
+ line-height: 1.5;
2869
+ opacity: 0.7;
2870
+ max-height: 120px;
2871
+ overflow-y: auto;
2872
+ }
2873
+
2874
+ /* Streaming state gets slightly more presence */
2875
+ .thinking-block--streaming:not(.thinking-block--collapsed) {
2876
+ opacity: 0.85;
2877
+ background-color: rgba(0, 0, 0, 0.015);
2878
+ }
2879
+
2880
+ .dark-theme .thinking-block--streaming:not(.thinking-block--collapsed) {
2881
+ background-color: rgba(255, 255, 255, 0.02);
2882
+ }
2883
+
2706
2884
  /* Animation when block first appears */
2707
2885
  .thinking-block {
2708
2886
  animation: thinkingBlockAppear 0.2s ease-out;
package/src/ChatPanel.css CHANGED
@@ -1359,6 +1359,23 @@ button[data-pending="true"]::after {
1359
1359
  gap: 8px;
1360
1360
  }
1361
1361
 
1362
+ /* Icon Wrapper - for spinning animation */
1363
+ .thinking-block__icon-wrapper {
1364
+ display: flex;
1365
+ align-items: center;
1366
+ justify-content: center;
1367
+ flex-shrink: 0;
1368
+ }
1369
+
1370
+ .thinking-block__icon-wrapper--spinning {
1371
+ animation: thinkingIconSpin 1.5s linear infinite;
1372
+ }
1373
+
1374
+ @keyframes thinkingIconSpin {
1375
+ from { transform: rotate(0deg); }
1376
+ to { transform: rotate(360deg); }
1377
+ }
1378
+
1362
1379
  /* Icon */
1363
1380
  .thinking-block__icon {
1364
1381
  width: 16px;
@@ -1372,6 +1389,33 @@ button[data-pending="true"]::after {
1372
1389
  font-weight: 600;
1373
1390
  font-size: 13px;
1374
1391
  color: var(--thinking-block-text, var(--title-text-color));
1392
+ position: relative;
1393
+ }
1394
+
1395
+ /* Shimmer effect on title when streaming */
1396
+ .thinking-block__title--shimmer {
1397
+ background: linear-gradient(
1398
+ 90deg,
1399
+ var(--thinking-block-text, var(--title-text-color)) 0%,
1400
+ var(--thinking-block-text, var(--title-text-color)) 40%,
1401
+ var(--thinking-block-accent, var(--ai-chat-thinking-icon)) 50%,
1402
+ var(--thinking-block-text, var(--title-text-color)) 60%,
1403
+ var(--thinking-block-text, var(--title-text-color)) 100%
1404
+ );
1405
+ background-size: 200% 100%;
1406
+ -webkit-background-clip: text;
1407
+ background-clip: text;
1408
+ -webkit-text-fill-color: transparent;
1409
+ animation: titleShimmer 2s ease-in-out infinite;
1410
+ }
1411
+
1412
+ @keyframes titleShimmer {
1413
+ 0% {
1414
+ background-position: 100% 0;
1415
+ }
1416
+ 100% {
1417
+ background-position: -100% 0;
1418
+ }
1375
1419
  }
1376
1420
 
1377
1421
  /* Chevron (collapse indicator) */
@@ -1563,6 +1607,140 @@ button[data-pending="true"]::after {
1563
1607
  border-left-width: 3px;
1564
1608
  }
1565
1609
 
1610
+ /* ============================================================================
1611
+ Collapsed State - Compact Line Style with Preview
1612
+ ============================================================================ */
1613
+
1614
+ .thinking-block--collapsed {
1615
+ margin-bottom: 4px;
1616
+ border-radius: 6px;
1617
+ border-width: 0;
1618
+ background-color: transparent;
1619
+ }
1620
+
1621
+ .thinking-block--collapsed .thinking-block__header {
1622
+ padding: 4px 8px;
1623
+ }
1624
+
1625
+ .thinking-block--collapsed .thinking-block__header-left {
1626
+ gap: 6px;
1627
+ flex: 1;
1628
+ min-width: 0;
1629
+ }
1630
+
1631
+ .thinking-block--collapsed .thinking-block__icon-wrapper {
1632
+ flex-shrink: 0;
1633
+ }
1634
+
1635
+ .thinking-block--collapsed .thinking-block__icon {
1636
+ width: 14px;
1637
+ height: 14px;
1638
+ opacity: 0.6;
1639
+ }
1640
+
1641
+ .thinking-block--collapsed .thinking-block__title {
1642
+ font-size: 12px;
1643
+ font-weight: 500;
1644
+ opacity: 0.7;
1645
+ flex-shrink: 0;
1646
+ }
1647
+
1648
+ /* Preview text in collapsed state */
1649
+ .thinking-block__preview {
1650
+ font-size: 11px;
1651
+ font-weight: 400;
1652
+ opacity: 0.5;
1653
+ color: var(--thinking-block-text, var(--title-text-color));
1654
+ white-space: nowrap;
1655
+ overflow: hidden;
1656
+ text-overflow: ellipsis;
1657
+ flex: 1;
1658
+ min-width: 0;
1659
+ }
1660
+
1661
+ .thinking-block--collapsed .thinking-block__chevron {
1662
+ width: 12px;
1663
+ height: 12px;
1664
+ opacity: 0.4;
1665
+ flex-shrink: 0;
1666
+ }
1667
+
1668
+ /* Hover state for collapsed - subtle highlight */
1669
+ .thinking-block--collapsed:hover {
1670
+ background-color: rgba(0, 0, 0, 0.04);
1671
+ }
1672
+
1673
+ .thinking-block--collapsed:hover .thinking-block__icon,
1674
+ .thinking-block--collapsed:hover .thinking-block__title {
1675
+ opacity: 0.9;
1676
+ }
1677
+
1678
+ .thinking-block--collapsed:hover .thinking-block__preview {
1679
+ opacity: 0.7;
1680
+ }
1681
+
1682
+ .thinking-block--collapsed:hover .thinking-block__chevron {
1683
+ opacity: 0.6;
1684
+ }
1685
+
1686
+ .dark-theme .thinking-block--collapsed:hover {
1687
+ background-color: rgba(255, 255, 255, 0.06);
1688
+ }
1689
+
1690
+ /* ============================================================================
1691
+ Expanded State - Subtle, Transient Content
1692
+ ============================================================================ */
1693
+
1694
+ .thinking-block:not(.thinking-block--collapsed) {
1695
+ margin-bottom: 8px;
1696
+ border-radius: 6px;
1697
+ border: none;
1698
+ background-color: transparent;
1699
+ opacity: 0.75;
1700
+ }
1701
+
1702
+ .thinking-block:not(.thinking-block--collapsed):hover {
1703
+ opacity: 0.9;
1704
+ }
1705
+
1706
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__header {
1707
+ padding: 4px 10px;
1708
+ }
1709
+
1710
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__icon {
1711
+ width: 14px;
1712
+ height: 14px;
1713
+ opacity: 0.7;
1714
+ }
1715
+
1716
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__title {
1717
+ font-size: 12px;
1718
+ opacity: 0.8;
1719
+ }
1720
+
1721
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__chevron {
1722
+ opacity: 0.5;
1723
+ }
1724
+
1725
+ .thinking-block:not(.thinking-block--collapsed) .thinking-block__content {
1726
+ padding: 0 10px 6px 10px;
1727
+ font-size: 11px;
1728
+ line-height: 1.5;
1729
+ opacity: 0.7;
1730
+ max-height: 120px;
1731
+ overflow-y: auto;
1732
+ }
1733
+
1734
+ /* Streaming state gets slightly more presence */
1735
+ .thinking-block--streaming:not(.thinking-block--collapsed) {
1736
+ opacity: 0.85;
1737
+ background-color: rgba(0, 0, 0, 0.015);
1738
+ }
1739
+
1740
+ .dark-theme .thinking-block--streaming:not(.thinking-block--collapsed) {
1741
+ background-color: rgba(255, 255, 255, 0.02);
1742
+ }
1743
+
1566
1744
  /* Animation when block first appears */
1567
1745
  .thinking-block {
1568
1746
  animation: thinkingBlockAppear 0.2s ease-out;
@@ -102,6 +102,11 @@ const getDefaultTitle = (type: ThinkingBlockType): string => {
102
102
  /**
103
103
  * ThinkingBlock - A collapsible block for displaying thinking/reasoning/searching content
104
104
  * with streaming support. Content streams in naturally as it arrives.
105
+ *
106
+ * Features Cursor-style effects:
107
+ * - Spinning icon when streaming
108
+ * - Shimmer highlight effect on title text
109
+ * - Compact collapsed state with content preview
105
110
  */
106
111
  export const ThinkingBlock: React.FC<ThinkingBlockProps> = ({
107
112
  type,
@@ -113,10 +118,17 @@ export const ThinkingBlock: React.FC<ThinkingBlockProps> = ({
113
118
  }) => {
114
119
  const displayTitle = title || getDefaultTitle(type);
115
120
  const icon = getIcon(type);
121
+
122
+ // Create a truncated preview for collapsed state
123
+ const getPreview = (text: string, maxLength: number = 60): string => {
124
+ const cleaned = text.replace(/\s+/g, ' ').trim();
125
+ if (cleaned.length <= maxLength) return cleaned;
126
+ return cleaned.substring(0, maxLength).trim() + '...';
127
+ };
116
128
 
117
129
  return (
118
130
  <div
119
- className={`thinking-block thinking-block--${type} ${isCollapsed ? 'thinking-block--collapsed' : ''}`}
131
+ className={`thinking-block thinking-block--${type} ${isCollapsed ? 'thinking-block--collapsed' : ''} ${isStreaming ? 'thinking-block--streaming' : ''}`}
120
132
  >
121
133
  <button
122
134
  className="thinking-block__header"
@@ -125,13 +137,15 @@ export const ThinkingBlock: React.FC<ThinkingBlockProps> = ({
125
137
  aria-expanded={!isCollapsed}
126
138
  >
127
139
  <div className="thinking-block__header-left">
128
- {icon}
129
- <span className="thinking-block__title">{displayTitle}</span>
130
- {isStreaming && (
131
- <span className="thinking-block__streaming-indicator">
132
- <span className="thinking-block__streaming-dot" />
133
- <span className="thinking-block__streaming-dot" />
134
- <span className="thinking-block__streaming-dot" />
140
+ <span className={`thinking-block__icon-wrapper ${isStreaming ? 'thinking-block__icon-wrapper--spinning' : ''}`}>
141
+ {icon}
142
+ </span>
143
+ <span className={`thinking-block__title ${isStreaming ? 'thinking-block__title--shimmer' : ''}`}>
144
+ {displayTitle}
145
+ </span>
146
+ {isCollapsed && content && (
147
+ <span className="thinking-block__preview">
148
+ {getPreview(content)}
135
149
  </span>
136
150
  )}
137
151
  </div>