-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4c70f75
commit 97fcbc6
Showing
14 changed files
with
389 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,100 +1,15 @@ | ||
<script lang="ts"> | ||
export let language = 'json' | ||
export let language: 'json' | 'yaml' | 'toml' = 'json' | ||
export let code: string | ||
export let convert = false | ||
import formatterYaml from 'yaml' | ||
import formatterToml from 'toml-js' | ||
import Highlight from 'svelte-highlight' | ||
import yaml from 'svelte-highlight/src/languages/yaml' | ||
import json from 'svelte-highlight/src/languages/json' | ||
import toml from 'svelte-highlight/src/languages/ini' | ||
import atomOneDark from 'svelte-highlight/src/styles/atom-one-dark' | ||
import { state } from '../state' | ||
import Alert from './Alert.svelte' | ||
import Icon from './Icon.svelte' | ||
let errorMsg = '' | ||
function convertFormat(code: string | {}, format: string) { | ||
errorMsg = '' | ||
if (!code) { | ||
return '' | ||
} | ||
if (!format) { | ||
return code | ||
} | ||
try { | ||
const obj = typeof code === 'string' ? JSON.parse(code) : code | ||
switch (format) { | ||
case 'yaml': | ||
case 'yml': | ||
return formatterYaml.stringify(obj, { sortMapEntries: true }) | ||
case 'toml': | ||
return formatterToml.dump(obj) | ||
case 'json': | ||
return JSON.stringify(obj, null, 2) | ||
default: | ||
console.error('Unsupported format', format) | ||
break | ||
} | ||
} catch (error) { | ||
console.error('failed to convert to format', { code, format, error }) | ||
errorMsg = error | ||
} | ||
return code | ||
} | ||
export let noFormatSelector = false | ||
import Editor from './Editor.svelte' | ||
</script> | ||
|
||
<svelte:head> | ||
{@html atomOneDark} | ||
</svelte:head> | ||
|
||
<div class:no-code={!code}> | ||
<button | ||
class="icon-button primary" | ||
on:click|preventDefault={() => { | ||
switch ($state.codeLanguage) { | ||
case 'json': | ||
$state.codeLanguage = 'yaml' | ||
break | ||
case 'yaml': | ||
$state.codeLanguage = 'toml' | ||
break | ||
case 'toml': | ||
$state.codeLanguage = 'json' | ||
break | ||
default: | ||
$state.codeLanguage = 'toml' | ||
break | ||
} | ||
}}> | ||
<Icon icon="code" /> | ||
{$state.codeLanguage}</button> | ||
{#if errorMsg} | ||
<Alert kind="error"> | ||
{errorMsg} | ||
</Alert> | ||
{/if} | ||
<Highlight | ||
language={{ | ||
yaml: yaml, | ||
yml: yaml, | ||
json: json, | ||
toml: toml, | ||
}[language]} | ||
code={convert | ||
? convertFormat(code, $state.codeLanguage || language) | ||
: code} /> | ||
</div> | ||
|
||
<style> | ||
div { | ||
position: relative; | ||
} | ||
button { | ||
position: absolute; | ||
right: 0; | ||
top: calc(-1 * var(--size-3)); | ||
} | ||
.no-code { | ||
opacity: 0.5; | ||
} | ||
</style> | ||
<Editor | ||
initialValue={code} | ||
bind:value={code} | ||
{noFormatSelector} | ||
config={{ readOnly: true, mode: language }} | ||
initialLanguage={language}> | ||
<slot name="title" slot="title" /> | ||
</Editor> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
<script lang="ts"> | ||
import { onMount, onDestroy } from 'svelte' | ||
import CodeMirror, { fromTextArea } from 'codemirror' | ||
import 'codemirror/mode/javascript/javascript' | ||
import 'codemirror/mode/toml/toml' | ||
import 'codemirror/mode/yaml/yaml' | ||
import 'codemirror/theme/dracula.css' | ||
import 'codemirror/lib/codemirror.css' | ||
import type { EditorFromTextArea, EditorConfiguration } from 'codemirror' | ||
import { convertStringToCodeFormat } from 'util/codeFormat' | ||
import Button from './Button.svelte' | ||
import Alert from './Alert.svelte' | ||
import { state } from 'state' | ||
import Tip from './Tip.svelte' | ||
import CodeInner from './CodeInner.svelte' | ||
import Collapse from './Collapse.svelte' | ||
export let id: string | undefined = undefined | ||
export let name: string | undefined = undefined | ||
export let value: string = '' | ||
export let initialValue = '' | ||
export let noFormatSelector = false | ||
export let initialLanguage: 'json' | 'toml' | 'yaml' | 'graphql' = 'json' | ||
export let config: EditorConfiguration = {} | ||
// export let outFormat: 'json' | 'toml' | 'yaml' = initialLanguage | ||
let editor: EditorFromTextArea | ||
let errorMessage: string | null | ||
let textarea: HTMLTextAreaElement | ||
let _config: EditorConfiguration = { | ||
theme: 'dracula', | ||
mode: config?.mode || $state.codeLanguage, | ||
lineWrapping: true, | ||
lineNumbers: true, | ||
tabSize: 2, | ||
...config, | ||
} | ||
if (_config.mode === 'json') { | ||
_config.mode = 'javascript' | ||
} | ||
$: { | ||
if (editor && config.readOnly) { | ||
editor.setValue(value) | ||
console.log('setting value') | ||
editor.setOption('mode', _config.mode) | ||
} | ||
} | ||
const setFormat = (format: typeof initialLanguage) => { | ||
editor.setOption('mode', format === 'json' ? 'javascript' : format) | ||
switch (format) { | ||
case 'json': | ||
case 'toml': | ||
case 'yaml': | ||
$state.codeLanguage = format | ||
break | ||
default: | ||
return | ||
} | ||
if ($state.editorRawFormat) { | ||
return | ||
} | ||
const [c, err] = convertStringToCodeFormat(editor.getValue(), format) | ||
if (!err) { | ||
editor.setValue(c as string) | ||
return | ||
} | ||
} | ||
function reset() { | ||
editor.setValue(initialValue || '') | ||
// if ($state.editorRawFormat) { | ||
// return | ||
// } | ||
if (initialLanguage) { | ||
setFormat($state.codeLanguage || 'yaml') | ||
return | ||
} | ||
} | ||
onMount(() => { | ||
editor = fromTextArea(textarea, _config) | ||
editor.setSize('100%', '100%') | ||
editor.on('change', (e) => { | ||
if ($state.editorRawFormat) { | ||
value = editor.getValue() | ||
return | ||
} | ||
switch (_config.mode) { | ||
case 'javascript': | ||
case 'toml': | ||
case 'yaml': | ||
break | ||
default: | ||
return | ||
} | ||
const [c, err] = convertStringToCodeFormat( | ||
editor.getValue(), | ||
initialLanguage | ||
) | ||
errorMessage = err | ||
if (err) { | ||
return | ||
} | ||
value = c || '' | ||
}) | ||
if (initialValue) { | ||
reset() | ||
} | ||
}) | ||
onDestroy(() => { | ||
editor.toTextArea() | ||
}) | ||
const langs: Array<typeof initialLanguage> = ['yaml', 'toml', 'json'] | ||
</script> | ||
|
||
<slot name="title" /> | ||
{#if !config.readOnly} | ||
<div class="header"> | ||
<Button color="danger" disabled={value === initialValue} on:click={reset}> | ||
Reset | ||
</Button> | ||
</div> | ||
{/if} | ||
<textarea bind:this={textarea} {name} {id} /> | ||
{#if !noFormatSelector} | ||
<div class="footer"> | ||
<Button | ||
color="primary" | ||
toggle={$state.editorRawFormat} | ||
on:click={() => ($state.editorRawFormat = !$state.editorRawFormat)}> | ||
Raw | ||
</Button> | ||
{#each langs as l} | ||
<Button | ||
active={$state.codeLanguage === l} | ||
color="secondary" | ||
on:click={() => setFormat(l)}>{l}</Button> | ||
{/each} | ||
</div> | ||
{/if} | ||
{#if !config.readOnly} | ||
<Tip key="editor-format"> | ||
<p> | ||
JSON is often used in API's, but is not always something that you want to | ||
edit manually. | ||
</p> | ||
<p> | ||
TOML and YAML are often considered better for human-readability and | ||
editing. | ||
</p> | ||
<p> | ||
You can therefore edit in a different language than what the backend | ||
supports | ||
</p> | ||
<p>Before sending, this value will be converted.</p> | ||
<p> | ||
If you do not want this behaviour, you can disable convertion by setting | ||
"Raw" | ||
</p> | ||
</Tip> | ||
{#if errorMessage} | ||
<Alert kind="error">{errorMessage}</Alert> | ||
{/if} | ||
{#if _config.mode !== 'graphql'} | ||
<paper> | ||
<Collapse key="editor-preview"> | ||
<div slot="title">Preview</div> | ||
<CodeInner noFormatSelector={true} bind:code={value} /> | ||
</Collapse> | ||
</paper> | ||
{/if} | ||
{/if} | ||
|
||
<style> | ||
.footer, | ||
.header { | ||
background-color: #2b2b2b; | ||
display: flex; | ||
justify-content: flex-end; | ||
} | ||
</style> |
Oops, something went wrong.