├── client ├── .prettierrc ├── cypress │ ├── support │ │ ├── index.ts │ │ └── commands.ts │ ├── fixtures │ │ └── example.json │ ├── tsconfig.json │ ├── plugins │ │ └── index.js │ └── e2e │ │ └── unit.ts ├── .babelrc ├── .prettierignore ├── .env.example ├── public │ ├── jsprep.jpg │ ├── favicon.ico │ ├── code.svg │ └── default.svg ├── next-env.d.ts ├── cypress.json ├── util │ ├── media.ts │ └── styletron.js ├── lib │ ├── graphql │ │ ├── queries │ │ │ ├── index.ts │ │ │ ├── HomePage │ │ │ │ ├── index.ts │ │ │ │ └── __generated__ │ │ │ │ │ └── unitList.ts │ │ │ ├── UnitPage │ │ │ │ ├── __generated__ │ │ │ │ │ ├── unitPaths.ts │ │ │ │ │ ├── unitNav.ts │ │ │ │ │ └── exerciseListByUnitSlug.ts │ │ │ │ └── index.ts │ │ │ └── ExercisePage │ │ │ │ ├── index.ts │ │ │ │ └── __generated__ │ │ │ │ ├── exerciseWithUnitPaths.ts │ │ │ │ └── exerciseBySlug.ts │ │ ├── globalTypes.ts │ │ └── apolloClient │ │ │ └── index.ts │ ├── components │ │ ├── Footer.tsx │ │ ├── Layout.tsx │ │ ├── github-logo.tsx │ │ └── Header.tsx │ └── types │ │ └── index.ts ├── sections │ ├── Home │ │ └── components │ │ │ ├── Units │ │ │ ├── components │ │ │ │ ├── index.ts │ │ │ │ ├── types │ │ │ │ │ └── index.ts │ │ │ │ ├── CardBody │ │ │ │ │ └── index.tsx │ │ │ │ ├── CardFeatures │ │ │ │ │ └── index.tsx │ │ │ │ ├── CardBackground │ │ │ │ │ └── index.tsx │ │ │ │ ├── Card │ │ │ │ │ └── index.tsx │ │ │ │ └── CardTitle │ │ │ │ │ └── index.tsx │ │ │ ├── tests │ │ │ │ └── index.test.tsx │ │ │ └── index.tsx │ │ │ └── HomeMain │ │ │ ├── index.tsx │ │ │ └── tests │ │ │ └── index.test.tsx │ ├── Exercise │ │ └── components │ │ │ ├── Challenge │ │ │ ├── components │ │ │ │ └── CodeEditor │ │ │ │ │ ├── components │ │ │ │ │ └── Codemirror │ │ │ │ │ │ ├── worker.js │ │ │ │ │ │ ├── tests │ │ │ │ │ │ └── index.test.ts │ │ │ │ │ │ ├── mocks │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ │ ├── ExerciseMain │ │ │ └── index.tsx │ │ │ └── Tutorial │ │ │ └── index.tsx │ └── Unit │ │ ├── components │ │ ├── SideNavSkeleton │ │ │ └── index.tsx │ │ ├── UnitMain │ │ │ ├── index.tsx │ │ │ ├── tests │ │ │ │ └── index.test.tsx │ │ │ └── mocks.ts │ │ ├── Exercises │ │ │ ├── tests │ │ │ │ └── index.test.tsx │ │ │ └── index.tsx │ │ └── SideNav │ │ │ └── index.tsx │ │ └── assets │ │ └── code-icon.tsx ├── jest.client.js ├── jest.lint.js ├── next-seo.config.js ├── pages │ ├── styles.css │ ├── _app.tsx │ ├── _document.js │ ├── index.tsx │ └── [unit] │ │ ├── index.tsx │ │ └── [exercise] │ │ └── index.tsx ├── jest.config.js ├── .gitignore ├── mocks │ ├── exercise.ts │ ├── home.ts │ └── unit.ts ├── tests │ └── __pages__ │ │ ├── home.test.tsx │ │ └── unit.test.tsx ├── tsconfig.json ├── .eslintrc.js ├── .vscode │ └── launch.json ├── next.config.js └── package.json ├── server ├── jsprep │ ├── __init__.py │ ├── settings_test.py │ ├── asgi.py │ ├── wsgi.py │ ├── util.py │ ├── types.py │ ├── urls.py │ ├── models.py │ ├── schema.py │ ├── fixtures.py │ ├── mutations_unit.py │ ├── settings.py │ ├── mutations_exercise.py │ ├── test_exercise.py │ └── test_unit.py ├── .gitignore ├── db.sqlite3 ├── pytest.ini ├── .env.example ├── requirements.txt └── manage.py ├── .gitattributes ├── LICENSE └── README.md /client/.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /server/jsprep/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/cypress/support/index.ts: -------------------------------------------------------------------------------- 1 | import "./commands"; 2 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | .env 3 | __pycache__ 4 | 5 | -------------------------------------------------------------------------------- /client/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["next/babel"] 3 | } 4 | -------------------------------------------------------------------------------- /client/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | package-lock.json 4 | public -------------------------------------------------------------------------------- /client/.env.example: -------------------------------------------------------------------------------- 1 | SITE_HOST=http://localhost:3000 2 | GRAPHQL_HOST=XXXXXXX 3 | -------------------------------------------------------------------------------- /server/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olga-f/JSPrep/HEAD/server/db.sqlite3 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /client/public/jsprep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olga-f/JSPrep/HEAD/client/public/jsprep.jpg -------------------------------------------------------------------------------- /client/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olga-f/JSPrep/HEAD/client/public/favicon.ico -------------------------------------------------------------------------------- /client/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "https://jsprep.org", 3 | "integrationFolder": "cypress/e2e" 4 | } 5 | -------------------------------------------------------------------------------- /client/util/media.ts: -------------------------------------------------------------------------------- 1 | export const mq = (breakpoint: number): string => 2 | `@media screen and (min-width: ${breakpoint}px)`; 3 | -------------------------------------------------------------------------------- /client/lib/graphql/queries/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ExercisePage"; 2 | export * from "./HomePage"; 3 | export * from "./UnitPage"; 4 | -------------------------------------------------------------------------------- /server/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | DJANGO_SETTINGS_MODULE = jsprep.settings 3 | addopts = --no-migrations --reuse-db 4 | filterwarnings = 5 | ignore::DeprecationWarning -------------------------------------------------------------------------------- /server/jsprep/settings_test.py: -------------------------------------------------------------------------------- 1 | from .settings import * 2 | from mongoengine import disconnect 3 | 4 | disconnect() 5 | connect( 6 | "testdb", host="mongomock://localhost", alias="default" 7 | ) -------------------------------------------------------------------------------- /client/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /client/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "types": ["cypress", "@testing-library/cypress"] 5 | }, 6 | "include": ["../node_modules/cypress", "./**/*.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /client/sections/Home/components/Units/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Card"; 2 | export * from "./CardBackground"; 3 | export * from "./CardBody"; 4 | export * from "./CardFeatures"; 5 | export * from "./CardTitle"; 6 | -------------------------------------------------------------------------------- /client/sections/Exercise/components/Challenge/components/CodeEditor/components/Codemirror/worker.js: -------------------------------------------------------------------------------- 1 | import JSrunner from "javascript-code-runner"; 2 | addEventListener("message", (e) => { 3 | postMessage(JSrunner(e.data)); 4 | }); 5 | -------------------------------------------------------------------------------- /client/sections/Unit/components/SideNavSkeleton/index.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "baseui/skeleton"; 2 | 3 | export const SideNavSkeleton = (): JSX.Element => { 4 | return ; 5 | }; 6 | -------------------------------------------------------------------------------- /client/jest.client.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ["ts", "tsx", "js", "json", "jsx"], 3 | displayName: "client", 4 | testEnvironment: "jest-environment-jsdom", 5 | setupFilesAfterEnv: ["@testing-library/jest-dom/extend-expect"], 6 | }; 7 | -------------------------------------------------------------------------------- /client/jest.lint.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: "lint", 3 | runner: "jest-runner-eslint", 4 | testMatch: ["/**/*.js", "/**/*.ts", "/**/*.tsx"], 5 | testPathIgnorePatterns: ["/next.config.js", "/cypress"], 6 | }; 7 | -------------------------------------------------------------------------------- /server/.env.example: -------------------------------------------------------------------------------- 1 | SECRET_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 | DEBUG=True 3 | _MONGODB_URI=mongodb+srv://XXXXXXXX:XXXXXXXXXXXXXXXXX@clusterXX.XXXXXX.mongodb.net/XXXXXX?retryWrites=true&w=majority 4 | CLIENT_APP_URL=http://localhost:3000 5 | ALLOWED_HOSTS=['*'] -------------------------------------------------------------------------------- /server/requirements.txt: -------------------------------------------------------------------------------- 1 | django==3.2.23 2 | graphene-django==2.15.0 3 | graphene-mongo==0.2.13 4 | python-decouple==3.4 5 | mongoengine==0.23.1 6 | dnspython==2.1.0 7 | pytest==6.2.4 8 | pytest-django==4.4.0 9 | mongomock==3.23.0 10 | django-cors-headers==3.7.0 11 | -------------------------------------------------------------------------------- /client/lib/graphql/queries/HomePage/index.ts: -------------------------------------------------------------------------------- 1 | import { gql } from "apollo-boost"; 2 | 3 | export const UNIT_LIST = gql` 4 | query unitList { 5 | unitList { 6 | id 7 | title 8 | about 9 | imageUrl 10 | position 11 | slug 12 | } 13 | } 14 | `; 15 | -------------------------------------------------------------------------------- /client/lib/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import { useStyletron } from "baseui"; 2 | export const Footer: React.FunctionComponent = () => { 3 | const [css, theme] = useStyletron(); 4 | return ( 5 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /client/next-seo.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | openGraph: { 3 | type: "website", 4 | locale: "en_US", 5 | url: "https://jsprep.org", 6 | site_name: "JS Prep", 7 | }, 8 | twitter: { 9 | handle: "@OlgaFAndreiko", 10 | site: "@jsprep.org", 11 | cardType: "summary_large_image", 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /client/util/styletron.js: -------------------------------------------------------------------------------- 1 | import { Client, Server } from "styletron-engine-atomic"; 2 | 3 | const getHydrateClass = () => 4 | document.getElementsByClassName("_styletron_hydrate_"); 5 | 6 | export const styletron = 7 | typeof window === "undefined" 8 | ? new Server() 9 | : new Client({ 10 | hydrate: getHydrateClass(), 11 | }); 12 | -------------------------------------------------------------------------------- /client/pages/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | .cm-content, 6 | .cm-gutter { 7 | min-height: 350px !important; 8 | max-width: 100% !important; 9 | } 10 | .cm-scroller { 11 | overflow: auto; 12 | } 13 | .cm-gutterElement { 14 | color: #676767 !important; 15 | } 16 | .markdown pre { 17 | background-color: #f6f6f6; 18 | overflow: auto; 19 | padding: 20px; 20 | } 21 | -------------------------------------------------------------------------------- /client/sections/Home/components/Units/components/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from "react"; 2 | import type { unitList_unitList as Unit } from "../../../../../../lib/graphql/queries/HomePage/__generated__/unitList"; 3 | 4 | export type CardProps = { 5 | children?: ReactNode; 6 | }; 7 | 8 | export type ImgBackground = { 9 | image: Unit["imageUrl"]; 10 | }; 11 | 12 | export type TitleProps = { 13 | title: string; 14 | }; 15 | -------------------------------------------------------------------------------- /client/sections/Home/components/Units/components/CardBody/index.tsx: -------------------------------------------------------------------------------- 1 | import { useStyletron } from "baseui"; 2 | import type { CardProps } from "../types"; 3 | 4 | export const CardBody = ({ children }: CardProps): JSX.Element => { 5 | const [css] = useStyletron(); 6 | return ( 7 |
13 | {children} 14 |
15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /server/jsprep/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for jsprep project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jsprep.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /server/jsprep/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for jsprep project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jsprep.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /client/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testPathIgnorePatterns: ["[/\\\\](node_modules|.next)[/\\\\]"], 3 | transformIgnorePatterns: ["[/\\\\]node_modules[/\\\\].+\\.(ts|tsx)$"], 4 | transform: { 5 | "^.+\\.(ts|tsx)$": "babel-jest", 6 | }, 7 | watchPlugins: [ 8 | "jest-watch-select-projects", 9 | "jest-watch-typeahead/filename", 10 | "jest-watch-typeahead/testname", 11 | ], 12 | projects: ["./jest.lint.js", "./jest.client.js"], 13 | }; 14 | -------------------------------------------------------------------------------- /client/sections/Home/components/HomeMain/index.tsx: -------------------------------------------------------------------------------- 1 | import { Units } from "../Units"; 2 | import type { UnitsProps } from "../../../../lib/types"; 3 | 4 | export const HomeUnitList = ({ units }: UnitsProps): JSX.Element => { 5 | const { data } = units; 6 | 7 | const renderHomeUnitList = () => { 8 | if (data.unitList?.length) { 9 | return ; 10 | } 11 | return null; 12 | }; 13 | 14 | return
{renderHomeUnitList()}
; 15 | }; 16 | -------------------------------------------------------------------------------- /client/sections/Exercise/components/Challenge/components/CodeEditor/index.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "baseui/skeleton"; 2 | import dynamic from "next/dynamic"; 3 | 4 | const CodeEditor: React.FC<{ code: string }> = ({ code }) => { 5 | const Editor = dynamic(() => import("./components/Codemirror"), { 6 | loading: () => , 7 | ssr: false, 8 | }); 9 | 10 | return ; 11 | }; 12 | 13 | export default CodeEditor; 14 | -------------------------------------------------------------------------------- /client/sections/Home/components/Units/components/CardFeatures/index.tsx: -------------------------------------------------------------------------------- 1 | import { useStyletron } from "baseui"; 2 | import type { CardProps } from "../types"; 3 | 4 | export const CardFeatures = ({ children }: CardProps): JSX.Element => { 5 | const [css] = useStyletron(); 6 | return ( 7 |
14 | {children} 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /server/jsprep/util.py: -------------------------------------------------------------------------------- 1 | def order_objects_by_position(objects): 2 | if (objects is not None): 3 | sorted_objects = objects.order_by('-date_created') 4 | sorted_objects = sorted(sorted_objects, key = lambda y: (y['position'])) 5 | count = len(sorted_objects) 6 | last_object = sorted_objects[count - 1] 7 | if (last_object is not None): 8 | for idx, val in enumerate(sorted_objects): 9 | val.position=idx + 1 10 | val.save() -------------------------------------------------------------------------------- /client/lib/graphql/globalTypes.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | // @generated 4 | // This file was automatically generated and should not be edited. 5 | 6 | //============================================================== 7 | // START Enums and Input Objects 8 | //============================================================== 9 | 10 | //============================================================== 11 | // END Enums and Input Objects 12 | //============================================================== 13 | -------------------------------------------------------------------------------- /client/sections/Home/components/Units/components/CardBackground/index.tsx: -------------------------------------------------------------------------------- 1 | import { useStyletron } from "baseui"; 2 | import type { ImgBackground } from "../types"; 3 | 4 | export const CardBackground = ({ image }: ImgBackground): JSX.Element => { 5 | const width = "65%"; 6 | const [css] = useStyletron(); 7 | return ( 8 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | .cache 11 | /dist 12 | /cypress/videos 13 | /cypress/screenshots 14 | 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | 30 | # local env files 31 | .env 32 | .env.local 33 | .env.development.local 34 | .env.test.local 35 | .env.production.local 36 | 37 | # vercel 38 | .vercel 39 | /__generated__ -------------------------------------------------------------------------------- /client/sections/Home/components/Units/components/Card/index.tsx: -------------------------------------------------------------------------------- 1 | import { useStyletron } from "baseui"; 2 | import type { CardProps } from "../types"; 3 | 4 | export const Card = ({ children }: CardProps): JSX.Element => { 5 | const [css, theme] = useStyletron(); 6 | return ( 7 |
17 | {children} 18 |
19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /client/lib/components/Layout.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from "react"; 2 | import { Header } from "./Header"; 3 | import { Footer } from "./Footer"; 4 | import Head from "next/head"; 5 | 6 | type Props = { 7 | children?: ReactNode; 8 | title?: string; 9 | }; 10 | 11 | const Layout = ({ children, title = "JS Prep.org" }: Props): JSX.Element => ( 12 | <> 13 | 14 | 15 | {title} 16 | 17 |
18 | {children} 19 |