├── .node-version ├── .husky └── pre-push ├── .yarnrc.yml ├── _config.yml ├── src ├── react-app-env.d.ts ├── fileMock.ts ├── assets │ ├── SA.jpg │ ├── default-avatar.jpg │ ├── login_background.jpg │ ├── academy_background.jpg │ ├── default_cover_image.jpg │ └── leaderboard_background.jpg ├── commons │ ├── application │ │ ├── types │ │ │ ├── VscodeTypes.ts │ │ │ ├── CommonsTypes.ts │ │ │ └── ExternalTypes.ts │ │ ├── actions │ │ │ ├── VscodeActions.ts │ │ │ ├── __tests__ │ │ │ │ └── CommonsActions.test.ts │ │ │ └── CommonsActions.ts │ │ ├── reducers │ │ │ ├── CommonsReducer.ts │ │ │ └── VscodeReducer.ts │ │ └── __tests__ │ │ │ ├── __snapshots__ │ │ │ └── Application.test.tsx.snap │ │ │ └── Application.test.tsx │ ├── repl │ │ └── ReplTypes.ts │ ├── fileSystem │ │ ├── FileSystemTypes.ts │ │ ├── FileSystemActions.ts │ │ ├── __tests__ │ │ │ ├── FileSystemActions.test.ts │ │ │ └── FileSystemReducer.test.ts │ │ └── FileSystemReducer.ts │ ├── gitHubOverlay │ │ └── GitHubFileNodeData.tsx │ ├── featureFlags │ │ ├── featureSelector.ts │ │ ├── useFeature.ts │ │ ├── selectFeatureSaga.ts │ │ ├── publicFlags.ts │ │ └── FeatureFlag.ts │ ├── sideContent │ │ ├── __tests__ │ │ │ └── __snapshots__ │ │ │ │ └── SideContentHtmlDisplay.test.tsx.snap │ │ └── content │ │ │ ├── SideContentCanvasOutput.tsx │ │ │ └── remoteExecution │ │ │ └── DeviceMenuItemButtons.tsx │ ├── utils │ │ ├── LocalStorageHelper.ts │ │ ├── __tests__ │ │ │ └── GitHubPersistenceHelper.test.ts │ │ ├── MemoizeHelper.ts │ │ ├── SourcerorHelper.ts │ │ ├── ConsoleOverload.ts │ │ ├── GitHubPersistenceHelper.ts │ │ ├── QueryHelper.ts │ │ ├── CastBackend.ts │ │ ├── ParamParseHelper.ts │ │ └── notifications │ │ │ └── NotificationsHelper.ts │ ├── controlBar │ │ ├── ControlBarResetButton.tsx │ │ ├── ControlBarClearButton.tsx │ │ ├── ControlBarCloseButton.tsx │ │ ├── ControlBarSubmit.tsx │ │ ├── ControlBarReturnToAcademyButton.tsx │ │ ├── ControlBarQuestionViewButton.tsx │ │ ├── ControlBarPreviousButton.tsx │ │ ├── ControlBarToggleEditModeButton.tsx │ │ ├── ControlBarExecutionTime.tsx │ │ ├── ControlBarEvalButton.tsx │ │ ├── ControlBarSaveButton.tsx │ │ ├── ControlBar.tsx │ │ └── ControlBarRunButton.tsx │ ├── editor │ │ ├── EditorHotkeys.ts │ │ ├── __tests__ │ │ │ ├── __snapshots__ │ │ │ │ └── Editor.test.tsx.snap │ │ │ ├── tabs │ │ │ │ └── utils.ts │ │ │ └── Editor.test.tsx │ │ └── tabs │ │ │ └── EditorTab.tsx │ ├── __tests__ │ │ ├── ContentDisplay.test.tsx │ │ └── __snapshots__ │ │ │ └── ContentDisplay.test.tsx.snap │ ├── fileSystemView │ │ └── FileSystemViewIndentationPadding.tsx │ ├── navigationBar │ │ └── subcomponents │ │ │ └── __tests__ │ │ │ └── SicpNavigationBar.test.tsx │ ├── assessment │ │ └── AssessmentNotFound.tsx │ ├── sagas │ │ ├── FeatureFlagSaga.ts │ │ ├── __tests__ │ │ │ └── GitHubPersistenceSaga.test.ts │ │ └── WorkspaceSaga │ │ │ └── helpers │ │ │ ├── dumpDisplayBuffer.ts │ │ │ └── restoreExtraMethods.ts │ ├── delay │ │ └── Delay.tsx │ ├── achievement │ │ ├── view │ │ │ └── AchievementViewCompletion.tsx │ │ ├── card │ │ │ ├── AchievementXp.tsx │ │ │ └── AchievementDeadline.tsx │ │ ├── control │ │ │ ├── achievementEditor │ │ │ │ ├── AchievementTemplate.ts │ │ │ │ ├── AchievementUuidCopier.tsx │ │ │ │ └── AchievementAdder.tsx │ │ │ ├── goalEditor │ │ │ │ ├── GoalAdder.tsx │ │ │ │ ├── EditableGoalTypes.ts │ │ │ │ └── metaDetails │ │ │ │ │ └── EditableManualMeta.tsx │ │ │ └── common │ │ │ │ ├── ItemDeleter.tsx │ │ │ │ └── ItemSaver.tsx │ │ ├── AchievementFilter.tsx │ │ └── overview │ │ │ └── AchievementMilestone.tsx │ ├── notificationBadge │ │ └── NotificationBadgeTypes.ts │ ├── WorkspaceSettingsContext.tsx │ ├── mobileWorkspace │ │ └── mobileSideContent │ │ │ └── MobileControlBar.tsx │ ├── grading │ │ ├── GradingText.tsx │ │ └── GradingFlex.tsx │ ├── editingWorkspaceSideContent │ │ ├── EditingWorkspaceSideContentHelper.ts │ │ └── EditingWorkspaceSideContentGradingTab.tsx │ ├── ContentDisplay.tsx │ ├── collabEditing │ │ └── __tests__ │ │ │ └── CollabEditingActions.test.ts │ └── Markdown.tsx ├── i18n │ ├── locales │ │ ├── zh-SG │ │ │ ├── sideContent │ │ │ │ ├── sessionManagement.json │ │ │ │ ├── faceapiDisplay.json │ │ │ │ ├── htmlDisplay.json │ │ │ │ ├── contestVoting.json │ │ │ │ ├── resultCard.json │ │ │ │ ├── dataVisualizer.json │ │ │ │ ├── upload.json │ │ │ │ ├── substVisualizer.json │ │ │ │ ├── contestLeaderboard.json │ │ │ │ ├── autograder.json │ │ │ │ └── cseMachine.json │ │ │ ├── login.json │ │ │ ├── stories.json │ │ │ ├── sourcecast.json │ │ │ ├── sourceRecorder.json │ │ │ ├── welcome.json │ │ │ ├── grading.json │ │ │ └── commons.json │ │ ├── en │ │ │ ├── sideContent │ │ │ │ ├── sessionManagement.json │ │ │ │ ├── faceapiDisplay.json │ │ │ │ ├── htmlDisplay.json │ │ │ │ ├── contestVoting.json │ │ │ │ ├── resultCard.json │ │ │ │ ├── dataVisualizer.json │ │ │ │ ├── upload.json │ │ │ │ ├── contestLeaderboard.json │ │ │ │ ├── autograder.json │ │ │ │ └── substVisualizer.json │ │ │ ├── login.json │ │ │ ├── sourcecast.json │ │ │ ├── stories.json │ │ │ ├── sourceRecorder.json │ │ │ ├── grading.json │ │ │ ├── welcome.json │ │ │ └── commons.json │ │ ├── pseudo │ │ │ ├── login.json │ │ │ ├── index.ts │ │ │ └── commons.json │ │ └── index.ts │ ├── i18next.d.ts │ └── i18n.ts ├── styles │ ├── Stories.module.scss │ ├── _variableHighlighting.scss │ ├── _game.scss │ ├── _playground.scss │ ├── NavigationBar.module.scss │ ├── ConfirmDialog.module.scss │ ├── Draggable.module.scss │ ├── ContextMenu.module.scss │ ├── Academy.module.scss │ ├── ConfigureControls.module.scss │ ├── _contributors.scss │ ├── _sourcereel.scss │ ├── _gamesimulator.scss │ ├── Login.module.scss │ ├── GradingCommentSelector.module.scss │ ├── AchievementCommentCard.module.scss │ ├── _application.scss │ ├── _global.scss │ └── _github.scss ├── features │ ├── github │ │ ├── GitHubTypes.ts │ │ └── GitHubActions.ts │ ├── dataVisualizer │ │ ├── tree │ │ │ ├── BaseTreeNode.ts │ │ │ ├── TreeNode.ts │ │ │ ├── DataTreeNode.tsx │ │ │ ├── AlreadyParsedTreeNode.ts │ │ │ ├── DrawableTreeNode.tsx │ │ │ └── FunctionTreeNode.tsx │ │ ├── dataVisualizerTypes.ts │ │ ├── drawable │ │ │ ├── Drawable.ts │ │ │ ├── NullDrawable.tsx │ │ │ └── ArrowDrawable.tsx │ │ └── Config.ts │ ├── sicp │ │ ├── chatCompletion │ │ │ └── sicpNotes.ts │ │ ├── TableOfContentsButton.tsx │ │ ├── utils │ │ │ └── SicpUtils.ts │ │ ├── TableOfContentsHelper.ts │ │ ├── errors │ │ │ └── SicpErrorBoundary.tsx │ │ └── __tests__ │ │ │ └── TableOfContentsHelper.test.ts │ ├── persistence │ │ ├── PersistenceTypes.ts │ │ └── PersistenceActions.ts │ ├── game │ │ ├── sound │ │ │ └── GameSoundTypes.ts │ │ ├── awards │ │ │ └── GameAwardsTypes.ts │ │ ├── dashboard │ │ │ ├── GameDashboardTypes.ts │ │ │ └── GameDashboardConstants.ts │ │ ├── character │ │ │ ├── GameCharacterConstants.ts │ │ │ └── GameCharacterTypes.ts │ │ ├── mode │ │ │ ├── GameModeTypes.ts │ │ │ ├── explore │ │ │ │ └── GameModeExploreConstants.ts │ │ │ ├── sequence │ │ │ │ └── GameModeSequence.ts │ │ │ ├── talk │ │ │ │ └── GameModeTalkConstants.ts │ │ │ ├── move │ │ │ │ └── GameModeMoveConstants.ts │ │ │ └── menu │ │ │ │ └── GameModeMenuConstants.ts │ │ ├── state │ │ │ ├── GameStateConstants.ts │ │ │ └── GameStateTypes.ts │ │ ├── task │ │ │ └── GameTaskTypes.ts │ │ ├── quiz │ │ │ └── GameQuizType.ts │ │ ├── location │ │ │ └── GameMapHelper.ts │ │ ├── popUp │ │ │ └── GamePopUpConstants.ts │ │ ├── input │ │ │ └── GameInputConstants.ts │ │ ├── boundingBoxes │ │ │ └── GameBoundingBoxTypes.ts │ │ ├── chapter │ │ │ └── GameChapterMocks.ts │ │ ├── phase │ │ │ └── GamePhaseTypes.ts │ │ ├── layer │ │ │ └── GameLayerTypes.ts │ │ ├── utils │ │ │ └── TextUtils.ts │ │ ├── commons │ │ │ └── CommonConstants.ts │ │ ├── assets │ │ │ ├── TextAssets.ts │ │ │ ├── FontAssets.ts │ │ │ └── AssetsTypes.ts │ │ ├── scenes │ │ │ ├── gameManager │ │ │ │ └── GameManagerHelper.ts │ │ │ ├── checkpointTransition │ │ │ │ └── CheckpointTransitionConstants.ts │ │ │ ├── bindings │ │ │ │ └── BindingsConstants.ts │ │ │ ├── settings │ │ │ │ └── SettingsConstants.ts │ │ │ └── mainMenu │ │ │ │ └── MainMenuConstants.ts │ │ ├── log │ │ │ └── GameLogConstants.ts │ │ └── dialogue │ │ │ └── GameDialogueConstants.ts │ ├── eventLogging │ │ └── client.ts │ ├── directory │ │ ├── PluginDirectoryTypes.ts │ │ ├── LanguageDirectoryTypes.ts │ │ ├── PluginDirectoryActions.ts │ │ ├── flagDirectoryLanguageEnable.ts │ │ ├── flagDirectoryPluginUrl.ts │ │ ├── flagDirectoryLanguageUrl.ts │ │ ├── LanguageDirectoryActions.ts │ │ ├── PluginDirectoryReducer.ts │ │ └── LanguageDirectoryReducer.ts │ ├── academy │ │ ├── AcademyTypes.ts │ │ └── AcademyActions.ts │ ├── conductor │ │ ├── flagConductorEnable.ts │ │ ├── flagConductorEvaluatorUrl.ts │ │ ├── createConductor.ts │ │ └── BrowserHostPlugin.ts │ ├── playground │ │ ├── PlaygroundTypes.ts │ │ └── __tests__ │ │ │ ├── PlaygroundReducer.test.ts │ │ │ └── PlaygroundActions.test.ts │ ├── sourceRecorder │ │ ├── sourcereel │ │ │ └── SourcereelTypes.ts │ │ └── sourcecast │ │ │ ├── SourcecastActions.ts │ │ │ └── SourcecastTypes.ts │ ├── teamFormation │ │ └── TeamFormationTypes.ts │ ├── dashboard │ │ ├── DashboardTypes.ts │ │ ├── DashboardActions.ts │ │ └── DashboardReducer.ts │ ├── gameSimulator │ │ ├── GameSimulatorUtils.ts │ │ └── GameSimulatorTypes.ts │ ├── achievement │ │ ├── __tests__ │ │ │ ├── AchievementReducer.test.ts │ │ │ └── AchievementActions.test.ts │ │ └── AchievementReducer.ts │ ├── remoteExecution │ │ ├── PeripheralContainer.tsx │ │ └── RemoteExecutionActions.ts │ ├── cseMachine │ │ ├── components │ │ │ ├── arrows │ │ │ │ ├── ArrowFromFrame.tsx │ │ │ │ └── ArrowFromStashItemComponent.tsx │ │ │ └── Visible.tsx │ │ └── CseMachineControlStashConfig.ts │ ├── leaderboard │ │ └── LeaderboardTypes.ts │ └── groundControl │ │ └── GroundControlActions.ts ├── pages │ ├── welcome │ │ └── Welcome.module.scss │ ├── sicp │ │ ├── subcomponents │ │ │ ├── SicpLatex.tsx │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── SicpLatex.test.tsx.snap │ │ │ │ ├── SicpIndexPage.test.tsx │ │ │ │ ├── SicpToc.test.tsx │ │ │ │ ├── SicpLatex.test.tsx │ │ │ │ └── CodeSnippet.test.tsx │ │ │ └── chatbot │ │ │ │ └── types.tsx │ │ └── __tests__ │ │ │ └── __snapshots__ │ │ │ └── Sicp.test.tsx.snap │ ├── academy │ │ ├── grading │ │ │ └── subcomponents │ │ │ │ ├── GradingFilterable.tsx │ │ │ │ ├── GradingColumnFilters.tsx │ │ │ │ └── GradingSubmissionFilters.tsx │ │ ├── teamFormation │ │ │ └── subcomponents │ │ │ │ ├── TeamFormationFilters.tsx │ │ │ │ └── TeamFormationBadges.tsx │ │ ├── groundControl │ │ │ └── configureControls │ │ │ │ ├── DispatchContestXpButton.tsx │ │ │ │ └── CalculateContestScoreButton.tsx │ │ ├── adminPanel │ │ │ └── subcomponents │ │ │ │ └── assessmentConfigPanel │ │ │ │ ├── BooleanCell.tsx │ │ │ │ └── NumericCell.tsx │ │ └── gameSimulator │ │ │ └── subcomponents │ │ │ └── assetViewer │ │ │ └── AssetViewerPreview.tsx │ ├── notFound │ │ └── NotFound.tsx │ ├── contributors │ │ └── Contributors.tsx │ ├── login │ │ └── Login.tsx │ └── leaderboard │ │ └── subcomponents │ │ └── ContestLeaderboardWrapper.tsx ├── global.d.ts └── bootstrap │ ├── sentry.ts │ └── agGrid.ts ├── public ├── assets │ ├── pixel.png │ ├── zekton.png │ ├── zekton_dark.png │ ├── alien_and_cows.png │ ├── alien_league.png │ ├── Sample_Profile_1.jpg │ ├── Sample_Profile_2.jpg │ ├── Sample_Profile_3.jpg │ ├── Sample_Profile_4.jpg │ ├── Sample_Profile_5.jpg │ ├── Sample_Profile_6.jpg │ ├── Sample_Profile_7.jpg │ ├── mockRoomPreviewMapping.txt │ ├── mockChapter2.txt │ ├── mockChapter1.txt │ ├── mockAwardsMapping.txt │ └── mockDefaultCheckpoint.txt ├── icons │ ├── favicon.ico │ ├── maskable.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ └── android-chrome-256x256.png └── manifest.json ├── .prettierrc ├── scripts └── test-coveralls.sh ├── .github ├── dependabot.yml └── pull_request_template.md ├── .vscode └── settings.json ├── .editorconfig ├── renovate.json ├── tsconfig.json ├── .gitignore └── vitest.config.ts /.node-version: -------------------------------------------------------------------------------- 1 | 22.17.0 2 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | bash scripts/test.sh 2 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/fileMock.ts: -------------------------------------------------------------------------------- 1 | // For mocking binary files like images 2 | export default {}; 3 | -------------------------------------------------------------------------------- /src/assets/SA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/src/assets/SA.jpg -------------------------------------------------------------------------------- /public/assets/pixel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/pixel.png -------------------------------------------------------------------------------- /public/assets/zekton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/zekton.png -------------------------------------------------------------------------------- /public/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/icons/favicon.ico -------------------------------------------------------------------------------- /src/commons/application/types/VscodeTypes.ts: -------------------------------------------------------------------------------- 1 | export type VscodeState = { 2 | isVscode: boolean; 3 | }; 4 | -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/sideContent/sessionManagement.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "姓名", 3 | "role": "角色" 4 | } 5 | -------------------------------------------------------------------------------- /public/icons/maskable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/icons/maskable.png -------------------------------------------------------------------------------- /src/i18n/locales/en/sideContent/sessionManagement.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Name", 3 | "role": "Role" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging In": "登录中...", 3 | "Log in with": "使用 {{name}} 登录" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/sideContent/faceapiDisplay.json: -------------------------------------------------------------------------------- 1 | { 2 | "takePicture": "拍照", 3 | "reset": "重置" 4 | } 5 | -------------------------------------------------------------------------------- /public/assets/zekton_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/zekton_dark.png -------------------------------------------------------------------------------- /src/assets/default-avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/src/assets/default-avatar.jpg -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/sideContent/htmlDisplay.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "HTML 显示", 3 | "label": "HTML 显示" 4 | } 5 | -------------------------------------------------------------------------------- /src/styles/Stories.module.scss: -------------------------------------------------------------------------------- 1 | @import '_global'; 2 | 3 | .highlight-row { 4 | background-color: #e0f2fe; 5 | } 6 | -------------------------------------------------------------------------------- /public/assets/alien_and_cows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/alien_and_cows.png -------------------------------------------------------------------------------- /public/assets/alien_league.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/alien_league.png -------------------------------------------------------------------------------- /src/assets/login_background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/src/assets/login_background.jpg -------------------------------------------------------------------------------- /src/i18n/locales/en/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging In": "Logging In...", 3 | "Log in with": "Log in with {{name}}" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/locales/en/sideContent/faceapiDisplay.json: -------------------------------------------------------------------------------- 1 | { 2 | "takePicture": "Take picture", 3 | "reset": "Reset" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/locales/en/sideContent/htmlDisplay.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "HTML Display", 3 | "label": "HTML Display" 4 | } 5 | -------------------------------------------------------------------------------- /public/assets/Sample_Profile_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/Sample_Profile_1.jpg -------------------------------------------------------------------------------- /public/assets/Sample_Profile_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/Sample_Profile_2.jpg -------------------------------------------------------------------------------- /public/assets/Sample_Profile_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/Sample_Profile_3.jpg -------------------------------------------------------------------------------- /public/assets/Sample_Profile_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/Sample_Profile_4.jpg -------------------------------------------------------------------------------- /public/assets/Sample_Profile_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/Sample_Profile_5.jpg -------------------------------------------------------------------------------- /public/assets/Sample_Profile_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/Sample_Profile_6.jpg -------------------------------------------------------------------------------- /public/assets/Sample_Profile_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/assets/Sample_Profile_7.jpg -------------------------------------------------------------------------------- /public/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /src/assets/academy_background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/src/assets/academy_background.jpg -------------------------------------------------------------------------------- /src/assets/default_cover_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/src/assets/default_cover_image.jpg -------------------------------------------------------------------------------- /src/i18n/locales/pseudo/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging In": "Lògging Ìn...", 3 | "Log in with": "Lòg in with {{name}}" 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/leaderboard_background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/src/assets/leaderboard_background.jpg -------------------------------------------------------------------------------- /public/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/icons/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/source-academy/frontend/HEAD/public/icons/android-chrome-256x256.png -------------------------------------------------------------------------------- /src/features/github/GitHubTypes.ts: -------------------------------------------------------------------------------- 1 | export type GitHubSaveInfo = { 2 | repoName: string; 3 | filePath: string; 4 | lastSaved?: Date; 5 | }; 6 | -------------------------------------------------------------------------------- /public/assets/mockRoomPreviewMapping.txt: -------------------------------------------------------------------------------- 1 | 405 2 | /locations/yourRoom-dim/normal.png 3 | 4 | 404 5 | /locations/deathCube_ext/shields-down.png 6 | -------------------------------------------------------------------------------- /src/i18n/locales/pseudo/index.ts: -------------------------------------------------------------------------------- 1 | import commons from './commons.json'; 2 | import login from './login.json'; 3 | 4 | export default { 5 | commons, 6 | login 7 | }; 8 | -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/sideContent/contestVoting.json: -------------------------------------------------------------------------------- 1 | { 2 | "noEntries": "未找到符合条件的投票条目。", 3 | "title": "比赛投票", 4 | "tooltip": "从 D(最差)到 S(最佳)为您最喜欢的比赛条目排名!" 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/stories.json: -------------------------------------------------------------------------------- 1 | { 2 | "stories": { 3 | "deleteConfirmation": "您确定要删除此故事吗?", 4 | "delete": "删除", 5 | "allStories": "所有故事" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "printWidth": 100, 5 | "arrowParens": "avoid", 6 | "trailingComma": "none", 7 | "endOfLine": "auto" 8 | } 9 | -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/sourcecast.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourcecast": { 3 | "titleDescription": "标题:{{title}}\n描述:{{description}}", 4 | "introduction": "欢迎来到 Sourcecast!" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/features/dataVisualizer/tree/BaseTreeNode.ts: -------------------------------------------------------------------------------- 1 | export class TreeNode { 2 | public children: TreeNode[] | null; 3 | 4 | constructor() { 5 | this.children = null; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/features/sicp/chatCompletion/sicpNotes.ts: -------------------------------------------------------------------------------- 1 | import { SicpSection } from './chatCompletion'; 2 | 3 | const sicpNotes: Partial> = {}; 4 | 5 | export default sicpNotes; 6 | -------------------------------------------------------------------------------- /src/styles/_variableHighlighting.scss: -------------------------------------------------------------------------------- 1 | .ace_variable_highlighting { 2 | z-index: 4; 3 | position: absolute; 4 | box-sizing: border-box; 5 | border: 1px dashed rgba(255, 255, 255, 0.6); 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/locales/en/sourcecast.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourcecast": { 3 | "titleDescription": "Title: {{title}}\nDescription: {{description}}", 4 | "introduction": "Welcome to Sourcecast!" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/locales/en/stories.json: -------------------------------------------------------------------------------- 1 | { 2 | "stories": { 3 | "deleteConfirmation": "Are you sure you want to delete this story?", 4 | "delete": "Delete", 5 | "allStories": "All Stories" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/commons/application/types/CommonsTypes.ts: -------------------------------------------------------------------------------- 1 | import type { createBrowserRouter } from 'react-router'; 2 | 3 | export type Router = ReturnType; 4 | export type RouterState = Router | null; 5 | -------------------------------------------------------------------------------- /src/features/persistence/PersistenceTypes.ts: -------------------------------------------------------------------------------- 1 | export type PersistenceState = 'INACTIVE' | 'SAVED' | 'DIRTY'; 2 | 3 | export type PersistenceFile = { 4 | id: string; 5 | name: string; 6 | lastSaved?: Date; 7 | }; 8 | -------------------------------------------------------------------------------- /scripts/test-coveralls.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | ./scripts/coverage-fix.sh do && \ 6 | yarn test --coverage --coverage.reporter=lcov \ 7 | --coverage.exclude='**/src/features/game/**' 8 | -------------------------------------------------------------------------------- /src/commons/repl/ReplTypes.ts: -------------------------------------------------------------------------------- 1 | import { InterpreterOutput } from '../application/ApplicationTypes'; 2 | 3 | export type OutputProps = { 4 | output: InterpreterOutput; 5 | usingSubst?: boolean; 6 | isHtml?: boolean; 7 | }; 8 | -------------------------------------------------------------------------------- /src/styles/_game.scss: -------------------------------------------------------------------------------- 1 | #game-display { 2 | display: flex; 3 | flex-direction: column; 4 | width: 100%; 5 | align-items: center; 6 | } 7 | 8 | .fullscreen-button { 9 | position: absolute; 10 | z-index: 10; 11 | } 12 | -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/sourceRecorder.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourceRecorder": { 3 | "deleteTitle": "删除 Sourcecast", 4 | "deleteConfirmation": "您确定要删除此 Sourcecast 条目吗?", 5 | "confirmDelete": "确认删除", 6 | "cancel": "取消" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/features/game/sound/GameSoundTypes.ts: -------------------------------------------------------------------------------- 1 | export const bgMusicFadeDuration = 1000; 2 | 3 | export const musicFadeOutTween = { 4 | volume: 0, 5 | ease: 'Power2' 6 | }; 7 | 8 | export enum GameSoundType { 9 | SFX, 10 | BGM 11 | } 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: '/' 5 | schedule: 6 | interval: monthly 7 | time: '07:00' 8 | open-pull-requests-limit: 0 # soft disable for `renovate` migration test 9 | -------------------------------------------------------------------------------- /src/i18n/locales/en/sideContent/contestVoting.json: -------------------------------------------------------------------------------- 1 | { 2 | "noEntries": "There are no eligible entries for voting found.", 3 | "title": "Contest Voting", 4 | "tooltip": "Rank your favourite contest entries from tiers D (worst) to S (best)!" 5 | } 6 | -------------------------------------------------------------------------------- /src/commons/fileSystem/FileSystemTypes.ts: -------------------------------------------------------------------------------- 1 | import { FSModule } from 'browserfs/dist/node/core/FS'; 2 | 3 | export const SET_IN_BROWSER_FILE_SYSTEM = 'SET_IN_BROWSER_FILE_SYSTEM'; 4 | 5 | export type FileSystemState = { 6 | inBrowserFileSystem: FSModule | null; 7 | }; 8 | -------------------------------------------------------------------------------- /src/i18n/locales/en/sourceRecorder.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourceRecorder": { 3 | "deleteTitle": "Delete Sourcecast", 4 | "deleteConfirmation": "Are you sure to delete this sourcecast entry?", 5 | "confirmDelete": "Confirm Delete", 6 | "cancel": "Cancel" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/features/github/GitHubActions.ts: -------------------------------------------------------------------------------- 1 | import { createActions } from 'src/commons/redux/utils'; 2 | 3 | const newActions = createActions('github', { 4 | githubOpenFile: 0, 5 | githubSaveFile: 0, 6 | githubSaveFileAs: 0 7 | }); 8 | 9 | export default newActions; 10 | -------------------------------------------------------------------------------- /src/features/eventLogging/client.ts: -------------------------------------------------------------------------------- 1 | export const SYNC_LOGS = 'SYNC_LOGS'; 2 | 3 | export function triggerSyncLogs(accessToken?: string) { 4 | if (!accessToken) { 5 | return; 6 | } 7 | navigator.serviceWorker.controller?.postMessage({ type: SYNC_LOGS, accessToken }); 8 | } 9 | -------------------------------------------------------------------------------- /src/features/directory/PluginDirectoryTypes.ts: -------------------------------------------------------------------------------- 1 | import { IPluginDefinition } from '@sourceacademy/plugin-directory/dist/types'; 2 | 3 | export type PluginDirectoryState = { 4 | readonly plugins: IPluginDefinition[]; 5 | readonly pluginMap: Record; 6 | }; 7 | -------------------------------------------------------------------------------- /src/pages/welcome/Welcome.module.scss: -------------------------------------------------------------------------------- 1 | .fullpage { 2 | margin-top: 20px; 3 | display: flex; 4 | justify-content: center; 5 | } 6 | 7 | .fullpage-content { 8 | display: flex; 9 | justify-content: center; 10 | } 11 | 12 | .text-left { 13 | text-align: left; 14 | } 15 | -------------------------------------------------------------------------------- /src/styles/_playground.scss: -------------------------------------------------------------------------------- 1 | .Playground { 2 | height: 100%; 3 | display: flex; 4 | flex-direction: column; 5 | flex: 1 1 100%; 6 | 7 | .workspace { 8 | .ControlBar { 9 | .ControlBar_editingWorkspace { 10 | width: 0; 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "eslint.useFlatConfig": true, 4 | "files.insertFinalNewline": true, 5 | "liveServer.settings.file": "/index.html", 6 | "liveServer.settings.NoBrowser": true, 7 | "liveServer.settings.root": "/build" 8 | } 9 | -------------------------------------------------------------------------------- /src/features/dataVisualizer/tree/TreeNode.ts: -------------------------------------------------------------------------------- 1 | export { TreeNode } from './BaseTreeNode'; 2 | export { DataTreeNode } from './DataTreeNode'; 3 | export { DrawableTreeNode } from './DrawableTreeNode'; 4 | export { FunctionTreeNode } from './FunctionTreeNode'; 5 | export { ArrayTreeNode } from './ArrayTreeNode'; 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | end_of_line = lf 6 | 7 | [*.{ts,tsx,json}] 8 | indent_style = space 9 | indent_size = 2 10 | 11 | [*.md] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.{html,css}] 16 | indent_style = space 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/sideContent/resultCard.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeout": "[超时] 提交的测试用例超出时间限制。", 3 | "syntax": "[语法] 第 {{line}} 行:{{errorExplanation}}", 4 | "runtime": "[运行时] 第 {{line}} 行:{{errorExplanation}}", 5 | "systemError": "[系统] {{errorMessage}}", 6 | "unknown": "[未知] 自动评分器错误:类型 {{errorType}}" 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/sicp/subcomponents/SicpLatex.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Latex from 'react-latex-next'; 3 | 4 | type Props = { 5 | math: string; 6 | }; 7 | 8 | const SicpLatex: React.FC = ({ math }) => { 9 | return {math}; 10 | }; 11 | 12 | export default SicpLatex; 13 | -------------------------------------------------------------------------------- /public/assets/mockChapter2.txt: -------------------------------------------------------------------------------- 1 | startingLoc: emergency 2 | 3 | objectives 4 | finish 5 | 6 | emergency 7 | actions 8 | show_dialogue(chapter2) 9 | complete_objective(finish) 10 | 11 | dialogues 12 | chapter2 13 | Hold it, we have an emergency. You're now at chapter 2! 14 | -------------------------------------------------------------------------------- /src/commons/application/actions/VscodeActions.ts: -------------------------------------------------------------------------------- 1 | import { createActions } from 'src/commons/redux/utils'; 2 | 3 | const VscodeActions = createActions('vscode', { 4 | setVscode: 0 5 | }); 6 | 7 | // For compatibility with existing code (actions helper) 8 | export default { 9 | ...VscodeActions 10 | }; 11 | -------------------------------------------------------------------------------- /src/features/game/awards/GameAwardsTypes.ts: -------------------------------------------------------------------------------- 1 | import { AssetKey, AssetPath, ItemId } from '../commons/CommonTypes'; 2 | 3 | export type AwardProperty = { 4 | id: ItemId; 5 | assetKey: AssetKey; 6 | assetPath: AssetPath; 7 | title: string; 8 | description: string; 9 | completed: boolean; 10 | }; 11 | -------------------------------------------------------------------------------- /public/assets/mockChapter1.txt: -------------------------------------------------------------------------------- 1 | startingLoc: hallway 2 | 3 | objectives 4 | finish 5 | 6 | hallway 7 | actions 8 | show_dialogue(chapter1) 9 | complete_objective(finish) 10 | 11 | dialogues 12 | chapter1, What? 13 | You're now in chapter 1. 14 | I'm glad you're part of it 15 | -------------------------------------------------------------------------------- /src/features/game/dashboard/GameDashboardTypes.ts: -------------------------------------------------------------------------------- 1 | export enum DashboardPage { 2 | Log = 'Log', 3 | Tasks = 'Tasks', 4 | Collectibles = 'Collectibles', 5 | Achievements = 'Achievements' 6 | } 7 | 8 | export interface DashboardPageManager { 9 | createUIContainer: () => Phaser.GameObjects.Container; 10 | } 11 | -------------------------------------------------------------------------------- /src/styles/NavigationBar.module.scss: -------------------------------------------------------------------------------- 1 | @import '_global'; 2 | 3 | .primary-navbar { 4 | background: #141e30; /* fallback for old browsers */ 5 | background: -webkit-linear-gradient(to right, #141e30, #243b55); /* Chrome 10-25, Safari 5.1-6 */ 6 | background: linear-gradient(to right, $cadet-color-1, $cadet-color-2); 7 | } 8 | -------------------------------------------------------------------------------- /src/commons/gitHubOverlay/GitHubFileNodeData.tsx: -------------------------------------------------------------------------------- 1 | export class GitHubFileNodeData { 2 | childrenRetrieved: boolean = false; 3 | filePath: string = 'dummy_path'; 4 | fileType: string = 'unset'; 5 | 6 | constructor(path: string, type: string) { 7 | this.filePath = path; 8 | this.fileType = type; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/features/dataVisualizer/dataVisualizerTypes.ts: -------------------------------------------------------------------------------- 1 | // Source-related types 2 | export type Data = any; 3 | export type Pair = [Data, Data]; 4 | export type EmptyList = null; 5 | export type List = [Data, List] | EmptyList; 6 | 7 | // Drawing-related types 8 | export type Drawing = JSX.Element; 9 | export type Step = Drawing[]; 10 | -------------------------------------------------------------------------------- /src/commons/application/actions/__tests__/CommonsActions.test.ts: -------------------------------------------------------------------------------- 1 | import CommonsActions from '../CommonsActions'; 2 | 3 | test('logOut generates correct action object', () => { 4 | const action = CommonsActions.logOut(); 5 | expect(action).toEqual({ 6 | type: CommonsActions.logOut.type, 7 | payload: {} 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/i18n/locales/zh-SG/sideContent/dataVisualizer.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultText": "数据可视化工具帮助您可视化数据结构。", 3 | "instructions": "通过调用函数 <0/> 激活,其中 <1/> 是您想要可视化的 <2/> 数据结构,<3/> 是结构的数量。", 4 | "reference": "数据可视化工具使用框图和指针图,这些图基于<0>《计算机程序的构造和解释,JavaScript 版》第 2 章第 2 节中介绍的符号。", 5 | "label": "数据可视化工具", 6 | "previous": "上一个", 7 | "next": "下一个" 8 | } 9 | -------------------------------------------------------------------------------- /src/styles/ConfirmDialog.module.scss: -------------------------------------------------------------------------------- 1 | .ConfirmDialog { 2 | .large-button:not(:first-of-type) { 3 | margin-top: 0.5em; 4 | } 5 | 6 | @media only screen and (max-width: 500px) { 7 | // Set width to 98% when screen width is less than 500px 8 | // 500px is the default width of the component 9 | width: 98%; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/commons/featureFlags/featureSelector.ts: -------------------------------------------------------------------------------- 1 | import { OverallState } from '../application/ApplicationTypes'; 2 | import { FeatureFlag } from './FeatureFlag'; 3 | 4 | export function featureSelector(featureFlag: FeatureFlag) { 5 | return (state: OverallState) => 6 | (state.featureFlags.modifiedFlags[featureFlag.flagName] || featureFlag.defaultValue) as T; 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/sicp/subcomponents/__tests__/__snapshots__/SicpLatex.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`Sicp latex renders > correctly block 1`] = ` 4 | 5 | 1+1 6 | 7 | `; 8 | 9 | exports[`Sicp latex renders > correctly inline 1`] = ` 10 | 11 | 1+1 12 | 13 | `; 14 | -------------------------------------------------------------------------------- /src/i18n/i18next.d.ts: -------------------------------------------------------------------------------- 1 | import 'i18next'; 2 | 3 | import { defaultLanguage, i18nLanguageCode } from './locales'; 4 | 5 | export type i18nDefaultLangKeys = (typeof defaultLanguage)[i18nLanguageCode.DEFAULT]; 6 | 7 | declare module 'i18next' { 8 | // Extend CustomTypeOptions 9 | interface CustomTypeOptions { 10 | resources: i18nDefaultLangKeys; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/pages/sicp/subcomponents/chatbot/types.tsx: -------------------------------------------------------------------------------- 1 | type ChatMessage = { 2 | role: 'user' | 'assistant'; 3 | content: string; 4 | }; 5 | 6 | type InitChatResponse = { 7 | response: ChatMessage; 8 | conversationId: string; 9 | maxContentSize: number; 10 | }; 11 | 12 | type ContinueChatResponse = { 13 | response: string; 14 | conversationId: string; 15 | }; 16 | -------------------------------------------------------------------------------- /src/styles/Draggable.module.scss: -------------------------------------------------------------------------------- 1 | .draggable { 2 | cursor: move; 3 | cursor: -webkit-grab; 4 | cursor: -moz-grab; 5 | cursor: grab; 6 | } 7 | 8 | /* During drag */ 9 | .draggable:active { 10 | cursor: -webkit-grabbing; 11 | cursor: -moz-grabbing; 12 | cursor: grabbing; 13 | } 14 | 15 | /* For clicking */ 16 | .clickable { 17 | cursor: pointer; 18 | } 19 | -------------------------------------------------------------------------------- /src/features/dataVisualizer/drawable/Drawable.ts: -------------------------------------------------------------------------------- 1 | export { default as ArrayDrawable } from './ArrayDrawable'; 2 | export { default as ArrowDrawable } from './ArrowDrawable'; 3 | export { default as BackwardArrowDrawable } from './BackwardArrowDrawable'; 4 | export { default as FunctionDrawable } from './FunctionDrawable'; 5 | export { default as NullDrawable } from './NullDrawable'; 6 | -------------------------------------------------------------------------------- /src/i18n/locales/en/sideContent/resultCard.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeout": "[TIMEOUT] Submission exceeded time limit for this test case.", 3 | "syntax": "[SYNTAX] Line {{line}}: {{errorExplanation}}", 4 | "runtime": "[RUNTIME] Line {{line}}: {{errorExplanation}}", 5 | "systemError": "[SYSTEM] {{errorMessage}}", 6 | "unknown": "[UNKNOWN] Autograder error: type {{errorType}}" 7 | } 8 | -------------------------------------------------------------------------------- /src/commons/sideContent/__tests__/__snapshots__/SideContentHtmlDisplay.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`HTML Display renders correctly 1`] = ` 4 |