This commit is contained in:
parent
beba067305
commit
87a35aeffc
@ -12,6 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource-variable/jetbrains-mono": "^5.1.1",
|
"@fontsource-variable/jetbrains-mono": "^5.1.1",
|
||||||
"@monaco-editor/react": "^4.6.0",
|
"@monaco-editor/react": "^4.6.0",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^11.11.10",
|
"framer-motion": "^11.11.10",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
|
@ -14,6 +14,9 @@ importers:
|
|||||||
'@monaco-editor/react':
|
'@monaco-editor/react':
|
||||||
specifier: ^4.6.0
|
specifier: ^4.6.0
|
||||||
version: 4.6.0(monaco-editor@0.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 4.6.0(monaco-editor@0.52.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
clsx:
|
||||||
|
specifier: ^2.1.1
|
||||||
|
version: 2.1.1
|
||||||
framer-motion:
|
framer-motion:
|
||||||
specifier: ^11.11.10
|
specifier: ^11.11.10
|
||||||
version: 11.11.10(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 11.11.10(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
@ -702,6 +705,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
clsx@2.1.1:
|
||||||
|
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
engines: {node: '>=7.0.0'}
|
engines: {node: '>=7.0.0'}
|
||||||
@ -1859,6 +1866,8 @@ snapshots:
|
|||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
supports-color: 7.2.0
|
supports-color: 7.2.0
|
||||||
|
|
||||||
|
clsx@2.1.1: {}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-name: 1.1.4
|
color-name: 1.1.4
|
||||||
|
@ -8,11 +8,14 @@ export const Button = styled.button`
|
|||||||
background-color: #ff1696;
|
background-color: #ff1696;
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
|
transition: background-color 0.25s ease-out;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #da1c9b;
|
background-color: #da1c9b;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:placeholder {
|
&:disabled {
|
||||||
color: gray;
|
background-color: gray;
|
||||||
|
cursor: inherit;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -3,11 +3,11 @@ import { motion } from "framer-motion";
|
|||||||
|
|
||||||
import style from './style.module.scss'
|
import style from './style.module.scss'
|
||||||
import { TransformGridItem } from "../TransformGridItem";
|
import { TransformGridItem } from "../TransformGridItem";
|
||||||
import { transforms } from "../Transforms/Transform";
|
import { transforms, wrapTransform } from "../Transforms/Transform";
|
||||||
|
|
||||||
export const TransformGrid: FC = () =>
|
export const TransformGrid: FC = () =>
|
||||||
<ul className={style.grid}>
|
<ul className={style.grid}>
|
||||||
{transforms.map((v, i) =>
|
{transforms.map((transform, i) =>
|
||||||
<motion.li
|
<motion.li
|
||||||
key={i}
|
key={i}
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
@ -15,7 +15,7 @@ export const TransformGrid: FC = () =>
|
|||||||
transition={{ delay: i * 0.1 + 1.5 }} >
|
transition={{ delay: i * 0.1 + 1.5 }} >
|
||||||
|
|
||||||
<TransformGridItem
|
<TransformGridItem
|
||||||
transform={v}/>
|
transform={wrapTransform(transform)}/>
|
||||||
|
|
||||||
</motion.li>
|
</motion.li>
|
||||||
)}
|
)}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
.grid {
|
.grid {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||||
|
align-content: flex-start;
|
||||||
|
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,30 +1,94 @@
|
|||||||
import { FC } from "react";
|
import { ChangeEvent, FC, useState } from "react";
|
||||||
import style from './style.module.scss'
|
import style from './style.module.scss'
|
||||||
import { Button } from "../Components/Button";
|
import { Button } from "../Components/Button";
|
||||||
import { Input } from "../Components/Input";
|
import { Input } from "../Components/Input";
|
||||||
import { TextArea } from "../Components/TextArea";
|
import { TextArea } from "../Components/TextArea";
|
||||||
import { Transform } from "../Transforms/Transform";
|
import { TransformCheckboxOption, TransformOption, TransformTextboxOption, WrappedTransform } from "../Transforms/Transform";
|
||||||
|
import { useRecoilState } from "recoil";
|
||||||
|
import { EditorValueState } from "../GlobalStates/EditorValueState";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
interface TransformGridItemProp {
|
interface TransformGridItemProp {
|
||||||
transform: Transform
|
transform: WrappedTransform
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TransformGridItem: FC<TransformGridItemProp> = ({ transform }) => {
|
export const TransformGridItem: FC<TransformGridItemProp> = ({ transform }) => {
|
||||||
|
const [value, setValue] = useRecoilState(EditorValueState)
|
||||||
|
const [options, setOptions] = useState(new Map<string, TransformOption>())
|
||||||
|
|
||||||
|
const result = transform.fn(value, options)
|
||||||
|
|
||||||
|
const onCheckboxOptionChanged =
|
||||||
|
(option: TransformCheckboxOption) =>
|
||||||
|
(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
|
||||||
|
options.set(option.key, {
|
||||||
|
...option,
|
||||||
|
value: event.target.checked
|
||||||
|
})
|
||||||
|
|
||||||
|
setOptions(new Map(options))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const onTextboxOptionChanged =
|
||||||
|
(option: TransformTextboxOption) =>
|
||||||
|
(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
|
||||||
|
options.set(option.key, {
|
||||||
|
...option,
|
||||||
|
value: event.target.value
|
||||||
|
})
|
||||||
|
|
||||||
|
setOptions(new Map(options))
|
||||||
|
}
|
||||||
|
|
||||||
|
const onForwardButtonPressed = () => {
|
||||||
|
if (result.error)
|
||||||
|
return
|
||||||
|
|
||||||
|
setValue(result.value)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.item}>
|
<div className={style.item}>
|
||||||
<div className={style.toolbar}>
|
<div className={style.toolbar}>
|
||||||
<Button><<<</Button>
|
<Button disabled={result.error} onClick={onForwardButtonPressed}>
|
||||||
|
<<<
|
||||||
|
</Button>
|
||||||
|
|
||||||
<h2 className={style.name}>{transform.name}</h2>
|
<h2 className={style.name}>{transform.name}</h2>
|
||||||
|
|
||||||
<div className={style.options}>
|
<div className={style.options}>
|
||||||
<label className={style.optionItem}>hello: <Input type="checkbox" /></label>
|
{transform.options
|
||||||
<label className={style.optionItem}>hello: <Input type="text" /></label>
|
?.filter((option) => option.type === 'CHECKBOX')
|
||||||
<label className={style.optionItem}>hello: <Input type="checkbox" /></label>
|
.map((option, i) => (
|
||||||
<label className={style.optionItem}>hello: <Input type="checkbox" /></label>
|
<label key={i} className={style.optionItem}>
|
||||||
|
<p>{option.label ?? option.key}:</p>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
onChange={onCheckboxOptionChanged(option)}
|
||||||
|
type="checkbox" />
|
||||||
|
</label>))}
|
||||||
|
|
||||||
|
{transform.options
|
||||||
|
?.filter((option) => option.type === 'TEXTBOX')
|
||||||
|
.map((option, i) => (
|
||||||
|
<label key={i} className={style.optionItem}>
|
||||||
|
<p>{option.label ?? option.key}:</p>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
onChange={onTextboxOptionChanged(option)}
|
||||||
|
type="checkbox" />
|
||||||
|
</label>))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TextArea placeholder="(empty)" className={style.input} />
|
<TextArea
|
||||||
|
value={result.value}
|
||||||
|
readOnly
|
||||||
|
placeholder="(empty)"
|
||||||
|
className={clsx(result.error && style.error)} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 300px;
|
min-height: 250px;
|
||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
.name {
|
.name {
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
padding: 14px 0px;
|
padding: 14px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.options {
|
.options {
|
||||||
@ -32,7 +32,12 @@
|
|||||||
|
|
||||||
.optionItem {
|
.optionItem {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: #ffcaca;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
import { Transform } from "./Transform";
|
|
||||||
|
|
||||||
export const Base64DecodeTransform: Transform = {
|
|
||||||
name: 'base64d',
|
|
||||||
fn: () => 'Hello, world!'
|
|
||||||
}
|
|
11
src/Transforms/Base64Transforms.ts
Normal file
11
src/Transforms/Base64Transforms.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Transform } from "./Transform";
|
||||||
|
|
||||||
|
export const Base64DecodeTransform: Transform = {
|
||||||
|
name: 'base64d',
|
||||||
|
fn: (v) => btoa(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Base64EncodeTransform: Transform = {
|
||||||
|
name: 'base64e',
|
||||||
|
fn: (v) => atob(v)
|
||||||
|
}
|
@ -1,12 +1,59 @@
|
|||||||
import { Base64DecodeTransform } from "./Base64DecodeTransform"
|
import { Base64DecodeTransform, Base64EncodeTransform } from "./Base64Transforms"
|
||||||
|
import { URIDecodeTransform, URIEncodeTransform } from "./URITransforms"
|
||||||
|
|
||||||
|
export interface TransformCheckboxOption {
|
||||||
|
type: 'CHECKBOX',
|
||||||
|
key: string,
|
||||||
|
label?: string,
|
||||||
|
value?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface TransformTextboxOption {
|
||||||
|
type: 'TEXTBOX',
|
||||||
|
key: string,
|
||||||
|
label?: string,
|
||||||
|
value?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TransformOption =
|
||||||
|
TransformCheckboxOption | TransformTextboxOption
|
||||||
|
|
||||||
export interface Transform {
|
export interface Transform {
|
||||||
name: string
|
name: string
|
||||||
fn: () => string
|
fn: (value: string, options: Map<string, TransformOption>) => string
|
||||||
|
options?: TransformOption[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WrappedTransform extends Omit<Transform, 'fn'> {
|
||||||
|
wrapped: true,
|
||||||
|
fn: (value: string, options: Map<string, TransformOption>) => {
|
||||||
|
error: boolean,
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const wrapTransform = (transform: Transform): WrappedTransform => ({
|
||||||
|
...transform,
|
||||||
|
fn: (...args) => {
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
error: false,
|
||||||
|
value: transform.fn(...args)
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
return {
|
||||||
|
error: true,
|
||||||
|
value: err.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
wrapped: true
|
||||||
|
})
|
||||||
|
|
||||||
export const transforms: Transform[] = [
|
export const transforms: Transform[] = [
|
||||||
Base64DecodeTransform,
|
Base64DecodeTransform,
|
||||||
Base64DecodeTransform,
|
Base64EncodeTransform,
|
||||||
Base64DecodeTransform,
|
URIDecodeTransform,
|
||||||
|
URIEncodeTransform
|
||||||
]
|
]
|
||||||
|
29
src/Transforms/URITransforms.ts
Normal file
29
src/Transforms/URITransforms.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Transform } from "./Transform";
|
||||||
|
|
||||||
|
export const URIDecodeTransform: Transform = {
|
||||||
|
name: 'urid',
|
||||||
|
|
||||||
|
fn: (v, o) =>
|
||||||
|
o.get('cmp')?.value === true
|
||||||
|
? decodeURIComponent(v)
|
||||||
|
: decodeURI(v),
|
||||||
|
|
||||||
|
options: [{
|
||||||
|
type: 'CHECKBOX',
|
||||||
|
key: 'cmp'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const URIEncodeTransform: Transform = {
|
||||||
|
name: 'urie',
|
||||||
|
|
||||||
|
fn: (v, o) =>
|
||||||
|
o.get('cmp')?.value === true
|
||||||
|
? encodeURIComponent(v)
|
||||||
|
: encodeURI(v),
|
||||||
|
|
||||||
|
options: [{
|
||||||
|
type: 'CHECKBOX',
|
||||||
|
key: 'cmp'
|
||||||
|
}]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user