@youtyan/code-viewer 0.2.8 → 0.2.10

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,43 @@ body.gdp-history-resizing * {
1720
1735
  gap: 8px;
1721
1736
  margin-top: 10px;
1722
1737
  }
1738
+ .scope-watch-limit-row {
1739
+ display: flex;
1740
+ align-items: center;
1741
+ gap: 10px;
1742
+ }
1743
+ .scope-watch-limit-row input[type="range"] {
1744
+ flex: 1;
1745
+ min-width: 0;
1746
+ accent-color: var(--accent, #2b6cb0);
1747
+ }
1748
+ .scope-watch-limit-row input[type="number"] {
1749
+ width: 88px;
1750
+ flex: 0 0 auto;
1751
+ }
1752
+ .scope-settings-toggle {
1753
+ display: flex;
1754
+ align-items: center;
1755
+ gap: 8px;
1756
+ margin-top: 4px;
1757
+ cursor: pointer;
1758
+ }
1759
+ .scope-settings-toggle input[type="checkbox"] {
1760
+ margin: 0;
1761
+ }
1762
+ .scope-settings-footer {
1763
+ display: flex;
1764
+ align-items: center;
1765
+ justify-content: space-between;
1766
+ gap: 12px;
1767
+ margin-top: 12px;
1768
+ padding-top: 10px;
1769
+ border-top: 1px solid var(--border);
1770
+ }
1771
+ .scope-settings-footer .scope-settings-help {
1772
+ margin: 0;
1773
+ flex: 1;
1774
+ }
1723
1775
  .scope-settings-actions button {
1724
1776
  border: 1px solid var(--border);
1725
1777
  border-radius: 6px;
@@ -5470,6 +5522,66 @@ body[data-sidebar-font-size="xlarge"] .db-container {
5470
5522
  .db-icon-toolbar[hidden] {
5471
5523
  display: none !important;
5472
5524
  }
5525
+
5526
+ /* sidebar の設定トグル行。dbToolbar 直下に並ぶ。複数トグルを横に並べる
5527
+ 想定なので flex-wrap で折り返し。 */
5528
+ .db-prefs-bar {
5529
+ display: flex;
5530
+ flex-wrap: wrap;
5531
+ gap: 6px;
5532
+ padding: 6px 8px;
5533
+ border-bottom: 1px solid var(--border);
5534
+ background: var(--bg-soft);
5535
+ }
5536
+ .db-prefs-bar[hidden] {
5537
+ display: none;
5538
+ }
5539
+ /* ラベル付きピル形式の永続化トグル (Rails FK 推測など)。active 時は
5540
+ accent 色のチントで「ON」が一目で分かるようにする。 */
5541
+ .db-pref-toggle {
5542
+ display: inline-flex;
5543
+ align-items: center;
5544
+ gap: 6px;
5545
+ padding: 3px 8px;
5546
+ border: 1px solid var(--border);
5547
+ border-radius: 999px;
5548
+ background: var(--bg);
5549
+ color: var(--fg-muted);
5550
+ cursor: pointer;
5551
+ font-size: var(--db-font-sm);
5552
+ }
5553
+ .db-pref-toggle:hover {
5554
+ background: var(--bg-hover, var(--bg-soft));
5555
+ }
5556
+ .db-pref-toggle.active {
5557
+ border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
5558
+ color: var(--accent);
5559
+ background: color-mix(in srgb, var(--accent) 12%, var(--bg));
5560
+ }
5561
+ .db-pref-toggle svg {
5562
+ flex: 0 0 auto;
5563
+ }
5564
+ .db-pref-toggle-label {
5565
+ white-space: nowrap;
5566
+ }
5567
+
5568
+ /* 推測 FK は実 FK と区別。関連パネルのリスト項目に淡いマーカーを乗せる。 */
5569
+ .db-related-list-inferred {
5570
+ background: color-mix(in srgb, var(--attn, var(--accent)) 6%, transparent);
5571
+ }
5572
+ .db-related-list-inferred-badge {
5573
+ display: inline-block;
5574
+ margin-left: 6px;
5575
+ padding: 0 5px;
5576
+ border-radius: 4px;
5577
+ background: color-mix(in srgb, var(--attn, var(--accent)) 18%, var(--bg));
5578
+ color: var(--attn, var(--accent));
5579
+ font-size: 9px;
5580
+ font-weight: 600;
5581
+ letter-spacing: 0.04em;
5582
+ text-transform: uppercase;
5583
+ vertical-align: middle;
5584
+ }
5473
5585
  .db-icon-btn {
5474
5586
  display: inline-flex;
5475
5587
  align-items: center;
@@ -5607,6 +5719,35 @@ body[data-sidebar-font-size="xlarge"] .db-container {
5607
5719
  border-bottom: 1px solid var(--border);
5608
5720
  }
5609
5721
 
5722
+ /* explorer (redis/es/s3) の第1階層セレクタ (Databases / Indices / Bucket+View)
5723
+ を抱える sidebar 内 host。kind が SQL のときは中身が全て hidden になるため
5724
+ 高さが潰れて見えなくなる (table list が下に詰まる)。
5725
+ redis/es/s3 のときは hidden 子要素を 1 つだけ表示し、その slot が sidebar
5726
+ の残り高さを全て取れるよう host 自身も flex:1 にする。 */
5727
+ .db-explorer-sidebar-host {
5728
+ flex: 1 1 auto;
5729
+ min-height: 0;
5730
+ display: flex;
5731
+ flex-direction: column;
5732
+ overflow: hidden;
5733
+ }
5734
+ /* author 側 display:flex が UA の [hidden]→display:none を上書きしてしまう
5735
+ ため、明示で潰す。SQL kind 時はこの host を畳んで tableList を上に詰める。 */
5736
+ .db-explorer-sidebar-host[hidden] {
5737
+ display: none;
5738
+ }
5739
+ .db-explorer-sidebar-slot {
5740
+ flex: 1 1 auto;
5741
+ min-height: 0;
5742
+ border-bottom: 1px solid var(--border);
5743
+ display: flex;
5744
+ flex-direction: column;
5745
+ overflow: hidden;
5746
+ }
5747
+ .db-explorer-sidebar-slot[hidden] {
5748
+ display: none;
5749
+ }
5750
+
5610
5751
  .db-file-select {
5611
5752
  width: 100%;
5612
5753
  padding: 5px 24px 5px 8px;
@@ -6381,18 +6522,41 @@ html[data-theme="dark"] .db-query-highlight span[style] {
6381
6522
  max-width: none !important;
6382
6523
  }
6383
6524
 
6525
+ /* 現在フッタ/関連パネルに表示している値の元セル。スクロール後も維持するため
6526
+ render 時に state からクラスが再付与される。selected 行 + active 列で
6527
+ 二重に強調する。border-left を残しつつ accent 色のリング。 */
6528
+ .db-grid-cell.db-grid-cell-active {
6529
+ background: color-mix(in srgb, var(--accent) 22%, var(--bg));
6530
+ box-shadow: inset 0 0 0 2px var(--accent);
6531
+ color: var(--fg);
6532
+ }
6533
+ .db-grid-cell.db-grid-cell-active.null,
6534
+ .db-grid-cell.db-grid-cell-active.empty,
6535
+ .db-grid-cell.db-grid-cell-active.blob {
6536
+ /* 空状態でも視認できるよう色だけ上書きしない (fg-muted) → 通常 fg。 */
6537
+ color: var(--fg);
6538
+ }
6539
+
6384
6540
  /* ---------- Cell Detail Panel ---------- */
6385
6541
  .db-grid-detail-panel[hidden] {
6386
6542
  display: none !important;
6387
6543
  }
6388
6544
 
6389
6545
  .db-grid-detail-panel {
6546
+ position: relative;
6390
6547
  border-top: 1px solid var(--border);
6391
6548
  background: var(--bg-soft);
6392
- max-height: 200px;
6549
+ /* 高さは JS から style.height で設定 (永続化対応)。default 200px
6550
+ min-height は table-grid.ts の DETAIL_PANEL_MIN_HEIGHT と揃える
6551
+ (40 → 40)。CSS 側を緩めにしておくと、ユーザーが 40px まで縮めた
6552
+ のに描画は 80px のまま、永続化値と表示が食い違う回帰になる。 */
6553
+ height: 200px;
6554
+ min-height: 40px;
6393
6555
  overflow: auto;
6394
6556
  flex-shrink: 0;
6395
6557
  }
6558
+ /* 上端のドラッグハンドル: detail フッタと関連パネルで共通。
6559
+ .db-related-resize と同じセレクタ規則を共有する。 */
6396
6560
 
6397
6561
  .db-grid-detail-header {
6398
6562
  display: flex;
@@ -6452,121 +6616,388 @@ html[data-theme="dark"] .db-query-highlight span[style] {
6452
6616
  word-break: break-word;
6453
6617
  }
6454
6618
 
6455
- /* ---------- Export Buttons ---------- */
6456
- .db-grid-export-btn {
6457
- margin-left: 6px;
6619
+ /* ---------- Foreign-key related data ---------- */
6620
+ .db-grid-header-fk-icon {
6621
+ margin-left: 4px;
6622
+ font-size: 10px;
6623
+ opacity: 0.7;
6458
6624
  }
6459
6625
 
6460
- /* ---------- Query History ---------- */
6461
- .db-query-history-btn {
6462
- border-radius: 6px;
6626
+ .db-grid-cell-fk {
6627
+ color: var(--accent, var(--link, #2563eb));
6628
+ }
6629
+ .db-grid-cell-fk:hover {
6630
+ text-decoration: underline;
6463
6631
  }
6464
6632
 
6465
- .db-query-history-dropdown[hidden] {
6633
+ /* Related-data panel: 下部に出る「左=関連テーブル一覧 / 右=データグリッド」 */
6634
+ .db-related-panel[hidden] {
6466
6635
  display: none !important;
6467
6636
  }
6468
6637
 
6469
- .db-query-history-dropdown {
6638
+ .db-related-panel {
6639
+ position: relative;
6640
+ display: flex;
6641
+ flex-direction: column;
6642
+ flex-shrink: 0;
6643
+ border-top: 2px solid var(--border);
6644
+ background: var(--bg-soft);
6645
+ overflow: hidden;
6646
+ }
6647
+
6648
+ .db-related-resize,
6649
+ .db-grid-detail-resize {
6470
6650
  position: absolute;
6471
- z-index: 10;
6472
- top: 100%;
6651
+ top: 0;
6473
6652
  left: 0;
6474
6653
  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;
6654
+ height: 6px;
6655
+ cursor: row-resize;
6656
+ z-index: 2;
6657
+ }
6658
+ .db-related-resize:hover,
6659
+ .db-grid-detail-resize:hover {
6660
+ background: var(--accent, var(--border));
6661
+ opacity: 0.4;
6482
6662
  }
6483
6663
 
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;
6664
+ .db-related-header {
6665
+ display: flex;
6666
+ align-items: center;
6667
+ gap: 4px;
6668
+ padding: 4px 8px;
6669
+ background: var(--bg-mute);
6492
6670
  border-bottom: 1px solid var(--border);
6671
+ font-size: var(--db-font-base);
6672
+ font-weight: 600;
6493
6673
  }
6494
- .db-query-history-item:last-child {
6495
- border-bottom: none;
6496
- }
6497
- .db-query-history-item:hover {
6498
- background: var(--accent-subtle);
6674
+
6675
+ .db-related-title {
6676
+ flex-shrink: 0;
6677
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
6499
6678
  }
6500
6679
 
6501
- .db-query-history-empty {
6502
- padding: 12px;
6680
+ .db-related-close {
6681
+ font-size: 14px;
6503
6682
  color: var(--fg-muted);
6504
- text-align: center;
6505
- font-size: var(--db-font-base);
6506
6683
  }
6507
-
6508
- /* ---------- Explain Button ---------- */
6509
- .db-query-explain {
6510
- background: var(--bg-mute);
6511
- color: var(--fg);
6512
- border: 1px solid var(--border);
6684
+ .db-related-close:hover {
6685
+ color: var(--danger);
6686
+ background: none;
6513
6687
  }
6514
- .db-query-explain:hover {
6515
- background: var(--bg-soft);
6688
+
6689
+ .db-related-body {
6690
+ display: flex;
6691
+ flex: 1;
6692
+ min-height: 0;
6516
6693
  }
6517
6694
 
6518
- /* ---------- Query Input (relative positioning for history dropdown) ---------- */
6519
- .db-query-input {
6520
- position: relative;
6695
+ .db-related-list {
6696
+ width: 200px;
6697
+ flex-shrink: 0;
6698
+ overflow: auto;
6699
+ border-right: 1px solid var(--border);
6700
+ padding: 4px;
6521
6701
  }
6522
6702
 
6523
- /* ---------- Column Resize Handle ---------- */
6524
- .db-grid-resize-handle {
6525
- position: absolute;
6526
- right: 0;
6527
- top: 0;
6528
- bottom: 0;
6529
- width: 6px;
6530
- cursor: col-resize;
6531
- background: transparent;
6532
- z-index: 1;
6703
+ .db-related-list-item {
6704
+ display: flex;
6705
+ flex-direction: column;
6706
+ align-items: flex-start;
6707
+ gap: 1px;
6708
+ width: 100%;
6709
+ padding: 5px 8px;
6710
+ margin-bottom: 2px;
6711
+ border: 1px solid transparent;
6712
+ border-radius: 4px;
6713
+ background: none;
6714
+ text-align: left;
6715
+ cursor: pointer;
6716
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
6533
6717
  }
6534
- .db-grid-resize-handle:hover,
6535
- body.db-resizing .db-grid-resize-handle {
6536
- background: var(--accent);
6537
- opacity: 0.5;
6718
+ .db-related-list-item:hover {
6719
+ background: var(--bg-mute);
6538
6720
  }
6539
- .db-grid-header-cell {
6540
- position: relative;
6721
+ .db-related-list-item.active {
6722
+ background: var(--bg-mute);
6723
+ border-color: var(--accent, var(--border));
6541
6724
  }
6542
- body.db-resizing {
6543
- cursor: col-resize !important;
6544
- user-select: none;
6725
+
6726
+ .db-related-list-name {
6727
+ font-size: var(--db-font-base);
6728
+ font-weight: 600;
6729
+ color: var(--fg);
6730
+ display: inline-flex;
6731
+ align-items: baseline;
6732
+ gap: 6px;
6545
6733
  }
6546
- body.db-resizing * {
6547
- user-select: none !important;
6734
+ /* 方向アイコンを name の前に出す: outgoing は → (自分→他テーブル)、
6735
+ incoming ← (他テーブル→自分の PK)。テキスト 1 文字なのでフォントに
6736
+ 影響されず軽量。 */
6737
+ .db-related-list-name::before {
6738
+ flex: 0 0 auto;
6739
+ font-size: 11px;
6740
+ font-weight: 500;
6741
+ color: var(--fg-muted);
6548
6742
  }
6549
-
6550
- /* ---------- Context Menu ---------- */
6551
- .db-context-menu {
6552
- z-index: 100;
6553
- min-width: 200px;
6554
- background: var(--bg);
6555
- border: 1px solid var(--border);
6556
- border-radius: 6px;
6557
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
6558
- padding: 4px 0;
6559
- font-size: var(--db-font-md);
6743
+ .db-related-list-outgoing .db-related-list-name::before {
6744
+ content: "→";
6560
6745
  }
6561
- .db-context-menu-item {
6562
- padding: 6px 14px;
6563
- cursor: pointer;
6564
- color: var(--fg);
6565
- white-space: nowrap;
6746
+ .db-related-list-incoming .db-related-list-name::before {
6747
+ content: "←";
6566
6748
  }
6567
- .db-context-menu-item:hover {
6568
- background: var(--accent-subtle);
6569
- color: var(--accent);
6749
+
6750
+ .db-related-list-via {
6751
+ font-size: 11px;
6752
+ color: var(--fg-muted);
6753
+ word-break: break-all;
6754
+ }
6755
+
6756
+ .db-related-grid-host {
6757
+ position: relative;
6758
+ display: flex;
6759
+ flex: 1;
6760
+ min-width: 0;
6761
+ overflow: hidden;
6762
+ }
6763
+
6764
+ .db-related-empty[hidden] {
6765
+ display: none !important;
6766
+ }
6767
+ .db-related-empty {
6768
+ position: absolute;
6769
+ inset: 0;
6770
+ z-index: 1;
6771
+ display: flex;
6772
+ align-items: center;
6773
+ justify-content: center;
6774
+ background: var(--bg-soft);
6775
+ color: var(--fg-muted);
6776
+ font-style: italic;
6777
+ font-size: var(--db-font-base);
6778
+ }
6779
+
6780
+ /* ---------- Export (icon + menu at the right of the search bar) ---------- */
6781
+ .db-grid-export {
6782
+ position: relative;
6783
+ flex-shrink: 0;
6784
+ }
6785
+
6786
+ .db-grid-export-toggle {
6787
+ border: 1px solid var(--border);
6788
+ border-radius: 4px;
6789
+ background: var(--bg);
6790
+ color: var(--fg-muted);
6791
+ font-size: var(--db-font-md);
6792
+ line-height: 1;
6793
+ padding: 3px 7px;
6794
+ cursor: pointer;
6795
+ }
6796
+ .db-grid-export-toggle:hover {
6797
+ color: var(--fg);
6798
+ border-color: var(--accent);
6799
+ }
6800
+
6801
+ .db-grid-export-menu[hidden] {
6802
+ display: none !important;
6803
+ }
6804
+ .db-grid-export-menu {
6805
+ position: absolute;
6806
+ z-index: 10;
6807
+ top: calc(100% + 4px);
6808
+ right: 0;
6809
+ min-width: 92px;
6810
+ background: var(--bg);
6811
+ border: 1px solid var(--border);
6812
+ border-radius: 6px;
6813
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
6814
+ padding: 4px;
6815
+ display: flex;
6816
+ flex-direction: column;
6817
+ gap: 2px;
6818
+ }
6819
+
6820
+ .db-grid-export-item {
6821
+ border: none;
6822
+ background: none;
6823
+ color: var(--fg);
6824
+ text-align: left;
6825
+ font-size: var(--db-font-base);
6826
+ font-family: inherit;
6827
+ padding: 5px 10px;
6828
+ border-radius: 4px;
6829
+ cursor: pointer;
6830
+ }
6831
+ .db-grid-export-item:hover {
6832
+ background: var(--bg-mute);
6833
+ }
6834
+
6835
+ /* Related-panel header: breadcrumb (drill path). */
6836
+ .db-related-crumbs {
6837
+ flex: 1;
6838
+ min-width: 0;
6839
+ display: flex;
6840
+ align-items: center;
6841
+ gap: 4px;
6842
+ margin-left: 8px;
6843
+ overflow-x: auto;
6844
+ white-space: nowrap;
6845
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
6846
+ font-weight: 400;
6847
+ font-size: var(--db-font-base);
6848
+ }
6849
+
6850
+ .db-related-crumb-origin {
6851
+ color: var(--fg-subtle);
6852
+ flex-shrink: 0;
6853
+ }
6854
+
6855
+ .db-related-crumb-sep {
6856
+ color: var(--fg-subtle);
6857
+ flex-shrink: 0;
6858
+ }
6859
+
6860
+ .db-related-crumb {
6861
+ flex-shrink: 0;
6862
+ border: none;
6863
+ background: none;
6864
+ font: inherit;
6865
+ padding: 1px 4px;
6866
+ border-radius: 4px;
6867
+ color: var(--accent, var(--link, #2563eb));
6868
+ cursor: pointer;
6869
+ }
6870
+ .db-related-crumb:hover {
6871
+ background: var(--bg-mute);
6872
+ text-decoration: underline;
6873
+ }
6874
+ .db-related-crumb.active {
6875
+ color: var(--fg);
6876
+ font-weight: 600;
6877
+ cursor: default;
6878
+ }
6879
+
6880
+ .db-related-copy {
6881
+ flex-shrink: 0;
6882
+ font-size: 11px;
6883
+ padding: 2px 8px;
6884
+ margin-right: 8px;
6885
+ color: var(--fg-muted);
6886
+ }
6887
+ .db-related-copy:hover {
6888
+ color: var(--fg);
6889
+ }
6890
+
6891
+ /* ---------- Query History ---------- */
6892
+ .db-query-history-btn {
6893
+ border-radius: 6px;
6894
+ }
6895
+
6896
+ .db-query-history-dropdown[hidden] {
6897
+ display: none !important;
6898
+ }
6899
+
6900
+ .db-query-history-dropdown {
6901
+ position: absolute;
6902
+ z-index: 10;
6903
+ top: 100%;
6904
+ left: 0;
6905
+ right: 0;
6906
+ max-height: 250px;
6907
+ overflow-y: auto;
6908
+ background: var(--bg);
6909
+ border: 1px solid var(--border);
6910
+ border-radius: 6px;
6911
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
6912
+ margin-top: 4px;
6913
+ }
6914
+
6915
+ .db-query-history-item {
6916
+ padding: 6px 12px;
6917
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
6918
+ font-size: var(--db-font-base);
6919
+ cursor: pointer;
6920
+ white-space: nowrap;
6921
+ overflow: hidden;
6922
+ text-overflow: ellipsis;
6923
+ border-bottom: 1px solid var(--border);
6924
+ }
6925
+ .db-query-history-item:last-child {
6926
+ border-bottom: none;
6927
+ }
6928
+ .db-query-history-item:hover {
6929
+ background: var(--accent-subtle);
6930
+ }
6931
+
6932
+ .db-query-history-empty {
6933
+ padding: 12px;
6934
+ color: var(--fg-muted);
6935
+ text-align: center;
6936
+ font-size: var(--db-font-base);
6937
+ }
6938
+
6939
+ /* ---------- Explain Button ---------- */
6940
+ .db-query-explain {
6941
+ background: var(--bg-mute);
6942
+ color: var(--fg);
6943
+ border: 1px solid var(--border);
6944
+ }
6945
+ .db-query-explain:hover {
6946
+ background: var(--bg-soft);
6947
+ }
6948
+
6949
+ /* ---------- Query Input (relative positioning for history dropdown) ---------- */
6950
+ .db-query-input {
6951
+ position: relative;
6952
+ }
6953
+
6954
+ /* ---------- Column Resize Handle ---------- */
6955
+ .db-grid-resize-handle {
6956
+ position: absolute;
6957
+ right: 0;
6958
+ top: 0;
6959
+ bottom: 0;
6960
+ width: 6px;
6961
+ cursor: col-resize;
6962
+ background: transparent;
6963
+ z-index: 1;
6964
+ }
6965
+ .db-grid-resize-handle:hover,
6966
+ body.db-resizing .db-grid-resize-handle {
6967
+ background: var(--accent);
6968
+ opacity: 0.5;
6969
+ }
6970
+ .db-grid-header-cell {
6971
+ position: relative;
6972
+ }
6973
+ body.db-resizing {
6974
+ cursor: col-resize !important;
6975
+ user-select: none;
6976
+ }
6977
+ body.db-resizing * {
6978
+ user-select: none !important;
6979
+ }
6980
+
6981
+ /* ---------- Context Menu ---------- */
6982
+ .db-context-menu {
6983
+ z-index: 100;
6984
+ min-width: 200px;
6985
+ background: var(--bg);
6986
+ border: 1px solid var(--border);
6987
+ border-radius: 6px;
6988
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
6989
+ padding: 4px 0;
6990
+ font-size: var(--db-font-md);
6991
+ }
6992
+ .db-context-menu-item {
6993
+ padding: 6px 14px;
6994
+ cursor: pointer;
6995
+ color: var(--fg);
6996
+ white-space: nowrap;
6997
+ }
6998
+ .db-context-menu-item:hover {
6999
+ background: var(--accent-subtle);
7000
+ color: var(--accent);
6570
7001
  }
6571
7002
 
6572
7003
  /* ---------- Schema Section Headers ---------- */
@@ -7283,13 +7714,15 @@ body.db-resizing {
7283
7714
  .redis-explorer[hidden] {
7284
7715
  display: none;
7285
7716
  }
7717
+ /* redis-db-list-pane は db-sidebar の dbToolbar 直下にスロットとして mount
7718
+ される (database-view の explorerSidebarHost)。サイドバー自体が bg-soft +
7719
+ resize handle 付きなので、固定幅 / border-right / 重複する背景は持たない。 */
7286
7720
  .redis-db-list-pane {
7287
- width: 220px;
7288
- border-right: 1px solid var(--border);
7721
+ flex: 1 1 auto;
7722
+ min-height: 120px;
7289
7723
  display: flex;
7290
7724
  flex-direction: column;
7291
7725
  overflow: hidden;
7292
- background: var(--bg-soft);
7293
7726
  }
7294
7727
  .db-explorer-pane-header {
7295
7728
  padding: 8px 12px;
@@ -7573,6 +8006,38 @@ body.db-resizing {
7573
8006
  color: var(--error, #c00);
7574
8007
  font-size: var(--db-font-sm);
7575
8008
  }
8009
+ /* explorer の詳細/プレビュー pane に出す「未選択」空状態。中央寄せの
8010
+ アイコン + メッセージで統一する (S3 / Redis / Elasticsearch 共通)。 */
8011
+ .db-pane-empty {
8012
+ height: 100%;
8013
+ box-sizing: border-box;
8014
+ display: flex;
8015
+ flex-direction: column;
8016
+ align-items: center;
8017
+ justify-content: center;
8018
+ gap: 10px;
8019
+ padding: 32px 16px;
8020
+ text-align: center;
8021
+ }
8022
+ .db-pane-empty-icon {
8023
+ display: flex;
8024
+ color: var(--fg-subtle);
8025
+ opacity: 0.65;
8026
+ }
8027
+ .db-pane-empty-icon .octicon {
8028
+ width: 32px;
8029
+ height: 32px;
8030
+ }
8031
+ .db-pane-empty-title {
8032
+ color: var(--fg-muted);
8033
+ font-size: var(--db-font-md);
8034
+ }
8035
+ .db-pane-empty-hint {
8036
+ max-width: 320px;
8037
+ color: var(--fg-subtle);
8038
+ font-size: var(--db-font-sm);
8039
+ line-height: 1.5;
8040
+ }
7576
8041
 
7577
8042
  /* ---------- Elasticsearch explorer ---------- */
7578
8043
  .es-explorer {
@@ -7586,13 +8051,14 @@ body.db-resizing {
7586
8051
  .es-explorer[hidden] {
7587
8052
  display: none;
7588
8053
  }
8054
+ /* es-index-list-pane は redis-db-list-pane と同じく db-sidebar の
8055
+ explorerSidebarHost 内にスロットとして mount される。 */
7589
8056
  .es-index-list-pane {
7590
- width: 260px;
7591
- border-right: 1px solid var(--border);
8057
+ flex: 1 1 auto;
8058
+ min-height: 120px;
7592
8059
  display: flex;
7593
8060
  flex-direction: column;
7594
8061
  overflow: hidden;
7595
- background: var(--bg-soft);
7596
8062
  }
7597
8063
  .es-index-list {
7598
8064
  flex: 1;
@@ -7815,31 +8281,43 @@ body.db-resizing {
7815
8281
  .s3-explorer[hidden] {
7816
8282
  display: none;
7817
8283
  }
7818
- .s3-object-list-pane {
7819
- width: 420px;
7820
- border-right: 1px solid var(--border);
8284
+ /* List/Explorer 共通: Bucket / View seg / Search / Prefix・Contains / sort /
8285
+ objectList / tree がすべて sidebarSlot に積まれる。
8286
+ 下記 .s3-search-row / .s3-options-row は flex 行なので [hidden] 属性
8287
+ (UA の display:none) を明示で上書きしないと消えないことに注意。 */
8288
+ .s3-search-row,
8289
+ .s3-options-row {
7821
8290
  display: flex;
7822
- flex-direction: column;
7823
- overflow: hidden;
7824
- background: var(--bg);
8291
+ align-items: center;
8292
+ gap: 8px;
8293
+ min-width: 0;
7825
8294
  }
7826
- .s3-toolbar {
7827
- flex-shrink: 0;
7828
- display: flex;
7829
- flex-direction: column;
8295
+ .s3-search-row[hidden],
8296
+ .s3-options-row[hidden] {
8297
+ display: none;
8298
+ }
8299
+ /* s3-bucket-row は db-sidebar の explorerSidebarHost に mount される。260px
8300
+ 幅でも Bucket label + select + List/Explorer seg が綺麗に収まるよう、縦並び
8301
+ (label+select の行 / seg の行) にする。
8302
+ Explorer モードでは下に tree がぶら下がるため、flex column で残り高さを
8303
+ tree に渡せるようにする (`.db-explorer-sidebar-slot` の flex:1 と組合せ)。 */
8304
+ .s3-sidebar-slot {
8305
+ padding: 8px;
7830
8306
  gap: 8px;
7831
- padding: 10px 12px;
7832
- border-bottom: 1px solid var(--border);
7833
- background: var(--bg-soft);
7834
8307
  }
7835
- .s3-bucket-row,
7836
- .s3-search-row,
7837
- .s3-options-row {
8308
+ .s3-bucket-row {
7838
8309
  display: flex;
7839
- align-items: center;
8310
+ flex-direction: column;
7840
8311
  gap: 8px;
7841
8312
  min-width: 0;
7842
8313
  }
8314
+ .s3-bucket-row .s3-view-seg {
8315
+ align-self: stretch;
8316
+ display: flex;
8317
+ }
8318
+ .s3-bucket-row .s3-view-seg button {
8319
+ flex: 1;
8320
+ }
7843
8321
  .s3-field-label {
7844
8322
  flex: 1;
7845
8323
  min-width: 0;
@@ -7883,23 +8361,26 @@ body.db-resizing {
7883
8361
  padding: 4px 8px;
7884
8362
  }
7885
8363
  .s3-object-status {
7886
- min-height: 26px;
7887
- padding: 6px 12px;
7888
- border-bottom: 1px solid var(--border);
8364
+ min-height: 22px;
8365
+ padding: 4px 0;
7889
8366
  color: var(--fg-muted);
7890
8367
  font-size: var(--db-font-sm);
7891
- background: var(--bg);
7892
8368
  flex-shrink: 0;
7893
8369
  }
7894
8370
  .s3-object-status.warn {
7895
8371
  color: #8a5a22;
7896
8372
  background: #fff4e0;
7897
8373
  }
8374
+ /* sidebarSlot 内で残り高さを取り、スクロール可能にする。横の負 margin で
8375
+ sidebarSlot の左右 padding を相殺してフルブリードにする (アイテムの border
8376
+ が sidebar の幅一杯まで届くように)。 */
7898
8377
  .s3-object-list {
7899
- flex: 1;
7900
- min-height: 0;
8378
+ flex: 1 1 auto;
8379
+ min-height: 120px;
7901
8380
  overflow-y: auto;
7902
8381
  padding: 4px 0;
8382
+ margin: 0 -8px;
8383
+ border-top: 1px solid var(--border);
7903
8384
  }
7904
8385
  .s3-object-item {
7905
8386
  display: flex;
@@ -7918,7 +8399,24 @@ body.db-resizing {
7918
8399
  background: var(--bg-active, var(--bg-soft));
7919
8400
  border-left-color: var(--accent);
7920
8401
  }
8402
+ /* 1 行目: 親パス (薄)。サイドバー狭幅でも末尾が見える ellipsis のみ。 */
8403
+ .s3-object-parent {
8404
+ overflow: hidden;
8405
+ text-overflow: ellipsis;
8406
+ white-space: nowrap;
8407
+ font-family: var(--mono, monospace);
8408
+ font-size: 10px;
8409
+ color: var(--fg-muted);
8410
+ line-height: 1.3;
8411
+ }
8412
+ .s3-object-head {
8413
+ display: flex;
8414
+ align-items: center;
8415
+ gap: 6px;
8416
+ min-width: 0;
8417
+ }
7921
8418
  .s3-object-name {
8419
+ flex: 1 1 auto;
7922
8420
  overflow: hidden;
7923
8421
  text-overflow: ellipsis;
7924
8422
  white-space: nowrap;
@@ -7933,8 +8431,59 @@ body.db-resizing {
7933
8431
  color: var(--fg-muted);
7934
8432
  font-size: var(--db-font-sm);
7935
8433
  }
8434
+
8435
+ /* List / Explorer 共通: 行ホバーで全 key を floating で出す。document.body
8436
+ に attach するので、sidebar 外 (preview pane 側) へ突き出して読める。 */
8437
+ .s3-key-tooltip {
8438
+ position: fixed;
8439
+ z-index: 9999;
8440
+ max-width: 360px;
8441
+ padding: 10px 12px;
8442
+ background: var(--bg);
8443
+ color: var(--fg);
8444
+ border: 1px solid var(--border);
8445
+ border-radius: 6px;
8446
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
8447
+ pointer-events: none;
8448
+ font-size: var(--db-font-sm);
8449
+ }
8450
+ .s3-key-tooltip[hidden] {
8451
+ display: none;
8452
+ }
8453
+ .s3-key-tooltip-image {
8454
+ display: block;
8455
+ max-width: 336px;
8456
+ max-height: 240px;
8457
+ width: auto;
8458
+ height: auto;
8459
+ margin: -2px 0 8px;
8460
+ border-radius: 4px;
8461
+ background: var(--bg-soft);
8462
+ }
8463
+ .s3-key-tooltip-path {
8464
+ font-family: var(--mono, monospace);
8465
+ font-size: var(--db-font-mono);
8466
+ word-break: break-all;
8467
+ line-height: 1.4;
8468
+ }
8469
+ .s3-key-tooltip-meta {
8470
+ margin-top: 6px;
8471
+ padding-top: 6px;
8472
+ border-top: 1px solid var(--border);
8473
+ color: var(--fg-muted);
8474
+ }
8475
+
8476
+ /* tooltip 切替トグル: bucketRow 内 (Bucket select + List/Explorer の下) の
8477
+ 小さなボタン。active 時はアクセントで強調。 */
8478
+ /* s3 explorer の Hover preview トグル: 共通 .db-pref-toggle を併用する。
8479
+ ここでは bucketRow (column flex) 内で stretch しないように align-self
8480
+ だけ上書き。ラベルクラスも .db-pref-toggle-label と同等。 */
8481
+ .s3-tooltip-toggle {
8482
+ align-self: flex-start;
8483
+ }
7936
8484
  .s3-object-more-btn {
7937
8485
  padding: 6px;
8486
+ margin: 0 -8px -8px;
7938
8487
  border: none;
7939
8488
  border-top: 1px solid var(--border);
7940
8489
  background: var(--bg-soft);
@@ -7949,6 +8498,205 @@ body.db-resizing {
7949
8498
  cursor: default;
7950
8499
  color: var(--fg-muted);
7951
8500
  }
8501
+
8502
+ /* ファイル種別がひと目で分かる色付きバッジ (List / Explorer 共通)。 */
8503
+ .s3-kind-badge {
8504
+ flex: 0 0 auto;
8505
+ display: inline-flex;
8506
+ align-items: center;
8507
+ padding: 0 6px;
8508
+ height: 16px;
8509
+ border-radius: 999px;
8510
+ border: 1px solid transparent;
8511
+ font-size: 10px;
8512
+ font-weight: 600;
8513
+ line-height: 1;
8514
+ letter-spacing: 0.02em;
8515
+ text-transform: uppercase;
8516
+ white-space: nowrap;
8517
+ user-select: none;
8518
+ }
8519
+ /* 色は意味別のテーマトークンを使い、ダークモードでも自動で追従させる
8520
+ (背景/縁も同じトークンを color-mix することで theme 変数の切替に乗る)。 */
8521
+ .s3-kind-badge.kind-image {
8522
+ color: var(--success);
8523
+ background: color-mix(in srgb, var(--success) 12%, var(--bg));
8524
+ border-color: color-mix(in srgb, var(--success) 35%, transparent);
8525
+ }
8526
+ .s3-kind-badge.kind-video {
8527
+ color: var(--done);
8528
+ background: color-mix(in srgb, var(--done) 12%, var(--bg));
8529
+ border-color: color-mix(in srgb, var(--done) 35%, transparent);
8530
+ }
8531
+ .s3-kind-badge.kind-audio {
8532
+ color: var(--attn);
8533
+ background: color-mix(in srgb, var(--attn) 12%, var(--bg));
8534
+ border-color: color-mix(in srgb, var(--attn) 35%, transparent);
8535
+ }
8536
+ .s3-kind-badge.kind-pdf {
8537
+ color: var(--danger);
8538
+ background: color-mix(in srgb, var(--danger) 12%, var(--bg));
8539
+ border-color: color-mix(in srgb, var(--danger) 35%, transparent);
8540
+ }
8541
+ .s3-kind-badge.kind-text {
8542
+ color: var(--accent);
8543
+ background: color-mix(in srgb, var(--accent) 12%, var(--bg));
8544
+ border-color: color-mix(in srgb, var(--accent) 35%, transparent);
8545
+ }
8546
+ .s3-kind-badge.kind-binary {
8547
+ color: var(--fg-muted);
8548
+ background: var(--bg-soft);
8549
+ border-color: var(--border);
8550
+ }
8551
+
8552
+ /* List / Explorer 切替セグメント。 */
8553
+ .s3-view-seg {
8554
+ flex-shrink: 0;
8555
+ }
8556
+
8557
+ /* Explorer 表示: 既存ファイルツリー (#filelist.tree) の見た目を S3 ペインに
8558
+ 合わせて再現したもの。クラス名は共通 (.tree-dir / .tree-file / .chev ...)。
8559
+ sidebar 内の sidebarSlot に置かれるため、flex で残りの高さを満たし、
8560
+ スクロール可能にする。padding をなくし、sidebarSlot の余白に揃える。 */
8561
+ .s3-tree {
8562
+ --lvl-pad: 12px;
8563
+ flex: 1 1 auto;
8564
+ min-height: 120px;
8565
+ overflow-y: auto;
8566
+ padding: 4px 0;
8567
+ margin: 0 -8px -8px;
8568
+ border-top: 1px solid var(--border);
8569
+ }
8570
+ .s3-tree[hidden] {
8571
+ display: none;
8572
+ }
8573
+ .s3-tree .s3-tree-node {
8574
+ min-width: 0;
8575
+ }
8576
+ .s3-tree .tree-children {
8577
+ list-style: none;
8578
+ margin: 0;
8579
+ padding: 0;
8580
+ }
8581
+ .s3-tree .tree-dir.collapsed + .tree-children {
8582
+ display: none;
8583
+ }
8584
+ .s3-tree .tree-dir {
8585
+ display: grid;
8586
+ grid-template-columns: 16px 16px minmax(0, 1fr);
8587
+ align-items: center;
8588
+ gap: 8px;
8589
+ padding: 4px 6px 4px var(--lvl-pad, 12px);
8590
+ border-radius: 6px;
8591
+ cursor: pointer;
8592
+ user-select: none;
8593
+ color: var(--fg);
8594
+ }
8595
+ .s3-tree .tree-dir:hover {
8596
+ background: var(--bg-hover, var(--bg-soft));
8597
+ }
8598
+ .s3-tree .tree-dir .chev {
8599
+ display: flex;
8600
+ width: 16px;
8601
+ height: 16px;
8602
+ align-items: center;
8603
+ justify-content: center;
8604
+ color: var(--fg-muted);
8605
+ transition: transform 0.15s;
8606
+ }
8607
+ .s3-tree .tree-dir.collapsed .chev {
8608
+ transform: rotate(-90deg);
8609
+ }
8610
+ .s3-tree .tree-dir .chev .octicon {
8611
+ width: 12px;
8612
+ height: 12px;
8613
+ display: block;
8614
+ }
8615
+ .s3-tree .tree-dir .dir-icon {
8616
+ color: #54aeff;
8617
+ width: 16px;
8618
+ height: 16px;
8619
+ display: grid;
8620
+ align-items: center;
8621
+ justify-content: center;
8622
+ }
8623
+ .s3-tree .tree-dir .dir-icon .octicon {
8624
+ display: block;
8625
+ }
8626
+ .s3-tree .tree-dir .dir-label {
8627
+ min-width: 0;
8628
+ display: flex;
8629
+ align-items: center;
8630
+ overflow: hidden;
8631
+ }
8632
+ .s3-tree .tree-dir .dir-name {
8633
+ min-width: 0;
8634
+ overflow: hidden;
8635
+ text-overflow: ellipsis;
8636
+ white-space: nowrap;
8637
+ font-family: var(--mono, monospace);
8638
+ font-size: var(--db-font-mono);
8639
+ }
8640
+ .s3-tree .tree-file {
8641
+ display: grid;
8642
+ grid-template-columns: 16px auto minmax(0, 1fr);
8643
+ align-items: center;
8644
+ gap: 8px;
8645
+ padding: 4px 6px 4px var(--lvl-pad, 12px);
8646
+ border-left: 2px solid transparent;
8647
+ cursor: pointer;
8648
+ user-select: none;
8649
+ color: var(--fg);
8650
+ }
8651
+ .s3-tree .tree-file:hover {
8652
+ background: var(--bg-hover, var(--bg-soft));
8653
+ }
8654
+ .s3-tree .tree-file.active {
8655
+ background: var(--bg-active, var(--bg-soft));
8656
+ border-left-color: var(--accent);
8657
+ }
8658
+ .s3-tree .tree-file .chev-spacer {
8659
+ width: 16px;
8660
+ height: 1px;
8661
+ }
8662
+ .s3-tree .tree-file .name {
8663
+ min-width: 0;
8664
+ overflow: hidden;
8665
+ text-overflow: ellipsis;
8666
+ white-space: nowrap;
8667
+ font-family: var(--mono, monospace);
8668
+ font-size: var(--db-font-mono);
8669
+ }
8670
+ .s3-tree .s3-tree-more {
8671
+ display: block;
8672
+ width: calc(100% - 12px);
8673
+ margin: 2px 6px;
8674
+ padding: 4px 6px 4px var(--lvl-pad, 12px);
8675
+ border: none;
8676
+ border-radius: 6px;
8677
+ background: var(--bg-soft);
8678
+ color: var(--accent);
8679
+ font-size: var(--db-font-sm);
8680
+ text-align: left;
8681
+ cursor: pointer;
8682
+ }
8683
+ .s3-tree .s3-tree-more:hover {
8684
+ background: var(--bg-hover, var(--bg));
8685
+ }
8686
+ .s3-tree .s3-tree-more:disabled {
8687
+ cursor: default;
8688
+ color: var(--fg-muted);
8689
+ }
8690
+ .s3-tree .s3-tree-empty,
8691
+ .s3-tree .s3-tree-loading,
8692
+ .s3-tree .s3-tree-error {
8693
+ padding: 4px 6px 4px var(--lvl-pad, 12px);
8694
+ color: var(--fg-muted);
8695
+ font-size: var(--db-font-sm);
8696
+ }
8697
+ .s3-tree .s3-tree-error {
8698
+ color: var(--danger);
8699
+ }
7952
8700
  .s3-preview-pane {
7953
8701
  flex: 1;
7954
8702
  min-width: 0;