Skip to content

Commit 605c27a

Browse files
takaokoujiclaude
andcommitted
feat: add Google Drive file upload functionality with custom dialog
This commit implements the ability to save Scratch 3.0 projects (.sb3) to Google Drive with a custom dialog for specifying the filename and save location, complementing the existing "Load from Google Drive" functionality. ## New Features - **Menu Integration**: Added "Save to Google Drive" menu item in File menu - **Save Dialog**: Custom dialog with filename input and save location selection - **Folder Selection**: Users can save to My Drive root or select a specific folder - **File Upload**: Multipart upload using Google Drive Files API v3 ## Implementation ### New Components 1. **google-drive-saver-hoc.jsx**: HOC for Google Drive save functionality - Manages save dialog state and upload process - Converts Ruby code to blocks before saving - Provides error handling and user feedback 2. **google-drive-save-dialog.jsx**: Custom save dialog component - Filename input with .sb3 extension validation - Save location dropdown (My Drive or folder selection) - Cancel, Reset, and Save buttons 3. **google-drive-save-dialog.css**: Dialog styling ### Modified Files 1. **google-drive-api.js**: Added upload functionality - uploadFile(): Multipart upload to Google Drive - showFolderPicker(): Folder selection via Google Picker - handleFolderPickerResponse(): Handle folder picker callback 2. **menu-bar.jsx**: Integrated save functionality - Added "Save to Google Drive" menu item - Integrated GoogleDriveSaverHOC - Added GoogleDriveSaveDialog component 3. **ja.js**: Added Japanese translations for all new UI elements ## Technical Details - Uses existing OAuth 2.0 authentication from GoogleDriveLoaderHOC - Leverages drive.file scope (already configured) - Multipart upload with metadata and file content - Base64 encoding for binary file data - Folder picker using Google Picker API ## Testing - ✅ Lint checks pass: npm run test:lint - Dialog UI follows app.diagrams.net design patterns - Supports both My Drive root and folder selection ## Related - Implements feature request from Issue #428 - Built on top of PR #427 (Google Drive load functionality) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 2f435b4 commit 605c27a

File tree

6 files changed

+830
-0
lines changed

6 files changed

+830
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
@import "../../css/colors.css";
2+
@import "../../css/units.css";
3+
4+
.modalContent {
5+
min-width: 500px;
6+
max-width: 600px;
7+
}
8+
9+
.body {
10+
display: flex;
11+
flex-direction: column;
12+
padding: 1rem;
13+
}
14+
15+
.header {
16+
font-size: 1.25rem;
17+
font-weight: bold;
18+
margin-bottom: 1.5rem;
19+
color: $text-primary;
20+
}
21+
22+
.content {
23+
display: flex;
24+
flex-direction: column;
25+
gap: 1rem;
26+
margin-bottom: 1.5rem;
27+
}
28+
29+
.formRow {
30+
display: flex;
31+
flex-direction: column;
32+
gap: 0.5rem;
33+
}
34+
35+
.label {
36+
font-weight: 500;
37+
color: $text-primary;
38+
font-size: 0.9rem;
39+
}
40+
41+
.input,
42+
.select {
43+
padding: 0.5rem;
44+
border: 1px solid $ui-black-transparent;
45+
border-radius: 0.25rem;
46+
font-size: 0.9rem;
47+
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
48+
width: 100%;
49+
}
50+
51+
.input:focus,
52+
.select:focus {
53+
outline: none;
54+
border-color: $motion-primary;
55+
}
56+
57+
.input:disabled {
58+
background-color: $ui-black-transparent;
59+
cursor: not-allowed;
60+
}
61+
62+
.select {
63+
cursor: pointer;
64+
background-color: $ui-white;
65+
}
66+
67+
.selectedFolder {
68+
font-size: 0.85rem;
69+
color: $text-primary-transparent;
70+
font-style: italic;
71+
margin-top: 0.25rem;
72+
}
73+
74+
.footer {
75+
display: flex;
76+
justify-content: flex-end;
77+
gap: 0.5rem;
78+
padding-top: 1rem;
79+
border-top: 1px solid $ui-black-transparent;
80+
}
81+
82+
.cancelButton,
83+
.resetButton,
84+
.saveButton {
85+
padding: 0.5rem 1rem;
86+
border: none;
87+
border-radius: 0.25rem;
88+
font-size: 0.9rem;
89+
cursor: pointer;
90+
font-weight: 500;
91+
transition: background-color 0.2s;
92+
}
93+
94+
.cancelButton {
95+
background-color: $ui-white;
96+
color: $text-primary;
97+
border: 1px solid $ui-black-transparent;
98+
}
99+
100+
.cancelButton:hover {
101+
background-color: $ui-black-transparent;
102+
}
103+
104+
.resetButton {
105+
background-color: $ui-white;
106+
color: $text-primary;
107+
border: 1px solid $ui-black-transparent;
108+
}
109+
110+
.resetButton:hover {
111+
background-color: $ui-black-transparent;
112+
}
113+
114+
.saveButton {
115+
background-color: $motion-primary;
116+
color: $ui-white;
117+
}
118+
119+
.saveButton:hover {
120+
background-color: $motion-primary-transparent;
121+
}

0 commit comments

Comments
 (0)