main
html 306 lines 10.3 KB
Raw
1 <html>
2
3 <head>
4 <script type="module">
5 import { store } from "/components/sidebar/chats/chats-store.js";
6 </script>
7 </head>
8
9 <body>
10 <div x-data>
11 <template x-if="$store.chats">
12 <div class="chats-list-container" x-data>
13 <x-extension id="sidebar-chats-list-start"></x-extension>
14 <div class="section-header-row">
15 <h3 class="section-header">Chats</h3>
16 <!-- New Chat Button -->
17 <button id="newChat" class="btn-icon-action chat-list-action-btn" @click="$store.chats.newChat()" aria-label="New Chat" title="New Chat" data-bs-placement="top" data-bs-trigger="hover">
18 <x-icon name="chat_add_on"></x-icon>
19 </button>
20 <x-extension id="chats-header-controls"></x-extension>
21 </div>
22
23
24
25 <ul class="config-list chats-config-list no-scrollbar" x-show="$store.chats.topLevelContexts().length > 0">
26 <template x-for="(context, contextIndex) in $store.chats.topLevelContexts()" :key="context.id">
27 <li class="chat-tree-item"
28 :class="{ 'sidebar-list-divider': $store.sidebar.hasRowDividerBefore('chat', context, contextIndex, $store.chats.topLevelContexts()) }">
29 <div :class="{'chat-container': true, 'chat-has-children': $store.chats.hasChildren(context.id), 'chat-selected': context.id === $store.chats.selected}"
30 @click="$store.chats.selectChat(context.id)">
31 <button class="chat-expand-btn"
32 x-show="$store.chats.hasChildren(context.id)"
33 :class="{ 'is-visible': $store.chats.hasChildren(context.id), 'is-expanded': $store.chats.isExpanded(context.id) }"
34 :aria-expanded="$store.chats.isExpanded(context.id)"
35 :aria-label="$store.chats.isExpanded(context.id) ? 'Collapse chat children' : 'Expand chat children'"
36 @click.stop="$store.chats.toggleChildren(context.id)">
37 <x-icon
38 :name="$store.chats.isExpanded(context.id) ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"></x-icon>
39 </button>
40 <div class="chat-list-button">
41 <span :class="{'project-color-ball': true, 'heartbeat': context.running}"
42 :style="context.project?.color ? { backgroundColor: context.project.color } : { border: '1px solid var(--color-border)' }"></span>
43 <span class="chat-name"
44 x-text="$store.chats.displayName(context)"></span>
45 </div>
46 <button class="btn-icon-action chat-list-action-btn" title="Close chat" @click.stop="$confirmClick($event, () => $store.chats.killChat(context.id))">
47 <x-icon name="close"></x-icon>
48 </button>
49 <button type="button" class="btn-icon-action chat-list-action-btn" title="More chat actions"
50 aria-label="More chat actions" aria-haspopup="menu"
51 :aria-expanded="($store.sidebar.rowMenuOpenId === `chat:${context.id}`).toString()"
52 @click.stop="$store.sidebar.rowMenuToggle(`chat:${context.id}`, 'chat', $event.currentTarget)">
53 <x-icon name="more_vert"></x-icon>
54 </button>
55 </div>
56 <ul class="chat-child-list" x-show="$store.chats.isExpanded(context.id) && $store.chats.hasChildren(context.id)">
57 <template x-for="(child, childIndex) in $store.chats.childContexts(context.id)" :key="child.id">
58 <li :class="{ 'sidebar-list-divider': $store.sidebar.hasRowDividerBefore('chat', child, childIndex, $store.chats.childContexts(context.id)) }">
59 <div :class="{'chat-container': true, 'chat-child-container': true, 'chat-selected': child.id === $store.chats.selected}"
60 @click="$store.chats.selectChat(child.id)">
61 <div class="chat-child-indent"></div>
62 <div class="chat-list-button">
63 <span :class="{'project-color-ball': true, 'heartbeat': child.running}"
64 :style="child.project?.color ? { backgroundColor: child.project.color } : { border: '1px solid var(--color-border)' }"></span>
65 <span class="chat-name"
66 x-text="$store.chats.displayName(child)"></span>
67 </div>
68 <button class="btn-icon-action chat-list-action-btn" title="Close chat" @click.stop="$confirmClick($event, () => $store.chats.killChat(child.id))">
69 <x-icon name="close"></x-icon>
70 </button>
71 <button type="button" class="btn-icon-action chat-list-action-btn" title="More chat actions"
72 aria-label="More chat actions" aria-haspopup="menu"
73 :aria-expanded="($store.sidebar.rowMenuOpenId === `chat:${child.id}`).toString()"
74 @click.stop="$store.sidebar.rowMenuToggle(`chat:${child.id}`, 'chat', $event.currentTarget)">
75 <x-icon name="more_vert"></x-icon>
76 </button>
77 </div>
78 </li>
79 </template>
80 </ul>
81 </li>
82 </template>
83 </ul>
84 <div class="empty-list-message" x-show="$store.chats.topLevelContexts().length === 0">
85 <p><i>No chats to list.</i></p>
86 </div>
87 <x-extension id="sidebar-chats-list-end"></x-extension>
88 </div>
89 </template>
90 </div>
91
92 <style>
93 .chats-list-container .section-header-row {
94 display: flex;
95 align-items: center;
96 justify-content: space-between;
97 position: sticky;
98 top: 0;
99 flex-shrink: 0;
100 margin-bottom: var(--spacing-xs);
101 z-index: 10;
102 }
103
104 .chats-list-container .section-header {
105 margin: 0;
106 }
107
108 /* Chats list container and items */
109 .chats-list-container {
110 display: flex;
111 flex-direction: column;
112 flex: 1;
113 min-height: 0;
114 margin-top: var(--spacing-md);
115 }
116
117 .chats-config-list {
118 flex: 1;
119 min-height: 0;
120 overflow: scroll;
121 scroll-behavior: smooth;
122 max-height: 100%;
123 }
124
125 .chats-config-list > .chat-tree-item {
126 padding-block: 0.14rem;
127 }
128
129 .chat-container {
130 position: relative;
131 display: flex;
132 align-items: center;
133 justify-content: space-between;
134 width: 100%;
135 min-height: 40px;
136 border-radius: 4px;
137 overflow: hidden;
138 cursor: pointer;
139 }
140
141 .chats-config-list .chat-tree-item {
142 display: block;
143 align-items: stretch;
144 justify-content: flex-start;
145 }
146
147 .chat-child-list {
148 list-style: none;
149 padding: 0;
150 margin: 0;
151 width: 100%;
152 }
153
154 .chats-config-list .chat-child-list > li {
155 display: block;
156 padding: 0;
157 }
158
159 .chat-child-container {
160 min-height: 34px;
161 }
162
163 .chat-child-indent {
164 width: 18px;
165 flex-shrink: 0;
166 }
167
168 .chat-expand-btn {
169 position: absolute;
170 left: 2px;
171 top: 50%;
172 transform: translateY(-50%);
173 width: 18px;
174 height: 32px;
175 display: inline-flex;
176 align-items: center;
177 justify-content: center;
178 flex-shrink: 0;
179 border: 0;
180 background: transparent;
181 color: var(--color-text-muted);
182 opacity: 0;
183 pointer-events: none;
184 padding: 0;
185 margin: 0;
186 z-index: 1;
187 }
188
189 .chat-expand-btn.is-visible {
190 opacity: 0.95;
191 pointer-events: auto;
192 }
193
194 .chat-expand-btn.is-visible:hover {
195 color: var(--color-text);
196 opacity: 1;
197 }
198
199 .chat-expand-btn .material-symbols-outlined {
200 font-size: 18px;
201 }
202
203 .chat-container.chat-has-children .chat-list-button {
204 padding-left: 24px;
205 }
206
207 .chat-list-button {
208 display: flex;
209 align-items: center;
210 flex: 1 1 auto;
211 min-width: 0;
212 padding: 8px 6px;
213 overflow: hidden;
214 gap: 0.5em;
215 }
216
217 .project-color-ball {
218 width: 0.6em;
219 height: 0.6em;
220 border-radius: 50%;
221 display: inline-block;
222 box-sizing: border-box;
223 flex-shrink: 0;
224 }
225
226 .chats-list-container .project-color-ball.heartbeat {
227 animation: chat-working-bubble 1500ms ease-in-out infinite;
228 transform-origin: center;
229 will-change: border-radius, transform;
230 }
231
232 @keyframes chat-working-bubble {
233 0% {
234 border-radius: 50%;
235 transform: rotate(0deg) scale(1);
236 }
237 25% {
238 border-radius: 0;
239 transform: rotate(45deg) scale(0.9);
240 }
241 75% {
242 border-radius: 0;
243 transform: rotate(405deg) scale(0.9);
244 }
245 100% {
246 border-radius: 50%;
247 transform: rotate(405deg) scale(1);
248 }
249 }
250
251 .chat-name {
252 min-width: 0;
253 white-space: nowrap;
254 overflow: hidden;
255 text-overflow: ellipsis;
256 font-size: var(--font-size-small);
257 }
258
259 .chat-list-action-btn {
260 flex-shrink: 0;
261 margin-right: 8px;
262 }
263
264 .chat-container:hover{
265 background-color: var(--color-background-hover);
266 }
267
268 .device-pointer .chat-container .chat-list-action-btn,
269 .device-touch .chat-container:not(.chat-selected) .chat-list-action-btn {
270 display: none;
271 }
272
273 .device-pointer .chat-container:hover .chat-list-action-btn,
274 .device-touch .chat-container.chat-selected .chat-list-action-btn {
275 display: inline-flex;
276 }
277
278 .empty-list-message {
279 display: flex;
280 justify-content: center;
281 align-items: center;
282 height: 100px;
283 color: var(--color-secondary);
284 text-align: center;
285 opacity: 0.7;
286 font-style: italic;
287 }
288
289 .light-mode .empty-list-message {
290 color: var(--color-secondary-light);
291 }
292
293 /* Selected chat accent */
294 .chat-selected .chat-name {
295 font-size: var(--font-size-normal);
296 font-weight: bold;
297 }
298
299 /* .chat-list-button.font-bold { position: relative; background-color: var(--color-border) 0.05; } */
300 /* .chat-list-button.font-bold::before { content: ""; position: absolute; left: 0; top: 0; height: 100%; width: 3px; background-color: var(--color-border); border-top-left-radius: 3px; border-bottom-left-radius: 3px; } */
301 /* .light-mode .chat-list-button.font-bold { background-color: var(--color-border) 0.05; } */
302 /* .light-mode .chat-list-button.font-bold::before { background-color: var(--color-border); } */
303 </style>
304 </body>
305
306 </html>