Compare commits
No commits in common. "master" and "build" have entirely different histories.
@ -1,3 +0,0 @@
|
||||
VITE_FETCH_URL=http://localhost:8080/
|
||||
VITE_FETCH_PATH=simplify/table/
|
||||
VITE_FETCH_FULL=$VITE_FETCH_URL$VITE_FETCH_PATH
|
@ -1,3 +0,0 @@
|
||||
VITE_FETCH_URL=https://api.martials.no/
|
||||
VITE_FETCH_PATH=simplify-truths/simplify/table/
|
||||
VITE_FETCH_FULL=$VITE_FETCH_URL$VITE_FETCH_PATH
|
@ -1,45 +0,0 @@
|
||||
name: Deploy
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: echo y | npm exec -- pnpm install
|
||||
- name: Build project
|
||||
run: npm exec -- pnpm build
|
||||
- name: Upload production-ready build files
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dist
|
||||
path: ./dist
|
||||
|
||||
deploy:
|
||||
name: Deploy
|
||||
needs: build
|
||||
runs-on: host
|
||||
|
||||
steps:
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: dist
|
||||
path: ./dist
|
||||
|
||||
# Deploy to local repo
|
||||
- name: Move files to server
|
||||
run: |
|
||||
rm -rf /var/www/martials.no/*
|
||||
cp -r dist/* /var/www/martials.no
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
node_modules
|
||||
dist
|
5
.idea/.gitignore
generated
vendored
5
.idea/.gitignore
generated
vendored
@ -1,5 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
89
.idea/codeStyles/Project.xml
generated
89
.idea/codeStyles/Project.xml
generated
@ -1,89 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_ALIGN_TEXT" value="true" />
|
||||
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
<option name="SPACES_WITHIN_INTERPOLATION_EXPRESSIONS" value="true" />
|
||||
</JSCodeStyleSettings>
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<Objective-C>
|
||||
<option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_CASE_EXPRESSIONS_IN_ONE_LINE" value="true" />
|
||||
</Objective-C>
|
||||
<TypeScriptCodeStyleSettings version="0">
|
||||
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
<option name="SPACES_WITHIN_INTERPOLATION_EXPRESSIONS" value="true" />
|
||||
</TypeScriptCodeStyleSettings>
|
||||
<VueCodeStyleSettings>
|
||||
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
|
||||
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
|
||||
</VueCodeStyleSettings>
|
||||
<codeStyleSettings language="HTML">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<option name="CATCH_ON_NEW_LINE" value="true" />
|
||||
<option name="FINALLY_ON_NEW_LINE" value="true" />
|
||||
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
|
||||
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="ObjectiveC">
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<option name="CATCH_ON_NEW_LINE" value="true" />
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="TypeScript">
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<option name="CATCH_ON_NEW_LINE" value="true" />
|
||||
<option name="FINALLY_ON_NEW_LINE" value="true" />
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Vue">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
12
.idea/inspectionProfiles/Project_Default.xml
generated
12
.idea/inspectionProfiles/Project_Default.xml
generated
@ -1,12 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="GrazieInspection" enabled="false" level="TYPO" enabled_by_default="false" />
|
||||
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
.idea/jsLibraryMappings.xml
generated
6
.idea/jsLibraryMappings.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<file url="PROJECT" libraries="{latest}" />
|
||||
</component>
|
||||
</project>
|
13
.idea/martials.no.iml
generated
13
.idea/martials.no.iml
generated
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="latest" level="application" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/martials.no.iml" filepath="$PROJECT_DIR$/.idea/martials.no.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
7
.idea/prettier.xml
generated
7
.idea/prettier.xml
generated
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PrettierConfiguration">
|
||||
<option name="myConfigurationMode" value="AUTOMATIC" />
|
||||
<option name="myRunOnSave" value="true" />
|
||||
</component>
|
||||
</project>
|
12
.idea/runConfigurations/build.xml
generated
12
.idea/runConfigurations/build.xml
generated
@ -1,12 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="build" type="js.build_tools.npm" nameIsGenerated="true">
|
||||
<package-json value="$PROJECT_DIR$/package.json" />
|
||||
<command value="run" />
|
||||
<scripts>
|
||||
<script value="build" />
|
||||
</scripts>
|
||||
<node-interpreter value="project" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
12
.idea/runConfigurations/dev.xml
generated
12
.idea/runConfigurations/dev.xml
generated
@ -1,12 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="dev" type="js.build_tools.npm" nameIsGenerated="true">
|
||||
<package-json value="$PROJECT_DIR$/package.json" />
|
||||
<command value="run" />
|
||||
<scripts>
|
||||
<script value="dev" />
|
||||
</scripts>
|
||||
<node-interpreter value="project" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
12
.idea/runConfigurations/serve.xml
generated
12
.idea/runConfigurations/serve.xml
generated
@ -1,12 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="serve" type="js.build_tools.npm" nameIsGenerated="true">
|
||||
<package-json value="$PROJECT_DIR$/package.json" />
|
||||
<command value="run" />
|
||||
<scripts>
|
||||
<script value="serve" />
|
||||
</scripts>
|
||||
<node-interpreter value="project" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
14
.idea/webResources.xml
generated
14
.idea/webResources.xml
generated
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="WebResourcesPaths">
|
||||
<contentEntries>
|
||||
<entry url="file://$PROJECT_DIR$">
|
||||
<entryData>
|
||||
<resourceRoots>
|
||||
<path value="file://$PROJECT_DIR$/resources" />
|
||||
</resourceRoots>
|
||||
</entryData>
|
||||
</entry>
|
||||
</contentEntries>
|
||||
</component>
|
||||
</project>
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
34
README.md
34
README.md
@ -1,34 +0,0 @@
|
||||
## Usage
|
||||
|
||||
Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`.
|
||||
|
||||
This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template.
|
||||
|
||||
```bash
|
||||
$ npm install # or pnpm install or yarn install
|
||||
```
|
||||
|
||||
### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm dev` or `npm start`
|
||||
|
||||
Runs the app in the development mode.<br>
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
||||
|
||||
The page will reload if you make edits.<br>
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `dist` folder.<br>
|
||||
It correctly bundles Solid in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.<br>
|
||||
Your app is ready to be deployed!
|
||||
|
||||
## Deployment
|
||||
|
||||
You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.)
|
Before Width: | Height: | Size: 307 B After Width: | Height: | Size: 307 B |
129
assets/main-7gPkv783.js
Normal file
129
assets/main-7gPkv783.js
Normal file
File diff suppressed because one or more lines are too long
1
assets/main-CQ3K2vor.css
Normal file
1
assets/main-CQ3K2vor.css
Normal file
File diff suppressed because one or more lines are too long
@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -e dist ]; then
|
||||
echo "dist directory not found, running 'vite bulid'"
|
||||
vite build
|
||||
fi
|
||||
|
||||
# Copying the file ($1) to the dist directory, or to subdirectory ($2)
|
||||
copy() {
|
||||
if [ -e "$1" ]; then
|
||||
cp "$1" dist/"$2"
|
||||
else
|
||||
echo "'$1' not found, skipping"
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p "dist/.well-known"
|
||||
|
||||
copy robots.txt
|
||||
copy security.txt .well-known
|
||||
copy .htaccess
|
@ -6,9 +6,11 @@
|
||||
<meta name="theme-color" content="#181a1b" />
|
||||
<title>Hjem | Martials.no</title>
|
||||
<meta name="description" content="Hjemmeside for API og diverse" />
|
||||
<link rel="icon" type="image/x-icon" href="resources/code.svg" />
|
||||
<link rel="icon" type="image/x-icon" href="/assets/code-nzJlNpcV.svg" />
|
||||
<!-- 100% privacy-first analytics -->
|
||||
<script data-collect-dnt="true" async defer src="https://scripts.simpleanalyticscdn.com/latest.js"></script>
|
||||
<script type="module" crossorigin src="/assets/main-7gPkv783.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-CQ3K2vor.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
@ -17,6 +19,5 @@
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
|
||||
<script src="/src/app.tsx" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
32
package.json
32
package.json
@ -1,32 +0,0 @@
|
||||
{
|
||||
"name": "martials-no",
|
||||
"version": "1.0",
|
||||
"description": "Landing page Martin Berg Alstad's APIs and other things",
|
||||
"scripts": {
|
||||
"prestart": "npx only-allow pnpm",
|
||||
"dev": "vite",
|
||||
"build": "vite build && sh build_extra.sh",
|
||||
"serve": "vite preview",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.17",
|
||||
"postcss": "^8.4.35",
|
||||
"prettier": "3.2.5",
|
||||
"prettier-plugin-tailwindcss": "^0.5.11",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.1.4",
|
||||
"vite-plugin-solid": "^2.10.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@solidjs/router": "^0.12.4",
|
||||
"@types/diff": "^5.0.9",
|
||||
"diff": "^5.2.0",
|
||||
"solid-headless": "^0.13.1",
|
||||
"solid-heroicons": "^3.2.4",
|
||||
"solid-js": "^1.8.15",
|
||||
"xlsx": "^0.18.5"
|
||||
}
|
||||
}
|
2381
pnpm-lock.yaml
generated
2381
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +0,0 @@
|
||||
packages:
|
||||
# include packages in subfolders (e.g. apps/ and packages/)
|
||||
- "apps/**"
|
||||
- "packages/**"
|
||||
# if required, exclude some directories
|
||||
- "!**/test/**"
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
purge: ["./*.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
18
src/app.tsx
18
src/app.tsx
@ -1,18 +0,0 @@
|
||||
import { Route, Router } from "@solidjs/router"
|
||||
import HomePage from "./pages/home"
|
||||
import TruthTablePage from "./pages/truth-table"
|
||||
import PageNotFound from "./pages/404"
|
||||
import { render } from "solid-js/web"
|
||||
import FailureFunctionPage from "./pages/failureFunction"
|
||||
|
||||
render(
|
||||
() => (
|
||||
<Router>
|
||||
<Route path={"/"} component={HomePage} />
|
||||
<Route path={"/simplify-truths"} component={TruthTablePage} />
|
||||
<Route path={"/failure-function"} component={FailureFunctionPage} />
|
||||
<Route path={"*"} component={PageNotFound} />
|
||||
</Router>
|
||||
),
|
||||
document.getElementById("root") as HTMLElement
|
||||
)
|
@ -1,59 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component, createSignal } from "solid-js"
|
||||
|
||||
interface SwitchProps extends TitleProps {
|
||||
defaultValue?: boolean
|
||||
onChange?: (value: boolean) => void
|
||||
}
|
||||
|
||||
export const MySwitch: Component<SwitchProps> = ({
|
||||
defaultValue = false,
|
||||
title,
|
||||
onChange,
|
||||
className,
|
||||
name,
|
||||
id
|
||||
}) => {
|
||||
const [checked, setChecked] = createSignal(defaultValue)
|
||||
|
||||
function handleChange() {
|
||||
const newChecked = !checked()
|
||||
setChecked(newChecked)
|
||||
if (onChange) {
|
||||
onChange(newChecked)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
id={id}
|
||||
onClick={handleChange}
|
||||
title={title}
|
||||
class={`${checked() ? "bg-cyan-900" : "bg-gray-500"} relative my-2 inline-flex h-6 w-11 items-center rounded-full ${className}`}
|
||||
>
|
||||
<span class={"sr-only"}>{name}</span>
|
||||
<span
|
||||
class={`${checked() ? "translate-x-6" : "translate-x-1"} inline-block h-4 w-4 transform rounded-full bg-white transition-all`}
|
||||
/>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export const Button: Component<ButtonProps> = ({
|
||||
className,
|
||||
title,
|
||||
children,
|
||||
id,
|
||||
onClick,
|
||||
type = "button"
|
||||
}) => (
|
||||
<button
|
||||
title={title}
|
||||
id={id}
|
||||
type={type}
|
||||
class={`border-rounded cursor-pointer bg-cyan-900 px-2 ${className}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component } from "solid-js"
|
||||
import { Link } from "./link"
|
||||
|
||||
const Card: Component<CardProps> = ({ children, className, title, to, newTab = false }) => (
|
||||
<div
|
||||
class={`relative h-32 w-72 rounded-2xl bg-gradient-to-r from-cyan-600 to-cyan-500 ${className}`}
|
||||
>
|
||||
<div class={"relative p-5"}>
|
||||
<Link className={"text-white"} to={to} newTab={newTab}>
|
||||
<h3 class={"mx-auto w-fit text-center before:content-['↗']"}>{title}</h3>
|
||||
</Link>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default Card
|
@ -1,100 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { Dialog, DialogDescription, DialogPanel, DialogTitle } from "solid-headless"
|
||||
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
|
||||
acceptButtonId?: string
|
||||
cancelButtonName?: string
|
||||
callback?: () => void
|
||||
buttonClass?: string
|
||||
buttonTitle?: string | null
|
||||
}
|
||||
|
||||
const MyDialog: Component<MyDialog> = ({
|
||||
title,
|
||||
description,
|
||||
button,
|
||||
acceptButtonName = "Ok",
|
||||
cancelButtonName = "Cancel",
|
||||
children,
|
||||
callback,
|
||||
className,
|
||||
buttonClass,
|
||||
buttonTitle,
|
||||
acceptButtonId
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = createSignal(false)
|
||||
|
||||
function callbackAndClose(): void {
|
||||
callback?.()
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
function setupKeyPress(): () => void {
|
||||
let isMounted = true
|
||||
|
||||
/**
|
||||
* Pressing "Enter" when the modal is open, will click the accept button
|
||||
* @param e KeyboardEvent of keypress
|
||||
*/
|
||||
function click(e: KeyboardEvent): void {
|
||||
if (isMounted && e.key === "Enter" && acceptButtonId) {
|
||||
getElementById<HTMLButtonElement>(acceptButtonId)?.click()
|
||||
}
|
||||
}
|
||||
|
||||
if (isOpen()) {
|
||||
const id = "cl-6"
|
||||
const el = getElementById(id)
|
||||
el?.addEventListener("keypress", click)
|
||||
return () => {
|
||||
el?.removeEventListener("keypress", click)
|
||||
isMounted = false
|
||||
}
|
||||
} else return () => undefined
|
||||
}
|
||||
|
||||
createEffect(setupKeyPress, isOpen())
|
||||
|
||||
return (
|
||||
<div class={"h-fit w-fit"}>
|
||||
<button onClick={() => setIsOpen(true)} class={buttonClass} title={buttonTitle ?? undefined}>
|
||||
{button}
|
||||
</button>
|
||||
|
||||
<Portal>
|
||||
<Dialog
|
||||
isOpen={isOpen()}
|
||||
onClose={() => setIsOpen(false)}
|
||||
class={`flex-row-center fixed inset-0 z-50 justify-center overflow-auto text-white ${className}`}
|
||||
>
|
||||
<div class={"fixed inset-0 bg-black/40" /*Backdrop*/} aria-hidden={true} />
|
||||
|
||||
<DialogPanel class={"border-rounded relative w-fit border-gray-500 bg-default-bg p-2"}>
|
||||
<DialogTitle class={"border-b"}>{title}</DialogTitle>
|
||||
<DialogDescription class={"mb-4 mt-1"}>{description}</DialogDescription>
|
||||
|
||||
{children}
|
||||
|
||||
<div class={"my-3"}>
|
||||
<Button onClick={callbackAndClose} className={"mr-2 h-10"} id={acceptButtonId}>
|
||||
{acceptButtonName}
|
||||
</Button>
|
||||
<Button onClick={() => setIsOpen(false)} className={"h-10"}>
|
||||
{cancelButtonName}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogPanel>
|
||||
</Dialog>
|
||||
</Portal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyDialog
|
@ -1,13 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component } from "solid-js"
|
||||
import { Link } from "./link"
|
||||
|
||||
const Footer: Component<SimpleProps> = ({ className }) => (
|
||||
<footer class={`container absolute bottom-0 py-5 text-center ${className}`}>
|
||||
<p>
|
||||
Kildekode på <Link to={"https://git.martials.no/martials/old.martials.no"}>Gitea</Link>
|
||||
</p>
|
||||
</footer>
|
||||
)
|
||||
|
||||
export default Footer
|
@ -1,29 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component, Show } from "solid-js"
|
||||
import { Icon } from "solid-heroicons"
|
||||
import { chevronLeft } from "solid-heroicons/solid"
|
||||
import { Link } from "./link"
|
||||
import { useLocation } from "@solidjs/router"
|
||||
|
||||
const Header: Component<TitleProps> = ({ className, title = "Title goes here" }) => {
|
||||
const location = useLocation()
|
||||
|
||||
return (
|
||||
<header class={className}>
|
||||
<div class={"flex-row-center mx-auto w-fit"}>
|
||||
<Show when={location.pathname !== "/"} keyed>
|
||||
<Link to={"/"} newTab={false} title={"Back to homepage"}>
|
||||
<Icon path={chevronLeft} class={"text-cyan-500"} />
|
||||
</Link>
|
||||
</Show>
|
||||
|
||||
<h1 class={"text-center text-cyan-500"}>{title}</h1>
|
||||
</div>
|
||||
<div class={"mx-auto w-fit"}>
|
||||
<p>Av Martin Berg Alstad</p>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
export default Header
|
@ -1,181 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component, createSignal, JSX, onMount, Setter, Show } from "solid-js"
|
||||
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
|
||||
|
||||
function hover(hover: boolean): void {
|
||||
if (isMounted) {
|
||||
setIsHover(hover)
|
||||
}
|
||||
}
|
||||
|
||||
const el = 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 = getElementById<HTMLInputElement | HTMLTextAreaElement>(id)
|
||||
if (el && (el.value !== "") !== isText) {
|
||||
setIsText(el.value !== "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Input<T extends HTMLElement> extends InputProps<T> {
|
||||
leading?: JSX.Element
|
||||
trailing?: JSX.Element
|
||||
onChange?: () => void
|
||||
inputClass?: string
|
||||
}
|
||||
|
||||
export const Input: Component<Input<HTMLInputElement>> = (
|
||||
// TODO remove leading and trailing from component
|
||||
{
|
||||
className,
|
||||
id,
|
||||
name,
|
||||
type = "text",
|
||||
title,
|
||||
placeholder,
|
||||
required = false,
|
||||
onChange,
|
||||
leading,
|
||||
trailing,
|
||||
inputClass,
|
||||
ref
|
||||
}
|
||||
): 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)
|
||||
|
||||
onMount(() => {
|
||||
if (id && title) {
|
||||
setupEventListener(id, setIsHover)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<Row className={`relative ${className}`}>
|
||||
{leading}
|
||||
<HoverTitle title={title} isActive={isFocused() || isHover() || isText()} htmlFor={id} />
|
||||
<input
|
||||
class={`border-2 border-gray-500 bg-default-bg outline-none hover:border-t-cyan-400
|
||||
focus:border-cyan-500 ${inputClass}`}
|
||||
id={id}
|
||||
ref={ref}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setIsFocused(false)}
|
||||
name={name ?? undefined}
|
||||
type={type}
|
||||
placeholder={placeholder ?? undefined}
|
||||
required={required}
|
||||
onInput={() => {
|
||||
setSetIsText(id, isText(), setIsText)
|
||||
if (onChange) {
|
||||
onChange()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{trailing}
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
const HoverTitle: Component<{ title?: string; isActive?: boolean; htmlFor?: string }> = ({
|
||||
title,
|
||||
isActive = false,
|
||||
htmlFor
|
||||
}) => (
|
||||
<label
|
||||
class={`pointer-events-none absolute
|
||||
${isActive ? "default-bg -top-2 left-3 text-sm" : "left-2 top-1"}
|
||||
text-gray-600 transition-all duration-150 dark:text-gray-400`}
|
||||
for={htmlFor}
|
||||
>
|
||||
<div class={"relative z-50"}>{title}</div>
|
||||
<div class={"default-bg absolute bottom-1/3 z-10 h-2 w-full"} />
|
||||
</label>
|
||||
)
|
||||
|
||||
interface SearchProps extends InputProps {
|
||||
typingDefault?: boolean
|
||||
}
|
||||
|
||||
export const Search: Component<SearchProps> = ({
|
||||
typingDefault = false,
|
||||
id = "search",
|
||||
className,
|
||||
ref
|
||||
}) => {
|
||||
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}
|
||||
ref={ref}
|
||||
placeholder={"¬A & B -> C"}
|
||||
type={"text"}
|
||||
onChange={onChange}
|
||||
leading={
|
||||
<Icon path={magnifyingGlass} aria-label={"Magnifying glass"} class={"absolute pl-2"} />
|
||||
}
|
||||
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>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component } from "solid-js"
|
||||
import Header from "./header"
|
||||
import Footer from "./footer"
|
||||
|
||||
const Layout: Component<TitleProps> = ({ children, title, className }) => (
|
||||
<div class={`relative min-h-screen bg-default-bg font-mono text-white ${className}`}>
|
||||
<div class="container mx-auto">
|
||||
<Header className={"py-3"} title={title} />
|
||||
<main>
|
||||
<div class={"pb-28"}>{children}</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default Layout
|
@ -1,17 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component } from "solid-js"
|
||||
|
||||
export const Link: Component<LinkProps> = (
|
||||
{ to, rel, children, className, id, newTab = true, title } // TODO <A/> throws exception
|
||||
) => (
|
||||
<a
|
||||
href={to}
|
||||
id={id}
|
||||
title={title}
|
||||
rel={`${rel} ${newTab ? "noreferrer" : undefined}`}
|
||||
target={newTab ? "_blank" : undefined}
|
||||
class={`link ${className}`}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
)
|
@ -1,72 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component, createEffect, createSignal, JSX, Show } from "solid-js"
|
||||
import { Button } from "./button"
|
||||
|
||||
interface MenuProps extends TitleProps {
|
||||
button?: JSX.Element
|
||||
buttonClassName?: string
|
||||
itemsClassName?: string
|
||||
}
|
||||
|
||||
const MyMenu: Component<MenuProps> = ({
|
||||
title,
|
||||
button,
|
||||
children,
|
||||
id,
|
||||
className,
|
||||
buttonClassName,
|
||||
itemsClassName
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = createSignal(false)
|
||||
|
||||
function closeMenu(): void {
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
function toggleMenu(): void {
|
||||
setIsOpen(!isOpen())
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
function click(e: MouseEvent): void {
|
||||
if (e.target instanceof HTMLElement) {
|
||||
if (e.target.closest(`#${id}`) === null) {
|
||||
closeMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function keypress(e: KeyboardEvent): void {
|
||||
if (e.key === "Escape") {
|
||||
closeMenu()
|
||||
}
|
||||
}
|
||||
|
||||
if (isOpen()) {
|
||||
document.addEventListener("click", click)
|
||||
document.addEventListener("keyup", keypress)
|
||||
} else {
|
||||
document.removeEventListener("click", click)
|
||||
document.removeEventListener("keyup", keypress)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
// TODO transition
|
||||
<div class={`${className}`} id={id}>
|
||||
<Button title={title} onClick={toggleMenu} className={`flex-row-center ${buttonClassName}`}>
|
||||
{button}
|
||||
</Button>
|
||||
|
||||
<Show when={isOpen()} keyed>
|
||||
<div
|
||||
class={`absolute z-50 mt-1 w-max rounded-b-xl border border-gray-500 bg-default-bg ${itemsClassName}`}
|
||||
>
|
||||
<div class={"mx-1"}>{children}</div>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyMenu
|
@ -1,65 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { Disclosure, DisclosureButton, DisclosurePanel, Transition } from "solid-headless"
|
||||
import { Icon } from "solid-heroicons"
|
||||
import { type 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 }) => (
|
||||
<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 => (
|
||||
<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() && "rotate-180 transform"} 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 }) => (
|
||||
<div
|
||||
class={`border-rounded mb-2 flex flex-col gap-1
|
||||
bg-cyan-900 p-2 dark:border-gray-800 ${className}`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
@ -1,14 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component } from "solid-js"
|
||||
|
||||
/**
|
||||
* 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
|
@ -1,54 +0,0 @@
|
||||
/* @refresh reload */
|
||||
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 }) => (
|
||||
<table
|
||||
class={`z-10 table border-collapse border-2 border-gray-500 ${className}`}
|
||||
id={id}
|
||||
style={style}
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<For each={header}>
|
||||
{(exp) => (
|
||||
<th
|
||||
scope={"col"}
|
||||
class={
|
||||
`sticky top-0 bg-default-bg text-center outline
|
||||
outline-2 outline-offset-[-1px] outline-gray-500 [position:-webkit-sticky;]` /*TODO sticky header at the top of the screen */
|
||||
}
|
||||
>
|
||||
<p class={"w-max px-2"}>{exp}</p>
|
||||
</th>
|
||||
)}
|
||||
</For>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<For each={table}>
|
||||
{(row) => (
|
||||
<tr class={"hover:text-black"}>
|
||||
<For each={row}>
|
||||
{(value) => (
|
||||
<td
|
||||
class={`border border-gray-500 text-center last:underline
|
||||
${value ? "bg-green-700" : "bg-red-700"}`}
|
||||
>
|
||||
<p>{value ? "T" : "F"}</p>
|
||||
</td>
|
||||
)}
|
||||
</For>
|
||||
</tr>
|
||||
)}
|
||||
</For>
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
|
||||
export default TruthTable
|
@ -1,46 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer components {
|
||||
.debug {
|
||||
@apply border border-red-500;
|
||||
@apply after:absolute after:content-['DEBUG'];
|
||||
}
|
||||
|
||||
.flex-row-center {
|
||||
@apply flex flex-row items-center;
|
||||
}
|
||||
|
||||
.border-rounded {
|
||||
@apply rounded-2xl border border-gray-700;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-4xl;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply text-3xl;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-2xl;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply text-xl;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-cyan-500 hover:underline;
|
||||
}
|
||||
|
||||
li {
|
||||
@apply ml-4 list-disc;
|
||||
}
|
||||
|
||||
svg {
|
||||
@apply pointer-events-none h-6 w-6;
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { type Component } from "solid-js"
|
||||
import { render } from "solid-js/web"
|
||||
import Layout from "../components/layout"
|
||||
import { Link } from "../components/link"
|
||||
|
||||
const PageNotFound: Component = () => (
|
||||
<Layout title={"Siden ble ikke funnet"}>
|
||||
<div class={"text-center"}>
|
||||
<h4>Error 404 - Siden ble ikke funnet</h4>
|
||||
<p>
|
||||
<Link to={"/"} newTab={false} className={"relative mx-auto w-max"}>
|
||||
Gå tilbake til forsiden
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</Layout>
|
||||
)
|
||||
|
||||
export default PageNotFound
|
@ -1,59 +0,0 @@
|
||||
/* @refresh reload */
|
||||
|
||||
import { Component, createSignal } from "solid-js"
|
||||
import { Input } from "../components/input"
|
||||
import Layout from "../components/layout"
|
||||
import { failureFunction } from "../utils/failureFunction"
|
||||
import { For } from "solid-js/web"
|
||||
|
||||
type FFProps = { char: string; index: number }
|
||||
|
||||
const FailureFunctionPage: Component = () => {
|
||||
let inputRef: HTMLInputElement | undefined = undefined
|
||||
|
||||
const [result, setResult] = createSignal<ReadonlyArray<FFProps>>()
|
||||
|
||||
function onSubmit(e: Event) {
|
||||
e.preventDefault()
|
||||
if (inputRef) {
|
||||
const input = inputRef.value
|
||||
const splitInput = input.split("")
|
||||
const output = failureFunction(input)
|
||||
|
||||
if (output.length !== splitInput.length) {
|
||||
console.error("Something went wrong")
|
||||
} else {
|
||||
setResult(output.map((value, index) => ({ char: splitInput[index], index: value })))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout title={"Failure function"}>
|
||||
<div class={"container mx-auto max-w-2xl overflow-auto"}>
|
||||
<p>Failure Function</p>
|
||||
<form onsubmit={onSubmit}>
|
||||
<Input ref={inputRef} inputClass={"rounded-2xl w-full h-10 px-3"} />
|
||||
</form>
|
||||
<table class={"mb-3"}>
|
||||
<thead>
|
||||
<tr>
|
||||
<For each={result()}>
|
||||
{({ char }) => <th class={"border border-black"}>{char}</th>}
|
||||
</For>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<For each={result()}>
|
||||
{({ index }) => <td class={"border border-black"}>{index}</td>}
|
||||
</For>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export default FailureFunctionPage
|
@ -1,57 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import { For } from "solid-js/web"
|
||||
|
||||
import "../index.css"
|
||||
import { type Component } from "solid-js"
|
||||
import Layout from "../components/layout"
|
||||
import Card from "../components/card"
|
||||
import { Link } from "../components/link"
|
||||
|
||||
const apiRoot = "https://api.martials.no"
|
||||
|
||||
const cards = [
|
||||
{
|
||||
title: "API-er",
|
||||
children: (
|
||||
<>
|
||||
<p>Sjekk ut mine API-er</p>
|
||||
<ul>
|
||||
<li>
|
||||
<Link className={"text-white"} to={`${apiRoot}/simplify-truths`}>
|
||||
Forenkle sannhetsverdier
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
),
|
||||
to: apiRoot,
|
||||
newTab: true
|
||||
},
|
||||
{
|
||||
title: "Hjemmeside",
|
||||
children: <p>Sjekk ut mine andre prosjekter</p>,
|
||||
to: "https://emberal.github.io/",
|
||||
newTab: true
|
||||
},
|
||||
{
|
||||
title: "Forenkle sannhetsverdier",
|
||||
children: <p>Implementering av API</p>,
|
||||
to: `/simplify-truths`
|
||||
}
|
||||
] satisfies CardProps[]
|
||||
|
||||
const HomePage: Component = () => (
|
||||
<Layout title={"Velkommen!"}>
|
||||
<div class={"mt-10 flex flex-wrap justify-center"}>
|
||||
<For each={cards}>
|
||||
{(card) => (
|
||||
<Card title={card.title} className={"m-4"} to={card.to} newTab={card.newTab}>
|
||||
{card.children}
|
||||
</Card>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Layout>
|
||||
)
|
||||
|
||||
export default HomePage
|
@ -1,447 +0,0 @@
|
||||
/* @refresh reload */
|
||||
import Layout from "../components/layout"
|
||||
import { Input, Search } from "../components/input"
|
||||
import { Icon } from "solid-heroicons"
|
||||
import TruthTable from "../components/truth-table"
|
||||
import { InfoBox, MyDisclosure, MyDisclosureContainer } from "../components/output"
|
||||
import { diffChars } from "diff"
|
||||
import MyMenu from "../components/menu"
|
||||
import { type Accessor, type Component, createSignal, JSX, onMount, Show } from "solid-js"
|
||||
import { For } from "solid-js/web"
|
||||
import Row from "../components/row"
|
||||
import { arrowDownTray, arrowPath, check, eye, eyeSlash, funnel } from "solid-heroicons/solid"
|
||||
import { Button, MySwitch } from "../components/button"
|
||||
import MyDialog from "../components/dialog"
|
||||
import { exportToExcel } from "../utils/export"
|
||||
import { Link } from "../components/link"
|
||||
import { isTouch } from "../utils/touch"
|
||||
import { replaceOperators } from "../utils/expressionUtils"
|
||||
import { getElementById } from "../utils/dom"
|
||||
import { useSearchParams } from "@solidjs/router"
|
||||
|
||||
type Option = {
|
||||
name: string
|
||||
value: "NONE" | "TRUE" | "FALSE" | "DEFAULT" | "TRUE_FIRST" | "FALSE_FIRST"
|
||||
}
|
||||
|
||||
const fetchUrls = [
|
||||
"http://localhost:8080/simplify/table/",
|
||||
"https://api.martials.no/simplify-truths/simplify/table/"
|
||||
]
|
||||
|
||||
// TODO move some code to new components
|
||||
const TruthTablePage: Component = () => {
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
let inputElement: HTMLInputElement | undefined = undefined
|
||||
|
||||
let simplifyDefault = searchParams.simplify === undefined || searchParams.simplify === "true",
|
||||
inputContent = !!searchParams.exp,
|
||||
hideIntermediate = searchParams.hideIntermediate === "true"
|
||||
|
||||
const [simplifyEnabled, setSimplifyEnabled] = createSignal(simplifyDefault)
|
||||
const [fetchResult, setFetchResult] = createSignal<FetchResult | null>(null)
|
||||
|
||||
const hideOptions: Option[] = [
|
||||
{ name: "Show all result", value: "NONE" },
|
||||
{ name: "Hide true results", value: "TRUE" },
|
||||
{ name: "Hide false results", value: "FALSE" }
|
||||
]
|
||||
|
||||
const [hideValues, setHideValues] = createSignal(hideOptions[0])
|
||||
|
||||
const sortOptions: Option[] = [
|
||||
{ name: "Sort by default", value: "DEFAULT" },
|
||||
{ name: "Sort by true first", value: "TRUE_FIRST" },
|
||||
{ name: "Sort by false first", value: "FALSE_FIRST" }
|
||||
]
|
||||
|
||||
const [sortValues, setSortValues] = createSignal(sortOptions[0])
|
||||
const [hideIntermediates, setHideIntermediates] = createSignal(hideIntermediate)
|
||||
const [isLoaded, setIsLoaded] = createSignal<boolean | null>(null)
|
||||
const [error, setError] = createSignal<{ title: string; message: string } | null>(null)
|
||||
const [useLocalhost, setUseLocalhost] = createSignal(false)
|
||||
|
||||
/**
|
||||
* Updates the state of the current expression to the new search with all whitespace removed.
|
||||
* If the element is not found, reset.
|
||||
*/
|
||||
function onClick(e: Event): void {
|
||||
e.preventDefault() // Stops the page from reloading onClick
|
||||
const exp = inputElement?.value
|
||||
|
||||
if (exp) {
|
||||
setSearchParams({
|
||||
exp,
|
||||
simplify: simplifyEnabled(),
|
||||
hide: hideValues().value,
|
||||
sort: sortValues().value,
|
||||
hideIntermediate: hideIntermediates()
|
||||
})
|
||||
|
||||
getFetchResult(exp)
|
||||
}
|
||||
}
|
||||
|
||||
function getFetchResult(exp: string | null): void {
|
||||
setFetchResult(null)
|
||||
|
||||
if (exp && exp !== "") {
|
||||
exp = replaceOperators(exp)
|
||||
setError(null)
|
||||
setIsLoaded(false)
|
||||
|
||||
fetch(`${fetchUrls[useLocalhost() ? 0 : 1]}${encodeURIComponent(exp)}?
|
||||
simplify=${simplifyEnabled()}&hide=${hideValues().value}&sort=${sortValues().value}&caseSensitive=false&
|
||||
hideIntermediate=${hideIntermediates()}`)
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
if (res.status !== "OK" && !res.ok) {
|
||||
return setError({ title: "Input error", message: res.message })
|
||||
}
|
||||
return setFetchResult(res)
|
||||
})
|
||||
.catch((err) => setError({ title: "Fetch error", message: err.toString() }))
|
||||
.finally(() => setIsLoaded(true))
|
||||
}
|
||||
}
|
||||
|
||||
onMount((): void => {
|
||||
if (searchParams.exp) {
|
||||
const exp = searchParams.exp
|
||||
if (exp && inputElement) {
|
||||
inputElement.value = exp
|
||||
}
|
||||
const hide = searchParams.hide
|
||||
if (hide) {
|
||||
setHideValues(hideOptions.find((o) => o.value === hide) ?? hideOptions[0])
|
||||
}
|
||||
const sort = searchParams.sort
|
||||
if (sort) {
|
||||
setSortValues(sortOptions.find((o) => o.value === sort) ?? sortOptions[0])
|
||||
}
|
||||
|
||||
getFetchResult(exp)
|
||||
}
|
||||
|
||||
// Focuses searchbar on load
|
||||
if (!isTouch()) {
|
||||
inputElement?.focus()
|
||||
}
|
||||
})
|
||||
|
||||
const tableId = "truth-table"
|
||||
const filenameId = "excel-filename"
|
||||
|
||||
function _exportToExcel(): void {
|
||||
const value = getElementById<HTMLInputElement>(filenameId)?.value
|
||||
exportToExcel({
|
||||
name: value !== "" ? value : undefined,
|
||||
tableId
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout title={"Truth tables"}>
|
||||
<Show when={import.meta.env.DEV ?? false} keyed>
|
||||
(DEV) Use localhost:
|
||||
<MySwitch title={"Use localhost"} defaultValue={false} onChange={setUseLocalhost} />
|
||||
</Show>
|
||||
|
||||
<div id={"truth-content"}>
|
||||
<div class={"mx-auto max-w-2xl"}>
|
||||
<HowTo />
|
||||
|
||||
<form class={"flex-row-center"} onSubmit={onClick} autocomplete={"off"}>
|
||||
<Search ref={inputElement} typingDefault={inputContent} />
|
||||
|
||||
<Button
|
||||
id={"truth-input-button"}
|
||||
title={"Generate (Enter)"}
|
||||
type={"submit"}
|
||||
className={"min-w-50px ml-2 h-10"}
|
||||
children={"Generate"}
|
||||
/>
|
||||
</form>
|
||||
|
||||
{/* Options row */}
|
||||
<Row className={"my-1 gap-2"}>
|
||||
<span class={"h-min"}>{"Simplify"}: </span>
|
||||
|
||||
<MySwitch
|
||||
onChange={setSimplifyEnabled}
|
||||
defaultValue={simplifyEnabled()}
|
||||
title={"Simplify"}
|
||||
name={"Turn on/off simplify expressions"}
|
||||
className={"mx-1"}
|
||||
/>
|
||||
|
||||
<div class={"relative h-min"}>
|
||||
<MyMenu
|
||||
title={"Filter results"}
|
||||
id={"filter-results"}
|
||||
button={
|
||||
<Show
|
||||
when={hideValues().value !== "NONE"}
|
||||
children={
|
||||
<Icon
|
||||
path={eyeSlash}
|
||||
aria-label={"An eye with a slash through it"}
|
||||
class={`mx-1 ${hideValues().value === "TRUE" ? "text-green-500" : "text-red-500"}`}
|
||||
/>
|
||||
}
|
||||
fallback={<Icon path={eye} aria-label={"An eye"} class={"mx-1"} />}
|
||||
keyed
|
||||
/>
|
||||
}
|
||||
children={
|
||||
<For each={hideOptions}>
|
||||
{(option) => (
|
||||
<SingleMenuItem
|
||||
onClick={() => setHideValues(option)}
|
||||
option={option}
|
||||
currentValue={hideValues}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
}
|
||||
itemsClassName={"right-0"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={"relative h-min"}>
|
||||
<MyMenu
|
||||
title={"Sort results"}
|
||||
id={"sort-results"}
|
||||
button={
|
||||
<Icon
|
||||
path={funnel}
|
||||
aria-label={"Filter"}
|
||||
class={`h-6 w-6 ${
|
||||
sortValues().value === "TRUE_FIRST"
|
||||
? "text-green-500"
|
||||
: sortValues().value === "FALSE_FIRST" && "text-red-500"
|
||||
}`}
|
||||
/>
|
||||
}
|
||||
children={
|
||||
<For each={sortOptions}>
|
||||
{(option) => (
|
||||
<SingleMenuItem
|
||||
option={option}
|
||||
currentValue={sortValues}
|
||||
onClick={() => setSortValues(option)}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
}
|
||||
itemsClassName={"right-0"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<MySwitch
|
||||
title={"Hide intermediate values"}
|
||||
onChange={setHideIntermediates}
|
||||
defaultValue={hideIntermediates()}
|
||||
/>
|
||||
|
||||
<Show when={isLoaded() && error() === null} keyed>
|
||||
<MyDialog
|
||||
title={"Download"}
|
||||
description={"Export current table (.xlsx)"}
|
||||
button={
|
||||
<>
|
||||
<p class={"sr-only"}>{"Download"}</p>
|
||||
<Icon aria-label={"Download"} path={arrowDownTray} />
|
||||
</>
|
||||
}
|
||||
callback={_exportToExcel}
|
||||
acceptButtonName={"Download"}
|
||||
cancelButtonName={"Cancel"}
|
||||
buttonClass={`float-right`}
|
||||
buttonTitle={"Export current table"}
|
||||
acceptButtonId={"download-accept"}
|
||||
>
|
||||
<p>{"Filename"}:</p>
|
||||
<Input
|
||||
className={"border-rounded h-10 px-2"}
|
||||
id={filenameId}
|
||||
placeholder={"Truth Table"}
|
||||
/>
|
||||
</MyDialog>
|
||||
</Show>
|
||||
</Row>
|
||||
|
||||
<Show when={error()} keyed>
|
||||
<ErrorBox
|
||||
title={error()?.title ?? "Error"}
|
||||
error={error()?.message ?? "Something went wrong"}
|
||||
/>
|
||||
</Show>
|
||||
|
||||
<Show when={isLoaded() === false} keyed>
|
||||
<Icon
|
||||
path={arrowPath}
|
||||
aria-label={"Loading indicator"}
|
||||
class={"mx-auto animate-spin"}
|
||||
/>
|
||||
</Show>
|
||||
|
||||
<Show when={simplifyEnabled() && (fetchResult()?.orderOperations?.length ?? 0) > 0} keyed>
|
||||
<ShowMeHow fetchResult={fetchResult} />
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<Show when={isLoaded() && error() === null} keyed>
|
||||
<Show when={simplifyEnabled()} keyed>
|
||||
<InfoBox
|
||||
className={"mx-auto w-fit pb-1 text-center text-lg"}
|
||||
title={"Output:"}
|
||||
id={"expression-output"}
|
||||
>
|
||||
<p>{fetchResult()?.after}</p>
|
||||
</InfoBox>
|
||||
</Show>
|
||||
|
||||
<div class={"m-2 flex justify-center"}>
|
||||
<div id={"table"} class={"h-[45rem] overflow-auto"}>
|
||||
<TruthTable
|
||||
header={fetchResult()?.header ?? undefined}
|
||||
table={fetchResult()?.table?.truthMatrix}
|
||||
id={tableId}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export default TruthTablePage
|
||||
|
||||
interface SingleMenuItem {
|
||||
option: Option
|
||||
currentValue?: Accessor<Option>
|
||||
onClick: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>
|
||||
}
|
||||
|
||||
const SingleMenuItem: Component<SingleMenuItem> = ({ option, currentValue, onClick }) => {
|
||||
const isSelected = () => currentValue?.().value === option.value
|
||||
return (
|
||||
<button class={`flex-row-center cursor-pointer last:mb-1 hover:underline`} onClick={onClick}>
|
||||
<Icon
|
||||
path={check}
|
||||
aria-label={isSelected() ? "A checkmark" : "Nothing"}
|
||||
class={`text-white ${!isSelected() && "invisible"}`}
|
||||
/>
|
||||
{option.name}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
const ErrorBox: Component<{ title: string; error: string }> = ({ title, error }) => (
|
||||
<InfoBox className={"mx-auto w-fit text-center"} title={title} error={true}>
|
||||
<p>{error}</p>
|
||||
</InfoBox>
|
||||
)
|
||||
|
||||
interface ShowMeHowProps {
|
||||
fetchResult: Accessor<FetchResult | null>
|
||||
}
|
||||
|
||||
const ShowMeHow: Component<ShowMeHowProps> = ({ fetchResult }) => (
|
||||
<MyDisclosureContainer>
|
||||
<MyDisclosure title={"Show me how it's done"}>
|
||||
<table class={"table"}>
|
||||
<tbody>
|
||||
<For each={fetchResult()?.orderOperations}>{orderOperationRow()}</For>
|
||||
</tbody>
|
||||
</table>
|
||||
</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 orderOperationRow = () => (operation: OrderOfOperation, index: Accessor<number>) => (
|
||||
<tr class={"border-b border-dotted border-gray-500"}>
|
||||
<td>{index() + 1}:</td>
|
||||
<td class={"px-2"}>
|
||||
{
|
||||
<For each={diffChars(operation.before, operation.after)}>
|
||||
{(part) => (
|
||||
<span class={`${part.added && "bg-green-700"} ${part.removed && "bg-red-700"}`}>
|
||||
{part.value}
|
||||
</span>
|
||||
)}
|
||||
</For>
|
||||
}
|
||||
|
||||
<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>
|
||||
<td>
|
||||
{"using"}: {operation.law}
|
||||
</td>
|
||||
</Show>
|
||||
</tr>
|
||||
)
|
||||
|
||||
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>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>
|
||||
)
|
11
src/types/env.d.ts
vendored
11
src/types/env.d.ts
vendored
@ -1,11 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_FETCH_URL: string
|
||||
readonly VITE_FETCH_PATH: string
|
||||
readonly VITE_FETCH_FULL: string
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
70
src/types/types.d.ts
vendored
70
src/types/types.d.ts
vendored
@ -1,70 +0,0 @@
|
||||
interface SimpleProps<T extends HTMLElement = HTMLElement> {
|
||||
name?: string
|
||||
className?: string
|
||||
style?: import("solid-js").JSX.CSSProperties
|
||||
id?: string
|
||||
title?: string
|
||||
ref?: T
|
||||
}
|
||||
|
||||
interface ChildProps<T extends HTMLElement = HTMLInputElement> extends SimpleProps<T> {
|
||||
children?: import("solid-js").JSX.Element
|
||||
}
|
||||
|
||||
interface LinkProps extends ChildProps {
|
||||
to?: string
|
||||
rel?: string
|
||||
newTab?: boolean
|
||||
}
|
||||
|
||||
interface TitleProps<T extends HTMLElement = HTMLElement> extends ChildProps<T> {
|
||||
title?: string
|
||||
}
|
||||
|
||||
interface ButtonProps extends TitleProps {
|
||||
onClick?: import("solid-js").JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>
|
||||
type?: "button" | "submit" | "reset"
|
||||
}
|
||||
|
||||
interface InputProps<T extends HTMLElement = HTMLInputElement> extends TitleProps<T> {
|
||||
onInput?: import("solid-js").JSX.EventHandlerUnion<T, Event>
|
||||
placeholder?: string
|
||||
required?: boolean
|
||||
type?: string
|
||||
}
|
||||
|
||||
interface CardProps extends LinkProps {
|
||||
title?: string
|
||||
}
|
||||
|
||||
type Expression = {
|
||||
leading: string
|
||||
left: Expression | null
|
||||
operator: Operator | null
|
||||
right: Expression | null
|
||||
trailing: string
|
||||
atomic: string | null
|
||||
}
|
||||
|
||||
type Operator = "AND" | "OR" | "NOT" | "IMPLICATION"
|
||||
|
||||
type Table = boolean[][]
|
||||
|
||||
type OrderOfOperation = {
|
||||
before: string
|
||||
after: string
|
||||
law: string
|
||||
}
|
||||
|
||||
type FetchResult = {
|
||||
status: string
|
||||
version: string | null
|
||||
before: string
|
||||
after: string
|
||||
orderOperations: OrderOfOperation[] | null
|
||||
expression: Expression | null
|
||||
header: string[] | null
|
||||
table: {
|
||||
truthMatrix: Table
|
||||
} | null
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* 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 <T>document.getElementById(id)
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
import { type BookType, utils, write, writeFile } from "xlsx"
|
||||
|
||||
/**
|
||||
* Exports the generated truth table to an excel (.xlsx) file
|
||||
*
|
||||
* @param type The downloaded files extension. Default is "xlsx"
|
||||
* @param name The name of the file, excluding the extension. Default is "Truth Table"
|
||||
* @param dl
|
||||
* @param tableId The id of the table to export
|
||||
* @returns {any}
|
||||
* @author SheetJS
|
||||
* @link https://cdn.sheetjs.com/
|
||||
* @license Apache 2.0 License
|
||||
* SheetJS Community Edition -- https://sheetjs.com/
|
||||
*
|
||||
* Copyright (C) 2012-present SheetJS LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export function exportToExcel({
|
||||
type = "xlsx",
|
||||
name = "Truth Table",
|
||||
dl = false,
|
||||
tableId
|
||||
}: {
|
||||
type?: BookType
|
||||
name?: string
|
||||
dl?: boolean
|
||||
tableId: string
|
||||
}): any {
|
||||
const element = document.getElementById(tableId)
|
||||
const wb = utils.table_to_book(element, { sheet: "sheet1" })
|
||||
return dl
|
||||
? write(wb, { bookType: type, bookSST: true, type: "base64" })
|
||||
: writeFile(wb, name + "." + type)
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
/**
|
||||
* 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 {
|
||||
return expression
|
||||
.replaceAll(/\//g, "|")
|
||||
.replaceAll(/¬/g, "!")
|
||||
.replaceAll(/\sOR\s/gi, " | ")
|
||||
.replaceAll(/\sAND\s/gi, " & ")
|
||||
.replaceAll(/\s(IMPLICATION|IMP)\s/gi, " -> ")
|
||||
.replaceAll(/\sNOT\s/gi, " !")
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
export function failureFunction(P: String, m = P.length): number[] {
|
||||
// No proper prefix for string of length 1:
|
||||
const arr = [0]
|
||||
let i = 0,
|
||||
j = 1
|
||||
|
||||
while (j < m) {
|
||||
if (P[i] == P[j]) {
|
||||
i++
|
||||
arr.push(i)
|
||||
j++
|
||||
}
|
||||
// The first character didn't match:
|
||||
else if (i == 0) {
|
||||
arr.push(0)
|
||||
j++
|
||||
}
|
||||
// Mismatch after at least one matching character:
|
||||
else {
|
||||
i = arr[i - 1]
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Check if the device is touch enabled
|
||||
* @returns {boolean} True if the device is touch enabled, otherwise false
|
||||
*/
|
||||
export function isTouch(): boolean {
|
||||
return "ontouchstart" in window || navigator.maxTouchPoints > 0
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./index.html", "./404.html", "./src/**/*.{js,ts,jsx,tsx,css,md,mdx,html,json,scss}"],
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"default-bg": "#181a1b"
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: []
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
"types": ["vite/client"],
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"strict": true
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
import { defineConfig } from "vite"
|
||||
import solidPlugin from "vite-plugin-solid"
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [solidPlugin()],
|
||||
server: {
|
||||
port: 3000
|
||||
},
|
||||
build: {
|
||||
target: "esnext",
|
||||
rollupOptions: {
|
||||
input: {
|
||||
main: "index.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user