Started moving over truth-table.tsx from h600878.GitHub.io
This commit is contained in:
113
src/components/input.tsx
Normal file
113
src/components/input.tsx
Normal file
@ -0,0 +1,113 @@
|
||||
/* @refresh reload */
|
||||
import { type Component, createSignal, JSX, Setter } from "solid-js";
|
||||
import type { InputProps } from "../types/interfaces";
|
||||
import Row from "./row";
|
||||
|
||||
function setupEventListener(id: string, setIsHover: Setter<boolean>): () => void {
|
||||
let isMounted = true;
|
||||
|
||||
function hover(hover: boolean): void {
|
||||
if (isMounted) {
|
||||
setIsHover(hover);
|
||||
}
|
||||
}
|
||||
|
||||
const el = document.getElementById(id);
|
||||
el?.addEventListener("pointerenter", () => hover(true));
|
||||
el?.addEventListener("pointerleave", () => hover(false));
|
||||
|
||||
return () => {
|
||||
el?.removeEventListener("pointerenter", () => hover(true));
|
||||
el?.removeEventListener("pointerleave", () => hover(false));
|
||||
isMounted = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets isText to 'true' or 'false' using the setIsText function.
|
||||
* if the value of the input element is not empty and it's different from the current value
|
||||
*/
|
||||
function setSetIsText(id: string | undefined, isText: boolean, setIsText: Setter<boolean>): void {
|
||||
if (id) {
|
||||
const el = document.getElementById(id) as HTMLInputElement | HTMLTextAreaElement | null;
|
||||
if (el && el.value !== "" !== isText) {
|
||||
setIsText(el.value !== "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Input<T> extends InputProps<T> {
|
||||
leading?: JSX.Element,
|
||||
trailing?: JSX.Element,
|
||||
}
|
||||
|
||||
export const Input: Component<Input<HTMLInputElement>> = (
|
||||
{
|
||||
className,
|
||||
id,
|
||||
name,
|
||||
type = "text",
|
||||
title,
|
||||
placeholder,
|
||||
required = false,
|
||||
onChange,
|
||||
leading,
|
||||
trailing
|
||||
}): JSX.Element => {
|
||||
|
||||
/**
|
||||
* Is 'true' if the input element is in focus
|
||||
*/
|
||||
const [isFocused, setIsFocused] = createSignal(false);
|
||||
/**
|
||||
* Is 'true' if the user is hovering over the input element
|
||||
*/
|
||||
const [isHover, setIsHover] = createSignal(false);
|
||||
/**
|
||||
* Is 'true' if the input element contains any characters
|
||||
*/
|
||||
const [isText, setIsText] = createSignal(false);
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
if (id && title) {
|
||||
setupEventListener(id, setIsHover);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Row className={ "relative" }>
|
||||
{ leading }
|
||||
<HoverTitle title={ title } isActive={ isFocused() || isHover() || isText() } htmlFor={ id }/>
|
||||
<input
|
||||
class={ `bg-default-bg focus:border-cyan-500 outline-none border-2 border-gray-500
|
||||
hover:border-t-cyan-400 ${ className }` }
|
||||
id={ id }
|
||||
onFocus={ () => setIsFocused(true) }
|
||||
onBlur={ () => setIsFocused(false) }
|
||||
name={ name ?? undefined }
|
||||
type={ type }
|
||||
placeholder={ placeholder ?? undefined }
|
||||
required={ required }
|
||||
onInput={ () => setSetIsText(id, isText(), setIsText) }
|
||||
onChange={ onChange /*TODO only called after ENTER*/ }/>
|
||||
{ trailing }
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
function HoverTitle(
|
||||
{
|
||||
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` }
|
||||
for={ htmlFor }>
|
||||
<div class={ "z-50 relative" }>{ title }</div>
|
||||
<div class={ "w-full h-2 default-bg absolute bottom-1/3 z-10" }/>
|
||||
</label>
|
||||
);
|
||||
}
|
75
src/components/output.tsx
Normal file
75
src/components/output.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import { Disclosure, DisclosureButton, DisclosurePanel, Transition } from "solid-headless";
|
||||
import { Icon } from "solid-heroicons";
|
||||
import type { ChildProps, TitleProps } from "../types/interfaces";
|
||||
import { Component, JSX } from "solid-js";
|
||||
import { chevronUp } from "solid-heroicons/solid";
|
||||
|
||||
interface InfoBoxProps extends TitleProps {
|
||||
error?: boolean,
|
||||
}
|
||||
|
||||
export const InfoBox: Component<InfoBoxProps> = (
|
||||
{
|
||||
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,
|
||||
onClick?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>,
|
||||
}
|
||||
|
||||
export const MyDisclosure: Component<MyDisclosureProps> = (
|
||||
{
|
||||
title,
|
||||
children,
|
||||
defaultOpen = false,
|
||||
className,
|
||||
id,
|
||||
onClick
|
||||
}): JSX.Element => {
|
||||
return (
|
||||
<div id={ id } class={ `border-rounded bg-default-bg ${ className }` }>
|
||||
<Disclosure defaultOpen={ defaultOpen }>
|
||||
{ ({ isOpen }) =>
|
||||
<>
|
||||
<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` } />
|
||||
</DisclosureButton>
|
||||
<Transition
|
||||
enter="transition duration-100 ease-out"
|
||||
enterFrom="transform scale-95 opacity-0"
|
||||
enterTo="transform scale-100 opacity-100"
|
||||
leave="transition duration-75 ease-out"
|
||||
leaveFrom="transform scale-100 opacity-100"
|
||||
leaveTo="transform scale-95 opacity-0" show>
|
||||
<DisclosurePanel>
|
||||
<div class={ "px-2 pb-2 text-gray-300" }>{ children }</div>
|
||||
</DisclosurePanel>
|
||||
</Transition>
|
||||
</>
|
||||
}
|
||||
</Disclosure>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const MyDisclosureContainer: Component<ChildProps> = ({ children, className }): JSX.Element => {
|
||||
return (
|
||||
<div class={ `bg-cyan-900 border-rounded dark:border-gray-800 p-2 mb-2
|
||||
flex flex-col gap-1 ${ className }` }>
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
}
|
9
src/components/row.tsx
Normal file
9
src/components/row.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
/* @refresh reload */
|
||||
import { type Component } from "solid-js";
|
||||
import type { ChildProps } from "../types/interfaces";
|
||||
|
||||
const Row: Component<ChildProps> = ({ children, className }) => {
|
||||
return <div class={ `flex-row-center ${ className }` }>{ children }</div>
|
||||
}
|
||||
|
||||
export default Row;
|
57
src/components/truth-table.tsx
Normal file
57
src/components/truth-table.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
/* @refresh reload */
|
||||
import type { SimpleProps } from "../types/interfaces";
|
||||
import type { Table } from "../types/interfaces";
|
||||
import { For } from "solid-js/web";
|
||||
import { type Component } from "solid-js";
|
||||
|
||||
interface TruthTableProps extends SimpleProps {
|
||||
table?: Table,
|
||||
header?: string[],
|
||||
}
|
||||
|
||||
const TruthTable: Component<TruthTableProps> = (
|
||||
{
|
||||
table,
|
||||
header,
|
||||
className,
|
||||
style,
|
||||
id,
|
||||
}) => {
|
||||
|
||||
return (
|
||||
<table class={ `border-2 border-gray-500 border-collapse table z-10 ${ className }` } id={ id }
|
||||
style={ style }>
|
||||
<thead>
|
||||
<tr>
|
||||
<For each={ header }>
|
||||
{ (exp) => (
|
||||
<th scope={ "col" }
|
||||
class={ `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 */ }>
|
||||
<p class={ "px-2" }>{ exp }</p>
|
||||
</th>
|
||||
) }
|
||||
</For>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<For each={ table }>
|
||||
{ (row) =>
|
||||
<tr class={ "dark:hover:text-black hover:text-white" }>
|
||||
<For each={ row }>
|
||||
{ (value) =>
|
||||
<td class={ `text-center border border-gray-500 last:underline
|
||||
${ value ? "bg-green-500 dark:bg-green-700" : "bg-red-500 dark:bg-red-700" }` }>
|
||||
<p>{ value ? "T" : "F" }</p>
|
||||
</td>
|
||||
}
|
||||
</For>
|
||||
</tr>
|
||||
}
|
||||
</For>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
export default TruthTable;
|
Reference in New Issue
Block a user