export class BaseClass<T extends object> {
constructor(values: T) {
Object.assign(this, values);
}
}
// @ts-expect-error: Typescript doesn't understand that BaseClass will always implement interface T due to Objet.assign(this, values)
export interface BaseClass<T extends object> extends T {
}
// Usage:
class SomeClass extends BaseClass<{ name: string }> {
}
const foo = new SomeClass({ name: 'a' });
foo.name // string
export type Exp = {
fn: string;
inputs: { [id: string]: string };
outputs: { [id: string]: string };
}[];
export type Cmp = {
name: string;
inputs: { [id: string]: Var };
outputs: { [id: string]: Var };
expression: Exp;
};
export type Var = {
name: string;
type: string;
};
export type Data = {
name: string;
type: string;
value: any;
};
export type Fn = {
name: string;
inputs: { [id: string]: Var };
outputs: { [id: string]: Var };
body: Function;
};
export function execute(
expression: Exp,
context: { [id: string]: Cmp | Data | Fn }
) {
const builtupValues: { [id: string]: Cmp | Data | Fn } = {};
expression.forEach((step) => {
const fn = lookup(step.fn, "fn", context) as Fn;
const inputs = toObject(
Object.keys(step.inputs).map((key) => {
const variableName = step.inputs[key];
let variableValue = lookup(variableName, fn.inputs[key].type, context, builtupValues);
if (typeof variableValue == 'object' && 'type' in variableValue && 'value' in variableValue) {
variableValue = variableValue.value;
}
return { [key]: variableValue };
})
);
console.log(inputs);
const fnOutputs = fn.body(inputs);
Object.keys(step.outputs).forEach((key) => {
const fnOutputVariable = step.outputs[key];
builtupValues[key] = lookup(
fnOutputVariable,
fn.outputs[fnOutputVariable].type,
fnOutputs
);
});
console.log(builtupValues)
});
return builtupValues;
}
function toObject(values: { [a: string]: any }[]) {
const result = {};
values.forEach((value) => {
Object.keys(value).forEach((key) => {
result[key] = value[key];
});
});
return result;
}
export function lookup(
id: string,
type: string,
...contexts: { [id: string]: Cmp | Data | Fn }[]
) {
for (let i = 0; i < contexts.length; i++) {
const context = contexts[i];
if (id in context) {
console.log(id, context[id], contexts.map(c => Object.keys(c)).join(','));
return context[id]
}
}
console.log(id, contexts.map(c => Object.keys(c)).join(','));
return undefined;
}
console.log(
execute([{
fn: 'y',
inputs: {
m: 'b'
},
outputs: {
n: 'r'
},
}, {
fn: 'x',
inputs: {
a: 'a',
b: 'n',
},
outputs: {
r: 'r'
},
}], {
a: { name: "a", type: "string", value: "fifty nine + " },
b: { name: "b", type: "number", value: 5 },
x: {
name: "x",
inputs: { a: { name: "main", type: "any"}, b: { name: "main", type: "any" } },
outputs: { r: { name: "result", type: "string" } },
body: ({ a, b }) => ({ r: a + b }),
},
y: {
name: "x",
inputs: { m: { name: "main", type: "number" } },
outputs: { r: { name: "result", type: "number" } },
body: ({ m }) => ({ r: m + 1 }),
},
})
);
export default function FixedTableHeaders() {
/*
Key styles
container: relative overflow-y-auto
headers: shadow instead of borders, sticky top-0
*/
return (
<main className="flex-1 relative h-screen overflow-y-auto">
<table className="min-w-full">
<thead className="bg-gray-50">
<tr>
<th
scope="col"
style={{ boxShadow: "0px 2px 0px 0px rgba(156, 163, 175, 1)" }}
className="px-6 py-3 text-left text-xs font-medium bg-gray-100 text-gray-500 uppercase tracking-wider sticky top-0"
>
Header
</th>
</tr>
</thead>
<tbody>
<tr className={1 /* index */ % 2 === 0 ? "bg-white" : "bg-gray-50"}>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
Foo
</td>
</tr>
</tbody>
</table>
</main>
);
}
/*
Author: Joshua Ohlman
Description: Finds all the files in a folder and adds them to an index.ts file as imports & exports
Name: Export all scripts in dir as an array
*/
import { readdirSync, writeFileSync } from 'fs';
import { resolve } from 'path';
function safeVariableName(path: string) {
return noExtension(path).replace(/[^a-zA-Z]/g, '')
}
function noExtension(path: string): string {
return path.replace(/\.[^.]+$/, '');
}
function generateArrayScriptIndex(directoryName: string) {
const files = readdirSync(directoryName).filter(a => a !== 'index.ts');
const output = `${
files.map(file => `import * as ${safeVariableName(file)} from './${noExtension(file)}';`).join('\n')
}\n\nexport const all = [\n${
files.map(file => ` ${safeVariableName(file)},`).join('\n')
}\n]\n\nexport default all;\n`;
writeFileSync(resolve(directoryName, 'index.ts'), output);
}
generateArrayScriptIndex(process.argv[2])
/*
Author: Joshua Ohlman
Description: Render a nextjs route with a list of files as the props
Name: Get Files as Static Props in NextJs
Comments: It's pretty crazy how you have to do this, because the next compiler replaces __dirname with '/' you have to explicitly encode the difference
between the current file & the root directory (see import('../' + ...))
Also, we get a warning: Critical dependency: the request of a dependency is an expression, which can't be removed
an alternative is to write a build time step that auto-generates an index which requires each file normally
*/
import { join } from 'path';
import { readdirSync } from 'fs';
import { GetStaticProps } from 'next'
type FilesList = { path: string, component: any }[]
function getFiles(directoryPath: string): Promise<FilesList> {
const fullPath = join(process.cwd(), directoryPath);
const paths = readdirSync(fullPath).map(path => join(directoryPath, path));
return Promise.all(paths.map(async path => {
const pathWithoutExtension = path.replace(/\.[a-z]+$/, '');
const component = (await import('../' + pathWithoutExtension)).default;
return {path, component};
}))
}
type Props = { files: FilesList }
export const getStaticProps: GetStaticProps<Props> = async (context) => {
const files = await getFiles('content/services');
return { props: { files } }
}
/*
Author: Joshua Ohlman
Description: Render a nextjs route with a list of files as the props
Name: Import all Files in a directory as Static Props in NextJs
*/
import { join } from 'path';
import { GetStaticProps } from 'next'
type FilesList = { path: string, content: string }[]
type Props = { files: FilesList }
export const getStaticProps: GetStaticProps<Props> = async (context) => {
/*
Seems like nextjs wasn't happy with this code being outside of a server-only code block, so I dropped it in here.
Could probably extract the whole getFiles into a separate module & import it in here.
The odd thing is that importing join from path still works, but I guess that's because the path module can be imported
on the client.
*/
async function getFiles(directoryPath: string): Promise<FilesList> {
const { readdirSync, readFile } = await import('fs');
const paths = readdirSync(directoryPath);
return Promise.all(paths.map(async path => {
const content = await new Promise<string>((resolve, reject) => {
readFile(join(directoryPath, path), 'utf8', (error, result) => error ? reject(error) : resolve(result))
});
return {path, content};
}))
}
const files = await getFiles('./content/services');
return { props: { files } }
}
import React from "react";
export default function UploadForm() {
const [file, setFile] = React.useState<File | null>(null);
const [hovering, setHovering] = React.useState<boolean>(false);
<div
className={`mt-2 flex justify-center px-6 pt-5 pb-6 border-2 ${
file || hovering ? "border-blue-300" : "border-gray-300"
} ${file || hovering ? "border-solid" : "border-dashed"} rounded-md ${
file || hovering ? "bg-blue-100" : ""
}`}
onDrop={(e) => {
e.preventDefault();
const file = e.dataTransfer.items[0].getAsFile();
setFile(file);
}}
onDragOver={(e) => {
e.preventDefault();
setHovering(true);
}}
onDragEnd={(e) => {
setHovering(false);
}}
onDragLeave={(e) => {
setHovering(false);
}}
>
{file ? (
<div className="space-y-1 text-center">
<svg
className="mx-auto h-12 w-12 text-blue-900"
stroke="currentColor"
fill="none"
viewBox="0 0 48 48"
aria-hidden="true"
>
<path
d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<div className="flex text-sm text-gray-600">{file.name}</div>
<p className="text-xs text-gray-500">
Type: {file.type} Size: {(file.size / 1000).toLocaleString()}kb
</p>
</div>
) : (
<div className="space-y-1 text-center">
<svg
className="mx-auto h-12 w-12 text-gray-400"
stroke="currentColor"
fill="none"
viewBox="0 0 48 48"
aria-hidden="true"
>
<path
d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<div className="flex text-sm text-gray-600">
{hovering ? (
<span className="font-bold">Drop to upload</span>
) : (
<>
<label
htmlFor="file-upload"
className="relative cursor-pointer bg-white rounded-md font-medium text-indigo-600 hover:text-indigo-500 focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-indigo-500"
>
<span>Upload a file</span>
<input
id="file-upload"
name="file-upload"
type="file"
className="sr-only"
onChange={(event) => {
const file = event.target.files && event.target.files[0];
setFile(file);
}}
/>
</label>
<p className="pl-1">or drag and drop</p>
</>
)}
</div>
<p className="text-xs text-gray-500">Text files: csv or json</p>
</div>
)}
</div>;
}
type Orientation = "N" | "R" | "I" | "B";
type Rotation = 0 | 90 | 180 | 270;
type Coordinates = [number, number];
export function rotateAndTransformZPL(
zpl: string,
rotate: Rotation,
size: Coordinates, // in pixels/points
transform: Coordinates
) {
let result = zpl;
if (result.match(/\^FW/)) {
result = result.replace(/\^FW([NRIB])/g, (val) => {
const currentOrientation = val[3] as Orientation;
const newOrientation: Orientation = mapOrientation(
currentOrientation,
rotate
);
return `^FW${newOrientation}`;
});
} else if (result.match(/\^XA/)) {
result.replace(/\^XA/g, `^XA\n^FW${rotationToOrientation[rotate]}`);
} else {
result = `^FW${rotationToOrientation[rotate]}\n${result}`;
}
result = result.replace(/\^FO\d+,\d+/g, (origin) => {
const parsedOrigin = origin.match(/\^FO(\d+),(\d+)/);
const coordinates = [
parseInt(parsedOrigin[1]),
parseInt(parsedOrigin[2]),
] as Coordinates;
const rotatedCoordinates = rotateCoordinates(coordinates, rotate, size);
const transformedCoordinates = transformCoordinates(
rotatedCoordinates,
transform
);
return `^FO${transformedCoordinates[0]},${transformedCoordinates[1]}`;
});
return result;
}
const orientationToRotationMap: { [P in Orientation]: Rotation } = {
N: 0,
R: 90,
I: 180,
B: 270,
};
const rotationToOrientation: { [P in Rotation]: Orientation } = {
0: "N",
90: "R",
180: "I",
270: "B",
};
function mapOrientation(orientation: Orientation, rotate: Rotation) {
const initialRotation = orientationToRotationMap[orientation];
const newRotation = ((initialRotation + rotate) % 360) as Rotation;
return rotationToOrientation[newRotation];
}
function rotateCoordinates(
coordinates: Coordinates,
rotation: Rotation,
size: Coordinates
): Coordinates {
if (rotation == 0) return coordinates;
const top = coordinates[1];
const left = coordinates[0];
const width = size[0];
const height = size[1];
// 90: left => top, top => right
if (rotation == 90) return [width - top, left]
// 180: left => right, top => bottom
if (rotation == 180) return [width - left, height - top]
// 270: left => bottom, top => left
if (rotation == 270) return [top, height - left]
return coordinates;
}
function transformCoordinates(
coordinates: Coordinates,
transform: Coordinates
): Coordinates {
return [coordinates[0] + transform[0], coordinates[1] + transform[1]];
}
console.log(
rotateAndTransformZPL(
`
^XA
^FWN
^FX Top section with logo, name and address.
^CF0,60
^FO50,50^GB100,100,100^FS
^FO75,75^FR^GB100,100,100^FS
^FO93,93^GB40,40,40^FS
^FO220,50^FDIntershipping, Inc.^FS
^CF0,30
^FO220,115^FD1000 Shipping Lane^FS
^FO220,155^FDShelbyville TN 38102^FS
^FO220,195^FDUnited States (USA)^FS
^FO50,250^GB700,3,3^FS
^FX Second section with recipient address and permit information.
^CFA,30
^FO50,300^FDJohn Doe^FS
^FO50,340^FD100 Main Street^FS
^FO50,380^FDSpringfield TN 39021^FS
^FO50,420^FDUnited States (USA)^FS
^CFA,15
^FO600,300^GB150,150,3^FS
^FO638,340^FDPermit^FS
^FO638,390^FD123456^FS
^FO50,500^GB700,3,3^FS
^FX Third section with bar code.
^BY5,2,270
^FO100,550^BC^FD12345678^FS
^FX Fourth section (the two boxes on the bottom).
^FO50,900^GB700,250,3^FS
^FO400,900^GB3,250,3^FS
^CF0,40
^FO100,960^FDCtr. X34B-1^FS
^FO100,1010^FDREF1 F00B47^FS
^FO100,1060^FDREF2 BL4H8^FS
^CF0,190
^FO470,955^FDCA^FS
^XZ
`,
90,
[203 * 6, 203 * 4],
[0, 0]
)
);