Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["next/babel"],
"plugins": ["macros"]
}
6 changes: 5 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
parser: '@typescript-eslint/parser',
root: true, // Make sure eslint picks up the config at the root of the directory
parserOptions: {
ecmaVersion: 2020, // Use the latest ecmascript standard
Expand All @@ -19,7 +20,7 @@ module.exports = {
es6: true,
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:jsx-a11y/recommended',
'plugin:prettier/recommended', // Make this the last element so prettier config overrides other formatting rules
Expand All @@ -28,5 +29,8 @@ module.exports = {
'react/prop-types': 'off',
'prettier/prettier': ['error', {}, { usePrettierrc: true }], // Use our .prettierrc file as source
'jsx-a11y/anchor-is-valid': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
ignorePatterns: ['*.macro.js'],
}
179 changes: 0 additions & 179 deletions components/Algorithm.js

This file was deleted.

8 changes: 8 additions & 0 deletions components/Algorithm/Algorithm.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.main {
grid-template-columns: minmax(0, 3fr) 4fr;
}

.controls {
top: 50%;
transform: translateY(-50%);
}
72 changes: 72 additions & 0 deletions components/Algorithm/ArgumentForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React, { FocusEventHandler, FormEventHandler } from 'react'

type Args = (readonly [string, unknown])[]

type ArgumentFormProps = {
args: Args
onSubmit: (newArgs: Args) => void
}

export default function ArgumentForm({ args, onSubmit }: ArgumentFormProps) {
const [errors, setErrors] = React.useState({})

const validate = (name: string, value: string) => {
if (isSerializable(value)) {
setErrors({ [name]: null })
return true
}
setErrors({ [name]: 'Please enter a serializable input.' })
return false
}

const handleBlur: FocusEventHandler<HTMLInputElement> = (evt) => {
const { name, value } = evt.target
validate(name, value)
}

const handleSubmit: FormEventHandler<HTMLFormElement> = (evt) => {
evt.preventDefault()
const data = [...new FormData(evt.target as HTMLFormElement).entries()] as [
string,
string
][]

if (!data.every(([name, value]) => validate(name, value))) {
return
}

onSubmit(data.map(([name, value]) => [name, JSON.parse(value)]))
}

return (
<form className="w-full" onSubmit={handleSubmit}>
{args.map(([name, value]) => (
<label key={name} className="block font-mono w-full mb-2">
{name}
<input
name={name}
className="w-full block border-3 border-black rounded-lg p-2"
type="text"
defaultValue={JSON.stringify(value)}
onBlur={handleBlur}
/>
{errors[name] && (
<p className="text-sm text-red-600">{errors[name]}</p>
)}
</label>
))}
<button className="bg-gray-300 rounded-lg w-full p-2 font-bold mt-4">
Update
</button>
</form>
)
}

function isSerializable(value: string) {
try {
JSON.parse(value)
return true
} catch {
return false
}
}
41 changes: 41 additions & 0 deletions components/Algorithm/CodeBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react'
import Highlight, { defaultProps } from 'prism-react-renderer'
import { motion } from 'framer-motion'
import clsx from 'clsx'

export default function CodeBlock({ code, highlightLine }) {
return (
<Highlight
{...defaultProps}
code={code}
language="typescript"
theme={undefined}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre
className={clsx(
className,
'w-full p-4 bg-gray-200 rounded-lg border-3 max-h-full overflow-scroll relative'
)}
style={{ ...style, fontSize: '14px' }}
>
<motion.div
layout
style={{
height: '22.4px',
top: 16 + 22.4 * highlightLine,
}}
className="absolute w-full bg-gray-500 opacity-25 left-0"
></motion.div>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
)}
</Highlight>
)
}
39 changes: 39 additions & 0 deletions components/Algorithm/Controls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react'
import clsx, { ClassValue } from 'clsx'
import { BsFillPlayFill, BsPauseFill } from 'react-icons/bs'
import { FaUndoAlt } from 'react-icons/fa'
import { BiLeftArrowAlt, BiRightArrowAlt } from 'react-icons/bi'

import { Button } from '~components/Button'
import { AlgorithmContext } from '~lib/types'

type ControlsProps = {
context: AlgorithmContext
className?: ClassValue
}

export default function Controls({
context: { actions, models },
className = '',
}: ControlsProps) {
return (
<section className={clsx(className)}>
<Button className="mb-2" onClick={actions.toggle} title="Start animation">
{models.isPlaying ? (
<BsPauseFill size="1.5em" />
) : (
<BsFillPlayFill size="1.5em" />
)}
</Button>
<Button className="mb-2" onClick={actions.reset} title="Reset">
<FaUndoAlt />
</Button>
<Button className="mb-2" onClick={actions.prev} title="Previous step">
<BiLeftArrowAlt size="1.5em" />
</Button>
<Button className="mb-2" onClick={actions.next} title="Next step">
<BiRightArrowAlt size="1.5em" />
</Button>
</section>
)
}
Loading