From 3233b7d9e8c317a19d65f1f76873f15d31fd4e04 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Sun, 16 Jun 2019 14:54:38 +0200 Subject: [PATCH 01/18] feat: add mql page --- data/introspection.json | 1341 +++++++++++ env.js | 17 +- gatsby-config.js | 2 + gatsby-node.js | 11 + package.json | 5 +- scripts/fetch-introspection-query.js | 33 + .../elements/CodeEditor/CodeEditor.js | 2 +- src/components/hook/use-site-meta.js | 1 + src/components/pages/mql/style.css | 2089 +++++++++++++++++ src/pages/mql.js | 129 + 10 files changed, 3621 insertions(+), 9 deletions(-) create mode 100644 data/introspection.json create mode 100644 scripts/fetch-introspection-query.js create mode 100644 src/components/pages/mql/style.css create mode 100644 src/pages/mql.js diff --git a/data/introspection.json b/data/introspection.json new file mode 100644 index 000000000..f86d88c43 --- /dev/null +++ b/data/introspection.json @@ -0,0 +1,1341 @@ +{ + "__schema": { + "queryType": { + "name": "Query" + }, + "mutationType": null, + "subscriptionType": null, + "types": [ + { + "kind": "OBJECT", + "name": "Query", + "description": "", + "fields": [ + { + "name": "page", + "description": "", + "args": [ + { + "name": "url", + "description": "", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "force", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "userAgent", + "description": "", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Selector", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "String", + "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Boolean", + "description": "The `Boolean` scalar type represents `true` or `false`.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Selector", + "description": "", + "fields": [ + { + "name": "lang", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "author", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "publisher", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "title", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logo", + "description": "", + "args": [], + "type": { + "kind": "OBJECT", + "name": "Image", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "url", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "date", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "image", + "description": "", + "args": [ + { + "name": "selector", + "description": "", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "attr", + "description": "", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Image", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "text", + "description": "", + "args": [ + { + "name": "selector", + "description": "", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Image", + "description": "", + "fields": [ + { + "name": "url", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "width", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "height", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "size", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "palette", + "description": "", + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "background_color", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "color", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "alternative_color", + "description": "", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Int", + "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Schema", + "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", + "fields": [ + { + "name": "types", + "description": "A list of all types supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "queryType", + "description": "The type that query operations will be rooted at.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mutationType", + "description": "If this server supports mutation, the type that mutation operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subscriptionType", + "description": "If this server support subscription, the type that subscription operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "directives", + "description": "A list of all directives supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Directive", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Type", + "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", + "fields": [ + { + "name": "kind", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__TypeKind", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fields", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Field", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "interfaces", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "possibleTypes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "enumValues", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__EnumValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "inputFields", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ofType", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__TypeKind", + "description": "An enum describing what kind of type a given `__Type` is.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "SCALAR", + "description": "Indicates this type is a scalar.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Indicates this type is a union. `possibleTypes` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Indicates this type is an enum. `enumValues` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Indicates this type is an input object. `inputFields` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "LIST", + "description": "Indicates this type is a list. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "NON_NULL", + "description": "Indicates this type is a non-null. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Field", + "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__InputValue", + "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "defaultValue", + "description": "A GraphQL-formatted string representing the default value for this input value.", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__EnumValue", + "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Directive", + "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "locations", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__DirectiveLocation", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__DirectiveLocation", + "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "QUERY", + "description": "Location adjacent to a query operation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "MUTATION", + "description": "Location adjacent to a mutation operation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "SUBSCRIPTION", + "description": "Location adjacent to a subscription operation.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD", + "description": "Location adjacent to a field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_DEFINITION", + "description": "Location adjacent to a fragment definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_SPREAD", + "description": "Location adjacent to a fragment spread.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INLINE_FRAGMENT", + "description": "Location adjacent to an inline fragment.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "VARIABLE_DEFINITION", + "description": "Location adjacent to a variable definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "SCHEMA", + "description": "Location adjacent to a schema definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "SCALAR", + "description": "Location adjacent to a scalar definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Location adjacent to an object type definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD_DEFINITION", + "description": "Location adjacent to a field definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ARGUMENT_DEFINITION", + "description": "Location adjacent to an argument definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Location adjacent to an interface definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Location adjacent to a union definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Location adjacent to an enum definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM_VALUE", + "description": "Location adjacent to an enum value definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Location adjacent to an input object type definition.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_FIELD_DEFINITION", + "description": "Location adjacent to an input object field definition.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "CacheControlScope", + "description": "", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "PUBLIC", + "description": "", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "PRIVATE", + "description": "", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Upload", + "description": "The `Upload` scalar type represents a file upload.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + } + ], + "directives": [ + { + "name": "cacheControl", + "description": "", + "locations": [ + "FIELD_DEFINITION", + "OBJECT", + "INTERFACE" + ], + "args": [ + { + "name": "maxAge", + "description": "", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "scope", + "description": "", + "type": { + "kind": "ENUM", + "name": "CacheControlScope", + "ofType": null + }, + "defaultValue": null + } + ] + }, + { + "name": "skip", + "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Skipped when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + }, + { + "name": "include", + "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Included when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + }, + { + "name": "deprecated", + "description": "Marks an element of a GraphQL schema as no longer supported.", + "locations": [ + "FIELD_DEFINITION", + "ENUM_VALUE" + ], + "args": [ + { + "name": "reason", + "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax (as specified by [CommonMark](https://commonmark.org/).", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": "\"No longer supported\"" + } + ] + } + ] + } +} diff --git a/env.js b/env.js index 0d813d804..f6760db52 100644 --- a/env.js +++ b/env.js @@ -11,12 +11,14 @@ const { STRIPE_KEY, PAYMENT_API_KEY, PAYMENT_ENDPOINT, - GOOGLE_ANALYTICS_ID + GOOGLE_ANALYTICS_ID, + MICROLINK_API_ENDPOINT } = process.env if (!STRIPE_KEY) throw envError('STRIPE_KEY') if (!PAYMENT_API_KEY) throw envError('PAYMENT_API_KEY') if (!PAYMENT_ENDPOINT) throw envError('PAYMENT_ENDPOINT') +if (!MICROLINK_API_ENDPOINT) throw envError('MICROLINK_API_ENDPOINT') const isProduction = NODE_ENV === 'production' @@ -26,14 +28,15 @@ const SITE_URL = (() => { })() module.exports = { - isProduction, - DEPLOY_URL, CONTEXT, + DEPLOY_URL, + GOOGLE_ANALYTICS_ID, + isProduction, + MICROLINK_API_ENDPOINT, NODE_ENV, - URL, - STRIPE_KEY, PAYMENT_API_KEY, PAYMENT_ENDPOINT, - GOOGLE_ANALYTICS_ID, - SITE_URL + SITE_URL, + STRIPE_KEY, + URL } diff --git a/gatsby-config.js b/gatsby-config.js index ffd44f6bc..9579f3753 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -5,6 +5,7 @@ const { PAYMENT_API_KEY, PAYMENT_ENDPOINT, GOOGLE_ANALYTICS_ID, + MICROLINK_API_ENDPOINT, SITE_URL } = require('./env') @@ -29,6 +30,7 @@ module.exports = { // additional paymentApiKey: PAYMENT_API_KEY, paymentEndpoint: PAYMENT_ENDPOINT, + apiEndpoint: MICROLINK_API_ENDPOINT, stripeKey: STRIPE_KEY }, plugins: [ diff --git a/gatsby-node.js b/gatsby-node.js index 971ced7ff..82cd0fe3a 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -29,6 +29,17 @@ const githubUrl = (() => { })() exports.onCreateWebpackConfig = ({ getConfig, loaders, stage, actions }) => { + actions.setWebpackConfig({ + module: { + rules: [ + { + test: /.js.flow$/, + use: loaders.null() + } + ] + } + }) + if (stage === 'build-html') { actions.setWebpackConfig({ module: { diff --git a/package.json b/package.json index 8e1d0f699..d2cb79a56 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,9 @@ "gatsby-transformer-remark": "~2.3.12", "gatsby-transformer-yaml": "~2.1.12", "git-jiggy": "~1.1.1", + "graphiql": "~0.13.0", + "graphiql-explorer": "~0.4.3", + "graphql": "~14.3.1", "human-number": "~1.0.3", "humanize-url": "~2.1.0", "json-future": "~2.2.0", @@ -150,7 +153,7 @@ "lint": "standard-markdown README.md && standard src/*/**.js", "postrelease": "npm run release:tags && npm run release:github", "prebuild": "npm run clean:urls && npm run clean:build && npm run build:urls", - "predev": "node scripts/fetch-demo-links", + "predev": "node scripts/fetch-demo-links && node scripts/fetch-introspection-query", "prerelease": "npm run update:check && git-authors-cli", "release": "git-authors-cli && git add package.json && standard-version -a", "release:github": "conventional-github-releaser -p angular", diff --git a/scripts/fetch-introspection-query.js b/scripts/fetch-introspection-query.js new file mode 100644 index 000000000..e5b97bf13 --- /dev/null +++ b/scripts/fetch-introspection-query.js @@ -0,0 +1,33 @@ +'use strict' + +const { getIntrospectionQuery } = require('graphql') +const { stringify } = require('querystring') +const beautyError = require('beauty-error') +const jsonFuture = require('json-future') +const existsFile = require('exists-file') +const path = require('path') +const got = require('got') + +const { NODE_ENV, MICROLINK_API_ENDPOINT } = require('../env') + +const INTROSPECTION_PATH = path.resolve(__dirname, '../data/introspection.json') + +const main = async () => { + if (!existsFile.sync(INTROSPECTION_PATH)) { + throw new Error('Introspection file not detected!') + } + + if (NODE_ENV === 'production') return + + const graphqlEndpoint = `${MICROLINK_API_ENDPOINT}/___graphql` + const query = stringify({ query: getIntrospectionQuery() }) + const { body } = await got(`${graphqlEndpoint}?${query}`, { json: true }) + return jsonFuture.saveAsync(INTROSPECTION_PATH, body) +} + +main() + .then(() => process.exit()) + .catch(err => { + console.log(beautyError(err)) + process.exit(1) + }) diff --git a/src/components/elements/CodeEditor/CodeEditor.js b/src/components/elements/CodeEditor/CodeEditor.js index 8f1f54b39..73cfffd54 100644 --- a/src/components/elements/CodeEditor/CodeEditor.js +++ b/src/components/elements/CodeEditor/CodeEditor.js @@ -1,7 +1,7 @@ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' -import { prettier, getLines, serializeComponent } from 'helpers' import styled, { css } from 'styled-components' import { get, identity, range } from 'lodash' +import { prettier, getLines } from 'helpers' import { Box } from 'components/elements' import React, { useState } from 'react' import CodeCopy from 'react-codecopy' diff --git a/src/components/hook/use-site-meta.js b/src/components/hook/use-site-meta.js index 573432d1f..b107d7963 100644 --- a/src/components/hook/use-site-meta.js +++ b/src/components/hook/use-site-meta.js @@ -8,6 +8,7 @@ export const useSiteMetadata = () => { siteMetadata { paymentEndpoint paymentApiKey + apiEndpoint stripeKey siteUrl headline diff --git a/src/components/pages/mql/style.css b/src/components/pages/mql/style.css new file mode 100644 index 000000000..7e0a42ced --- /dev/null +++ b/src/components/pages/mql/style.css @@ -0,0 +1,2089 @@ +:root { + --sans: 'Inter', sans-serif; + --mono: "Operator Mono", "Fira Code", "SF Mono", "Roboto Mono", Menlo, monospace; + --base: #449bf8; + --secondary: #EA407B; + --black: #3a3f44; + --gray0: #f8f9fa; + --gray1: #ebedef; + --gray2: #dde1e4; + --gray3: #ced3d8; + --gray4: #bdc4cb; + --gray5: #aab4bd; + --gray6: #95a1ac; + --gray7: #7f8a94; + --gray8: #646d75; + --gray9: #3a3f44; + --blue0: #e8f3fe; + --blue1: #d0e6fd; + --blue2: #b5d7fc; + --blue3: #96c6fb; + --blue4: #71b3f9; + --blue5: #449bf8; + --blue6: #3d8ce0; + --blue7: #357ac4; + --blue8: #2c65a2; + --blue9: #1f4874; + --indigo0: #ececfe; + --indigo1: #d8d7fd; + --indigo2: #c1c0fc; + --indigo3: #a5a3fb; + --indigo4: #817ffa; + --indigo5: #4744f8; + --indigo6: #3f3ddf; + --indigo7: #3735c2; + --indigo8: #2d2b9f; + --indigo9: #201e70; + --violet0: #f5ebfe; + --violet1: #ead6fd; + --violet2: #debdfc; + --violet3: #cfa0fb; + --violet4: #bd7bfa; + --violet5: #a144f8; + --violet6: #913ddf; + --violet7: #7f35c3; + --violet8: #682ca1; + --violet9: #4a1f72; + --fuschia0: #feecfe; + --fuschia1: #fdd7fc; + --fuschia2: #fcbffb; + --fuschia3: #fba3fa; + --fuschia4: #fa7ef8; + --fuschia5: #f844f5; + --fuschia6: #e03ddd; + --fuschia7: #c435c2; + --fuschia8: #a32ca1; + --fuschia9: #752074; + --pink0: #feecf4; + --pink1: #fdd6e9; + --pink2: #fcbedc; + --pink3: #fba2cd; + --pink4: #fa7db9; + --pink5: #f8449b; + --pink6: #e03d8c; + --pink7: #c4357a; + --pink8: #a22c65; + --pink9: #742049; + --red0: #feecec; + --red1: #fdd7d7; + --red2: #fcc0bf; + --red3: #fba4a2; + --red4: #fa807e; + --red5: #f84744; + --red6: #e0403d; + --red7: #c43835; + --red8: #a22e2c; + --red9: #74211f; + --orange0: #fef3e7; + --orange1: #fde6cd; + --orange2: #fcd7b1; + --orange3: #fac891; + --orange4: #f9b66e; + --orange5: #f8a144; + --orange6: #e0913d; + --orange7: #c47f35; + --orange8: #a36a2c; + --orange9: #754c20; + --yellow0: #fdfee8; + --yellow1: #fcfdce; + --yellow2: #fafcb3; + --yellow3: #f9fa93; + --yellow4: #f7f96f; + --yellow5: #f5f844; + --yellow6: #dee03d; + --yellow7: #c3c536; + --yellow8: #a2a42d; + --yellow9: #767720; + --lime0: #f2fee7; + --lime1: #e5fdce; + --lime2: #d6fcb2; + --lime3: #c5fa93; + --lime4: #b2f96f; + --lime5: #9bf844; + --lime6: #8ce03d; + --lime7: #7bc536; + --lime8: #66a42d; + --lime9: #4a7720; + --green0: #ebfeeb; + --green1: #d5fdd6; + --green2: #bcfcbd; + --green3: #9ffba0; + --green4: #7afa7c; + --green5: #44f847; + --green6: #3de040; + --green7: #36c538; + --green8: #2da42f; + --green9: #207722; + --teal0: #eafef4; + --teal1: #d3fde9; + --teal2: #b9fcdc; + --teal3: #9bfbcd; + --teal4: #76f9ba; + --teal5: #44f8a1; + --teal6: #3de091; + --teal7: #36c580; + --teal8: #2da46a; + --teal9: #20774d; + --cyan0: #eafdfe; + --cyan1: #d3fcfd; + --cyan2: #b9fbfc; + --cyan3: #9bf9fb; + --cyan4: #76f7f9; + --cyan5: #44f5f8; + --cyan6: #3ddde0; + --cyan7: #36c3c5; + --cyan8: #2da2a4; + --cyan9: #207677 +} + + +.graphiql-container, +.graphiql-container button, +.graphiql-container input { + color: #141823; + font-family: var(--sans); + font-size: 14px; +} + +.graphiql-container { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + height: 100%; + margin: 0; + overflow: hidden; + width: 100%; +} + +.graphiql-container .editorWrap { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + overflow-x: hidden; +} + +.graphiql-container .title { + font-size: 18px; +} + +.graphiql-container .title em { + font-family: georgia; + font-size: 19px; +} + +.graphiql-container .topBarWrap { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; +} + +.graphiql-container .topBar { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background: -webkit-gradient(linear, left top, left bottom, from(#f7f7f7), to(#e2e2e2)); + background: linear-gradient(#f7f7f7, #e2e2e2); + border-bottom: 1px solid #d0d0d0; + cursor: default; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + height: 34px; + overflow-y: visible; + padding: 7px 14px 6px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.graphiql-container .toolbar { + overflow-x: visible; + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} + +.graphiql-container .docExplorerShow, +.graphiql-container .historyShow { + background: -webkit-gradient(linear, left top, left bottom, from(#f7f7f7), to(#e2e2e2)); + background: linear-gradient(#f7f7f7, #e2e2e2); + border-radius: 0; + border-bottom: 1px solid #d0d0d0; + border-right: none; + border-top: none; + color: #3B5998; + cursor: pointer; + font-size: 14px; + margin: 0; + outline: 0; + padding: 2px 20px 0 18px; +} + +.graphiql-container .docExplorerShow { + border-left: 1px solid rgba(0, 0, 0, 0.2); +} + +.graphiql-container .historyShow { + border-right: 1px solid rgba(0, 0, 0, 0.2); + border-left: 0; +} + +.graphiql-container .docExplorerShow:before { + border-left: 2px solid #3B5998; + border-top: 2px solid #3B5998; + content: ''; + display: inline-block; + height: 9px; + margin: 0 3px -1px 0; + position: relative; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + width: 9px; +} + +.graphiql-container .editorBar { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.graphiql-container .queryWrap { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.graphiql-container .resultWrap { + border-left: solid 1px #e0e0e0; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + position: relative; +} + +.graphiql-container .docExplorerWrap, +.graphiql-container .historyPaneWrap { + background: white; + -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 8px rgba(0, 0, 0, 0.15); + position: relative; + z-index: 3; +} + +.graphiql-container .historyPaneWrap { + min-width: 230px; + z-index: 5; +} + +.graphiql-container .docExplorerResizer { + cursor: col-resize; + height: 100%; + left: -5px; + position: absolute; + top: 0; + width: 10px; + z-index: 10; +} + +.graphiql-container .docExplorerHide { + cursor: pointer; + font-size: 18px; + margin: -7px -8px -6px 0; + padding: 18px 16px 15px 12px; +} + +.graphiql-container div .query-editor { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + position: relative; +} + +.graphiql-container .variable-editor { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + height: 30px; + position: relative; +} + +.graphiql-container .variable-editor-title { + background: #eeeeee; + border-bottom: 1px solid #d6d6d6; + border-top: 1px solid #e0e0e0; + color: #777; + font-variant: small-caps; + font-weight: bold; + letter-spacing: 1px; + line-height: 14px; + padding: 6px 0 8px 43px; + text-transform: lowercase; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.graphiql-container .codemirrorWrap { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + height: 100%; + position: relative; +} + +.graphiql-container .result-window { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + height: 100%; + position: relative; +} + +.graphiql-container .footer { + background: #f6f7f8; + border-left: 1px solid #e0e0e0; + border-top: 1px solid #e0e0e0; + margin-left: 12px; + position: relative; +} + +.graphiql-container .footer:before { + background: #eeeeee; + bottom: 0; + content: " "; + left: -13px; + position: absolute; + top: -1px; + width: 12px; +} + +/* No `.graphiql-container` here so themes can overwrite */ +.result-window .CodeMirror { + background: #f6f7f8; +} + +.graphiql-container .result-window .CodeMirror-gutters { + background-color: #eeeeee; + border-color: #e0e0e0; + cursor: col-resize; +} + +.graphiql-container .result-window .CodeMirror-foldgutter, +.graphiql-container .result-window .CodeMirror-foldgutter-open:after, +.graphiql-container .result-window .CodeMirror-foldgutter-folded:after { + padding-left: 3px; +} + +.graphiql-container .toolbar-button { + background: #fdfdfd; + background: -webkit-gradient(linear, left top, left bottom, from(#f9f9f9), to(#ececec)); + background: linear-gradient(#f9f9f9, #ececec); + border-radius: 3px; + -webkit-box-shadow: + inset 0 0 0 1px rgba(0, 0, 0, 0.20), + 0 1px 0 rgba(255, 255, 255, 0.7), + inset 0 1px #fff; + box-shadow: + inset 0 0 0 1px rgba(0, 0, 0, 0.20), + 0 1px 0 rgba(255, 255, 255, 0.7), + inset 0 1px #fff; + color: #555; + cursor: pointer; + display: inline-block; + margin: 0 5px; + padding: 3px 11px 5px; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 150px; +} + +.graphiql-container .toolbar-button:active { + background: -webkit-gradient(linear, left top, left bottom, from(#ececec), to(#d5d5d5)); + background: linear-gradient(#ececec, #d5d5d5); + -webkit-box-shadow: + 0 1px 0 rgba(255, 255, 255, 0.7), + inset 0 0 0 1px rgba(0, 0, 0, 0.10), + inset 0 1px 1px 1px rgba(0, 0, 0, 0.12), + inset 0 0 5px rgba(0, 0, 0, 0.1); + box-shadow: + 0 1px 0 rgba(255, 255, 255, 0.7), + inset 0 0 0 1px rgba(0, 0, 0, 0.10), + inset 0 1px 1px 1px rgba(0, 0, 0, 0.12), + inset 0 0 5px rgba(0, 0, 0, 0.1); +} + +.graphiql-container .toolbar-button.error { + background: -webkit-gradient(linear, left top, left bottom, from(#fdf3f3), to(#e6d6d7)); + background: linear-gradient(#fdf3f3, #e6d6d7); + color: #b00; +} + +.graphiql-container .toolbar-button-group { + margin: 0 5px; + white-space: nowrap; +} + +.graphiql-container .toolbar-button-group>* { + margin: 0; +} + +.graphiql-container .toolbar-button-group>*:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.graphiql-container .toolbar-button-group>*:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin-left: -1px; +} + +.graphiql-container .execute-button-wrap { + height: 34px; + margin: 0 14px 0 28px; + position: relative; +} + +.graphiql-container .execute-button { + background: -webkit-gradient(linear, left top, left bottom, from(#fdfdfd), to(#d2d3d6)); + background: linear-gradient(#fdfdfd, #d2d3d6); + border-radius: 17px; + border: 1px solid rgba(0, 0, 0, 0.25); + -webkit-box-shadow: 0 1px 0 #fff; + box-shadow: 0 1px 0 #fff; + cursor: pointer; + fill: #444; + height: 34px; + margin: 0; + padding: 0; + width: 34px; +} + +.graphiql-container .execute-button svg { + pointer-events: none; +} + +.graphiql-container .execute-button:active { + background: -webkit-gradient(linear, left top, left bottom, from(#e6e6e6), to(#c3c3c3)); + background: linear-gradient(#e6e6e6, #c3c3c3); + -webkit-box-shadow: + 0 1px 0 #fff, + inset 0 0 2px rgba(0, 0, 0, 0.2), + inset 0 0 6px rgba(0, 0, 0, 0.1); + box-shadow: + 0 1px 0 #fff, + inset 0 0 2px rgba(0, 0, 0, 0.2), + inset 0 0 6px rgba(0, 0, 0, 0.1); +} + +.graphiql-container .execute-button:focus { + outline: 0; +} + +.graphiql-container .toolbar-menu, +.graphiql-container .toolbar-select { + position: relative; +} + +.graphiql-container .execute-options, +.graphiql-container .toolbar-menu-items, +.graphiql-container .toolbar-select-options { + background: #fff; + -webkit-box-shadow: + 0 0 0 1px rgba(0, 0, 0, 0.1), + 0 2px 4px rgba(0, 0, 0, 0.25); + box-shadow: + 0 0 0 1px rgba(0, 0, 0, 0.1), + 0 2px 4px rgba(0, 0, 0, 0.25); + margin: 0; + padding: 6px 0; + position: absolute; + z-index: 100; +} + +.graphiql-container .execute-options { + min-width: 100px; + top: 37px; + left: -1px; +} + +.graphiql-container .toolbar-menu-items { + left: 1px; + margin-top: -1px; + min-width: 110%; + top: 100%; + visibility: hidden; +} + +.graphiql-container .toolbar-menu-items.open { + visibility: visible; +} + +.graphiql-container .toolbar-select-options { + left: 0; + min-width: 100%; + top: -5px; + visibility: hidden; +} + +.graphiql-container .toolbar-select-options.open { + visibility: visible; +} + +.graphiql-container .execute-options>li, +.graphiql-container .toolbar-menu-items>li, +.graphiql-container .toolbar-select-options>li { + cursor: pointer; + display: block; + margin: none; + max-width: 300px; + overflow: hidden; + padding: 2px 20px 4px 11px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.graphiql-container .execute-options>li.selected, +.graphiql-container .toolbar-menu-items>li.hover, +.graphiql-container .toolbar-menu-items>li:active, +.graphiql-container .toolbar-menu-items>li:hover, +.graphiql-container .toolbar-select-options>li.hover, +.graphiql-container .toolbar-select-options>li:active, +.graphiql-container .toolbar-select-options>li:hover, +.graphiql-container .history-contents>p:hover, +.graphiql-container .history-contents>p:active { + background: var(--secondary); + color: #fff; +} + +.graphiql-container .toolbar-select-options>li>svg { + display: inline; + fill: #666; + margin: 0 -6px 0 6px; + pointer-events: none; + vertical-align: middle; +} + +.graphiql-container .toolbar-select-options>li.hover>svg, +.graphiql-container .toolbar-select-options>li:active>svg, +.graphiql-container .toolbar-select-options>li:hover>svg { + fill: #fff; +} + +.graphiql-container .CodeMirror-scroll { + overflow-scrolling: touch; +} + +.graphiql-container .CodeMirror { + color: #141823; + font-family: var(--mono); + font-size: 16px; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.graphiql-container .CodeMirror-lines { + padding: 20px 0; +} + +.CodeMirror-hint-information .content { + box-orient: vertical; + color: #141823; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + font-family: system, -apple-system, 'San Francisco', '.SFNSDisplay-Regular', 'Segoe UI', Segoe, 'Segoe WP', 'Helvetica Neue', helvetica, 'Lucida Grande', arial, sans-serif; + font-size: 13px; + line-clamp: 3; + line-height: 16px; + max-height: 48px; + overflow: hidden; + text-overflow: -o-ellipsis-lastline; +} + +.CodeMirror-hint-information .content p:first-child { + margin-top: 0; +} + +.CodeMirror-hint-information .content p:last-child { + margin-bottom: 0; +} + +.CodeMirror-hint-information .infoType { + color: #CA9800; + cursor: pointer; + display: inline; + margin-right: 0.5em; +} + +.autoInsertedLeaf.cm-property { + -webkit-animation-duration: 6s; + animation-duration: 6s; + -webkit-animation-name: insertionFade; + animation-name: insertionFade; + border-bottom: 2px solid rgba(255, 255, 255, 0); + border-radius: 2px; + margin: -2px -4px -1px; + padding: 2px 4px 1px; +} + +@-webkit-keyframes insertionFade { + + from, + to { + background: rgba(255, 255, 255, 0); + border-color: rgba(255, 255, 255, 0); + } + + 15%, + 85% { + background: #fbffc9; + border-color: #f0f3c0; + } +} + +@keyframes insertionFade { + + from, + to { + background: rgba(255, 255, 255, 0); + border-color: rgba(255, 255, 255, 0); + } + + 15%, + 85% { + background: #fbffc9; + border-color: #f0f3c0; + } +} + +div.CodeMirror-lint-tooltip { + background-color: white; + border-radius: 2px; + border: 0; + color: #141823; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); + font-family: var(--sans); + font-size: 13px; + line-height: 16px; + max-width: 430px; + opacity: 0; + padding: 8px 10px; + -webkit-transition: opacity 0.15s; + transition: opacity 0.15s; + white-space: pre-wrap; +} + +div.CodeMirror-lint-tooltip>* { + padding-left: 23px; +} + +div.CodeMirror-lint-tooltip>*+* { + margin-top: 12px; +} + +/* COLORS */ + +.graphiql-container .CodeMirror-foldmarker { + border-radius: 4px; + background: #08f; + background: -webkit-gradient(linear, left top, left bottom, from(#43A8FF), to(#0F83E8)); + background: linear-gradient(#43A8FF, #0F83E8); + -webkit-box-shadow: + 0 1px 1px rgba(0, 0, 0, 0.2), + inset 0 0 0 1px rgba(0, 0, 0, 0.1); + box-shadow: + 0 1px 1px rgba(0, 0, 0, 0.2), + inset 0 0 0 1px rgba(0, 0, 0, 0.1); + color: white; + font-family: arial; + font-size: 12px; + line-height: 0; + margin: 0 3px; + padding: 0px 4px 1px; + text-shadow: 0 -1px rgba(0, 0, 0, 0.1); +} + +.graphiql-container div.CodeMirror span.CodeMirror-matchingbracket { + color: #555; + text-decoration: underline; +} + +.graphiql-container div.CodeMirror span.CodeMirror-nonmatchingbracket { + color: #f00; +} + +/* Comment */ +.cm-comment { + color: #999; +} + +/* Punctuation */ +.cm-punctuation { + color: #555; +} + +/* Keyword */ +.cm-keyword { + color: #B11A04; +} + +/* OperationName, FragmentName */ +.cm-def { + color: #D2054E; +} + +/* FieldName */ +.cm-property { + color: #1F61A0; +} + +/* FieldAlias */ +.cm-qualifier { + color: #1C92A9; +} + +/* ArgumentName and ObjectFieldName */ +.cm-attribute { + color: #8B2BB9; +} + +/* Number */ +.cm-number { + color: #2882F9; +} + +/* String */ +.cm-string { + color: #D64292; +} + +/* Boolean */ +.cm-builtin { + color: #D47509; +} + +/* EnumValue */ +.cm-string-2 { + color: #0B7FC7; +} + +/* Variable */ +.cm-variable { + color: #397D13; +} + +/* Directive */ +.cm-meta { + color: #B33086; +} + +/* Type */ +.cm-atom { + color: #CA9800; +} + +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + color: black; + font-family: monospace; + height: 300px; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; + /* Vertical padding around content */ +} + +.CodeMirror pre { + padding: 0 4px; + /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, +.CodeMirror-gutter-filler { + background-color: white; + /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} + +.CodeMirror-linenumbers {} + +.CodeMirror-linenumber { + color: #999; + min-width: 20px; + padding: 0 3px 0 5px; + text-align: right; + white-space: nowrap; +} + +.CodeMirror-guttermarker { + color: black; +} + +.CodeMirror-guttermarker-subtle { + color: #999; +} + +/* CURSOR */ + +.CodeMirror .CodeMirror-cursor { + border-left: 1px solid black; +} + +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} + +.CodeMirror.cm-fat-cursor div.CodeMirror-cursor { + background: #7e7; + border: 0; + width: auto; +} + +.CodeMirror.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} + +.cm-animate-fat-cursor { + -webkit-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + border: 0; + width: auto; +} + +@-webkit-keyframes blink { + 0% { + background: #7e7; + } + + 50% { + background: none; + } + + 100% { + background: #7e7; + } +} + +@keyframes blink { + 0% { + background: #7e7; + } + + 50% { + background: none; + } + + 100% { + background: #7e7; + } +} + +/* Can style cursor different in overwrite (non-insert) mode */ +div.CodeMirror-overwrite div.CodeMirror-cursor {} + +.cm-tab { + display: inline-block; + text-decoration: inherit; +} + +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-keyword { + color: #708; +} + +.cm-s-default .cm-atom { + color: #219; +} + +.cm-s-default .cm-number { + color: #164; +} + +.cm-s-default .cm-def { + color: #00f; +} + +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} + +.cm-s-default .cm-variable-2 { + color: #05a; +} + +.cm-s-default .cm-variable-3 { + color: #085; +} + +.cm-s-default .cm-comment { + color: #a50; +} + +.cm-s-default .cm-string { + color: #a11; +} + +.cm-s-default .cm-string-2 { + color: #f50; +} + +.cm-s-default .cm-meta { + color: #555; +} + +.cm-s-default .cm-qualifier { + color: #555; +} + +.cm-s-default .cm-builtin { + color: #30a; +} + +.cm-s-default .cm-bracket { + color: #997; +} + +.cm-s-default .cm-tag { + color: #170; +} + +.cm-s-default .cm-attribute { + color: #00c; +} + +.cm-s-default .cm-header { + color: blue; +} + +.cm-s-default .cm-quote { + color: #090; +} + +.cm-s-default .cm-hr { + color: #999; +} + +.cm-s-default .cm-link { + color: #00c; +} + +.cm-negative { + color: #d44; +} + +.cm-positive { + color: #292; +} + +.cm-header, +.cm-strong { + font-weight: bold; +} + +.cm-em { + font-style: italic; +} + +.cm-link { + text-decoration: underline; +} + +.cm-strikethrough { + text-decoration: line-through; +} + +.cm-s-default .cm-error { + color: #f00; +} + +.cm-invalidchar { + color: #f00; +} + +.CodeMirror-composing { + border-bottom: 2px solid; +} + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket { + color: #0f0; +} + +div.CodeMirror span.CodeMirror-nonmatchingbracket { + color: #f22; +} + +.CodeMirror-matchingtag { + background: rgba(255, 150, 0, .3); +} + +.CodeMirror-activeline-background { + background: #e8f2ff; +} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + background: white; + overflow: hidden; + position: relative; +} + +.CodeMirror-scroll { + height: 100%; + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; + margin-right: -30px; + outline: none; + /* Prevent dragging from highlighting the element */ + overflow: scroll !important; + /* Things will break if this is overridden */ + padding-bottom: 30px; + position: relative; +} + +.CodeMirror-sizer { + border-right: 30px solid transparent; + position: relative; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, +.CodeMirror-hscrollbar, +.CodeMirror-scrollbar-filler, +.CodeMirror-gutter-filler { + display: none; + position: absolute; + z-index: 6; +} + +.CodeMirror-vscrollbar { + overflow-x: hidden; + overflow-y: scroll; + right: 0; + top: 0; +} + +.CodeMirror-hscrollbar { + bottom: 0; + left: 0; + overflow-x: scroll; + overflow-y: hidden; +} + +.CodeMirror-scrollbar-filler { + right: 0; + bottom: 0; +} + +.CodeMirror-gutter-filler { + left: 0; + bottom: 0; +} + +.CodeMirror-gutters { + min-height: 100%; + position: absolute; + left: 0; + top: 0; + z-index: 3; +} + +.CodeMirror-gutter { + display: inline-block; + height: 100%; + margin-bottom: -30px; + vertical-align: top; + white-space: normal; + /* Hack to make IE7 behave */ + *zoom: 1; + *display: inline; +} + +.CodeMirror-gutter-wrapper { + background: none !important; + border: none !important; + position: absolute; + z-index: 4; +} + +.CodeMirror-gutter-background { + position: absolute; + top: 0; + bottom: 0; + z-index: 4; +} + +.CodeMirror-gutter-elt { + cursor: default; + position: absolute; + z-index: 4; +} + +.CodeMirror-gutter-wrapper { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.CodeMirror-lines { + cursor: text; + min-height: 1px; + /* prevents collapsing before first draw */ +} + +.CodeMirror pre { + -webkit-tap-highlight-color: transparent; + /* Reset some styles that the rest of the page might have set */ + background: transparent; + border-radius: 0; + border-width: 0; + color: inherit; + font-family: inherit; + font-size: inherit; + -webkit-font-variant-ligatures: none; + font-variant-ligatures: none; + line-height: inherit; + margin: 0; + overflow: visible; + position: relative; + white-space: pre; + word-wrap: normal; + z-index: 2; +} + +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + overflow: auto; + position: relative; + z-index: 2; +} + +.CodeMirror-widget {} + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -webkit-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + height: 0; + overflow: hidden; + position: absolute; + visibility: hidden; + width: 100%; +} + +.CodeMirror-cursor { + position: absolute; +} + +.CodeMirror-measure pre { + position: static; +} + +div.CodeMirror-cursors { + position: relative; + visibility: hidden; + z-index: 3; +} + +div.CodeMirror-dragcursors { + visibility: visible; +} + +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { + background: #d9d9d9; +} + +.CodeMirror-focused .CodeMirror-selected { + background: #d7d4f0; +} + +.CodeMirror-crosshair { + cursor: crosshair; +} + +.CodeMirror-line::-moz-selection, +.CodeMirror-line>span::-moz-selection, +.CodeMirror-line>span>span::-moz-selection { + background: #d7d4f0; +} + +.CodeMirror-line::selection, +.CodeMirror-line>span::selection, +.CodeMirror-line>span>span::selection { + background: #d7d4f0; +} + +.CodeMirror-line::-moz-selection, +.CodeMirror-line>span::-moz-selection, +.CodeMirror-line>span>span::-moz-selection { + background: #d7d4f0; +} + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { + *vertical-align: text-bottom; +} + +/* Used to force a border model for a node */ +.cm-force-border { + padding-right: .1px; +} + +@media print { + + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { + content: ''; +} + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { + background: none; +} + +.CodeMirror-dialog { + background: inherit; + color: inherit; + left: 0; + right: 0; + overflow: hidden; + padding: .1em .8em; + position: absolute; + z-index: 15; +} + +.CodeMirror-dialog-top { + border-bottom: 1px solid #eee; + top: 0; +} + +.CodeMirror-dialog-bottom { + border-top: 1px solid #eee; + bottom: 0; +} + +.CodeMirror-dialog input { + background: transparent; + border: 1px solid #d3d6db; + color: inherit; + font-family: monospace; + outline: none; + width: 20em; +} + +.CodeMirror-dialog button { + font-size: 70%; +} + +.graphiql-container .doc-explorer { + background: white; +} + +.graphiql-container .doc-explorer-title-bar, +.graphiql-container .history-title-bar { + cursor: default; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + height: 34px; + line-height: 14px; + padding: 8px 8px 5px; + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.graphiql-container .doc-explorer-title, +.graphiql-container .history-title { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + font-weight: bold; + overflow-x: hidden; + padding: 10px 0 10px 10px; + text-align: center; + text-overflow: ellipsis; + -webkit-user-select: initial; + -moz-user-select: initial; + -ms-user-select: initial; + user-select: initial; + white-space: nowrap; +} + +.graphiql-container .doc-explorer-back { + color: #3B5998; + cursor: pointer; + margin: -7px 0 -6px -8px; + overflow-x: hidden; + padding: 17px 12px 16px 16px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.doc-explorer-narrow .doc-explorer-back { + width: 0; +} + +.graphiql-container .doc-explorer-back:before { + border-left: 2px solid #3B5998; + border-top: 2px solid #3B5998; + content: ''; + display: inline-block; + height: 9px; + margin: 0 3px -1px 0; + position: relative; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + width: 9px; +} + +.graphiql-container .doc-explorer-rhs { + position: relative; +} + +.graphiql-container .doc-explorer-contents, +.graphiql-container .history-contents { + background-color: #ffffff; + border-top: 1px solid #d6d6d6; + bottom: 0; + left: 0; + overflow-y: auto; + padding: 20px 15px; + position: absolute; + right: 0; + top: 47px; +} + +.graphiql-container .doc-explorer-contents { + min-width: 300px; +} + +.graphiql-container .doc-type-description p:first-child, +.graphiql-container .doc-type-description blockquote:first-child { + margin-top: 0; +} + +.graphiql-container .doc-explorer-contents a { + cursor: pointer; + text-decoration: none; +} + +.graphiql-container .doc-explorer-contents a:hover { + text-decoration: underline; +} + +.graphiql-container .doc-value-description> :first-child { + margin-top: 4px; +} + +.graphiql-container .doc-value-description> :last-child { + margin-bottom: 4px; +} + +.graphiql-container .doc-category { + margin: 20px 0; +} + +.graphiql-container .doc-category-title { + border-bottom: 1px solid #e0e0e0; + color: #777; + cursor: default; + font-size: 14px; + font-variant: small-caps; + font-weight: bold; + letter-spacing: 1px; + margin: 0 -15px 10px 0; + padding: 10px 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.graphiql-container .doc-category-item { + margin: 12px 0; + color: #555; +} + +.graphiql-container .keyword { + color: #B11A04; +} + +.graphiql-container .type-name { + color: #CA9800; +} + +.graphiql-container .field-name { + color: #1F61A0; +} + +.graphiql-container .field-short-description { + color: #999; + margin-left: 5px; + overflow: hidden; + text-overflow: ellipsis; +} + +.graphiql-container .enum-value { + color: #0B7FC7; +} + +.graphiql-container .arg-name { + color: #8B2BB9; +} + +.graphiql-container .arg { + display: block; + margin-left: 1em; +} + +.graphiql-container .arg:first-child:last-child, +.graphiql-container .arg:first-child:nth-last-child(2), +.graphiql-container .arg:first-child:nth-last-child(2)~.arg { + display: inherit; + margin: inherit; +} + +.graphiql-container .arg:first-child:nth-last-child(2):after { + content: ', '; +} + +.graphiql-container .arg-default-value { + color: #43A047; +} + +.graphiql-container .doc-deprecation { + background: #fffae8; + -webkit-box-shadow: inset 0 0 1px #bfb063; + box-shadow: inset 0 0 1px #bfb063; + color: #867F70; + line-height: 16px; + margin: 8px -8px; + max-height: 80px; + overflow: hidden; + padding: 8px; + border-radius: 3px; +} + +.graphiql-container .doc-deprecation:before { + content: 'Deprecated:'; + color: #c79b2e; + cursor: default; + display: block; + font-size: 9px; + font-weight: bold; + letter-spacing: 1px; + line-height: 1; + padding-bottom: 5px; + text-transform: uppercase; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.graphiql-container .doc-deprecation> :first-child { + margin-top: 0; +} + +.graphiql-container .doc-deprecation> :last-child { + margin-bottom: 0; +} + +.graphiql-container .show-btn { + -webkit-appearance: initial; + display: block; + border-radius: 3px; + border: solid 1px #ccc; + text-align: center; + padding: 8px 12px 10px; + width: 100%; + -webkit-box-sizing: border-box; + box-sizing: border-box; + background: #fbfcfc; + color: #555; + cursor: pointer; +} + +.graphiql-container .search-box { + border-bottom: 1px solid #d3d6db; + display: block; + font-size: 14px; + margin: -15px -15px 12px 0; + position: relative; +} + +.graphiql-container .search-box:before { + content: '\26b2'; + cursor: pointer; + display: block; + font-size: 24px; + position: absolute; + top: -2px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.graphiql-container .search-box .search-box-clear { + background-color: #d0d0d0; + border-radius: 12px; + color: #fff; + cursor: pointer; + font-size: 11px; + padding: 1px 5px 2px; + position: absolute; + right: 3px; + top: 8px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.graphiql-container .search-box .search-box-clear:hover { + background-color: #b9b9b9; +} + +.graphiql-container .search-box>input { + border: none; + -webkit-box-sizing: border-box; + box-sizing: border-box; + font-size: 14px; + outline: none; + padding: 6px 24px 8px 20px; + width: 100%; +} + +.graphiql-container .error-container { + font-weight: bold; + left: 0; + letter-spacing: 1px; + opacity: 0.5; + position: absolute; + right: 0; + text-align: center; + text-transform: uppercase; + top: 50%; + -webkit-transform: translate(0, -50%); + transform: translate(0, -50%); +} + +.CodeMirror-foldmarker { + color: blue; + cursor: pointer; + font-family: arial; + line-height: .3; + text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; +} + +.CodeMirror-foldgutter { + width: .7em; +} + +.CodeMirror-foldgutter-open, +.CodeMirror-foldgutter-folded { + cursor: pointer; +} + +.CodeMirror-foldgutter-open:after { + content: "\25BE"; +} + +.CodeMirror-foldgutter-folded:after { + content: "\25B8"; +} + +.graphiql-container .history-contents, +.graphiql-container .history-contents input { + font-family: var(--mono); + padding: 0; +} + +.graphiql-container .history-contents p { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + font-size: 12px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin: 0; + padding: 8px; + border-bottom: 1px solid #e0e0e0; +} + +.graphiql-container .history-contents p.editable { + padding-bottom: 6px; + padding-top: 7px; +} + +.graphiql-container .history-contents input { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + font-size: 12px; +} + +.graphiql-container .history-contents p:hover { + cursor: pointer; +} + +.graphiql-container .history-contents p span.history-label { + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + overflow: hidden; + text-overflow: ellipsis; +} + +.CodeMirror-info { + background: white; + border-radius: 2px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: #555; + font-family: var(--sans); + font-size: 13px; + line-height: 16px; + margin: 8px -8px; + max-width: 400px; + opacity: 0; + overflow: hidden; + padding: 8px 8px; + position: fixed; + -webkit-transition: opacity 0.15s; + transition: opacity 0.15s; + z-index: 50; +} + +.CodeMirror-info :first-child { + margin-top: 0; +} + +.CodeMirror-info :last-child { + margin-bottom: 0; +} + +.CodeMirror-info p { + margin: 1em 0; +} + +.CodeMirror-info .info-description { + color: #777; + line-height: 16px; + margin-top: 1em; + max-height: 80px; + overflow: hidden; +} + +.CodeMirror-info .info-deprecation { + background: #fffae8; + -webkit-box-shadow: inset 0 1px 1px -1px #bfb063; + box-shadow: inset 0 1px 1px -1px #bfb063; + color: #867F70; + line-height: 16px; + margin: -8px; + margin-top: 8px; + max-height: 80px; + overflow: hidden; + padding: 8px; +} + +.CodeMirror-info .info-deprecation-label { + color: #c79b2e; + cursor: default; + display: block; + font-size: 9px; + font-weight: bold; + letter-spacing: 1px; + line-height: 1; + padding-bottom: 5px; + text-transform: uppercase; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.CodeMirror-info .info-deprecation-label+* { + margin-top: 0; +} + +.CodeMirror-info a { + text-decoration: none; +} + +.CodeMirror-info a:hover { + text-decoration: underline; +} + +.CodeMirror-info .type-name { + color: #CA9800; +} + +.CodeMirror-info .field-name { + color: #1F61A0; +} + +.CodeMirror-info .enum-value { + color: #0B7FC7; +} + +.CodeMirror-info .arg-name { + color: #8B2BB9; +} + +.CodeMirror-info .directive-name { + color: #B33086; +} + +.CodeMirror-jump-token { + text-decoration: underline; + cursor: pointer; +} + +/* The lint marker gutter */ +.CodeMirror-lint-markers { + width: 16px; +} + +.CodeMirror-lint-tooltip { + background-color: infobackground; + border-radius: 4px 4px 4px 4px; + border: 1px solid black; + color: infotext; + font-family: monospace; + font-size: 10pt; + max-width: 600px; + opacity: 0; + overflow: hidden; + padding: 2px 5px; + position: fixed; + -webkit-transition: opacity .4s; + transition: opacity .4s; + white-space: pre-wrap; + z-index: 100; +} + +.CodeMirror-lint-mark-error, +.CodeMirror-lint-mark-warning { + background-position: left bottom; + background-repeat: repeat-x; +} + +.CodeMirror-lint-mark-error { + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg=="); +} + +.CodeMirror-lint-mark-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-error, +.CodeMirror-lint-marker-warning { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + position: relative; + vertical-align: middle; + width: 16px; +} + +.CodeMirror-lint-message-error, +.CodeMirror-lint-message-warning { + background-position: top left; + background-repeat: no-repeat; + padding-left: 18px; +} + +.CodeMirror-lint-marker-error, +.CodeMirror-lint-message-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-warning, +.CodeMirror-lint-message-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-multiple { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); + background-position: right bottom; + background-repeat: no-repeat; + width: 100%; + height: 100%; +} + +.graphiql-container .spinner-container { + height: 36px; + left: 50%; + position: absolute; + top: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + width: 36px; + z-index: 10; +} + +.graphiql-container .spinner { + -webkit-animation: rotation .6s infinite linear; + animation: rotation .6s infinite linear; + border-bottom: 6px solid rgba(150, 150, 150, .15); + border-left: 6px solid rgba(150, 150, 150, .15); + border-radius: 100%; + border-right: 6px solid rgba(150, 150, 150, .15); + border-top: 6px solid rgba(150, 150, 150, .8); + display: inline-block; + height: 24px; + position: absolute; + vertical-align: middle; + width: 24px; +} + +@-webkit-keyframes rotation { + from { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + to { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@keyframes rotation { + from { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + to { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +.CodeMirror-hints { + background: white; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); + font-family: var(--mono); + font-size: 13px; + list-style: none; + margin-left: -6px; + margin: 0; + max-height: 14.5em; + overflow-y: auto; + overflow: hidden; + padding: 0; + position: absolute; + z-index: 10; +} + +.CodeMirror-hint { + border-top: solid 1px #f7f7f7; + color: #141823; + cursor: pointer; + margin: 0; + max-width: 300px; + overflow: hidden; + padding: 2px 6px; + white-space: pre; +} + +li.CodeMirror-hint-active { + background-color: #08f; + border-top-color: white; + color: white; +} + +.CodeMirror-hint-information { + border-top: solid 1px #c0c0c0; + max-width: 300px; + padding: 4px 6px; + position: relative; + z-index: 1; +} + +.CodeMirror-hint-information:first-child { + border-bottom: solid 1px #c0c0c0; + border-top: none; + margin-bottom: -1px; +} + +.CodeMirror-hint-deprecation { + background: #fffae8; + -webkit-box-shadow: inset 0 1px 1px -1px #bfb063; + box-shadow: inset 0 1px 1px -1px #bfb063; + color: #867F70; + font-family: var(--sans); + font-size: 13px; + line-height: 16px; + margin-top: 4px; + max-height: 80px; + overflow: hidden; + padding: 6px; +} + +.CodeMirror-hint-deprecation .deprecation-label { + color: #c79b2e; + cursor: default; + display: block; + font-size: 9px; + font-weight: bold; + letter-spacing: 1px; + line-height: 1; + padding-bottom: 5px; + text-transform: uppercase; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.CodeMirror-hint-deprecation .deprecation-label+* { + margin-top: 0; +} + +.CodeMirror-hint-deprecation :last-child { + margin-bottom: 0; +} diff --git a/src/pages/mql.js b/src/pages/mql.js new file mode 100644 index 000000000..ad8d289b8 --- /dev/null +++ b/src/pages/mql.js @@ -0,0 +1,129 @@ +/* global fetch */ + +import { Text, Box, Flex } from 'components/elements' +import { useSiteMetadata } from 'components/hook' +import GraphiQLExplorer from 'graphiql-explorer' +import React, { useRef, useState } from 'react' +import { Layout } from 'components/patterns' +import { buildClientSchema } from 'graphql' +import { css } from 'styled-components' +import fromEntries from 'fromentries' +import { marshall } from 'helpers' +import GraphiQL from 'graphiql' +import { pickBy, noop } from 'lodash' + +import 'components/pages/mql/style.css' +import introspection from '../../data/introspection.json' + +const NOOP_GRAPHIQL = { + handlePrettifyQuery: noop, + handleToggleHistory: noop, + handleRunQuery: noop +} + +const DEFAULT_QUERY = ` +{ + page (url: "https://kikobeats.com") { + url + } +} +` + +export default () => { + const graphiqlEl = useRef(NOOP_GRAPHIQL) + const graphiql = graphiqlEl.current + + const [schema] = useState(buildClientSchema(introspection)) + const [isExplorerOpen, setExplorerOpen] = useState(true) + const [query, setQuery] = useState(DEFAULT_QUERY) + const [resHeaders, setResHeaders] = useState({}) + const { apiEndpoint } = useSiteMetadata() + const graphqlEndpoint = `${apiEndpoint}/___graphql` + + async function fetcher (graphQLParams) { + const query = marshall(pickBy(graphQLParams)) + const response = await fetch(`${graphqlEndpoint}?${query}`) + setResHeaders(fromEntries(response.headers.entries())) + const payload = await response.json() + return payload.data + } + + // useEffect(() => { + // fetcher({ query: getIntrospectionQuery() }).then(result => { + // setSchema(buildClientSchema(result)) + // }) + // }, []) + + const stats = [ + { key: 'Plan', value: resHeaders['x-pricing-plan'] }, + { key: 'Cache', value: resHeaders['x-cache-status'] }, + { key: 'Request Time', value: resHeaders['x-response-time'] } + ] + + const toggleExplorer = () => setExplorerOpen(!isExplorerOpen) + + const graphqlContainerStyle = css` + height: 80vh !important; + * { + box-sizing: content-box; + } + ` + + return ( + + + + + MQL + + + + + + + + {stats.map(({ key, value }) => ( + + {key}: + + {' '} + {value || '-'} + + + ))} + + + + + + ) +} From 6ab4379ffd1b5cbd6c6e82669a86666d2414b82d Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Sun, 16 Jun 2019 23:04:11 +0200 Subject: [PATCH 02/18] build: update dependencies --- package.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index d2cb79a56..cf8847dbb 100644 --- a/package.json +++ b/package.json @@ -38,10 +38,10 @@ ], "dependencies": { "@microlink/demo-links": "~1.0.0", - "@microlink/mql": "~0.3.10", + "@microlink/mql": "~0.3.13", "@microlink/react": "~4.0.1", "@rebass/components": "~4.0.0-1", - "@tippy.js/react": "~2.2.0", + "@tippy.js/react": "~2.2.1", "autoprefixer": "~9.6.0", "beauty-error": "~1.2.0", "color": "~3.1.2", @@ -52,10 +52,10 @@ "download": "~7.1.0", "exists-file": "~3.0.2", "fromentries": "~1.1.0", - "gatsby": "~2.8.6", + "gatsby": "~2.9.4", "gatsby-plugin-canonical-urls": "~2.0.13", "gatsby-plugin-catch-links": "~2.0.15", - "gatsby-plugin-google-analytics": "~2.0.20", + "gatsby-plugin-google-analytics": "~2.0.21", "gatsby-plugin-meta-redirect": "~1.1.1", "gatsby-plugin-netlify": "~2.0.17", "gatsby-plugin-react-helmet": "~3.0.12", @@ -63,11 +63,11 @@ "gatsby-plugin-sass": "~2.0.11", "gatsby-plugin-sitemap": "~2.1.0", "gatsby-plugin-styled-components": "~3.0.7", - "gatsby-redirect-from": "~0.1.1", - "gatsby-source-filesystem": "~2.0.38", + "gatsby-redirect-from": "~0.2.1", + "gatsby-source-filesystem": "~2.0.39", "gatsby-transformer-javascript-frontmatter": "~2.0.10", "gatsby-transformer-json": "~2.1.11", - "gatsby-transformer-remark": "~2.3.12", + "gatsby-transformer-remark": "~2.4.0", "gatsby-transformer-yaml": "~2.1.12", "git-jiggy": "~1.1.1", "graphiql": "~0.13.0", @@ -82,8 +82,8 @@ "normalize.css": "~8.0.1", "p-all": "~2.1.0", "palx": "~1.0.3", - "parse-domain": "~2.3.0", - "polished": "~3.4.0", + "parse-domain": "~2.3.1", + "polished": "~3.4.1", "postcss-focus": "~4.0.0", "prettier": "~1.18.2", "react": "16.8.6", @@ -99,7 +99,7 @@ "react-syntax-highlighter": "~10.3.0", "react-timeago": "~4.4.0", "rebass": "~3.1.1", - "remark-slug": "~5.1.1", + "remark-slug": "~5.1.2", "smooth-scroll": "~16.1.0", "styled-components": "~4.3.1", "styled-is": "~1.3.0", From 1ff56fcde385d4f41bc9c8f20df713994c60fd02 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Mon, 17 Jun 2019 09:08:20 +0200 Subject: [PATCH 03/18] fix: typo --- src/pages/blog/product-brief-4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/blog/product-brief-4.md b/src/pages/blog/product-brief-4.md index 713e98d62..e3a433d9a 100644 --- a/src/pages/blog/product-brief-4.md +++ b/src/pages/blog/product-brief-4.md @@ -29,7 +29,7 @@ Using [@microlink/react](/docs/sdk/integrations/react/) just pass your custom CS import Microlink from '@microlink/react' From 4421ae20f78471fd5dae64990544c511cd6cac85 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Mon, 17 Jun 2019 09:08:33 +0200 Subject: [PATCH 04/18] fix: best effort --- src/helpers/prettier.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/helpers/prettier.js b/src/helpers/prettier.js index 5e7634ba4..08d1aba91 100644 --- a/src/helpers/prettier.js +++ b/src/helpers/prettier.js @@ -60,8 +60,14 @@ export const serializeObject = props => { }, '') } -const prettier = (code, opts) => - prettierStandalone.format(code, { ...PRETTIER_CONFIG, ...opts }) +const prettier = (code, opts) => { + try { + return prettierStandalone.format(code, { ...PRETTIER_CONFIG, ...opts }) + } catch (err) { + return code + } +} + prettier.jsx = prettier.javascript = prettier.js = (code, opts) => prettier(code, { ...JS_OPTS, ...opts }) prettier.html = (code, opts) => prettier(code, { ...HTML_OPTS, ...opts }) From 4c1c5ca7593af27589711e723cfbfd150e9bdee2 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Mon, 17 Jun 2019 09:32:40 +0200 Subject: [PATCH 05/18] fix: avoid SSR --- src/pages/mql.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/pages/mql.js b/src/pages/mql.js index ad8d289b8..f547574d6 100644 --- a/src/pages/mql.js +++ b/src/pages/mql.js @@ -1,15 +1,14 @@ /* global fetch */ +import React, { useRef, useState, useEffect } from 'react' import { Text, Box, Flex } from 'components/elements' import { useSiteMetadata } from 'components/hook' import GraphiQLExplorer from 'graphiql-explorer' -import React, { useRef, useState } from 'react' import { Layout } from 'components/patterns' import { buildClientSchema } from 'graphql' import { css } from 'styled-components' import fromEntries from 'fromentries' import { marshall } from 'helpers' -import GraphiQL from 'graphiql' import { pickBy, noop } from 'lodash' import 'components/pages/mql/style.css' @@ -29,6 +28,12 @@ const DEFAULT_QUERY = ` } ` +let GraphiQL + +if (global.window) { + GraphiQL = require('graphiql') +} + export default () => { const graphiqlEl = useRef(NOOP_GRAPHIQL) const graphiql = graphiqlEl.current @@ -49,9 +54,9 @@ export default () => { } // useEffect(() => { - // fetcher({ query: getIntrospectionQuery() }).then(result => { - // setSchema(buildClientSchema(result)) - // }) + // fetcher({ query: getIntrospectionQuery() }).then(result => { + // setSchema(buildClientSchema(result)) + // }) // }, []) const stats = [ @@ -69,6 +74,8 @@ export default () => { } ` + if (!GraphiQL) return null + return ( Date: Mon, 17 Jun 2019 09:48:43 +0200 Subject: [PATCH 06/18] build: improve default query --- src/pages/mql.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/pages/mql.js b/src/pages/mql.js index f547574d6..909fed28c 100644 --- a/src/pages/mql.js +++ b/src/pages/mql.js @@ -22,8 +22,14 @@ const NOOP_GRAPHIQL = { const DEFAULT_QUERY = ` { - page (url: "https://kikobeats.com") { + home: page (url: "https://microlink.io") { url + image { + url + palette + } + resume: text(selector: "h2:first"), + caption: text(selector: "h3:first") } } ` From 4df8605bb1140fbaa37929f087ba0ba44a32a9a4 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 18 Jun 2019 23:55:28 +0200 Subject: [PATCH 07/18] build: use qss instead of marshal/unmarshall --- package.json | 1 + src/components/elements/Checkout.js | 6 ++---- src/helpers/index.js | 6 +----- src/helpers/marshall.js | 7 ------- src/helpers/unmarshall.js | 8 -------- src/pages/payment.js | 10 ++++------ 6 files changed, 8 insertions(+), 30 deletions(-) delete mode 100644 src/helpers/marshall.js delete mode 100644 src/helpers/unmarshall.js diff --git a/package.json b/package.json index cf8847dbb..2fc7b77e5 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "polished": "~3.4.1", "postcss-focus": "~4.0.0", "prettier": "~1.18.2", + "qss": "~2.0.3", "react": "16.8.6", "react-codecopy": "~4.0.1", "react-dom": "16.8.6", diff --git a/src/components/elements/Checkout.js b/src/components/elements/Checkout.js index 7376e5b99..50e1785a8 100644 --- a/src/components/elements/Checkout.js +++ b/src/components/elements/Checkout.js @@ -7,7 +7,7 @@ import { Notification, ButtonSecondary } from 'components/elements' -import { marshall } from 'helpers' +import { encode } from 'qss' import { Choose } from 'react-extras' const PAYMENT_STATE = { @@ -118,9 +118,7 @@ export default class extends Component { display='inline' color='red8' children='Contact us' - href={`mailto:hello@microlink.io?${marshall( - ERROR_MAIL_OPTS - )}`} + href={`mailto:hello@microlink.io?${encode(ERROR_MAIL_OPTS)}`} /> {'.'} diff --git a/src/helpers/index.js b/src/helpers/index.js index 6595b9d3b..34219f9e0 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -1,9 +1,7 @@ import serializeComponent from './serialize-component' import formatNumber from './format-number' import formatDate from './format-date' -import unmarshall from './unmarshall' import getLines from './get-lines' -import marshall from './marshall' import title from './title' import prettier from './prettier' @@ -11,9 +9,7 @@ export { formatDate, formatNumber, getLines, - marshall, prettier, serializeComponent, - title, - unmarshall + title } diff --git a/src/helpers/marshall.js b/src/helpers/marshall.js deleted file mode 100644 index 3152f36ec..000000000 --- a/src/helpers/marshall.js +++ /dev/null @@ -1,7 +0,0 @@ -export default obj => - Object.keys(obj) - .reduce((acc, key) => { - acc.push(`${key}=${encodeURIComponent(obj[key])}`) - return acc - }, []) - .join('&') diff --git a/src/helpers/unmarshall.js b/src/helpers/unmarshall.js deleted file mode 100644 index 8fbf5aaf3..000000000 --- a/src/helpers/unmarshall.js +++ /dev/null @@ -1,8 +0,0 @@ -export default str => - str - .substr(1) - .split('&') - .reduce((acc, item) => { - acc[item.split('=')[0]] = item.split('=')[1] - return acc - }, {}) diff --git a/src/pages/payment.js b/src/pages/payment.js index b37645823..640e4d8e8 100644 --- a/src/pages/payment.js +++ b/src/pages/payment.js @@ -4,6 +4,8 @@ import React, { useState, Fragment, Component } from 'react' import { useSiteMetadata } from 'components/hook' import styled from 'styled-components' import { Choose } from 'react-extras' +import { encode, decode } from 'qss' + import { Label, Container, @@ -16,8 +18,6 @@ import { import { Layout } from 'components/patterns' import Head from 'components/Head' -import { marshall, unmarshall } from 'helpers' - import { CardNumberElement, CardExpiryElement, @@ -96,7 +96,7 @@ class _CardForm extends Component { body: JSON.stringify([ { command: 'payment.update', - customerId: unmarshall(window.location.search).id, + customerId: decode(window.location.search).id, token }, { command: 'notification.email', templateId: 'payment_updated' } @@ -132,9 +132,7 @@ class _CardForm extends Component { display='inline' children='Contact us' color='red8' - href={`mailto:hello@microlink.io?${marshall( - ERROR_MAIL_OPTS - )}`} + href={`mailto:hello@microlink.io?${encode(ERROR_MAIL_OPTS)}`} /> {'.'} From 3edf01d52a066778770d7345f96d653ff4c145ce Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 18 Jun 2019 23:56:25 +0200 Subject: [PATCH 08/18] build: encode state into url --- src/components/hook/use-query-state.js | 21 ++++++++++----------- src/pages/{mql.js => graphql.js} | 26 ++++++++++++++------------ 2 files changed, 24 insertions(+), 23 deletions(-) rename src/pages/{mql.js => graphql.js} (87%) diff --git a/src/components/hook/use-query-state.js b/src/components/hook/use-query-state.js index 6b87f2eb9..432f5d282 100644 --- a/src/components/hook/use-query-state.js +++ b/src/components/hook/use-query-state.js @@ -1,22 +1,21 @@ import { useState, useEffect } from 'react' -import fromEntries from 'fromentries' +import { decode, encode } from 'qss' import { navigate } from 'gatsby' +const fromLocation = () => decode(window.location.search.substring(1)) + export const useQueryState = () => { - const [urlSearchParams, setUrlSearchParams] = useState(new URLSearchParams()) + const [query, setQuery] = useState(fromLocation()) + useEffect( - () => { - setUrlSearchParams(new URLSearchParams(window.location.search)) - }, + () => setQuery(fromLocation()), global.window ? [window.location.search] : [] ) - const query = fromEntries(urlSearchParams.entries()) - - const setQuery = (obj = {}) => { - Object.keys(obj).forEach(key => urlSearchParams.set(key, obj[key])) - navigate(`${window.location.pathname}?${urlSearchParams.toString()}`) + const set = (obj = {}, { navigate: isNavigate = true } = {}) => { + const newQuery = { ...query, ...obj } + if (isNavigate) navigate(`${window.location.pathname}?${encode(newQuery)}`) } - return [query, setQuery] + return [query, set] } diff --git a/src/pages/mql.js b/src/pages/graphql.js similarity index 87% rename from src/pages/mql.js rename to src/pages/graphql.js index 909fed28c..a25de7456 100644 --- a/src/pages/mql.js +++ b/src/pages/graphql.js @@ -1,15 +1,15 @@ /* global fetch */ -import React, { useRef, useState, useEffect } from 'react' +import { useSiteMetadata, useQueryState } from 'components/hook' import { Text, Box, Flex } from 'components/elements' -import { useSiteMetadata } from 'components/hook' import GraphiQLExplorer from 'graphiql-explorer' +import React, { useRef, useState } from 'react' import { Layout } from 'components/patterns' import { buildClientSchema } from 'graphql' import { css } from 'styled-components' import fromEntries from 'fromentries' -import { marshall } from 'helpers' import { pickBy, noop } from 'lodash' +import { encode } from 'qss' import 'components/pages/mql/style.css' import introspection from '../../data/introspection.json' @@ -31,6 +31,10 @@ const DEFAULT_QUERY = ` resume: text(selector: "h2:first"), caption: text(selector: "h3:first") } + + blog: page(url: "https://microlink.io/blog") { + url + } } ` @@ -44,27 +48,25 @@ export default () => { const graphiqlEl = useRef(NOOP_GRAPHIQL) const graphiql = graphiqlEl.current + const [windowQuery, setWindowQuery] = useQueryState() + const [schema] = useState(buildClientSchema(introspection)) const [isExplorerOpen, setExplorerOpen] = useState(true) - const [query, setQuery] = useState(DEFAULT_QUERY) + + const [query, setQuery] = useState(windowQuery.query || DEFAULT_QUERY) const [resHeaders, setResHeaders] = useState({}) const { apiEndpoint } = useSiteMetadata() const graphqlEndpoint = `${apiEndpoint}/___graphql` async function fetcher (graphQLParams) { - const query = marshall(pickBy(graphQLParams)) - const response = await fetch(`${graphqlEndpoint}?${query}`) + const query = pickBy(graphQLParams) + setWindowQuery(query) + const response = await fetch(`${graphqlEndpoint}?${encode(query)}`) setResHeaders(fromEntries(response.headers.entries())) const payload = await response.json() return payload.data } - // useEffect(() => { - // fetcher({ query: getIntrospectionQuery() }).then(result => { - // setSchema(buildClientSchema(result)) - // }) - // }, []) - const stats = [ { key: 'Plan', value: resHeaders['x-pricing-plan'] }, { key: 'Cache', value: resHeaders['x-cache-status'] }, From ec874240add95f877a0e8f70bc5f3be9bd34f1fe Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Wed, 19 Jun 2019 00:14:16 +0200 Subject: [PATCH 09/18] build: avoid return something internal --- src/components/hook/use-query-state.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/hook/use-query-state.js b/src/components/hook/use-query-state.js index 432f5d282..c2eb73447 100644 --- a/src/components/hook/use-query-state.js +++ b/src/components/hook/use-query-state.js @@ -8,7 +8,9 @@ export const useQueryState = () => { const [query, setQuery] = useState(fromLocation()) useEffect( - () => setQuery(fromLocation()), + () => { + setQuery(fromLocation()) + }, global.window ? [window.location.search] : [] ) From 678e3bd0c473fcfcfc8a2bf6f27b12869d2111cf Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Wed, 19 Jun 2019 00:47:58 +0200 Subject: [PATCH 10/18] build: do an initial fetch when is necessary --- src/pages/graphql.js | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/pages/graphql.js b/src/pages/graphql.js index a25de7456..9595d92ba 100644 --- a/src/pages/graphql.js +++ b/src/pages/graphql.js @@ -1,9 +1,9 @@ /* global fetch */ import { useSiteMetadata, useQueryState } from 'components/hook' +import React, { useRef, useState, useEffect } from 'react' import { Text, Box, Flex } from 'components/elements' import GraphiQLExplorer from 'graphiql-explorer' -import React, { useRef, useState } from 'react' import { Layout } from 'components/patterns' import { buildClientSchema } from 'graphql' import { css } from 'styled-components' @@ -49,24 +49,37 @@ export default () => { const graphiql = graphiqlEl.current const [windowQuery, setWindowQuery] = useQueryState() - const [schema] = useState(buildClientSchema(introspection)) const [isExplorerOpen, setExplorerOpen] = useState(true) - const [query, setQuery] = useState(windowQuery.query || DEFAULT_QUERY) const [resHeaders, setResHeaders] = useState({}) const { apiEndpoint } = useSiteMetadata() const graphqlEndpoint = `${apiEndpoint}/___graphql` + const [response, setResponse] = useState(null) + + async function fetchQuery (query) { + const response = await fetch(`${graphqlEndpoint}?${encode(query)}`, { + cache: 'no-store' + }) + const headers = fromEntries(response.headers.entries()) + const payload = await response.json() + return { payload, headers } + } async function fetcher (graphQLParams) { const query = pickBy(graphQLParams) setWindowQuery(query) - const response = await fetch(`${graphqlEndpoint}?${encode(query)}`) - setResHeaders(fromEntries(response.headers.entries())) - const payload = await response.json() + const { payload, headers } = await fetchQuery(query) + setResHeaders(headers) return payload.data } + async function fetchInitialResponse (query) { + const { payload, headers } = await fetchQuery(query) + setResponse(JSON.stringify(payload.data, null, 2)) + setResHeaders(headers) + } + const stats = [ { key: 'Plan', value: resHeaders['x-pricing-plan'] }, { key: 'Cache', value: resHeaders['x-cache-status'] }, @@ -82,6 +95,12 @@ export default () => { } ` + useEffect(() => { + if (windowQuery.query === query && response === null) { + fetchInitialResponse(windowQuery) + } + }, [windowQuery.query]) + if (!GraphiQL) return null return ( @@ -105,6 +124,7 @@ export default () => { schema={schema} query={query} onEditQuery={setQuery} + response={response} > MQL From 0ea4bf588680badaa857f5e59ed15d2c0c7442cf Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Wed, 19 Jun 2019 09:53:50 +0200 Subject: [PATCH 11/18] fix: avoid SSR --- src/components/hook/use-query-state.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/hook/use-query-state.js b/src/components/hook/use-query-state.js index c2eb73447..73b54384c 100644 --- a/src/components/hook/use-query-state.js +++ b/src/components/hook/use-query-state.js @@ -2,7 +2,10 @@ import { useState, useEffect } from 'react' import { decode, encode } from 'qss' import { navigate } from 'gatsby' -const fromLocation = () => decode(window.location.search.substring(1)) +let hasWindow = !!global.window + +const fromLocation = () => + hasWindow ? decode(window.location.search.substring(1)) : {} export const useQueryState = () => { const [query, setQuery] = useState(fromLocation()) From 58185d95a141daa6553b552cf94e6d0df9400066 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Wed, 19 Jun 2019 17:53:58 +0200 Subject: [PATCH 12/18] build: update travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2780fca4b..b35d38d2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,8 +17,8 @@ jobs: node_js: lts/* install: npm install --no-package-lock before_deploy: - - git config user.email "travis@travis-ci.org" - - git config user.name "Travis CI" + - git config user.email ${GITHUB_EMAIL:-"travis@travis-ci.org"} + - git config user.name ${GITHUB_USER:-"Travis CI"} - git remote set-url origin https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git deploy: skip_cleanup: true From 026a41cf3c616dc768863381f4027578df1d0d45 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Sat, 22 Jun 2019 13:05:26 +0200 Subject: [PATCH 13/18] WIP --- env.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env.js b/env.js index f6760db52..5787a1bf7 100644 --- a/env.js +++ b/env.js @@ -23,7 +23,7 @@ if (!MICROLINK_API_ENDPOINT) throw envError('MICROLINK_API_ENDPOINT') const isProduction = NODE_ENV === 'production' const SITE_URL = (() => { - if (!isProduction) return 'http://localhost:8000' + return 'http://localhost:8000' return CONTEXT === 'production' ? URL : DEPLOY_URL })() From f3cb9924ff3a0591e7cb72971f7365c50d75a100 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 25 Jun 2019 11:30:04 +0200 Subject: [PATCH 14/18] build: add copy buttons --- package.json | 1 + scripts/fetch-introspection-query.js | 2 +- src/components/pages/mql/style.css | 1 + src/pages/graphql.js | 44 ++++++++++++++++++++++++++-- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 9480fa004..65469af83 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "autoprefixer": "~9.6.0", "beauty-error": "~1.2.0", "color": "~3.1.2", + "copy-to-clipboard": "~3.2.0", "cssnano": "~4.1.10", "cssnano-preset-advanced": "~4.0.7", "date-fns": "~1.30.1", diff --git a/scripts/fetch-introspection-query.js b/scripts/fetch-introspection-query.js index e5b97bf13..58ebac6aa 100644 --- a/scripts/fetch-introspection-query.js +++ b/scripts/fetch-introspection-query.js @@ -19,7 +19,7 @@ const main = async () => { if (NODE_ENV === 'production') return - const graphqlEndpoint = `${MICROLINK_API_ENDPOINT}/___graphql` + const graphqlEndpoint = `${MICROLINK_API_ENDPOINT}/graphql` const query = stringify({ query: getIntrospectionQuery() }) const { body } = await got(`${graphqlEndpoint}?${query}`, { json: true }) return jsonFuture.saveAsync(INTROSPECTION_PATH, body) diff --git a/src/components/pages/mql/style.css b/src/components/pages/mql/style.css index 7e0a42ced..55057a5db 100644 --- a/src/components/pages/mql/style.css +++ b/src/components/pages/mql/style.css @@ -224,6 +224,7 @@ display: -webkit-box; display: -ms-flexbox; display: flex; + width: 100%; } .graphiql-container .docExplorerShow, diff --git a/src/pages/graphql.js b/src/pages/graphql.js index 9595d92ba..cfef1c23f 100644 --- a/src/pages/graphql.js +++ b/src/pages/graphql.js @@ -10,8 +10,10 @@ import { css } from 'styled-components' import fromEntries from 'fromentries' import { pickBy, noop } from 'lodash' import { encode } from 'qss' +import copy from 'copy-to-clipboard' import 'components/pages/mql/style.css' + import introspection from '../../data/introspection.json' const NOOP_GRAPHIQL = { @@ -32,12 +34,21 @@ const DEFAULT_QUERY = ` caption: text(selector: "h3:first") } - blog: page(url: "https://microlink.io/blog") { + blog: page(url: "https://microlink.io/blog", force:true) { url + posts: text(selector: "section a") } } ` +const TEXT = { + SHARE: 'Share', + SHARED: 'Copied!', + CURL: 'Copy as cURL' +} + +const TEXT_ANIMATION_MS = 1000 + let GraphiQL if (global.window) { @@ -51,14 +62,18 @@ export default () => { const [windowQuery, setWindowQuery] = useQueryState() const [schema] = useState(buildClientSchema(introspection)) const [isExplorerOpen, setExplorerOpen] = useState(true) + const [shareText, setShareText] = useState(TEXT.SHARE) + const [curlText, setCurlText] = useState(TEXT.CURL) const [query, setQuery] = useState(windowQuery.query || DEFAULT_QUERY) const [resHeaders, setResHeaders] = useState({}) const { apiEndpoint } = useSiteMetadata() - const graphqlEndpoint = `${apiEndpoint}/___graphql` + const graphqlEndpoint = `${apiEndpoint}/graphql` const [response, setResponse] = useState(null) + const apiUrl = query => `${graphqlEndpoint}?${encode(query)}` + async function fetchQuery (query) { - const response = await fetch(`${graphqlEndpoint}?${encode(query)}`, { + const response = await fetch(apiUrl(query), { cache: 'no-store' }) const headers = fromEntries(response.headers.entries()) @@ -88,6 +103,18 @@ export default () => { const toggleExplorer = () => setExplorerOpen(!isExplorerOpen) + const onShare = () => { + copy(window.location.href) + setShareText(TEXT.SHARED) + setTimeout(() => setShareText(TEXT.SHARE), TEXT_ANIMATION_MS) + } + + const onCurl = () => { + copy(apiUrl(windowQuery)) + setCurlText(TEXT.SHARED) + setTimeout(() => setCurlText(TEXT.CURL), TEXT_ANIMATION_MS) + } + const graphqlContainerStyle = css` height: 80vh !important; * { @@ -143,6 +170,17 @@ export default () => { label='Explorer' title='Toggle Explorer' /> + + + From 2f22799cb2e2e29e0bb67842b9c01a64b7bcc8ae Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 25 Jun 2019 11:45:02 +0200 Subject: [PATCH 15/18] build: tweak scripts --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 65469af83..9567b2e5f 100644 --- a/package.json +++ b/package.json @@ -156,8 +156,9 @@ "postrelease": "npm run release:tags && npm run release:github", "prebuild": "npm run clean:urls && npm run clean:build && npm run build:urls", "predev": "node scripts/fetch-demo-links && node scripts/fetch-introspection-query", - "prerelease": "npm run update:check && git-authors-cli", - "release": "git-authors-cli && git add package.json && standard-version -a", + "prerelease": "npm run update:check", + "preversion": "git-authors-cli && git add package.json", + "release": "standard-version -a", "release:github": "conventional-github-releaser -p angular", "release:tags": "git push --follow-tags origin HEAD:master", "storybook": "start-storybook -p 6006", From 6c0370bc13673ab45648c38341bb42c7b2d297df Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 25 Jun 2019 12:34:21 +0200 Subject: [PATCH 16/18] build: better copy handle --- src/pages/graphql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/graphql.js b/src/pages/graphql.js index cfef1c23f..f1b03024f 100644 --- a/src/pages/graphql.js +++ b/src/pages/graphql.js @@ -110,7 +110,7 @@ export default () => { } const onCurl = () => { - copy(apiUrl(windowQuery)) + copy(`curl ${apiUrl({ query })}`) setCurlText(TEXT.SHARED) setTimeout(() => setCurlText(TEXT.CURL), TEXT_ANIMATION_MS) } From 159aced775ea4a2884aa585e5c136e2cb1a149e6 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 25 Jun 2019 12:39:30 +0200 Subject: [PATCH 17/18] build: remove develop thing --- env.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env.js b/env.js index 5787a1bf7..f6760db52 100644 --- a/env.js +++ b/env.js @@ -23,7 +23,7 @@ if (!MICROLINK_API_ENDPOINT) throw envError('MICROLINK_API_ENDPOINT') const isProduction = NODE_ENV === 'production' const SITE_URL = (() => { - return 'http://localhost:8000' + if (!isProduction) return 'http://localhost:8000' return CONTEXT === 'production' ? URL : DEPLOY_URL })() From 9939672acf9cd9705e54d7071b577548bc4dcd35 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 25 Jun 2019 12:42:05 +0200 Subject: [PATCH 18/18] build: update dependencies --- package.json | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 9567b2e5f..ef15f6d46 100644 --- a/package.json +++ b/package.json @@ -37,13 +37,13 @@ "gatsby" ], "dependencies": { - "@microlink/demo-links": "~1.0.0", + "@microlink/demo-links": "~1.0.1", "@microlink/mql": "~0.3.13", "@microlink/react": "~4.0.1", "@rebass/components": "~4.0.0-1", - "@tippy.js/react": "~2.2.1", + "@tippy.js/react": "~2.2.2", "autoprefixer": "~9.6.0", - "beauty-error": "~1.2.0", + "beauty-error": "~1.2.2", "color": "~3.1.2", "copy-to-clipboard": "~3.2.0", "cssnano": "~4.1.10", @@ -53,30 +53,30 @@ "download": "~7.1.0", "exists-file": "~3.0.2", "fromentries": "~1.1.0", - "gatsby": "~2.9.4", - "gatsby-plugin-canonical-urls": "~2.0.13", - "gatsby-plugin-catch-links": "~2.0.15", - "gatsby-plugin-google-analytics": "~2.0.21", + "gatsby": "~2.10.5", + "gatsby-plugin-canonical-urls": "~2.1.0", + "gatsby-plugin-catch-links": "~2.1.0", + "gatsby-plugin-google-analytics": "~2.1.0", "gatsby-plugin-meta-redirect": "~1.1.1", - "gatsby-plugin-netlify": "~2.0.17", - "gatsby-plugin-react-helmet": "~3.0.12", - "gatsby-plugin-remove-trailing-slashes": "~2.0.11", - "gatsby-plugin-sass": "~2.0.11", - "gatsby-plugin-sitemap": "~2.1.0", - "gatsby-plugin-styled-components": "~3.0.7", + "gatsby-plugin-netlify": "~2.1.0", + "gatsby-plugin-react-helmet": "~3.1.0", + "gatsby-plugin-remove-trailing-slashes": "~2.1.0", + "gatsby-plugin-sass": "~2.1.0", + "gatsby-plugin-sitemap": "~2.2.0", + "gatsby-plugin-styled-components": "~3.1.0", "gatsby-redirect-from": "~0.2.1", - "gatsby-source-filesystem": "~2.0.39", - "gatsby-transformer-javascript-frontmatter": "~2.0.10", - "gatsby-transformer-json": "~2.1.11", - "gatsby-transformer-remark": "~2.4.0", - "gatsby-transformer-yaml": "~2.1.12", + "gatsby-source-filesystem": "~2.1.1", + "gatsby-transformer-javascript-frontmatter": "~2.1.0", + "gatsby-transformer-json": "~2.2.0", + "gatsby-transformer-remark": "~2.5.0", + "gatsby-transformer-yaml": "~2.2.0", "git-jiggy": "~1.1.1", - "graphiql": "~0.13.0", + "graphiql": "~0.13.2", "graphiql-explorer": "~0.4.3", "graphql": "~14.3.1", - "human-number": "~1.0.3", + "human-number": "~1.0.4", "humanize-url": "~2.1.0", - "json-future": "~2.2.0", + "json-future": "~2.2.4", "lodash": "~4.17.11", "mdx-scoped-runtime": "~0.7.1", "node-sass": "~4.12.0", @@ -103,7 +103,7 @@ "rebass": "~3.1.1", "remark-slug": "~5.1.2", "smooth-scroll": "~16.1.0", - "styled-components": "~4.3.1", + "styled-components": "~4.3.2", "styled-is": "~1.3.0", "styled-system": "4", "title": "~3.4.1"