mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-18 05:29:33 +02:00
Usable proof of concept of generated variables
This commit is contained in:
62
src/datatables/data/american_wire_gauge.ts
Normal file
62
src/datatables/data/american_wire_gauge.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
export default {
|
||||
title: 'American Wire Gauge',
|
||||
columns: [
|
||||
{
|
||||
diameter: {
|
||||
title: 'Diameter',
|
||||
type: 'number',
|
||||
unit: 'mm'
|
||||
}
|
||||
}
|
||||
],
|
||||
data: {
|
||||
'0000': { diameter: 11.684 },
|
||||
'000': { diameter: 10.405 },
|
||||
'00': { diameter: 9.266 },
|
||||
'0': { diameter: 8.251 },
|
||||
'(4/0)': { diameter: 11.684 },
|
||||
'(3/0)': { diameter: 10.405 },
|
||||
'(2/0)': { diameter: 9.266 },
|
||||
'(1/0)': { diameter: 8.251 },
|
||||
'1': { diameter: 7.348 },
|
||||
'2': { diameter: 6.544 },
|
||||
'3': { diameter: 5.827 },
|
||||
'4': { diameter: 5.189 },
|
||||
'5': { diameter: 4.621 },
|
||||
'6': { diameter: 4.115 },
|
||||
'7': { diameter: 3.665 },
|
||||
'8': { diameter: 3.264 },
|
||||
'9': { diameter: 2.906 },
|
||||
'10': { diameter: 2.588 },
|
||||
'11': { diameter: 2.305 },
|
||||
'12': { diameter: 2.053 },
|
||||
'13': { diameter: 1.828 },
|
||||
'14': { diameter: 1.628 },
|
||||
'15': { diameter: 1.45 },
|
||||
'16': { diameter: 1.291 },
|
||||
'17': { diameter: 1.15 },
|
||||
'18': { diameter: 1.024 },
|
||||
'19': { diameter: 0.912 },
|
||||
'20': { diameter: 0.812 },
|
||||
'21': { diameter: 0.723 },
|
||||
'22': { diameter: 0.644 },
|
||||
'23': { diameter: 0.573 },
|
||||
'24': { diameter: 0.511 },
|
||||
'25': { diameter: 0.455 },
|
||||
'26': { diameter: 0.405 },
|
||||
'27': { diameter: 0.361 },
|
||||
'28': { diameter: 0.321 },
|
||||
'29': { diameter: 0.286 },
|
||||
'30': { diameter: 0.255 },
|
||||
'31': { diameter: 0.227 },
|
||||
'32': { diameter: 0.202 },
|
||||
'33': { diameter: 0.18 },
|
||||
'34': { diameter: 0.16 },
|
||||
'35': { diameter: 0.143 },
|
||||
'36': { diameter: 0.127 },
|
||||
'37': { diameter: 0.113 },
|
||||
'38': { diameter: 0.101 },
|
||||
'39': { diameter: 0.0897 },
|
||||
'40': { diameter: 0.0799 }
|
||||
}
|
||||
};
|
3
src/datatables/data/index.ts
Normal file
3
src/datatables/data/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const allDataTables: { [key: string]: { [key: string]: any } } = {
|
||||
'american-wire-gauge': {}
|
||||
};
|
20
src/datatables/data/material_electrical_properties.ts
Normal file
20
src/datatables/data/material_electrical_properties.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export default {
|
||||
title: 'Material Electrical Properties',
|
||||
columns: [
|
||||
{
|
||||
resistivity_20c: {
|
||||
title: 'Resistivity at 20°C',
|
||||
type: 'number',
|
||||
unit: 'Ω/m'
|
||||
}
|
||||
}
|
||||
],
|
||||
data: {
|
||||
copper: {
|
||||
resistivity: 1.68e-8
|
||||
},
|
||||
aluminum: {
|
||||
resistivity: 2.82e-8
|
||||
}
|
||||
}
|
||||
};
|
17
src/datatables/index.ts
Normal file
17
src/datatables/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { DataTable } from './types.ts';
|
||||
import { allDataTables } from './data/index';
|
||||
|
||||
export async function getDataTable(name: string): Promise<DataTable> {
|
||||
const x = await import(`./${name}`);
|
||||
return x.default;
|
||||
}
|
||||
|
||||
export async function listDataTables(): Promise<{ name: string }[]> {
|
||||
const x: { name: string }[] = [];
|
||||
for (const key in allDataTables) {
|
||||
x.push({ name: key });
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
export { DataTable };
|
19
src/datatables/types.ts
Normal file
19
src/datatables/types.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Represents a set of rows indexed by a key.
|
||||
Used for calculator presets
|
||||
|
||||
*/
|
||||
export interface DataTable {
|
||||
[key: string]: {
|
||||
title: string;
|
||||
/* A JSON schema properties */
|
||||
columns: {
|
||||
[key: string]: any;
|
||||
};
|
||||
data: {
|
||||
[key: string]: {
|
||||
[key: string]: any;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
3
src/pages/tools/number/generic-calc/data/index.ts
Normal file
3
src/pages/tools/number/generic-calc/data/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import ohmslaw from './ohms_law';
|
||||
|
||||
export default [ohmslaw];
|
29
src/pages/tools/number/generic-calc/data/ohms_law.ts
Normal file
29
src/pages/tools/number/generic-calc/data/ohms_law.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { GenericCalcType } from './types';
|
||||
|
||||
const ohmsLawCalc: GenericCalcType = {
|
||||
title: "Ohm's Law",
|
||||
name: 'ohms-law',
|
||||
formula: 'V = I * R',
|
||||
selections: [],
|
||||
variables: [
|
||||
{
|
||||
name: 'V',
|
||||
title: 'Voltage',
|
||||
unit: 'V',
|
||||
default: 5
|
||||
},
|
||||
{
|
||||
name: 'I',
|
||||
title: 'Current',
|
||||
unit: 'A',
|
||||
default: 1
|
||||
},
|
||||
{
|
||||
name: 'R',
|
||||
title: 'Resistance',
|
||||
unit: 'Ω'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default ohmsLawCalc;
|
21
src/pages/tools/number/generic-calc/data/types.ts
Normal file
21
src/pages/tools/number/generic-calc/data/types.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export interface GenericCalcType {
|
||||
title: string;
|
||||
name: string;
|
||||
formula: string;
|
||||
selections?: {
|
||||
title: string;
|
||||
source: string;
|
||||
default: string;
|
||||
bind: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}[];
|
||||
variables: {
|
||||
name: string;
|
||||
title: string;
|
||||
unit: string;
|
||||
|
||||
// If absence, assume it's the default target var
|
||||
default?: number;
|
||||
}[];
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
Box,
|
||||
InputLabel,
|
||||
Autocomplete,
|
||||
TextField,
|
||||
Radio,
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -13,54 +14,41 @@ import ToolContent from '@components/ToolContent';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||
import { GetGroupsType, UpdateField } from '@components/options/ToolOptions';
|
||||
import { UpdateField } from '@components/options/ToolOptions';
|
||||
import { InitialValuesType } from './types';
|
||||
import type { GenericCalcType } from './data/types';
|
||||
import type { DataTable } from 'datatables';
|
||||
import { getDataTable } from 'datatables';
|
||||
|
||||
import nerdamer from 'nerdamer';
|
||||
import 'nerdamer/Algebra';
|
||||
import 'nerdamer/Solve';
|
||||
import 'nerdamer/Calculus';
|
||||
|
||||
const ohmsLawCalc: {
|
||||
name: string;
|
||||
formula: string;
|
||||
variables: {
|
||||
name: string;
|
||||
title: string;
|
||||
unit: string;
|
||||
}[];
|
||||
} = {
|
||||
name: "Ohm's Law Calculator",
|
||||
formula: 'V = I * R',
|
||||
variables: [
|
||||
{
|
||||
name: 'V',
|
||||
title: 'Voltage',
|
||||
unit: 'V'
|
||||
},
|
||||
{
|
||||
name: 'I',
|
||||
title: 'Current',
|
||||
unit: 'A'
|
||||
},
|
||||
{
|
||||
name: 'R',
|
||||
title: 'Resistance',
|
||||
unit: 'Ω'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default function makeTool(): React.JSXElementConstructor<ToolComponentProps> {
|
||||
export default async function makeTool(
|
||||
calcData: GenericCalcType
|
||||
): Promise<React.JSXElementConstructor<ToolComponentProps>> {
|
||||
const initialValues: InitialValuesType = {
|
||||
outputVariable: '',
|
||||
vars: {}
|
||||
vars: {},
|
||||
presets: {}
|
||||
};
|
||||
|
||||
const dataTables: { [key: string]: DataTable } = {};
|
||||
|
||||
for (const selection of calcData.selections || []) {
|
||||
dataTables[selection.source] = await getDataTable(selection.source);
|
||||
}
|
||||
|
||||
return function GenericCalc({ title }: ToolComponentProps) {
|
||||
const [result, setResult] = useState<string>('');
|
||||
const [shortResult, setShortResult] = useState<string>('');
|
||||
|
||||
// For UX purposes we need to track what vars are
|
||||
const [valsBoundToPreset, setValsBoundToPreset] = useState<{
|
||||
[key: string]: string;
|
||||
}>({});
|
||||
|
||||
const updateVarField = (
|
||||
name: string,
|
||||
value: number,
|
||||
@@ -83,12 +71,89 @@ export default function makeTool(): React.JSXElementConstructor<ToolComponentPro
|
||||
updateFieldFunc('outputVariable', varName);
|
||||
};
|
||||
|
||||
const handleSelectedPresetChange = (
|
||||
selection: string,
|
||||
preset: string,
|
||||
currentValues: InitialValuesType,
|
||||
updateFieldFunc: UpdateField<InitialValuesType>
|
||||
) => {
|
||||
const newValsBoundToPreset = { ...valsBoundToPreset };
|
||||
|
||||
const newPresets = { ...currentValues.presets };
|
||||
newPresets[selection] = preset;
|
||||
updateFieldFunc('presets', newPresets);
|
||||
|
||||
// Clear old selection
|
||||
for (const key in valsBoundToPreset) {
|
||||
if (valsBoundToPreset[key] === selection) {
|
||||
delete newValsBoundToPreset[key];
|
||||
}
|
||||
}
|
||||
|
||||
const selectionData = calcData.selections?.find(
|
||||
(sel) => sel.title === selection
|
||||
);
|
||||
|
||||
if (preset != '<custom>') {
|
||||
if (selectionData) {
|
||||
for (const key in selectionData.bind) {
|
||||
newValsBoundToPreset[key] = selection;
|
||||
updateVarField(
|
||||
key,
|
||||
dataTables[selectionData.source].data[preset][
|
||||
selectionData.bind[key]
|
||||
],
|
||||
currentValues,
|
||||
updateFieldFunc
|
||||
);
|
||||
}
|
||||
} else {
|
||||
setValsBoundToPreset(newValsBoundToPreset);
|
||||
throw new Error(
|
||||
`Preset "${preset}" is not valid for selection "${selection}"`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setValsBoundToPreset(newValsBoundToPreset);
|
||||
};
|
||||
|
||||
calcData.variables.forEach((variable) => {
|
||||
if (variable.default === undefined) {
|
||||
initialValues.vars[variable.name] = {
|
||||
value: NaN,
|
||||
unit: variable.unit
|
||||
};
|
||||
initialValues.outputVariable = variable.name;
|
||||
} else {
|
||||
initialValues.vars[variable.name] = {
|
||||
value: variable.default || 0,
|
||||
unit: variable.unit
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
calcData.selections?.forEach((selection) => {
|
||||
initialValues.presets[selection.title] = selection.default;
|
||||
if (selection.default == '<custom>') return;
|
||||
for (const key in selection.bind) {
|
||||
initialValues.vars[key] = {
|
||||
value:
|
||||
dataTables[selection.source].data[selection.default][
|
||||
selection.bind[key]
|
||||
],
|
||||
unit: dataTables[selection.source].cols[selection.bind[key]].unit
|
||||
};
|
||||
valsBoundToPreset[key] = selection.default;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
inputComponent={null}
|
||||
resultComponent={
|
||||
<ToolTextResult title={ohmsLawCalc.name} value={result} />
|
||||
<ToolTextResult title={calcData.title} value={result} />
|
||||
}
|
||||
initialValues={initialValues}
|
||||
toolInfo={{
|
||||
@@ -97,6 +162,50 @@ export default function makeTool(): React.JSXElementConstructor<ToolComponentPro
|
||||
'Common mathematical equations that can be used in calculations.'
|
||||
}}
|
||||
getGroups={({ values, updateField }) => [
|
||||
{
|
||||
title: 'Presets',
|
||||
component: (
|
||||
<Box>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Option</TableCell>
|
||||
<TableCell>Value</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{calcData.selections?.map((preset) => (
|
||||
<TableRow key={preset.title}>
|
||||
<TableCell>{preset.title}</TableCell>
|
||||
<TableCell>
|
||||
<Autocomplete
|
||||
disablePortal
|
||||
id="combo-box-demo"
|
||||
value={values.presets[preset.title]}
|
||||
options={Object.keys(
|
||||
dataTables[preset.source].data
|
||||
).sort()}
|
||||
sx={{ width: 300 }}
|
||||
onChange={(event, newValue) => {
|
||||
handleSelectedPresetChange(
|
||||
preset.title,
|
||||
newValue || '',
|
||||
values,
|
||||
updateField
|
||||
);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Preset" />
|
||||
)}
|
||||
></Autocomplete>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Input Variables',
|
||||
component: (
|
||||
@@ -110,20 +219,23 @@ export default function makeTool(): React.JSXElementConstructor<ToolComponentPro
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{ohmsLawCalc.variables.map((variable) => (
|
||||
{calcData.variables.map((variable) => (
|
||||
<TableRow key={variable.name}>
|
||||
<TableCell>{variable.name}</TableCell>
|
||||
<TableCell>
|
||||
<TextFieldWithDesc
|
||||
title={variable.title}
|
||||
sx={{ width: '25ch' }}
|
||||
description=""
|
||||
description={valsBoundToPreset[variable.name] || ''}
|
||||
value={
|
||||
values.outputVariable === variable.name
|
||||
? shortResult
|
||||
: values.vars[variable.name]?.value || NaN
|
||||
}
|
||||
disabled={values.outputVariable === variable.name}
|
||||
disabled={
|
||||
values.outputVariable === variable.name ||
|
||||
valsBoundToPreset[variable.name] !== undefined
|
||||
}
|
||||
onOwnChange={(val) =>
|
||||
updateVarField(
|
||||
variable.name,
|
||||
@@ -161,7 +273,7 @@ export default function makeTool(): React.JSXElementConstructor<ToolComponentPro
|
||||
setResult('Please select a solve for variable');
|
||||
return;
|
||||
}
|
||||
let expr = nerdamer(ohmsLawCalc.formula);
|
||||
let expr = nerdamer(calcData.formula);
|
||||
|
||||
Object.keys(values.vars).forEach((key) => {
|
||||
if (key === values.outputVariable) return;
|
||||
|
@@ -1,17 +1,32 @@
|
||||
import { defineTool } from '@tools/defineTool';
|
||||
import { DefinedTool, defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
import type { GenericCalcType } from './data/types';
|
||||
import allGenericCalcs from './data/index';
|
||||
|
||||
async function importComponent() {
|
||||
async function importComponent(data: GenericCalcType) {
|
||||
const x = await import('./index');
|
||||
return { default: x.default() };
|
||||
return { default: await x.default(data) };
|
||||
}
|
||||
export const tool = defineTool('number', {
|
||||
name: 'Generic calc',
|
||||
path: 'generic-calc',
|
||||
icon: '',
|
||||
description: '',
|
||||
shortDescription: '',
|
||||
keywords: ['generic', 'calc'],
|
||||
longDescription: '',
|
||||
component: lazy(importComponent)
|
||||
|
||||
const tools: DefinedTool[] = [];
|
||||
|
||||
allGenericCalcs.forEach((x) => {
|
||||
async function importComponent2() {
|
||||
return await importComponent(x);
|
||||
}
|
||||
|
||||
tools.push(
|
||||
defineTool('number', {
|
||||
name: x.title,
|
||||
path: 'generic-calc/x.name',
|
||||
icon: '',
|
||||
description: '',
|
||||
shortDescription: '',
|
||||
keywords: ['generic', 'calc'],
|
||||
longDescription: '',
|
||||
component: lazy(importComponent2)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
export { tools };
|
||||
|
@@ -6,5 +6,9 @@ export type InitialValuesType = {
|
||||
};
|
||||
};
|
||||
|
||||
// Track preset selections
|
||||
presets: {
|
||||
[key: string]: string;
|
||||
};
|
||||
outputVariable: string;
|
||||
};
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import { tool as numberSum } from './sum/meta';
|
||||
import { tool as numberGenerate } from './generate/meta';
|
||||
import { tool as numberArithmeticSequence } from './arithmetic-sequence/meta';
|
||||
import { tool as genericCalc } from './generic-calc/meta';
|
||||
import { tools as genericCalcTools } from './generic-calc/meta';
|
||||
export const numberTools = [
|
||||
numberSum,
|
||||
numberGenerate,
|
||||
numberArithmeticSequence,
|
||||
genericCalc
|
||||
...genericCalcTools
|
||||
];
|
||||
|
Reference in New Issue
Block a user