Skip to content

Commit 1c88575

Browse files
Copilotmikebarkmin
andcommitted
Add file upload option to learn view for importing LearningMap JSON files
Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com>
1 parent e11a094 commit 1c88575

2 files changed

Lines changed: 114 additions & 0 deletions

File tree

platforms/web/src/Learn.css

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,56 @@
182182
margin-bottom: 0;
183183
}
184184

185+
.add-map-divider {
186+
display: flex;
187+
align-items: center;
188+
text-align: center;
189+
margin: 1.5rem 0;
190+
color: var(--learningmap-color-quicksilver, #a4a4a4);
191+
}
192+
193+
.add-map-divider::before,
194+
.add-map-divider::after {
195+
content: '';
196+
flex: 1;
197+
border-bottom: 1px solid #dee2e6;
198+
}
199+
200+
.add-map-divider span {
201+
padding: 0 1rem;
202+
font-size: 0.9rem;
203+
}
204+
205+
.add-map-upload {
206+
display: flex;
207+
justify-content: center;
208+
}
209+
210+
.upload-button {
211+
padding: 0.75rem 1.5rem;
212+
background: white;
213+
color: var(--learningmap-color-openpatch, #007864);
214+
border: 2px solid var(--learningmap-color-openpatch, #007864);
215+
border-radius: 4px;
216+
cursor: pointer;
217+
font-size: 1rem;
218+
font-weight: 400;
219+
transition: all 0.2s;
220+
font-family: "Concert One", sans-serif;
221+
display: inline-block;
222+
}
223+
224+
.upload-button:hover {
225+
background: var(--learningmap-color-freshmint, #b5e3d8);
226+
border-color: var(--learningmap-color-dark-forest, #004c45);
227+
color: var(--learningmap-color-dark-forest, #004c45);
228+
}
229+
230+
.upload-button:focus {
231+
outline: 2px solid var(--learningmap-color-openpatch, #007864);
232+
outline-offset: 2px;
233+
}
234+
185235
.empty-state {
186236
text-align: center;
187237
padding: 3rem;

platforms/web/src/Learn.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,55 @@ function Learn() {
150150
setError('Invalid learning map URL. Please paste a valid URL with #json=...');
151151
}
152152
};
153+
154+
const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
155+
const file = event.target.files?.[0];
156+
if (!file) return;
157+
158+
setError(null);
159+
const reader = new FileReader();
160+
161+
reader.onload = (e) => {
162+
try {
163+
const content = e.target?.result as string;
164+
const json = JSON.parse(content);
165+
166+
// Generate a unique ID for this uploaded map
167+
const uploadId = `upload-${Date.now()}`;
168+
const storageId = json.settings?.id || uploadId;
169+
170+
// Check if a map with this storage ID already exists
171+
const existingMap = getLearningMap(storageId);
172+
if (existingMap) {
173+
const shouldReplace = window.confirm(
174+
`A learning map with this ID already exists. Would you like to replace it? Your progress will not be removed.`
175+
);
176+
if (shouldReplace) {
177+
const existingState = existingMap.state;
178+
addLearningMap(storageId, json);
179+
if (existingState) {
180+
updateState(storageId, existingState);
181+
}
182+
navigate(`/learn#json=${storageId}`);
183+
}
184+
} else {
185+
addLearningMap(storageId, json);
186+
navigate(`/learn#json=${storageId}`);
187+
}
188+
} catch (err) {
189+
setError('Invalid file format. Please upload a valid LearningMap JSON file.');
190+
}
191+
};
192+
193+
reader.onerror = () => {
194+
setError('Failed to read the file. Please try again.');
195+
};
196+
197+
reader.readAsText(file);
198+
199+
// Reset the input so the same file can be uploaded again if needed
200+
event.target.value = '';
201+
};
153202

154203
const handleRemoveMap = (id: string) => {
155204
if (window.confirm('Are you sure you want to remove this learning map?')) {
@@ -258,6 +307,21 @@ function Learn() {
258307
/>
259308
<button onClick={handleAddMap}>Add Map</button>
260309
</div>
310+
<div className="add-map-divider">
311+
<span>or</span>
312+
</div>
313+
<div className="add-map-upload">
314+
<label htmlFor="file-upload" className="upload-button">
315+
Upload Map File
316+
</label>
317+
<input
318+
id="file-upload"
319+
type="file"
320+
accept=".json,application/json"
321+
onChange={handleFileUpload}
322+
style={{ display: 'none' }}
323+
/>
324+
</div>
261325
{error && <p className="error-message">{error}</p>}
262326
</div>
263327

0 commit comments

Comments
 (0)