@youtyan/code-viewer 0.2.8 → 0.2.9

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/web/style.css CHANGED
@@ -958,13 +958,21 @@ body[data-code-font-size="xlarge"] { --code-font-size: 15px; }
958
958
  100% { transform: translateX(450%); }
959
959
  }
960
960
 
961
- /* ===== Change notification banner ===== */
962
- #change-banner {
961
+ /* ===== Notification banners (change + watch-limit) ===== */
962
+ #banner-stack {
963
963
  position: fixed;
964
964
  right: 16px;
965
965
  bottom: 16px;
966
966
  z-index: 80;
967
967
  display: flex;
968
+ flex-direction: column-reverse;
969
+ align-items: flex-end;
970
+ gap: 10px;
971
+ pointer-events: none;
972
+ }
973
+ .gdp-banner {
974
+ pointer-events: auto;
975
+ display: flex;
968
976
  align-items: center;
969
977
  gap: 10px;
970
978
  width: max-content;
@@ -978,12 +986,16 @@ body[data-code-font-size="xlarge"] { --code-font-size: 15px; }
978
986
  color: var(--fg);
979
987
  animation: gdp-banner-slide 0.2s ease;
980
988
  }
981
- #change-banner[hidden] { display: none; }
989
+ .gdp-banner[hidden] { display: none; }
990
+ .gdp-banner--warn {
991
+ background: var(--bg-soft);
992
+ border-color: var(--attn);
993
+ }
982
994
  @keyframes gdp-banner-slide {
983
995
  from { opacity: 0; transform: translateY(8px); }
984
996
  to { opacity: 1; transform: translateY(0); }
985
997
  }
986
- #change-banner-copy {
998
+ .gdp-banner-copy {
987
999
  display: grid;
988
1000
  gap: 2px;
989
1001
  min-width: 0;
@@ -999,6 +1011,9 @@ body[data-code-font-size="xlarge"] { --code-font-size: 15px; }
999
1011
  font-size: 12px;
1000
1012
  white-space: nowrap;
1001
1013
  }
1014
+ #watch-limit-text {
1015
+ font-weight: 600;
1016
+ }
1002
1017
  #change-banner-reload {
1003
1018
  flex: 0 0 auto;
1004
1019
  min-height: 30px;
@@ -1012,7 +1027,7 @@ body[data-code-font-size="xlarge"] { --code-font-size: 15px; }
1012
1027
  white-space: nowrap;
1013
1028
  }
1014
1029
  #change-banner-reload:hover { background: var(--accent-emph); }
1015
- #change-banner-dismiss {
1030
+ .gdp-banner-dismiss {
1016
1031
  flex: 0 0 auto;
1017
1032
  width: 30px;
1018
1033
  height: 30px;
@@ -1024,7 +1039,7 @@ body[data-code-font-size="xlarge"] { --code-font-size: 15px; }
1024
1039
  cursor: pointer;
1025
1040
  line-height: 1;
1026
1041
  }
1027
- #change-banner-dismiss:hover { color: var(--fg); }
1042
+ .gdp-banner-dismiss:hover { color: var(--fg); }
1028
1043
 
1029
1044
  /* ===== Commit history panel ===== */
1030
1045
  #history-panel {
@@ -1720,6 +1735,29 @@ body.gdp-history-resizing * {
1720
1735
  gap: 8px;
1721
1736
  margin-top: 10px;
1722
1737
  }
1738
+ .scope-settings-toggle {
1739
+ display: flex;
1740
+ align-items: center;
1741
+ gap: 8px;
1742
+ margin-top: 4px;
1743
+ cursor: pointer;
1744
+ }
1745
+ .scope-settings-toggle input[type="checkbox"] {
1746
+ margin: 0;
1747
+ }
1748
+ .scope-settings-footer {
1749
+ display: flex;
1750
+ align-items: center;
1751
+ justify-content: space-between;
1752
+ gap: 12px;
1753
+ margin-top: 12px;
1754
+ padding-top: 10px;
1755
+ border-top: 1px solid var(--border);
1756
+ }
1757
+ .scope-settings-footer .scope-settings-help {
1758
+ margin: 0;
1759
+ flex: 1;
1760
+ }
1723
1761
  .scope-settings-actions button {
1724
1762
  border: 1px solid var(--border);
1725
1763
  border-radius: 6px;
@@ -5470,6 +5508,66 @@ body[data-sidebar-font-size="xlarge"] .db-container {
5470
5508
  .db-icon-toolbar[hidden] {
5471
5509
  display: none !important;
5472
5510
  }
5511
+
5512
+ /* sidebar の設定トグル行。dbToolbar 直下に並ぶ。複数トグルを横に並べる
5513
+ 想定なので flex-wrap で折り返し。 */
5514
+ .db-prefs-bar {
5515
+ display: flex;
5516
+ flex-wrap: wrap;
5517
+ gap: 6px;
5518
+ padding: 6px 8px;
5519
+ border-bottom: 1px solid var(--border);
5520
+ background: var(--bg-soft);
5521
+ }
5522
+ .db-prefs-bar[hidden] {
5523
+ display: none;
5524
+ }
5525
+ /* ラベル付きピル形式の永続化トグル (Rails FK 推測など)。active 時は
5526
+ accent 色のチントで「ON」が一目で分かるようにする。 */
5527
+ .db-pref-toggle {
5528
+ display: inline-flex;
5529
+ align-items: center;
5530
+ gap: 6px;
5531
+ padding: 3px 8px;
5532
+ border: 1px solid var(--border);
5533
+ border-radius: 999px;
5534
+ background: var(--bg);
5535
+ color: var(--fg-muted);
5536
+ cursor: pointer;
5537
+ font-size: var(--db-font-sm);
5538
+ }
5539
+ .db-pref-toggle:hover {
5540
+ background: var(--bg-hover, var(--bg-soft));
5541
+ }
5542
+ .db-pref-toggle.active {
5543
+ border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
5544
+ color: var(--accent);
5545
+ background: color-mix(in srgb, var(--accent) 12%, var(--bg));
5546
+ }
5547
+ .db-pref-toggle svg {
5548
+ flex: 0 0 auto;
5549
+ }
5550
+ .db-pref-toggle-label {
5551
+ white-space: nowrap;
5552
+ }
5553
+
5554
+ /* 推測 FK は実 FK と区別。関連パネルのリスト項目に淡いマーカーを乗せる。 */
5555
+ .db-related-list-inferred {
5556
+ background: color-mix(in srgb, var(--attn, var(--accent)) 6%, transparent);
5557
+ }
5558
+ .db-related-list-inferred-badge {
5559
+ display: inline-block;
5560
+ margin-left: 6px;
5561
+ padding: 0 5px;
5562
+ border-radius: 4px;
5563
+ background: color-mix(in srgb, var(--attn, var(--accent)) 18%, var(--bg));
5564
+ color: var(--attn, var(--accent));
5565
+ font-size: 9px;
5566
+ font-weight: 600;
5567
+ letter-spacing: 0.04em;
5568
+ text-transform: uppercase;
5569
+ vertical-align: middle;
5570
+ }
5473
5571
  .db-icon-btn {
5474
5572
  display: inline-flex;
5475
5573
  align-items: center;
@@ -5607,6 +5705,35 @@ body[data-sidebar-font-size="xlarge"] .db-container {
5607
5705
  border-bottom: 1px solid var(--border);
5608
5706
  }
5609
5707
 
5708
+ /* explorer (redis/es/s3) の第1階層セレクタ (Databases / Indices / Bucket+View)
5709
+ を抱える sidebar 内 host。kind が SQL のときは中身が全て hidden になるため
5710
+ 高さが潰れて見えなくなる (table list が下に詰まる)。
5711
+ redis/es/s3 のときは hidden 子要素を 1 つだけ表示し、その slot が sidebar
5712
+ の残り高さを全て取れるよう host 自身も flex:1 にする。 */
5713
+ .db-explorer-sidebar-host {
5714
+ flex: 1 1 auto;
5715
+ min-height: 0;
5716
+ display: flex;
5717
+ flex-direction: column;
5718
+ overflow: hidden;
5719
+ }
5720
+ /* author 側 display:flex が UA の [hidden]→display:none を上書きしてしまう
5721
+ ため、明示で潰す。SQL kind 時はこの host を畳んで tableList を上に詰める。 */
5722
+ .db-explorer-sidebar-host[hidden] {
5723
+ display: none;
5724
+ }
5725
+ .db-explorer-sidebar-slot {
5726
+ flex: 1 1 auto;
5727
+ min-height: 0;
5728
+ border-bottom: 1px solid var(--border);
5729
+ display: flex;
5730
+ flex-direction: column;
5731
+ overflow: hidden;
5732
+ }
5733
+ .db-explorer-sidebar-slot[hidden] {
5734
+ display: none;
5735
+ }
5736
+
5610
5737
  .db-file-select {
5611
5738
  width: 100%;
5612
5739
  padding: 5px 24px 5px 8px;
@@ -6381,18 +6508,41 @@ html[data-theme="dark"] .db-query-highlight span[style] {
6381
6508
  max-width: none !important;
6382
6509
  }
6383
6510
 
6511
+ /* 現在フッタ/関連パネルに表示している値の元セル。スクロール後も維持するため
6512
+ render 時に state からクラスが再付与される。selected 行 + active 列で
6513
+ 二重に強調する。border-left を残しつつ accent 色のリング。 */
6514
+ .db-grid-cell.db-grid-cell-active {
6515
+ background: color-mix(in srgb, var(--accent) 22%, var(--bg));
6516
+ box-shadow: inset 0 0 0 2px var(--accent);
6517
+ color: var(--fg);
6518
+ }
6519
+ .db-grid-cell.db-grid-cell-active.null,
6520
+ .db-grid-cell.db-grid-cell-active.empty,
6521
+ .db-grid-cell.db-grid-cell-active.blob {
6522
+ /* 空状態でも視認できるよう色だけ上書きしない (fg-muted) → 通常 fg。 */
6523
+ color: var(--fg);
6524
+ }
6525
+
6384
6526
  /* ---------- Cell Detail Panel ---------- */
6385
6527
  .db-grid-detail-panel[hidden] {
6386
6528
  display: none !important;
6387
6529
  }
6388
6530
 
6389
6531
  .db-grid-detail-panel {
6532
+ position: relative;
6390
6533
  border-top: 1px solid var(--border);
6391
6534
  background: var(--bg-soft);
6392
- max-height: 200px;
6535
+ /* 高さは JS から style.height で設定 (永続化対応)。default 200px
6536
+ min-height は table-grid.ts の DETAIL_PANEL_MIN_HEIGHT と揃える
6537
+ (40 → 40)。CSS 側を緩めにしておくと、ユーザーが 40px まで縮めた
6538
+ のに描画は 80px のまま、永続化値と表示が食い違う回帰になる。 */
6539
+ height: 200px;
6540
+ min-height: 40px;
6393
6541
  overflow: auto;
6394
6542
  flex-shrink: 0;
6395
6543
  }
6544
+ /* 上端のドラッグハンドル: detail フッタと関連パネルで共通。
6545
+ .db-related-resize と同じセレクタ規則を共有する。 */
6396
6546
 
6397
6547
  .db-grid-detail-header {
6398
6548
  display: flex;
@@ -6452,99 +6602,366 @@ html[data-theme="dark"] .db-query-highlight span[style] {
6452
6602
  word-break: break-word;
6453
6603
  }
6454
6604
 
6455
- /* ---------- Export Buttons ---------- */
6456
- .db-grid-export-btn {
6457
- margin-left: 6px;
6605
+ /* ---------- Foreign-key related data ---------- */
6606
+ .db-grid-header-fk-icon {
6607
+ margin-left: 4px;
6608
+ font-size: 10px;
6609
+ opacity: 0.7;
6458
6610
  }
6459
6611
 
6460
- /* ---------- Query History ---------- */
6461
- .db-query-history-btn {
6462
- border-radius: 6px;
6612
+ .db-grid-cell-fk {
6613
+ color: var(--accent, var(--link, #2563eb));
6614
+ }
6615
+ .db-grid-cell-fk:hover {
6616
+ text-decoration: underline;
6463
6617
  }
6464
6618
 
6465
- .db-query-history-dropdown[hidden] {
6619
+ /* Related-data panel: 下部に出る「左=関連テーブル一覧 / 右=データグリッド」 */
6620
+ .db-related-panel[hidden] {
6466
6621
  display: none !important;
6467
6622
  }
6468
6623
 
6469
- .db-query-history-dropdown {
6624
+ .db-related-panel {
6625
+ position: relative;
6626
+ display: flex;
6627
+ flex-direction: column;
6628
+ flex-shrink: 0;
6629
+ border-top: 2px solid var(--border);
6630
+ background: var(--bg-soft);
6631
+ overflow: hidden;
6632
+ }
6633
+
6634
+ .db-related-resize,
6635
+ .db-grid-detail-resize {
6470
6636
  position: absolute;
6471
- z-index: 10;
6472
- top: 100%;
6637
+ top: 0;
6473
6638
  left: 0;
6474
6639
  right: 0;
6475
- max-height: 250px;
6476
- overflow-y: auto;
6477
- background: var(--bg);
6478
- border: 1px solid var(--border);
6479
- border-radius: 6px;
6480
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
6481
- margin-top: 4px;
6640
+ height: 6px;
6641
+ cursor: row-resize;
6642
+ z-index: 2;
6643
+ }
6644
+ .db-related-resize:hover,
6645
+ .db-grid-detail-resize:hover {
6646
+ background: var(--accent, var(--border));
6647
+ opacity: 0.4;
6482
6648
  }
6483
6649
 
6484
- .db-query-history-item {
6485
- padding: 6px 12px;
6486
- font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
6487
- font-size: var(--db-font-base);
6488
- cursor: pointer;
6489
- white-space: nowrap;
6490
- overflow: hidden;
6491
- text-overflow: ellipsis;
6650
+ .db-related-header {
6651
+ display: flex;
6652
+ align-items: center;
6653
+ gap: 4px;
6654
+ padding: 4px 8px;
6655
+ background: var(--bg-mute);
6492
6656
  border-bottom: 1px solid var(--border);
6657
+ font-size: var(--db-font-base);
6658
+ font-weight: 600;
6493
6659
  }
6494
- .db-query-history-item:last-child {
6495
- border-bottom: none;
6496
- }
6497
- .db-query-history-item:hover {
6498
- background: var(--accent-subtle);
6660
+
6661
+ .db-related-title {
6662
+ flex-shrink: 0;
6663
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
6499
6664
  }
6500
6665
 
6501
- .db-query-history-empty {
6502
- padding: 12px;
6666
+ .db-related-close {
6667
+ font-size: 14px;
6503
6668
  color: var(--fg-muted);
6504
- text-align: center;
6505
- font-size: var(--db-font-base);
6669
+ }
6670
+ .db-related-close:hover {
6671
+ color: var(--danger);
6672
+ background: none;
6506
6673
  }
6507
6674
 
6508
- /* ---------- Explain Button ---------- */
6509
- .db-query-explain {
6675
+ .db-related-body {
6676
+ display: flex;
6677
+ flex: 1;
6678
+ min-height: 0;
6679
+ }
6680
+
6681
+ .db-related-list {
6682
+ width: 200px;
6683
+ flex-shrink: 0;
6684
+ overflow: auto;
6685
+ border-right: 1px solid var(--border);
6686
+ padding: 4px;
6687
+ }
6688
+
6689
+ .db-related-list-item {
6690
+ display: flex;
6691
+ flex-direction: column;
6692
+ align-items: flex-start;
6693
+ gap: 1px;
6694
+ width: 100%;
6695
+ padding: 5px 8px;
6696
+ margin-bottom: 2px;
6697
+ border: 1px solid transparent;
6698
+ border-radius: 4px;
6699
+ background: none;
6700
+ text-align: left;
6701
+ cursor: pointer;
6702
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
6703
+ }
6704
+ .db-related-list-item:hover {
6705
+ background: var(--bg-mute);
6706
+ }
6707
+ .db-related-list-item.active {
6510
6708
  background: var(--bg-mute);
6709
+ border-color: var(--accent, var(--border));
6710
+ }
6711
+
6712
+ .db-related-list-name {
6713
+ font-size: var(--db-font-base);
6714
+ font-weight: 600;
6511
6715
  color: var(--fg);
6512
- border: 1px solid var(--border);
6716
+ display: inline-flex;
6717
+ align-items: baseline;
6718
+ gap: 6px;
6513
6719
  }
6514
- .db-query-explain:hover {
6515
- background: var(--bg-soft);
6720
+ /* 方向アイコンを name の前に出す: outgoing は → (自分→他テーブル)、
6721
+ incoming は ← (他テーブル→自分の PK)。テキスト 1 文字なのでフォントに
6722
+ 影響されず軽量。 */
6723
+ .db-related-list-name::before {
6724
+ flex: 0 0 auto;
6725
+ font-size: 11px;
6726
+ font-weight: 500;
6727
+ color: var(--fg-muted);
6728
+ }
6729
+ .db-related-list-outgoing .db-related-list-name::before {
6730
+ content: "→";
6731
+ }
6732
+ .db-related-list-incoming .db-related-list-name::before {
6733
+ content: "←";
6516
6734
  }
6517
6735
 
6518
- /* ---------- Query Input (relative positioning for history dropdown) ---------- */
6519
- .db-query-input {
6736
+ .db-related-list-via {
6737
+ font-size: 11px;
6738
+ color: var(--fg-muted);
6739
+ word-break: break-all;
6740
+ }
6741
+
6742
+ .db-related-grid-host {
6520
6743
  position: relative;
6744
+ display: flex;
6745
+ flex: 1;
6746
+ min-width: 0;
6747
+ overflow: hidden;
6521
6748
  }
6522
6749
 
6523
- /* ---------- Column Resize Handle ---------- */
6524
- .db-grid-resize-handle {
6750
+ .db-related-empty[hidden] {
6751
+ display: none !important;
6752
+ }
6753
+ .db-related-empty {
6525
6754
  position: absolute;
6526
- right: 0;
6527
- top: 0;
6528
- bottom: 0;
6529
- width: 6px;
6530
- cursor: col-resize;
6531
- background: transparent;
6755
+ inset: 0;
6532
6756
  z-index: 1;
6757
+ display: flex;
6758
+ align-items: center;
6759
+ justify-content: center;
6760
+ background: var(--bg-soft);
6761
+ color: var(--fg-muted);
6762
+ font-style: italic;
6763
+ font-size: var(--db-font-base);
6533
6764
  }
6534
- .db-grid-resize-handle:hover,
6535
- body.db-resizing .db-grid-resize-handle {
6536
- background: var(--accent);
6537
- opacity: 0.5;
6538
- }
6539
- .db-grid-header-cell {
6765
+
6766
+ /* ---------- Export (icon + menu at the right of the search bar) ---------- */
6767
+ .db-grid-export {
6540
6768
  position: relative;
6769
+ flex-shrink: 0;
6541
6770
  }
6542
- body.db-resizing {
6543
- cursor: col-resize !important;
6544
- user-select: none;
6771
+
6772
+ .db-grid-export-toggle {
6773
+ border: 1px solid var(--border);
6774
+ border-radius: 4px;
6775
+ background: var(--bg);
6776
+ color: var(--fg-muted);
6777
+ font-size: var(--db-font-md);
6778
+ line-height: 1;
6779
+ padding: 3px 7px;
6780
+ cursor: pointer;
6545
6781
  }
6546
- body.db-resizing * {
6547
- user-select: none !important;
6782
+ .db-grid-export-toggle:hover {
6783
+ color: var(--fg);
6784
+ border-color: var(--accent);
6785
+ }
6786
+
6787
+ .db-grid-export-menu[hidden] {
6788
+ display: none !important;
6789
+ }
6790
+ .db-grid-export-menu {
6791
+ position: absolute;
6792
+ z-index: 10;
6793
+ top: calc(100% + 4px);
6794
+ right: 0;
6795
+ min-width: 92px;
6796
+ background: var(--bg);
6797
+ border: 1px solid var(--border);
6798
+ border-radius: 6px;
6799
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
6800
+ padding: 4px;
6801
+ display: flex;
6802
+ flex-direction: column;
6803
+ gap: 2px;
6804
+ }
6805
+
6806
+ .db-grid-export-item {
6807
+ border: none;
6808
+ background: none;
6809
+ color: var(--fg);
6810
+ text-align: left;
6811
+ font-size: var(--db-font-base);
6812
+ font-family: inherit;
6813
+ padding: 5px 10px;
6814
+ border-radius: 4px;
6815
+ cursor: pointer;
6816
+ }
6817
+ .db-grid-export-item:hover {
6818
+ background: var(--bg-mute);
6819
+ }
6820
+
6821
+ /* Related-panel header: breadcrumb (drill path). */
6822
+ .db-related-crumbs {
6823
+ flex: 1;
6824
+ min-width: 0;
6825
+ display: flex;
6826
+ align-items: center;
6827
+ gap: 4px;
6828
+ margin-left: 8px;
6829
+ overflow-x: auto;
6830
+ white-space: nowrap;
6831
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
6832
+ font-weight: 400;
6833
+ font-size: var(--db-font-base);
6834
+ }
6835
+
6836
+ .db-related-crumb-origin {
6837
+ color: var(--fg-subtle);
6838
+ flex-shrink: 0;
6839
+ }
6840
+
6841
+ .db-related-crumb-sep {
6842
+ color: var(--fg-subtle);
6843
+ flex-shrink: 0;
6844
+ }
6845
+
6846
+ .db-related-crumb {
6847
+ flex-shrink: 0;
6848
+ border: none;
6849
+ background: none;
6850
+ font: inherit;
6851
+ padding: 1px 4px;
6852
+ border-radius: 4px;
6853
+ color: var(--accent, var(--link, #2563eb));
6854
+ cursor: pointer;
6855
+ }
6856
+ .db-related-crumb:hover {
6857
+ background: var(--bg-mute);
6858
+ text-decoration: underline;
6859
+ }
6860
+ .db-related-crumb.active {
6861
+ color: var(--fg);
6862
+ font-weight: 600;
6863
+ cursor: default;
6864
+ }
6865
+
6866
+ .db-related-copy {
6867
+ flex-shrink: 0;
6868
+ font-size: 11px;
6869
+ padding: 2px 8px;
6870
+ margin-right: 8px;
6871
+ color: var(--fg-muted);
6872
+ }
6873
+ .db-related-copy:hover {
6874
+ color: var(--fg);
6875
+ }
6876
+
6877
+ /* ---------- Query History ---------- */
6878
+ .db-query-history-btn {
6879
+ border-radius: 6px;
6880
+ }
6881
+
6882
+ .db-query-history-dropdown[hidden] {
6883
+ display: none !important;
6884
+ }
6885
+
6886
+ .db-query-history-dropdown {
6887
+ position: absolute;
6888
+ z-index: 10;
6889
+ top: 100%;
6890
+ left: 0;
6891
+ right: 0;
6892
+ max-height: 250px;
6893
+ overflow-y: auto;
6894
+ background: var(--bg);
6895
+ border: 1px solid var(--border);
6896
+ border-radius: 6px;
6897
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
6898
+ margin-top: 4px;
6899
+ }
6900
+
6901
+ .db-query-history-item {
6902
+ padding: 6px 12px;
6903
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
6904
+ font-size: var(--db-font-base);
6905
+ cursor: pointer;
6906
+ white-space: nowrap;
6907
+ overflow: hidden;
6908
+ text-overflow: ellipsis;
6909
+ border-bottom: 1px solid var(--border);
6910
+ }
6911
+ .db-query-history-item:last-child {
6912
+ border-bottom: none;
6913
+ }
6914
+ .db-query-history-item:hover {
6915
+ background: var(--accent-subtle);
6916
+ }
6917
+
6918
+ .db-query-history-empty {
6919
+ padding: 12px;
6920
+ color: var(--fg-muted);
6921
+ text-align: center;
6922
+ font-size: var(--db-font-base);
6923
+ }
6924
+
6925
+ /* ---------- Explain Button ---------- */
6926
+ .db-query-explain {
6927
+ background: var(--bg-mute);
6928
+ color: var(--fg);
6929
+ border: 1px solid var(--border);
6930
+ }
6931
+ .db-query-explain:hover {
6932
+ background: var(--bg-soft);
6933
+ }
6934
+
6935
+ /* ---------- Query Input (relative positioning for history dropdown) ---------- */
6936
+ .db-query-input {
6937
+ position: relative;
6938
+ }
6939
+
6940
+ /* ---------- Column Resize Handle ---------- */
6941
+ .db-grid-resize-handle {
6942
+ position: absolute;
6943
+ right: 0;
6944
+ top: 0;
6945
+ bottom: 0;
6946
+ width: 6px;
6947
+ cursor: col-resize;
6948
+ background: transparent;
6949
+ z-index: 1;
6950
+ }
6951
+ .db-grid-resize-handle:hover,
6952
+ body.db-resizing .db-grid-resize-handle {
6953
+ background: var(--accent);
6954
+ opacity: 0.5;
6955
+ }
6956
+ .db-grid-header-cell {
6957
+ position: relative;
6958
+ }
6959
+ body.db-resizing {
6960
+ cursor: col-resize !important;
6961
+ user-select: none;
6962
+ }
6963
+ body.db-resizing * {
6964
+ user-select: none !important;
6548
6965
  }
6549
6966
 
6550
6967
  /* ---------- Context Menu ---------- */
@@ -7283,13 +7700,15 @@ body.db-resizing {
7283
7700
  .redis-explorer[hidden] {
7284
7701
  display: none;
7285
7702
  }
7703
+ /* redis-db-list-pane は db-sidebar の dbToolbar 直下にスロットとして mount
7704
+ される (database-view の explorerSidebarHost)。サイドバー自体が bg-soft +
7705
+ resize handle 付きなので、固定幅 / border-right / 重複する背景は持たない。 */
7286
7706
  .redis-db-list-pane {
7287
- width: 220px;
7288
- border-right: 1px solid var(--border);
7707
+ flex: 1 1 auto;
7708
+ min-height: 120px;
7289
7709
  display: flex;
7290
7710
  flex-direction: column;
7291
7711
  overflow: hidden;
7292
- background: var(--bg-soft);
7293
7712
  }
7294
7713
  .db-explorer-pane-header {
7295
7714
  padding: 8px 12px;
@@ -7573,6 +7992,38 @@ body.db-resizing {
7573
7992
  color: var(--error, #c00);
7574
7993
  font-size: var(--db-font-sm);
7575
7994
  }
7995
+ /* explorer の詳細/プレビュー pane に出す「未選択」空状態。中央寄せの
7996
+ アイコン + メッセージで統一する (S3 / Redis / Elasticsearch 共通)。 */
7997
+ .db-pane-empty {
7998
+ height: 100%;
7999
+ box-sizing: border-box;
8000
+ display: flex;
8001
+ flex-direction: column;
8002
+ align-items: center;
8003
+ justify-content: center;
8004
+ gap: 10px;
8005
+ padding: 32px 16px;
8006
+ text-align: center;
8007
+ }
8008
+ .db-pane-empty-icon {
8009
+ display: flex;
8010
+ color: var(--fg-subtle);
8011
+ opacity: 0.65;
8012
+ }
8013
+ .db-pane-empty-icon .octicon {
8014
+ width: 32px;
8015
+ height: 32px;
8016
+ }
8017
+ .db-pane-empty-title {
8018
+ color: var(--fg-muted);
8019
+ font-size: var(--db-font-md);
8020
+ }
8021
+ .db-pane-empty-hint {
8022
+ max-width: 320px;
8023
+ color: var(--fg-subtle);
8024
+ font-size: var(--db-font-sm);
8025
+ line-height: 1.5;
8026
+ }
7576
8027
 
7577
8028
  /* ---------- Elasticsearch explorer ---------- */
7578
8029
  .es-explorer {
@@ -7586,13 +8037,14 @@ body.db-resizing {
7586
8037
  .es-explorer[hidden] {
7587
8038
  display: none;
7588
8039
  }
8040
+ /* es-index-list-pane は redis-db-list-pane と同じく db-sidebar の
8041
+ explorerSidebarHost 内にスロットとして mount される。 */
7589
8042
  .es-index-list-pane {
7590
- width: 260px;
7591
- border-right: 1px solid var(--border);
8043
+ flex: 1 1 auto;
8044
+ min-height: 120px;
7592
8045
  display: flex;
7593
8046
  flex-direction: column;
7594
8047
  overflow: hidden;
7595
- background: var(--bg-soft);
7596
8048
  }
7597
8049
  .es-index-list {
7598
8050
  flex: 1;
@@ -7815,31 +8267,43 @@ body.db-resizing {
7815
8267
  .s3-explorer[hidden] {
7816
8268
  display: none;
7817
8269
  }
7818
- .s3-object-list-pane {
7819
- width: 420px;
7820
- border-right: 1px solid var(--border);
8270
+ /* List/Explorer 共通: Bucket / View seg / Search / Prefix・Contains / sort /
8271
+ objectList / tree がすべて sidebarSlot に積まれる。
8272
+ 下記 .s3-search-row / .s3-options-row は flex 行なので [hidden] 属性
8273
+ (UA の display:none) を明示で上書きしないと消えないことに注意。 */
8274
+ .s3-search-row,
8275
+ .s3-options-row {
7821
8276
  display: flex;
7822
- flex-direction: column;
7823
- overflow: hidden;
7824
- background: var(--bg);
8277
+ align-items: center;
8278
+ gap: 8px;
8279
+ min-width: 0;
7825
8280
  }
7826
- .s3-toolbar {
7827
- flex-shrink: 0;
7828
- display: flex;
7829
- flex-direction: column;
8281
+ .s3-search-row[hidden],
8282
+ .s3-options-row[hidden] {
8283
+ display: none;
8284
+ }
8285
+ /* s3-bucket-row は db-sidebar の explorerSidebarHost に mount される。260px
8286
+ 幅でも Bucket label + select + List/Explorer seg が綺麗に収まるよう、縦並び
8287
+ (label+select の行 / seg の行) にする。
8288
+ Explorer モードでは下に tree がぶら下がるため、flex column で残り高さを
8289
+ tree に渡せるようにする (`.db-explorer-sidebar-slot` の flex:1 と組合せ)。 */
8290
+ .s3-sidebar-slot {
8291
+ padding: 8px;
7830
8292
  gap: 8px;
7831
- padding: 10px 12px;
7832
- border-bottom: 1px solid var(--border);
7833
- background: var(--bg-soft);
7834
8293
  }
7835
- .s3-bucket-row,
7836
- .s3-search-row,
7837
- .s3-options-row {
8294
+ .s3-bucket-row {
7838
8295
  display: flex;
7839
- align-items: center;
8296
+ flex-direction: column;
7840
8297
  gap: 8px;
7841
8298
  min-width: 0;
7842
8299
  }
8300
+ .s3-bucket-row .s3-view-seg {
8301
+ align-self: stretch;
8302
+ display: flex;
8303
+ }
8304
+ .s3-bucket-row .s3-view-seg button {
8305
+ flex: 1;
8306
+ }
7843
8307
  .s3-field-label {
7844
8308
  flex: 1;
7845
8309
  min-width: 0;
@@ -7883,23 +8347,26 @@ body.db-resizing {
7883
8347
  padding: 4px 8px;
7884
8348
  }
7885
8349
  .s3-object-status {
7886
- min-height: 26px;
7887
- padding: 6px 12px;
7888
- border-bottom: 1px solid var(--border);
8350
+ min-height: 22px;
8351
+ padding: 4px 0;
7889
8352
  color: var(--fg-muted);
7890
8353
  font-size: var(--db-font-sm);
7891
- background: var(--bg);
7892
8354
  flex-shrink: 0;
7893
8355
  }
7894
8356
  .s3-object-status.warn {
7895
8357
  color: #8a5a22;
7896
8358
  background: #fff4e0;
7897
8359
  }
8360
+ /* sidebarSlot 内で残り高さを取り、スクロール可能にする。横の負 margin で
8361
+ sidebarSlot の左右 padding を相殺してフルブリードにする (アイテムの border
8362
+ が sidebar の幅一杯まで届くように)。 */
7898
8363
  .s3-object-list {
7899
- flex: 1;
7900
- min-height: 0;
8364
+ flex: 1 1 auto;
8365
+ min-height: 120px;
7901
8366
  overflow-y: auto;
7902
8367
  padding: 4px 0;
8368
+ margin: 0 -8px;
8369
+ border-top: 1px solid var(--border);
7903
8370
  }
7904
8371
  .s3-object-item {
7905
8372
  display: flex;
@@ -7918,7 +8385,24 @@ body.db-resizing {
7918
8385
  background: var(--bg-active, var(--bg-soft));
7919
8386
  border-left-color: var(--accent);
7920
8387
  }
8388
+ /* 1 行目: 親パス (薄)。サイドバー狭幅でも末尾が見える ellipsis のみ。 */
8389
+ .s3-object-parent {
8390
+ overflow: hidden;
8391
+ text-overflow: ellipsis;
8392
+ white-space: nowrap;
8393
+ font-family: var(--mono, monospace);
8394
+ font-size: 10px;
8395
+ color: var(--fg-muted);
8396
+ line-height: 1.3;
8397
+ }
8398
+ .s3-object-head {
8399
+ display: flex;
8400
+ align-items: center;
8401
+ gap: 6px;
8402
+ min-width: 0;
8403
+ }
7921
8404
  .s3-object-name {
8405
+ flex: 1 1 auto;
7922
8406
  overflow: hidden;
7923
8407
  text-overflow: ellipsis;
7924
8408
  white-space: nowrap;
@@ -7933,8 +8417,59 @@ body.db-resizing {
7933
8417
  color: var(--fg-muted);
7934
8418
  font-size: var(--db-font-sm);
7935
8419
  }
8420
+
8421
+ /* List / Explorer 共通: 行ホバーで全 key を floating で出す。document.body
8422
+ に attach するので、sidebar 外 (preview pane 側) へ突き出して読める。 */
8423
+ .s3-key-tooltip {
8424
+ position: fixed;
8425
+ z-index: 9999;
8426
+ max-width: 360px;
8427
+ padding: 10px 12px;
8428
+ background: var(--bg);
8429
+ color: var(--fg);
8430
+ border: 1px solid var(--border);
8431
+ border-radius: 6px;
8432
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
8433
+ pointer-events: none;
8434
+ font-size: var(--db-font-sm);
8435
+ }
8436
+ .s3-key-tooltip[hidden] {
8437
+ display: none;
8438
+ }
8439
+ .s3-key-tooltip-image {
8440
+ display: block;
8441
+ max-width: 336px;
8442
+ max-height: 240px;
8443
+ width: auto;
8444
+ height: auto;
8445
+ margin: -2px 0 8px;
8446
+ border-radius: 4px;
8447
+ background: var(--bg-soft);
8448
+ }
8449
+ .s3-key-tooltip-path {
8450
+ font-family: var(--mono, monospace);
8451
+ font-size: var(--db-font-mono);
8452
+ word-break: break-all;
8453
+ line-height: 1.4;
8454
+ }
8455
+ .s3-key-tooltip-meta {
8456
+ margin-top: 6px;
8457
+ padding-top: 6px;
8458
+ border-top: 1px solid var(--border);
8459
+ color: var(--fg-muted);
8460
+ }
8461
+
8462
+ /* tooltip 切替トグル: bucketRow 内 (Bucket select + List/Explorer の下) の
8463
+ 小さなボタン。active 時はアクセントで強調。 */
8464
+ /* s3 explorer の Hover preview トグル: 共通 .db-pref-toggle を併用する。
8465
+ ここでは bucketRow (column flex) 内で stretch しないように align-self
8466
+ だけ上書き。ラベルクラスも .db-pref-toggle-label と同等。 */
8467
+ .s3-tooltip-toggle {
8468
+ align-self: flex-start;
8469
+ }
7936
8470
  .s3-object-more-btn {
7937
8471
  padding: 6px;
8472
+ margin: 0 -8px -8px;
7938
8473
  border: none;
7939
8474
  border-top: 1px solid var(--border);
7940
8475
  background: var(--bg-soft);
@@ -7949,6 +8484,205 @@ body.db-resizing {
7949
8484
  cursor: default;
7950
8485
  color: var(--fg-muted);
7951
8486
  }
8487
+
8488
+ /* ファイル種別がひと目で分かる色付きバッジ (List / Explorer 共通)。 */
8489
+ .s3-kind-badge {
8490
+ flex: 0 0 auto;
8491
+ display: inline-flex;
8492
+ align-items: center;
8493
+ padding: 0 6px;
8494
+ height: 16px;
8495
+ border-radius: 999px;
8496
+ border: 1px solid transparent;
8497
+ font-size: 10px;
8498
+ font-weight: 600;
8499
+ line-height: 1;
8500
+ letter-spacing: 0.02em;
8501
+ text-transform: uppercase;
8502
+ white-space: nowrap;
8503
+ user-select: none;
8504
+ }
8505
+ /* 色は意味別のテーマトークンを使い、ダークモードでも自動で追従させる
8506
+ (背景/縁も同じトークンを color-mix することで theme 変数の切替に乗る)。 */
8507
+ .s3-kind-badge.kind-image {
8508
+ color: var(--success);
8509
+ background: color-mix(in srgb, var(--success) 12%, var(--bg));
8510
+ border-color: color-mix(in srgb, var(--success) 35%, transparent);
8511
+ }
8512
+ .s3-kind-badge.kind-video {
8513
+ color: var(--done);
8514
+ background: color-mix(in srgb, var(--done) 12%, var(--bg));
8515
+ border-color: color-mix(in srgb, var(--done) 35%, transparent);
8516
+ }
8517
+ .s3-kind-badge.kind-audio {
8518
+ color: var(--attn);
8519
+ background: color-mix(in srgb, var(--attn) 12%, var(--bg));
8520
+ border-color: color-mix(in srgb, var(--attn) 35%, transparent);
8521
+ }
8522
+ .s3-kind-badge.kind-pdf {
8523
+ color: var(--danger);
8524
+ background: color-mix(in srgb, var(--danger) 12%, var(--bg));
8525
+ border-color: color-mix(in srgb, var(--danger) 35%, transparent);
8526
+ }
8527
+ .s3-kind-badge.kind-text {
8528
+ color: var(--accent);
8529
+ background: color-mix(in srgb, var(--accent) 12%, var(--bg));
8530
+ border-color: color-mix(in srgb, var(--accent) 35%, transparent);
8531
+ }
8532
+ .s3-kind-badge.kind-binary {
8533
+ color: var(--fg-muted);
8534
+ background: var(--bg-soft);
8535
+ border-color: var(--border);
8536
+ }
8537
+
8538
+ /* List / Explorer 切替セグメント。 */
8539
+ .s3-view-seg {
8540
+ flex-shrink: 0;
8541
+ }
8542
+
8543
+ /* Explorer 表示: 既存ファイルツリー (#filelist.tree) の見た目を S3 ペインに
8544
+ 合わせて再現したもの。クラス名は共通 (.tree-dir / .tree-file / .chev ...)。
8545
+ sidebar 内の sidebarSlot に置かれるため、flex で残りの高さを満たし、
8546
+ スクロール可能にする。padding をなくし、sidebarSlot の余白に揃える。 */
8547
+ .s3-tree {
8548
+ --lvl-pad: 12px;
8549
+ flex: 1 1 auto;
8550
+ min-height: 120px;
8551
+ overflow-y: auto;
8552
+ padding: 4px 0;
8553
+ margin: 0 -8px -8px;
8554
+ border-top: 1px solid var(--border);
8555
+ }
8556
+ .s3-tree[hidden] {
8557
+ display: none;
8558
+ }
8559
+ .s3-tree .s3-tree-node {
8560
+ min-width: 0;
8561
+ }
8562
+ .s3-tree .tree-children {
8563
+ list-style: none;
8564
+ margin: 0;
8565
+ padding: 0;
8566
+ }
8567
+ .s3-tree .tree-dir.collapsed + .tree-children {
8568
+ display: none;
8569
+ }
8570
+ .s3-tree .tree-dir {
8571
+ display: grid;
8572
+ grid-template-columns: 16px 16px minmax(0, 1fr);
8573
+ align-items: center;
8574
+ gap: 8px;
8575
+ padding: 4px 6px 4px var(--lvl-pad, 12px);
8576
+ border-radius: 6px;
8577
+ cursor: pointer;
8578
+ user-select: none;
8579
+ color: var(--fg);
8580
+ }
8581
+ .s3-tree .tree-dir:hover {
8582
+ background: var(--bg-hover, var(--bg-soft));
8583
+ }
8584
+ .s3-tree .tree-dir .chev {
8585
+ display: flex;
8586
+ width: 16px;
8587
+ height: 16px;
8588
+ align-items: center;
8589
+ justify-content: center;
8590
+ color: var(--fg-muted);
8591
+ transition: transform 0.15s;
8592
+ }
8593
+ .s3-tree .tree-dir.collapsed .chev {
8594
+ transform: rotate(-90deg);
8595
+ }
8596
+ .s3-tree .tree-dir .chev .octicon {
8597
+ width: 12px;
8598
+ height: 12px;
8599
+ display: block;
8600
+ }
8601
+ .s3-tree .tree-dir .dir-icon {
8602
+ color: #54aeff;
8603
+ width: 16px;
8604
+ height: 16px;
8605
+ display: grid;
8606
+ align-items: center;
8607
+ justify-content: center;
8608
+ }
8609
+ .s3-tree .tree-dir .dir-icon .octicon {
8610
+ display: block;
8611
+ }
8612
+ .s3-tree .tree-dir .dir-label {
8613
+ min-width: 0;
8614
+ display: flex;
8615
+ align-items: center;
8616
+ overflow: hidden;
8617
+ }
8618
+ .s3-tree .tree-dir .dir-name {
8619
+ min-width: 0;
8620
+ overflow: hidden;
8621
+ text-overflow: ellipsis;
8622
+ white-space: nowrap;
8623
+ font-family: var(--mono, monospace);
8624
+ font-size: var(--db-font-mono);
8625
+ }
8626
+ .s3-tree .tree-file {
8627
+ display: grid;
8628
+ grid-template-columns: 16px auto minmax(0, 1fr);
8629
+ align-items: center;
8630
+ gap: 8px;
8631
+ padding: 4px 6px 4px var(--lvl-pad, 12px);
8632
+ border-left: 2px solid transparent;
8633
+ cursor: pointer;
8634
+ user-select: none;
8635
+ color: var(--fg);
8636
+ }
8637
+ .s3-tree .tree-file:hover {
8638
+ background: var(--bg-hover, var(--bg-soft));
8639
+ }
8640
+ .s3-tree .tree-file.active {
8641
+ background: var(--bg-active, var(--bg-soft));
8642
+ border-left-color: var(--accent);
8643
+ }
8644
+ .s3-tree .tree-file .chev-spacer {
8645
+ width: 16px;
8646
+ height: 1px;
8647
+ }
8648
+ .s3-tree .tree-file .name {
8649
+ min-width: 0;
8650
+ overflow: hidden;
8651
+ text-overflow: ellipsis;
8652
+ white-space: nowrap;
8653
+ font-family: var(--mono, monospace);
8654
+ font-size: var(--db-font-mono);
8655
+ }
8656
+ .s3-tree .s3-tree-more {
8657
+ display: block;
8658
+ width: calc(100% - 12px);
8659
+ margin: 2px 6px;
8660
+ padding: 4px 6px 4px var(--lvl-pad, 12px);
8661
+ border: none;
8662
+ border-radius: 6px;
8663
+ background: var(--bg-soft);
8664
+ color: var(--accent);
8665
+ font-size: var(--db-font-sm);
8666
+ text-align: left;
8667
+ cursor: pointer;
8668
+ }
8669
+ .s3-tree .s3-tree-more:hover {
8670
+ background: var(--bg-hover, var(--bg));
8671
+ }
8672
+ .s3-tree .s3-tree-more:disabled {
8673
+ cursor: default;
8674
+ color: var(--fg-muted);
8675
+ }
8676
+ .s3-tree .s3-tree-empty,
8677
+ .s3-tree .s3-tree-loading,
8678
+ .s3-tree .s3-tree-error {
8679
+ padding: 4px 6px 4px var(--lvl-pad, 12px);
8680
+ color: var(--fg-muted);
8681
+ font-size: var(--db-font-sm);
8682
+ }
8683
+ .s3-tree .s3-tree-error {
8684
+ color: var(--danger);
8685
+ }
7952
8686
  .s3-preview-pane {
7953
8687
  flex: 1;
7954
8688
  min-width: 0;