Skip to content

Commit e0f85a0

Browse files
staredclaude
andcommitted
Improve UI layout and chart-focused design
- Redesign layout with code editor on left, output on right (50/50 split) - Move run button to intuitive position next to code editor - Compact file upload and example selector in horizontal toolbar - Combine all text output into single foldable "Console Output" bar below charts - Charts now display prominently with full width, text output collapsible - Restore colored message styling (SUCCESS green, ERROR red, STDERR orange) - Fix example names and ensure all examples generate charts - Remove redundant UI elements (clear button, output header) - Update initial code to generate immediate chart visualization 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 29ff7d6 commit e0f85a0

File tree

11 files changed

+346
-313
lines changed

11 files changed

+346
-313
lines changed

env.d.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
/// <reference types="vite/client" />
1+
/// <reference types="vite/client" />
2+
3+
declare global {
4+
interface Window {
5+
MonacoEnvironment?: {
6+
getWorkerUrl?: () => string
7+
getWorker?: () => Worker
8+
}
9+
}
10+
}

src/App.vue

Lines changed: 58 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ import OutputDisplay from './components/OutputDisplay.vue'
77
import { useWebR } from './composables/useWebR'
88
import type { RExample, CsvData } from './types'
99
10-
const code = ref(`# Welcome to WebR ggplot2 & dplyr Demo!
11-
# Select an example from the dropdown or write your own R code
10+
const code = ref(`# WebR ggplot2 & dplyr Demo
11+
# Select an example or write your own code
1212
1313
library(ggplot2)
1414
library(dplyr)
1515
16-
# Basic example with built-in data
17-
mtcars %>%
18-
head(10) %>%
19-
print()`)
16+
# Create your first visualization
17+
ggplot(mtcars, aes(x = wt, y = mpg)) +
18+
geom_point() +
19+
theme_minimal()`)
2020
2121
const {
2222
isReady,
@@ -60,32 +60,26 @@ onMounted(() => {
6060
</header>
6161

6262
<main class="main">
63+
<div class="toolbar">
64+
<FileUpload @file-uploaded="handleFileUpload" @file-removed="handleFileRemoved" />
65+
<ExampleSelector @example-selected="handleExampleSelect" />
66+
</div>
67+
6368
<div class="container">
64-
<div class="sidebar">
65-
<div class="controls">
66-
<FileUpload @file-uploaded="handleFileUpload" @file-removed="handleFileRemoved" />
67-
<ExampleSelector @example-selected="handleExampleSelect" />
69+
<div class="editor-section">
70+
<CodeEditor v-model="code" />
71+
<div class="editor-controls">
6872
<button @click="runCode" :disabled="!isReady || isLoading" class="run-button">
6973
{{ isLoading ? 'Running...' : 'Run Code' }}
7074
</button>
7175
</div>
7276
</div>
7377

74-
<div class="content">
75-
<div class="editor-section">
76-
<div class="section-header">
77-
<h2 class="section-title">R Code Editor</h2>
78-
</div>
79-
<CodeEditor v-model="code" />
80-
</div>
81-
82-
<div class="output-section">
83-
<OutputDisplay
84-
:messages="messages"
85-
:is-loading="isLoading"
86-
@clear="clearMessages"
87-
/>
88-
</div>
78+
<div class="output-section">
79+
<OutputDisplay
80+
:messages="messages"
81+
:is-loading="isLoading"
82+
/>
8983
</div>
9084
</div>
9185
</main>
@@ -102,14 +96,14 @@ onMounted(() => {
10296
.header {
10397
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
10498
color: white;
105-
padding: 2rem 0;
99+
padding: 1.5rem 0;
106100
text-align: center;
107-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
101+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
108102
}
109103
110104
.title {
111105
margin: 0;
112-
font-size: 2.5rem;
106+
font-size: 2rem;
113107
font-weight: 700;
114108
margin-bottom: 0.5rem;
115109
}
@@ -121,41 +115,36 @@ onMounted(() => {
121115
font-weight: 300;
122116
}
123117
118+
124119
.main {
125120
flex: 1;
126121
}
127122
128-
.container {
129-
max-width: 1200px;
130-
margin: 0 auto;
131-
padding: 2rem;
132-
display: grid;
133-
grid-template-columns: 300px 1fr;
134-
gap: 2rem;
135-
align-items: start;
136-
}
137-
138-
.sidebar {
123+
.toolbar {
139124
background: white;
140-
border-radius: 8px;
141-
padding: 1.5rem;
142-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
143-
border: 1px solid #e5e7eb;
144-
}
145-
146-
.controls {
125+
border-bottom: 1px solid #e5e7eb;
126+
padding: 1rem 2rem;
147127
display: flex;
148-
flex-direction: column;
149128
gap: 1.5rem;
129+
align-items: center;
130+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
150131
}
151132
133+
.container {
134+
display: grid;
135+
grid-template-columns: 1fr 1fr;
136+
gap: 0;
137+
height: calc(100vh - 140px);
138+
}
139+
140+
152141
.run-button {
153142
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
154143
color: white;
155144
border: none;
156145
padding: 0.75rem 1.5rem;
157146
border-radius: 6px;
158-
font-size: 1rem;
147+
font-size: 0.875rem;
159148
font-weight: 600;
160149
cursor: pointer;
161150
transition: all 0.3s ease;
@@ -173,44 +162,43 @@ onMounted(() => {
173162
transform: none;
174163
}
175164
176-
.content {
165+
166+
.editor-section {
167+
background: white;
168+
border-right: 1px solid #e5e7eb;
169+
padding: 1.5rem;
170+
overflow: hidden;
177171
display: flex;
178172
flex-direction: column;
179-
gap: 2rem;
180173
}
181174
182-
.editor-section,
175+
.editor-controls {
176+
margin-top: 1rem;
177+
display: flex;
178+
justify-content: flex-end;
179+
}
180+
183181
.output-section {
184182
background: white;
185-
border-radius: 8px;
186183
padding: 1.5rem;
187-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
188-
border: 1px solid #e5e7eb;
184+
overflow: hidden;
189185
}
190186
191-
.section-header {
192-
margin-bottom: 1rem;
193-
}
194-
195-
.section-title {
196-
margin: 0;
197-
font-size: 1.25rem;
198-
font-weight: 600;
199-
color: #374151;
200-
}
201187
202188
@media (max-width: 768px) {
189+
.toolbar {
190+
flex-direction: column;
191+
gap: 1rem;
192+
align-items: stretch;
193+
}
194+
203195
.container {
204196
grid-template-columns: 1fr;
205-
padding: 1rem;
197+
height: auto;
206198
}
207199
208200
.title {
209-
font-size: 2rem;
210-
}
211-
212-
.subtitle {
213-
font-size: 1rem;
201+
font-size: 1.75rem;
214202
}
215203
}
216204
</style>

src/components/CodeEditor.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ onMounted(() => {
3333
scrollBeyondLastLine: false,
3434
wordWrap: 'on',
3535
automaticLayout: true,
36+
// Disable features that require workers
37+
links: false,
38+
colorDecorators: false,
39+
codeLens: false,
40+
folding: false,
41+
foldingStrategy: 'indentation',
42+
showFoldingControls: 'never',
43+
matchBrackets: 'never',
44+
glyphMargin: false,
45+
// Disable language features that need workers
46+
suggest: { showWords: false },
47+
quickSuggestions: false,
48+
parameterHints: { enabled: false },
49+
hover: { enabled: false },
3650
})
3751
3852
editor.onDidChangeModelContent(() => {

src/components/ExampleSelector.vue

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,65 +22,45 @@ const handleExampleChange = () => {
2222

2323
<template>
2424
<div class="example-selector">
25-
<label for="example-select" class="label">Examples:</label>
2625
<select
2726
id="example-select"
2827
v-model="selectedExample"
2928
@change="handleExampleChange"
3029
class="select"
3130
>
32-
<option value="">Select an example...</option>
31+
<option value="">Examples ▼</option>
3332
<option v-for="example in examples" :key="example.id" :value="example.id">
3433
{{ example.title }}
3534
</option>
3635
</select>
37-
<div v-if="currentExample" class="example-info">
38-
<p class="description">{{ currentExample.description }}</p>
39-
</div>
4036
</div>
4137
</template>
4238

4339
<style scoped>
4440
.example-selector {
45-
margin-bottom: 1rem;
46-
}
47-
48-
.label {
49-
display: block;
50-
font-weight: 500;
51-
color: #374151;
52-
margin-bottom: 0.5rem;
41+
display: flex;
42+
align-items: center;
5343
}
5444
5545
.select {
56-
width: 100%;
57-
padding: 0.5rem;
46+
background: #f3f4f6;
5847
border: 1px solid #d1d5db;
59-
border-radius: 4px;
48+
border-radius: 6px;
49+
padding: 0.5rem 0.75rem;
6050
font-size: 0.875rem;
61-
background-color: white;
6251
cursor: pointer;
63-
transition: border-color 0.3s ease;
52+
transition: all 0.3s ease;
53+
white-space: nowrap;
54+
}
55+
56+
.select:hover {
57+
background: #e5e7eb;
58+
border-color: #9ca3af;
6459
}
6560
6661
.select:focus {
6762
outline: none;
6863
border-color: #3b82f6;
6964
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
7065
}
71-
72-
.example-info {
73-
margin-top: 0.5rem;
74-
padding: 0.75rem;
75-
background-color: #f8fafc;
76-
border-radius: 4px;
77-
border-left: 4px solid #3b82f6;
78-
}
79-
80-
.description {
81-
margin: 0;
82-
color: #64748b;
83-
font-size: 0.875rem;
84-
line-height: 1.4;
85-
}
8666
</style>

0 commit comments

Comments
 (0)