mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-04-20 06:55:06 -04:00
refactor(dx): generic data transformer
This commit is contained in:
parent
9fa4c26929
commit
05f06f6a07
5 changed files with 78 additions and 50 deletions
1
components.d.ts
vendored
1
components.d.ts
vendored
|
@ -12,6 +12,7 @@ declare module '@vue/runtime-core' {
|
||||||
CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']
|
CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']
|
||||||
ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']
|
ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']
|
||||||
FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']
|
FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']
|
||||||
|
FormatTransformer: typeof import('./src/components/FormatTransformer.vue')['default']
|
||||||
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
|
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
|
||||||
MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default']
|
MenuIconItem: typeof import('./src/components/MenuIconItem.vue')['default']
|
||||||
MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']
|
MenuLayout: typeof import('./src/components/MenuLayout.vue')['default']
|
||||||
|
|
57
src/components/FormatTransformer.vue
Normal file
57
src/components/FormatTransformer.vue
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<template>
|
||||||
|
<n-form-item :label="inputLabel" v-bind="validationAttrs">
|
||||||
|
<n-input
|
||||||
|
ref="inputElement"
|
||||||
|
v-model:value="input"
|
||||||
|
:placeholder="inputPlaceholder"
|
||||||
|
type="textarea"
|
||||||
|
rows="20"
|
||||||
|
autocomplete="off"
|
||||||
|
autocorrect="off"
|
||||||
|
autocapitalize="off"
|
||||||
|
spellcheck="false"
|
||||||
|
:input-props="{ 'data-test-id': 'input' }"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item :label="outputLabel">
|
||||||
|
<textarea-copyable :value="output" :language="outputLanguage" :follow-height-of="inputElement" />
|
||||||
|
</n-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useValidation, type UseValidationRule } from '@/composable/validation';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
transformer?: (v: string) => string;
|
||||||
|
inputValidationRules?: UseValidationRule<string>[];
|
||||||
|
inputLabel?: string;
|
||||||
|
inputPlaceholder?: string;
|
||||||
|
inputDefault?: string;
|
||||||
|
outputLabel?: string;
|
||||||
|
outputLanguage?: string;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
transformer: _.identity,
|
||||||
|
inputValidationRules: () => [],
|
||||||
|
inputLabel: 'Input',
|
||||||
|
inputDefault: '',
|
||||||
|
inputPlaceholder: 'Input...',
|
||||||
|
outputLabel: 'Output',
|
||||||
|
outputLanguage: '',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const { transformer, inputValidationRules, inputLabel, outputLabel, outputLanguage, inputPlaceholder, inputDefault } =
|
||||||
|
toRefs(props);
|
||||||
|
|
||||||
|
const inputElement = ref();
|
||||||
|
|
||||||
|
const input = ref(inputDefault.value);
|
||||||
|
const output = computed(() => transformer.value(input.value));
|
||||||
|
|
||||||
|
const { attrs: validationAttrs } = useValidation({ source: input, rules: inputValidationRules.value });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
|
@ -7,7 +7,7 @@
|
||||||
:style="height ? `min-height: ${height - 40 /* card padding */ + 10 /* negative margin compensation */}px` : ''"
|
:style="height ? `min-height: ${height - 40 /* card padding */ + 10 /* negative margin compensation */}px` : ''"
|
||||||
>
|
>
|
||||||
<n-config-provider :hljs="hljs">
|
<n-config-provider :hljs="hljs">
|
||||||
<n-code :code="value" :language="language" :trim="false" />
|
<n-code :code="value" :language="language" :trim="false" data-test-id="area-content" />
|
||||||
</n-config-provider>
|
</n-config-provider>
|
||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
<n-tooltip v-if="value" trigger="hover">
|
<n-tooltip v-if="value" trigger="hover">
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { reactive, watch, type Ref } from 'vue';
|
||||||
|
|
||||||
type ValidatorReturnType = unknown;
|
type ValidatorReturnType = unknown;
|
||||||
|
|
||||||
interface UseValidationRule<T> {
|
export interface UseValidationRule<T> {
|
||||||
validator: (value: T) => ValidatorReturnType;
|
validator: (value: T) => ValidatorReturnType;
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,57 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<n-form-item
|
<format-transformer
|
||||||
label="Your raw json"
|
input-label="Your raw json"
|
||||||
:feedback="rawJsonValidation.message"
|
:input-default="defaultValue"
|
||||||
:validation-status="rawJsonValidation.status"
|
input-placeholder="Paste your raw json here..."
|
||||||
>
|
output-label="Minify version of your JSON"
|
||||||
<n-input
|
output-language="json"
|
||||||
ref="inputElement"
|
:input-validation-rules="rules"
|
||||||
v-model:value="rawJson"
|
:transformer="transformer"
|
||||||
placeholder="Paste your raw json here..."
|
/>
|
||||||
type="textarea"
|
|
||||||
rows="20"
|
|
||||||
autocomplete="off"
|
|
||||||
autocorrect="off"
|
|
||||||
autocapitalize="off"
|
|
||||||
spellcheck="false"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="Minify version of your JSON">
|
|
||||||
<textarea-copyable :value="cleanJson" language="json" :follow-height-of="inputElement" />
|
|
||||||
</n-form-item>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import TextareaCopyable from '@/components/TextareaCopyable.vue';
|
import type { UseValidationRule } from '@/composable/validation';
|
||||||
import { useValidation } from '@/composable/validation';
|
|
||||||
import { withDefaultOnError } from '@/utils/defaults';
|
import { withDefaultOnError } from '@/utils/defaults';
|
||||||
import JSON5 from 'json5';
|
import JSON5 from 'json5';
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
|
|
||||||
const inputElement = ref<HTMLElement>();
|
const defaultValue = '{\n\t"hello": [\n\t\t"world"\n\t]\n}';
|
||||||
|
const transformer = (value: string) => withDefaultOnError(() => JSON.stringify(JSON5.parse(value), null, 0), '');
|
||||||
|
|
||||||
const rawJson = ref('{\n\t"hello": [\n\t\t"world"\n\t]\n}');
|
const rules: UseValidationRule<string>[] = [
|
||||||
const cleanJson = computed(() => withDefaultOnError(() => JSON.stringify(JSON5.parse(rawJson.value), null, 0), ''));
|
{
|
||||||
|
validator: (v: string) => v === '' || JSON5.parse(v),
|
||||||
const rawJsonValidation = useValidation({
|
message: 'Provided JSON is not valid.',
|
||||||
source: rawJson,
|
},
|
||||||
rules: [
|
];
|
||||||
{
|
|
||||||
validator: (v) => v === '' || JSON5.parse(v),
|
|
||||||
message: 'Provided JSON is not valid.',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.result-card {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.copy-button {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
right: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue