Set ts compiler to strict, refactored a bit
This commit is contained in:
parent
292da46769
commit
7f6c405890
@ -49,13 +49,10 @@ export const Button: Component<ButtonProps> = (
|
|||||||
onClick,
|
onClick,
|
||||||
type = "button",
|
type = "button",
|
||||||
}
|
}
|
||||||
) => {
|
) => (
|
||||||
return (
|
<button title={ title } id={ id } type={ type }
|
||||||
<button title={ title } id={ id } type={ type }
|
class={ `border-rounded bg-cyan-900 px-2 cursor-pointer ${ className }` }
|
||||||
class={ `border-rounded bg-cyan-900 px-2 cursor-pointer ${ className }` }
|
onClick={ onClick }>
|
||||||
onClick={ onClick }>
|
{ children }
|
||||||
{ children }
|
</button>
|
||||||
</button>
|
);
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@ -3,21 +3,22 @@ import { type Component } from "solid-js";
|
|||||||
import type { CardProps } from "../types/types";
|
import type { CardProps } from "../types/types";
|
||||||
import { Link } from "./link";
|
import { Link } from "./link";
|
||||||
|
|
||||||
const Card: Component<CardProps> = ({ children, className, title, to, newTab = false }) => {
|
const Card: Component<CardProps> = (
|
||||||
return (
|
{
|
||||||
<>
|
children,
|
||||||
<div
|
className,
|
||||||
class={ `relative bg-gradient-to-r from-cyan-600 to-cyan-500 h-32 w-72 rounded-2xl ${ className }` }>
|
title,
|
||||||
<div class="relative p-5">
|
to,
|
||||||
<Link className={ "text-white" } to={ to } newTab={ newTab }>
|
newTab = false
|
||||||
<h3 class={ "text-center w-fit mx-auto before:content-['↗']" }>{ title }</h3>
|
}) => (
|
||||||
</Link>
|
<div class={ `relative bg-gradient-to-r from-cyan-600 to-cyan-500 h-32 w-72 rounded-2xl ${ className }` }>
|
||||||
{ children }
|
<div class={ "relative p-5" }>
|
||||||
</div>
|
<Link className={ "text-white" } to={ to } newTab={ newTab }>
|
||||||
</div>
|
<h3 class={ "text-center w-fit mx-auto before:content-['↗']" }>{ title }</h3>
|
||||||
|
</Link>
|
||||||
</>
|
{ children }
|
||||||
);
|
</div>
|
||||||
};
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
export default Card;
|
export default Card;
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
/* @refresh reload */
|
/* @refresh reload */
|
||||||
import { Dialog, DialogDescription, DialogPanel, DialogTitle } from "solid-headless";
|
import { Dialog, DialogDescription, DialogPanel, DialogTitle } from "solid-headless";
|
||||||
import type { TitleProps } from "../types/types";
|
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 { Button } from "./button";
|
||||||
import { Portal } from "solid-js/web";
|
import { Portal } from "solid-js/web";
|
||||||
|
import { getElementById } from "../utils/dom";
|
||||||
|
|
||||||
interface MyDialog extends TitleProps {
|
interface MyDialog extends TitleProps {
|
||||||
description?: string,
|
description?: string,
|
||||||
button?: JSX.Element,
|
button?: JSX.Element,
|
||||||
acceptButtonName?: string | null,
|
acceptButtonName?: string,
|
||||||
acceptButtonId?: string,
|
acceptButtonId?: string,
|
||||||
cancelButtonName?: string | null,
|
cancelButtonName?: string,
|
||||||
callback?: () => void,
|
callback?: () => void,
|
||||||
buttonClasses?: string,
|
buttonClass?: string,
|
||||||
buttonTitle?: string | null,
|
buttonTitle?: string | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MyDialog(
|
const MyDialog: Component<MyDialog> = (
|
||||||
{
|
{
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
@ -26,10 +27,10 @@ export default function MyDialog(
|
|||||||
children,
|
children,
|
||||||
callback,
|
callback,
|
||||||
className,
|
className,
|
||||||
buttonClasses,
|
buttonClass,
|
||||||
buttonTitle,
|
buttonTitle,
|
||||||
acceptButtonId,
|
acceptButtonId,
|
||||||
}: MyDialog): JSX.Element {
|
}) => {
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = createSignal(false);
|
const [isOpen, setIsOpen] = createSignal(false);
|
||||||
|
|
||||||
@ -48,20 +49,21 @@ export default function MyDialog(
|
|||||||
* @param e KeyboardEvent of keypress
|
* @param e KeyboardEvent of keypress
|
||||||
*/
|
*/
|
||||||
function click(e: KeyboardEvent): void {
|
function click(e: KeyboardEvent): void {
|
||||||
if (isMounted && e.key === "Enter") {
|
if (isMounted && e.key === "Enter" && acceptButtonId) {
|
||||||
(document.getElementById(acceptButtonId ?? "") as HTMLButtonElement | null)?.click();
|
getElementById<HTMLButtonElement>(acceptButtonId)?.click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOpen()) {
|
if (isOpen()) {
|
||||||
const id = "cl-6"
|
const id = "cl-6"
|
||||||
const el = document.getElementById(id);
|
const el = getElementById(id);
|
||||||
el?.addEventListener("keypress", e => click(e));
|
el?.addEventListener("keypress", click);
|
||||||
return () => {
|
return () => {
|
||||||
el?.removeEventListener("keypress", e => click(e));
|
el?.removeEventListener("keypress", click);
|
||||||
isMounted = false;
|
isMounted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else return () => undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(setupKeyPress, isOpen());
|
createEffect(setupKeyPress, isOpen());
|
||||||
@ -69,7 +71,7 @@ export default function MyDialog(
|
|||||||
return (
|
return (
|
||||||
<div class={ "w-fit h-fit" }>
|
<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 }
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@ -99,3 +101,5 @@ export default function MyDialog(
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default MyDialog;
|
||||||
|
@ -3,12 +3,10 @@ import { type Component } from "solid-js";
|
|||||||
import type { SimpleProps } from "../types/types";
|
import type { SimpleProps } from "../types/types";
|
||||||
import { Link } from "./link";
|
import { Link } from "./link";
|
||||||
|
|
||||||
const Footer: Component<SimpleProps> = ({ className }) => {
|
const Footer: Component<SimpleProps> = ({ className }) => (
|
||||||
return (
|
<footer class={ `text-center py-5 absolute bottom-0 container ${ className }` }>
|
||||||
<footer class={ `text-center py-5 absolute bottom-0 container ${ className }` }>
|
<p>Kildekode på <Link to={ "https://github.com/h600878/martials.no" }>GitHub</Link></p>
|
||||||
<p>Kildekode på <Link to={ "https://github.com/h600878/martials.no" }>GitHub</Link></p>
|
</footer>
|
||||||
</footer>
|
);
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Footer;
|
export default Footer;
|
||||||
|
@ -5,24 +5,22 @@ import { Icon } from "solid-heroicons";
|
|||||||
import { chevronLeft } from "solid-heroicons/solid";
|
import { chevronLeft } from "solid-heroicons/solid";
|
||||||
import { Link } from "./link";
|
import { Link } from "./link";
|
||||||
|
|
||||||
const Header: Component<TitleProps> = ({ className, title }) => {
|
const Header: Component<TitleProps> = ({ className, title = "Title goes here" }) => (
|
||||||
return (
|
<header class={ className }>
|
||||||
<header class={ className }>
|
<div class={ "flex-row-center mx-auto w-fit" }>
|
||||||
<div class={ "flex-row-center mx-auto w-fit" }>
|
|
||||||
|
|
||||||
<Show when={ typeof location !== "undefined" && location.pathname !== "/" } keyed>
|
<Show when={ typeof location !== "undefined" && location.pathname !== "/" } keyed>
|
||||||
<Link to={ "/" } newTab={ false } title={ "Back to homepage" }>
|
<Link to={ "/" } newTab={ false } title={ "Back to homepage" }>
|
||||||
<Icon path={ chevronLeft } class={ "text-cyan-500" } />
|
<Icon path={ chevronLeft } class={ "text-cyan-500" } />
|
||||||
</Link>
|
</Link>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<h1 class={ "text-center text-cyan-500" }>{ title }</h1>
|
<h1 class={ "text-center text-cyan-500" }>{ title }</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class={ "mx-auto w-fit" }>
|
<div class={ "mx-auto w-fit" }>
|
||||||
<p>Av Martin Berg Alstad</p>
|
<p>Av Martin Berg Alstad</p>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
/* @refresh reload */
|
/* @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 type { InputProps } from "../types/types";
|
||||||
import Row from "./row";
|
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 {
|
function setupEventListener(id: string, setIsHover: Setter<boolean>): () => void {
|
||||||
let isMounted = true;
|
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("pointerenter", () => hover(true));
|
||||||
el?.addEventListener("pointerleave", () => hover(false));
|
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 {
|
function setSetIsText(id: string | undefined, isText: boolean, setIsText: Setter<boolean>): void {
|
||||||
if (id) {
|
if (id) {
|
||||||
const el = document.getElementById(id) as HTMLInputElement | HTMLTextAreaElement | null;
|
const el = getElementById<HTMLInputElement | HTMLTextAreaElement>(id);
|
||||||
if (el && el.value !== "" !== isText) {
|
if (el && el.value !== "" !== isText) {
|
||||||
setIsText(el.value !== "");
|
setIsText(el.value !== "");
|
||||||
}
|
}
|
||||||
@ -43,7 +46,7 @@ interface Input<T> extends InputProps<T> {
|
|||||||
inputClass?: string,
|
inputClass?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Input: Component<Input<HTMLInputElement>> = (
|
export const Input: Component<Input<HTMLInputElement>> = ( // TODO remove leading and trailing from component
|
||||||
{
|
{
|
||||||
className,
|
className,
|
||||||
id,
|
id,
|
||||||
@ -71,7 +74,7 @@ export const Input: Component<Input<HTMLInputElement>> = (
|
|||||||
*/
|
*/
|
||||||
const [isText, setIsText] = createSignal(false);
|
const [isText, setIsText] = createSignal(false);
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
onMount(() => {
|
||||||
if (id && title) {
|
if (id && title) {
|
||||||
setupEventListener(id, setIsHover);
|
setupEventListener(id, setIsHover);
|
||||||
}
|
}
|
||||||
@ -102,19 +105,71 @@ export const Input: Component<Input<HTMLInputElement>> = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function HoverTitle(
|
const HoverTitle: Component<{ title?: string, isActive?: boolean, htmlFor?: string }> = (
|
||||||
{
|
{
|
||||||
title,
|
title,
|
||||||
isActive = false,
|
isActive = false,
|
||||||
htmlFor
|
htmlFor
|
||||||
}: { title?: string | null, isActive?: boolean, htmlFor?: string }): JSX.Element {
|
}) => (
|
||||||
return (
|
<label class={ `absolute pointer-events-none
|
||||||
<label class={ `absolute pointer-events-none
|
|
||||||
${ isActive ? "-top-2 left-3 default-bg text-sm" : "left-2 top-1" }
|
${ isActive ? "-top-2 left-3 default-bg text-sm" : "left-2 top-1" }
|
||||||
transition-all duration-150 text-gray-600 dark:text-gray-400` }
|
transition-all duration-150 text-gray-600 dark:text-gray-400` }
|
||||||
for={ htmlFor }>
|
for={ htmlFor }>
|
||||||
<div class={ "z-50 relative" }>{ title }</div>
|
<div class={ "z-50 relative" }>{ title }</div>
|
||||||
<div class={ "w-full h-2 default-bg absolute bottom-1/3 z-10" } />
|
<div class={ "w-full h-2 default-bg absolute bottom-1/3 z-10" } />
|
||||||
</label>
|
</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> }
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,21 @@ import type { TitleProps } from "../types/types";
|
|||||||
import Header from "./header";
|
import Header from "./header";
|
||||||
import Footer from "./footer";
|
import Footer from "./footer";
|
||||||
|
|
||||||
const Layout: Component<TitleProps> = ({ children, title, className }) => {
|
const Layout: Component<TitleProps> = (
|
||||||
return (
|
{
|
||||||
<div class={ `bg-default-bg text-white min-h-screen relative font-mono ${ className }` }>
|
children,
|
||||||
<div class="container mx-auto">
|
title,
|
||||||
<Header className={ "py-3" } title={ title } />
|
className
|
||||||
<main>
|
}) => (
|
||||||
<div class={ "pb-28" }>{ children }</div>
|
<div class={ `bg-default-bg text-white min-h-screen relative font-mono ${ className }` }>
|
||||||
<Footer />
|
<div class="container mx-auto">
|
||||||
</main>
|
<Header className={ "py-3" } title={ title } />
|
||||||
</div>
|
<main>
|
||||||
|
<div class={ "pb-28" }>{ children }</div>
|
||||||
|
<Footer />
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
};
|
);
|
||||||
|
|
||||||
export default Layout;
|
export default Layout;
|
||||||
|
@ -11,14 +11,11 @@ export const Link: Component<LinkProps> = (
|
|||||||
id,
|
id,
|
||||||
newTab = true,
|
newTab = true,
|
||||||
title,
|
title,
|
||||||
}) => {
|
}) => (
|
||||||
return (
|
<a href={ to } id={ id } title={ title }
|
||||||
<a href={ to } id={ id } title={ title }
|
rel={ `${ rel } ${ newTab ? "noreferrer" : undefined }` }
|
||||||
rel={ `${ rel } ${ newTab ? "noreferrer" : undefined }` }
|
target={ newTab ? "_blank" : undefined }
|
||||||
target={ newTab ? "_blank" : undefined }
|
class={ `link ${ className }` }>
|
||||||
class={ `link ${ className }` }>
|
{ children }
|
||||||
{ children }
|
</a>
|
||||||
</a>
|
);
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
/* @refresh reload */
|
||||||
import { Disclosure, DisclosureButton, DisclosurePanel, Transition } from "solid-headless";
|
import { Disclosure, DisclosureButton, DisclosurePanel, Transition } from "solid-headless";
|
||||||
import { Icon } from "solid-heroicons";
|
import { Icon } from "solid-heroicons";
|
||||||
import type { ChildProps, TitleProps } from "../types/types";
|
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";
|
import { chevronUp } from "solid-heroicons/solid";
|
||||||
|
|
||||||
interface InfoBoxProps extends TitleProps {
|
interface InfoBoxProps extends TitleProps {
|
||||||
@ -10,18 +11,16 @@ interface InfoBoxProps extends TitleProps {
|
|||||||
|
|
||||||
export const InfoBox: Component<InfoBoxProps> = (
|
export const InfoBox: Component<InfoBoxProps> = (
|
||||||
{
|
{
|
||||||
title = "",
|
title,
|
||||||
children,
|
children,
|
||||||
error = false,
|
error = false,
|
||||||
className
|
className
|
||||||
}: InfoBoxProps): JSX.Element => {
|
}) => (
|
||||||
return (
|
<div class={ `border-rounded ${ error ? "border-red-500" : "border-gray-500" } ${ className }` }>
|
||||||
<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>
|
||||||
<p class={ `border-b px-2 ${ error ? "border-red-500" : "border-gray-500" }` }>{ title }</p>
|
<div class={ "mx-2" }>{ children }</div>
|
||||||
<div class={ "mx-2" }>{ children }</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MyDisclosureProps extends TitleProps {
|
interface MyDisclosureProps extends TitleProps {
|
||||||
defaultOpen?: boolean,
|
defaultOpen?: boolean,
|
||||||
@ -36,40 +35,41 @@ export const MyDisclosure: Component<MyDisclosureProps> = (
|
|||||||
className,
|
className,
|
||||||
id,
|
id,
|
||||||
onClick
|
onClick
|
||||||
}): JSX.Element => {
|
}): JSX.Element => (
|
||||||
return (
|
<div id={ id } class={ `border-rounded bg-default-bg ${ className }` }>
|
||||||
<div id={ id } class={ `border-rounded bg-default-bg ${ className }` }>
|
<Disclosure defaultOpen={ defaultOpen }>
|
||||||
<Disclosure defaultOpen={ defaultOpen }>
|
{ ({ isOpen }) =>
|
||||||
{ ({ isOpen }) =>
|
<>
|
||||||
<>
|
<DisclosureButton onClick={ onClick }
|
||||||
<DisclosureButton onClick={ onClick }
|
class={ `flex-row-center w-full justify-between px-2` }>
|
||||||
class={ `flex-row-center w-full justify-between px-2` }>
|
<p class={ `py-1` }>{ title }</p>
|
||||||
<p class={ `py-1` }>{ title }</p>
|
<Icon path={ chevronUp }
|
||||||
<Icon path={ chevronUp } class={ `w-5 ${ isOpen() && "transform rotate-180" } transition` } />
|
class={ `w-5 ${ isOpen() && "transform rotate-180" } transition` } />
|
||||||
</DisclosureButton>
|
</DisclosureButton>
|
||||||
<Transition
|
<Transition
|
||||||
enter="transition duration-100 ease-out"
|
enter="transition duration-100 ease-out"
|
||||||
enterFrom="transform scale-95 opacity-0"
|
enterFrom="transform scale-95 opacity-0"
|
||||||
enterTo="transform scale-100 opacity-100"
|
enterTo="transform scale-100 opacity-100"
|
||||||
leave="transition duration-75 ease-out"
|
leave="transition duration-75 ease-out"
|
||||||
leaveFrom="transform scale-100 opacity-100"
|
leaveFrom="transform scale-100 opacity-100"
|
||||||
leaveTo="transform scale-95 opacity-0" show>
|
leaveTo="transform scale-95 opacity-0" show>
|
||||||
<DisclosurePanel>
|
<DisclosurePanel>
|
||||||
<div class={ "px-2 pb-2 text-gray-300" }>{ children }</div>
|
<div class={ "px-2 pb-2 text-gray-300" }>{ children }</div>
|
||||||
</DisclosurePanel>
|
</DisclosurePanel>
|
||||||
</Transition>
|
</Transition>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
</Disclosure>
|
</Disclosure>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
export const MyDisclosureContainer: Component<ChildProps> = ({ children, className }): JSX.Element => {
|
export const MyDisclosureContainer: Component<ChildProps> = (
|
||||||
return (
|
{
|
||||||
<div class={ `bg-cyan-900 border-rounded dark:border-gray-800 p-2 mb-2
|
children,
|
||||||
|
className
|
||||||
|
}) => (
|
||||||
|
<div class={ `bg-cyan-900 border-rounded dark:border-gray-800 p-2 mb-2
|
||||||
flex flex-col gap-1 ${ className }` }>
|
flex flex-col gap-1 ${ className }` }>
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
@ -2,8 +2,14 @@
|
|||||||
import { type Component } from "solid-js";
|
import { type Component } from "solid-js";
|
||||||
import type { ChildProps } from "../types/types";
|
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;
|
export default Row;
|
||||||
|
@ -16,42 +16,38 @@ const TruthTable: Component<TruthTableProps> = (
|
|||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
id,
|
id,
|
||||||
}) => {
|
}) => (
|
||||||
|
<table class={ `border-2 border-gray-500 border-collapse table z-10 ${ className }` } id={ id } style={ style }>
|
||||||
return (
|
<thead>
|
||||||
<table class={ `border-2 border-gray-500 border-collapse table z-10 ${ className }` } id={ id }
|
<tr>
|
||||||
style={ style }>
|
<For each={ header }>
|
||||||
<thead>
|
{ (exp) => (
|
||||||
<tr>
|
<th scope={ "col" }
|
||||||
<For each={ header }>
|
class={ `bg-default-bg text-center sticky top-0 [position:-webkit-sticky;]
|
||||||
{ (exp) => (
|
|
||||||
<th scope={ "col" }
|
|
||||||
class={ `bg-default-bg text-center sticky top-0 [position:-webkit-sticky;]
|
|
||||||
outline outline-2 outline-offset-[-1px] outline-gray-500` /*TODO sticky header at the top of the screen */ }>
|
outline outline-2 outline-offset-[-1px] outline-gray-500` /*TODO sticky header at the top of the screen */ }>
|
||||||
<p class={ "px-2 w-max" }>{ exp }</p>
|
<p class={ "px-2 w-max" }>{ exp }</p>
|
||||||
</th>
|
</th>
|
||||||
) }
|
) }
|
||||||
</For>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<For each={ table }>
|
|
||||||
{ (row) =>
|
|
||||||
<tr class={ "hover:text-black" }>
|
|
||||||
<For each={ row }>
|
|
||||||
{ (value) =>
|
|
||||||
<td class={ `text-center border border-gray-500 last:underline
|
|
||||||
${ value ? "bg-green-700" : "bg-red-700" }` }>
|
|
||||||
<p>{ value ? "T" : "F" }</p>
|
|
||||||
</td>
|
|
||||||
}
|
|
||||||
</For>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</For>
|
</For>
|
||||||
</tbody>
|
</tr>
|
||||||
</table>
|
</thead>
|
||||||
);
|
<tbody>
|
||||||
}
|
<For each={ table }>
|
||||||
|
{ (row) =>
|
||||||
|
<tr class={ "hover:text-black" }>
|
||||||
|
<For each={ row }>
|
||||||
|
{ (value) =>
|
||||||
|
<td class={ `text-center border border-gray-500 last:underline
|
||||||
|
${ value ? "bg-green-700" : "bg-red-700" }` }>
|
||||||
|
<p>{ value ? "T" : "F" }</p>
|
||||||
|
</td>
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
|
||||||
export default TruthTable;
|
export default TruthTable;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* @refresh reload */
|
/* @refresh reload */
|
||||||
import Layout from "./components/layout";
|
import Layout from "./components/layout";
|
||||||
import { Input } from "./components/input";
|
import { Input, Search } from "./components/input";
|
||||||
import { Icon } from "solid-heroicons";
|
import { Icon } from "solid-heroicons";
|
||||||
import TruthTable from "./components/truth-table";
|
import TruthTable from "./components/truth-table";
|
||||||
import { InfoBox, MyDisclosure, MyDisclosureContainer } from "./components/output";
|
import { InfoBox, MyDisclosure, MyDisclosureContainer } from "./components/output";
|
||||||
@ -15,15 +15,15 @@ import {
|
|||||||
check,
|
check,
|
||||||
eye,
|
eye,
|
||||||
eyeSlash,
|
eyeSlash,
|
||||||
funnel,
|
funnel
|
||||||
magnifyingGlass,
|
|
||||||
xMark
|
|
||||||
} from "solid-heroicons/solid";
|
} from "solid-heroicons/solid";
|
||||||
import { Button, MySwitch } from "./components/button";
|
import { Button, MySwitch } from "./components/button";
|
||||||
import MyDialog from "./components/dialog";
|
import MyDialog from "./components/dialog";
|
||||||
import { exportToExcel } from "./functions/export";
|
import { exportToExcel } from "./utils/export";
|
||||||
import { Link } from "./components/link";
|
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" };
|
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
|
* The state element used to store the simplified string, "empty string" by default
|
||||||
*/
|
*/
|
||||||
const [fetchResult, setFetchResult] = createSignal<FetchResult | null>(null);
|
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[] = [
|
const hideOptions: Option[] = [
|
||||||
{ name: "Show all result", value: "NONE" },
|
{ name: "Show all result", value: "NONE" },
|
||||||
@ -98,7 +94,7 @@ const TruthTablePage: Component = () => {
|
|||||||
let exp = getInputElement()?.value;
|
let exp = getInputElement()?.value;
|
||||||
|
|
||||||
if (exp) {
|
if (exp) {
|
||||||
exp = exp.replaceAll("|", ":").trimEnd();
|
exp = replaceOperators(exp);
|
||||||
|
|
||||||
history.pushState(null, "", `?exp=${ encodeURIComponent(exp) }&simplify=${ simplifyEnabled() }&
|
history.pushState(null, "", `?exp=${ encodeURIComponent(exp) }&simplify=${ simplifyEnabled() }&
|
||||||
hide=${ hideValues().value }&sort=${ sortValues().value }&hideIntermediate=${ hideIntermediates() }`);
|
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);
|
setFetchResult(null);
|
||||||
|
|
||||||
if (exp !== "") {
|
if (exp && exp !== "") {
|
||||||
setError(null);
|
setError(null);
|
||||||
setIsLoaded(false);
|
setIsLoaded(false);
|
||||||
|
|
||||||
@ -132,34 +128,17 @@ hideIntermediate=${ hideIntermediates() }`)
|
|||||||
const inputId = "truth-input";
|
const inputId = "truth-input";
|
||||||
|
|
||||||
function getInputElement(): HTMLInputElement | null {
|
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 => {
|
onMount((): void => {
|
||||||
|
|
||||||
|
const inputElement = getInputElement();
|
||||||
|
|
||||||
if (searchParams.has("exp")) {
|
if (searchParams.has("exp")) {
|
||||||
const exp = searchParams.get("exp");
|
const exp = searchParams.get("exp");
|
||||||
if (exp !== "") {
|
if (exp && inputElement) {
|
||||||
getInputElement().value = exp;
|
inputElement.value = exp;
|
||||||
}
|
}
|
||||||
const hide = searchParams.get("hide");
|
const hide = searchParams.get("hide");
|
||||||
if (hide) {
|
if (hide) {
|
||||||
@ -175,12 +154,15 @@ hideIntermediate=${ hideIntermediates() }`)
|
|||||||
|
|
||||||
// Focuses searchbar on load
|
// Focuses searchbar on load
|
||||||
if (!isTouch()) {
|
if (!isTouch()) {
|
||||||
getInputElement()?.focus();
|
inputElement?.focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tableId = "truth-table";
|
||||||
|
const filenameId = "excel-filename";
|
||||||
|
|
||||||
function _exportToExcel(): void {
|
function _exportToExcel(): void {
|
||||||
const value = (document.getElementById(filenameId) as HTMLInputElement | null)?.value;
|
const value = getElementById<HTMLInputElement>(filenameId)?.value;
|
||||||
exportToExcel({
|
exportToExcel({
|
||||||
name: value !== "" ? value : undefined, tableId
|
name: value !== "" ? value : undefined, tableId
|
||||||
});
|
});
|
||||||
@ -197,40 +179,12 @@ hideIntermediate=${ hideIntermediates() }`)
|
|||||||
|
|
||||||
<div id={ "truth-content" }>
|
<div id={ "truth-content" }>
|
||||||
<div class={ "max-w-2xl mx-auto" }>
|
<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 />
|
<HowTo />
|
||||||
|
|
||||||
</MyDisclosureContainer>
|
|
||||||
|
|
||||||
<form class={ "flex-row-center" } onSubmit={ onClick } autocomplete={ "off" }>
|
<form class={ "flex-row-center" } onSubmit={ onClick } autocomplete={ "off" }>
|
||||||
|
|
||||||
<Input inputClass={ `rounded-xl pl-7 h-10 w-full pr-8` } className={ "w-full" }
|
<Search id={ inputId } typingDefault={ inputContent } />
|
||||||
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> }
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button id={ "truth-input-button" }
|
<Button id={ "truth-input-button" }
|
||||||
title={ "Generate (Enter)" }
|
title={ "Generate (Enter)" }
|
||||||
@ -292,7 +246,7 @@ hideIntermediate=${ hideIntermediates() }`)
|
|||||||
onChange={ setHideIntermediates }
|
onChange={ setHideIntermediates }
|
||||||
defaultValue={ hideIntermediates() } />
|
defaultValue={ hideIntermediates() } />
|
||||||
|
|
||||||
<Show when={ isLoaded() } keyed>
|
<Show when={ isLoaded() && error() === null } keyed>
|
||||||
|
|
||||||
<MyDialog title={ "Download" }
|
<MyDialog title={ "Download" }
|
||||||
description={ "Export current table (.xlsx)" }
|
description={ "Export current table (.xlsx)" }
|
||||||
@ -303,7 +257,7 @@ hideIntermediate=${ hideIntermediates() }`)
|
|||||||
callback={ _exportToExcel }
|
callback={ _exportToExcel }
|
||||||
acceptButtonName={ "Download" }
|
acceptButtonName={ "Download" }
|
||||||
cancelButtonName={ "Cancel" }
|
cancelButtonName={ "Cancel" }
|
||||||
buttonClasses={ `float-right` }
|
buttonClass={ `float-right` }
|
||||||
buttonTitle={ "Export current table" }
|
buttonTitle={ "Export current table" }
|
||||||
acceptButtonId={ "download-accept" }>
|
acceptButtonId={ "download-accept" }>
|
||||||
<p>{ "Filename" }:</p>
|
<p>{ "Filename" }:</p>
|
||||||
@ -320,11 +274,11 @@ hideIntermediate=${ hideIntermediates() }`)
|
|||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={ error() && isLoaded() } keyed>
|
<Show when={ error() && isLoaded() } keyed>
|
||||||
<ErrorBox title={ error().title ?? "Error" }
|
<ErrorBox title={ error()?.title ?? "Error" }
|
||||||
error={ error().message ?? "Something went wrong" } />
|
error={ error()?.message ?? "Something went wrong" } />
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={ simplifyEnabled() && fetchResult()?.orderOperations?.length > 0 } keyed>
|
<Show when={ simplifyEnabled() && (fetchResult()?.orderOperations?.length ?? 0) > 0 } keyed>
|
||||||
<ShowMeHow fetchResult={ fetchResult } />
|
<ShowMeHow fetchResult={ fetchResult } />
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
@ -341,7 +295,7 @@ hideIntermediate=${ hideIntermediates() }`)
|
|||||||
<div class={ "flex justify-center m-2" }>
|
<div class={ "flex justify-center m-2" }>
|
||||||
<div id={ "table" } class={ "h-[45rem] overflow-auto" }>
|
<div id={ "table" } class={ "h-[45rem] overflow-auto" }>
|
||||||
|
|
||||||
<TruthTable header={ fetchResult()?.header }
|
<TruthTable header={ fetchResult()?.header ?? undefined }
|
||||||
table={ fetchResult()?.table?.truthMatrix } id={ tableId } />
|
table={ fetchResult()?.table?.truthMatrix } id={ tableId } />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -362,8 +316,13 @@ interface SingleMenuItem {
|
|||||||
onClick: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>,
|
onClick: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SingleMenuItem: Component<SingleMenuItem> = ({ option, currentValue, onClick }) => {
|
const SingleMenuItem: Component<SingleMenuItem> = (
|
||||||
const isSelected = () => currentValue()?.value === option.value;
|
{
|
||||||
|
option,
|
||||||
|
currentValue,
|
||||||
|
onClick
|
||||||
|
}) => {
|
||||||
|
const isSelected = () => currentValue && currentValue().value === option.value;
|
||||||
return (
|
return (
|
||||||
<button class={ `hover:underline cursor-pointer last:mb-1 flex-row-center` }
|
<button class={ `hover:underline cursor-pointer last:mb-1 flex-row-center` }
|
||||||
onClick={ onClick }>
|
onClick={ onClick }>
|
||||||
@ -374,91 +333,112 @@ const SingleMenuItem: Component<SingleMenuItem> = ({ option, currentValue, onCli
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrorBox: Component<{ title: string, error: string }> = ({ title, error }) => {
|
const ErrorBox: Component<{ title: string, error: string }> = ({ title, error }) => (
|
||||||
return (
|
<InfoBox className={ "w-fit text-center mx-auto" }
|
||||||
<InfoBox className={ "w-fit text-center mx-auto" }
|
title={ title }
|
||||||
title={ title }
|
error={ true }>
|
||||||
error={ true }>
|
<p>{ error }</p>
|
||||||
<p>{ error }</p>
|
</InfoBox>
|
||||||
</InfoBox>
|
);
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ShowMeHowProps {
|
interface ShowMeHowProps {
|
||||||
fetchResult: Accessor<FetchResult>,
|
fetchResult: Accessor<FetchResult | null>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ShowMeHow: Component<ShowMeHowProps> = ({ fetchResult }) => {
|
const ShowMeHow: Component<ShowMeHowProps> = ({ fetchResult }) => (
|
||||||
return (
|
<MyDisclosureContainer>
|
||||||
<MyDisclosureContainer>
|
<MyDisclosure title={ "Show me how it's done" }>
|
||||||
<MyDisclosure title={ "Show me how it's done" }>
|
<table class={ "table" }>
|
||||||
<table class={ "table" }>
|
<tbody>
|
||||||
<tbody>
|
|
||||||
|
|
||||||
<For each={ fetchResult()?.orderOperations }>{
|
<For each={ fetchResult()?.orderOperations }>{
|
||||||
(operation, index) => (
|
(operation, index) => (
|
||||||
<tr class={ "border-b border-dotted border-gray-500" }>
|
<tr class={ "border-b border-dotted border-gray-500" }>
|
||||||
<td>{ index() + 1 }:</td>
|
<td>{ index() + 1 }:</td>
|
||||||
<td class={ "px-2" }>{
|
<td class={ "px-2" }>{
|
||||||
|
|
||||||
<For each={ diffChars(operation.before, operation.after) }>
|
<For each={ diffChars(operation.before, operation.after) }>
|
||||||
{ (part) => (
|
{ (part) => (
|
||||||
<span class={
|
<span class={
|
||||||
`${ part.added && "bg-green-700" }
|
`${ part.added && "bg-green-700" }
|
||||||
${ part.removed && "bg-red-700" }` }>
|
${ part.removed && "bg-red-700" }` }>
|
||||||
{ part.value }
|
{ part.value }
|
||||||
</span>) }
|
</span>) }
|
||||||
</For> }
|
</For> }
|
||||||
|
|
||||||
<Show
|
<Show when={ typeof window !== "undefined" && window.outerWidth <= 640 } keyed>
|
||||||
when={ typeof window !== "undefined" && window.outerWidth <= 640 }
|
<p>{ "using" }: { operation.law }</p>
|
||||||
keyed>
|
|
||||||
<p>{ "using" }: { operation.law }</p>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
<Show
|
|
||||||
when={ typeof window !== "undefined" && window.outerWidth > 640 }
|
|
||||||
keyed>
|
|
||||||
<td>{ "using" }: { operation.law }</td>
|
|
||||||
</Show>
|
</Show>
|
||||||
</tr>
|
|
||||||
) }
|
|
||||||
</For>
|
|
||||||
|
|
||||||
</tbody>
|
</td>
|
||||||
</table>
|
<Show when={ typeof window !== "undefined" && window.outerWidth > 640 } keyed>
|
||||||
</MyDisclosure>
|
<td>{ "using" }: { operation.law }</td>
|
||||||
</MyDisclosureContainer>
|
</Show>
|
||||||
)
|
</tr>
|
||||||
}
|
) }
|
||||||
|
</For>
|
||||||
|
|
||||||
const KeywordsDisclosure = () => {
|
|
||||||
return (
|
|
||||||
<MyDisclosure title={ "Keywords" }>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>Not:</td>
|
|
||||||
<td>!</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>And:</td>
|
|
||||||
<td>&</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Or:</td>
|
|
||||||
<td>|</td>
|
|
||||||
<td>/</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class={ "pr-2" }>Implication:</td>
|
|
||||||
<td>{ "->" }</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</MyDisclosure>
|
</MyDisclosure>
|
||||||
);
|
</MyDisclosureContainer>
|
||||||
};
|
);
|
||||||
|
|
||||||
|
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);
|
render(() => <TruthTablePage />, document.getElementById("root") as HTMLElement);
|
||||||
|
2
src/types/types.d.ts
vendored
2
src/types/types.d.ts
vendored
@ -29,7 +29,7 @@ interface ButtonProps extends TitleProps {
|
|||||||
|
|
||||||
interface InputProps<T> extends TitleProps {
|
interface InputProps<T> extends TitleProps {
|
||||||
onInput?: JSX.EventHandlerUnion<T, Event>,
|
onInput?: JSX.EventHandlerUnion<T, Event>,
|
||||||
placeholder?: string | null,
|
placeholder?: string,
|
||||||
required?: boolean,
|
required?: boolean,
|
||||||
type?: string,
|
type?: string,
|
||||||
}
|
}
|
||||||
|
9
src/utils/dom.ts
Normal file
9
src/utils/dom.ts
Normal 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;
|
||||||
|
}
|
16
src/utils/expressionUtils.ts
Normal file
16
src/utils/expressionUtils.ts
Normal 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;
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
"jsxImportSource": "solid-js",
|
"jsxImportSource": "solid-js",
|
||||||
"types": ["vite/client"],
|
"types": ["vite/client"],
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"isolatedModules": true
|
"isolatedModules": true,
|
||||||
|
"strict": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user