Skip to content

Commit 9596333

Browse files
happy scrolling
1 parent ce0a9da commit 9596333

File tree

5 files changed

+91
-144
lines changed

5 files changed

+91
-144
lines changed

src/app.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
name="viewport"
1212
content="width=device-width, initial-scale=1, viewport-fit=cover, user-scalable=no"
1313
/>
14-
<meta name="apple-mobile-web-app-capable" content="yes" />
14+
<meta name="mobile-web-app-capable" content="yes" />
1515
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
1616
<meta name="apple-mobile-web-app-title" content="WebLLM Chat" />
1717
<meta name="theme-color" content="#000000" />

src/lib/components/ChatInterface.svelte

Lines changed: 74 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,11 +1223,13 @@
12231223
// Removed problematic reactive statement that caused infinite loops
12241224
</script>
12251225

1226-
<div class="relative h-full overflow-hidden flex">
1226+
<div class="h-full flex overflow-hidden">
12271227
<!-- Progress bar - positioned absolutely at top -->
12281228
{#if !$isModelLoaded && $modelLoadingProgress < 100}
12291229
<div
1230-
class="absolute top-0 left-0 right-0 z-20 p-4 bg-surface-100-800-token border-b border-surface-300-600-token"
1230+
class="absolute top-0 left-0 z-20 p-4 bg-surface-100-800-token border-b border-surface-300-600-token"
1231+
class:right-0={!showRAGPanel}
1232+
class:right-80={showRAGPanel}
12311233
>
12321234
<div class="flex items-center justify-between mb-2">
12331235
<span class="text-sm font-medium text-surface-700-200-token"
@@ -1241,14 +1243,14 @@
12411243
{/if}
12421244

12431245
<!-- Main chat area -->
1244-
<div class="flex-1 relative">
1246+
<div class="flex-1 min-h-0 flex flex-col transition-all duration-300" class:mr-80={showRAGPanel}>
12451247
<!-- Chat messages with drag-and-drop -->
1246-
<DragDropZone className="h-full" on:files={handleFilesDropped} on:error={handleFileError}>
1248+
<DragDropZone className="flex-1 min-h-0" on:files={handleFilesDropped} on:error={handleFileError}>
12471249
<div
12481250
bind:this={chatContainer}
1249-
class="absolute inset-0 overflow-y-auto p-4 space-y-4 scroll-smooth"
1251+
class="h-full overflow-y-auto p-4 space-y-4 scroll-smooth"
12501252
class:pt-24={!$isModelLoaded && $modelLoadingProgress < 100}
1251-
style="padding-bottom: 10rem; scroll-behavior: smooth; -webkit-overflow-scrolling: touch;"
1253+
style="scroll-behavior: smooth; -webkit-overflow-scrolling: touch;"
12521254
on:scroll={handleScroll}
12531255
>
12541256
{#if $currentMessages.length === 0}
@@ -1277,81 +1279,78 @@
12771279
</div>
12781280
</DragDropZone>
12791281

1280-
<!-- Gradient fade for smooth scroll under effect -->
1281-
<div
1282-
class="absolute bottom-20 left-0 right-0 h-24 bg-gradient-to-t from-surface-100/50 dark:from-surface-800/50 to-transparent pointer-events-none z-40"
1283-
></div>
1284-
1285-
<!-- Input area -->
1286-
<div
1287-
class="absolute bottom-0 left-0 right-0 bg-surface-100-800-token border-t border-surface-300-600-token p-4 z-50"
1288-
>
1289-
<div class="relative max-w-4xl mx-auto">
1290-
<div
1291-
class="flex items-end gap-2 p-2 bg-surface-200-700-token rounded-full ring-2 ring-surface-300-600-token hover:ring-primary-500 focus-within:ring-primary-500 transition-all duration-200 shadow-sm"
1292-
>
1293-
<button
1294-
class="btn-icon btn-icon-sm variant-soft-surface ml-1"
1295-
disabled={uploadingFiles}
1296-
aria-label="Upload documents"
1297-
on:click={handleFileButtonClick}
1298-
>
1299-
{#if uploadingFiles}
1300-
<i class="fa fa-spinner fa-spin"></i>
1301-
{:else}
1302-
<i class="fa fa-paperclip"></i>
1303-
{/if}
1304-
</button>
1305-
<textarea
1306-
id="message-input"
1307-
bind:value={messageInput}
1308-
on:keydown={handleKeydown}
1309-
placeholder={$isModelLoaded
1310-
? 'Write a message...'
1311-
: 'Model loading... You can type but wait to send'}
1312-
disabled={isSubmitting || $isTyping}
1313-
class="flex-1 bg-transparent border-0 ring-0 resize-none px-2 py-1.5 leading-normal min-h-[2.5rem] max-h-32"
1314-
rows="1"
1315-
style="field-sizing: content;"
1316-
></textarea>
1317-
<button
1318-
on:click={handleSubmit}
1319-
disabled={!messageInput.trim() || isSubmitting || $isTyping}
1320-
class="btn-icon btn-icon-sm variant-filled-primary mr-1"
1282+
<!-- Input area at bottom -->
1283+
<div class="fixed bottom-0 left-80 flex flex-col bg-surface-100-800-token border-t border-surface-300-600-token p-4 z-30 transition-all duration-300" class:right-80={showRAGPanel} class:right-0={!showRAGPanel}>
1284+
<!-- Gradient fade above input -->
1285+
<div class="absolute -top-4 left-0 right-0 h-4 bg-gradient-to-t from-surface-100-800-token to-transparent pointer-events-none"></div>
1286+
<div class="relative w-full">
1287+
<div
1288+
class="flex items-end gap-2 p-2 bg-surface-200-700-token rounded-full ring-2 ring-surface-300-600-token hover:ring-primary-500 focus-within:ring-primary-500 transition-all duration-200 shadow-sm"
13211289
>
1322-
{#if isSubmitting || $isTyping}
1323-
<i class="fa fa-spinner fa-spin"></i>
1324-
{:else}
1325-
<i class="fa fa-arrow-up"></i>
1326-
{/if}
1327-
</button>
1290+
<button
1291+
class="btn-icon btn-icon-sm variant-soft-surface ml-1"
1292+
disabled={uploadingFiles}
1293+
aria-label="Upload documents"
1294+
on:click={handleFileButtonClick}
1295+
>
1296+
{#if uploadingFiles}
1297+
<i class="fa fa-spinner fa-spin"></i>
1298+
{:else}
1299+
<i class="fa fa-paperclip"></i>
1300+
{/if}
1301+
</button>
1302+
<textarea
1303+
id="message-input"
1304+
bind:value={messageInput}
1305+
on:keydown={handleKeydown}
1306+
placeholder={$isModelLoaded
1307+
? 'Write a message...'
1308+
: 'Model loading... You can type but wait to send'}
1309+
disabled={isSubmitting || $isTyping}
1310+
class="flex-1 bg-transparent border-0 ring-0 resize-none px-2 py-1.5 leading-normal min-h-[2.5rem] max-h-32"
1311+
rows="1"
1312+
style="field-sizing: content;"
1313+
></textarea>
1314+
<button
1315+
on:click={handleSubmit}
1316+
disabled={!messageInput.trim() || isSubmitting || $isTyping}
1317+
class="btn-icon btn-icon-sm variant-filled-primary mr-1"
1318+
>
1319+
{#if isSubmitting || $isTyping}
1320+
<i class="fa fa-spinner fa-spin"></i>
1321+
{:else}
1322+
<i class="fa fa-arrow-up"></i>
1323+
{/if}
1324+
</button>
1325+
</div>
1326+
1327+
<!-- Hidden file input for upload button -->
1328+
<input
1329+
bind:this={fileInput}
1330+
type="file"
1331+
multiple
1332+
accept=".pdf,.txt,.md,.docx"
1333+
on:change={handleFileInputChange}
1334+
style="display: none;"
1335+
/>
13281336
</div>
13291337

1330-
<!-- Hidden file input for upload button -->
1331-
<input
1332-
bind:this={fileInput}
1333-
type="file"
1334-
multiple
1335-
accept=".pdf,.txt,.md,.docx"
1336-
on:change={handleFileInputChange}
1337-
style="display: none;"
1338-
/>
1338+
{#if !$isModelLoaded && $modelLoadingProgress < 100}
1339+
<div class="text-xs text-surface-700-200-token opacity-70 mt-2">
1340+
Model is loading ({$modelLoadingProgress}%)... Messages will queue until ready.
1341+
</div>
1342+
{/if}
13391343
</div>
1340-
1341-
{#if !$isModelLoaded && $modelLoadingProgress < 100}
1342-
<div class="text-xs text-surface-700-200-token opacity-70 mt-2">
1343-
Model is loading ({$modelLoadingProgress}%)... Messages will queue until ready.
1344-
</div>
1345-
{/if}
13461344
</div>
1347-
</div>
13481345

1349-
<!-- RAG Context Panel -->
1350-
<RAGContext
1351-
bind:isVisible={showRAGPanel}
1352-
bind:lastQuery={lastRAGQuery}
1353-
forceRefresh={ragRefreshCounter}
1354-
/>
1346+
<!-- RAG Context Panel - fixed sidebar -->
1347+
{#if showRAGPanel}
1348+
<RAGContext
1349+
bind:isVisible={showRAGPanel}
1350+
bind:lastQuery={lastRAGQuery}
1351+
forceRefresh={ragRefreshCounter}
1352+
/>
1353+
{/if}
13551354
</div>
13561355

13571356
<!-- RAG Toggle Button -->

src/lib/components/RAGContext.svelte

Lines changed: 13 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -148,82 +148,34 @@
148148
}
149149
150150
function handleDocumentLoaded(event) {
151-
console.log('[RAGContext] handleDocumentLoaded called');
152151
// Document is already loaded in RAG system, just refresh the display
153-
debounceLoadDocuments();
152+
loadDocuments();
154153
}
155154
156155
function handleDocumentRemoved(event) {
157-
console.log('[RAGContext] handleDocumentRemoved called');
158156
// Document was removed, refresh the display
159-
debounceLoadDocuments();
157+
loadDocuments();
160158
}
161159
162-
let lastQueryId = '';
163-
let lastForceRefresh = 0;
164-
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
160+
// Removed reactive query/refresh handling to prevent loops
161+
// These will be handled manually when needed
165162
166-
function debounceLoadDocuments() {
167-
console.log('[RAGContext] debounceLoadDocuments called');
168-
if (debounceTimer) {
169-
console.log('[RAGContext] Clearing existing debounce timer');
170-
clearTimeout(debounceTimer);
171-
}
172-
debounceTimer = setTimeout(() => {
173-
console.log('[RAGContext] Debounce timer triggered, calling loadDocuments');
174-
loadDocuments();
175-
debounceTimer = null;
176-
}, 100);
177-
}
178-
179-
// Reactive statement to reload documents when feature is enabled
180-
let hasTriggeredInit = false;
181-
$: if (featureManager.isEnabled('clientSideRAG') && !isInitialized && !isInitializing && !hasTriggeredInit) {
182-
console.log('[RAGContext] Reactive: Feature enabled and not initialized, calling initializeRAG');
183-
hasTriggeredInit = true;
184-
initializeRAG().finally(() => {
185-
hasTriggeredInit = false;
186-
});
187-
}
188163
189-
// Reactive statement to reload documents when lastQuery changes (with deduplication)
190-
$: if (lastQuery && isInitialized && lastQuery.query !== lastQueryId) {
191-
lastQueryId = lastQuery.query;
192-
debounceLoadDocuments();
164+
// Only initialize once when feature is enabled and component is ready
165+
$: if (featureManager.isEnabled('clientSideRAG') && !isInitialized && !isInitializing) {
166+
initializeRAG();
193167
}
194168
195-
// Reactive statement to refresh when forceRefresh counter changes (with deduplication)
196-
$: if (forceRefresh > 0 && isInitialized && forceRefresh !== lastForceRefresh) {
197-
lastForceRefresh = forceRefresh;
198-
debounceLoadDocuments();
199-
}
200-
201-
let refreshInterval: ReturnType<typeof setInterval> | null = null;
202-
203-
// Periodically refresh documents when panel is visible (reduced frequency)
204-
$: {
205-
if (isVisible && isInitialized) {
206-
if (!refreshInterval) {
207-
console.log('[RAGContext] Starting document refresh interval (10s)');
208-
refreshInterval = setInterval(() => {
209-
console.log('[RAGContext] Interval refresh trigger');
210-
loadDocuments();
211-
}, 10000); // Reduced from 2s to 10s
212-
}
213-
} else {
214-
if (refreshInterval) {
215-
console.log('[RAGContext] Clearing document refresh interval');
216-
clearInterval(refreshInterval);
217-
refreshInterval = null;
218-
}
219-
}
220-
}
169+
// Removed automatic refresh interval to prevent loops
170+
// Documents will refresh manually via button or when needed
221171
</script>
222172

223-
{#if featureManager.isEnabled('clientSideRAG') && isVisible}
173+
{#if featureManager.isEnabled('clientSideRAG')}
224174
<!-- Debug: RAG Panel is rendering -->
225175
<div
226-
class="rag-context-panel bg-surface-100-800-token border-l border-surface-300-600-token p-4 w-80 flex flex-col"
176+
class="fixed top-0 right-0 bg-surface-100-800-token border-l border-surface-300-600-token p-4 w-80 flex flex-col h-full shadow-lg z-40 transition-transform duration-300"
177+
class:translate-x-0={isVisible}
178+
class:translate-x-full={!isVisible}
227179
>
228180
<div class="flex items-center justify-between mb-4">
229181
<h3 class="text-lg font-semibold">RAG Context</h3>
@@ -512,10 +464,6 @@
512464
{/if}
513465

514466
<style>
515-
.rag-context-panel {
516-
height: 100vh;
517-
}
518-
519467
.line-clamp-3 {
520468
display: -webkit-box;
521469
-webkit-line-clamp: 3;

src/lib/components/Sidebar.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@
197197
</div>
198198

199199
<!-- Fixed button bar at bottom -->
200-
<div class="absolute bottom-0 left-0 right-0 theme-glass border-t border-white/20 p-3 z-50">
200+
<div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-primary-500/20 to-secondary-500/20 backdrop-blur-sm border-t border-surface-300-600-token p-3 z-50">
201201
<div class="flex space-x-2">
202202
<button
203203
class="btn variant-outline-surface flex-1 text-sm"

src/lib/components/TokenCounter.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
}
3838
</script>
3939

40-
<!-- Token counters positioned in bottom-right corner -->
41-
<div class="fixed bottom-4 right-20 z-30 flex flex-col gap-2">
40+
<!-- Token counters positioned under RAG toggle button -->
41+
<div class="fixed bottom-4 right-4 z-50 flex flex-col gap-2">
4242
<!-- Total Context Used -->
4343
<div class="bg-surface-100-800-token backdrop-blur-sm border border-surface-300-600-token rounded-full px-3 py-1.5 shadow-md">
4444
<div class="flex items-center gap-2 text-xs font-medium">

0 commit comments

Comments
 (0)