Marking progress on roadmap

pull/1202/head
Kamran Ahmed 3 years ago
parent dd7306cd6d
commit 537ffc365e
  1. 12
      components/md-renderer/mdx-components/heading.tsx
  2. 67
      components/roadmap/content-drawer.tsx
  3. 13
      lib/renderer/renderer.ts
  4. 4
      lib/renderer/utils.ts
  5. 17
      pages/[roadmap]/interactive.tsx
  6. 5
      pages/_app.tsx

@ -70,12 +70,12 @@ const H6 = styled(H1).attrs({ as: 'h6' })`
`; `;
const Headings = { const Headings = {
h1: linkify(H1), h1: H1,
h2: linkify(H2), h2: H2,
h3: linkify(H3), h3: H3,
h4: linkify(H4), h4: H4,
h5: linkify(H5), h5: H5,
h6: linkify(H6) h6: H6
}; };
export default Headings; export default Headings;

@ -1,7 +1,8 @@
import { Box, CloseButton } from '@chakra-ui/react'; import { Box, Button, Flex, Text } from '@chakra-ui/react';
import { RemoveScroll } from 'react-remove-scroll'; import { RemoveScroll } from 'react-remove-scroll';
import { RoadmapType } from '../../lib/roadmap'; import { RoadmapType } from '../../lib/roadmap';
import RoadmapGroup from '../../pages/[roadmap]/[group]'; import RoadmapGroup from '../../pages/[roadmap]/[group]';
import { CheckIcon, CloseIcon, RepeatIcon } from '@chakra-ui/icons';
type ContentDrawerProps = { type ContentDrawerProps = {
roadmap: RoadmapType; roadmap: RoadmapType;
@ -15,6 +16,8 @@ export function ContentDrawer(props: ContentDrawerProps) {
return null; return null;
} }
const isDone = localStorage.getItem(groupId) === 'done';
return ( return (
<Box zIndex={99999} pos="relative"> <Box zIndex={99999} pos="relative">
<Box <Box
@ -39,13 +42,63 @@ export function ContentDrawer(props: ContentDrawerProps) {
borderLeftWidth={'1px'} borderLeftWidth={'1px'}
overflowY="scroll" overflowY="scroll"
> >
<CloseButton <Flex
onClick={onClose} mt="20px"
pos="absolute" justifyContent="space-between"
top={'20px'} alignItems="center"
right={'20px'}
zIndex={1} zIndex={1}
/> >
{!isDone && (
<Button
onClick={() => {
localStorage.setItem(groupId, 'done');
document
.querySelector(`[data-group-id*="-${groupId}"]`)
?.classList?.add('done');
onClose();
}}
colorScheme="green"
leftIcon={<CheckIcon />}
size="xs"
iconSpacing={0}
>
<Text as="span" d={['block', 'none', 'none', 'block']} ml="10px">
Mark as Done
</Text>
</Button>
)}
{isDone && (
<Button
onClick={() => {
localStorage.removeItem(groupId);
document
.querySelector(`[data-group-id*="-${groupId}"]`)
?.classList?.remove('done');
onClose();
}}
colorScheme="purple"
leftIcon={<RepeatIcon />}
size="xs"
iconSpacing={0}
>
<Text as="span" d={['block', 'none', 'none', 'block']} ml="10px">
Mark as Pending
</Text>
</Button>
)}
<Button
onClick={onClose}
colorScheme="yellow"
ml="5px"
leftIcon={<CloseIcon width="8px" />}
iconSpacing={0}
size="xs"
>
<Text as="span" d={['none', 'none', 'none', 'block']} ml="10px">
Close
</Text>
</Button>
</Flex>
<RoadmapGroup isOutlet roadmap={roadmap} group={groupId} /> <RoadmapGroup isOutlet roadmap={roadmap} group={groupId} />
</Box> </Box>
</RemoveScroll> </RemoveScroll>

@ -1,4 +1,8 @@
import { getRGBFromDecimalColor, makeSVGElement } from './utils'; import {
getRGBFromDecimalColor,
makeSVGElement,
removeSortingInfo,
} from './utils';
import { import {
ARROW_WIDTH, ARROW_WIDTH,
BORDER_WIDTH, BORDER_WIDTH,
@ -257,12 +261,17 @@ export class Renderer {
__group__(control: any, container: any) { __group__(control: any, container: any) {
const controlName = control?.properties?.controlName; const controlName = control?.properties?.controlName;
const groupId = removeSortingInfo(controlName);
const isDone = localStorage.getItem(groupId) === 'done';
let group = makeSVGElement( let group = makeSVGElement(
'g', 'g',
{ {
...(controlName ...(controlName
? { class: 'clickable-group', 'data-group-id': controlName } ? {
class: `clickable-group ${isDone ? 'done' : ''}`,
'data-group-id': controlName,
}
: {}), : {}),
}, },
container container

@ -1,3 +1,7 @@
export function removeSortingInfo(groupId: string) {
return (groupId || '').replace(/^\d+-/, '');
}
export function getRGBFromDecimalColor(color: number) { export function getRGBFromDecimalColor(color: number) {
let red = (color >> 16) & 0xff; let red = (color >> 16) & 0xff;
let green = (color >> 8) & 0xff; let green = (color >> 8) & 0xff;

@ -12,6 +12,7 @@ import { RoadmapPageHeader } from '../../components/roadmap/roadmap-page-header'
import { ContentDrawer } from '../../components/roadmap/content-drawer'; import { ContentDrawer } from '../../components/roadmap/content-drawer';
import { RoadmapError } from '../../components/roadmap/roadmap-error'; import { RoadmapError } from '../../components/roadmap/roadmap-error';
import { RoadmapLoader } from '../../components/roadmap/roadmap-loader'; import { RoadmapLoader } from '../../components/roadmap/roadmap-loader';
import { removeSortingInfo } from '../../lib/renderer/utils';
type RoadmapProps = { type RoadmapProps = {
roadmap: RoadmapType; roadmap: RoadmapType;
@ -19,10 +20,6 @@ type RoadmapProps = {
export function InteractiveRoadmapRenderer(props: RoadmapProps) { export function InteractiveRoadmapRenderer(props: RoadmapProps) {
const { roadmap } = props; const { roadmap } = props;
if (!roadmap.jsonUrl) {
return null;
}
const { loading: isLoading, error: hasErrorLoading, get } = useFetch(); const { loading: isLoading, error: hasErrorLoading, get } = useFetch();
const roadmapRef = useRef(null); const roadmapRef = useRef(null);
@ -33,6 +30,10 @@ export function InteractiveRoadmapRenderer(props: RoadmapProps) {
const [hasErrorRendering, setHasErrorRendering] = useState(false); const [hasErrorRendering, setHasErrorRendering] = useState(false);
useEffect(() => { useEffect(() => {
if (!roadmap.jsonUrl) {
return;
}
get(roadmap.jsonUrl) get(roadmap.jsonUrl)
.then((roadmapJson) => { .then((roadmapJson) => {
setRoadmapJson(roadmapJson); setRoadmapJson(roadmapJson);
@ -65,7 +66,7 @@ export function InteractiveRoadmapRenderer(props: RoadmapProps) {
// e.g. 100-internet:how-does-the-internet-work // e.g. 100-internet:how-does-the-internet-work
// will be translated to `internet:how-does-the-internet-work` // will be translated to `internet:how-does-the-internet-work`
setGroupId(groupId.replace(/^\d+-/, '')); setGroupId(removeSortingInfo(groupId));
} }
window.addEventListener('keydown', keydownListener); window.addEventListener('keydown', keydownListener);
@ -104,8 +105,12 @@ export function InteractiveRoadmapRenderer(props: RoadmapProps) {
}); });
}, [roadmapJson]); }, [roadmapJson]);
if (!roadmap.jsonUrl) {
return null;
}
if (hasErrorLoading || hasErrorRendering) { if (hasErrorLoading || hasErrorRendering) {
return <RoadmapError roadmap={roadmap} /> return <RoadmapError roadmap={roadmap} />;
} }
return ( return (

@ -43,6 +43,11 @@ const GlobalStyles = css`
&:hover > [fill="rgb(153,153,153)"] { fill: #646464; } &:hover > [fill="rgb(153,153,153)"] { fill: #646464; }
&:hover > [fill="rgb(255,255,255)"] { fill: #d7d7d7; } &:hover > [fill="rgb(255,255,255)"] { fill: #d7d7d7; }
} }
svg .done {
& rect { fill: #cbcbcb; }
& text { text-decoration: line-through; }
}
`; `;

Loading…
Cancel
Save