Styled operator pages

This commit is contained in:
Felix Kaspar
2024-08-12 21:05:52 +02:00
parent 51e35ee0ee
commit e806ee8015
14 changed files with 148 additions and 57 deletions

View File

@@ -23,6 +23,7 @@
"react-dom": "^18.2.0",
"react-i18next": "^13.3.1",
"react-icons": "^4.11.0",
"react-material-symbols": "^4.4.0",
"react-router-bootstrap": "^0.26.2",
"react-router-dom": "^6.18.0",
"vite-plugin-node-polyfills": "^0.21.0",

View File

@@ -0,0 +1,22 @@
.fields {
margin: 20px 0;
}
.fields input, select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.submit {
background-color: var(--md-sys-color-primary);;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
cursor: pointer;
}

View File

@@ -0,0 +1,28 @@
import Joi from "@stirling-tools/joi";
import { GenericField } from "./fields/GenericField";
import React from "react";
import styles from "./BuildForm.module.css";
interface BuildFormProps {
/** The text to display inside the button */
schemaDescription: Joi.Description | undefined;
onSubmit: React.FormEventHandler<HTMLFormElement>;
}
export function BuildForm({ schemaDescription, onSubmit }: BuildFormProps) {
console.log("Render Build Fields", schemaDescription);
const values = (schemaDescription?.keys as any)?.values.keys as { [key: string]: Joi.Description};
return (
<form onSubmit={(e) => { onSubmit(e); e.preventDefault(); }}>
<div className={styles.fields}>
{
values ? Object.keys(values).map((key) => {
return (<GenericField key={key} fieldName={key} joiDefinition={values[key]} />)
}) : undefined
}
</div>
<input className={styles.submit} type="submit" value="Submit" />
</form>
);
}

View File

@@ -1,8 +1,10 @@
import { useEffect, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { getSchemaByName } from "@stirling-pdf/shared-operations/src/workflow/operatorAccessor";
import styles from './OperatorCard.module.css';
import { MaterialSymbol, MaterialSymbolProps } from 'react-material-symbols';
interface OperatorCardProps {
/** The text to display inside the button */
operatorInternalName: string;
@@ -10,22 +12,21 @@ interface OperatorCardProps {
export function OperatorCard({ operatorInternalName }: OperatorCardProps) {
const [schema, setSchema] = useState<any>(undefined); // TODO: Type as joi type
const [materialSymbolName, setMaterialSymbolName] = useState<MaterialSymbolProps["icon"]>("error");
useEffect(() => {
getSchemaByName(operatorInternalName).then(schema => {
if(schema) {
setSchema(schema.schema);
setMaterialSymbolName(schema.materialSymbolName || "error");
}
});
}, [operatorInternalName]);
return (
<a key={operatorInternalName} href={"/operators/" + operatorInternalName}>
<div>
</div>
<div className={styles.operator_card}>
<h3>{ schema?.describe().flags.label }</h3>
<h3><MaterialSymbol icon={materialSymbolName} size={30} fill grade={-25} color='black'></MaterialSymbol> { schema?.describe().flags.label }</h3>
{ schema?.describe().flags.description }
</div>
</a>

View File

@@ -1,24 +0,0 @@
import Joi from "@stirling-tools/joi";
import { GenericField } from "./GenericField";
import React from "react";
interface BuildFieldsProps {
/** The text to display inside the button */
schemaDescription: Joi.Description | undefined;
onSubmit: React.FormEventHandler<HTMLFormElement>;
}
export function BuildFields({ schemaDescription, onSubmit }: BuildFieldsProps) {
console.log("Render Build Fields", schemaDescription);
const values = (schemaDescription?.keys as any)?.values.keys as { [key: string]: Joi.Description};
return (
<form onSubmit={(e) => { onSubmit(e); e.preventDefault(); }}>
{
values ? Object.keys(values).map((key) => {
return (<GenericField key={key} fieldName={key} joiDefinition={values[key]} />)
}) : undefined
}
<input type="submit" value="Submit" />
</form>
);
}

View File

@@ -0,0 +1,10 @@
.custom_file_upload input[type="file"] {
display: none;
}
.custom_file_upload {
border: 1px solid #ccc;
display: inline-block;
padding: 6px 12px;
cursor: pointer;
}

View File

@@ -0,0 +1,29 @@
import { forwardRef, ForwardedRef, FormEvent } from 'react';
import styles from "./InputField.module.css";
function InputField(_props: {}, inputRef: ForwardedRef<HTMLInputElement>) {
function onChange(e: FormEvent<HTMLInputElement>) {
const files = (e.target as HTMLInputElement).files;
if(files) {
const filesArray: File[] = Array.from(files as any);
for (let i = 0; i < files.length; i++) {
const file = filesArray[i];
if(file) {
console.log(file.name);
}
else
throw new Error("This should not happen. Contact maintainers.");
}
}
}
return (
<label className={styles.custom_file_upload}>
<input onChange={onChange} type="file" id="pdfFile" accept=".pdf" multiple ref={inputRef}/>
Upload your PDF(s)!
</label>
)
}
export default forwardRef(InputField);

View File

@@ -4,6 +4,7 @@ import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./root.css";
import 'react-material-symbols/rounded';
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>

View File

@@ -1,16 +1,15 @@
import { Link } from "react-router-dom";
import { Fragment, useEffect } from "react";
import { Fragment, useEffect, useRef } from "react";
import { BaseSyntheticEvent, useRef, useState } from "react";
import { Operator, OperatorSchema } from "@stirling-pdf/shared-operations/src/functions";
import Joi from "@stirling-tools/joi";
import { BuildFields } from "../components/fields/BuildFields";
import { BaseSyntheticEvent, useState } from "react";
import { BuildForm } from "../components/BuildForm";
import { getOperatorByName, getSchemaByName } from "@stirling-pdf/shared-operations/src/workflow/operatorAccessor";
import { PdfFile, RepresentationType } from "@stirling-pdf/shared-operations/src/wrappers/PdfFile";
import { Action } from "@stirling-pdf/shared-operations/declarations/Action";
import { useLocation } from 'react-router-dom'
import InputField from "../components/fields/InputField";
function Dynamic() {
const [schema, setSchema] = useState<any>(undefined); // TODO: Type as joi type
@@ -26,32 +25,19 @@ function Dynamic() {
}
});
}, [location]);
return (
<Fragment>
<h3>{ schema?.describe().flags.label }</h3>
{ schema?.describe().flags.description }
<br />
<input type="file" id="pdfFile" accept=".pdf" multiple />
<br />
<div id="values">
<BuildFields schemaDescription={schema?.describe()} onSubmit={handleSubmit}></BuildFields>
</div>
</Fragment>
);
const inputRef = useRef<HTMLInputElement>();
async function handleSubmit(e: BaseSyntheticEvent) {
const formData = new FormData(e.target);
const values = Object.fromEntries(formData.entries());
let action: Action = {type: operatorInternalName, values: values};
// Validate PDF File
// Createing the pdffile before validation because joi cant handle it for some reason and I can't fix the underlying issue / I want to make progress, wasted like 3 hours on this already. TODO: The casting should be done in JoiPDFFileSchema.ts if done correctly...
const files = (document.getElementById("pdfFile") as HTMLInputElement).files;
const files = inputRef.current?.files;
const inputs: PdfFile[] = [];
if(files) {
@@ -93,6 +79,19 @@ function Dynamic() {
});
}
};
return (
<Fragment>
<h1>{ schema?.describe().flags.label }</h1>
<h2>{ schema?.describe().flags.description }</h2>
<InputField ref={inputRef} />
<div id="values">
<BuildForm schemaDescription={schema?.describe()} onSubmit={handleSubmit}></BuildForm>
</div>
</Fragment>
);
}

View File

@@ -144,4 +144,8 @@ body {
a {
text-decoration: inherit;
color: inherit;
}
.material-symbols {
vertical-align: top;
}