|
1 | 1 | <script lang="ts">
|
2 |
| - import { Badge, Icon, TimeAgo, Tooltip } from '@gitbutler/ui'; |
| 2 | + import { Badge, Icon, TimeAgo, Tooltip, InfoButton } from '@gitbutler/ui'; |
3 | 3 | import { slide } from 'svelte/transition';
|
4 | 4 | import type { ClaudeStatus } from '$lib/codegen/types';
|
5 | 5 | import type { Snippet } from 'svelte';
|
|
15 | 15 | commits: Snippet;
|
16 | 16 | onclick: (e: MouseEvent) => void;
|
17 | 17 | branchIcon: Snippet;
|
| 18 | + totalHeads: number; |
18 | 19 | };
|
19 | 20 |
|
20 | 21 | const {
|
|
27 | 28 | lastInteractionTime,
|
28 | 29 | commits,
|
29 | 30 | onclick,
|
30 |
| - branchIcon |
| 31 | + branchIcon, |
| 32 | + totalHeads |
31 | 33 | }: Props = $props();
|
32 | 34 |
|
33 | 35 | let isOpen = $state(false);
|
34 | 36 | </script>
|
35 | 37 |
|
36 |
| -<div class="sidebar-entry"> |
37 |
| - <button class="sidebar-entry-header" class:selected type="button" {onclick}> |
38 |
| - {#if selected} |
39 |
| - <div class="entry-active-indicator" in:slide={{ axis: 'x', duration: 150 }}></div> |
40 |
| - {/if} |
41 |
| - <div class="sidebar-entry-header-left"> |
42 |
| - {@render branchIcon()} |
| 38 | +<div class="codegen-entry-wrapper"> |
| 39 | + <div class="codegen-entry"> |
| 40 | + <button class="codegen-entry-header" class:selected type="button" {onclick}> |
| 41 | + {#if selected} |
| 42 | + <div class="active-indicator" in:slide={{ axis: 'x', duration: 150 }}></div> |
| 43 | + {/if} |
| 44 | + <div class="entry-header-content"> |
| 45 | + {@render branchIcon()} |
43 | 46 |
|
44 |
| - <p class="text-14 text-bold truncate full-width">{branchName}</p> |
45 |
| - {@render vibeIcon()} |
46 |
| - </div> |
| 47 | + <p class="text-14 text-bold truncate full-width">{branchName}</p> |
| 48 | + {@render vibeIcon()} |
| 49 | + </div> |
47 | 50 |
|
48 |
| - {#if status !== 'disabled'} |
49 |
| - <div class="sidebar-entry-drawer__header-info text-12"> |
50 |
| - <Tooltip text="Total tokens used and cost"> |
51 |
| - <div class="flex gap-4 items-center"> |
52 |
| - <p>{tokensUsed}</p> |
53 |
| - |
54 |
| - <svg |
55 |
| - width="0.938rem" |
56 |
| - height="0.938rem" |
57 |
| - viewBox="0 0 15 15" |
58 |
| - fill="none" |
59 |
| - xmlns="http://www.w3.org/2000/svg" |
60 |
| - opacity="0.6" |
61 |
| - > |
62 |
| - <circle cx="7.5" cy="7.5" r="5.5" stroke="currentColor" stroke-width="1.5" /> |
63 |
| - <circle |
64 |
| - cx="7.50015" |
65 |
| - cy="7.5" |
66 |
| - r="2.92106" |
67 |
| - transform="rotate(-45 7.50015 7.5)" |
68 |
| - stroke="currentColor" |
69 |
| - stroke-width="1.5" |
70 |
| - stroke-dasharray="2 1" |
71 |
| - /> |
72 |
| - </svg> |
73 |
| - |
74 |
| - <div class="sidebar-entry-drawer__header-info__divider"></div> |
75 |
| - <p>${cost.toFixed(2)}</p> |
| 51 | + {#if status !== 'disabled'} |
| 52 | + <div class="entry-metadata text-12"> |
| 53 | + <Tooltip text="Total tokens used and cost"> |
| 54 | + <div class="flex gap-4 items-center"> |
| 55 | + <p>{tokensUsed}</p> |
| 56 | + |
| 57 | + <svg |
| 58 | + width="0.938rem" |
| 59 | + height="0.938rem" |
| 60 | + viewBox="0 0 15 15" |
| 61 | + fill="none" |
| 62 | + xmlns="http://www.w3.org/2000/svg" |
| 63 | + opacity="0.6" |
| 64 | + > |
| 65 | + <circle cx="7.5" cy="7.5" r="5.5" stroke="currentColor" stroke-width="1.5" /> |
| 66 | + <circle |
| 67 | + cx="7.50015" |
| 68 | + cy="7.5" |
| 69 | + r="2.92106" |
| 70 | + transform="rotate(-45 7.50015 7.5)" |
| 71 | + stroke="currentColor" |
| 72 | + stroke-width="1.5" |
| 73 | + stroke-dasharray="2 1" |
| 74 | + /> |
| 75 | + </svg> |
| 76 | + |
| 77 | + <div class="metadata-divider"></div> |
| 78 | + <p>${cost.toFixed(2)}</p> |
| 79 | + </div> |
| 80 | + </Tooltip> |
| 81 | + |
| 82 | + {#if lastInteractionTime} |
| 83 | + <p class="text-11 last-interaction-time opacity-60"> |
| 84 | + <TimeAgo date={lastInteractionTime} addSuffix /> |
| 85 | + </p> |
| 86 | + {/if} |
| 87 | + </div> |
| 88 | + {/if} |
| 89 | + </button> |
| 90 | + |
| 91 | + {#if commitCount > 0} |
| 92 | + <div class="commits-drawer"> |
| 93 | + <button class="commits-drawer-header" onclick={() => (isOpen = !isOpen)} type="button"> |
| 94 | + <div class="fold-icon" class:open={isOpen}> |
| 95 | + <Icon name="chevron-right" /> |
76 | 96 | </div>
|
77 |
| - </Tooltip> |
| 97 | + <p class="text-13 text-semibold">Commits</p> |
| 98 | + <Badge kind="soft">{commitCount}</Badge> |
| 99 | + </button> |
78 | 100 |
|
79 |
| - {#if lastInteractionTime} |
80 |
| - <p class="text-11 sidebar-entry-drawer__tima-ago opacity-60"> |
81 |
| - <TimeAgo date={lastInteractionTime} addSuffix /> |
82 |
| - </p> |
| 101 | + {#if isOpen} |
| 102 | + <div class="stack-v full-width" transition:slide|local={{ duration: 150, axis: 'y' }}> |
| 103 | + <div class="commits-list"> |
| 104 | + {@render commits()} |
| 105 | + </div> |
| 106 | + </div> |
83 | 107 | {/if}
|
84 | 108 | </div>
|
85 | 109 | {/if}
|
86 |
| - </button> |
| 110 | + </div> |
87 | 111 |
|
88 |
| - {#if commitCount > 0} |
89 |
| - <div class="sidebar-entry-drawer"> |
90 |
| - <button class="sidebar-entry-drawer__header" onclick={() => (isOpen = !isOpen)} type="button"> |
91 |
| - <div class="sidebar-entry-drawer__header__fold-icon" class:open={isOpen}> |
92 |
| - <Icon name="chevron-right" /> |
93 |
| - </div> |
94 |
| - <p class="text-13 text-semibold">Commits</p> |
95 |
| - <Badge kind="soft">{commitCount}</Badge> |
96 |
| - </button> |
97 |
| - |
98 |
| - {#if isOpen} |
99 |
| - <div class="stack-v full-width" transition:slide|local={{ duration: 150, axis: 'y' }}> |
100 |
| - <div class="sidebar-entry-drawer__commits"> |
101 |
| - {@render commits()} |
102 |
| - </div> |
103 |
| - </div> |
104 |
| - {/if} |
| 112 | + {#if totalHeads > 1} |
| 113 | + <div class="entry-heads"> |
| 114 | + <Icon name="stack" color="var(--clr-text-3)" /> |
| 115 | + <p class="text-12 text-semibold full-width">{totalHeads - 1} more branches in stack</p> |
| 116 | + |
| 117 | + <InfoButton> |
| 118 | + Currently GitButler doesn’t support multiple sessions for a stack. A session is applied only |
| 119 | + to the top branch. |
| 120 | + </InfoButton> |
105 | 121 | </div>
|
106 | 122 | {/if}
|
107 | 123 | </div>
|
|
117 | 133 | {/snippet}
|
118 | 134 |
|
119 | 135 | <style lang="postcss">
|
120 |
| - .sidebar-entry { |
| 136 | + .codegen-entry-wrapper { |
| 137 | + display: flex; |
| 138 | + flex-direction: column; |
| 139 | + align-items: center; |
| 140 | + } |
| 141 | +
|
| 142 | + .codegen-entry { |
| 143 | + z-index: var(--z-ground); |
| 144 | + position: relative; |
121 | 145 | flex-shrink: 0;
|
122 | 146 | width: 100%;
|
123 | 147 | overflow: hidden;
|
124 | 148 | border: 1px solid var(--clr-border-2);
|
125 | 149 | border-radius: var(--radius-ml);
|
126 | 150 | }
|
127 | 151 |
|
128 |
| - .sidebar-entry-header { |
| 152 | + .codegen-entry-header { |
129 | 153 | display: flex;
|
130 | 154 | position: relative;
|
131 | 155 | flex-direction: column;
|
|
144 | 168 | }
|
145 | 169 | }
|
146 | 170 |
|
147 |
| - .sidebar-entry-header-left { |
| 171 | + .entry-header-content { |
148 | 172 | display: flex;
|
149 | 173 | align-items: center;
|
150 | 174 | width: 100%;
|
|
161 | 185 | }
|
162 | 186 |
|
163 | 187 | /* DRAWER */
|
164 |
| - .sidebar-entry-drawer { |
| 188 | + .commits-drawer { |
165 | 189 | display: flex;
|
166 | 190 | flex-direction: column;
|
167 | 191 | width: 100%;
|
168 | 192 | border-top: 1px solid var(--clr-border-2);
|
169 | 193 | }
|
170 | 194 |
|
171 |
| - .sidebar-entry-drawer__header { |
| 195 | + .commits-drawer-header { |
172 | 196 | display: flex;
|
173 | 197 | align-items: center;
|
174 | 198 | width: 100%;
|
175 | 199 | padding: 10px 12px;
|
176 | 200 | gap: 6px;
|
177 |
| - background-color: color-mix(in srgb, var(--clr-bg-2) 60%, transparent); |
| 201 | + background-color: var(--clr-bg-2); |
178 | 202 |
|
179 | 203 | &:hover {
|
180 |
| - .sidebar-entry-drawer__header__fold-icon { |
| 204 | + .fold-icon { |
181 | 205 | color: var(--clr-text-2);
|
182 | 206 | }
|
183 | 207 | }
|
184 | 208 | }
|
185 | 209 |
|
186 |
| - .sidebar-entry-drawer__header__fold-icon { |
| 210 | + .fold-icon { |
187 | 211 | display: flex;
|
188 | 212 | color: var(--clr-text-3);
|
189 | 213 | transition:
|
|
195 | 219 | }
|
196 | 220 | }
|
197 | 221 |
|
198 |
| - .sidebar-entry-drawer__header-info { |
| 222 | + .entry-metadata { |
199 | 223 | display: flex;
|
200 | 224 | align-items: center;
|
201 | 225 | justify-content: space-between;
|
|
205 | 229 | opacity: 0.7;
|
206 | 230 | }
|
207 | 231 |
|
208 |
| - .sidebar-entry-drawer__header-info__divider { |
| 232 | + .metadata-divider { |
209 | 233 | width: 1px;
|
210 | 234 | height: 12px;
|
211 | 235 | margin: 0 4px;
|
212 | 236 | background-color: var(--clr-text-1);
|
213 | 237 | opacity: 0.3;
|
214 | 238 | }
|
215 | 239 |
|
216 |
| - .sidebar-entry-drawer__commits { |
| 240 | + .commits-list { |
217 | 241 | display: flex;
|
218 | 242 | flex-direction: column;
|
219 | 243 | border-top: 1px solid var(--clr-border-2);
|
| 244 | + background-color: var(--clr-bg-1); |
220 | 245 | }
|
221 | 246 |
|
222 | 247 | .vibe-icon {
|
223 | 248 | display: flex;
|
224 | 249 |
|
225 |
| - &.enabled { |
226 |
| - /* color: var(--clr-theme-pop-element); */ |
227 |
| - } |
228 | 250 | &.running {
|
229 |
| - /* color: var(--clr-theme-pop-element); */ |
| 251 | + color: var(--clr-theme-pop-element); |
230 | 252 | }
|
231 | 253 | &.completed {
|
232 |
| - /* color: var(--clr-theme-succ-element); */ |
| 254 | + color: var(--clr-theme-succ-element); |
233 | 255 | }
|
234 | 256 | }
|
235 | 257 |
|
236 |
| - .entry-active-indicator { |
| 258 | + .active-indicator { |
237 | 259 | position: absolute;
|
238 | 260 | top: 12px;
|
239 | 261 | left: 0;
|
|
243 | 265 | border-radius: var(--radius-m);
|
244 | 266 | background-color: var(--clr-theme-pop-element);
|
245 | 267 | }
|
| 268 | +
|
| 269 | + .entry-heads { |
| 270 | + display: flex; |
| 271 | + position: relative; |
| 272 | + align-items: center; |
| 273 | + width: calc(100% - 8px); |
| 274 | + padding: 12px 12px 10px; |
| 275 | + gap: 8px; |
| 276 | + transform: translateY(-4px); |
| 277 | + border: 1px solid var(--clr-border-3); |
| 278 | + border-radius: 0 0 var(--radius-ml) var(--radius-ml); |
| 279 | + background: linear-gradient(180deg, var(--clr-bg-2) 20%, var(--clr-bg-1) 200%); |
| 280 | + background-color: var(--clr-bg-2); |
| 281 | + color: var(--clr-text-2); |
| 282 | + } |
246 | 283 | </style>
|
0 commit comments