lots of code refactors
This commit is contained in:
parent
6673aca3bf
commit
6d5c0c6b9e
|
@ -1,5 +1,7 @@
|
|||
.cache
|
||||
package.json
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
public
|
||||
content
|
||||
content
|
||||
docs
|
||||
static
|
|
@ -9,8 +9,8 @@ As much as possible, please try to keep the markdown files independent of the fr
|
|||
|
||||
## Documentation
|
||||
|
||||
- To get this site running locally, refer to the [Front End Documentation](Front%20End%20Documentation.md).
|
||||
- For information regarding Content Writing, refer to the [Content Documentation](Content%20Documentation.md).
|
||||
- To get this site running locally, refer to the [Front End Documentation](docs/Front%20End%20Documentation.md).
|
||||
- For information regarding Content Writing, refer to the [Content Documentation](docs/Content%20Documentation.md).
|
||||
|
||||
## Tech Stack
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
## Content Formatting Documentation
|
||||
|
||||
**Note:** It is highly recommended to [run a local version of the site](Front%20End%20Documentation.md) in order to view your changes.
|
||||
|
||||
All modules are written in [Markdown](https://www.markdownguide.org/cheat-sheet/). There are special additions to the markdown that we have added to this site.
|
||||
These special additions are still under development, so they may change frequently.
|
||||
If you are confused about something, or if there's a certain feature that you want to add, reach out to Nathan Wang.
|
|
@ -1,9 +1,9 @@
|
|||
import * as React from 'react';
|
||||
import { ModuleInfo } from '../models/module';
|
||||
import { SECTION_LABELS } from '../../content/ordering';
|
||||
import SlideoverForm from './Slideover/SlideoverForm';
|
||||
import { ModuleInfo } from '../../models/module';
|
||||
import { SECTION_LABELS } from '../../../content/ordering';
|
||||
import SlideoverForm from './SlideoverForm';
|
||||
import { useState } from 'react';
|
||||
import useStickyState from '../hooks/useStickyState';
|
||||
import useStickyState from '../../hooks/useStickyState';
|
||||
|
||||
// Warning: this file is insanely messy. This should be rewritten soon :)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from 'react';
|
||||
|
||||
export default function Dots({ count, color, totalCount }) {
|
||||
export default function ModuleFrequencyDots({ count, color, totalCount }) {
|
||||
const emptyCircle = 'text-gray-300';
|
||||
return (
|
||||
<>
|
|
@ -13,17 +13,17 @@ import MODULE_ORDERING, {
|
|||
Category,
|
||||
SECTION_LABELS,
|
||||
} from '../../../content/ordering';
|
||||
import Dots from '../Dots';
|
||||
import ContactUsSlideover from '../ContactUsSlideover';
|
||||
import ModuleFrequencyDots from './ModuleFrequencyDots';
|
||||
import ContactUsSlideover from '../ContactUsSlideover/ContactUsSlideover';
|
||||
import MarkCompleteButton from './MarkCompleteButton';
|
||||
import ModuleConfetti from './ModuleConfetti';
|
||||
import TextTooltip from '../tooltip/TextTooltip';
|
||||
import TextTooltip from '../Tooltip/TextTooltip';
|
||||
import UserDataContext, { UserLang } from '../../context/UserDataContext';
|
||||
import { NavLinkGroup, SidebarNav } from './SidebarNav/SidebarNav';
|
||||
import { graphqlToModuleLinks } from '../../utils';
|
||||
import ModuleLayoutContext from '../../context/ModuleLayoutContext';
|
||||
import TableOfContentsSidebar from './TableOfContentsSidebar';
|
||||
import TableOfContentsBlock from './TableOfContentsBlock';
|
||||
import TableOfContentsSidebar from './TableOfContents/TableOfContentsSidebar';
|
||||
import TableOfContentsBlock from './TableOfContents/TableOfContentsBlock';
|
||||
|
||||
const Frequency = ({ frequency }: { frequency: ModuleFrequency }) => {
|
||||
const textColors = [
|
||||
|
@ -59,7 +59,11 @@ const Frequency = ({ frequency }: { frequency: ModuleFrequency }) => {
|
|||
<span
|
||||
className={`inline-flex items-center font-medium ${textColors[frequency]}`}
|
||||
>
|
||||
<Dots count={frequency} totalCount={4} color={circleColors[frequency]} />
|
||||
<ModuleFrequencyDots
|
||||
count={frequency}
|
||||
totalCount={4}
|
||||
color={circleColors[frequency]}
|
||||
/>
|
||||
<TextTooltip position="bottom" content={hints[frequency]}>
|
||||
{labels[frequency]}
|
||||
</TextTooltip>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import { ModuleLinkInfo } from '../../../models/module';
|
||||
import { Link } from 'gatsby';
|
||||
import ItemLink from './ItemLink';
|
||||
import Accordion from './Accordion';
|
||||
import MODULE_ORDERING, { Category } from '../../../../content/ordering';
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import * as React from 'react';
|
||||
import { TOCHeading } from '../../../models/module';
|
||||
import genLinksFromTOCHeadings from './genLinksFromTOCHeadings';
|
||||
|
||||
const TableOfContentsBlock = ({
|
||||
tableOfContents,
|
||||
}: {
|
||||
tableOfContents: TOCHeading[];
|
||||
}) => {
|
||||
let links = genLinksFromTOCHeadings(
|
||||
tableOfContents,
|
||||
_ =>
|
||||
'block mb-2 transition duration-150 ease-in-out text-gray-600 hover:underline hover:text-blue-600'
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<h2 className="uppercase text-gray-500 font-bold mt-8 mb-3 tracking-wider">
|
||||
Table of Contents
|
||||
</h2>
|
||||
{links}
|
||||
<hr className="mt-6 mb-2" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableOfContentsBlock;
|
|
@ -0,0 +1,37 @@
|
|||
import * as React from 'react';
|
||||
import { TOCHeading } from '../../../models/module';
|
||||
import { Link } from 'gatsby';
|
||||
import { useActiveHash } from '../../../hooks/useActiveHash';
|
||||
import { useMemo } from 'react';
|
||||
import genLinksFromTOCHeadings from './genLinksFromTOCHeadings';
|
||||
|
||||
const TableOfContentsSidebar = ({
|
||||
tableOfContents,
|
||||
}: {
|
||||
tableOfContents: TOCHeading[];
|
||||
}) => {
|
||||
const hashes = useMemo(() => tableOfContents.map(heading => heading.slug), [
|
||||
tableOfContents,
|
||||
]);
|
||||
const activeHash = useActiveHash(hashes, '10px 0px 0px 0px');
|
||||
|
||||
let links = genLinksFromTOCHeadings(
|
||||
tableOfContents,
|
||||
heading =>
|
||||
'block mb-1 text-sm transition duration-150 ease-in-out ' +
|
||||
(activeHash === heading.slug
|
||||
? 'underline text-blue-600'
|
||||
: 'text-gray-600 hover:underline hover:text-blue-600')
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="sticky" style={{ top: '2.5rem' }}>
|
||||
<h2 className="uppercase text-gray-500 font-bold mb-4 text-sm tracking-wider">
|
||||
Table of Contents
|
||||
</h2>
|
||||
{links}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableOfContentsSidebar;
|
|
@ -0,0 +1,44 @@
|
|||
import { TOCHeading } from '../../../models/module';
|
||||
import * as React from 'react';
|
||||
import { Link } from 'gatsby';
|
||||
|
||||
export default function genLinksFromTOCHeadings(
|
||||
headings: TOCHeading[],
|
||||
getClasses: (heading: TOCHeading) => string
|
||||
) {
|
||||
let indentationLevels = ['0', '1.5rem', '3rem', '4.5rem'];
|
||||
let links: React.ReactNode[] = [];
|
||||
let curDepth = -1;
|
||||
let indentIdx = 0;
|
||||
headings.forEach((heading, idx) => {
|
||||
if (curDepth === -1) curDepth = heading.depth;
|
||||
if (heading.depth > curDepth) {
|
||||
indentIdx++;
|
||||
} else if (heading.depth < curDepth) {
|
||||
indentIdx = Math.max(0, indentIdx - (curDepth - heading.depth));
|
||||
}
|
||||
curDepth = heading.depth;
|
||||
links.push(
|
||||
<Link
|
||||
key={heading.slug}
|
||||
to={'#' + heading.slug}
|
||||
className={getClasses(heading)}
|
||||
style={{
|
||||
marginLeft: indentationLevels[indentIdx],
|
||||
marginTop:
|
||||
indentIdx === 0 &&
|
||||
((idx !== 0 && headings[idx - 1].depth > heading.depth) ||
|
||||
(idx !== headings.length - 1 &&
|
||||
headings[idx + 1].depth > heading.depth))
|
||||
? '1rem'
|
||||
: indentIdx === 0
|
||||
? '0.5rem'
|
||||
: 0,
|
||||
}}
|
||||
>
|
||||
{heading.value}
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
return links;
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { TOCHeading } from '../../models/module';
|
||||
import { Link } from 'gatsby';
|
||||
import { useActiveHash } from '../../hooks/useActiveHash';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
// lol this file is basically idential to the sidebar file... should consolidate
|
||||
|
||||
const TableOfContentsBlock = ({
|
||||
tableOfContents,
|
||||
}: {
|
||||
tableOfContents: TOCHeading[];
|
||||
}) => {
|
||||
let links = [];
|
||||
let curDepth = -1;
|
||||
let indentIdx = 0;
|
||||
let indent = ['0', '1.5rem', '3rem', '4.5rem'];
|
||||
tableOfContents.forEach((heading, idx) => {
|
||||
if (curDepth === -1) curDepth = heading.depth;
|
||||
if (heading.depth > curDepth) {
|
||||
indentIdx++;
|
||||
} else if (heading.depth < curDepth) {
|
||||
indentIdx = Math.max(0, indentIdx - (curDepth - heading.depth));
|
||||
}
|
||||
curDepth = heading.depth;
|
||||
links.push(
|
||||
<Link
|
||||
key={heading.slug}
|
||||
to={'#' + heading.slug}
|
||||
className="block mb-2 transition duration-150 ease-in-out text-gray-600 hover:underline hover:text-blue-600"
|
||||
style={{
|
||||
marginLeft: indent[indentIdx],
|
||||
marginTop:
|
||||
indentIdx === 0 &&
|
||||
((idx !== 0 && tableOfContents[idx - 1].depth > heading.depth) ||
|
||||
(idx !== tableOfContents.length - 1 &&
|
||||
tableOfContents[idx + 1].depth > heading.depth))
|
||||
? '1rem'
|
||||
: indentIdx === 0
|
||||
? '0.5rem'
|
||||
: 0,
|
||||
}}
|
||||
>
|
||||
{heading.value}
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="uppercase text-gray-500 font-bold mt-8 mb-3 tracking-wider">
|
||||
Table of Contents
|
||||
</h2>
|
||||
{links}
|
||||
<hr className="mt-6 mb-2" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableOfContentsBlock;
|
|
@ -1,67 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { TOCHeading } from '../../models/module';
|
||||
import { Link } from 'gatsby';
|
||||
import { useActiveHash } from '../../hooks/useActiveHash';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const TableOfContentsSidebar = ({
|
||||
tableOfContents,
|
||||
}: {
|
||||
tableOfContents: TOCHeading[];
|
||||
}) => {
|
||||
const hashes = useMemo(() => tableOfContents.map(heading => heading.slug), [
|
||||
tableOfContents,
|
||||
]);
|
||||
const activeHash = useActiveHash(hashes, '10px 0px 0px 0px');
|
||||
|
||||
let links = [];
|
||||
let curDepth = -1;
|
||||
let indentIdx = 0;
|
||||
let indent = ['0', '1.5rem', '3rem', '4.5rem'];
|
||||
tableOfContents.forEach((heading, idx) => {
|
||||
if (curDepth === -1) curDepth = heading.depth;
|
||||
if (heading.depth > curDepth) {
|
||||
indentIdx++;
|
||||
} else if (heading.depth < curDepth) {
|
||||
indentIdx = Math.max(0, indentIdx - (curDepth - heading.depth));
|
||||
}
|
||||
curDepth = heading.depth;
|
||||
links.push(
|
||||
<Link
|
||||
key={heading.slug}
|
||||
to={'#' + heading.slug}
|
||||
className={
|
||||
'block mb-1 text-sm transition duration-150 ease-in-out ' +
|
||||
(activeHash === heading.slug
|
||||
? 'underline text-blue-600'
|
||||
: 'text-gray-600 hover:underline hover:text-blue-600')
|
||||
}
|
||||
style={{
|
||||
marginLeft: indent[indentIdx],
|
||||
marginTop:
|
||||
indentIdx === 0 &&
|
||||
((idx !== 0 && tableOfContents[idx - 1].depth > heading.depth) ||
|
||||
(idx !== tableOfContents.length - 1 &&
|
||||
tableOfContents[idx + 1].depth > heading.depth))
|
||||
? '1rem'
|
||||
: indentIdx === 0
|
||||
? '0.5rem'
|
||||
: 0,
|
||||
}}
|
||||
>
|
||||
{heading.value}
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="sticky" style={{ top: '2.5rem' }}>
|
||||
<h2 className="uppercase text-gray-500 font-bold mb-4 text-sm tracking-wider">
|
||||
Table of Contents
|
||||
</h2>
|
||||
{links}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableOfContentsSidebar;
|
67
src/components/markdown/HTMLComponents.tsx
Normal file
67
src/components/markdown/HTMLComponents.tsx
Normal file
|
@ -0,0 +1,67 @@
|
|||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const OffsetAnchor = ({ id, ...props }) => (
|
||||
<span
|
||||
id={id}
|
||||
{...props}
|
||||
className="absolute"
|
||||
style={{ bottom: '100px', height: '2px' }}
|
||||
/>
|
||||
);
|
||||
|
||||
const HTMLComponents = {
|
||||
table: ({ className, ...props }) => (
|
||||
<table
|
||||
{...props}
|
||||
className={classNames(
|
||||
'text-base border-gray-600 no-bottom-margin',
|
||||
className
|
||||
)}
|
||||
/>
|
||||
),
|
||||
th: ({ className, ...props }) => (
|
||||
<th {...props} className={classNames('border py-1 px-3', className)} />
|
||||
),
|
||||
td: ({ className, ...props }) => (
|
||||
<td {...props} className={classNames('border py-1 px-3', className)} />
|
||||
),
|
||||
h1: ({ id, children, ...props }) => (
|
||||
<h1
|
||||
{...props}
|
||||
className="leading-tight text-4xl font-bold mb-4 mt-12 text-gray-700"
|
||||
>
|
||||
<OffsetAnchor id={id} />
|
||||
{children}
|
||||
</h1>
|
||||
),
|
||||
h2: ({ id, children, ...props }) => (
|
||||
<h2
|
||||
className="leading-tight text-3xl font-bold mb-4 mt-12 text-gray-700 relative"
|
||||
{...props}
|
||||
>
|
||||
<OffsetAnchor id={id} />
|
||||
{children}
|
||||
</h2>
|
||||
),
|
||||
h3: ({ id, children, ...props }) => (
|
||||
<h3 {...props} className="leading-snug text-2xl font-semibold mb-4 mt-8">
|
||||
<OffsetAnchor id={id} />
|
||||
{children}
|
||||
</h3>
|
||||
),
|
||||
h4: ({ id, children, ...props }) => (
|
||||
<h4 {...props} className="leading-none text-xl font-semibold mb-2 mt-6">
|
||||
<OffsetAnchor id={id} />
|
||||
{children}
|
||||
</h4>
|
||||
),
|
||||
p: props => <p {...props} className="mb-4" />,
|
||||
'ol.li': ({ children, ...props }) => (
|
||||
<li {...props}>
|
||||
<div className="flex-1">{children}</div>
|
||||
</li>
|
||||
),
|
||||
};
|
||||
|
||||
export default HTMLComponents;
|
|
@ -1,8 +1,6 @@
|
|||
import * as React from 'react';
|
||||
import UserDataContext from '../../context/UserDataContext';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export const IncompleteSection = props => {
|
||||
export const IncompleteSection = () => {
|
||||
return (
|
||||
<div className="p-4 bg-red-100 text-red-800 rounded">
|
||||
<b>This section is not complete.</b> Feel free to file a request to
|
||||
|
|
33
src/components/markdown/Info.tsx
Normal file
33
src/components/markdown/Info.tsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
import * as React from 'react';
|
||||
|
||||
const Info = ({
|
||||
children,
|
||||
title,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
title: string;
|
||||
}) => (
|
||||
<div className="rounded-md bg-blue-50 p-4 mb-4 info-block">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<svg
|
||||
className="h-5 w-5 text-blue-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-3 flex-1">
|
||||
<h3 className="info-block__heading">{title}</h3>
|
||||
<div className="info-block__body no-bottom-margin">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Info;
|
10
src/components/markdown/InlineCode.tsx
Normal file
10
src/components/markdown/InlineCode.tsx
Normal file
|
@ -0,0 +1,10 @@
|
|||
import * as React from 'react';
|
||||
|
||||
const InlineCode = props => (
|
||||
<code
|
||||
{...props}
|
||||
className="font-mono inline bg-gray-200 rounded px-1 py-05"
|
||||
/>
|
||||
);
|
||||
|
||||
export default InlineCode;
|
|
@ -1,10 +1,11 @@
|
|||
import * as React from 'react';
|
||||
import UserDataContext from '../../context/UserDataContext';
|
||||
import UserDataContext, {
|
||||
LANGUAGE_LABELS,
|
||||
} from '../../context/UserDataContext';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export const LanguageSection = props => {
|
||||
const userSettings = useContext(UserDataContext);
|
||||
let lang = userSettings.lang;
|
||||
const { lang } = useContext(UserDataContext);
|
||||
|
||||
let sections = {};
|
||||
React.Children.map(props.children, child => {
|
||||
|
@ -13,24 +14,13 @@ export const LanguageSection = props => {
|
|||
if (type === 'JavaSection') sections['java'] = child;
|
||||
if (type === 'PySection') sections['py'] = child;
|
||||
});
|
||||
// props.children.forEach(child => {
|
||||
// let type = child.props.mdxType;
|
||||
// if (type === 'CPPSection') sections['cpp'] = child;
|
||||
// if (type === 'JavaSection') sections['java'] = child;
|
||||
// if (type === 'PySection') sections['py'] = child;
|
||||
// });
|
||||
const languages = {
|
||||
cpp: 'C++',
|
||||
java: 'Java',
|
||||
py: 'Python',
|
||||
};
|
||||
|
||||
if (lang === 'showAll') {
|
||||
return (
|
||||
<>
|
||||
{Object.keys(sections).map(lang => (
|
||||
<div key={lang}>
|
||||
<p className="text-lg font-bold">{languages[lang]}</p>
|
||||
<p className="text-lg font-bold">{LANGUAGE_LABELS[lang]}</p>
|
||||
{sections[lang]}
|
||||
</div>
|
||||
))}
|
||||
|
@ -43,11 +33,11 @@ export const LanguageSection = props => {
|
|||
<div className="p-4 bg-red-100 text-red-800 rounded">
|
||||
<b>
|
||||
This section isn't yet available in your chosen language:{' '}
|
||||
{languages[lang]}.
|
||||
{LANGUAGE_LABELS[lang]}.
|
||||
</b>{' '}
|
||||
Please choose a different default language for now. Feel free to file a
|
||||
request to add support for {languages[lang]} using the "Contact Us"
|
||||
button.
|
||||
request to add support for {LANGUAGE_LABELS[lang]} using the "Contact
|
||||
Us" button.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import * as React from 'react';
|
||||
import { MDXProvider } from '@mdx-js/react';
|
||||
import SpoilerComponent from './SpoilerComponent';
|
||||
import { ProblemsListComponent } from './Problems';
|
||||
import { ResourceComponent, ResourcesListComponent } from './Resources';
|
||||
import CodeBlock from './CodeBlock';
|
||||
import classNames from 'classnames';
|
||||
import Asterisk from '../tooltip/Asterisk';
|
||||
import TextTooltip from '../tooltip/TextTooltip';
|
||||
import Spoiler from './Spoiler';
|
||||
import { ProblemsList } from './ProblemsList/ProblemsList';
|
||||
import { Resource, ResourcesList } from './ResourcesList';
|
||||
import CodeBlock from './CodeBlock/CodeBlock';
|
||||
import Asterisk from '../Tooltip/Asterisk';
|
||||
import TextTooltip from '../Tooltip/TextTooltip';
|
||||
import {
|
||||
CPPSection,
|
||||
JavaSection,
|
||||
|
@ -14,165 +13,31 @@ import {
|
|||
PySection,
|
||||
} from './LanguageSection';
|
||||
import { IncompleteSection } from './IncompleteSection';
|
||||
|
||||
const OffsetAnchor = ({ id, ...props }) => (
|
||||
<span
|
||||
id={id}
|
||||
{...props}
|
||||
className="absolute"
|
||||
style={{ bottom: '100px', height: '2px' }}
|
||||
/>
|
||||
);
|
||||
import Info from './Info';
|
||||
import Warning from './Warning';
|
||||
import Optional from './Optional';
|
||||
import InlineCode from './InlineCode';
|
||||
import HTMLComponents from './HTMLComponents';
|
||||
|
||||
const components = {
|
||||
'module-excerpt': props => <div {...props} />,
|
||||
spoiler: SpoilerComponent,
|
||||
'info-block': ({
|
||||
children,
|
||||
title,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
title: string;
|
||||
}) => (
|
||||
<div className="rounded-md bg-blue-50 p-4 mb-4 info-block">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<svg
|
||||
className="h-5 w-5 text-blue-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-3 flex-1">
|
||||
<h3 className="info-block__heading">{title}</h3>
|
||||
<div className="info-block__body no-bottom-margin">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
'warning-block': ({ children, title }) => (
|
||||
<div className="rounded-md bg-yellow-50 p-4 mb-4">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<svg
|
||||
className="h-5 w-5 text-yellow-400"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<h3 className="text-sm leading-5 font-medium text-yellow-800">
|
||||
Warning{title ? ': ' + title : '!'}
|
||||
</h3>
|
||||
<div className="mt-2 text-sm leading-5 text-yellow-700 no-bottom-margin">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
'optional-content': ({
|
||||
children,
|
||||
title,
|
||||
className,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
title?: string;
|
||||
className?: string;
|
||||
}) => (
|
||||
<div
|
||||
className={`bg-white overflow-hidden shadow rounded-lg border border-purple-400 mb-8`}
|
||||
>
|
||||
<div className="p-4 flex items-center font-medium text-purple-800 bg-purple-50">
|
||||
<svg className="h-6 w-6 mr-3" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M11 3a1 1 0 10-2 0v1a1 1 0 102 0V3zM15.657 5.757a1 1 0 00-1.414-1.414l-.707.707a1 1 0 001.414 1.414l.707-.707zM18 10a1 1 0 01-1 1h-1a1 1 0 110-2h1a1 1 0 011 1zM5.05 6.464A1 1 0 106.464 5.05l-.707-.707a1 1 0 00-1.414 1.414l.707.707zM5 10a1 1 0 01-1 1H3a1 1 0 110-2h1a1 1 0 011 1zM8 16v-1h4v1a2 2 0 11-4 0zM12 14c.015-.34.208-.646.477-.859a4 4 0 10-4.954 0c.27.213.462.519.476.859h4.002z" />
|
||||
</svg>
|
||||
Optional{title ? `: ${title}` : ''}
|
||||
</div>
|
||||
<div className="p-4 pb-0">{children}</div>
|
||||
</div>
|
||||
),
|
||||
'problems-list': ProblemsListComponent,
|
||||
resources: ResourcesListComponent,
|
||||
resource: ResourceComponent,
|
||||
spoiler: Spoiler,
|
||||
'info-block': Info,
|
||||
'warning-block': Warning,
|
||||
'optional-content': Optional,
|
||||
'problems-list': ProblemsList,
|
||||
resources: ResourcesList,
|
||||
resource: Resource,
|
||||
code: CodeBlock,
|
||||
TextTooltip: TextTooltip,
|
||||
inlineCode: props => (
|
||||
<code
|
||||
{...props}
|
||||
className="font-mono inline bg-gray-200 rounded px-1 py-05"
|
||||
/>
|
||||
),
|
||||
inlineCode: InlineCode,
|
||||
LanguageSection: LanguageSection,
|
||||
CPPSection: CPPSection,
|
||||
JavaSection: JavaSection,
|
||||
PySection: PySection,
|
||||
IncompleteSection: IncompleteSection,
|
||||
Asterisk: Asterisk,
|
||||
table: ({ className, ...props }) => (
|
||||
<table
|
||||
{...props}
|
||||
className={classNames(
|
||||
'text-base border-gray-600 no-bottom-margin',
|
||||
className
|
||||
)}
|
||||
/>
|
||||
),
|
||||
th: ({ className, ...props }) => (
|
||||
<th {...props} className={classNames('border py-1 px-3', className)} />
|
||||
),
|
||||
td: ({ className, ...props }) => (
|
||||
<td {...props} className={classNames('border py-1 px-3', className)} />
|
||||
),
|
||||
h1: ({ id, children, ...props }) => (
|
||||
<h1
|
||||
{...props}
|
||||
className="leading-tight text-4xl font-bold mb-4 mt-12 text-gray-700"
|
||||
>
|
||||
<OffsetAnchor id={id} />
|
||||
{children}
|
||||
</h1>
|
||||
),
|
||||
h2: ({ id, children, ...props }) => (
|
||||
<h2
|
||||
className="leading-tight text-3xl font-bold mb-4 mt-12 text-gray-700 relative"
|
||||
{...props}
|
||||
>
|
||||
<OffsetAnchor id={id} />
|
||||
{children}
|
||||
</h2>
|
||||
),
|
||||
h3: ({ id, children, ...props }) => (
|
||||
<h3 {...props} className="leading-snug text-2xl font-semibold mb-4 mt-8">
|
||||
<OffsetAnchor id={id} />
|
||||
{children}
|
||||
</h3>
|
||||
),
|
||||
h4: ({ id, children, ...props }) => (
|
||||
<h4 {...props} className="leading-none text-xl font-semibold mb-2 mt-6">
|
||||
<OffsetAnchor id={id} />
|
||||
{children}
|
||||
</h4>
|
||||
),
|
||||
|
||||
p: props => <p {...props} className="mb-4" />,
|
||||
'ol.li': ({ children, ...props }) => (
|
||||
<li {...props}>
|
||||
<div className="flex-1">{children}</div>
|
||||
</li>
|
||||
),
|
||||
...HTMLComponents,
|
||||
};
|
||||
|
||||
export default function ({ children }) {
|
||||
|
|
25
src/components/markdown/Optional.tsx
Normal file
25
src/components/markdown/Optional.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import * as React from 'react';
|
||||
|
||||
const Optional = ({
|
||||
children,
|
||||
title,
|
||||
className,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
title?: string;
|
||||
className?: string;
|
||||
}) => (
|
||||
<div
|
||||
className={`bg-white overflow-hidden shadow rounded-lg border border-purple-400 mb-8`}
|
||||
>
|
||||
<div className="p-4 flex items-center font-medium text-purple-800 bg-purple-50">
|
||||
<svg className="h-6 w-6 mr-3" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M11 3a1 1 0 10-2 0v1a1 1 0 102 0V3zM15.657 5.757a1 1 0 00-1.414-1.414l-.707.707a1 1 0 001.414 1.414l.707-.707zM18 10a1 1 0 01-1 1h-1a1 1 0 110-2h1a1 1 0 011 1zM5.05 6.464A1 1 0 106.464 5.05l-.707-.707a1 1 0 00-1.414 1.414l.707.707zM5 10a1 1 0 01-1 1H3a1 1 0 110-2h1a1 1 0 011 1zM8 16v-1h4v1a2 2 0 11-4 0zM12 14c.015-.34.208-.646.477-.859a4 4 0 10-4.954 0c.27.213.462.519.476.859h4.002z" />
|
||||
</svg>
|
||||
Optional{title ? `: ${title}` : ''}
|
||||
</div>
|
||||
<div className="p-4 pb-0">{children}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Optional;
|
|
@ -1,9 +1,9 @@
|
|||
import * as React from 'react';
|
||||
import Tooltip from './tooltip/Tooltip';
|
||||
import { Problem } from '../../content/models';
|
||||
import Tooltip from '../../Tooltip/Tooltip';
|
||||
import { Problem } from '../../../../content/models';
|
||||
import { useContext } from 'react';
|
||||
import UserDataContext from '../context/UserDataContext';
|
||||
import { NEXT_PROBLEM_STATUS, ProblemProgress } from '../models/problem';
|
||||
import UserDataContext from '../../../context/UserDataContext';
|
||||
import { NEXT_PROBLEM_STATUS, ProblemProgress } from '../../../models/problem';
|
||||
|
||||
export default function ProblemStatusCheckbox({
|
||||
problem,
|
|
@ -1,18 +1,18 @@
|
|||
import * as React from 'react';
|
||||
import { Problem } from '../../../content/models';
|
||||
import Transition from '../Transition';
|
||||
import Tooltip from '../tooltip/Tooltip';
|
||||
import TextTooltip from '../tooltip/TextTooltip';
|
||||
import { sourceTooltip } from './Resources';
|
||||
import ProblemStatusCheckbox from '../ProblemStatusCheckbox';
|
||||
import { Problem } from '../../../../content/models';
|
||||
import Transition from '../../Transition';
|
||||
import Tooltip from '../../Tooltip/Tooltip';
|
||||
import TextTooltip from '../../Tooltip/TextTooltip';
|
||||
import { sourceTooltip } from '../ResourcesList';
|
||||
import ProblemStatusCheckbox from './ProblemStatusCheckbox';
|
||||
|
||||
type ProblemsListComponentProps = {
|
||||
type ProblemsListProps = {
|
||||
title?: string;
|
||||
children?: React.ReactChildren;
|
||||
problems: Problem[];
|
||||
};
|
||||
|
||||
export function ProblemsListComponent(props: ProblemsListComponentProps) {
|
||||
export function ProblemsList(props: ProblemsListProps) {
|
||||
const [problem, setProblem] = React.useState(null);
|
||||
const [showModal, setShowModal] = React.useState(false);
|
||||
return (
|
|
@ -1,11 +1,10 @@
|
|||
import * as React from 'react';
|
||||
import Dots from '../Dots';
|
||||
import Tooltip from '../tooltip/Tooltip';
|
||||
import TextTooltip from '../tooltip/TextTooltip';
|
||||
import Tooltip from '../Tooltip/Tooltip';
|
||||
import TextTooltip from '../Tooltip/TextTooltip';
|
||||
import { useContext } from 'react';
|
||||
import UserDataContext from '../../context/UserDataContext';
|
||||
|
||||
export function ResourcesListComponent(props) {
|
||||
export function ResourcesList(props) {
|
||||
const embedded = props.embedded;
|
||||
return (
|
||||
<div className="flex flex-col mb-4">
|
||||
|
@ -91,7 +90,7 @@ export const sourceTooltip = {
|
|||
'Old Gold': 'USACO Platinum did not exist prior to 2015-16.',
|
||||
};
|
||||
|
||||
export function ResourceComponent(props) {
|
||||
export function Resource(props) {
|
||||
const userSettings = useContext(UserDataContext);
|
||||
|
||||
const source = props.source;
|
|
@ -1,6 +1,6 @@
|
|||
import * as React from 'react';
|
||||
|
||||
const SpoilerComponent = ({ children, title }) => {
|
||||
const Spoiler = ({ children, title }) => {
|
||||
const [show, setShow] = React.useState(false);
|
||||
|
||||
return (
|
||||
|
@ -44,4 +44,4 @@ const SpoilerComponent = ({ children, title }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default SpoilerComponent;
|
||||
export default Spoiler;
|
31
src/components/markdown/Warning.tsx
Normal file
31
src/components/markdown/Warning.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import * as React from 'react';
|
||||
|
||||
const Warning = ({ children, title }) => (
|
||||
<div className="rounded-md bg-yellow-50 p-4 mb-4">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<svg
|
||||
className="h-5 w-5 text-yellow-400"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<h3 className="text-sm leading-5 font-medium text-yellow-800">
|
||||
Warning{title ? ': ' + title : '!'}
|
||||
</h3>
|
||||
<div className="mt-2 text-sm leading-5 text-yellow-700 no-bottom-margin">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Warning;
|
|
@ -5,6 +5,12 @@ import { ModuleProgress } from '../models/module';
|
|||
import { ProblemProgress } from '../models/problem';
|
||||
|
||||
export type UserLang = 'showAll' | 'cpp' | 'java' | 'py';
|
||||
export const LANGUAGE_LABELS: { [key in UserLang]: string } = {
|
||||
showAll: 'All',
|
||||
cpp: 'C++',
|
||||
java: 'Java',
|
||||
py: 'Python',
|
||||
};
|
||||
|
||||
const UserDataContext = createContext<{
|
||||
lang: UserLang;
|
||||
|
|
Reference in a new issue