Skip to content

Commit b115533

Browse files
staredclaude
andcommitted
Enhance loading UX with better state separation and chart overlay (v0.1.5)
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent be2e176 commit b115533

File tree

4 files changed

+60
-23
lines changed

4 files changed

+60
-23
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "webr-ggplot2-demo",
33
"private": true,
4-
"version": "0.1.4",
4+
"version": "0.1.5",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",

src/App.vue

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const currentCsvData = ref<CsvData | null>(null)
3636
const {
3737
isReady,
3838
isLoading,
39+
isInitializing,
3940
loadingStatus,
4041
installedLibraries,
4142
messages,
@@ -46,6 +47,7 @@ const {
4647
executeCode,
4748
uploadCsvData,
4849
clearMessages,
50+
clearConsoleMessages,
4951
toggleLibrary,
5052
} = useWebR()
5153
@@ -66,7 +68,7 @@ const hasWarnings = computed(() => {
6668
6769
const runCode = async () => {
6870
if (code.value.trim()) {
69-
clearMessages() // Clear console and charts before running
71+
clearConsoleMessages() // Clear console messages but keep charts visible
7072
await executeCode(code.value)
7173
lastExecutedCode.value = code.value
7274
@@ -129,7 +131,7 @@ const handleExampleSelect = async (example: RExample) => {
129131
130132
// Execute code after CSV is loaded
131133
if (example.code.trim()) {
132-
clearMessages() // Clear console and charts before running
134+
clearConsoleMessages() // Clear console messages but keep charts visible
133135
await executeCode(example.code)
134136
lastExecutedCode.value = example.code
135137
@@ -151,7 +153,7 @@ const handleExampleSelect = async (example: RExample) => {
151153
152154
// Execute code immediately for examples without CSV
153155
if (example.code.trim()) {
154-
clearMessages() // Clear console and charts before running
156+
clearConsoleMessages() // Clear console messages but keep charts visible
155157
await executeCode(example.code)
156158
lastExecutedCode.value = example.code
157159
@@ -231,12 +233,12 @@ onMounted(async () => {
231233
<div class="toolbar-right">
232234
<WebRStatus
233235
:is-ready="isReady"
234-
:is-loading="isLoading"
236+
:is-loading="isInitializing"
235237
:loading-status="loadingStatus"
236238
/>
237239
<LibrarySelector
238240
:installed-libraries="installedLibraries"
239-
:is-loading="isLoading"
241+
:is-loading="isInitializing"
240242
:package-versions="packageVersions"
241243
@toggle-library="toggleLibrary"
242244
/>
@@ -289,7 +291,7 @@ onMounted(async () => {
289291
class="run-button"
290292
@click="runCode"
291293
>
292-
{{ isLoading ? 'Running...' : 'Run Code' }}
294+
{{ !isReady ? 'Waiting for WebR...' : isLoading ? 'Running...' : 'Run Code' }}
293295
</button>
294296
<div v-if="isReady && (webrVersion || rVersion)" class="runtime-versions">
295297
<span v-if="webrVersion">WebR {{ webrVersion }}</span>

src/components/OutputDisplay.vue

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@ watch(
4747
<template>
4848
<div class="output-display">
4949
<div ref="outputRef" class="output-content">
50-
<div v-if="isLoading" class="loading">
51-
<div class="spinner"></div>
52-
<span>Running R code...</span>
53-
</div>
54-
5550
<div v-if="messages.length === 0 && !isLoading" class="empty-state">
5651
<p>Run some R code to see the output here</p>
5752
</div>
@@ -66,6 +61,14 @@ watch(
6661
@error="handlePlotError"
6762
/>
6863
</div>
64+
65+
<!-- Loading overlay -->
66+
<div v-if="isLoading" class="loading-overlay">
67+
<div class="loading-content">
68+
<div class="spinner"></div>
69+
<span>Executing R code...</span>
70+
</div>
71+
</div>
6972
</div>
7073
</div>
7174
</template>
@@ -85,19 +88,39 @@ watch(
8588
display: flex;
8689
flex-direction: column;
8790
min-height: 0;
91+
position: relative;
8892
}
8993
90-
.loading {
94+
.loading-overlay {
95+
position: absolute;
96+
top: 0;
97+
left: 0;
98+
right: 0;
99+
bottom: 0;
100+
background-color: rgba(255, 255, 255, 0.4);
91101
display: flex;
92102
align-items: center;
93-
gap: 0.5rem;
94-
color: #6b7280;
95-
font-style: italic;
103+
justify-content: center;
104+
z-index: 10;
105+
backdrop-filter: blur(1px);
106+
}
107+
108+
.loading-content {
109+
display: flex;
110+
align-items: center;
111+
gap: 0.75rem;
112+
color: #374151;
113+
font-weight: 500;
114+
padding: 1rem 1.5rem;
115+
background: rgba(255, 255, 255, 0.95);
116+
border-radius: 8px;
117+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.15);
118+
border: 1px solid rgba(255, 255, 255, 0.8);
96119
}
97120
98121
.spinner {
99-
width: 16px;
100-
height: 16px;
122+
width: 20px;
123+
height: 20px;
101124
border: 2px solid #e5e7eb;
102125
border-top: 2px solid #3b82f6;
103126
border-radius: 50%;

src/composables/useWebR.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ const extractContentFromWebROutput = async (output: WebROutputItem): Promise<str
5858

5959
export const useWebR = () => {
6060
const isReady = ref(false)
61-
const isLoading = ref(false)
61+
const isLoading = ref(false) // For code execution
62+
const isInitializing = ref(false) // For WebR initialization
6263
const loadingStatus = ref('')
6364
const installedLibraries = reactive(new Set<string>())
6465
const messages = reactive<WebRMessage[]>([])
@@ -71,7 +72,7 @@ export const useWebR = () => {
7172

7273
const initializeWebR = async (initialCode?: string) => {
7374
try {
74-
isLoading.value = true
75+
isInitializing.value = true
7576
loadingStatus.value = 'Initializing WebR...'
7677

7778
// Import WebR from installed package
@@ -118,7 +119,7 @@ export const useWebR = () => {
118119
loadingStatus.value = 'WebR Failed'
119120
addMessage('error', `Failed to initialize WebR: ${error}`)
120121
} finally {
121-
isLoading.value = false
122+
isInitializing.value = false
122123
}
123124
}
124125

@@ -130,6 +131,15 @@ export const useWebR = () => {
130131
messages.splice(0, messages.length)
131132
}
132133

134+
const clearConsoleMessages = () => {
135+
// Remove only non-plot messages, keep charts visible during execution
136+
for (let i = messages.length - 1; i >= 0; i--) {
137+
if (messages[i].type !== 'plot') {
138+
messages.splice(i, 1)
139+
}
140+
}
141+
}
142+
133143
const executeCode = async (code: string) => {
134144
if (!webR || !isReady.value) {
135145
addMessage('error', 'WebR is not ready. Please wait for initialization.')
@@ -227,7 +237,7 @@ export const useWebR = () => {
227237
try {
228238
if (install) {
229239
loadingStatus.value = `Installing ${library}...`
230-
isLoading.value = true
240+
isInitializing.value = true
231241
await webR.installPackages([library])
232242
installedLibraries.add(library)
233243
addMessage('success', `${library} installed successfully`)
@@ -239,7 +249,7 @@ export const useWebR = () => {
239249
} catch (error) {
240250
addMessage('error', `Failed to install ${library}: ${error}`)
241251
} finally {
242-
isLoading.value = false
252+
isInitializing.value = false
243253
loadingStatus.value = isReady.value ? 'WebR Ready' : loadingStatus.value
244254
}
245255
}
@@ -289,6 +299,7 @@ export const useWebR = () => {
289299
return {
290300
isReady,
291301
isLoading,
302+
isInitializing,
292303
loadingStatus,
293304
installedLibraries,
294305
messages,
@@ -299,6 +310,7 @@ export const useWebR = () => {
299310
executeCode,
300311
uploadCsvData,
301312
clearMessages,
313+
clearConsoleMessages,
302314
toggleLibrary,
303315
}
304316
}

0 commit comments

Comments
 (0)