diff --git a/src/components/Generator/GeneredTaskfile/GeneratedTaskfile.tsx b/src/components/Generator/GeneredTaskfile/GeneratedTaskfile.tsx index cf8438e..202ccb1 100644 --- a/src/components/Generator/GeneredTaskfile/GeneratedTaskfile.tsx +++ b/src/components/Generator/GeneredTaskfile/GeneratedTaskfile.tsx @@ -5,6 +5,7 @@ import { taskfile } from '@/components/Generator/GeneredTaskfile/taskfile'; import { useFormContext } from 'react-hook-form'; import { GeneratorSettings } from '@/components/Generator/Generator'; import CopyToClipboard from '@/components/Generator/GeneredTaskfile/Copy'; +import { highlighter } from './Highlighter'; const GeneratedTaskfile = (): ReactElement => { const form = useFormContext(); @@ -16,7 +17,7 @@ const GeneratedTaskfile = (): ReactElement => { return ( <> navigator.clipboard.writeText(resultTaskfile)} /> -
{resultTaskfile}
+
{highlighter(resultTaskfile)}
); }; diff --git a/src/components/Generator/GeneredTaskfile/Highlighter/Highlighter.tsx b/src/components/Generator/GeneredTaskfile/Highlighter/Highlighter.tsx new file mode 100644 index 0000000..c379269 --- /dev/null +++ b/src/components/Generator/GeneredTaskfile/Highlighter/Highlighter.tsx @@ -0,0 +1,24 @@ +import { ReactElement } from 'react'; + +import styles from './highlighter.module.css'; + +import { lineRenderers } from './lineRenderers'; + +export const highlighter = (code: string): ReactElement[] => { + const normalizedCode = code.endsWith('\n') ? code : code + '\n'; + const lines = normalizedCode.split('\n').slice(0, -1); + + return lines.map((line, index) => { + const renderer = Object.values(lineRenderers).find((r) => r.test(line)); + + if (renderer) { + return renderer.render(line, index); + } + + return ( +
+ {line} +
+ ); + }); +}; diff --git a/src/components/Generator/GeneredTaskfile/Highlighter/highlighter.module.css b/src/components/Generator/GeneredTaskfile/Highlighter/highlighter.module.css new file mode 100644 index 0000000..1dcda92 --- /dev/null +++ b/src/components/Generator/GeneredTaskfile/Highlighter/highlighter.module.css @@ -0,0 +1,35 @@ +.line { + display: flex; +} + +.text-white { + color: #fff; +} + +.text-gray { + color: #888589; +} + +.text-yellow { + color: #fde047; +} + +.text-yellow-light { + color: #fef08a; +} + +.text-pink { + color: #ec4899; +} + +.text-purple { + color: #a855f7; +} + +.text-blue { + color: #60a5fa; +} + +.text-blue-light { + color: #93c5fd; +} diff --git a/src/components/Generator/GeneredTaskfile/Highlighter/index.ts b/src/components/Generator/GeneredTaskfile/Highlighter/index.ts new file mode 100644 index 0000000..b881459 --- /dev/null +++ b/src/components/Generator/GeneredTaskfile/Highlighter/index.ts @@ -0,0 +1 @@ +export * from './Highlighter'; diff --git a/src/components/Generator/GeneredTaskfile/Highlighter/lineRenderers.tsx b/src/components/Generator/GeneredTaskfile/Highlighter/lineRenderers.tsx new file mode 100644 index 0000000..f6d94ec --- /dev/null +++ b/src/components/Generator/GeneredTaskfile/Highlighter/lineRenderers.tsx @@ -0,0 +1,79 @@ +import React, { ReactElement } from 'react'; + +import styles from './highlighter.module.css'; + +enum RendererType { + EmptyLines, + FunctionDefinitions, + Comments, + Variables, + Conditionals, + EchoStatements, +} + +type LineRenderer = { + test: (line: string) => boolean; + render: (line: string, index: number) => ReactElement; +}; + +export const lineRenderers: Record = { + [RendererType.EmptyLines]: { + test: (line) => line.trim() === '', + render: (_, i) =>
 
, + }, + [RendererType.FunctionDefinitions]: { + test: (line) => /^function\s+[a-zA-Z_:]+/.test(line), + render: (line, i) => { + const [, name, rest] = line.match(/^function\s+([a-zA-Z_:]+)(.*)/) || []; + return ( +
+ function + {name} + {rest} +
+ ); + }, + }, + [RendererType.Comments]: { + test: (line) => line.trim().startsWith('#'), + render: (line, i) => ( +
+ {line} +
+ ), + }, + [RendererType.Variables]: { + test: (line) => /^[A-Z_]+=.*/.test(line), + render: (line, i) => { + const [varName, ...rest] = line.split('='); + return ( +
+ {varName} + = + {rest.join('=')} +
+ ); + }, + }, + [RendererType.Conditionals]: { + test: (line) => /^\s*if\s+|^\s*then\s+|^\s*else\s+|^\s*fi\s*/.test(line), + render: (line, i) => ( +
+ {line} +
+ ), + }, + [RendererType.EchoStatements]: { + test: (line) => line.includes('echo'), + render: (line, i) => { + const parts = line.split('echo'); + return ( +
+ {parts[0]} + echo + {parts[1]} +
+ ); + }, + }, +};