Set ts compiler to strict, refactored a bit

This commit is contained in:
Martin Berg Alstad 2023-04-08 19:24:10 +02:00
parent 292da46769
commit 7f6c405890
18 changed files with 391 additions and 330 deletions

View File

@ -49,13 +49,10 @@ export const Button: Component<ButtonProps> = (
onClick,
type = "button",
}
) => {
return (
) => (
<button title={ title } id={ id } type={ type }
class={ `border-rounded bg-cyan-900 px-2 cursor-pointer ${ className }` }
onClick={ onClick }>
{ children }
</button>
);
};
);

View File

@ -3,21 +3,22 @@ import { type Component } from "solid-js";
import type { CardProps } from "../types/types";
import { Link } from "./link";
const Card: Component<CardProps> = ({ children, className, title, to, newTab = false }) => {
return (
<>
<div
class={ `relative bg-gradient-to-r from-cyan-600 to-cyan-500 h-32 w-72 rounded-2xl ${ className }` }>
<div class="relative p-5">
const Card: Component<CardProps> = (
{
children,
className,
title,
to,
newTab = false
}) => (
<div class={ `relative bg-gradient-to-r from-cyan-600 to-cyan-500 h-32 w-72 rounded-2xl ${ className }` }>
<div class={ "relative p-5" }>
<Link className={ "text-white" } to={ to } newTab={ newTab }>
<h3 class={ "text-center w-fit mx-auto before:content-['↗']" }>{ title }</h3>
</Link>
{ children }
</div>
</div>
</>
);
};
);
export default Card;

View File

@ -1,22 +1,23 @@
/* @refresh reload */
import { Dialog, DialogDescription, DialogPanel, DialogTitle } from "solid-headless";
import type { TitleProps } from "../types/types";
import { createEffect, createSignal, JSX } from "solid-js";
import { Component, createEffect, createSignal, JSX } from "solid-js";
import { Button } from "./button";
import { Portal } from "solid-js/web";
import { getElementById } from "../utils/dom";
interface MyDialog extends TitleProps {
description?: string,
button?: JSX.Element,
acceptButtonName?: string | null,
acceptButtonName?: string,
acceptButtonId?: string,
cancelButtonName?: string | null,
cancelButtonName?: string,
callback?: () => void,
buttonClasses?: string,
buttonClass?: string,
buttonTitle?: string | null,
}
export default function MyDialog(
const MyDialog: Component<MyDialog> = (
{
title,
description,
@ -26,10 +27,10 @@ export default function MyDialog(
children,
callback,
className,
buttonClasses,
buttonClass,
buttonTitle,
acceptButtonId,
}: MyDialog): JSX.Element {
}) => {
const [isOpen, setIsOpen] = createSignal(false);
@ -48,20 +49,21 @@ export default function MyDialog(
* @param e KeyboardEvent of keypress
*/
function click(e: KeyboardEvent): void {
if (isMounted && e.key === "Enter") {
(document.getElementById(acceptButtonId ?? "") as HTMLButtonElement | null)?.click();
if (isMounted && e.key === "Enter" && acceptButtonId) {
getElementById<HTMLButtonElement>(acceptButtonId)?.click();
}
}
if (isOpen()) {
const id = "cl-6"
const el = document.getElementById(id);
el?.addEventListener("keypress", e => click(e));
const el = getElementById(id);
el?.addEventListener("keypress", click);
return () => {
el?.removeEventListener("keypress", e => click(e));
el?.removeEventListener("keypress", click);
isMounted = false;
}
}
else return () => undefined;
}
createEffect(setupKeyPress, isOpen());
@ -69,7 +71,7 @@ export default function MyDialog(
return (
<div class={ "w-fit h-fit" }>
<button onClick={ () => setIsOpen(true) } class={ buttonClasses } title={ buttonTitle ?? undefined }>
<button onClick={ () => setIsOpen(true) } class={ buttonClass } title={ buttonTitle ?? undefined }>
{ button }
</button>
@ -99,3 +101,5 @@ export default function MyDialog(
</div>
);
}
export default MyDialog;

View File

@ -3,12 +3,10 @@ import { type Component } from "solid-js";
import type { SimpleProps } from "../types/types";
import { Link } from "./link";
const Footer: Component<SimpleProps> = ({ className }) => {
return (
const Footer: Component<SimpleProps> = ({ className }) => (
<footer class={ `text-center py-5 absolute bottom-0 container ${ className }` }>
<p>Kildekode <Link to={ "https://github.com/h600878/martials.no" }>GitHub</Link></p>
</footer>
);
};
);
export default Footer;

View File

@ -5,8 +5,7 @@ import { Icon } from "solid-heroicons";
import { chevronLeft } from "solid-heroicons/solid";
import { Link } from "./link";
const Header: Component<TitleProps> = ({ className, title }) => {
return (
const Header: Component<TitleProps> = ({ className, title = "Title goes here" }) => (
<header class={ className }>
<div class={ "flex-row-center mx-auto w-fit" }>
@ -22,7 +21,6 @@ const Header: Component<TitleProps> = ({ className, title }) => {
<p>Av Martin Berg Alstad</p>
</div>
</header>
);
};
);
export default Header;

View File

@ -1,7 +1,10 @@
/* @refresh reload */
import { type Component, createSignal, JSX, Setter } from "solid-js";
import { type Component, createSignal, JSX, onMount, Setter, Show } from "solid-js";
import type { InputProps } from "../types/types";
import Row from "./row";
import { Icon } from "solid-heroicons";
import { magnifyingGlass, xMark } from "solid-heroicons/solid";
import { getElementById } from "../utils/dom";
function setupEventListener(id: string, setIsHover: Setter<boolean>): () => void {
let isMounted = true;
@ -12,7 +15,7 @@ function setupEventListener(id: string, setIsHover: Setter<boolean>): () => void
}
}
const el = document.getElementById(id);
const el = getElementById(id);
el?.addEventListener("pointerenter", () => hover(true));
el?.addEventListener("pointerleave", () => hover(false));
@ -29,7 +32,7 @@ function setupEventListener(id: string, setIsHover: Setter<boolean>): () => void
*/
function setSetIsText(id: string | undefined, isText: boolean, setIsText: Setter<boolean>): void {
if (id) {
const el = document.getElementById(id) as HTMLInputElement | HTMLTextAreaElement | null;
const el = getElementById<HTMLInputElement | HTMLTextAreaElement>(id);
if (el && el.value !== "" !== isText) {
setIsText(el.value !== "");
}
@ -43,7 +46,7 @@ interface Input<T> extends InputProps<T> {
inputClass?: string,
}
export const Input: Component<Input<HTMLInputElement>> = (
export const Input: Component<Input<HTMLInputElement>> = ( // TODO remove leading and trailing from component
{
className,
id,
@ -71,7 +74,7 @@ export const Input: Component<Input<HTMLInputElement>> = (
*/
const [isText, setIsText] = createSignal(false);
document.addEventListener("DOMContentLoaded", () => {
onMount(() => {
if (id && title) {
setupEventListener(id, setIsHover);
}
@ -102,13 +105,12 @@ export const Input: Component<Input<HTMLInputElement>> = (
);
}
function HoverTitle(
const HoverTitle: Component<{ title?: string, isActive?: boolean, htmlFor?: string }> = (
{
title,
isActive = false,
htmlFor
}: { title?: string | null, isActive?: boolean, htmlFor?: string }): JSX.Element {
return (
}) => (
<label class={ `absolute pointer-events-none
${ isActive ? "-top-2 left-3 default-bg text-sm" : "left-2 top-1" }
transition-all duration-150 text-gray-600 dark:text-gray-400` }
@ -116,5 +118,58 @@ function HoverTitle(
<div class={ "z-50 relative" }>{ title }</div>
<div class={ "w-full h-2 default-bg absolute bottom-1/3 z-10" } />
</label>
);
interface SearchProps extends InputProps<HTMLInputElement> {
typingDefault?: boolean
}
export const Search: Component<SearchProps> = (
{
typingDefault = false,
id = "search",
className
}) => {
const [typing, setTyping] = createSignal(typingDefault);
function getInputElement() {
return getElementById<HTMLInputElement>(id);
}
function clearSearch(): void {
const el = getInputElement();
if (el) {
el.value = "";
setTyping(false);
history.replaceState(null, "", location.pathname);
el.focus();
}
}
function onChange(): void {
const el = getInputElement();
if (el && (el.value !== "") !== typing()) {
setTyping(el.value !== "");
}
}
return (
<Input inputClass={ `rounded-xl pl-7 h-10 w-full pr-8` } className={ `w-full ${ className }` }
id={ id }
placeholder={ "¬A & B -> C" }
type={ "text" }
onChange={ onChange }
leading={ <Icon path={ magnifyingGlass } aria-label={ "Magnifying glass" }
class={ "pl-2 absolute" } /> }
trailing={ <Show when={ typing() } keyed>
<button class={ "absolute right-2" }
title={ "Clear" }
type={ "reset" }
onClick={ clearSearch }>
<Icon path={ xMark } aria-label={ "The letter X" } />
</button>
</Show> }
/>
);
}

View File

@ -4,8 +4,12 @@ import type { TitleProps } from "../types/types";
import Header from "./header";
import Footer from "./footer";
const Layout: Component<TitleProps> = ({ children, title, className }) => {
return (
const Layout: Component<TitleProps> = (
{
children,
title,
className
}) => (
<div class={ `bg-default-bg text-white min-h-screen relative font-mono ${ className }` }>
<div class="container mx-auto">
<Header className={ "py-3" } title={ title } />
@ -15,7 +19,6 @@ const Layout: Component<TitleProps> = ({ children, title, className }) => {
</main>
</div>
</div>
);
};
);
export default Layout;

View File

@ -11,14 +11,11 @@ export const Link: Component<LinkProps> = (
id,
newTab = true,
title,
}) => {
return (
}) => (
<a href={ to } id={ id } title={ title }
rel={ `${ rel } ${ newTab ? "noreferrer" : undefined }` }
target={ newTab ? "_blank" : undefined }
class={ `link ${ className }` }>
{ children }
</a>
);
};
);

View File

@ -1,7 +1,8 @@
/* @refresh reload */
import { Disclosure, DisclosureButton, DisclosurePanel, Transition } from "solid-headless";
import { Icon } from "solid-heroicons";
import type { ChildProps, TitleProps } from "../types/types";
import { Component, JSX } from "solid-js";
import { type Component, JSX } from "solid-js";
import { chevronUp } from "solid-heroicons/solid";
interface InfoBoxProps extends TitleProps {
@ -10,18 +11,16 @@ interface InfoBoxProps extends TitleProps {
export const InfoBox: Component<InfoBoxProps> = (
{
title = "",
title,
children,
error = false,
className
}: InfoBoxProps): JSX.Element => {
return (
}) => (
<div class={ `border-rounded ${ error ? "border-red-500" : "border-gray-500" } ${ className }` }>
<p class={ `border-b px-2 ${ error ? "border-red-500" : "border-gray-500" }` }>{ title }</p>
<div class={ "mx-2" }>{ children }</div>
</div>
);
}
);
interface MyDisclosureProps extends TitleProps {
defaultOpen?: boolean,
@ -36,8 +35,7 @@ export const MyDisclosure: Component<MyDisclosureProps> = (
className,
id,
onClick
}): JSX.Element => {
return (
}): JSX.Element => (
<div id={ id } class={ `border-rounded bg-default-bg ${ className }` }>
<Disclosure defaultOpen={ defaultOpen }>
{ ({ isOpen }) =>
@ -45,7 +43,8 @@ export const MyDisclosure: Component<MyDisclosureProps> = (
<DisclosureButton onClick={ onClick }
class={ `flex-row-center w-full justify-between px-2` }>
<p class={ `py-1` }>{ title }</p>
<Icon path={ chevronUp } class={ `w-5 ${ isOpen() && "transform rotate-180" } transition` } />
<Icon path={ chevronUp }
class={ `w-5 ${ isOpen() && "transform rotate-180" } transition` } />
</DisclosureButton>
<Transition
enter="transition duration-100 ease-out"
@ -62,14 +61,15 @@ export const MyDisclosure: Component<MyDisclosureProps> = (
}
</Disclosure>
</div>
);
}
);
export const MyDisclosureContainer: Component<ChildProps> = ({ children, className }): JSX.Element => {
return (
export const MyDisclosureContainer: Component<ChildProps> = (
{
children,
className
}) => (
<div class={ `bg-cyan-900 border-rounded dark:border-gray-800 p-2 mb-2
flex flex-col gap-1 ${ className }` }>
{ children }
</div>
);
}
);

View File

@ -2,8 +2,14 @@
import { type Component } from "solid-js";
import type { ChildProps } from "../types/types";
const Row: Component<ChildProps> = ({ children, className }) => {
return <div class={ `flex-row-center ${ className }` }>{ children }</div>
}
/**
* A row that centers its children
* @param children The children of the row
* @param className The class name of the row
* @returns The row
*/
const Row: Component<ChildProps> = ({ children, className }) => (
<div class={ `flex-row-center ${ className }` }>{ children }</div>
);
export default Row;

View File

@ -16,11 +16,8 @@ const TruthTable: Component<TruthTableProps> = (
className,
style,
id,
}) => {
return (
<table class={ `border-2 border-gray-500 border-collapse table z-10 ${ className }` } id={ id }
style={ style }>
}) => (
<table class={ `border-2 border-gray-500 border-collapse table z-10 ${ className }` } id={ id } style={ style }>
<thead>
<tr>
<For each={ header }>
@ -51,7 +48,6 @@ const TruthTable: Component<TruthTableProps> = (
</For>
</tbody>
</table>
);
}
);
export default TruthTable;

View File

@ -1,6 +1,6 @@
/* @refresh reload */
import Layout from "./components/layout";
import { Input } from "./components/input";
import { Input, Search } from "./components/input";
import { Icon } from "solid-heroicons";
import TruthTable from "./components/truth-table";
import { InfoBox, MyDisclosure, MyDisclosureContainer } from "./components/output";
@ -15,15 +15,15 @@ import {
check,
eye,
eyeSlash,
funnel,
magnifyingGlass,
xMark
funnel
} from "solid-heroicons/solid";
import { Button, MySwitch } from "./components/button";
import MyDialog from "./components/dialog";
import { exportToExcel } from "./functions/export";
import { exportToExcel } from "./utils/export";
import { Link } from "./components/link";
import { isTouch } from "./functions/touch";
import { isTouch } from "./utils/touch";
import { replaceOperators } from "./utils/expressionUtils";
import { getElementById } from "./utils/dom";
type Option = { name: string, value: "NONE" | "TRUE" | "FALSE" | "DEFAULT" | "TRUE_FIRST" | "FALSE_FIRST" };
@ -60,10 +60,6 @@ const TruthTablePage: Component = () => {
* The state element used to store the simplified string, "empty string" by default
*/
const [fetchResult, setFetchResult] = createSignal<FetchResult | null>(null);
/**
* If the searchbar is empty, this state is 'false', otherwise 'true'
*/
const [typing, setTyping] = createSignal(inputContent);
const hideOptions: Option[] = [
{ name: "Show all result", value: "NONE" },
@ -98,7 +94,7 @@ const TruthTablePage: Component = () => {
let exp = getInputElement()?.value;
if (exp) {
exp = exp.replaceAll("|", ":").trimEnd();
exp = replaceOperators(exp);
history.pushState(null, "", `?exp=${ encodeURIComponent(exp) }&simplify=${ simplifyEnabled() }&
hide=${ hideValues().value }&sort=${ sortValues().value }&hideIntermediate=${ hideIntermediates() }`);
@ -107,10 +103,10 @@ hide=${ hideValues().value }&sort=${ sortValues().value }&hideIntermediate=${ hi
}
}
function getFetchResult(exp: string): void {
function getFetchResult(exp: string | null): void {
setFetchResult(null);
if (exp !== "") {
if (exp && exp !== "") {
setError(null);
setIsLoaded(false);
@ -132,34 +128,17 @@ hideIntermediate=${ hideIntermediates() }`)
const inputId = "truth-input";
function getInputElement(): HTMLInputElement | null {
return document.getElementById(inputId) as HTMLInputElement | null;
return getElementById(inputId);
}
function onTyping(): void {
const el = getInputElement();
if (el && (el.value !== "") !== typing()) {
setTyping(el.value !== "");
}
}
function clearSearch(): void {
const el = getInputElement();
if (el) {
el.value = "";
setTyping(false);
history.replaceState(null, "", location.pathname);
el.focus();
}
}
const tableId = "truth-table";
const filenameId = "excel-filename";
onMount((): void => {
const inputElement = getInputElement();
if (searchParams.has("exp")) {
const exp = searchParams.get("exp");
if (exp !== "") {
getInputElement().value = exp;
if (exp && inputElement) {
inputElement.value = exp;
}
const hide = searchParams.get("hide");
if (hide) {
@ -175,12 +154,15 @@ hideIntermediate=${ hideIntermediates() }`)
// Focuses searchbar on load
if (!isTouch()) {
getInputElement()?.focus();
inputElement?.focus();
}
});
const tableId = "truth-table";
const filenameId = "excel-filename";
function _exportToExcel(): void {
const value = (document.getElementById(filenameId) as HTMLInputElement | null)?.value;
const value = getElementById<HTMLInputElement>(filenameId)?.value;
exportToExcel({
name: value !== "" ? value : undefined, tableId
});
@ -197,40 +179,12 @@ hideIntermediate=${ hideIntermediates() }`)
<div id={ "truth-content" }>
<div class={ "max-w-2xl mx-auto" }>
<MyDisclosureContainer>
<MyDisclosure title={ "How to" }>
<p>Fill in a truth expression and it will be simplified for you as much as possible.
It will also genereate a truth table with all possible values. You can use a single
letter,
word or multiple words without spacing for each atomic value.
If you do not want to simplify the expression, simply turn off the toggle.
Keywords for operators are defined below. Parentheses is also allowed.</p>
<p>API docs can be found <Link to={ "https://api.martials.no/simplify-truths" }>here</Link>.
</p>
</MyDisclosure>
<KeywordsDisclosure />
</MyDisclosureContainer>
<HowTo />
<form class={ "flex-row-center" } onSubmit={ onClick } autocomplete={ "off" }>
<Input inputClass={ `rounded-xl pl-7 h-10 w-full pr-8` } className={ "w-full" }
id={ "truth-input" }
placeholder={ "¬A & B -> C" }
type={ "text" }
onChange={ onTyping }
leading={ <Icon path={ magnifyingGlass } aria-label={ "Magnifying glass" }
class={ "pl-2 absolute" } /> }
trailing={ <Show when={ typing() } keyed>
<button class={ "absolute right-2" }
title={ "Clear" }
type={ "reset" }
onClick={ clearSearch }>
<Icon path={ xMark } aria-label={ "The letter X" } />
</button>
</Show> }
/>
<Search id={ inputId } typingDefault={ inputContent } />
<Button id={ "truth-input-button" }
title={ "Generate (Enter)" }
@ -292,7 +246,7 @@ hideIntermediate=${ hideIntermediates() }`)
onChange={ setHideIntermediates }
defaultValue={ hideIntermediates() } />
<Show when={ isLoaded() } keyed>
<Show when={ isLoaded() && error() === null } keyed>
<MyDialog title={ "Download" }
description={ "Export current table (.xlsx)" }
@ -303,7 +257,7 @@ hideIntermediate=${ hideIntermediates() }`)
callback={ _exportToExcel }
acceptButtonName={ "Download" }
cancelButtonName={ "Cancel" }
buttonClasses={ `float-right` }
buttonClass={ `float-right` }
buttonTitle={ "Export current table" }
acceptButtonId={ "download-accept" }>
<p>{ "Filename" }:</p>
@ -320,11 +274,11 @@ hideIntermediate=${ hideIntermediates() }`)
</Show>
<Show when={ error() && isLoaded() } keyed>
<ErrorBox title={ error().title ?? "Error" }
error={ error().message ?? "Something went wrong" } />
<ErrorBox title={ error()?.title ?? "Error" }
error={ error()?.message ?? "Something went wrong" } />
</Show>
<Show when={ simplifyEnabled() && fetchResult()?.orderOperations?.length > 0 } keyed>
<Show when={ simplifyEnabled() && (fetchResult()?.orderOperations?.length ?? 0) > 0 } keyed>
<ShowMeHow fetchResult={ fetchResult } />
</Show>
@ -341,7 +295,7 @@ hideIntermediate=${ hideIntermediates() }`)
<div class={ "flex justify-center m-2" }>
<div id={ "table" } class={ "h-[45rem] overflow-auto" }>
<TruthTable header={ fetchResult()?.header }
<TruthTable header={ fetchResult()?.header ?? undefined }
table={ fetchResult()?.table?.truthMatrix } id={ tableId } />
</div>
@ -362,8 +316,13 @@ interface SingleMenuItem {
onClick: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>,
}
const SingleMenuItem: Component<SingleMenuItem> = ({ option, currentValue, onClick }) => {
const isSelected = () => currentValue()?.value === option.value;
const SingleMenuItem: Component<SingleMenuItem> = (
{
option,
currentValue,
onClick
}) => {
const isSelected = () => currentValue && currentValue().value === option.value;
return (
<button class={ `hover:underline cursor-pointer last:mb-1 flex-row-center` }
onClick={ onClick }>
@ -374,22 +333,19 @@ const SingleMenuItem: Component<SingleMenuItem> = ({ option, currentValue, onCli
);
}
const ErrorBox: Component<{ title: string, error: string }> = ({ title, error }) => {
return (
const ErrorBox: Component<{ title: string, error: string }> = ({ title, error }) => (
<InfoBox className={ "w-fit text-center mx-auto" }
title={ title }
error={ true }>
<p>{ error }</p>
</InfoBox>
)
}
);
interface ShowMeHowProps {
fetchResult: Accessor<FetchResult>,
fetchResult: Accessor<FetchResult | null>,
}
const ShowMeHow: Component<ShowMeHowProps> = ({ fetchResult }) => {
return (
const ShowMeHow: Component<ShowMeHowProps> = ({ fetchResult }) => (
<MyDisclosureContainer>
<MyDisclosure title={ "Show me how it's done" }>
<table class={ "table" }>
@ -410,16 +366,12 @@ const ShowMeHow: Component<ShowMeHowProps> = ({ fetchResult }) => {
</span>) }
</For> }
<Show
when={ typeof window !== "undefined" && window.outerWidth <= 640 }
keyed>
<Show when={ typeof window !== "undefined" && window.outerWidth <= 640 } keyed>
<p>{ "using" }: { operation.law }</p>
</Show>
</td>
<Show
when={ typeof window !== "undefined" && window.outerWidth > 640 }
keyed>
<Show when={ typeof window !== "undefined" && window.outerWidth > 640 } keyed>
<td>{ "using" }: { operation.law }</td>
</Show>
</tr>
@ -430,35 +382,63 @@ const ShowMeHow: Component<ShowMeHowProps> = ({ fetchResult }) => {
</table>
</MyDisclosure>
</MyDisclosureContainer>
)
}
);
const KeywordsDisclosure = () => {
return (
const HowTo: Component = () => (
<MyDisclosureContainer>
<MyDisclosure title={ "How to" }>
<p>Fill in a truth expression and it will be simplified for you as much as possible.
It will also genereate a truth table with all possible values. You can use a single
letter,
word or multiple words without spacing for each atomic value.
If you do not want to simplify the expression, simply turn off the toggle.
Keywords for operators are defined below. Parentheses is also allowed.</p>
<p>API docs can be found <Link to={ "https://api.martials.no/simplify-truths" }>here</Link>.
</p>
</MyDisclosure>
<KeywordsDisclosure />
</MyDisclosureContainer>
);
const KeywordsDisclosure: Component = () => (
<MyDisclosure title={ "Keywords" }>
<table>
<thead>
<tr class={ "text-left" }>
<th>Name</th>
<th class={ "pr-2" }>API</th>
<th>Other</th>
</tr>
</thead>
<tbody>
<tr>
<td>Not:</td>
<td>!</td>
<td>NOT</td>
</tr>
<tr>
<td>And:</td>
<td>&</td>
<td>AND</td>
</tr>
<tr>
<td>Or:</td>
<td>:</td>
<td>|</td>
<td>/</td>
<td>OR</td>
</tr>
<tr>
<td class={ "pr-2" }>Implication:</td>
<td>{ "->" }</td>
<td class={ "px-2" }>IMPLICATION</td>
<td>IMP</td>
</tr>
</tbody>
</table>
</MyDisclosure>
);
};
);
render(() => <TruthTablePage />, document.getElementById("root") as HTMLElement);

View File

@ -29,7 +29,7 @@ interface ButtonProps extends TitleProps {
interface InputProps<T> extends TitleProps {
onInput?: JSX.EventHandlerUnion<T, Event>,
placeholder?: string | null,
placeholder?: string,
required?: boolean,
type?: string,
}

9
src/utils/dom.ts Normal file
View File

@ -0,0 +1,9 @@
/**
* Get an element by id
* @param id The id of the element
* @type T The type of the HTMLElement
* @returns The element with the given id, or null if it doesn't exist
*/
export function getElementById<T extends HTMLElement = HTMLElement>(id: string): T | null {
return document.getElementById(id) as T | null;
}

View File

@ -0,0 +1,16 @@
/**
* Replaces the operators in the expression with the ones used by the backend
* @param expression The expression to replace the operators in
* @returns The expression with the replaced operators
*/
export function replaceOperators(expression: string): string {
expression = expression.replaceAll(/[|/]/g, ":");
expression = expression.replaceAll(/¬/g, "!");
expression = expression.replaceAll(/\sOR\s/gi, " : ");
expression = expression.replaceAll(/\sAND\s/gi, " & ");
expression = expression.replaceAll(/\s(IMPLICATION|IMP)\s/gi, " -> ");
expression = expression.replaceAll(/\sNOT\s/gi, " !");
return expression;
}

View File

@ -9,6 +9,7 @@
"jsxImportSource": "solid-js",
"types": ["vite/client"],
"noEmit": true,
"isolatedModules": true
"isolatedModules": true,
"strict": true
}
}