code refactors
This commit is contained in:
parent
92dd089b9a
commit
2ea225cf71
|
@ -1,50 +1 @@
|
||||||
const sources = {
|
export { Problem } from "../src/models/problem";
|
||||||
"AC": "https://atcoder.jp/",
|
|
||||||
"CC": "https://www.codechef.com/problems/",
|
|
||||||
"CSA": "https://csacademy.com/contest/archive/task/",
|
|
||||||
"DMOJ": "https://dmoj.ca/problem/",
|
|
||||||
"SPOJ": "https://www.spoj.com/problems/",
|
|
||||||
"YS": "https://judge.yosupo.jp/problem/",
|
|
||||||
"CF": "https://codeforces.com/",
|
|
||||||
"Bronze": "http://www.usaco.org/index.php?page=viewproblem2&cpid=",
|
|
||||||
"Silver": "http://www.usaco.org/index.php?page=viewproblem2&cpid=",
|
|
||||||
"Gold": "http://www.usaco.org/index.php?page=viewproblem2&cpid=",
|
|
||||||
"Old Bronze": "http://www.usaco.org/index.php?page=viewproblem2&cpid=",
|
|
||||||
"Old Silver": "http://www.usaco.org/index.php?page=viewproblem2&cpid=",
|
|
||||||
"Old Gold": "http://www.usaco.org/index.php?page=viewproblem2&cpid=",
|
|
||||||
"Plat": "http://www.usaco.org/index.php?page=viewproblem2&cpid=",
|
|
||||||
"Kattis": "https://open.kattis.com/problems/",
|
|
||||||
"CSES": "https://cses.fi/problemset/task/",
|
|
||||||
"LC": "https://leetcode.com/problems/",
|
|
||||||
"ojuz": "https://oj.uz/problem/view/",
|
|
||||||
"HR": "https://www.hackerrank.com/",
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Problem {
|
|
||||||
public url: string;
|
|
||||||
public difficulty: 'Very Easy' | 'Easy' | 'Normal' | 'Hard' | 'Very Hard' | 'Insane';
|
|
||||||
public isIntro: boolean;
|
|
||||||
|
|
||||||
get uniqueID() {
|
|
||||||
return this.url;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public source: string,
|
|
||||||
public name: string,
|
|
||||||
public id: string,
|
|
||||||
labels?: 'Very Easy' | 'Easy' | 'Normal' | 'Hard' | 'Very Hard' | 'Insane' | 'Intro|Very Easy' | 'Intro|Easy' | 'Intro|Normal' | 'Intro|Hard' | 'Intro|Very Hard' | 'Intro|Insane',
|
|
||||||
public starred?: boolean,
|
|
||||||
public tags?: string[],
|
|
||||||
public sketch?: string,
|
|
||||||
) {
|
|
||||||
this.isIntro = labels && labels.includes("Intro|");
|
|
||||||
if (labels) labels = labels.replace("Intro|", "") as any;
|
|
||||||
this.difficulty = labels as any;
|
|
||||||
if (!id.startsWith("http")) {
|
|
||||||
if (source in sources) {
|
|
||||||
this.url = sources[source] + id;
|
|
||||||
} else throw `URL ${id} is not valid. Did you make a typo in the problem source (${source}), or in the URL? Problem name: ${name}`
|
|
||||||
} else this.url = id;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||||
import { random, sample, range, getDiameter } from './Confetti.helpers';
|
import { random, sample, range, getDiameter } from './Confetti.helpers';
|
||||||
import { createCircle, createTriangle, createZigZag } from './confetti-shapes';
|
import { createCircle, createTriangle, createZigZag } from './confetti-shapes';
|
||||||
|
|
||||||
import Canvas from '../Canvas/Canvas';
|
import Canvas from './Canvas';
|
||||||
|
|
||||||
class Confetti extends Component {
|
class Confetti extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ModuleInfo } from '../module';
|
import { ModuleInfo } from '../models/module';
|
||||||
import { SECTION_LABELS } from '../../content/ordering';
|
import { SECTION_LABELS } from '../../content/ordering';
|
||||||
import SlideoverForm from './Slideover/SlideoverForm';
|
import SlideoverForm from './Slideover/SlideoverForm';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
@ -83,7 +83,7 @@ export default function ContactUsSlideover({
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (activeModule)
|
if (activeModule)
|
||||||
setLocation(
|
setLocation(
|
||||||
`${activeModule.title} - ${SECTION_LABELS[activeModule.division]}`
|
`${activeModule.title} - ${SECTION_LABELS[activeModule.section]}`
|
||||||
);
|
);
|
||||||
else setLocation('');
|
else setLocation('');
|
||||||
}, [activeModule]);
|
}, [activeModule]);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Transition from '../Transition';
|
import Transition from '../Transition';
|
||||||
import { ModuleProgressOptions } from '../../context/UserDataContext';
|
import { ModuleProgressOptions } from '../../models/module';
|
||||||
|
|
||||||
const MarkCompleteButton = ({
|
const MarkCompleteButton = ({
|
||||||
state,
|
state,
|
||||||
|
|
|
@ -3,7 +3,11 @@ import Transition from '../Transition';
|
||||||
import { useContext, useRef, useState } from 'react';
|
import { useContext, useRef, useState } from 'react';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import logo from '../../assets/logo.svg';
|
import logo from '../../assets/logo.svg';
|
||||||
import { ModuleFrequency, ModuleInfo, ModuleLinkInfo } from '../../module';
|
import {
|
||||||
|
ModuleFrequency,
|
||||||
|
ModuleInfo,
|
||||||
|
ModuleLinkInfo,
|
||||||
|
} from '../../models/module';
|
||||||
import { graphql, Link, useStaticQuery } from 'gatsby';
|
import { graphql, Link, useStaticQuery } from 'gatsby';
|
||||||
import MODULE_ORDERING, {
|
import MODULE_ORDERING, {
|
||||||
Category,
|
Category,
|
||||||
|
@ -86,10 +90,10 @@ const Breadcrumbs = () => {
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<Link
|
<Link
|
||||||
to={`/${module.division}`}
|
to={`/${module.section}`}
|
||||||
className="text-gray-500 hover:text-gray-700 transition duration-150 ease-in-out"
|
className="text-gray-500 hover:text-gray-700 transition duration-150 ease-in-out"
|
||||||
>
|
>
|
||||||
{SECTION_LABELS[module.division]}
|
{SECTION_LABELS[module.section]}
|
||||||
</Link>
|
</Link>
|
||||||
<svg
|
<svg
|
||||||
className="flex-shrink-0 mx-2 h-5 w-5 text-gray-400"
|
className="flex-shrink-0 mx-2 h-5 w-5 text-gray-400"
|
||||||
|
@ -170,7 +174,7 @@ const NavBar = ({ alignNavButtonsRight = true }) => {
|
||||||
const { module, moduleLinks } = moduleLayoutInfo;
|
const { module, moduleLinks } = moduleLayoutInfo;
|
||||||
const sortedModuleLinks = React.useMemo(() => {
|
const sortedModuleLinks = React.useMemo(() => {
|
||||||
let links: ModuleLinkInfo[] = [];
|
let links: ModuleLinkInfo[] = [];
|
||||||
for (let group of MODULE_ORDERING[module.division]) {
|
for (let group of MODULE_ORDERING[module.section]) {
|
||||||
for (let id of group.items) {
|
for (let id of group.items) {
|
||||||
links.push(moduleLinks.find(x => x.id === id));
|
links.push(moduleLinks.find(x => x.id === id));
|
||||||
}
|
}
|
||||||
|
@ -254,7 +258,7 @@ const renderPrerequisite = (prerequisite, moduleLinks: ModuleLinkInfo[]) => {
|
||||||
return (
|
return (
|
||||||
<li key={prerequisite}>
|
<li key={prerequisite}>
|
||||||
<Link to={moduleLink.url} className="underline text-black">
|
<Link to={moduleLink.url} className="underline text-black">
|
||||||
{SECTION_LABELS[moduleLink.division]} - {moduleLink.title}
|
{SECTION_LABELS[moduleLink.section]} - {moduleLink.title}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
@ -268,12 +272,15 @@ export default function ModuleLayout({
|
||||||
module: ModuleInfo;
|
module: ModuleInfo;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { userProgress, setModuleProgress, lang } = useContext(UserDataContext);
|
const { userProgressOnModules, setModuleProgress, lang } = useContext(
|
||||||
|
UserDataContext
|
||||||
|
);
|
||||||
const [isMobileNavOpen, setIsMobileNavOpen] = useState(false);
|
const [isMobileNavOpen, setIsMobileNavOpen] = useState(false);
|
||||||
const [isContactUsActive, setIsContactUsActive] = useState(false);
|
const [isContactUsActive, setIsContactUsActive] = useState(false);
|
||||||
const [isConfettiActive, setIsConfettiActive] = useState(false);
|
const [isConfettiActive, setIsConfettiActive] = useState(false);
|
||||||
const moduleProgress =
|
const moduleProgress =
|
||||||
(userProgress && userProgress[module.id]) || 'Not Started';
|
(userProgressOnModules && userProgressOnModules[module.id]) ||
|
||||||
|
'Not Started';
|
||||||
|
|
||||||
const tableOfContents =
|
const tableOfContents =
|
||||||
lang in module.toc ? module.toc[lang] : module.toc['cpp'];
|
lang in module.toc ? module.toc[lang] : module.toc['cpp'];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Link } from 'gatsby';
|
import { Link } from 'gatsby';
|
||||||
import { ModuleLinkInfo } from '../../../module';
|
import { ModuleLinkInfo } from '../../../models/module';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import tw from 'twin.macro';
|
import tw from 'twin.macro';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
@ -88,8 +88,8 @@ const ItemLink = ({ link }: { link: ModuleLinkInfo }) => {
|
||||||
}
|
}
|
||||||
}, [isActive]);
|
}, [isActive]);
|
||||||
|
|
||||||
const { userProgress } = useContext(UserDataContext);
|
const { userProgressOnModules } = useContext(UserDataContext);
|
||||||
const progress = userProgress[link.id] || 'Not Started';
|
const progress = userProgressOnModules[link.id] || 'Not Started';
|
||||||
|
|
||||||
let lineColorStyle = tw`bg-gray-200`;
|
let lineColorStyle = tw`bg-gray-200`;
|
||||||
let dotColorStyle = tw`bg-gray-200`;
|
let dotColorStyle = tw`bg-gray-200`;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ModuleLinkInfo } from '../../../module';
|
import { ModuleLinkInfo } from '../../../models/module';
|
||||||
import { Link } from 'gatsby';
|
import { Link } from 'gatsby';
|
||||||
import ItemLink from './ItemLink';
|
import ItemLink from './ItemLink';
|
||||||
import Accordion from './Accordion';
|
import Accordion from './Accordion';
|
||||||
|
@ -16,13 +16,13 @@ export const SidebarNav = () => {
|
||||||
const { module, moduleLinks } = useContext(ModuleLayoutContext);
|
const { module, moduleLinks } = useContext(ModuleLayoutContext);
|
||||||
|
|
||||||
const links: NavLinkGroup[] = React.useMemo(() => {
|
const links: NavLinkGroup[] = React.useMemo(() => {
|
||||||
return MODULE_ORDERING[module.division].map((category: Category) => ({
|
return MODULE_ORDERING[module.section].map((category: Category) => ({
|
||||||
label: category.name,
|
label: category.name,
|
||||||
children: category.items.map(
|
children: category.items.map(
|
||||||
moduleID => moduleLinks.find(link => link.id === moduleID) // lol O(n^2)?
|
moduleID => moduleLinks.find(link => link.id === moduleID) // lol O(n^2)?
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
}, [module.division, moduleLinks]);
|
}, [module.section, moduleLinks]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { TOCHeading } from '../../module';
|
import { TOCHeading } from '../../models/module';
|
||||||
import { Link } from 'gatsby';
|
import { Link } from 'gatsby';
|
||||||
import { useActiveHash } from '../../hooks/useActiveHash';
|
import { useActiveHash } from '../../hooks/useActiveHash';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { TOCHeading } from '../../module';
|
import { TOCHeading } from '../../models/module';
|
||||||
import { Link } from 'gatsby';
|
import { Link } from 'gatsby';
|
||||||
import { useActiveHash } from '../../hooks/useActiveHash';
|
import { useActiveHash } from '../../hooks/useActiveHash';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
|
@ -2,20 +2,20 @@ import * as React from 'react';
|
||||||
import Tooltip from './tooltip/Tooltip';
|
import Tooltip from './tooltip/Tooltip';
|
||||||
import { Problem } from '../../content/models';
|
import { Problem } from '../../content/models';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import UserDataContext, {
|
import UserDataContext from '../context/UserDataContext';
|
||||||
NEXT_PROBLEM_STATUS,
|
import { NEXT_PROBLEM_STATUS, ProblemProgress } from '../models/problem';
|
||||||
ProblemStatus,
|
|
||||||
} from '../context/UserDataContext';
|
|
||||||
|
|
||||||
export default function ProblemStatusCheckbox({
|
export default function ProblemStatusCheckbox({
|
||||||
problem,
|
problem,
|
||||||
}: {
|
}: {
|
||||||
problem: Problem;
|
problem: Problem;
|
||||||
}) {
|
}) {
|
||||||
const { problemStatus, setProblemStatus } = useContext(UserDataContext);
|
const { userProgressOnProblems, setUserProgressOnProblems } = useContext(
|
||||||
let status: ProblemStatus =
|
UserDataContext
|
||||||
problemStatus[problem.uniqueID] || 'Not Attempted';
|
);
|
||||||
const color: { [key in ProblemStatus]: string } = {
|
let status: ProblemProgress =
|
||||||
|
userProgressOnProblems[problem.uniqueID] || 'Not Attempted';
|
||||||
|
const color: { [key in ProblemProgress]: string } = {
|
||||||
'Not Attempted': 'bg-gray-200',
|
'Not Attempted': 'bg-gray-200',
|
||||||
Solving: 'bg-yellow-300',
|
Solving: 'bg-yellow-300',
|
||||||
Solved: 'bg-green-500',
|
Solved: 'bg-green-500',
|
||||||
|
@ -23,7 +23,7 @@ export default function ProblemStatusCheckbox({
|
||||||
Skipped: 'bg-blue-300',
|
Skipped: 'bg-blue-300',
|
||||||
};
|
};
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
setProblemStatus(problem, NEXT_PROBLEM_STATUS[status]);
|
setUserProgressOnProblems(problem, NEXT_PROBLEM_STATUS[status]);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { createContext } from 'react';
|
import { createContext } from 'react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ModuleInfo, ModuleLinkInfo } from '../module';
|
import { ModuleInfo, ModuleLinkInfo } from '../models/module';
|
||||||
|
|
||||||
const ModuleLayoutContext = createContext<{
|
const ModuleLayoutContext = createContext<{
|
||||||
module: ModuleInfo;
|
module: ModuleInfo;
|
||||||
|
|
|
@ -1,50 +1,30 @@
|
||||||
import { createContext, useState } from 'react';
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { createContext, useState } from 'react';
|
||||||
import { Problem } from '../../content/models';
|
import { Problem } from '../../content/models';
|
||||||
|
import { ModuleProgress } from '../models/module';
|
||||||
|
import { ProblemProgress } from '../models/problem';
|
||||||
|
|
||||||
export type ModuleProgress =
|
|
||||||
| 'Not Started'
|
|
||||||
| 'Reading'
|
|
||||||
| 'Practicing'
|
|
||||||
| 'Complete'
|
|
||||||
| 'Skipped';
|
|
||||||
export const ModuleProgressOptions: ModuleProgress[] = [
|
|
||||||
'Not Started',
|
|
||||||
'Reading',
|
|
||||||
'Practicing',
|
|
||||||
'Complete',
|
|
||||||
'Skipped',
|
|
||||||
];
|
|
||||||
export type UserProgress = { [key: string]: ModuleProgress };
|
|
||||||
export type UserLang = 'showAll' | 'cpp' | 'java' | 'py';
|
export type UserLang = 'showAll' | 'cpp' | 'java' | 'py';
|
||||||
export type ProblemStatus =
|
|
||||||
| 'Not Attempted'
|
|
||||||
| 'Solving'
|
|
||||||
| 'Solved'
|
|
||||||
| "Can't Solve"
|
|
||||||
| 'Skipped';
|
|
||||||
export const NEXT_PROBLEM_STATUS: { [key in ProblemStatus]: ProblemStatus } = {
|
|
||||||
'Not Attempted': 'Solving',
|
|
||||||
Solving: 'Solved',
|
|
||||||
Solved: "Can't Solve",
|
|
||||||
"Can't Solve": 'Skipped',
|
|
||||||
Skipped: 'Not Attempted',
|
|
||||||
};
|
|
||||||
|
|
||||||
const UserDataContext = createContext<{
|
const UserDataContext = createContext<{
|
||||||
lang: UserLang;
|
lang: UserLang;
|
||||||
setLang: (lang: UserLang) => void;
|
setLang: (lang: UserLang) => void;
|
||||||
userProgress: UserProgress;
|
|
||||||
|
userProgressOnModules: { [key: string]: ModuleProgress };
|
||||||
setModuleProgress: (moduleID: string, progress: ModuleProgress) => void;
|
setModuleProgress: (moduleID: string, progress: ModuleProgress) => void;
|
||||||
problemStatus: { [key: string]: ProblemStatus };
|
|
||||||
setProblemStatus: (problem: Problem, status: ProblemStatus) => void;
|
userProgressOnProblems: { [key: string]: ProblemProgress };
|
||||||
|
setUserProgressOnProblems: (
|
||||||
|
problem: Problem,
|
||||||
|
status: ProblemProgress
|
||||||
|
) => void;
|
||||||
}>({
|
}>({
|
||||||
lang: 'showAll',
|
lang: 'showAll',
|
||||||
setLang: null,
|
setLang: null,
|
||||||
userProgress: null,
|
userProgressOnModules: null,
|
||||||
setModuleProgress: null,
|
setModuleProgress: null,
|
||||||
problemStatus: null,
|
userProgressOnProblems: null,
|
||||||
setProblemStatus: null,
|
setUserProgressOnProblems: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const langKey = 'guide:userData:lang';
|
const langKey = 'guide:userData:lang';
|
||||||
|
@ -86,9 +66,11 @@ const getProblemStatusFromStorage = () => {
|
||||||
|
|
||||||
export const UserDataProvider = ({ children }) => {
|
export const UserDataProvider = ({ children }) => {
|
||||||
const [lang, setLang] = useState<UserLang>('showAll');
|
const [lang, setLang] = useState<UserLang>('showAll');
|
||||||
const [userProgress, setUserProgress] = useState<UserProgress>({});
|
const [userProgress, setUserProgress] = useState<{
|
||||||
|
[key: string]: ModuleProgress;
|
||||||
|
}>({});
|
||||||
const [problemStatus, setProblemStatus] = useState<{
|
const [problemStatus, setProblemStatus] = useState<{
|
||||||
[key: string]: ProblemStatus;
|
[key: string]: ProblemProgress;
|
||||||
}>({});
|
}>({});
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -105,7 +87,7 @@ export const UserDataProvider = ({ children }) => {
|
||||||
window.localStorage.setItem(langKey, JSON.stringify(lang));
|
window.localStorage.setItem(langKey, JSON.stringify(lang));
|
||||||
setLang(lang);
|
setLang(lang);
|
||||||
},
|
},
|
||||||
userProgress,
|
userProgressOnModules: userProgress,
|
||||||
setModuleProgress: (moduleID: string, progress: ModuleProgress) => {
|
setModuleProgress: (moduleID: string, progress: ModuleProgress) => {
|
||||||
const newProgress = {
|
const newProgress = {
|
||||||
...getProgressFromStorage(),
|
...getProgressFromStorage(),
|
||||||
|
@ -114,8 +96,8 @@ export const UserDataProvider = ({ children }) => {
|
||||||
window.localStorage.setItem(progressKey, JSON.stringify(newProgress));
|
window.localStorage.setItem(progressKey, JSON.stringify(newProgress));
|
||||||
setUserProgress(newProgress);
|
setUserProgress(newProgress);
|
||||||
},
|
},
|
||||||
problemStatus,
|
userProgressOnProblems: problemStatus,
|
||||||
setProblemStatus: (problem, status) => {
|
setUserProgressOnProblems: (problem, status) => {
|
||||||
const newStatus = {
|
const newStatus = {
|
||||||
...getProblemStatusFromStorage(),
|
...getProblemStatusFromStorage(),
|
||||||
[problem.uniqueID]: status,
|
[problem.uniqueID]: status,
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
export class ModuleLinkInfo {
|
export class ModuleLinkInfo {
|
||||||
public url: string;
|
public url: string;
|
||||||
|
|
||||||
constructor(
|
constructor(public id: string, public section: string, public title: string) {
|
||||||
public id: string,
|
this.url = `/${section}/${id}`;
|
||||||
public division: string,
|
|
||||||
public title: string
|
|
||||||
) {
|
|
||||||
this.url = `/${division}/${id}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,11 +20,10 @@ export type TableOfContents = {
|
||||||
py: TOCHeading[];
|
py: TOCHeading[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// there's probably a way to do this without the duplicated types...
|
|
||||||
export class ModuleInfo extends ModuleLinkInfo {
|
export class ModuleInfo extends ModuleLinkInfo {
|
||||||
constructor(
|
constructor(
|
||||||
public id: string,
|
public id: string,
|
||||||
public division: string,
|
public section: string,
|
||||||
public title: string,
|
public title: string,
|
||||||
public body: any,
|
public body: any,
|
||||||
public author: string,
|
public author: string,
|
||||||
|
@ -37,6 +32,21 @@ export class ModuleInfo extends ModuleLinkInfo {
|
||||||
public frequency: ModuleFrequency,
|
public frequency: ModuleFrequency,
|
||||||
public toc: TableOfContents
|
public toc: TableOfContents
|
||||||
) {
|
) {
|
||||||
super(id, division, title);
|
super(id, section, title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ModuleProgress =
|
||||||
|
| 'Not Started'
|
||||||
|
| 'Reading'
|
||||||
|
| 'Practicing'
|
||||||
|
| 'Complete'
|
||||||
|
| 'Skipped';
|
||||||
|
|
||||||
|
export const ModuleProgressOptions: ModuleProgress[] = [
|
||||||
|
'Not Started',
|
||||||
|
'Reading',
|
||||||
|
'Practicing',
|
||||||
|
'Complete',
|
||||||
|
'Skipped',
|
||||||
|
];
|
86
src/models/problem.ts
Normal file
86
src/models/problem.ts
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
const sources = {
|
||||||
|
AC: 'https://atcoder.jp/',
|
||||||
|
CC: 'https://www.codechef.com/problems/',
|
||||||
|
CSA: 'https://csacademy.com/contest/archive/task/',
|
||||||
|
DMOJ: 'https://dmoj.ca/problem/',
|
||||||
|
SPOJ: 'https://www.spoj.com/problems/',
|
||||||
|
YS: 'https://judge.yosupo.jp/problem/',
|
||||||
|
CF: 'https://codeforces.com/',
|
||||||
|
Bronze: 'http://www.usaco.org/index.php?page=viewproblem2&cpid=',
|
||||||
|
Silver: 'http://www.usaco.org/index.php?page=viewproblem2&cpid=',
|
||||||
|
Gold: 'http://www.usaco.org/index.php?page=viewproblem2&cpid=',
|
||||||
|
'Old Bronze': 'http://www.usaco.org/index.php?page=viewproblem2&cpid=',
|
||||||
|
'Old Silver': 'http://www.usaco.org/index.php?page=viewproblem2&cpid=',
|
||||||
|
'Old Gold': 'http://www.usaco.org/index.php?page=viewproblem2&cpid=',
|
||||||
|
Plat: 'http://www.usaco.org/index.php?page=viewproblem2&cpid=',
|
||||||
|
Kattis: 'https://open.kattis.com/problems/',
|
||||||
|
CSES: 'https://cses.fi/problemset/task/',
|
||||||
|
LC: 'https://leetcode.com/problems/',
|
||||||
|
ojuz: 'https://oj.uz/problem/view/',
|
||||||
|
HR: 'https://www.hackerrank.com/',
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Problem {
|
||||||
|
public url: string;
|
||||||
|
public difficulty:
|
||||||
|
| 'Very Easy'
|
||||||
|
| 'Easy'
|
||||||
|
| 'Normal'
|
||||||
|
| 'Hard'
|
||||||
|
| 'Very Hard'
|
||||||
|
| 'Insane';
|
||||||
|
public isIntro: boolean;
|
||||||
|
|
||||||
|
get uniqueID() {
|
||||||
|
return this.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public source: string,
|
||||||
|
public name: string,
|
||||||
|
public id: string,
|
||||||
|
labels?:
|
||||||
|
| 'Very Easy'
|
||||||
|
| 'Easy'
|
||||||
|
| 'Normal'
|
||||||
|
| 'Hard'
|
||||||
|
| 'Very Hard'
|
||||||
|
| 'Insane'
|
||||||
|
| 'Intro|Very Easy'
|
||||||
|
| 'Intro|Easy'
|
||||||
|
| 'Intro|Normal'
|
||||||
|
| 'Intro|Hard'
|
||||||
|
| 'Intro|Very Hard'
|
||||||
|
| 'Intro|Insane',
|
||||||
|
public starred?: boolean,
|
||||||
|
public tags?: string[],
|
||||||
|
public sketch?: string
|
||||||
|
) {
|
||||||
|
this.isIntro = labels && labels.includes('Intro|');
|
||||||
|
if (labels) labels = labels.replace('Intro|', '') as any;
|
||||||
|
this.difficulty = labels as any;
|
||||||
|
if (!id.startsWith('http')) {
|
||||||
|
if (source in sources) {
|
||||||
|
this.url = sources[source] + id;
|
||||||
|
} else
|
||||||
|
throw `URL ${id} is not valid. Did you make a typo in the problem source (${source}), or in the URL? Problem name: ${name}`;
|
||||||
|
} else this.url = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProblemProgress =
|
||||||
|
| 'Not Attempted'
|
||||||
|
| 'Solving'
|
||||||
|
| 'Solved'
|
||||||
|
| "Can't Solve"
|
||||||
|
| 'Skipped';
|
||||||
|
|
||||||
|
export const NEXT_PROBLEM_STATUS: {
|
||||||
|
[key in ProblemProgress]: ProblemProgress;
|
||||||
|
} = {
|
||||||
|
'Not Attempted': 'Solving',
|
||||||
|
Solving: 'Solved',
|
||||||
|
Solved: "Can't Solve",
|
||||||
|
"Can't Solve": 'Skipped',
|
||||||
|
Skipped: 'Not Attempted',
|
||||||
|
};
|
|
@ -15,7 +15,7 @@ export default function Template(props) {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<SEO
|
<SEO
|
||||||
title={`${module.title} (${SECTION_LABELS[module.division]})`}
|
title={`${module.title} (${SECTION_LABELS[module.section]})`}
|
||||||
description={module.description}
|
description={module.description}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import MODULE_ORDERING from '../content/ordering';
|
import MODULE_ORDERING from '../content/ordering';
|
||||||
import { ModuleInfo, ModuleLinkInfo } from './module';
|
import { ModuleInfo, ModuleLinkInfo } from './models/module';
|
||||||
|
|
||||||
export const getModule = (allModules, division) => {
|
export const getModule = (allModules, division) => {
|
||||||
return MODULE_ORDERING[division].map(k => {
|
return MODULE_ORDERING[division].map(k => {
|
||||||
|
|
Reference in a new issue