Show more recent chats

c45f1ceaffd932e0e009ada84bfaa9a121e7dfec

Cohee <18619528+Cohee1207@users.noreply.github.com>

4 files changed, +41 -7Ignore whitespace
public/css/welcome.css+14 -2
@@ -6,6 +6,10 @@
6 width: 100%;6 width: 100%;
7}7}
88
9.welcomePanel:has(.showMoreChats) {
10 padding-bottom: 5px;
11}
12
9body.bubblechat .welcomePanel {13body.bubblechat .welcomePanel {
10 border-radius: 10px;14 border-radius: 10px;
11 background-color: var(--SmartThemeBotMesBlurTintColor);15 background-color: var(--SmartThemeBotMesBlurTintColor);
@@ -22,7 +26,7 @@ body.bubblechat .welcomePanel {
2226
23.welcomePanel .recentChatsTitle {27.welcomePanel .recentChatsTitle {
24 flex-grow: 1;28 flex-grow: 1;
25 font-size: calc(var(--mainFontSize) * 1.1);29 font-size: calc(var(--mainFontSize) * 1.15);
26 font-weight: 600;30 font-weight: 600;
27}31}
2832
@@ -36,7 +40,7 @@ body.bubblechat .welcomePanel {
36}40}
3741
38.welcomePanel .welcomeHeaderVersionDisplay {42.welcomePanel .welcomeHeaderVersionDisplay {
39 font-size: calc(var(--mainFontSize) * 1.2);43 font-size: calc(var(--mainFontSize) * 1.3);
40 font-weight: 600;44 font-weight: 600;
41}45}
4246
@@ -174,6 +178,14 @@ body.big-avatars .welcomeRecent .recentChatList .recentChat .chatMessageContaine
174 font-size: calc(var(--mainFontSize) * 0.95);178 font-size: calc(var(--mainFontSize) * 0.95);
175}179}
176180
181.welcomeRecent .recentChatList .recentChat.hidden {
182 display: none;
183}
184
185.welcomeRecent .recentChatList .showMoreChats {
186 align-self: center;
187}
188
177@media screen and (max-width: 1000px) {189@media screen and (max-width: 1000px) {
178 .welcomePanel .welcomeShortcuts a span {190 .welcomePanel .welcomeShortcuts a span {
179 display: none;191 display: none;
public/scripts/templates/welcomePanel.html+8 -1
@@ -37,7 +37,7 @@
37 {{/if}}37 {{/if}}
38 {{#each chats}}38 {{#each chats}}
39 {{#with this}}39 {{#with this}}
40 <div class="recentChat" data-file="{{chat_name}}" data-avatar="{{avatar}}">40 <div class="recentChat {{#if hidden}}hidden{{/if}}" data-file="{{chat_name}}" data-avatar="{{avatar}}">
41 <div class="avatar" title="{{char_name}}">41 <div class="avatar" title="{{char_name}}">
42 <img src="{{char_thumbnail}}" alt="{{char_name}}">42 <img src="{{char_thumbnail}}" alt="{{char_name}}">
43 </div>43 </div>
@@ -66,6 +66,13 @@
66 </div>66 </div>
67 {{/with}}67 {{/with}}
68 {{/each}}68 {{/each}}
69 {{#if more}}
70 <button class="menu_button menu_button_icon showMoreChats">
71 <small data-i18n="Show more">
72 Show more
73 </small>
74 </button>
75 {{/if}}
69 </div>76 </div>
70 </div>77 </div>
71</div>78</div>
public/scripts/welcome-screen.js+18 -3
@@ -62,6 +62,7 @@ async function sendWelcomePanel() {
62 chats,62 chats,
63 empty: !chats.length,63 empty: !chats.length,
64 version: displayVersion,64 version: displayVersion,
65 more: chats.some(chat => chat.hidden),
65 };66 };
66 const template = await renderTemplateAsync('welcomePanel', templateData);67 const template = await renderTemplateAsync('welcomePanel', templateData);
67 const fragment = document.createRange().createContextualFragment(template);68 const fragment = document.createRange().createContextualFragment(template);
@@ -74,8 +75,19 @@ async function sendWelcomePanel() {
74 }75 }
75 });76 });
76 });77 });
77 fragment.querySelector('button.openTemporaryChat').addEventListener('click', () => {78 const hiddenChats = fragment.querySelectorAll('.recentChat.hidden');
78 void newAssistantChat({ temporary: true });79 fragment.querySelectorAll('button.showMoreChats').forEach((button) => {
80 button.addEventListener('click', () => {
81 hiddenChats.forEach((chatItem) => {
82 chatItem.classList.remove('hidden');
83 });
84 button.remove();
85 });
86 });
87 fragment.querySelectorAll('button.openTemporaryChat').forEach((button) => {
88 button.addEventListener('click', () => {
89 void newAssistantChat({ temporary: true });
90 });
79 });91 });
80 chatElement.append(fragment.firstChild);92 chatElement.append(fragment.firstChild);
81 } catch (error) {93 } catch (error) {
@@ -125,6 +137,7 @@ async function openRecentChat(avatarId, fileName) {
125 * @property {string} char_name Character name137 * @property {string} char_name Character name
126 * @property {string} date_short Date in short format138 * @property {string} date_short Date in short format
127 * @property {string} date_long Date in long format139 * @property {string} date_long Date in long format
140 * @property {boolean} hidden Chat will be hidden by default
128 */141 */
129async function getRecentChats() {142async function getRecentChats() {
130 const response = await fetch('/api/characters/recent', {143 const response = await fetch('/api/characters/recent', {
@@ -141,13 +154,15 @@ async function getRecentChats() {
141 data.sort((a, b) => b.last_mes - a.last_mes)154 data.sort((a, b) => b.last_mes - a.last_mes)
142 .map(chat => ({ chat, character: characters.find(x => x.avatar === chat.avatar) }))155 .map(chat => ({ chat, character: characters.find(x => x.avatar === chat.avatar) }))
143 .filter(t => t.character)156 .filter(t => t.character)
144 .forEach(({ chat, character }) => {157 .forEach(({ chat, character }, index) => {
158 const DEFAULT_DISPLAYED = 5;
145 const chatTimestamp = timestampToMoment(chat.last_mes);159 const chatTimestamp = timestampToMoment(chat.last_mes);
146 chat.char_name = character.name;160 chat.char_name = character.name;
147 chat.date_short = chatTimestamp.format('l');161 chat.date_short = chatTimestamp.format('l');
148 chat.date_long = chatTimestamp.format('LL LT');162 chat.date_long = chatTimestamp.format('LL LT');
149 chat.chat_name = chat.file_name.replace('.jsonl', '');163 chat.chat_name = chat.file_name.replace('.jsonl', '');
150 chat.char_thumbnail = getThumbnailUrl('avatar', character.avatar);164 chat.char_thumbnail = getThumbnailUrl('avatar', character.avatar);
165 chat.hidden = index >= DEFAULT_DISPLAYED;
151 });166 });
152167
153 return data;168 return data;
src/endpoints/characters.js+1 -1
@@ -1312,7 +1312,7 @@ router.post('/recent', async function (request, response) {
1312 }1312 }
1313 }1313 }
13141314
1315 const recentChats = allChatFiles.sort((a, b) => b.mtime - a.mtime).slice(0, 5);1315 const recentChats = allChatFiles.sort((a, b) => b.mtime - a.mtime).slice(0, 15);
1316 const jsonFilesPromise = recentChats.map((file) => {1316 const jsonFilesPromise = recentChats.map((file) => {
1317 return getChatInfo(file.filePath, { avatar: file.pngFile });1317 return getChatInfo(file.filePath, { avatar: file.pngFile });
1318 });1318 });