Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ There are no tests. `.github/workflows/ci.yml` runs `npm ci`, the build (tsc cat
## Layout

- `src/App.tsx` — the shell. It renders `GlPythonWorkspace` (stacked layout; its buttons go into the bar through `actionsContainer`, every file is a tab with `closeFileTabs: false`) and uses glpython-editor's project helpers (`addProjectFile`, `renameProjectFile`, …).
- `src/index.css` — the shell's styles (`ide-*` classes), from glpython-editor's `--glp-*` tokens. glpython-editor's `style.css` still has the old shell's rules (`.app-shell`, `.topbar`, `.sidebar`, …), now unused.
- `src/index.css` — the shell's styles (`ide-*` classes), from glpython-editor's `--glp-*` tokens. glpython-editor's `style.css` styles only the workspace (plus `icon-button`, `hidden-input` and `auth-notice`, which the shell uses too).
- `src/i18n.ts` — only the shell's own strings (`ShellStrings`, de/en). The workspace's strings come from glpython-editor's `coreStrings`, so don't copy them here. A new workspace string goes into glpython-editor's `src/i18n.ts`.
- `src/projectStorage.ts` (local storage, folder/ZIP) and `src/projectShare.ts` (`?project=` share links, lz-string, versioned payload).
- `src/auth.ts` — MSAL. Only active with `VITE_ENTRA_CLIENT_ID` in `.env.local` (README «Microsoft sign-in»).
Expand Down
10 changes: 8 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,15 @@ function App() {
}, [])

// The drawer and the menu take keyboard focus when they open; a click
// elsewhere closes the menu.
// elsewhere closes them (the drawer: anywhere but itself and 📁).
useEffect(() => {
if (isDrawerOpen) drawerRef.current?.querySelector<HTMLElement>('button')?.focus()
if (!isDrawerOpen) return
drawerRef.current?.querySelector<HTMLElement>('button')?.focus()
const closeOnOutsideClick = (event: PointerEvent) => {
if (!drawerRef.current?.contains(event.target as Node) && !filesButtonRef.current?.contains(event.target as Node)) setIsDrawerOpen(false)
}
document.addEventListener('pointerdown', closeOnOutsideClick)
return () => document.removeEventListener('pointerdown', closeOnOutsideClick)
}, [isDrawerOpen])
useEffect(() => {
if (!isMenuOpen) return
Expand Down
57 changes: 0 additions & 57 deletions src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ export const localeNames: Record<Locale, string> = {
// The IDE's own shell strings; everything the workspace shows comes from
// glpython-editor's coreStrings (see translations below).
type ShellStrings = {
workspaceName: string
openProject: string
openFolder: string
downloadProject: string
shareLinkCopiedOutput: string
shareLinkPromptLabel: string
share: string
shareCopied: string
Expand All @@ -25,32 +23,15 @@ type ShellStrings = {
ideTools: string
restartPython: string
projectMenu: string
microsoftConnected: string
signInWithMicrosoft: string
settings: string
notSignedIn: string
courseMenu: string
renameProject: string
promptRenameProject: string
lessonProgress: string
addFile: string
renameFile: (path: string) => string
deleteFile: (path: string) => string
teacherNoteTitle: string
teacherNoteBody: string
pythonReference: string
unsaved: string
save: string
autosaveOff: string
devTools: string
clearLocalProject: string
language: string
savedOutput: (path: string) => string
downloadedOutput: (name: string) => string
openedFolderOutput: (name: string) => string
folderNotOpened: string
openedZipOutput: (name: string) => string
zipNotOpened: string
authInitError: string
authConfigError: string
authCancelledError: string
Expand All @@ -66,11 +47,9 @@ export type Translation = CoreStrings & ShellStrings
export const translations: Record<Locale, Translation> = {
en: {
...coreStrings.en,
workspaceName: 'Classroom workspace',
openProject: 'Open project',
openFolder: 'Open folder',
downloadProject: 'Download project',
shareLinkCopiedOutput: 'Share link copied to the clipboard. Anyone who opens it gets a copy of this project.',
shareLinkPromptLabel: 'Copy this share link:',
share: 'Share',
shareCopied: 'Link copied ✓',
Expand All @@ -81,32 +60,15 @@ export const translations: Record<Locale, Translation> = {
ideTools: 'Tools',
restartPython: 'Restart Python',
projectMenu: 'Project',
microsoftConnected: 'Microsoft connected',
signInWithMicrosoft: 'Sign in with Microsoft',
settings: 'Settings',
notSignedIn: 'Not signed in',
courseMenu: 'Course menu',
renameProject: 'Rename project',
promptRenameProject: 'Project name',
lessonProgress: 'Lesson 01 of 08',
addFile: 'Add file',
renameFile: (path) => `Rename ${path}`,
deleteFile: (path) => `Delete ${path}`,
teacherNoteTitle: "Teacher's note",
teacherNoteBody: 'Start by changing the name.',
pythonReference: 'Python reference',
unsaved: 'Unsaved',
save: 'Save',
autosaveOff: 'Autosave is off',
devTools: 'Development tools',
clearLocalProject: 'Clear local project',
language: 'Language',
savedOutput: (path) => `Saved ${path} to your workspace. OneDrive sync is ready to connect.`,
downloadedOutput: (name) => `Downloaded ${name} as a ZIP project folder.`,
openedFolderOutput: (name) => `Opened ${name} from a local folder.`,
folderNotOpened: 'The folder was not opened.',
openedZipOutput: (name) => `Opened ${name} from a ZIP project folder.`,
zipNotOpened: 'That ZIP file could not be opened as a project.',
authInitError: 'Microsoft sign-in could not be initialized.',
authConfigError: 'Add VITE_ENTRA_CLIENT_ID to .env.local to enable Microsoft sign-in.',
authCancelledError: 'Microsoft sign-in was cancelled or failed.',
Expand All @@ -118,11 +80,9 @@ export const translations: Record<Locale, Translation> = {
},
de: {
...coreStrings.de,
workspaceName: 'Klassenarbeitsbereich',
openProject: 'Projekt öffnen',
openFolder: 'Ordner öffnen',
downloadProject: 'Projekt herunterladen',
shareLinkCopiedOutput: 'Freigabelink in die Zwischenablage kopiert. Wer ihn öffnet, erhält eine Kopie dieses Projekts.',
shareLinkPromptLabel: 'Diesen Freigabelink kopieren:',
share: 'Teilen',
shareCopied: 'Link kopiert ✓',
Expand All @@ -133,32 +93,15 @@ export const translations: Record<Locale, Translation> = {
ideTools: 'Werkzeuge',
restartPython: 'Python neu starten',
projectMenu: 'Projekt',
microsoftConnected: 'Mit Microsoft verbunden',
signInWithMicrosoft: 'Mit Microsoft anmelden',
settings: 'Einstellungen',
notSignedIn: 'Nicht angemeldet',
courseMenu: 'Kursmenü',
renameProject: 'Projekt umbenennen',
promptRenameProject: 'Projektname',
lessonProgress: 'Lektion 01 von 08',
addFile: 'Datei hinzufügen',
renameFile: (path) => `${path} umbenennen`,
deleteFile: (path) => `${path} löschen`,
teacherNoteTitle: 'Hinweis der Lehrkraft',
teacherNoteBody: 'Zuerst den Namen ändern.',
pythonReference: 'Python-Referenz',
unsaved: 'Nicht gespeichert',
save: 'Speichern',
autosaveOff: 'Automatisches Speichern ist deaktiviert',
devTools: 'Entwicklerwerkzeuge',
clearLocalProject: 'Lokales Projekt löschen',
language: 'Sprache',
savedOutput: (path) => `${path} im Arbeitsbereich gespeichert. OneDrive-Synchronisierung ist bereit zur Verbindung.`,
downloadedOutput: (name) => `${name} als ZIP-Projektordner heruntergeladen.`,
openedFolderOutput: (name) => `${name} aus einem lokalen Ordner geöffnet.`,
folderNotOpened: 'Der Ordner wurde nicht geöffnet.',
openedZipOutput: (name) => `${name} aus einem ZIP-Projektordner geöffnet.`,
zipNotOpened: 'Diese ZIP-Datei konnte nicht als Projekt geöffnet werden.',
authInitError: 'Die Microsoft-Anmeldung konnte nicht initialisiert werden.',
authConfigError: 'Für die Microsoft-Anmeldung VITE_ENTRA_CLIENT_ID in .env.local eintragen.',
authCancelledError: 'Die Microsoft-Anmeldung wurde abgebrochen oder ist fehlgeschlagen.',
Expand Down
Loading