From 86b3af694d34ef0933df455ff12a5ebc52979610 Mon Sep 17 00:00:00 2001 From: Brooke Date: Wed, 29 Jun 2022 15:35:32 -0700 Subject: [PATCH 001/346] PROD-2313 #comment add learn tool to platform UI #time 30m --- README.md | 2 +- package.json | 19 +- .../environment.default.config.ts | 1 + .../environments/environment.dev.config.ts | 5 +- .../environments/environment.prod.config.ts | 1 + src-ts/lib/breadcrumb/index.ts | 1 + src-ts/lib/global-config.model.ts | 1 + src-ts/lib/index.ts | 1 + .../lib/progress-bar/ProgressBar.module.scss | 16 ++ src-ts/lib/progress-bar/ProgressBar.tsx | 18 ++ src-ts/lib/progress-bar/index.ts | 1 + src-ts/lib/styles/_buttons.scss | 11 +- src-ts/lib/styles/mixins/_icons.mixins.scss | 10 + src-ts/lib/styles/mixins/_layout.mixins.scss | 26 +++ src-ts/lib/styles/variables/_layouts.scss | 3 +- src-ts/lib/styles/variables/_palette.scss | 1 + src-ts/lib/styles/variables/_spacing.scss | 1 + src-ts/tools/learn/Learn.tsx | 26 +++ .../CourseDetailsPage.module.scss | 53 +++++ .../course-details/CourseDetailsPage.tsx | 109 ++++++++++ .../CourseCurriculum.module.scss | 47 +++++ .../course-curriculum/CourseCurriculum.tsx | 90 ++++++++ .../CurriculumSummary.module.scss | 31 +++ .../curriculum-summary/CurriculumSummary.tsx | 64 ++++++ .../curriculum-summary/index.ts | 1 + .../course-details/course-curriculum/index.ts | 1 + .../TcAcademyPolicyModal.module.scss | 25 +++ .../TcAcademyPolicyModal.tsx | 70 +++++++ .../tc-academy-policy-modal/index.ts | 1 + src-ts/tools/learn/course-details/index.ts | 1 + .../promo-course/PromoCourse.module.scss | 18 ++ .../promo-course/PromoCourse.tsx | 32 +++ .../course-details/promo-course/index.ts | 1 + .../promo-course/learn-get-certified.svg | 45 ++++ .../free-code-camp/FreeCodeCamp.module.scss | 55 +++++ .../learn/free-code-camp/FreeCodeCamp.tsx | 193 ++++++++++++++++++ .../CollapsiblePane.module.scss | 54 +++++ .../collapsible-pane/CollapsiblePane.tsx | 40 ++++ .../free-code-camp/collapsible-pane/index.ts | 1 + src-ts/tools/learn/free-code-camp/index.ts | 1 + .../title-nav/TitleNav.module.scss | 40 ++++ .../free-code-camp/title-nav/TitleNav.tsx | 47 +++++ .../learn/free-code-camp/title-nav/index.ts | 1 + src-ts/tools/learn/index.ts | 1 + .../certification.store.ts | 11 + .../certifications-functions/index.ts | 2 + .../learn-certification.model.ts | 10 + .../certifications-provider-data.model.ts | 8 + .../certifications.provider.tsx | 32 +++ .../certifications-provider/index.ts | 3 + .../course-outline/CourseOutline.module.scss | 27 +++ .../course-outline/CourseOutline.tsx | 62 ++++++ .../CollapsibleItem.module.scss | 94 +++++++++ .../collapsible-item/CollapsibleItem.tsx | 110 ++++++++++ .../course-outline/collapsible-item/index.ts | 1 + .../learn/learn-lib/course-outline/index.ts | 1 + .../status-icon/StatusIcon.module.scss | 6 + .../course-outline/status-icon/StatusIcon.tsx | 36 ++++ .../course-outline/status-icon/index.ts | 1 + .../step-icon/StepIcon.module.scss | 25 +++ .../course-outline/step-icon/StepIcon.tsx | 27 +++ .../course-outline/step-icon/index.ts | 1 + .../course-title/CourseTitle.module.scss | 38 ++++ .../learn-lib/course-title/CourseTitle.tsx | 47 +++++ .../learn/learn-lib/course-title/index.ts | 1 + .../learn-challenge-badge-icon.svg | 11 + .../courses-functions/course.store.ts | 11 + .../courses-functions/index.ts | 2 + .../courses-functions/learn-course.model.ts | 14 ++ .../courses-provider-data.model.ts | 7 + .../courses-provider/courses.provider.tsx | 39 ++++ .../learn/learn-lib/courses-provider/index.ts | 3 + .../CurriculumSummary.module.scss | 39 ++++ .../curriculum-summary/CurriculumSummary.tsx | 46 +++++ .../learn-lib/curriculum-summary/index.ts | 1 + src-ts/tools/learn/learn-lib/index.ts | 11 + .../tools/learn/learn-lib/learn-url.config.ts | 7 + .../learn/learn-lib/lesson-provider/index.ts | 6 + .../learn-lesson-meta.model.ts | 13 ++ .../lesson-provider/learn-lesson.model.ts | 4 + .../learn-module-meta.model.ts | 10 + .../lesson-provider/learn-module.model.ts | 8 + .../lesson-provider-data.model.ts | 7 + .../lesson-provider/lesson.provider.tsx | 67 ++++++ .../my-certifications-provider/index.ts | 7 + .../learn-my-certification-progress.model.ts | 10 + .../learn-my-certification.model.ts | 7 + .../learn-my-module-progress.model.ts | 8 + ...tification-progress-provider-data.model.ts | 7 + .../my-certification-progress.provider.tsx | 35 ++++ .../my-certifications.json | 53 +++++ .../my-certifications-provider-data.model.ts | 9 + .../my-certifications.provider.tsx | 39 ++++ .../completed/Completed.module.scss | 35 ++++ .../my-course-card/completed/Completed.tsx | 43 ++++ .../my-course-card/completed/index.tsx | 1 + .../in-progress/InProgress.module.scss | 86 ++++++++ .../my-course-card/in-progress/InProgress.tsx | 114 +++++++++++ .../my-course-card/in-progress/index.ts | 1 + .../learn/learn-lib/my-course-card/index.ts | 2 + src-ts/tools/learn/learn-lib/svgs/index.ts | 3 + .../learn/learn-lib/svgs/learning-hat.svg | 25 +++ .../learn-lib/wave-hero/WaveHero.module.scss | 36 ++++ .../learn/learn-lib/wave-hero/WaveHero.tsx | 36 ++++ .../tools/learn/learn-lib/wave-hero/index.ts | 1 + .../learn-welcome-bg-curve-white.png | Bin 0 -> 1855 bytes .../wave-hero/learn-welcome-bg-curve.png | Bin 0 -> 4129 bytes src-ts/tools/learn/learn.routes.tsx | 67 ++++++ .../learn/my-learning/MyLearning.module.scss | 37 ++++ src-ts/tools/learn/my-learning/MyLearning.tsx | 71 +++++++ .../hero-card/HeroCard.module.scss | 21 ++ .../learn/my-learning/hero-card/HeroCard.tsx | 31 +++ .../learn/my-learning/hero-card/index.ts | 1 + src-ts/tools/learn/my-learning/index.ts | 1 + .../learn/welcome/WelcomePage.module.scss | 17 ++ src-ts/tools/learn/welcome/WelcomePage.tsx | 69 +++++++ .../courses-card/CoursesCard.module.scss | 35 ++++ .../welcome/courses-card/CoursesCard.tsx | 45 ++++ .../tools/learn/welcome/courses-card/index.ts | 1 + src-ts/tools/learn/welcome/index.ts | 1 + .../progress-block/ProgressBlock.module.scss | 28 +++ .../welcome/progress-block/ProgressBlock.tsx | 72 +++++++ .../learn/welcome/progress-block/index.ts | 1 + .../init-state/InitState.module.scss | 16 ++ .../progress-block/init-state/InitState.tsx | 26 +++ .../progress-block/init-state/index.ts | 1 + src-ts/tools/tools.routes.ts | 2 + start-ssl-bsouza.sh | 1 + start-ssl.sh | 1 + yarn.lock | 34 +-- 130 files changed, 3118 insertions(+), 34 deletions(-) create mode 100644 src-ts/lib/progress-bar/ProgressBar.module.scss create mode 100644 src-ts/lib/progress-bar/ProgressBar.tsx create mode 100644 src-ts/lib/progress-bar/index.ts create mode 100644 src-ts/tools/learn/Learn.tsx create mode 100644 src-ts/tools/learn/course-details/CourseDetailsPage.module.scss create mode 100644 src-ts/tools/learn/course-details/CourseDetailsPage.tsx create mode 100644 src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.module.scss create mode 100644 src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.tsx create mode 100644 src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/CurriculumSummary.module.scss create mode 100644 src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/CurriculumSummary.tsx create mode 100644 src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/index.ts create mode 100644 src-ts/tools/learn/course-details/course-curriculum/index.ts create mode 100644 src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/TcAcademyPolicyModal.module.scss create mode 100644 src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/TcAcademyPolicyModal.tsx create mode 100644 src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/index.ts create mode 100644 src-ts/tools/learn/course-details/index.ts create mode 100644 src-ts/tools/learn/course-details/promo-course/PromoCourse.module.scss create mode 100644 src-ts/tools/learn/course-details/promo-course/PromoCourse.tsx create mode 100644 src-ts/tools/learn/course-details/promo-course/index.ts create mode 100755 src-ts/tools/learn/course-details/promo-course/learn-get-certified.svg create mode 100644 src-ts/tools/learn/free-code-camp/FreeCodeCamp.module.scss create mode 100644 src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx create mode 100644 src-ts/tools/learn/free-code-camp/collapsible-pane/CollapsiblePane.module.scss create mode 100644 src-ts/tools/learn/free-code-camp/collapsible-pane/CollapsiblePane.tsx create mode 100644 src-ts/tools/learn/free-code-camp/collapsible-pane/index.ts create mode 100644 src-ts/tools/learn/free-code-camp/index.ts create mode 100755 src-ts/tools/learn/free-code-camp/title-nav/TitleNav.module.scss create mode 100755 src-ts/tools/learn/free-code-camp/title-nav/TitleNav.tsx create mode 100755 src-ts/tools/learn/free-code-camp/title-nav/index.ts create mode 100644 src-ts/tools/learn/index.ts create mode 100755 src-ts/tools/learn/learn-lib/certifications-provider/certifications-functions/certification.store.ts create mode 100755 src-ts/tools/learn/learn-lib/certifications-provider/certifications-functions/index.ts create mode 100644 src-ts/tools/learn/learn-lib/certifications-provider/certifications-functions/learn-certification.model.ts create mode 100755 src-ts/tools/learn/learn-lib/certifications-provider/certifications-provider-data.model.ts create mode 100644 src-ts/tools/learn/learn-lib/certifications-provider/certifications.provider.tsx create mode 100755 src-ts/tools/learn/learn-lib/certifications-provider/index.ts create mode 100644 src-ts/tools/learn/learn-lib/course-outline/CourseOutline.module.scss create mode 100644 src-ts/tools/learn/learn-lib/course-outline/CourseOutline.tsx create mode 100644 src-ts/tools/learn/learn-lib/course-outline/collapsible-item/CollapsibleItem.module.scss create mode 100644 src-ts/tools/learn/learn-lib/course-outline/collapsible-item/CollapsibleItem.tsx create mode 100644 src-ts/tools/learn/learn-lib/course-outline/collapsible-item/index.ts create mode 100644 src-ts/tools/learn/learn-lib/course-outline/index.ts create mode 100755 src-ts/tools/learn/learn-lib/course-outline/status-icon/StatusIcon.module.scss create mode 100755 src-ts/tools/learn/learn-lib/course-outline/status-icon/StatusIcon.tsx create mode 100755 src-ts/tools/learn/learn-lib/course-outline/status-icon/index.ts create mode 100755 src-ts/tools/learn/learn-lib/course-outline/step-icon/StepIcon.module.scss create mode 100755 src-ts/tools/learn/learn-lib/course-outline/step-icon/StepIcon.tsx create mode 100755 src-ts/tools/learn/learn-lib/course-outline/step-icon/index.ts create mode 100644 src-ts/tools/learn/learn-lib/course-title/CourseTitle.module.scss create mode 100644 src-ts/tools/learn/learn-lib/course-title/CourseTitle.tsx create mode 100644 src-ts/tools/learn/learn-lib/course-title/index.ts create mode 100644 src-ts/tools/learn/learn-lib/course-title/learn-challenge-badge-icon.svg create mode 100755 src-ts/tools/learn/learn-lib/courses-provider/courses-functions/course.store.ts create mode 100755 src-ts/tools/learn/learn-lib/courses-provider/courses-functions/index.ts create mode 100644 src-ts/tools/learn/learn-lib/courses-provider/courses-functions/learn-course.model.ts create mode 100755 src-ts/tools/learn/learn-lib/courses-provider/courses-provider-data.model.ts create mode 100644 src-ts/tools/learn/learn-lib/courses-provider/courses.provider.tsx create mode 100755 src-ts/tools/learn/learn-lib/courses-provider/index.ts create mode 100644 src-ts/tools/learn/learn-lib/curriculum-summary/CurriculumSummary.module.scss create mode 100644 src-ts/tools/learn/learn-lib/curriculum-summary/CurriculumSummary.tsx create mode 100644 src-ts/tools/learn/learn-lib/curriculum-summary/index.ts create mode 100755 src-ts/tools/learn/learn-lib/index.ts create mode 100755 src-ts/tools/learn/learn-lib/learn-url.config.ts create mode 100755 src-ts/tools/learn/learn-lib/lesson-provider/index.ts create mode 100644 src-ts/tools/learn/learn-lib/lesson-provider/learn-lesson-meta.model.ts create mode 100644 src-ts/tools/learn/learn-lib/lesson-provider/learn-lesson.model.ts create mode 100644 src-ts/tools/learn/learn-lib/lesson-provider/learn-module-meta.model.ts create mode 100644 src-ts/tools/learn/learn-lib/lesson-provider/learn-module.model.ts create mode 100755 src-ts/tools/learn/learn-lib/lesson-provider/lesson-provider-data.model.ts create mode 100644 src-ts/tools/learn/learn-lib/lesson-provider/lesson.provider.tsx create mode 100755 src-ts/tools/learn/learn-lib/my-certifications-provider/index.ts create mode 100644 src-ts/tools/learn/learn-lib/my-certifications-provider/learn-my-certification-progress.model.ts create mode 100644 src-ts/tools/learn/learn-lib/my-certifications-provider/learn-my-certification.model.ts create mode 100644 src-ts/tools/learn/learn-lib/my-certifications-provider/learn-my-module-progress.model.ts create mode 100755 src-ts/tools/learn/learn-lib/my-certifications-provider/my-certification-progress-provider-data.model.ts create mode 100644 src-ts/tools/learn/learn-lib/my-certifications-provider/my-certification-progress.provider.tsx create mode 100644 src-ts/tools/learn/learn-lib/my-certifications-provider/my-certifications-functions/my-certifications.json create mode 100755 src-ts/tools/learn/learn-lib/my-certifications-provider/my-certifications-provider-data.model.ts create mode 100644 src-ts/tools/learn/learn-lib/my-certifications-provider/my-certifications.provider.tsx create mode 100644 src-ts/tools/learn/learn-lib/my-course-card/completed/Completed.module.scss create mode 100644 src-ts/tools/learn/learn-lib/my-course-card/completed/Completed.tsx create mode 100644 src-ts/tools/learn/learn-lib/my-course-card/completed/index.tsx create mode 100644 src-ts/tools/learn/learn-lib/my-course-card/in-progress/InProgress.module.scss create mode 100644 src-ts/tools/learn/learn-lib/my-course-card/in-progress/InProgress.tsx create mode 100644 src-ts/tools/learn/learn-lib/my-course-card/in-progress/index.ts create mode 100755 src-ts/tools/learn/learn-lib/my-course-card/index.ts create mode 100644 src-ts/tools/learn/learn-lib/svgs/index.ts create mode 100644 src-ts/tools/learn/learn-lib/svgs/learning-hat.svg create mode 100755 src-ts/tools/learn/learn-lib/wave-hero/WaveHero.module.scss create mode 100755 src-ts/tools/learn/learn-lib/wave-hero/WaveHero.tsx create mode 100755 src-ts/tools/learn/learn-lib/wave-hero/index.ts create mode 100755 src-ts/tools/learn/learn-lib/wave-hero/learn-welcome-bg-curve-white.png create mode 100755 src-ts/tools/learn/learn-lib/wave-hero/learn-welcome-bg-curve.png create mode 100644 src-ts/tools/learn/learn.routes.tsx create mode 100755 src-ts/tools/learn/my-learning/MyLearning.module.scss create mode 100755 src-ts/tools/learn/my-learning/MyLearning.tsx create mode 100755 src-ts/tools/learn/my-learning/hero-card/HeroCard.module.scss create mode 100755 src-ts/tools/learn/my-learning/hero-card/HeroCard.tsx create mode 100755 src-ts/tools/learn/my-learning/hero-card/index.ts create mode 100755 src-ts/tools/learn/my-learning/index.ts create mode 100644 src-ts/tools/learn/welcome/WelcomePage.module.scss create mode 100644 src-ts/tools/learn/welcome/WelcomePage.tsx create mode 100644 src-ts/tools/learn/welcome/courses-card/CoursesCard.module.scss create mode 100644 src-ts/tools/learn/welcome/courses-card/CoursesCard.tsx create mode 100644 src-ts/tools/learn/welcome/courses-card/index.ts create mode 100644 src-ts/tools/learn/welcome/index.ts create mode 100644 src-ts/tools/learn/welcome/progress-block/ProgressBlock.module.scss create mode 100644 src-ts/tools/learn/welcome/progress-block/ProgressBlock.tsx create mode 100644 src-ts/tools/learn/welcome/progress-block/index.ts create mode 100644 src-ts/tools/learn/welcome/progress-block/init-state/InitState.module.scss create mode 100644 src-ts/tools/learn/welcome/progress-block/init-state/InitState.tsx create mode 100644 src-ts/tools/learn/welcome/progress-block/init-state/index.ts diff --git a/README.md b/README.md index 91c4de5a4..84c9abb41 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ You will need to add the following line to your hosts file. The hosts file is no >% yarn start -3. Go to https://local.topcoder-dev.com:3000/ +3. Go to https://local.topcoder-dev.com:3003/ **NOTE:** SSL is required for authentication, so you must accept the invalid cert. diff --git a/package.json b/package.json index 0317b2c88..a601db205 100644 --- a/package.json +++ b/package.json @@ -15,13 +15,14 @@ "test:no-watch": "react-scripts test --watchAll=false --passWithNoTests" }, "dependencies": { - "@datadog/browser-logs": "^4.5.0", + "@datadog/browser-logs": "^4.7.1", "@heroicons/react": "^1.0.6", "apexcharts": "^3.35.3", "axios": "^0.26.1", "browser-cookies": "^1.2.0", "classnames": "^2.3.1", "crypto-js": "^4.1.1", + "customize-cra": "^1.0.0", "lodash": "^4.17.21", "moment": "^2.29.3", "moment-timezone": "^0.5.34", @@ -29,6 +30,7 @@ "rc-checkbox": "^2.3.2", "react": "^17.0.2", "react-apexcharts": "^1.4.0", + "react-app-rewired": "^2.2.1", "react-dom": "^17.0.2", "react-elastic-carousel": "^0.11.5", "react-gtm-module": "^2.0.11", @@ -47,10 +49,9 @@ "redux-thunk": "^2.4.1", "sass": "^1.49.8", "styled-components": "^5.3.5", - "tc-auth-lib": "topcoder-platform/tc-auth-lib#1.0.3", - "typescript": "^4.4.2", - "uuid": "^8.3.2", - "web-vitals": "^2.1.0" + "tc-auth-lib": "topcoder-platform/tc-auth-lib#1.0.4", + "typescript": "^4.6.3", + "uuid": "^8.3.2" }, "devDependencies": { "@babel/core": "^7.7.5", @@ -68,10 +69,10 @@ "@types/axios": "^0.14.0", "@types/jest": "^27.0.1", "@types/lodash": "^4.14.182", - "@types/node": "^16.7.13", + "@types/node": "^17.0.24", "@types/reach__router": "^1.3.10", - "@types/react": "^17.0.20", - "@types/react-dom": "^17.0.9", + "@types/react": "^18.0.5", + "@types/react-dom": "^18.0.1", "@types/react-gtm-module": "^2.0.1", "@types/react-redux-toastr": "^7.6.2", "@types/react-router-dom": "^5.3.3", @@ -85,7 +86,6 @@ "concurrently": "^5.0.1", "config": "^3.3.6", "cross-env": "^7.0.2", - "customize-cra": "^1.0.0", "eslint": "^8.18.0", "eslint-config-prettier": "^6.7.0", "eslint-config-react-app": "^7.0.1", @@ -99,7 +99,6 @@ "postcss-scss": "^3.0.2", "prettier": "^2.0.4", "pretty-quick": "^2.0.1", - "react-app-rewired": "^2.2.1", "resolve-url-loader": "^3.1.2", "sass": "^1.48.0", "sass-loader": "^10.0.5", diff --git a/src-ts/config/environments/environment.default.config.ts b/src-ts/config/environments/environment.default.config.ts index b7bf62fa7..f734371df 100644 --- a/src-ts/config/environments/environment.default.config.ts +++ b/src-ts/config/environments/environment.default.config.ts @@ -10,6 +10,7 @@ export const EnvironmentConfigDefault: GlobalConfig = { V5: 'https://api.topcoder-dev.com/v5', }, ENV: AppHostEnvironment.default, + LEARN_SRC: 'https://fcc.topcoder-dev.com:4431', LOGGING: { PUBLIC_TOKEN: 'puba0825671e469d16f940c5a30dc738f11', SERVICE: 'platform-ui', diff --git a/src-ts/config/environments/environment.dev.config.ts b/src-ts/config/environments/environment.dev.config.ts index 5a3256772..5c6a48771 100644 --- a/src-ts/config/environments/environment.dev.config.ts +++ b/src-ts/config/environments/environment.dev.config.ts @@ -1,14 +1,11 @@ import { GlobalConfig } from '../../lib' -import { ToolTitle } from '../constants' import { AppHostEnvironment } from './app-host-environment.enum' import { EnvironmentConfigDefault } from './environment.default.config' export const EnvironmentConfigDev: GlobalConfig = { ...EnvironmentConfigDefault, - DISABLED_TOOLS: [ - ToolTitle.designLib, - ], + DISABLED_TOOLS: [ ], ENV: AppHostEnvironment.dev, TAG_MANAGER_ID: 'GTM-W7B537Z', } diff --git a/src-ts/config/environments/environment.prod.config.ts b/src-ts/config/environments/environment.prod.config.ts index 1bb9d32d8..1f99f260e 100644 --- a/src-ts/config/environments/environment.prod.config.ts +++ b/src-ts/config/environments/environment.prod.config.ts @@ -13,6 +13,7 @@ export const EnvironmentConfigProd: GlobalConfig = { }, DISABLED_TOOLS: [ ], ENV: AppHostEnvironment.prod, + LEARN_SRC: 'https://fcc.topcoder.com:4431', TAG_MANAGER_ID: 'GTM-MXXQHG8', URL: { ACCOUNTS_APP_CONNECTOR: 'https://accounts-auth0.topcoder.com', diff --git a/src-ts/lib/breadcrumb/index.ts b/src-ts/lib/breadcrumb/index.ts index 29b136a96..f3dbd74e0 100644 --- a/src-ts/lib/breadcrumb/index.ts +++ b/src-ts/lib/breadcrumb/index.ts @@ -1 +1,2 @@ export { default as Breadcrumb } from './Breadcrumb' +export * from './breadcrumb-item' diff --git a/src-ts/lib/global-config.model.ts b/src-ts/lib/global-config.model.ts index 41b3339d8..ad96f36a7 100644 --- a/src-ts/lib/global-config.model.ts +++ b/src-ts/lib/global-config.model.ts @@ -7,6 +7,7 @@ export interface GlobalConfig { } DISABLED_TOOLS?: Array ENV: string + LEARN_SRC: string, LOGGING: { PUBLIC_TOKEN: string SERVICE: string diff --git a/src-ts/lib/index.ts b/src-ts/lib/index.ts index 6ae9572e0..45ae41001 100644 --- a/src-ts/lib/index.ts +++ b/src-ts/lib/index.ts @@ -28,6 +28,7 @@ export * from './modals' export * from './page-footer' export * from './pagination' export * from './portal' +export * from './progress-bar' export * from './profile-provider' export * from './route-provider' export * from './svgs' diff --git a/src-ts/lib/progress-bar/ProgressBar.module.scss b/src-ts/lib/progress-bar/ProgressBar.module.scss new file mode 100644 index 000000000..1fd18c650 --- /dev/null +++ b/src-ts/lib/progress-bar/ProgressBar.module.scss @@ -0,0 +1,16 @@ +@import '../styles/includes'; + +.wrap { + background: $black-10; + border-radius: $pad-xs; + height: $pad-sm; + width: 100%; + + display: flex; + + :global(.progress) { + background: $turq-75; + border-radius: inherit; + width: calc(var(--progress, 0) * 100%); + } +} diff --git a/src-ts/lib/progress-bar/ProgressBar.tsx b/src-ts/lib/progress-bar/ProgressBar.tsx new file mode 100644 index 000000000..2343ba488 --- /dev/null +++ b/src-ts/lib/progress-bar/ProgressBar.tsx @@ -0,0 +1,18 @@ +import React, { FC } from 'react' + +import styles from './ProgressBar.module.scss' + +interface ProgressBarProps { + progress: number +} + +const ProgressBar: FC = (props: ProgressBarProps) => { + + return ( +
+
+
+ ) +} + +export default ProgressBar diff --git a/src-ts/lib/progress-bar/index.ts b/src-ts/lib/progress-bar/index.ts new file mode 100644 index 000000000..3f629f5f1 --- /dev/null +++ b/src-ts/lib/progress-bar/index.ts @@ -0,0 +1 @@ +export { default as ProgressBar } from './ProgressBar' diff --git a/src-ts/lib/styles/_buttons.scss b/src-ts/lib/styles/_buttons.scss index efdfc86e6..3eeb63daf 100644 --- a/src-ts/lib/styles/_buttons.scss +++ b/src-ts/lib/styles/_buttons.scss @@ -27,6 +27,7 @@ font-weight: $font-weight-bold; font-size: 11px; line-height: 24px; + display: inline-block; &.primary, &.secondary { @@ -36,10 +37,16 @@ } } - &.button-sm { + &.button-xs { + line-height: 20px; padding: 0 $pad-lg; font-size: 12px; } + + &.button-sm { + padding: $border $pad-xl; + font-size: 13px; + } &.button-md { padding: 3*$border $pad-xl; @@ -132,7 +139,7 @@ align-items: center; font-size: 16px; color: $turq-160; - background-color: $tc-white; + background-color: transparent; border: none; outline: none; border-radius: 0; diff --git a/src-ts/lib/styles/mixins/_icons.mixins.scss b/src-ts/lib/styles/mixins/_icons.mixins.scss index 2e86e77a6..e5446c4b5 100644 --- a/src-ts/lib/styles/mixins/_icons.mixins.scss +++ b/src-ts/lib/styles/mixins/_icons.mixins.scss @@ -29,3 +29,13 @@ height: $pad-xxxxl; width: $pad-xxxxl; } + +@mixin icon-mx { + height: $pad-mx; + width: $pad-mx; +} + +@mixin icon-size($size) { + height: $size * 1px; + width: $size * 1px; +} diff --git a/src-ts/lib/styles/mixins/_layout.mixins.scss b/src-ts/lib/styles/mixins/_layout.mixins.scss index 421726081..7a862764c 100644 --- a/src-ts/lib/styles/mixins/_layout.mixins.scss +++ b/src-ts/lib/styles/mixins/_layout.mixins.scss @@ -13,4 +13,30 @@ padding-left: $pad-lg; padding-right: $pad-lg; } +} + +@mixin contentWidth { + max-width: $xxl-min; + @include pagePaddings; + margin: 0 auto; + width: 100%; +} + +@mixin scrollbar { + &::-webkit-scrollbar-track { + background: transparent; + } + &::-webkit-scrollbar { + width: 5px; + height: 5px; + } + + &::-webkit-scrollbar-thumb { + background-color: rgba($tc-black, 0.4); + border-radius: 4px; + + &:hover { + background-color: rgba($tc-black, 0.6); + } + } } \ No newline at end of file diff --git a/src-ts/lib/styles/variables/_layouts.scss b/src-ts/lib/styles/variables/_layouts.scss index ea6bc0687..54d74435d 100644 --- a/src-ts/lib/styles/variables/_layouts.scss +++ b/src-ts/lib/styles/variables/_layouts.scss @@ -1,5 +1,6 @@ $header-height: var(--header-height, 80px); $footer-height: var(--footer-height, 51px); +$breadcrumb-height: var(--breadcrumb-height, 64px); $max-content-width: 1440px; -$content-height: calc(100vh - $header-height); // TO BE ADDED WHEN FOOTER IS MERGED: `- $footer-height` +$content-height: calc(100vh - $header-height - $footer-height); diff --git a/src-ts/lib/styles/variables/_palette.scss b/src-ts/lib/styles/variables/_palette.scss index 0ce32dbae..10f8c6d09 100644 --- a/src-ts/lib/styles/variables/_palette.scss +++ b/src-ts/lib/styles/variables/_palette.scss @@ -193,6 +193,7 @@ $tc-grad12: linear-gradient(90deg, #652385 0%, #8C384C 100%); $tc-grad13: linear-gradient(90deg, #219174 0%, #B98F31 100%); $tc-grad14: linear-gradient(0deg, #880152 0%, #BE4A1D 100%); $tc-grad15: linear-gradient(84.45deg, $blue-160 2.12%, $blue-110 97.43%); +$tc-grad16: linear-gradient(265.38deg, $turq-100 1.99%, $teal-100 98.19%); /* OPACITY */ diff --git a/src-ts/lib/styles/variables/_spacing.scss b/src-ts/lib/styles/variables/_spacing.scss index 06ebb1628..1faba11a4 100644 --- a/src-ts/lib/styles/variables/_spacing.scss +++ b/src-ts/lib/styles/variables/_spacing.scss @@ -18,3 +18,4 @@ $pad-xl: calc(5 * $pad-xs); // 20 $pad-xxl: calc(6 * $pad-xs); // 24 $pad-xxxl: calc(7 * $pad-xs); // 28 $pad-xxxxl: calc(8 * $pad-xs); // 32 +$pad-mx: calc(8 * $pad-xs + $pad-sm); // 40 diff --git a/src-ts/tools/learn/Learn.tsx b/src-ts/tools/learn/Learn.tsx new file mode 100644 index 000000000..aba5d5288 --- /dev/null +++ b/src-ts/tools/learn/Learn.tsx @@ -0,0 +1,26 @@ +import { FC, useContext } from 'react' +import { Outlet, Routes } from 'react-router-dom' + +import { + ContentLayout, + routeContext, + RouteContextData, +} from '../../lib' + +export const toolTitle: string = 'Learn' + +const Learn: FC<{}> = () => { + + const { getChildRoutes }: RouteContextData = useContext(routeContext) + + return ( + <> + + + {getChildRoutes(toolTitle)} + + + ) +} + +export default Learn diff --git a/src-ts/tools/learn/course-details/CourseDetailsPage.module.scss b/src-ts/tools/learn/course-details/CourseDetailsPage.module.scss new file mode 100644 index 000000000..997c8d32c --- /dev/null +++ b/src-ts/tools/learn/course-details/CourseDetailsPage.module.scss @@ -0,0 +1,53 @@ +@use '../../../lib/styles/typography'; +@import '../../../lib/styles/includes'; + +.wrap { + padding: $pad-mx 0 $pad-xxxxl; + display: flex; + gap: $pad-xxxxl; + position: relative; +} + +.main { + flex: 1 1 auto; +} + +.aside { + flex: 0 0 auto; + width: 560px; +} + +.description { + .text { + @extend .body-main; + margin-top: $pad-xxl; + } + + h3 { + margin-top: $pad-xxxxl; + } + p { + margin: $pad-sm 0; + } +} + +.coming-soon { + margin-top: $pad-xxxxl; +} + +.credits-link { + padding-bottom: $pad-xxl; + + a { + @extend .quote-small; + color: $link-blue-dark; + font-style: italic; + + display: inline-flex; + align-items: center; + } + svg { + @include icon-md; + margin-left: $pad-xs; + } +} diff --git a/src-ts/tools/learn/course-details/CourseDetailsPage.tsx b/src-ts/tools/learn/course-details/CourseDetailsPage.tsx new file mode 100644 index 000000000..6e8e0a348 --- /dev/null +++ b/src-ts/tools/learn/course-details/CourseDetailsPage.tsx @@ -0,0 +1,109 @@ +import { FC, useMemo } from 'react' +import { Params, useParams } from 'react-router-dom' + +import { + Breadcrumb, + BreadcrumbItemModel, + ContentLayout, + IconOutline, + LoadingSpinner, +} from '../../../lib' +import { + CoursesProviderData, + CourseTitle, + MyCertificationProgressProviderData, + useCoursesProvider, + useMyCertificationProgress +} from '../learn-lib' + +import { CourseCurriculum } from './course-curriculum' +import styles from './CourseDetailsPage.module.scss' +import { PromoCourse } from './promo-course' + +interface CourseDetailsPageProps { +} + +const CourseDetailsPage: FC = (props: CourseDetailsPageProps) => { + const routeParams: Params = useParams() + + const { + course, + ready, + }: CoursesProviderData = useCoursesProvider(routeParams.certification) + + const { progress }: MyCertificationProgressProviderData = useMyCertificationProgress(routeParams.certification) + + const breadcrumb: Array = useMemo(() => [ + { url: '/learn', name: 'Topcoder Academy' }, + { url: `/learn/${course?.certification}`, name: course?.title ?? '' }, + ], [course?.certification]) + + return ( + + {!ready && ( +
+ +
+ )} + + {ready && course && ( + <> +
+
+
+ + +

') }} + >
+ + {progress?.status === 'completed' ? ( + <> +

Suggested next steps

+ +
+

+ Now that you have completed the {course.title}, + we'd recommend you enroll in another course to continue your learning. + You can view our other courses from the Topcoder Academy course page. +

+
+ + ) : ( + course.keyPoints && ( + <> +

Why should you complete this course?

+ +

') }} + >
+ + ) + )} +
+ +
+ +
+
+
+ +
+
+ {course?.provider === 'freeCodeCamp' && ( + + )} + + )} +
+ ) +} + +export default CourseDetailsPage diff --git a/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.module.scss b/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.module.scss new file mode 100644 index 000000000..d2d61f4a1 --- /dev/null +++ b/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.module.scss @@ -0,0 +1,47 @@ +@import '../../../../lib/styles/includes'; + +.wrap { + background: $tc-grad15; + padding: $pad-xxxxl; + border-radius: $pad-sm; + + color: $tc-white; + + display: flex; + flex-direction: column; + gap: $pad-xxl; +} + +.title { + display: flex; + align-items: center; + + svg { + @include icon-size(60); + margin-right: $pad-sm; + path { + fill: url(#lh-paint-02); + } + } +} + +.bottom-link { + margin-top: $pad-xxxxl; +} + +.course-outline { + max-height: 650px; + display: flex; + flex-direction: column; + overflow: auto; + + @include scrollbar; + + :global(.steps-list) { + pointer-events: none; + } + :global(.course-outline-wrap .content) { + padding-right: 0; + margin-right: 0; + } +} \ No newline at end of file diff --git a/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.tsx b/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.tsx new file mode 100644 index 000000000..aab41ab5b --- /dev/null +++ b/src-ts/tools/learn/course-details/course-curriculum/CourseCurriculum.tsx @@ -0,0 +1,90 @@ +import { Dispatch, FC, SetStateAction, useCallback, useState } from 'react' +import { NavigateFunction, useNavigate } from 'react-router-dom' + +import { Button } from '../../../../lib' +import { + CourseOutline, + LearnCourse, + LearningHat, + LearnLesson, + LearnModule, + LearnMyCertificationProgress +} from '../../learn-lib' +import { getFccLessonPath } from '../../learn.routes' + +import styles from './CourseCurriculum.module.scss' +import { CurriculumSummary } from './curriculum-summary' +import { TcAcademyPolicyModal } from './tc-academy-policy-modal' + +interface CourseCurriculumProps { + course: LearnCourse + progress?: LearnMyCertificationProgress +} + +const CourseCurriculum: FC = (props: CourseCurriculumProps) => { + const navigate: NavigateFunction = useNavigate() + + const [isTcAcademyPolicyModal, setIsTcAcademyPolicyModal]: [boolean, Dispatch>] = useState(false) + + const handleStartCourse: () => void = useCallback(() => { + const current: Array = (props.progress?.currentLesson ?? '').split('/') + const course: LearnCourse = props.course + const module: LearnModule = course.modules[0] + const lesson: LearnLesson = module.lessons[0] + + const lessonPath: string = getFccLessonPath({ + course: course.certification, + lesson: current[1] ?? lesson.dashedName, + module: current[0] ?? module.meta.dashedName, + }) + navigate(lessonPath) + }, [props.course, props.progress]) + + const status: string = props.progress?.status ?? 'init' + const progress: number = props.progress?.completed ?? 0 + const inProgress: boolean = status === 'in-progress' + const isCompleted: boolean = status === 'completed' + + return ( + <> +
+
+ {isCompleted && ( + <> + +

Congratulations!

+ + )} + {!isCompleted && (

Course Curriculum

)} +
+ + setIsTcAcademyPolicyModal(true)} + progress={inProgress ? progress : 0} + completed={isCompleted} + /> + +
+ +
+
+ {isCompleted && ( +
+
+ )} + + setIsTcAcademyPolicyModal(false)} + onConfirm={handleStartCourse} + /> + + ) +} + +export default CourseCurriculum diff --git a/src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/CurriculumSummary.module.scss b/src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/CurriculumSummary.module.scss new file mode 100644 index 000000000..2a89cd74f --- /dev/null +++ b/src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/CurriculumSummary.module.scss @@ -0,0 +1,31 @@ +@use '../../../../../lib/styles/typography'; +@import '../../../../../lib/styles/includes'; + +.wrap { + padding: $pad-xxl; + border-radius: $pad-sm; + background: $tc-white; + + display: flex; + flex-direction: column; + gap: $pad-lg; +} + +.title { + @extend .body-main-bold; + color: $blue-140; + + display: flex; + align-items: center; + justify-content: space-between; +} + +.summary { + display: flex; + gap: $pad-lg; + align-items: center; +} + +.button { + margin-left: auto; +} \ No newline at end of file diff --git a/src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/CurriculumSummary.tsx b/src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/CurriculumSummary.tsx new file mode 100644 index 000000000..33b58d973 --- /dev/null +++ b/src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/CurriculumSummary.tsx @@ -0,0 +1,64 @@ +import { FC } from 'react' + +import { Button, ProgressBar, textFormatDateLocaleShortString } from '../../../../../lib' +import { CurriculumSummary as CurriculumSummaryStats, LearnCourse } from '../../../learn-lib' + +import styles from './CurriculumSummary.module.scss' + +interface CurriculumSummaryProps { + completed?: boolean + course: LearnCourse + onClickCertificateBtn?: () => void + onClickMainBtn: () => void + progress?: number +} + +const CurriculumSummary: FC = (props: CurriculumSummaryProps) => { + const progress: number|undefined = props.progress + const inProgress: boolean = !!progress + const completed: boolean|undefined = props.completed + + return ( +
+ {(inProgress || completed) && ( + <> +
+ {completed ? ( + <> + + Completed{' '} + {textFormatDateLocaleShortString(new Date('2022-06-24'))} + +
+ + + )} + +
+ + +
+
+
+
+ ) +} + +export default CurriculumSummary diff --git a/src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/index.ts b/src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/index.ts new file mode 100644 index 000000000..4b6c34cc9 --- /dev/null +++ b/src-ts/tools/learn/course-details/course-curriculum/curriculum-summary/index.ts @@ -0,0 +1 @@ +export { default as CurriculumSummary } from './CurriculumSummary' diff --git a/src-ts/tools/learn/course-details/course-curriculum/index.ts b/src-ts/tools/learn/course-details/course-curriculum/index.ts new file mode 100644 index 000000000..f01b16c59 --- /dev/null +++ b/src-ts/tools/learn/course-details/course-curriculum/index.ts @@ -0,0 +1 @@ +export { default as CourseCurriculum } from './CourseCurriculum' diff --git a/src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/TcAcademyPolicyModal.module.scss b/src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/TcAcademyPolicyModal.module.scss new file mode 100644 index 000000000..f4157408a --- /dev/null +++ b/src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/TcAcademyPolicyModal.module.scss @@ -0,0 +1,25 @@ +@import '../../../../../lib/styles/includes'; + +.container { + + ol { + padding: 0; + } + + h4 { + margin-top: 20px; + } + + p { + margin-bottom: 20px; + + &.sm { + font-size: 14px; + } + } +} + +.topCoderLink { + text-decoration: underline; + color: $link-blue-light; +} diff --git a/src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/TcAcademyPolicyModal.tsx b/src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/TcAcademyPolicyModal.tsx new file mode 100644 index 000000000..345aef7b9 --- /dev/null +++ b/src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/TcAcademyPolicyModal.tsx @@ -0,0 +1,70 @@ +import { FC } from 'react' + +import { BaseModal, Button } from '../../../../../lib' + +import styles from './TcAcademyPolicyModal.module.scss' + +export interface TcAcademyPolicyModal { + isOpen: boolean + onClose: () => void + onConfirm: () => void +} + +const TcAcademyPolicyModal: FC = ({ isOpen, onClose, onConfirm }: TcAcademyPolicyModal) => ( + +
+

+ Before you can claim a verified certification, you must accept our Academic Honesty Pledge, which reads: +

+ +

+ "I understand that plagiarism means copying someone else’s work and presenting the work as if it were my own, + without clearly attributing the original author." +

+ +

+ "I understand that plagiarism is an act of intellectual dishonesty, and that people usually get kicked out of + Academy or fired from their jobs if they get caught plagiarizing." +

+ +

+ "Aside from using open source libraries such as jQuery and Bootstrap, and short snippets of code which are clearly + attributed to their original author, 100% of the code in my projects was written by me, or along with another + person going through the freeCodeCamp curriculum with whom I was pair programming in real time." +

+ +

+ "I pledge that I did not plagiarize any of my freeCodeCamp.org work. I understand that freeCodeCamp.org's team + will audit my projects to confirm this." +

+ +

+ In the situations where we discover instances of unambiguous plagiarism, we will replace the person in question's + certification with a message that "Upon review, this account has been flagged for academic dishonesty." +

+ +

+ As an academic institution that grants achievement-based certifications, we take academic honesty very seriously. + If you have any questions about this policy, or suspect that someone has violated it, you can email team@freecodecamp.org + and we will investigate. +

+
+ +
+
+
+) + +export default TcAcademyPolicyModal diff --git a/src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/index.ts b/src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/index.ts new file mode 100644 index 000000000..188bce5ce --- /dev/null +++ b/src-ts/tools/learn/course-details/course-curriculum/tc-academy-policy-modal/index.ts @@ -0,0 +1 @@ +export { default as TcAcademyPolicyModal } from './TcAcademyPolicyModal' diff --git a/src-ts/tools/learn/course-details/index.ts b/src-ts/tools/learn/course-details/index.ts new file mode 100644 index 000000000..ad9cf94bf --- /dev/null +++ b/src-ts/tools/learn/course-details/index.ts @@ -0,0 +1 @@ +export { default as CourseDetailsPage } from './CourseDetailsPage' diff --git a/src-ts/tools/learn/course-details/promo-course/PromoCourse.module.scss b/src-ts/tools/learn/course-details/promo-course/PromoCourse.module.scss new file mode 100644 index 000000000..31e15a184 --- /dev/null +++ b/src-ts/tools/learn/course-details/promo-course/PromoCourse.module.scss @@ -0,0 +1,18 @@ +@use '../../../../lib/styles/typography'; +@import '../../../../lib/styles/includes'; + +.wrap { + background: $black-5; + border-radius: $pad-sm; + + padding: $pad-xxxxl; + gap: 32px; + display: flex; + flex-direction: column; +} + +.text-content { + > * { + margin-top: $pad-sm; + } +} \ No newline at end of file diff --git a/src-ts/tools/learn/course-details/promo-course/PromoCourse.tsx b/src-ts/tools/learn/course-details/promo-course/PromoCourse.tsx new file mode 100644 index 000000000..b07413039 --- /dev/null +++ b/src-ts/tools/learn/course-details/promo-course/PromoCourse.tsx @@ -0,0 +1,32 @@ +import { FC } from 'react' + +import { ReactComponent as LearnGetCertified } from './learn-get-certified.svg' +import styles from './PromoCourse.module.scss' + +interface PromoCourseProps { +} + +const PromoCourse: FC = (props: PromoCourseProps) => { + + return ( +
+
+

Coming soon

+
+ More ways to reach your potential with Recommended Learning Paths +
+
+ We will be building additional learning path courses, where when taken + in sequence, will result in a larger Topcoder certification. + These certifications will show in your Topcoder profile and will showcase + your verified skills and earned certifications. The resulting outcome is + that you have gained essential skills allowing you to be more successful + on the Topcoder platform. +
+
+ +
+ ) +} + +export default PromoCourse diff --git a/src-ts/tools/learn/course-details/promo-course/index.ts b/src-ts/tools/learn/course-details/promo-course/index.ts new file mode 100644 index 000000000..2a71dac9a --- /dev/null +++ b/src-ts/tools/learn/course-details/promo-course/index.ts @@ -0,0 +1 @@ +export { default as PromoCourse } from './PromoCourse' diff --git a/src-ts/tools/learn/course-details/promo-course/learn-get-certified.svg b/src-ts/tools/learn/course-details/promo-course/learn-get-certified.svg new file mode 100755 index 000000000..5b968b348 --- /dev/null +++ b/src-ts/tools/learn/course-details/promo-course/learn-get-certified.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.module.scss b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.module.scss new file mode 100644 index 000000000..f26bcec53 --- /dev/null +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.module.scss @@ -0,0 +1,55 @@ +@use '../../../lib/styles/typography'; +@import '../../../lib/styles/includes'; + +.wrap { + margin: 0 -32px; +} + +.main-wrap { + height: calc($content-height - $breadcrumb-height); + width: 100%; + margin-bottom: -$pad-lg; + background: $tc-white; + + display: flex; + + position: relative; +} + +.course-frame { + width: 100%; + display: flex; + flex-direction: column; + + padding-left: $pad-xxxxl; + + hr { + margin-left: $pad-xxxxl; + margin-right: $pad-xxxxl; + width: calc(100% - 2 * $pad-xxxxl); + } +} + +.iframe { + width: 100%; + padding: 0; + height: 100%; + flex: 1 1 auto; +} + +.course-outline-pane { + position: absolute; + left: 0; + top: 0; + bottom: 0; +} + +.course-outline-wrap { + width: 406px; +} + +.course-outline-title { + @extend .body-main-bold; + flex: 0 0 auto; + margin-bottom: $pad-xl; +} \ No newline at end of file diff --git a/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx new file mode 100644 index 000000000..c07d55eb7 --- /dev/null +++ b/src-ts/tools/learn/free-code-camp/FreeCodeCamp.tsx @@ -0,0 +1,193 @@ +import { Dispatch, FC, memo, MutableRefObject, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { NavigateFunction, useNavigate, useSearchParams } from 'react-router-dom' + +import { EnvironmentConfig } from '../../../config' +import { + Breadcrumb, + BreadcrumbItemModel, + LoadingSpinner, + Portal, +} from '../../../lib' +import { + CourseOutline, + CoursesProviderData, + LearnLesson, + LearnModule, + LessonProviderData, + useCoursesProvider, + useLessonProvider, +} from '../learn-lib' +import { getFccLessonPath } from '../learn.routes' + +import { CollapsiblePane } from './collapsible-pane' +import styles from './FreeCodeCamp.module.scss' +import { TitleNav } from './title-nav' + +const FreecodecampIfr: FC = memo((params: any) => ( +