ui: Fix code editor resizing and restyle (#11474)
Fixes an issue where the code editor would not resizing to the full extent of the browser window plus CodeEditor restyling/refactoring - :label named block - :tools named block - :content named block - code and CSS cleanup - CodeEditor.mdx Signed-off-by: Alessandro De Blasis <alex@deblasis.net> Co-authored-by: John Cowen <johncowen@users.noreply.github.com>
This commit is contained in:
parent
dadb7a7c33
commit
e0b46721c4
|
@ -0,0 +1,6 @@
|
||||||
|
```release-note:bug
|
||||||
|
ui: code editor styling (layout consistency + wide screen support)
|
||||||
|
```
|
||||||
|
```release-note:improvement
|
||||||
|
ui: added copy to clipboard button in code editor toolbars
|
||||||
|
```
|
|
@ -6,6 +6,49 @@ state: needs-love
|
||||||
# CodeEditor
|
# CodeEditor
|
||||||
|
|
||||||
```hbs preview-template
|
```hbs preview-template
|
||||||
<CodeEditor />
|
<CodeEditor
|
||||||
|
@readonly={{true}}
|
||||||
|
@name={{concat name "[Rules]"}}
|
||||||
|
@syntax="hcl"
|
||||||
|
@oninput={{noop}}
|
||||||
|
>
|
||||||
|
<:label>
|
||||||
|
Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a>
|
||||||
|
</:label>
|
||||||
|
<:content>
|
||||||
|
<!-- Plain text or something that renders data like the following -->
|
||||||
|
<Consul::ServiceIdentity::Template
|
||||||
|
@nspace={{nspace}}
|
||||||
|
@name={{item.Name}}
|
||||||
|
/>
|
||||||
|
</:content>
|
||||||
|
</CodeEditor>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A code-editor with syntax highlighting supporting multiple languages (JSON, HCL, YAML), validation and simple tools such as "Copy to clipboard"
|
||||||
|
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
| Argument | Type | Default | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `readonly` | `Boolean` | false | If true, the content (value) of the CodeEditor cannot be changed by the user |
|
||||||
|
| `name` | `String` | | The name attribute of the form element |
|
||||||
|
| `syntax` | `String` | | Identifies the language used to validate/syntax highlight the code (possible values: hcl, json, yaml) |
|
||||||
|
| `oninput` | `Action` | noop | Action/callback that is triggered when the user inputs data |
|
||||||
|
|
||||||
|
### Named Blocks
|
||||||
|
|
||||||
|
| Name | Description | Behaviour if empty |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `:label` | Used to define the title that's displayed on the left inside the toolbar above the CodeEditor | Nothing is displayed |
|
||||||
|
| `:tools` | Used to define tools, buttons, widgets that will be displayed on the right inside the toolbar above the CodeEditor | By default it renders a `language selector` dropdown (if `readonly`== false and `syntax` is falsy) and a `CopyButton`
|
||||||
|
| `:content` | Used to display specific content such as code templates inside the CodeEditor | if the block is defined, @value will be displayed instead |
|
||||||
|
|
||||||
|
|
||||||
|
### See
|
||||||
|
|
||||||
|
- [Component Source Code](./index.js)
|
||||||
|
- [Template Source Code](./index.hbs)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
|
@ -1,11 +1,28 @@
|
||||||
|
<div class="toolbar-container">
|
||||||
|
<div class="toolbar">
|
||||||
|
<label class="title">
|
||||||
|
{{#if (has-block "label")}}
|
||||||
|
{{yield to="label"}}
|
||||||
|
{{/if}}
|
||||||
|
</label>
|
||||||
|
<div class="tools">
|
||||||
|
{{#if (has-block "tools")}}
|
||||||
|
{{yield to="tools"}}
|
||||||
|
{{else}}
|
||||||
|
{{#if (and (not readonly) (not syntax))}}
|
||||||
|
<PowerSelect
|
||||||
|
@onChange={{action "change"}}
|
||||||
|
@selected={{mode}}
|
||||||
|
@searchEnabled={{false}}
|
||||||
|
@options={{modes}} as |mode|>
|
||||||
|
{{mode.name}}
|
||||||
|
</PowerSelect>
|
||||||
|
<div class="toolbar-separator"></div>
|
||||||
|
<CopyButton @value={{value}} @name="value" />
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<IvyCodemirror @value={{value}} @name={{name}} @class={{class}} @options={{options}} @valueUpdated={{action onkeyup}} />
|
<IvyCodemirror @value={{value}} @name={{name}} @class={{class}} @options={{options}} @valueUpdated={{action onkeyup}} />
|
||||||
<pre><code>{{yield}}</code></pre>
|
<pre><code>{{#if (has-block "content")}}{{yield to="content"}}{{else}}{{value}}{{/if}}</code></pre>
|
||||||
{{#if (and (not readonly) (not syntax))}}
|
|
||||||
<PowerSelect
|
|
||||||
@onChange={{action "change"}}
|
|
||||||
@selected={{mode}}
|
|
||||||
@searchEnabled={{false}}
|
|
||||||
@options={{modes}} as |mode|>
|
|
||||||
{{mode.name}}
|
|
||||||
</PowerSelect>
|
|
||||||
{{/if}}
|
|
||||||
|
|
|
@ -3,23 +3,9 @@
|
||||||
border: 10px;
|
border: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
clear: both;
|
||||||
}
|
}
|
||||||
%code-editor .ember-power-select-trigger {
|
|
||||||
@extend %code-editor-syntax-select;
|
|
||||||
}
|
|
||||||
%code-editor-syntax-select {
|
|
||||||
width: 200px;
|
|
||||||
float: right;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
%code-editor-syntax-select {
|
|
||||||
margin-top: 1px;
|
|
||||||
border: 0;
|
|
||||||
background-color: rgb(var(--black));
|
|
||||||
color: rgb(var(--white));
|
|
||||||
border-left: 1px solid;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
%code-editor::after {
|
%code-editor::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
|
@ -32,3 +18,51 @@
|
||||||
%code-editor > pre {
|
%code-editor > pre {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%code-editor {
|
||||||
|
.toolbar-container,
|
||||||
|
.toolbar-container .toolbar {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-container {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 4px;
|
||||||
|
height: 44px;
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
flex: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-separator {
|
||||||
|
height: 32px;
|
||||||
|
margin: 0 4px;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin: 0 10px;
|
||||||
|
align-items: center;
|
||||||
|
.copy-button {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ember-basic-dropdown-trigger {
|
||||||
|
margin: 0 8px;
|
||||||
|
width: 120px;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ $syntax-dark-gray: #535f73;
|
||||||
--syntax-yellow: rgb(var(--tone-yellow-500));
|
--syntax-yellow: rgb(var(--tone-yellow-500));
|
||||||
}
|
}
|
||||||
.CodeMirror {
|
.CodeMirror {
|
||||||
max-width: 1150px;
|
max-width: 1260px;
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
height: auto;
|
height: auto;
|
||||||
/* adds some space at the bottom of the editor for when a horizonal-scroll has appeared */
|
/* adds some space at the bottom of the editor for when a horizonal-scroll has appeared */
|
||||||
|
@ -186,3 +186,35 @@ $syntax-dark-gray: #535f73;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%code-editor {
|
||||||
|
.toolbar-container {
|
||||||
|
background: rgb(var(--tone-gray-050));
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgb(var(--tone-gray-050)) 50%,
|
||||||
|
rgb(var(--tone-gray-150)) 100%
|
||||||
|
);
|
||||||
|
border: 1px solid rgb(var(--tone-gray-150));
|
||||||
|
border-bottom-color: rgb(var(--tone-gray-600));
|
||||||
|
border-top-color: rgb(var(--tone-gray-400));
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
.title {
|
||||||
|
color: rgb(var(--tone-gray-900));
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.toolbar-separator {
|
||||||
|
border-right: 1px solid rgb(var(--tone-gray-300));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ember-power-select-trigger {
|
||||||
|
background-color: rgb(var(--tone-gray-000));
|
||||||
|
color: rgb(var(--tone-gray-999));
|
||||||
|
border-radius: var(--decor-radius-100);
|
||||||
|
border: var(--decor-border-100);
|
||||||
|
border-color: rgb(var(--tone-gray-700));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -38,16 +38,19 @@
|
||||||
<span>Code</span>
|
<span>Code</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="" class="type-text{{if api.data.error.Value ' has-error'}}">
|
<label for="" class="type-text{{if api.data.error.Value ' has-error'}}">
|
||||||
<span>Value</span>
|
|
||||||
{{#if json}}
|
{{#if json}}
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
@name="value"
|
@name="value"
|
||||||
@readonly={{or disabld api.disabled}}
|
@readonly={{or disabld api.disabled}}
|
||||||
@value={{atob api.data.Value}}
|
@value={{atob api.data.Value}}
|
||||||
@onkeyup={{action api.change "value"}}
|
@onkeyup={{action api.change "value"}}
|
||||||
/>
|
>
|
||||||
|
<:label>Value</:label>
|
||||||
|
</CodeEditor>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
<span>Value</span>
|
||||||
<textarea
|
<textarea
|
||||||
{{disabled (or disabld api.disabled)}}
|
{{disabled (or disabld api.disabled)}}
|
||||||
autofocus={{not api.isCreate}}
|
autofocus={{not api.isCreate}}
|
||||||
|
|
|
@ -36,27 +36,40 @@
|
||||||
<strong>{{item.error.Name.validation}}</strong>
|
<strong>{{item.error.Name.validation}}</strong>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</label>
|
</label>
|
||||||
<label class="type-text" data-test-rules>
|
<label for="" class="type-text" data-test-rules>
|
||||||
<span>Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a></span>
|
|
||||||
{{#if (eq item.template 'service-identity')}}
|
{{#if (eq item.template 'service-identity')}}
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
@readonly={{true}}
|
@readonly={{true}}
|
||||||
@name={{concat name "[Rules]"}}
|
@name={{concat name "[Rules]"}}
|
||||||
@syntax="hcl"
|
@syntax="hcl"
|
||||||
@oninput={{action "change" (concat name "[Rules]")}}
|
@oninput={{action "change" (concat name "[Rules]")}}
|
||||||
><Consul::ServiceIdentity::Template
|
>
|
||||||
@nspace={{nspace}}
|
<:label>
|
||||||
@name={{item.Name}}
|
Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a>
|
||||||
/></CodeEditor>
|
</:label>
|
||||||
|
<:content>
|
||||||
|
<Consul::ServiceIdentity::Template
|
||||||
|
@nspace={{nspace}}
|
||||||
|
@name={{item.Name}}
|
||||||
|
/>
|
||||||
|
</:content>
|
||||||
|
</CodeEditor>
|
||||||
{{else if (eq item.template 'node-identity')}}
|
{{else if (eq item.template 'node-identity')}}
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
@readonly={{true}}
|
@readonly={{true}}
|
||||||
@name={{concat name "[Rules]"}}
|
@name={{concat name "[Rules]"}}
|
||||||
@syntax="hcl"
|
@syntax="hcl"
|
||||||
@oninput={{action "change" (concat name "[Rules]")}}
|
@oninput={{action "change" (concat name "[Rules]")}}
|
||||||
><Consul::NodeIdentity::Template
|
>
|
||||||
@name={{item.Name}}
|
<:label>
|
||||||
/></CodeEditor>
|
Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a>
|
||||||
|
</:label>
|
||||||
|
<:content>
|
||||||
|
<Consul::NodeIdentity::Template
|
||||||
|
@name={{item.Name}}
|
||||||
|
/>
|
||||||
|
</:content>
|
||||||
|
</CodeEditor>
|
||||||
{{else}}
|
{{else}}
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
@syntax="hcl"
|
@syntax="hcl"
|
||||||
|
@ -64,7 +77,11 @@
|
||||||
@name={{concat name "[Rules]"}}
|
@name={{concat name "[Rules]"}}
|
||||||
@value={{item.Rules}}
|
@value={{item.Rules}}
|
||||||
@onkeyup={{action "change" (concat name "[Rules]")}}
|
@onkeyup={{action "change" (concat name "[Rules]")}}
|
||||||
/>
|
>
|
||||||
|
<:label>
|
||||||
|
Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a>
|
||||||
|
</:label>
|
||||||
|
</CodeEditor>
|
||||||
{{#if item.error.Rules}}
|
{{#if item.error.Rules}}
|
||||||
<strong>{{item.error.Rules.validation}}</strong>
|
<strong>{{item.error.Rules.validation}}</strong>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -114,28 +114,45 @@
|
||||||
</dl>
|
</dl>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<label class="type-text">
|
<label class="type-text">
|
||||||
<span>Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a></span>
|
|
||||||
{{#if (eq item.template 'service-identity')}}
|
{{#if (eq item.template 'service-identity')}}
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
@syntax="hcl"
|
@syntax="hcl"
|
||||||
@readonly={{true}}
|
@readonly={{true}}
|
||||||
><Consul::ServiceIdentity::Template
|
>
|
||||||
@nspace={{nspace}}
|
<:label>
|
||||||
@name={{item.Name}}
|
Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a>
|
||||||
/></CodeEditor>
|
</:label>
|
||||||
|
<:content>
|
||||||
|
<Consul::ServiceIdentity::Template
|
||||||
|
@nspace={{nspace}}
|
||||||
|
@name={{item.Name}}
|
||||||
|
/>
|
||||||
|
</:content>
|
||||||
|
</CodeEditor>
|
||||||
{{else if (eq item.template 'node-identity')}}
|
{{else if (eq item.template 'node-identity')}}
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
@syntax="hcl"
|
@syntax="hcl"
|
||||||
@readonly={{true}}
|
@readonly={{true}}
|
||||||
><Consul::NodeIdentity::Template
|
>
|
||||||
@name={{item.Name}}
|
<:label>
|
||||||
/></CodeEditor>
|
Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a>
|
||||||
|
</:label>
|
||||||
|
<:content>
|
||||||
|
<Consul::NodeIdentity::Template
|
||||||
|
@name={{item.Name}}
|
||||||
|
/>
|
||||||
|
</:content>
|
||||||
|
</CodeEditor>
|
||||||
{{else}}
|
{{else}}
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
@syntax="hcl"
|
@syntax="hcl"
|
||||||
@readonly={{true}}
|
@readonly={{true}}
|
||||||
@value={{or loadedItem.Rules item.Rules}}
|
@value={{or loadedItem.Rules item.Rules}}
|
||||||
/>
|
>
|
||||||
|
<:label>
|
||||||
|
Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a>
|
||||||
|
</:label>
|
||||||
|
</CodeEditor>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</label>
|
</label>
|
||||||
{{#if (not disabled)}}
|
{{#if (not disabled)}}
|
||||||
|
|
|
@ -16,8 +16,12 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<label class="type-text">
|
<label class="type-text">
|
||||||
<span>Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a></span>
|
<CodeEditor
|
||||||
<CodeEditor @class={{if item.error.Rules "error"}} @name="Rules" @syntax="hcl" @value={{item.Rules}} @onkeyup={{action "change" "Rules"}} />
|
@class={{if item.error.Rules "error"}} @name="Rules" @syntax="hcl" @value={{item.Rules}} @onkeyup={{action "change" "Rules"}}>
|
||||||
|
<:label>
|
||||||
|
Rules <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl.html#rule-specification" rel="help noopener noreferrer" target="_blank">(HCL Format)</a>
|
||||||
|
</:label>
|
||||||
|
</CodeEditor>
|
||||||
</label>
|
</label>
|
||||||
{{#if create }}
|
{{#if create }}
|
||||||
<label class="type-text">
|
<label class="type-text">
|
||||||
|
|
Loading…
Reference in New Issue