mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #12284 from grafana/davkal/queryfield-refactor
Query field refactorings to support external plugins
This commit is contained in:
commit
25bcdbcab1
@ -9,7 +9,7 @@ import { getNextCharacter, getPreviousCousin } from './utils/dom';
|
|||||||
import BracesPlugin from './slate-plugins/braces';
|
import BracesPlugin from './slate-plugins/braces';
|
||||||
import ClearPlugin from './slate-plugins/clear';
|
import ClearPlugin from './slate-plugins/clear';
|
||||||
import NewlinePlugin from './slate-plugins/newline';
|
import NewlinePlugin from './slate-plugins/newline';
|
||||||
import PluginPrism, { configurePrismMetricsTokens } from './slate-plugins/prism/index';
|
import PluginPrism, { setPrismTokens } from './slate-plugins/prism/index';
|
||||||
import RunnerPlugin from './slate-plugins/runner';
|
import RunnerPlugin from './slate-plugins/runner';
|
||||||
import debounce from './utils/debounce';
|
import debounce from './utils/debounce';
|
||||||
import { processLabels, RATE_RANGES, cleanText } from './utils/prometheus';
|
import { processLabels, RATE_RANGES, cleanText } from './utils/prometheus';
|
||||||
@ -17,13 +17,13 @@ import { processLabels, RATE_RANGES, cleanText } from './utils/prometheus';
|
|||||||
import Typeahead from './Typeahead';
|
import Typeahead from './Typeahead';
|
||||||
|
|
||||||
const EMPTY_METRIC = '';
|
const EMPTY_METRIC = '';
|
||||||
const TYPEAHEAD_DEBOUNCE = 300;
|
export const TYPEAHEAD_DEBOUNCE = 300;
|
||||||
|
|
||||||
function flattenSuggestions(s) {
|
function flattenSuggestions(s) {
|
||||||
return s ? s.reduce((acc, g) => acc.concat(g.items), []) : [];
|
return s ? s.reduce((acc, g) => acc.concat(g.items), []) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const getInitialValue = query =>
|
export const getInitialValue = query =>
|
||||||
Value.fromJSON({
|
Value.fromJSON({
|
||||||
document: {
|
document: {
|
||||||
nodes: [
|
nodes: [
|
||||||
@ -45,12 +45,14 @@ const getInitialValue = query =>
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
class Portal extends React.Component {
|
class Portal extends React.Component<any, any> {
|
||||||
node: any;
|
node: any;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
const { index = 0, prefix = 'query' } = props;
|
||||||
this.node = document.createElement('div');
|
this.node = document.createElement('div');
|
||||||
this.node.classList.add('explore-typeahead', `explore-typeahead-${props.index}`);
|
this.node.classList.add(`slate-typeahead`, `slate-typeahead-${prefix}-${index}`);
|
||||||
document.body.appendChild(this.node);
|
document.body.appendChild(this.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,12 +73,14 @@ class QueryField extends React.Component<any, any> {
|
|||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
|
const { prismDefinition = {}, prismLanguage = 'promql' } = props;
|
||||||
|
|
||||||
this.plugins = [
|
this.plugins = [
|
||||||
BracesPlugin(),
|
BracesPlugin(),
|
||||||
ClearPlugin(),
|
ClearPlugin(),
|
||||||
RunnerPlugin({ handler: props.onPressEnter }),
|
RunnerPlugin({ handler: props.onPressEnter }),
|
||||||
NewlinePlugin(),
|
NewlinePlugin(),
|
||||||
PluginPrism(),
|
PluginPrism({ definition: prismDefinition, language: prismLanguage }),
|
||||||
];
|
];
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -131,7 +135,8 @@ class QueryField extends React.Component<any, any> {
|
|||||||
if (!this.state.metrics) {
|
if (!this.state.metrics) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
configurePrismMetricsTokens(this.state.metrics);
|
setPrismTokens(this.props.prismLanguage, 'metrics', this.state.metrics);
|
||||||
|
|
||||||
// Trigger re-render
|
// Trigger re-render
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
// Bogus edit to trigger highlighting
|
// Bogus edit to trigger highlighting
|
||||||
@ -162,7 +167,7 @@ class QueryField extends React.Component<any, any> {
|
|||||||
const selection = window.getSelection();
|
const selection = window.getSelection();
|
||||||
if (selection.anchorNode) {
|
if (selection.anchorNode) {
|
||||||
const wrapperNode = selection.anchorNode.parentElement;
|
const wrapperNode = selection.anchorNode.parentElement;
|
||||||
const editorNode = wrapperNode.closest('.query-field');
|
const editorNode = wrapperNode.closest('.slate-query-field');
|
||||||
if (!editorNode || this.state.value.isBlurred) {
|
if (!editorNode || this.state.value.isBlurred) {
|
||||||
// Not inside this editor
|
// Not inside this editor
|
||||||
return;
|
return;
|
||||||
@ -330,20 +335,30 @@ class QueryField extends React.Component<any, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown = (event, change) => {
|
onKeyDown = (event, change) => {
|
||||||
if (this.menuEl) {
|
|
||||||
const { typeaheadIndex, suggestions } = this.state;
|
const { typeaheadIndex, suggestions } = this.state;
|
||||||
|
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Escape': {
|
case 'Escape': {
|
||||||
if (this.menuEl) {
|
if (this.menuEl) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
this.resetTypeahead();
|
this.resetTypeahead();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ' ': {
|
||||||
|
if (event.ctrlKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.handleTypeahead();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'Tab': {
|
case 'Tab': {
|
||||||
|
if (this.menuEl) {
|
||||||
// Dont blur input
|
// Dont blur input
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!suggestions || suggestions.length === 0) {
|
if (!suggestions || suggestions.length === 0) {
|
||||||
@ -359,18 +374,24 @@ class QueryField extends React.Component<any, any> {
|
|||||||
this.applyTypeahead(change, suggestion);
|
this.applyTypeahead(change, suggestion);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'ArrowDown': {
|
case 'ArrowDown': {
|
||||||
|
if (this.menuEl) {
|
||||||
// Select next suggestion
|
// Select next suggestion
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.setState({ typeaheadIndex: typeaheadIndex + 1 });
|
this.setState({ typeaheadIndex: typeaheadIndex + 1 });
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'ArrowUp': {
|
case 'ArrowUp': {
|
||||||
|
if (this.menuEl) {
|
||||||
// Select previous suggestion
|
// Select previous suggestion
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.setState({ typeaheadIndex: Math.max(0, typeaheadIndex - 1) });
|
this.setState({ typeaheadIndex: Math.max(0, typeaheadIndex - 1) });
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +400,6 @@ class QueryField extends React.Component<any, any> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -502,10 +522,17 @@ class QueryField extends React.Component<any, any> {
|
|||||||
|
|
||||||
// Align menu overlay to editor node
|
// Align menu overlay to editor node
|
||||||
if (node) {
|
if (node) {
|
||||||
|
// Read from DOM
|
||||||
const rect = node.parentElement.getBoundingClientRect();
|
const rect = node.parentElement.getBoundingClientRect();
|
||||||
|
const scrollX = window.scrollX;
|
||||||
|
const scrollY = window.scrollY;
|
||||||
|
|
||||||
|
// Write DOM
|
||||||
|
requestAnimationFrame(() => {
|
||||||
menu.style.opacity = 1;
|
menu.style.opacity = 1;
|
||||||
menu.style.top = `${rect.top + window.scrollY + rect.height + 4}px`;
|
menu.style.top = `${rect.top + scrollY + rect.height + 4}px`;
|
||||||
menu.style.left = `${rect.left + window.scrollX - 2}px`;
|
menu.style.left = `${rect.left + scrollX - 2}px`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -514,6 +541,7 @@ class QueryField extends React.Component<any, any> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderMenu = () => {
|
renderMenu = () => {
|
||||||
|
const { portalPrefix } = this.props;
|
||||||
const { suggestions } = this.state;
|
const { suggestions } = this.state;
|
||||||
const hasSuggesstions = suggestions && suggestions.length > 0;
|
const hasSuggesstions = suggestions && suggestions.length > 0;
|
||||||
if (!hasSuggesstions) {
|
if (!hasSuggesstions) {
|
||||||
@ -524,11 +552,13 @@ class QueryField extends React.Component<any, any> {
|
|||||||
let selectedIndex = Math.max(this.state.typeaheadIndex, 0);
|
let selectedIndex = Math.max(this.state.typeaheadIndex, 0);
|
||||||
const flattenedSuggestions = flattenSuggestions(suggestions);
|
const flattenedSuggestions = flattenSuggestions(suggestions);
|
||||||
selectedIndex = selectedIndex % flattenedSuggestions.length || 0;
|
selectedIndex = selectedIndex % flattenedSuggestions.length || 0;
|
||||||
const selectedKeys = flattenedSuggestions.length > 0 ? [flattenedSuggestions[selectedIndex]] : [];
|
const selectedKeys = (flattenedSuggestions.length > 0 ? [flattenedSuggestions[selectedIndex]] : []).map(
|
||||||
|
i => (typeof i === 'object' ? i.text : i)
|
||||||
|
);
|
||||||
|
|
||||||
// Create typeahead in DOM root so we can later position it absolutely
|
// Create typeahead in DOM root so we can later position it absolutely
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal prefix={portalPrefix}>
|
||||||
<Typeahead
|
<Typeahead
|
||||||
menuRef={this.menuRef}
|
menuRef={this.menuRef}
|
||||||
selectedItems={selectedKeys}
|
selectedItems={selectedKeys}
|
||||||
@ -541,7 +571,7 @@ class QueryField extends React.Component<any, any> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="query-field">
|
<div className="slate-query-field">
|
||||||
{this.renderMenu()}
|
{this.renderMenu()}
|
||||||
<Editor
|
<Editor
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
|
import promql from './slate-plugins/prism/promql';
|
||||||
import QueryField from './QueryField';
|
import QueryField from './QueryField';
|
||||||
|
|
||||||
class QueryRow extends PureComponent<any, any> {
|
class QueryRow extends PureComponent<any, any> {
|
||||||
@ -55,12 +56,15 @@ class QueryRow extends PureComponent<any, any> {
|
|||||||
<i className="fa fa-minus" />
|
<i className="fa fa-minus" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="query-field-wrapper">
|
<div className="slate-query-field-wrapper">
|
||||||
<QueryField
|
<QueryField
|
||||||
initialQuery={edited ? null : query}
|
initialQuery={edited ? null : query}
|
||||||
|
portalPrefix="explore"
|
||||||
onPressEnter={this.handlePressEnter}
|
onPressEnter={this.handlePressEnter}
|
||||||
onQueryChange={this.handleChangeQuery}
|
onQueryChange={this.handleChangeQuery}
|
||||||
placeholder="Enter a PromQL query"
|
placeholder="Enter a PromQL query"
|
||||||
|
prismLanguage="promql"
|
||||||
|
prismDefinition={promql}
|
||||||
request={request}
|
request={request}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,12 +23,13 @@ class TypeaheadItem extends React.PureComponent<any, any> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isSelected, label, onClickItem } = this.props;
|
const { hint, isSelected, label, onClickItem } = this.props;
|
||||||
const className = isSelected ? 'typeahead-item typeahead-item__selected' : 'typeahead-item';
|
const className = isSelected ? 'typeahead-item typeahead-item__selected' : 'typeahead-item';
|
||||||
const onClick = () => onClickItem(label);
|
const onClick = () => onClickItem(label);
|
||||||
return (
|
return (
|
||||||
<li ref={this.getRef} className={className} onClick={onClick}>
|
<li ref={this.getRef} className={className} onClick={onClick}>
|
||||||
{label}
|
{label}
|
||||||
|
{hint && isSelected ? <div className="typeahead-item-hint">{hint}</div> : null}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -41,9 +42,19 @@ class TypeaheadGroup extends React.PureComponent<any, any> {
|
|||||||
<li className="typeahead-group">
|
<li className="typeahead-group">
|
||||||
<div className="typeahead-group__title">{label}</div>
|
<div className="typeahead-group__title">{label}</div>
|
||||||
<ul className="typeahead-group__list">
|
<ul className="typeahead-group__list">
|
||||||
{items.map(item => (
|
{items.map(item => {
|
||||||
<TypeaheadItem key={item} onClickItem={onClickItem} isSelected={selected.indexOf(item) > -1} label={item} />
|
const text = typeof item === 'object' ? item.text : item;
|
||||||
))}
|
const label = typeof item === 'object' ? item.display || item.text : item;
|
||||||
|
return (
|
||||||
|
<TypeaheadItem
|
||||||
|
key={text}
|
||||||
|
onClickItem={onClickItem}
|
||||||
|
isSelected={selected.indexOf(text) > -1}
|
||||||
|
hint={item.hint}
|
||||||
|
label={label}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Prism from 'prismjs';
|
import Prism from 'prismjs';
|
||||||
|
|
||||||
import Promql from './promql';
|
|
||||||
|
|
||||||
Prism.languages.promql = Promql;
|
|
||||||
|
|
||||||
const TOKEN_MARK = 'prism-token';
|
const TOKEN_MARK = 'prism-token';
|
||||||
|
|
||||||
export function configurePrismMetricsTokens(metrics) {
|
export function setPrismTokens(language, field, values, alias = 'variable') {
|
||||||
Prism.languages.promql.metric = {
|
Prism.languages[language][field] = {
|
||||||
alias: 'variable',
|
alias,
|
||||||
pattern: new RegExp(`(?:^|\\s)(${metrics.join('|')})(?:$|\\s)`),
|
pattern: new RegExp(`(?:^|\\s)(${values.join('|')})(?:$|\\s)`),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,7 +17,12 @@ export function configurePrismMetricsTokens(metrics) {
|
|||||||
* (Adapted to handle nested grammar definitions.)
|
* (Adapted to handle nested grammar definitions.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default function PrismPlugin() {
|
export default function PrismPlugin({ definition, language }) {
|
||||||
|
if (definition) {
|
||||||
|
// Don't override exising modified definitions
|
||||||
|
Prism.languages[language] = Prism.languages[language] || definition;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* Render a Slate mark with appropiate CSS class names
|
* Render a Slate mark with appropiate CSS class names
|
||||||
@ -54,7 +55,7 @@ export default function PrismPlugin() {
|
|||||||
|
|
||||||
const texts = node.getTexts().toArray();
|
const texts = node.getTexts().toArray();
|
||||||
const tstring = texts.map(t => t.text).join('\n');
|
const tstring = texts.map(t => t.text).join('\n');
|
||||||
const grammar = Prism.languages.promql;
|
const grammar = Prism.languages[language];
|
||||||
const tokens = Prism.tokenize(tstring, grammar);
|
const tokens = Prism.tokenize(tstring, grammar);
|
||||||
const decorations = [];
|
const decorations = [];
|
||||||
let startText = texts.shift();
|
let startText = texts.shift();
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
@import 'components/filter-list';
|
@import 'components/filter-list';
|
||||||
@import 'components/filter-table';
|
@import 'components/filter-table';
|
||||||
@import 'components/old_stuff';
|
@import 'components/old_stuff';
|
||||||
|
@import 'components/slate_editor';
|
||||||
@import 'components/typeahead';
|
@import 'components/typeahead';
|
||||||
@import 'components/modals';
|
@import 'components/modals';
|
||||||
@import 'components/dropdown';
|
@import 'components/dropdown';
|
||||||
|
151
public/sass/components/_slate_editor.scss
Normal file
151
public/sass/components/_slate_editor.scss
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
.slate-query-field {
|
||||||
|
font-size: $font-size-root;
|
||||||
|
font-family: $font-family-monospace;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slate-query-field-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 7px 4px;
|
||||||
|
width: 100%;
|
||||||
|
cursor: text;
|
||||||
|
line-height: $line-height-base;
|
||||||
|
color: $text-color-weak;
|
||||||
|
background-color: $panel-bg;
|
||||||
|
background-image: none;
|
||||||
|
border: $panel-border;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slate-typeahead {
|
||||||
|
.typeahead {
|
||||||
|
position: absolute;
|
||||||
|
z-index: auto;
|
||||||
|
top: -10000px;
|
||||||
|
left: -10000px;
|
||||||
|
opacity: 0;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
transition: opacity 0.75s;
|
||||||
|
border: $panel-border;
|
||||||
|
max-height: calc(66vh);
|
||||||
|
overflow-y: scroll;
|
||||||
|
max-width: calc(66%);
|
||||||
|
overflow-x: hidden;
|
||||||
|
outline: none;
|
||||||
|
list-style: none;
|
||||||
|
background: $panel-bg;
|
||||||
|
color: $text-color;
|
||||||
|
transition: opacity 0.4s ease-out;
|
||||||
|
box-shadow: $typeahead-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typeahead-group__title {
|
||||||
|
color: $text-color-weak;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
line-height: $line-height-base;
|
||||||
|
padding: $input-padding-y $input-padding-x;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typeahead-item {
|
||||||
|
height: auto;
|
||||||
|
font-family: $font-family-monospace;
|
||||||
|
padding: $input-padding-y $input-padding-x;
|
||||||
|
padding-left: $input-padding-x-lg;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 1;
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), border-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
|
||||||
|
background 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), padding 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.typeahead-item__selected {
|
||||||
|
background-color: $typeahead-selected-bg;
|
||||||
|
color: $typeahead-selected-color;
|
||||||
|
|
||||||
|
.typeahead-item-hint {
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
color: $text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SYNTAX */
|
||||||
|
|
||||||
|
.slate-query-field {
|
||||||
|
.token.comment,
|
||||||
|
.token.block-comment,
|
||||||
|
.token.prolog,
|
||||||
|
.token.doctype,
|
||||||
|
.token.cdata {
|
||||||
|
color: $text-color-weak;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.punctuation {
|
||||||
|
color: $text-color-weak;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.property,
|
||||||
|
.token.tag,
|
||||||
|
.token.boolean,
|
||||||
|
.token.number,
|
||||||
|
.token.function-name,
|
||||||
|
.token.constant,
|
||||||
|
.token.symbol,
|
||||||
|
.token.deleted {
|
||||||
|
color: $query-red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.selector,
|
||||||
|
.token.attr-name,
|
||||||
|
.token.string,
|
||||||
|
.token.char,
|
||||||
|
.token.function,
|
||||||
|
.token.builtin,
|
||||||
|
.token.inserted {
|
||||||
|
color: $query-green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.operator,
|
||||||
|
.token.entity,
|
||||||
|
.token.url,
|
||||||
|
.token.variable {
|
||||||
|
color: $query-purple;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.atrule,
|
||||||
|
.token.attr-value,
|
||||||
|
.token.keyword,
|
||||||
|
.token.class-name {
|
||||||
|
color: $query-blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.regex,
|
||||||
|
.token.important {
|
||||||
|
color: $query-orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.important {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.token.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.entity {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
|
.namespace {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
@ -93,150 +93,3 @@
|
|||||||
.query-row-tools {
|
.query-row-tools {
|
||||||
width: 4rem;
|
width: 4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.query-field {
|
|
||||||
font-size: $font-size-root;
|
|
||||||
font-family: $font-family-monospace;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.query-field-wrapper {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 6px 7px 4px;
|
|
||||||
width: 100%;
|
|
||||||
cursor: text;
|
|
||||||
line-height: $line-height-base;
|
|
||||||
color: $text-color-weak;
|
|
||||||
background-color: $panel-bg;
|
|
||||||
background-image: none;
|
|
||||||
border: $panel-border;
|
|
||||||
border-radius: $border-radius;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.explore-typeahead {
|
|
||||||
.typeahead {
|
|
||||||
position: absolute;
|
|
||||||
z-index: auto;
|
|
||||||
top: -10000px;
|
|
||||||
left: -10000px;
|
|
||||||
opacity: 0;
|
|
||||||
border-radius: $border-radius;
|
|
||||||
transition: opacity 0.75s;
|
|
||||||
border: $panel-border;
|
|
||||||
max-height: calc(66vh);
|
|
||||||
overflow-y: scroll;
|
|
||||||
max-width: calc(66%);
|
|
||||||
overflow-x: hidden;
|
|
||||||
outline: none;
|
|
||||||
list-style: none;
|
|
||||||
background: $panel-bg;
|
|
||||||
color: $text-color;
|
|
||||||
transition: opacity 0.4s ease-out;
|
|
||||||
box-shadow: $typeahead-shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
.typeahead-group__title {
|
|
||||||
color: $text-color-weak;
|
|
||||||
font-size: $font-size-sm;
|
|
||||||
line-height: $line-height-base;
|
|
||||||
padding: $input-padding-y $input-padding-x;
|
|
||||||
}
|
|
||||||
|
|
||||||
.typeahead-item {
|
|
||||||
height: auto;
|
|
||||||
font-family: $font-family-monospace;
|
|
||||||
padding: $input-padding-y $input-padding-x;
|
|
||||||
padding-left: $input-padding-x-lg;
|
|
||||||
font-size: $font-size-sm;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: 1;
|
|
||||||
display: block;
|
|
||||||
white-space: nowrap;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), border-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
|
|
||||||
background 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), padding 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.typeahead-item__selected {
|
|
||||||
background-color: $typeahead-selected-bg;
|
|
||||||
color: $typeahead-selected-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SYNTAX */
|
|
||||||
|
|
||||||
.explore {
|
|
||||||
.token.comment,
|
|
||||||
.token.block-comment,
|
|
||||||
.token.prolog,
|
|
||||||
.token.doctype,
|
|
||||||
.token.cdata {
|
|
||||||
color: $text-color-weak;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.punctuation {
|
|
||||||
color: $text-color-weak;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.property,
|
|
||||||
.token.tag,
|
|
||||||
.token.boolean,
|
|
||||||
.token.number,
|
|
||||||
.token.function-name,
|
|
||||||
.token.constant,
|
|
||||||
.token.symbol,
|
|
||||||
.token.deleted {
|
|
||||||
color: $query-red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.selector,
|
|
||||||
.token.attr-name,
|
|
||||||
.token.string,
|
|
||||||
.token.char,
|
|
||||||
.token.function,
|
|
||||||
.token.builtin,
|
|
||||||
.token.inserted {
|
|
||||||
color: $query-green;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.operator,
|
|
||||||
.token.entity,
|
|
||||||
.token.url,
|
|
||||||
.token.variable {
|
|
||||||
color: $query-purple;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.atrule,
|
|
||||||
.token.attr-value,
|
|
||||||
.token.keyword,
|
|
||||||
.token.class-name {
|
|
||||||
color: $query-blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.regex,
|
|
||||||
.token.important {
|
|
||||||
color: $query-orange;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.important {
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.bold {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.token.italic {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.entity {
|
|
||||||
cursor: help;
|
|
||||||
}
|
|
||||||
|
|
||||||
.namespace {
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user