claude-code-kanban 4.25.0 → 4.27.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/public/index.html CHANGED
@@ -5,6 +5,11 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>CC Kanban</title>
7
7
  <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='6' fill='%231a1a1a'/%3E%3Crect x='4' y='6' width='7' height='20' rx='2' fill='%23e8927c'/%3E%3Crect x='13' y='6' width='7' height='14' rx='2' fill='%23e8927c'/%3E%3Crect x='22' y='6' width='7' height='8' rx='2' fill='%23e8927c'/%3E%3C/svg%3E">
8
+ <!-- Chrome uses the SVG only in the tab strip; app windows, shortcuts and the
9
+ history list need a raster icon or they fall back to /favicon.ico and then to
10
+ whatever icon localhost was last seen with, which is a sibling app's. -->
11
+ <link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png">
12
+ <link rel="icon" type="image/png" sizes="512x512" href="/icons/icon-512.png">
8
13
  <link rel="manifest" href="/manifest.json">
9
14
  <meta name="theme-color" content="#101114" media="(prefers-color-scheme: dark)">
10
15
  <meta name="theme-color" content="#e8e6e3" media="(prefers-color-scheme: light)">
@@ -60,6 +65,20 @@
60
65
  <span class="section-header-label">Sessions</span>
61
66
  <span id="filter-summary" class="filter-summary" title=""></span>
62
67
  <span class="section-header-actions">
68
+ <button
69
+ id="zen-mode-btn"
70
+ class="icon-btn section-btn"
71
+ onclick="event.stopPropagation(); toggleZenMode()"
72
+ title="Zen mode: current session only (Shift+Z)"
73
+ aria-label="Zen mode: current session only"
74
+ aria-pressed="false"
75
+ >
76
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
77
+ <circle cx="12" cy="12" r="7"/>
78
+ <circle cx="12" cy="12" r="2"/>
79
+ <path d="M12 1v3M12 20v3M1 12h3M20 12h3"/>
80
+ </svg>
81
+ </button>
63
82
  <button
64
83
  id="filter-menu-btn"
65
84
  class="icon-btn section-btn"
package/public/style.css CHANGED
@@ -9,6 +9,9 @@
9
9
  --bg-surface: #16181c;
10
10
  --bg-elevated: #1e2025;
11
11
  --bg-hover: #282a30;
12
+ /* Selection reads as a recess against the darker surface here, but light theme's deep tone
13
+ sits within a shade of the sidebar, so there it has to rise instead. */
14
+ --session-active-bg: var(--bg-deep);
12
15
  --border: #363840;
13
16
  --text-primary: #f0f1f3;
14
17
  --text-secondary: #c2c4c9;
@@ -440,7 +443,8 @@ body::before {
440
443
  }
441
444
 
442
445
  /* Ember only while something is actually filtered — at rest the funnel is just chrome. */
443
- .icon-btn.section-btn.has-filters {
446
+ .icon-btn.section-btn.has-filters,
447
+ .icon-btn.section-btn.active {
444
448
  color: var(--accent-text);
445
449
  }
446
450
 
@@ -575,17 +579,18 @@ body::before {
575
579
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
576
580
  }
577
581
 
578
- /* `.active` is the open session, `.kb-selected` the keyboard cursor. The cursor
579
- must win when both land on one card, which is why it is ordered second. */
582
+ /* `.active` is the open session, `.kb-selected` the keyboard cursor. They own different
583
+ properties — fill and border — so the cursor landing on the open session adds to it
584
+ instead of replacing how it looks. */
580
585
  .session-item.active {
581
- background: var(--bg-deep);
582
- border-color: var(--accent);
586
+ background: var(--session-active-bg);
583
587
  }
584
588
 
585
589
  .session-item.kb-selected {
586
- background: var(--bg-elevated);
587
590
  border-color: var(--accent);
588
- box-shadow: 0 0 0 1px var(--accent-dim);
591
+ box-shadow:
592
+ inset 0 0 0 1px var(--accent),
593
+ 0 0 10px var(--accent-glow);
589
594
  }
590
595
 
591
596
  .session-item.stale {
@@ -633,7 +638,8 @@ body::before {
633
638
  }
634
639
 
635
640
  .session-name {
636
- font-size: 13px;
641
+ font-size: 14px;
642
+ font-weight: 500;
637
643
  color: var(--text-primary);
638
644
  white-space: nowrap;
639
645
  overflow: hidden;
@@ -642,7 +648,9 @@ body::before {
642
648
  padding-right: 22px;
643
649
  }
644
650
 
645
- .session-indicators .pulse {
651
+ .session-indicators .pulse,
652
+ .wf-live-name .pulse {
653
+ flex: none;
646
654
  width: 6px;
647
655
  height: 6px;
648
656
  background: var(--accent);
@@ -671,6 +679,26 @@ body::before {
671
679
  overflow: hidden;
672
680
  }
673
681
 
682
+ /* inline-block, not inline-flex: a flex box ignores text-overflow, so a long worktree name
683
+ ran past the card edge instead of truncating. */
684
+ .wt-chip {
685
+ display: inline-block;
686
+ max-width: 60%;
687
+ margin-left: 5px;
688
+ padding: 0 5px;
689
+ border: 1px solid var(--accent-dim);
690
+ border-radius: 999px;
691
+ background: var(--accent-dim);
692
+ color: var(--accent-text);
693
+ font-family: var(--mono);
694
+ font-size: 9px;
695
+ line-height: 14px;
696
+ vertical-align: middle;
697
+ white-space: nowrap;
698
+ overflow: hidden;
699
+ text-overflow: ellipsis;
700
+ }
701
+
674
702
  .session-branch {
675
703
  font-size: 10px;
676
704
  color: var(--text-secondary);
@@ -746,7 +774,10 @@ body::before {
746
774
  transition: width 0.5s ease-out;
747
775
  }
748
776
 
749
- .session-item:not(.active) .progress-fill {
777
+ /* The live-workflow bar takes the muted fill too: its card already carries a pulsing
778
+ accent dot, and a second accent bar under it shouts. */
779
+ .session-item:not(.active) .progress-fill,
780
+ .wf-live-bar .progress-fill {
750
781
  background: color-mix(in srgb, var(--text-tertiary) 55%, transparent);
751
782
  }
752
783
 
@@ -858,6 +889,57 @@ body::before {
858
889
  color: var(--text-secondary);
859
890
  }
860
891
 
892
+ /* Zen view: the sidebar holds one card, so the usage detail that normally lives behind the
893
+ info modal gets rendered underneath it. */
894
+ .zen-panel {
895
+ margin-top: 10px;
896
+ /* No bottom padding: the linked-docs section that always closes the panel carries its own. */
897
+ padding: 10px 10px 0;
898
+ background: var(--bg-elevated);
899
+ border: 1px solid var(--border);
900
+ border-radius: 8px;
901
+ }
902
+
903
+ .zen-panel .detail-context {
904
+ margin-bottom: 0;
905
+ }
906
+
907
+ .zen-panel .detail-context-stats {
908
+ gap: 3px 10px;
909
+ }
910
+
911
+ .zen-scratchpad {
912
+ display: flex;
913
+ align-items: center;
914
+ gap: 8px;
915
+ margin-top: 12px;
916
+ padding-top: 10px;
917
+ border-top: 1px solid var(--border);
918
+ font-size: 11px;
919
+ }
920
+
921
+ .zen-scratchpad-label {
922
+ font-weight: 500;
923
+ color: var(--text-muted);
924
+ text-transform: uppercase;
925
+ letter-spacing: 0.5px;
926
+ white-space: nowrap;
927
+ }
928
+
929
+ .zen-scratchpad-path {
930
+ flex: 1;
931
+ min-width: 0;
932
+ overflow: hidden;
933
+ text-overflow: ellipsis;
934
+ white-space: nowrap;
935
+ font-family: var(--font-mono);
936
+ color: var(--text-secondary);
937
+ }
938
+
939
+ .zen-panel:hover .row-actions {
940
+ opacity: 1;
941
+ }
942
+
861
943
  .session-time {
862
944
  font-size: 11px;
863
945
  font-weight: 450;
@@ -3818,7 +3900,9 @@ body::before {
3818
3900
  color: var(--text-primary);
3819
3901
  }
3820
3902
 
3821
- .linked-doc-list {
3903
+ .linked-doc-list,
3904
+ .scratch-file-list,
3905
+ .artifact-list {
3822
3906
  list-style: none;
3823
3907
  padding: 0;
3824
3908
  margin: 0;
@@ -3827,18 +3911,26 @@ body::before {
3827
3911
  gap: 4px;
3828
3912
  }
3829
3913
 
3830
- .linked-doc-item {
3914
+ .linked-doc-item,
3915
+ .scratch-file-item,
3916
+ .artifact-item {
3831
3917
  display: flex;
3832
3918
  align-items: baseline;
3833
3919
  gap: 8px;
3834
3920
  min-width: 0;
3835
3921
  }
3836
3922
 
3837
- .linked-doc-link {
3923
+ .linked-doc-link,
3924
+ .scratch-file-link,
3925
+ .artifact-link {
3838
3926
  color: var(--accent-text);
3839
3927
  text-decoration: underline;
3840
3928
  text-decoration-style: dotted;
3841
3929
  text-underline-offset: 3px;
3930
+ }
3931
+
3932
+ .linked-doc-link,
3933
+ .artifact-link {
3842
3934
  flex-shrink: 0;
3843
3935
  }
3844
3936
 
@@ -3852,19 +3944,87 @@ body::before {
3852
3944
  min-width: 0;
3853
3945
  }
3854
3946
 
3947
+ .scratch-file-time {
3948
+ color: var(--text-muted);
3949
+ font-size: 11px;
3950
+ opacity: 0.7;
3951
+ white-space: nowrap;
3952
+ flex-shrink: 0;
3953
+ }
3954
+
3855
3955
  /* Rides on the shared .row-actions group; only the reveal trigger differs — per row
3856
3956
  here, per grid in the session info. margin-left:auto pins the group to the same
3857
3957
  right edge however long the names in between are. */
3858
- .linked-doc-actions {
3958
+ .linked-doc-actions,
3959
+ .scratch-file-actions,
3960
+ .artifact-actions {
3859
3961
  margin-left: auto;
3860
3962
  align-self: center;
3861
3963
  flex-shrink: 0;
3964
+ /* Two .row-actions buttons wide (22px each, 4px gap), filled from the left, so a
3965
+ row with one action puts it in the same column as the rows that have two. */
3966
+ min-width: 48px;
3967
+ justify-content: flex-start;
3862
3968
  }
3863
3969
 
3864
- .linked-doc-item:hover .linked-doc-actions {
3970
+ .linked-doc-item:hover .linked-doc-actions,
3971
+ .scratch-file-item:hover .scratch-file-actions,
3972
+ .artifact-item:hover .artifact-actions {
3865
3973
  opacity: 1;
3866
3974
  }
3867
3975
 
3976
+ /* Hangs off the Scratchpad path row, so it carries no header of its own. */
3977
+ .scratch-files-section {
3978
+ margin-top: 6px;
3979
+ font-size: 11px;
3980
+ }
3981
+
3982
+ .scratch-file-link {
3983
+ background: none;
3984
+ border: none;
3985
+ padding: 0;
3986
+ font: inherit;
3987
+ cursor: pointer;
3988
+ text-align: left;
3989
+ /* A scratch name can be longer than the zen panel is wide; without this it pushes
3990
+ the action buttons out of their column. The full path is on the title. */
3991
+ min-width: 0;
3992
+ overflow: hidden;
3993
+ text-overflow: ellipsis;
3994
+ white-space: nowrap;
3995
+ }
3996
+
3997
+ .scratch-files-more {
3998
+ margin: 6px 0 0;
3999
+ font-size: 11px;
4000
+ }
4001
+
4002
+ /* A folder row wraps so its child list lands on its own full-width line under the
4003
+ name, indented one chevron in. */
4004
+ .scratch-folder-item {
4005
+ flex-wrap: wrap;
4006
+ }
4007
+
4008
+ .scratch-folder-item > .scratch-file-list,
4009
+ .scratch-folder-item > .scratch-folder-empty {
4010
+ flex-basis: 100%;
4011
+ margin-top: 4px;
4012
+ padding-left: 14px;
4013
+ }
4014
+
4015
+ .scratch-folder-empty {
4016
+ color: var(--text-muted);
4017
+ opacity: 0.7;
4018
+ }
4019
+
4020
+ .scratch-folder-toggle {
4021
+ display: inline-flex;
4022
+ align-items: center;
4023
+ gap: 4px;
4024
+ text-decoration: none;
4025
+ color: var(--text-secondary);
4026
+ }
4027
+
3868
4028
  /* The × is a glyph, not an svg, so .row-actions button svg does not size it. */
3869
4029
  .linked-doc-remove {
3870
4030
  font-family: var(--mono);
@@ -3885,7 +4045,147 @@ body::before {
3885
4045
  text-decoration-style: dashed;
3886
4046
  }
3887
4047
 
3888
- .linked-docs-empty {
4048
+ /* A section of the session panel: linked documents, artifacts. */
4049
+ .panel-section {
4050
+ margin-bottom: 16px;
4051
+ padding-top: 10px;
4052
+ border-top: 1px solid var(--border);
4053
+ font-size: 11px;
4054
+ }
4055
+
4056
+ .linked-docs-section {
4057
+ margin-top: 12px;
4058
+ }
4059
+
4060
+ /* Artifacts are read out of the transcript, so the section renders before the
4061
+ list arrives and stays in the DOM as the patch target when there is none. */
4062
+ .artifacts-section:empty,
4063
+ .scratch-files-section:empty,
4064
+ .workflow-live-section:empty {
4065
+ display: none;
4066
+ }
4067
+
4068
+ /* Its own card below the zen panel — the run is live state, not session detail, so it
4069
+ comes and goes on its own while the panel above stays put. */
4070
+ .workflow-live-section {
4071
+ margin-top: 10px;
4072
+ padding: 10px;
4073
+ background: var(--bg-elevated);
4074
+ border: 1px solid var(--border);
4075
+ border-radius: 8px;
4076
+ font-size: 11px;
4077
+ }
4078
+
4079
+ .wf-live {
4080
+ cursor: pointer;
4081
+ }
4082
+
4083
+ .wf-live-name {
4084
+ display: flex;
4085
+ align-items: center;
4086
+ gap: 6px;
4087
+ font-size: 12px;
4088
+ font-weight: 500;
4089
+ color: var(--text-primary);
4090
+ overflow: hidden;
4091
+ text-overflow: ellipsis;
4092
+ white-space: nowrap;
4093
+ }
4094
+
4095
+ .wf-live-bar {
4096
+ margin: 6px 0;
4097
+ }
4098
+
4099
+ .wf-live-phases {
4100
+ display: flex;
4101
+ flex-wrap: wrap;
4102
+ gap: 4px;
4103
+ }
4104
+
4105
+ /* A phase reads as one chip, so the dot goes in ::before rather than costing a span. */
4106
+ .wf-live-phase {
4107
+ display: flex;
4108
+ align-items: center;
4109
+ gap: 4px;
4110
+ padding: 1px 6px;
4111
+ border: 1px solid var(--border);
4112
+ border-radius: 10px;
4113
+ font-size: 10px;
4114
+ color: var(--text-secondary);
4115
+ }
4116
+
4117
+ .wf-live-phase::before {
4118
+ content: '';
4119
+ width: 5px;
4120
+ height: 5px;
4121
+ border-radius: 50%;
4122
+ background: var(--text-muted);
4123
+ }
4124
+
4125
+ .wf-live-phase.running::before {
4126
+ background: var(--accent);
4127
+ animation: pulse 2s ease-in-out infinite;
4128
+ }
4129
+
4130
+ .wf-live-phase.done::before {
4131
+ background: var(--ok, #3fb950);
4132
+ }
4133
+
4134
+ .wf-live-phase.done {
4135
+ color: var(--text-muted);
4136
+ }
4137
+
4138
+ .wf-live-phase-count {
4139
+ font-family: var(--font-mono);
4140
+ }
4141
+
4142
+ .wf-live-running {
4143
+ margin-top: 6px;
4144
+ overflow: hidden;
4145
+ text-overflow: ellipsis;
4146
+ white-space: nowrap;
4147
+ font-family: var(--font-mono);
4148
+ font-size: 10px;
4149
+ color: var(--text-muted);
4150
+ }
4151
+
4152
+ .panel-section-header {
4153
+ display: flex;
4154
+ align-items: center;
4155
+ gap: 6px;
4156
+ margin-bottom: 6px;
4157
+ font-size: 11px;
4158
+ font-weight: 500;
4159
+ color: var(--text-muted);
4160
+ text-transform: uppercase;
4161
+ letter-spacing: 0.5px;
4162
+ }
4163
+
4164
+ .panel-section-header svg {
4165
+ width: 12px;
4166
+ height: 12px;
4167
+ }
4168
+
4169
+ .panel-section-count {
4170
+ background: var(--bg-elevated);
4171
+ border: 1px solid var(--border);
4172
+ border-radius: 10px;
4173
+ padding: 0 6px;
4174
+ font-size: 10px;
4175
+ color: var(--text-secondary);
4176
+ }
4177
+
4178
+ /* The artifact title is a URL away from the reader, so it truncates where a file
4179
+ name, which the linked-doc row shows in full, does not. */
4180
+ .artifact-link {
4181
+ overflow: hidden;
4182
+ text-overflow: ellipsis;
4183
+ white-space: nowrap;
4184
+ min-width: 0;
4185
+ }
4186
+
4187
+ .linked-docs-empty,
4188
+ .zen-panel-empty {
3889
4189
  color: var(--text-muted);
3890
4190
  font-size: 11px;
3891
4191
  font-style: italic;
@@ -4122,6 +4422,7 @@ body.light {
4122
4422
  --bg-surface: #efede9;
4123
4423
  --bg-elevated: #fbfaf9;
4124
4424
  --bg-hover: #d2d0cc;
4425
+ --session-active-bg: var(--bg-elevated);
4125
4426
  --border: #cfcbc4;
4126
4427
  --text-primary: #0a0a0a;
4127
4428
  --text-secondary: #444444;
@@ -4416,6 +4717,16 @@ body.light .msg-assistant .msg-text {
4416
4717
  padding-right: 8px;
4417
4718
  }
4418
4719
 
4720
+ #preview-modal-body .preview-image {
4721
+ display: block;
4722
+ max-width: 100%;
4723
+ max-height: 70vh;
4724
+ margin: 0 auto;
4725
+ border: 1px solid var(--border);
4726
+ border-radius: 4px;
4727
+ background: var(--bg-hover);
4728
+ }
4729
+
4419
4730
  #preview-modal-meta {
4420
4731
  margin-top: 12px;
4421
4732
  font-size: 11px;
@@ -4459,6 +4770,29 @@ body.light .msg-assistant .msg-text {
4459
4770
  padding-right: 0;
4460
4771
  }
4461
4772
 
4773
+ /* Source is read line by line, so it keeps its own line breaks and scrolls sideways
4774
+ instead of inheriting the body's `word-break: break-word`. */
4775
+ .preview-source {
4776
+ margin: 0;
4777
+ padding: 10px 12px;
4778
+ background: var(--bg-elevated);
4779
+ border: 1px solid var(--border);
4780
+ border-radius: 6px;
4781
+ overflow-x: auto;
4782
+ font-family: var(--mono);
4783
+ font-size: 12px;
4784
+ line-height: 1.55;
4785
+ white-space: pre;
4786
+ word-break: normal;
4787
+ tab-size: 4;
4788
+ }
4789
+
4790
+ .preview-source code {
4791
+ background: none;
4792
+ padding: 0;
4793
+ font: inherit;
4794
+ }
4795
+
4462
4796
  .preview-html-frame {
4463
4797
  width: 100%;
4464
4798
  height: 100%;
@@ -5450,6 +5784,7 @@ select.form-input option:checked {
5450
5784
  --bg-surface: #efede9;
5451
5785
  --bg-elevated: #fbfaf9;
5452
5786
  --bg-hover: #d2d0cc;
5787
+ --session-active-bg: var(--bg-elevated);
5453
5788
  --border: #cfcbc4;
5454
5789
  --text-primary: #0a0a0a;
5455
5790
  --text-secondary: #444444;
@@ -5613,7 +5948,8 @@ pre.mermaid svg {
5613
5948
 
5614
5949
  .project-group-header .group-chevron,
5615
5950
  .session-group-header .group-chevron,
5616
- .sg-section-toggle .group-chevron {
5951
+ .sg-section-toggle .group-chevron,
5952
+ .scratch-folder-toggle .group-chevron {
5617
5953
  transition: transform 0.15s ease;
5618
5954
  flex-shrink: 0;
5619
5955
  display: block;
@@ -5621,7 +5957,8 @@ pre.mermaid svg {
5621
5957
 
5622
5958
  .project-group-header.collapsed .group-chevron,
5623
5959
  .session-group-header.collapsed .group-chevron,
5624
- .sg-section-toggle.collapsed .group-chevron {
5960
+ .sg-section-toggle.collapsed .group-chevron,
5961
+ .scratch-folder-toggle.collapsed .group-chevron {
5625
5962
  transform: rotate(-90deg);
5626
5963
  }
5627
5964