Big improvements in docs pages

This commit is contained in:
Syrus Akbary 2015-11-25 15:25:03 -08:00
parent 0cf6cd65c7
commit 65c9cc7ce8
22 changed files with 494 additions and 117 deletions

4
.gitignore vendored
View File

@ -61,3 +61,7 @@ target/
/tests/django.sqlite
/graphene/index.json
/graphene/meta.json

View File

@ -6,22 +6,25 @@ python:
- 3.4
- 3.5
- pypy
node_js:
- 4.1
cache:
- pip
- directories:
directories:
- .cache/pip/
- docs/node_modules
- $HOME/.cache/pip
- docs/node_modules/
- $HOME/docs/node_modules
install:
- pip install --download-cache .cache/pip/ pytest pytest-cov coveralls flake8 six
- pip install --download-cache $HOME/.cache/pip/ pytest pytest-cov coveralls flake8 six
blinker pytest-django
- pip install --download-cache .cache/pip/ -e .[django]
- pip install --download-cache $HOME/.cache/pip/ -e .[django]
- python setup.py develop
script:
- py.test --cov=graphene
- flake8
after_success:
- coveralls
- cd docs && npm run deploy
- nvm install 4.1 && cd docs && npm run deploy
env:
matrix:

BIN
docs/assets/edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

BIN
docs/assets/edit@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

View File

@ -1 +1,17 @@
siteTitle="Graphene"
siteTitle = "Graphene"
[docs.quickstart]
name = "Quickstart"
pages = [
"/docs/quickstart/",
"/docs/quickstart-django/",
]
[docs.walkthrough]
name = "Walkthrough"
pages = [
"/docs/interfaces/",
"/docs/objecttypes/",
"/docs/mutations/",
"/docs/basic-types/",
]

70
docs/css/hljs.css Normal file
View File

@ -0,0 +1,70 @@
/**
* GitHub Gist Theme
* Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
*/
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}

View File

@ -1,6 +1,7 @@
@import 'nib'
@import 'jeet'
@import 'hljs.css'
@import 'https://fonts.googleapis.com/css?family=Raleway:400,500,600,200,100&.css'
normalize-css()
@ -15,6 +16,9 @@ $wrapper
a, a:hover
text-decoration none
a
color rgb(42,93,173)
html, body
font-family "Helvetica Neue", Helvetica, Arial, sans-serif
font-weight 300
@ -85,7 +89,19 @@ html, body
text-transform uppercase
font-weight 600
line-height 15px
position relative
&.active:before
content: ''
width 5px
height 5px
border-radius 100%
display block
position absolute
background white
left 50%
margin-left -3px
bottom -24px
.header-logo
font-family 'Raleway'
font-size 22px
@ -168,45 +184,183 @@ html, body
border-radius: 100px
font-size 13px
padding 17px 17px 17px 71px
width 226px
width 236px
box-sizing border-box
color white
font-family 'Raleway'
font-weight 500
transition all .2s ease-in-out
&:before
content: ''
display block
position absolute
left 0
top 0
left 20px
top 20px
height 32px
width 32px
image '../assets/starwars-icon.png'
image '~!file-loader!../assets/starwars-icon.png' 32px 32px
&:hover
transform translateY(-3px)
box-shadow 0px 4px 8px 0px rgba(0,0,0,0.32)
.improve-document-link
@extend $wrapper
position fixed
right 0
bottom 70px
transform-origin 100% 100%
background: #999;
border: 1px solid #919191;
border-radius: 3px 3px 0 0;
border-bottom 0
padding 9px 12px 12px 34px
transform: rotate(270deg) translateX(100%) translateY(3px);
font-size: 11px;
font-weight: 500;
text-transform uppercase
color: #FFFFFF;
letter-spacing: 0.3px;
line-height: 11px;
transition all .2s ease-in-out
&:before
content: ''
display block
position absolute
left 10px
top 8px
height 16px
width 16px
image '~!file-loader!../assets/edit.png' 16px 16px
&:hover
transform: rotate(270deg) translateX(100%)
background #666
border-color #555
+below(600px)
display none
$title
display block
font-family: 'Raleway';
font-weight 500
line-height 1.2em
padding-top .3em
margin-bottom .5em
padding-bottom .5em
color #4A4A4A
.markdown
.wrapper
margin-top 60px
h1, h2, h3, h4, h5, h6
font-family: 'Raleway';
font-weight 600
color #4A4A4A
strong
font-weight 500
h1, h2, h3, h4, h5, h6
@extend $title
h1
font-size 32px
h2
font-size 26px
h3
font-size 24px
h4
font-size 21px
h5
font-size 18px
h6
font-size 16px
strong
font-weight 500
pre
line-height 20px
background #FAFAFA
padding 20px
white-space: pre
display: block;
color: #333333;
overflow-x: auto;
p code, ul code
background #FAFAFA
padding 2px 4px
border-radius 2px
border 1px solid #CCC
color #000
code
font-size 14px
line-height 20px
overflow-x: auto;
margin-bottom 40px
.markdown h1:first-child
margin-top 0
padding-top 0
.title
background: #F9F9F9;
padding 30px 0
padding 54px 0
h1
margin 0 auto
@extend $wrapper
font-family: 'Raleway';
font-size: 42px;
font-weight 200
color: #585858;
line-height: 49px;
.docs
@extend $wrapper
.docs-aside
col(1/4)
margin-top 60px
+below(600px)
padding 20px
width 100%
box-sizing content-box
margin 0 -20px
margin-bottom 30px
background #F9F9F9
.docs-aside-group
display block
margin-bottom 40px
h3
font-family: 'Raleway';
font-weight 500
font-size 12px
text-transform uppercase
line-height 1.2em
margin-bottom 1em
color #AAA
a
display block
font-size 15px
font-weight 400
line-height 22px
height 28px
padding 3px 0
color #4A4A4A
&.active
font-weight 500
line-height 21px
color #E05B49
+below(600px)
display none
.docs-aside-navselect
display none
width 100%
+below(600px)
display block
.docs-content
col(3/4)
margin-top 60px
+below(600px)
margin-top 10px
col(1)
>h1
margin 0
@extend $title
font-size 32px

View File

@ -1,12 +1,13 @@
var nib = require("nib");
var jeet = require("jeet");
var rupture = require("rupture");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = function(config, env) {
var IS_STATIC = env === 'static';
config.merge({
stylus: {
use: [nib(), jeet()]
use: [nib(), jeet(), rupture()]
}
});
if (IS_STATIC) {

View File

@ -5,7 +5,7 @@
"main": "n/a",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "npm install -g gatsby && npm install",
"build": "npm install -g gatsby && npm install && gatsby build",
"deploy": "npm run build"
},
"keywords": [

View File

@ -1,6 +1,13 @@
var IN_BROWSER = typeof window != 'undefined';
import React from 'react';
var browser_supported;
if (IN_BROWSER) {
var isSafari = navigator.vendor && navigator.vendor.indexOf('Apple') > -1 &&
navigator.userAgent && !navigator.userAgent.match('CriOS');
var browser_supported = !isSafari;
}
console.log(browser_supported);
if (IN_BROWSER && browser_supported) {
var glfx = require('../vendor/glfx.optim')
var particlesJS = require('../vendor/particles.js')
}
@ -23,12 +30,12 @@ class Header extends React.Component {
this.mounted = false;
}
componentDidMount() {
if (!IN_BROWSER) return;
if (!(IN_BROWSER && browser_supported)) return;
this.mounted = true;
new particlesJS('header-background', {
"particles": {
"number": {
"value": 36,
"value": 40,
"density": {
"enable": true,
"value_area": 800

View File

@ -19,10 +19,10 @@ class Template extends React.Component {
Graphene
</Link>
<nav className="header-nav">
<Link to="/docs/quickstart/">Get started</Link>
<Link to="/">Playground</Link>
<Link to="/">Docs</Link>
<Link to="/try/">Try it out</Link>
<Link to="/docs/quickstart/" className={path.indexOf('/docs')==0?"active":null}>Docs</Link>
<Link to="/community/">Community</Link>
<a href="https://github.com/graphql-python/graphene/">Github</a>
</nav>
</div>
{isIndex?

View File

@ -17,9 +17,17 @@ If you think working with Graphene is fun, there are many ways you can contribut
- **GraphQL Relay**: [Source Code][1] - [PyPI package][2]
- **Graphene**: [Source Code][3] - [PyPI package][4]
Django integration:
- **graphql-django-view**: [Source Code][5] - [PyPI package][6]
- **django-graphiql**: [Source Code][7] - [PyPI package][8]
[Source Code]: https://github.com/graphql-python/graphql-core
[PyPI package]: https://pypi.python.org/pypi/graphql-core
[1]: https://github.com/graphql-python/graphql-relay
[2]: https://pypi.python.org/pypi/graphql-relay
[3]: https://github.com/graphql-python/graphene
[4]: https://pypi.python.org/pypi/graphene
[5]: https://github.com/graphql-python/graphql-django-view
[6]: https://pypi.python.org/pypi/graphql-django-view
[7]: https://github.com/graphql-python/django-graphiql
[8]: https://pypi.python.org/pypi/django-graphiql

View File

@ -0,0 +1,48 @@
import React from 'react';
import { RouteHandler, Link, State } from 'react-router';
import _ from 'lodash';
class Template extends React.Component {
goToPage(event) {
var page = event.target.value;
this.context.router.transitionTo(page);
}
render() {
var docs = this.props.config.docs;
var docs_index = _.indexBy(this.props.pages, 'path');
return (
<div className="docs">
<aside className="docs-aside">
{Object.keys(docs).map((key) => {
let group = docs[key];
return <div className="docs-aside-group" key={key}>
<h3>{group.name}</h3>
{group.pages.map((page) => {
return <Link key={page} to={page}>{docs_index[page].data.title}</Link>
})}
</div>;
})}
<select className="docs-aside-navselect" onChange={this.goToPage.bind(this)}>
{Object.keys(docs).map((key) => {
let group = docs[key];
return <optgroup key={key} label={group.name}>
{group.pages.map((page) => {
return <option key={page} value={page}>{docs_index[page].data.title}</option>
})}
</optgroup>;
})}
</select>
</aside>
<div className="docs-content">
<RouteHandler {...this.props} docs={true}/>
</div>
</div>
);
}
}
Template.contextTypes = {
router: React.PropTypes.func
};
module.exports = Template;

View File

@ -0,0 +1,52 @@
---
title: Basic Types
description: Walkthrough Basic Types
---
# Basic Types
Graphene define the following base Types:
- `graphene.String`
- `graphene.Int`
- `graphene.Float`
- `graphene.Boolean`
- `graphene.ID`
Also, define:
- `graphene.List`
- `graphene.NonNull`
## Mounting in ClassTypes
This types if are mounted in a `ObjectType`, `Interface` or `Mutation`,
would act as `Field`s.
So, the following examples will behave exactly the same:
```python
class Person(graphene.ObjectType):
name = graphene.String()
```
and
```python
class Person(graphene.ObjectType):
name = graphene.Field(graphene.String())
```
## Mounting in Fields
If this types are mounted in a `Field`, would act as `Argument`s.
So, the following examples will behave exactly the same:
```python
class Person(graphene.ObjectType):
say_hello = graphene.Field(graphene.String(),
to=graphene.String())
```
and
```python
class Person(graphene.ObjectType):
say_hello = graphene.Field(graphene.String(),
to=graphene.Argument(graphene.String()))
```

View File

@ -1,9 +1,13 @@
---
title: Interfaces
description: Walkthrough Interfaces
---
# Interfaces
An Interface contains the essential fields that will be shared among multiple ObjectTypes.
The basics:
- Each Interface is a Python class that inherits from graphene.Interface.
- Each attribute of the Interface represents a GraphQL field.
@ -16,19 +20,19 @@ import graphene
# Character is an Interface
class Character(graphene.Interface):
name = graphene.String()
name = graphene.String()
# Human is an ObjectType, as inherits an interface
class Human(Character):
born_in = graphene.String()
born_in = graphene.String()
# Droid is an ObjectType, as inherits an interface
class Droid(Character):
function = graphene.String()
function = graphene.String()
```
**name** is a field in the `Character` interface that will be in both `Human` and `Droid` ObjectTypes (as those inherit from Character). Each ObjectType also define extra fields at the same time.
**name** is a field in the `Character` interface that will be in both `Human` and `Droid` ObjectTypes (as those inherit from `Character`). Each ObjectType also define extra fields at the same time.
The above types would have the following representation in a schema:

View File

@ -0,0 +1,75 @@
---
title: Mutations
description: Walkthrough Mutations
---
# Mutations
A Mutation is a special ObjectType that define also an Input.
## Quick example
This example defines a Mutation:
```python
import graphene
class CreatePerson(graphene.Mutation):
class Input:
name = graphene.String()
ok = graphene.String()
person = graphene.Field('Person')
@classmethod
def mutate(cls, args, info):
person = Person(name=args.get('name'))
ok = True
return CreatePerson(person=person, ok=ok)
```
**person** and **ok** are the output fields of the Mutation when is resolved.
**Input** attributes are the arguments that the Mutation `CreatePerson` needs for resolving, in this case **name** will be the only argument for the mutation.
**mutate** is the function that will be applied once the mutation is called.
So, we can finish our schema like this:
```python
# ... the Mutation Class
class Person(graphene.ObjectType):
name = graphene.String()
class MyMutations(graphene.ObjectType):
create_person = graphene.Field(CreatePerson)
schema = graphene.Schema(mutation=MyMutations)
```
## Executing the Mutation
Then, if we query (`schema.execute(query_str)`) the following:
```graphql
mutation myFirstMutation {
createPerson(name:"Peter") {
person {
name
}
ok
}
}
```
We should receive:
```json
{
"createPerson": {
"person" : {
name: "Peter"
},
"ok": true
}
}

View File

@ -1,10 +1,14 @@
---
title: ObjectTypes
description: Walkthrough ObjectTypes
---
# ObjectTypes
An ObjectType is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data youre querying.
The basics:
- Each ObjectType is a Python class that inherits graphene.ObjectType or inherits an implemented [interface](/docs/interface).
- Each ObjectType is a Python class that inherits graphene.ObjectType or inherits an implemented [interfaces](/docs/interfaces/).
- Each attribute of the ObjectType represents a GraphQL field.
## Quick example
@ -20,7 +24,7 @@ class Person(graphene.ObjectType):
full_name = graphene.String()
def resolve_full_name(self, args, info):
return '{} {}'.format(self.first_name, self.last_name)
return '{} {}'.format(self.first_name, self.last_name)
```
**first_name** and **last_name** are fields of the ObjectType. Each field is specified as a class attribute, and each attribute maps to a GraphQL field.

View File

@ -1,13 +1,10 @@
---
title: Django Quickstart Guide
active_tab: quickstart
title: Guide to Django
description: A Quick guide to Graphene in Django
---
## Django Quickstart
In our previous quickstart page we created a very simple schema.
Now we will adapt the schema for our Django models.
Now we will adapt the schema to map automatically some Django models.
## Project setup

View File

@ -1,10 +1,10 @@
---
title: Quickstart Guide
active_tab: quickstart
title: Getting started
description: A Quick guide to Graphene
---
Graphene is a powerful framework for creating GraphQL schemas easily in Python.
Let's build a basic GraphQL schema from scratch.
## Requirements
@ -23,6 +23,7 @@ cd tutorial
virtualenv env
source env/bin/activate # On Windows use `env\Scripts\activate`
# Install Graphene
pip install graphene
```
@ -30,7 +31,7 @@ pip install graphene
A GraphQL schema describes your data model, and provides a GraphQL server with an associated set of resolve methods that know how to fetch data.
We are going to create a very simple schema, with a `Query` with only one field: `hello`. And when we query it should return 'World'.
We are going to create a very simple schema, with a `Query` with only one field: `hello`. And when we query it should return `"World"`.
```python

View File

@ -1,67 +0,0 @@
# Mutations
A Mutation is a special ObjectType that define also an Input.
## Quick example
This example model defines a Mutation:
```python
import graphene
class CreatePerson(graphene.Mutation):
class Input:
name = graphene.String()
ok = graphene.String()
person = graphene.Field('Person')
@classmethod
def mutate(cls, args, info):
person = Person(name=args.get('name'))
ok = True
return CreatePerson(person=person, ok=ok)
```
**person** and **ok** are the output fields of the Mutation when is resolved.
**Input** attributes are the arguments that the Mutation needs for resolving. **mutate** is the function that will be applied once the mutation is called.
So, we can finish our schema like this:
```python
# ... the Mutation Class
class Person(graphene.ObjectType):
name = graphene.String()
class MyMutations(graphene.ObjectType):
create_person = graphene.Field(CreatePerson)
schema = graphene.Schema(mutation=MyMutations)
```
## Executing the Mutation
Then, if we query (`schema.execute(query_str)`) the following:
```graphql
mutation myFirstMutation {
createPerson(name:"Peter") {
person {
name
}
ok
}
}
```
We should receive:
```json
{
"createPerson": {
"person" : {
name: "Peter"
},
"ok": true
}
}

View File

@ -1,7 +1,7 @@
---
path: /
---
<a class="starwars-example" href="http://swapi.graphene-python.org/">Check our starwars API example!</a>
<div><a class="starwars-example" href="http://swapi.graphene-python.org/">Check our Django Starwars API example!</a></div>
## About Graphene

View File

@ -9,15 +9,15 @@ class Markdown extends React.Component {
var post = this.props.page.data;
var pagePath = this.props.page.requirePath;
var documentUrl = `${DOCS_BASEURL}${pagePath}`;
var showTitle = post.title && !this.props.docs;
return (
<DocumentTitle title={`${post.title?post.title+' - ':''}${this.props.config.siteTitle}`}>
<div className="markdown">
{post.title?<div className="title">
{showTitle?<div className="title">
<h1>{post.title}</h1>
</div>:null}
<div className="wrapper" dangerouslySetInnerHTML={{__html: post.body}}/>
<a href={documentUrl} className="improve-document-link">Improve this document!</a>
<div className={!this.props.docs?"wrapper":null} dangerouslySetInnerHTML={{__html: post.body}}/>
<a href={documentUrl} className="improve-document-link">Edit page</a>
</div>
</DocumentTitle>
);