diff --git a/.htaccess b/.htaccess index 9fded1e..4a897c9 100644 --- a/.htaccess +++ b/.htaccess @@ -1 +1,5 @@ -ErrorDocument 404 /404.html \ No newline at end of file +ErrorDocument 404 /404.html + + + Header add Access-Control-Allow-Origin 'https://api.martials.no/' + diff --git a/package-lock.json b/package-lock.json index 6190cd0..7c115ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,25 @@ { - "name": "vite-template-solid", + "name": "martials-no", "version": "0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "vite-template-solid", + "name": "martials-no", "version": "0.1", "license": "MIT", "dependencies": { - "solid-js": "^1.6.2" + "solid-headless": "^0.13.0", + "solid-heroicons": "^3.1.1", + "solid-js": "^1.6.6" }, "devDependencies": { "autoprefixer": "^10.4.13", - "postcss": "^8.4.19", + "postcss": "^8.4.20", "tailwindcss": "^3.2.4", - "typescript": "^4.9.3", - "vite": "^3.2.4", - "vite-plugin-solid": "^2.4.0" + "typescript": "^4.9.4", + "vite": "^3.2.5", + "vite-plugin-solid": "^2.5.0" } }, "node_modules/@ampproject/remapping": { @@ -1965,6 +1967,31 @@ "semver": "bin/semver.js" } }, + "node_modules/solid-headless": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/solid-headless/-/solid-headless-0.13.0.tgz", + "integrity": "sha512-N118iPl7W5lyug4K+4c0cwM8YR2yEVJ/3H4wq6tVijATHfXfLnB1ACFI5GGHSXlwu70PUzaGSKwcVqLlloUMyA==", + "dependencies": { + "solid-use": "^0.5.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "solid-js": "^1.2" + } + }, + "node_modules/solid-heroicons": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/solid-heroicons/-/solid-heroicons-3.1.1.tgz", + "integrity": "sha512-wfU/SqxqxWxInvfFlKJfCBPnJ94Zq1GQFiFL3M0KwZzT81lSF5yIC4HA/Czp3DYrn+dUumjO0qdrx8Ab3cy2sA==", + "dependencies": { + "solid-js": "^1.6.2" + }, + "peerDependencies": { + "solid-js": ">= ^1.2.5" + } + }, "node_modules/solid-js": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.6.6.tgz", @@ -1987,6 +2014,17 @@ "solid-js": "^1.3" } }, + "node_modules/solid-use": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/solid-use/-/solid-use-0.5.0.tgz", + "integrity": "sha512-z1AaS99SL3gNP70K4+XIVKGXDRI56m3Q6Q4X63bfgw0kaN6cwT4SAyFZAmIRjHcvf5rOMRQfNgUV4YVDha+LcQ==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "solid-js": "^1.2" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", diff --git a/package.json b/package.json index 0c91e72..e026cb8 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "vite-plugin-solid": "^2.5.0" }, "dependencies": { + "solid-headless": "^0.13.0", + "solid-heroicons": "^3.1.1", "solid-js": "^1.6.6" } } diff --git a/simplify-truths.html b/simplify-truths.html new file mode 100644 index 0000000..fefba88 --- /dev/null +++ b/simplify-truths.html @@ -0,0 +1,18 @@ + + + + + + + Simplify | Martials.no + + + + + + +
+ + + + diff --git a/src/components/input.tsx b/src/components/input.tsx new file mode 100644 index 0000000..3fdb1e5 --- /dev/null +++ b/src/components/input.tsx @@ -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): () => 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): void { + if (id) { + const el = document.getElementById(id) as HTMLInputElement | HTMLTextAreaElement | null; + if (el && el.value !== "" !== isText) { + setIsText(el.value !== ""); + } + } +} + +interface Input extends InputProps { + leading?: JSX.Element, + trailing?: JSX.Element, +} + +export const Input: Component> = ( + { + 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 ( + + { leading } + + 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 } + + ); +} + +function HoverTitle( + { + title, + isActive = false, + htmlFor + }: { title?: string | null, isActive?: boolean, htmlFor?: string }): JSX.Element { + return ( +