From 603a3f40c5d8d9abb5cbf416069398d9a5ca0814 Mon Sep 17 00:00:00 2001 From: Pokey Rule Date: Wed, 26 Oct 2016 15:23:36 +0100 Subject: [PATCH 001/239] Fix small bug in code of mark-adverbs tutorial --- website/docs/tutorials/mark-adverbs.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/tutorials/mark-adverbs.jade b/website/docs/tutorials/mark-adverbs.jade index ca3061f81..03799b7dd 100644 --- a/website/docs/tutorials/mark-adverbs.jade +++ b/website/docs/tutorials/mark-adverbs.jade @@ -78,7 +78,7 @@ p A simple work-around is to average the vectors of several words, and use that +code. >>> say_verbs = ['pleaded', 'confessed', 'remonstrated', 'begged', 'bragged', 'confided', 'requested'] >>> say_vector = sum(nlp.vocab[verb].vector for verb in say_verbs) / len(say_verbs) - >>> words.sort(key=lambda w: cosine(w.vector * say_vector)) + >>> words.sort(key=lambda w: cosine(w.vector, say_vector)) >>> words.reverse() >>> print('1-20', ', '.join(w.orth_ for w in words[0:20])) 1-20 bragged, remonstrated, enquired, demurred, sighed, mused, intimated, retorted, entreated, motioned, ranted, confided, countersued, gestured, implored, interceded, muttered, marvelled, bickered, despaired From 6c47048912df028bc51288f7ebed6f74fdd9cef3 Mon Sep 17 00:00:00 2001 From: Matthew Honnibal Date: Wed, 26 Oct 2016 17:22:03 +0200 Subject: [PATCH 002/239] Fix test, after IOB tweak. --- spacy/tests/tokens/test_tokens_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spacy/tests/tokens/test_tokens_api.py b/spacy/tests/tokens/test_tokens_api.py index 62c3a660b..47ad8545f 100644 --- a/spacy/tests/tokens/test_tokens_api.py +++ b/spacy/tests/tokens/test_tokens_api.py @@ -108,7 +108,7 @@ def test_set_ents(EN): assert len(tokens.ents) == 0 tokens.ents = [(EN.vocab.strings['PRODUCT'], 2, 4)] assert len(list(tokens.ents)) == 1 - assert [t.ent_iob for t in tokens] == [2, 2, 3, 1, 2, 2, 2, 2] + assert [t.ent_iob for t in tokens] == [0, 0, 3, 1, 0, 0, 0, 0] ent = tokens.ents[0] assert ent.label_ == 'PRODUCT' assert ent.start == 2 From 63b7c2ef619f2cf3f0be29ec8ac0f6903a6801d6 Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Wed, 26 Oct 2016 18:20:08 -0700 Subject: [PATCH 003/239] Added pull request template. Making following assumptions: * Pull requests do not need to originate from Issues discussion. * But encouraged * No current CONTRIBUTING.md file * honor code that people follow current coding conventions * Tests run and passed * New features require additonal tests for confirmation --- .github/PULL_REQUEST_TEMPLATE.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..5d28f0ff2 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,30 @@ + + +## Description + + +## Motivation and Context + + + +## How Has This Been Tested? + + + + +## Screenshots (if appropriate): + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. \ No newline at end of file From 3e1dbbd52a0250d366684dbbbed5529278682642 Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Wed, 26 Oct 2016 18:27:56 -0700 Subject: [PATCH 004/239] Clarified a few statements on the pull request template. * Added spaCy to several areas to avoid confusion * Simplified a few statements and checkboxes. --- .github/PULL_REQUEST_TEMPLATE.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5d28f0ff2..e99d6dadc 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,30 +1,30 @@ - + ## Description - + ## Motivation and Context - + ## How Has This Been Tested? - - - + + + ## Screenshots (if appropriate): ## Types of changes - -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +- [ ] Bug fix (non-breaking change fixing an issue) +- [ ] New feature (non-breaking change adding functionality to spaCy) +- [ ] Breaking change (fix or feature causing change to spaCy's existing functionality) +- [ ] Documentation (Addition to documentation of spaCy) ## Checklist: - - -- [ ] My code follows the code style of this project. -- [ ] My change requires a change to the documentation. + +- [ ] My code follows spaCy's code style. +- [ ] My change requires a change to spaCy's documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. \ No newline at end of file From 03a520ec4f9296c3d0fa57045154db23f43d2e12 Mon Sep 17 00:00:00 2001 From: Matthew Honnibal Date: Thu, 27 Oct 2016 17:58:56 +0200 Subject: [PATCH 005/239] Change signature of Parser.parseC, so that nr_class is read from the transition system. This allows the transition system to modify the number of actions in initialize_state. --- spacy/syntax/parser.pxd | 2 +- spacy/syntax/parser.pyx | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/spacy/syntax/parser.pxd b/spacy/syntax/parser.pxd index 1ad0ce729..4370f5c6f 100644 --- a/spacy/syntax/parser.pxd +++ b/spacy/syntax/parser.pxd @@ -20,4 +20,4 @@ cdef class Parser: cdef readonly TransitionSystem moves cdef readonly object cfg - cdef int parseC(self, TokenC* tokens, int length, int nr_feat, int nr_class) nogil + cdef int parseC(self, TokenC* tokens, int length, int nr_feat) nogil diff --git a/spacy/syntax/parser.pyx b/spacy/syntax/parser.pyx index 62b61c37b..d7fce5b3d 100644 --- a/spacy/syntax/parser.pyx +++ b/spacy/syntax/parser.pyx @@ -107,10 +107,9 @@ cdef class Parser: return (Parser, (self.vocab, self.moves, self.model), None, None) def __call__(self, Doc tokens): - cdef int nr_class = self.moves.n_moves cdef int nr_feat = self.model.nr_feat with nogil: - status = self.parseC(tokens.c, tokens.length, nr_feat, nr_class) + status = self.parseC(tokens.c, tokens.length, nr_feat) # Check for KeyboardInterrupt etc. Untested PyErr_CheckSignals() if status != 0: @@ -123,7 +122,6 @@ cdef class Parser: cdef int* lengths = mem.alloc(batch_size, sizeof(int)) cdef Doc doc cdef int i - cdef int nr_class = self.moves.n_moves cdef int nr_feat = self.model.nr_feat cdef int status queue = [] @@ -134,7 +132,7 @@ cdef class Parser: if len(queue) == batch_size: with nogil: for i in cython.parallel.prange(batch_size, num_threads=n_threads): - status = self.parseC(doc_ptr[i], lengths[i], nr_feat, nr_class) + status = self.parseC(doc_ptr[i], lengths[i], nr_feat) if status != 0: with gil: raise ParserStateError(queue[i]) @@ -146,7 +144,7 @@ cdef class Parser: batch_size = len(queue) with nogil: for i in cython.parallel.prange(batch_size, num_threads=n_threads): - status = self.parseC(doc_ptr[i], lengths[i], nr_feat, nr_class) + status = self.parseC(doc_ptr[i], lengths[i], nr_feat) if status != 0: with gil: raise ParserStateError(queue[i]) @@ -155,7 +153,12 @@ cdef class Parser: self.moves.finalize_doc(doc) yield doc - cdef int parseC(self, TokenC* tokens, int length, int nr_feat, int nr_class) nogil: + cdef int parseC(self, TokenC* tokens, int length, int nr_feat) nogil: + state = new StateC(tokens, length) + # NB: This can change self.moves.n_moves! + self.moves.initialize_state(state) + nr_class = self.moves.n_moves + cdef ExampleC eg eg.nr_feat = nr_feat eg.nr_atom = CONTEXT_SIZE @@ -164,8 +167,6 @@ cdef class Parser: eg.atoms = calloc(sizeof(atom_t), CONTEXT_SIZE) eg.scores = calloc(sizeof(weight_t), nr_class) eg.is_valid = calloc(sizeof(int), nr_class) - state = new StateC(tokens, length) - self.moves.initialize_state(state) cdef int i while not state.is_final(): self.model.set_featuresC(&eg, state) From afea6505f3b0ebaf82d6e4dd25e6cb63ed2b3087 Mon Sep 17 00:00:00 2001 From: Matthew Honnibal Date: Thu, 27 Oct 2016 18:01:34 +0200 Subject: [PATCH 006/239] Test Issue 429: No valid actions for NER after matcher adds a new entity label. --- spacy/tests/regression/test_issue429.py | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 spacy/tests/regression/test_issue429.py diff --git a/spacy/tests/regression/test_issue429.py b/spacy/tests/regression/test_issue429.py new file mode 100644 index 000000000..b3e6b2831 --- /dev/null +++ b/spacy/tests/regression/test_issue429.py @@ -0,0 +1,29 @@ +from __future__ import unicode_literals +import pytest + +import spacy +from spacy.attrs import ORTH + + +@pytest.mark.models +def test_issue429(): + + nlp = spacy.load('en', parser=False) + + + def merge_phrases(matcher, doc, i, matches): + if i != len(matches) - 1: + return None + spans = [(ent_id, label, doc[start:end]) for ent_id, label, start, end in matches] + for ent_id, label, span in spans: + span.merge('NNP' if label else span.root.tag_, span.text, nlp.vocab.strings[label]) + + doc = nlp('a') + nlp.matcher.add('key', label='TEST', attrs={}, specs=[[{ORTH: 'a'}]], on_match=merge_phrases) + doc = nlp.tokenizer('a b c') + nlp.tagger(doc) + nlp.matcher(doc) + + for word in doc: + print(word.text, word.ent_iob_, word.ent_type_) + nlp.entity(doc) From 301f3cc8981407d7c69099f5bc706b3ac035bdc8 Mon Sep 17 00:00:00 2001 From: Matthew Honnibal Date: Thu, 27 Oct 2016 18:01:55 +0200 Subject: [PATCH 007/239] Fix Issue #429. Add an initialize_state method to the named entity recogniser that adds missing entity types. This is a messy place to add this, because it's strange to have the method mutate state. A better home for this logic could be found. --- spacy/syntax/ner.pyx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spacy/syntax/ner.pyx b/spacy/syntax/ner.pyx index 53eb1496d..c04205d89 100644 --- a/spacy/syntax/ner.pyx +++ b/spacy/syntax/ner.pyx @@ -158,6 +158,15 @@ cdef class BiluoPushDown(TransitionSystem): raise Exception(move) return t + cdef int initialize_state(self, StateC* st) nogil: + for i in range(st.length): + if st._sent[i].ent_type != 0: + with gil: + self.add_action(BEGIN, st._sent[i].ent_type) + self.add_action(IN, st._sent[i].ent_type) + self.add_action(UNIT, st._sent[i].ent_type) + self.add_action(LAST, st._sent[i].ent_type) + cdef class Missing: @staticmethod From 18590eba94824ee0d419125e644e283173d2dd91 Mon Sep 17 00:00:00 2001 From: Matthew Honnibal Date: Thu, 27 Oct 2016 18:02:19 +0200 Subject: [PATCH 008/239] Fix training evaluate method --- spacy/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spacy/train.py b/spacy/train.py index 097218310..26fdf0e11 100644 --- a/spacy/train.py +++ b/spacy/train.py @@ -48,7 +48,7 @@ class Trainer(object): docs = self.make_docs(raw_text, paragraph_tuples) golds = self.make_golds(docs, paragraph_tuples) for doc, gold in zip(docs, golds): - for process in self.nlp.pipeline[1:]: + for process in self.nlp.pipeline: process(doc) scorer.score(doc, gold) return scorer From 708ea22208935b03fe57086e8ba91ef925410145 Mon Sep 17 00:00:00 2001 From: Matthew Honnibal Date: Thu, 27 Oct 2016 18:08:13 +0200 Subject: [PATCH 009/239] Infer types in transition_system.pyx --- spacy/syntax/transition_system.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/spacy/syntax/transition_system.pyx b/spacy/syntax/transition_system.pyx index 9e624bd58..a4bb02753 100644 --- a/spacy/syntax/transition_system.pyx +++ b/spacy/syntax/transition_system.pyx @@ -1,3 +1,4 @@ +# cython: infer_types=True from cymem.cymem cimport Pool from thinc.typedefs cimport weight_t from collections import defaultdict From bd48d44fa7c88400b118299c6c58d7a02431838f Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Thu, 27 Oct 2016 13:46:35 -0700 Subject: [PATCH 010/239] Started work on ISSUES template. Want to have small section to address each issue area: * What happened/what did you expect? * Fix suggestions/reason bug happened. * How to reproduce for other contributors to replicate. * Look at how workflow was affected by issue. * As much detail as they can provide about their setup. --- .github/ISSUES.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/ISSUES.md diff --git a/.github/ISSUES.md b/.github/ISSUES.md new file mode 100644 index 000000000..335b27aa3 --- /dev/null +++ b/.github/ISSUES.md @@ -0,0 +1,10 @@ + + +# Context + + +# Expected Behavior + + +# Actual Behavior + From 932f4c846972867ea5c905474e03d71d0e810809 Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Thu, 27 Oct 2016 23:03:33 -0700 Subject: [PATCH 011/239] Finished ISSUES.md * Added section for reproducing bug * Promote step by step reproduction of code, see if anything has been incorrectly done. * Context section for extra details that might be helpful for issue tracking * Final Checklist. Verify bug can be reproduced and details are present. --- .github/ISSUES.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/.github/ISSUES.md b/.github/ISSUES.md index 335b27aa3..f714ca4d3 100644 --- a/.github/ISSUES.md +++ b/.github/ISSUES.md @@ -1,10 +1,39 @@ -# Context +## Context -# Expected Behavior +### Expected Behavior -# Actual Behavior +### Actual Behavior + +## Possible Fix + + + +## Reproduction + +**Steps** +1. Step +2. Step +3. Step + + +# Context + + +## Your Environment + +* Operating System: +* Python Version Used: +* spaCy Version Used: +* Environment Information: + +# Checklist + +- [] Included Explanation of Issue +- [] Can Replicate Issue With Your Provided Steps +- [] Code / error snippet is present +- [] Detailed description of your environment From b66c4c37885c5aea109d11138874201c7314319e Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Thu, 27 Oct 2016 23:09:28 -0700 Subject: [PATCH 012/239] Formatted the steps to be in neat ordered list. Minor grammar adjustments. --- .github/ISSUES.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/ISSUES.md b/.github/ISSUES.md index f714ca4d3..981669a4b 100644 --- a/.github/ISSUES.md +++ b/.github/ISSUES.md @@ -16,9 +16,12 @@ ## Reproduction **Steps** + 1. Step 2. Step 3. Step +4. Step + # Context @@ -32,7 +35,7 @@ * Environment Information: # Checklist - + - [] Included Explanation of Issue - [] Can Replicate Issue With Your Provided Steps - [] Code / error snippet is present From b2230cd7fb5b0ba0424e02d28f5a1ba064015924 Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Thu, 27 Oct 2016 23:15:55 -0700 Subject: [PATCH 013/239] Renamed ISSUES.md to proper template convention of ISSUE_TEMPLATE.md --- .github/ISSUES.md | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 .github/ISSUES.md diff --git a/.github/ISSUES.md b/.github/ISSUES.md deleted file mode 100644 index 981669a4b..000000000 --- a/.github/ISSUES.md +++ /dev/null @@ -1,42 +0,0 @@ - - -## Context - - -### Expected Behavior - - -### Actual Behavior - - -## Possible Fix - - - -## Reproduction - -**Steps** - -1. Step -2. Step -3. Step -4. Step - - - -# Context - - -## Your Environment - -* Operating System: -* Python Version Used: -* spaCy Version Used: -* Environment Information: - -# Checklist - -- [] Included Explanation of Issue -- [] Can Replicate Issue With Your Provided Steps -- [] Code / error snippet is present -- [] Detailed description of your environment From 071989fd15fa48fdc58febac367b2a28931d6af6 Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Thu, 27 Oct 2016 23:15:55 -0700 Subject: [PATCH 014/239] Renamed ISSUES.md to proper template convention of ISSUE_TEMPLATE.md --- .github/ISSUES.md | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 .github/ISSUES.md diff --git a/.github/ISSUES.md b/.github/ISSUES.md deleted file mode 100644 index 981669a4b..000000000 --- a/.github/ISSUES.md +++ /dev/null @@ -1,42 +0,0 @@ - - -## Context - - -### Expected Behavior - - -### Actual Behavior - - -## Possible Fix - - - -## Reproduction - -**Steps** - -1. Step -2. Step -3. Step -4. Step - - - -# Context - - -## Your Environment - -* Operating System: -* Python Version Used: -* spaCy Version Used: -* Environment Information: - -# Checklist - -- [] Included Explanation of Issue -- [] Can Replicate Issue With Your Provided Steps -- [] Code / error snippet is present -- [] Detailed description of your environment From 1f8826e9061066308537575e4e7064da25e206dd Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Thu, 27 Oct 2016 23:19:18 -0700 Subject: [PATCH 015/239] Tracking proper file: ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..981669a4b --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,42 @@ + + +## Context + + +### Expected Behavior + + +### Actual Behavior + + +## Possible Fix + + + +## Reproduction + +**Steps** + +1. Step +2. Step +3. Step +4. Step + + + +# Context + + +## Your Environment + +* Operating System: +* Python Version Used: +* spaCy Version Used: +* Environment Information: + +# Checklist + +- [] Included Explanation of Issue +- [] Can Replicate Issue With Your Provided Steps +- [] Code / error snippet is present +- [] Detailed description of your environment From 782e4814f4ef4c5dead5cd633dd07b35400636b0 Mon Sep 17 00:00:00 2001 From: Matthew Honnibal Date: Fri, 28 Oct 2016 16:38:32 +0200 Subject: [PATCH 016/239] Test Issue #587: Matcher segfaults on particular input --- spacy/tests/regression/test_issue587.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 spacy/tests/regression/test_issue587.py diff --git a/spacy/tests/regression/test_issue587.py b/spacy/tests/regression/test_issue587.py new file mode 100644 index 000000000..9f2a317f5 --- /dev/null +++ b/spacy/tests/regression/test_issue587.py @@ -0,0 +1,16 @@ +import spacy +import spacy.matcher + +import pytest + +@pytest.mark.models +def test_matcher_segfault(): + nlp = spacy.load('en', parser=False, entity=False) + matcher = spacy.matcher.Matcher(nlp.vocab) + content = u'''a b; c''' + matcher.add(entity_key='1', label='TEST', attrs={}, specs=[[{65: 'a'}, {65: 'b'}]]) + matcher(nlp(content)) + matcher.add(entity_key='2', label='TEST', attrs={}, specs=[[{65: 'a'}, {65: 'b'}, {5: True}, {65: 'c'}]]) + matcher(nlp(content)) + matcher.add(entity_key='3', label='TEST', attrs={}, specs=[[{65: 'a'}, {65: 'b'}, {5: True}, {65: 'd'}]]) + matcher(nlp(content)) From 7e5f63a59596a7951af4ccfb286cc831c3972822 Mon Sep 17 00:00:00 2001 From: Matthew Honnibal Date: Fri, 28 Oct 2016 17:41:16 +0200 Subject: [PATCH 017/239] Improve test slightly --- spacy/tests/regression/test_issue587.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spacy/tests/regression/test_issue587.py b/spacy/tests/regression/test_issue587.py index 9f2a317f5..5b86801d6 100644 --- a/spacy/tests/regression/test_issue587.py +++ b/spacy/tests/regression/test_issue587.py @@ -1,5 +1,6 @@ import spacy import spacy.matcher +from spacy.attrs import IS_PUNCT, ORTH import pytest @@ -8,9 +9,9 @@ def test_matcher_segfault(): nlp = spacy.load('en', parser=False, entity=False) matcher = spacy.matcher.Matcher(nlp.vocab) content = u'''a b; c''' - matcher.add(entity_key='1', label='TEST', attrs={}, specs=[[{65: 'a'}, {65: 'b'}]]) + matcher.add(entity_key='1', label='TEST', attrs={}, specs=[[{ORTH: 'a'}, {ORTH: 'b'}]]) matcher(nlp(content)) - matcher.add(entity_key='2', label='TEST', attrs={}, specs=[[{65: 'a'}, {65: 'b'}, {5: True}, {65: 'c'}]]) + matcher.add(entity_key='2', label='TEST', attrs={}, specs=[[{ORTH: 'a'}, {ORTH: 'b'}, {IS_PUNCT: True}, {ORTH: 'c'}]]) matcher(nlp(content)) - matcher.add(entity_key='3', label='TEST', attrs={}, specs=[[{65: 'a'}, {65: 'b'}, {5: True}, {65: 'd'}]]) + matcher.add(entity_key='3', label='TEST', attrs={}, specs=[[{ORTH: 'a'}, {ORTH: 'b'}, {IS_PUNCT: True}, {ORTH: 'd'}]]) matcher(nlp(content)) From d563f1eadb965de5dc09536cc8c6263277b864fe Mon Sep 17 00:00:00 2001 From: Matthew Honnibal Date: Fri, 28 Oct 2016 17:42:00 +0200 Subject: [PATCH 018/239] Fix Issue #587: Segfault in Matcher, due to simple error in the state machine. --- spacy/matcher.pyx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spacy/matcher.pyx b/spacy/matcher.pyx index de7622dca..7279b003c 100644 --- a/spacy/matcher.pyx +++ b/spacy/matcher.pyx @@ -1,4 +1,5 @@ # cython: profile=True +# cython: infer_types=True from __future__ import unicode_literals from os import path @@ -277,6 +278,8 @@ cdef class Matcher: # we over-write them (q doesn't advance) for state in partials: action = get_action(state.second, token) + if action == PANIC: + raise Exception("Error selecting action in matcher") while action == ADVANCE_ZERO: state.second += 1 action = get_action(state.second, token) @@ -288,6 +291,7 @@ cdef class Matcher: elif action == REJECT: pass elif action == ADVANCE: + partials[q] = state partials[q].second += 1 q += 1 elif action == ACCEPT: @@ -307,6 +311,8 @@ cdef class Matcher: # Check whether we open any new patterns on this token for pattern in self.patterns: action = get_action(pattern, token) + if action == PANIC: + raise Exception("Error selecting action in matcher") while action == ADVANCE_ZERO: pattern += 1 action = get_action(pattern, token) From c2d2b12ef73835ebbfff4c72bd175108400a6264 Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Fri, 28 Oct 2016 23:21:32 -0700 Subject: [PATCH 019/239] Tightening up ISSUE_Template --- .github/ISSUES.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/ISSUES.md diff --git a/.github/ISSUES.md b/.github/ISSUES.md new file mode 100644 index 000000000..1f7cf9a99 --- /dev/null +++ b/.github/ISSUES.md @@ -0,0 +1,18 @@ + +## Issue body + + + +## Your Environment + +* Operating System: +* Python Version Used: +* spaCy Version Used: +* Environment Information: + +# Checklist + +- [] Included Explanation of Issue +- [] Can Replicate Issue With Your Provided Steps +- [] Code / error snippet is present +- [] Detailed description of your environment From f0eba7f568a65fa16984c531801d10e644ed5a3a Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Fri, 28 Oct 2016 23:21:50 -0700 Subject: [PATCH 020/239] Tightening up ISSUE_Template --- .github/ISSUES.md | 18 ------------------ .github/ISSUE_TEMPLATE.md | 30 +++--------------------------- 2 files changed, 3 insertions(+), 45 deletions(-) delete mode 100644 .github/ISSUES.md diff --git a/.github/ISSUES.md b/.github/ISSUES.md deleted file mode 100644 index 1f7cf9a99..000000000 --- a/.github/ISSUES.md +++ /dev/null @@ -1,18 +0,0 @@ - -## Issue body - - - -## Your Environment - -* Operating System: -* Python Version Used: -* spaCy Version Used: -* Environment Information: - -# Checklist - -- [] Included Explanation of Issue -- [] Can Replicate Issue With Your Provided Steps -- [] Code / error snippet is present -- [] Detailed description of your environment diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 981669a4b..adfd3d6b8 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,31 +1,7 @@ +## Issue body + -## Context - - -### Expected Behavior - - -### Actual Behavior - - -## Possible Fix - - - -## Reproduction - -**Steps** - -1. Step -2. Step -3. Step -4. Step - - - -# Context - ## Your Environment @@ -39,4 +15,4 @@ - [] Included Explanation of Issue - [] Can Replicate Issue With Your Provided Steps - [] Code / error snippet is present -- [] Detailed description of your environment +- [] Detailed description of your environment \ No newline at end of file From 39a2e993f17745ac41373457fa0ba62c4fc07dcd Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Fri, 28 Oct 2016 23:27:36 -0700 Subject: [PATCH 021/239] Add link to spaCy stackoverflow tag --- .github/ISSUE_TEMPLATE.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index adfd3d6b8..3700f4786 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,6 +1,10 @@ ## Issue body - + ## Your Environment @@ -8,11 +12,4 @@ * Operating System: * Python Version Used: * spaCy Version Used: -* Environment Information: - -# Checklist - -- [] Included Explanation of Issue -- [] Can Replicate Issue With Your Provided Steps -- [] Code / error snippet is present -- [] Detailed description of your environment \ No newline at end of file +* Environment Information: \ No newline at end of file From 3bc4c6bbab78cc75d29c3ab656b2addf04053b23 Mon Sep 17 00:00:00 2001 From: Sam Bozek Date: Fri, 28 Oct 2016 23:32:11 -0700 Subject: [PATCH 022/239] Minor grammar tweak to environment section --- .github/ISSUE_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 3700f4786..45cec7aff 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -8,7 +8,7 @@ Has your issue been discussed on stackoverflow? http://stackoverflow.com/questio ## Your Environment - + * Operating System: * Python Version Used: * spaCy Version Used: From 7615b41bff05f71283996a27bb18353e046201c1 Mon Sep 17 00:00:00 2001 From: Ines Montani Date: Mon, 31 Oct 2016 19:04:15 +0100 Subject: [PATCH 023/239] Update to new website --- .gitignore | 2 + website/404.jade | 10 +- website/README.md | 103 +++- website/_data.json | 66 +-- website/_harp.json | 42 +- website/_includes/_footer.jade | 33 +- website/_includes/_functions.jade | 16 +- website/_includes/_logo.jade | 6 - website/_includes/_mixins-base.jade | 102 ++++ website/_includes/_mixins.jade | 256 +++++++++- website/_includes/_mixins/_base.jade | 42 -- website/_includes/_mixins/_components.jade | 112 ----- website/_includes/_mixins/_headlines.jade | 49 -- website/_includes/_navigation.jade | 25 +- website/_includes/_newsletter.jade | 26 +- website/_includes/_page-docs.jade | 27 + website/_includes/_scripts.jade | 14 - website/_includes/_sidebar.jade | 16 +- website/_layout.jade | 55 ++- website/announcement.jade | 14 + website/assets/css/_base/_animations.sass | 4 +- website/assets/css/_base/_fonts.sass | 4 +- website/assets/css/_base/_grid.sass | 4 +- website/assets/css/_base/_layout.sass | 19 +- website/assets/css/_base/_objects.sass | 83 ++-- website/assets/css/_base/_reset.sass | 22 +- website/assets/css/_base/_utilities.sass | 142 +++--- website/assets/css/_components/_asides.sass | 58 ++- website/assets/css/_components/_buttons.sass | 18 +- website/assets/css/_components/_code.sass | 44 +- website/assets/css/_components/_landing.sass | 20 + website/assets/css/_components/_lists.sass | 14 +- website/assets/css/_components/_misc.sass | 22 +- .../assets/css/_components/_navigation.sass | 35 +- website/assets/css/_components/_sidebar.sass | 54 +- website/assets/css/_components/_tables.sass | 76 ++- website/assets/css/_mixins.sass | 16 +- website/assets/css/_variables.sass | 45 +- website/assets/css/style.sass | 7 +- website/assets/css/style_red.sass | 4 + website/assets/img/graphics.svg | 68 +++ website/assets/img/icons.svg | 41 +- website/assets/img/logo.png | Bin 4246 -> 0 bytes website/assets/img/logos/indico.png | Bin 0 -> 1215 bytes website/assets/img/logos/spyjack.png | Bin 644 -> 0 bytes website/assets/img/logos/wonderflow.png | Bin 1217 -> 1216 bytes website/assets/img/pattern.jpg | Bin 222353 -> 0 bytes website/assets/img/pattern_blue.jpg | Bin 0 -> 230088 bytes website/assets/img/pattern_landing.jpg | Bin 0 -> 186575 bytes website/assets/img/pattern_red.jpg | Bin 0 -> 184784 bytes website/assets/img/profile_matt.png | Bin 0 -> 110069 bytes website/assets/img/showcase/displacy-ent.jpg | Bin 0 -> 32314 bytes website/assets/img/showcase/displacy.jpg | Bin 0 -> 16049 bytes website/assets/img/showcase/foxtype.jpg | Bin 0 -> 27435 bytes website/assets/img/showcase/indico.jpg | Bin 0 -> 33559 bytes website/assets/img/showcase/kip.jpg | Bin 0 -> 28937 bytes website/assets/img/showcase/laice.jpg | Bin 0 -> 9263 bytes website/assets/img/showcase/sense2vec.jpg | Bin 0 -> 32686 bytes website/assets/img/showcase/textanalysis.jpg | Bin 0 -> 16789 bytes website/assets/img/social.jpg | Bin 0 -> 372379 bytes website/assets/img/social.png | Bin 252761 -> 0 bytes website/assets/img/social_docs.jpg | Bin 0 -> 258021 bytes website/assets/img/spacy_screen.png | Bin 515998 -> 0 bytes website/assets/js/main.js | 54 +- website/blog/_data.json | 10 - website/blog/announcement.jade | 12 - website/blog/index.jade | 5 - website/docs/_annotation-specs.jade | 167 ------- website/docs/_api-doc.jade | 305 ------------ website/docs/_api-language.jade | 258 ---------- website/docs/_api-lexeme.jade | 194 -------- website/docs/_api-matcher.jade | 81 --- website/docs/_api-span.jade | 305 ------------ website/docs/_api-stringstore.jade | 105 ---- website/docs/_api-token.jade | 321 ------------ website/docs/_api-vocab.jade | 154 ------ website/docs/_data.json | 44 +- website/docs/_quickstart-examples.jade | 176 ------- website/docs/_quickstart-install.jade | 122 ----- website/docs/_tutorials.jade | 12 - website/docs/api/_data.json | 103 ++++ website/docs/api/annotation.jade | 148 ++++++ website/docs/api/dependencyparser.jade | 135 +++++ website/docs/api/doc.jade | 416 ++++++++++++++++ website/docs/api/entityrecognizer.jade | 133 +++++ website/docs/api/goldparse.jade | 103 ++++ website/docs/api/index.jade | 239 +++++++++ website/docs/api/language.jade | 138 ++++++ website/docs/api/lexeme.jade | 239 +++++++++ website/docs/api/matcher.jade | 179 +++++++ website/docs/api/philosophy.jade | 14 + website/docs/api/span.jade | 264 ++++++++++ website/docs/api/stringstore.jade | 107 ++++ website/docs/api/tagger.jade | 117 +++++ website/docs/api/token.jade | 460 ++++++++++++++++++ website/docs/api/vocab.jade | 278 +++++++++++ website/docs/index.jade | 37 +- website/docs/tutorials/_data.json | 49 -- website/docs/tutorials/byo-annotations.jade | 117 ----- website/docs/tutorials/custom-pipelines.jade | 89 ---- .../docs/tutorials/load-new-word-vectors.jade | 66 --- .../docs/tutorials/rule-based-matcher.jade | 74 --- website/docs/tutorials/syntax-search.jade | 76 --- website/docs/tutorials/twitter-filter.jade | 154 ------ website/docs/usage/_data.json | 276 +++++++++++ website/docs/usage/customizing-pipeline.jade | 38 ++ website/docs/usage/data-model.jade | 259 ++++++++++ website/docs/usage/deep-learning.jade | 213 ++++++++ website/docs/usage/dependency-parse.jade | 163 +++++++ website/docs/usage/index.jade | 111 +++++ .../usage/language-processing-pipeline.jade | 128 +++++ website/docs/usage/lightning-tour.jade | 177 +++++++ website/docs/usage/processing-text.jade | 133 +++++ website/docs/usage/rule-based-matching.jade | 155 ++++++ website/docs/usage/showcase.jade | 44 ++ website/docs/usage/tutorials.jade | 38 ++ .../docs/usage/word-vectors-similarities.jade | 66 +++ website/index.jade | 257 +++++----- website/robots.txt.jade | 4 +- 119 files changed, 6161 insertions(+), 3777 deletions(-) delete mode 100644 website/_includes/_logo.jade create mode 100644 website/_includes/_mixins-base.jade delete mode 100644 website/_includes/_mixins/_base.jade delete mode 100644 website/_includes/_mixins/_components.jade delete mode 100644 website/_includes/_mixins/_headlines.jade create mode 100644 website/_includes/_page-docs.jade delete mode 100644 website/_includes/_scripts.jade create mode 100644 website/announcement.jade create mode 100644 website/assets/css/_components/_landing.sass create mode 100644 website/assets/css/style_red.sass create mode 100644 website/assets/img/graphics.svg delete mode 100644 website/assets/img/logo.png create mode 100644 website/assets/img/logos/indico.png delete mode 100644 website/assets/img/logos/spyjack.png delete mode 100644 website/assets/img/pattern.jpg create mode 100644 website/assets/img/pattern_blue.jpg create mode 100644 website/assets/img/pattern_landing.jpg create mode 100644 website/assets/img/pattern_red.jpg create mode 100644 website/assets/img/profile_matt.png create mode 100644 website/assets/img/showcase/displacy-ent.jpg create mode 100644 website/assets/img/showcase/displacy.jpg create mode 100644 website/assets/img/showcase/foxtype.jpg create mode 100644 website/assets/img/showcase/indico.jpg create mode 100644 website/assets/img/showcase/kip.jpg create mode 100644 website/assets/img/showcase/laice.jpg create mode 100644 website/assets/img/showcase/sense2vec.jpg create mode 100644 website/assets/img/showcase/textanalysis.jpg create mode 100644 website/assets/img/social.jpg delete mode 100644 website/assets/img/social.png create mode 100644 website/assets/img/social_docs.jpg delete mode 100644 website/assets/img/spacy_screen.png delete mode 100644 website/blog/_data.json delete mode 100644 website/blog/announcement.jade delete mode 100644 website/blog/index.jade delete mode 100644 website/docs/_annotation-specs.jade delete mode 100644 website/docs/_api-doc.jade delete mode 100644 website/docs/_api-language.jade delete mode 100644 website/docs/_api-lexeme.jade delete mode 100644 website/docs/_api-matcher.jade delete mode 100644 website/docs/_api-span.jade delete mode 100644 website/docs/_api-stringstore.jade delete mode 100644 website/docs/_api-token.jade delete mode 100644 website/docs/_api-vocab.jade delete mode 100644 website/docs/_quickstart-examples.jade delete mode 100644 website/docs/_quickstart-install.jade delete mode 100644 website/docs/_tutorials.jade create mode 100644 website/docs/api/_data.json create mode 100644 website/docs/api/annotation.jade create mode 100644 website/docs/api/dependencyparser.jade create mode 100644 website/docs/api/doc.jade create mode 100644 website/docs/api/entityrecognizer.jade create mode 100644 website/docs/api/goldparse.jade create mode 100644 website/docs/api/index.jade create mode 100644 website/docs/api/language.jade create mode 100644 website/docs/api/lexeme.jade create mode 100644 website/docs/api/matcher.jade create mode 100644 website/docs/api/philosophy.jade create mode 100644 website/docs/api/span.jade create mode 100644 website/docs/api/stringstore.jade create mode 100644 website/docs/api/tagger.jade create mode 100644 website/docs/api/token.jade create mode 100644 website/docs/api/vocab.jade delete mode 100644 website/docs/tutorials/_data.json delete mode 100644 website/docs/tutorials/byo-annotations.jade delete mode 100644 website/docs/tutorials/custom-pipelines.jade delete mode 100644 website/docs/tutorials/load-new-word-vectors.jade delete mode 100644 website/docs/tutorials/rule-based-matcher.jade delete mode 100644 website/docs/tutorials/syntax-search.jade delete mode 100644 website/docs/tutorials/twitter-filter.jade create mode 100644 website/docs/usage/_data.json create mode 100644 website/docs/usage/customizing-pipeline.jade create mode 100644 website/docs/usage/data-model.jade create mode 100644 website/docs/usage/deep-learning.jade create mode 100644 website/docs/usage/dependency-parse.jade create mode 100644 website/docs/usage/index.jade create mode 100644 website/docs/usage/language-processing-pipeline.jade create mode 100644 website/docs/usage/lightning-tour.jade create mode 100644 website/docs/usage/processing-text.jade create mode 100644 website/docs/usage/rule-based-matching.jade create mode 100644 website/docs/usage/showcase.jade create mode 100644 website/docs/usage/tutorials.jade create mode 100644 website/docs/usage/word-vectors-similarities.jade diff --git a/.gitignore b/.gitignore index 74d63241a..fa84fb38e 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,5 @@ website/demos/sense2vec/ # Website website/_deploy.sh website/package.json + +website/blog/announcement.jade diff --git a/website/404.jade b/website/404.jade index e243a9ba6..33b936a08 100644 --- a/website/404.jade +++ b/website/404.jade @@ -1,7 +1,11 @@ -//- ---------------------------------- //- 💫 404 ERROR -//- ---------------------------------- include _includes/_mixins -p.u-text-large.u-text-center Ooops, this page does not exist. Click #[a(href="javascript:history.go(-1)") here] to go back. ++landing-header + h1.c-landing__title.u-heading-0 + | Ooops, this page#[br] + | does not exist! + + h2.c-landing__title.u-heading-3.u-padding-small + a(href="javascript:history.go(-1)") Click here to go back. diff --git a/website/README.md b/website/README.md index 04acb47ce..5d0fbfad1 100644 --- a/website/README.md +++ b/website/README.md @@ -1,13 +1,13 @@ -# Source files for the spacy.io website and docs +# spacy.io website and docs The [spacy.io](https://spacy.io) website is implemented in [Jade (aka Pug)](https://www.jade-lang.org), and is built or served by [Harp](https://harpjs.com). Jade is an extensible templating language with a readable syntax, that compiles to HTML. The website source makes extensive use of Jade mixins, so that the design system is abstracted away from the content you're writing. You can read more about our approach in our blog post, ["Rebuilding a Website with Modular Markup"](https://explosion.ai/blog/modular-markup). -## Building the site +## Viewing the site locally ```bash sudo npm install --global harp @@ -17,3 +17,102 @@ harp server ``` This will serve the site on [http://localhost:9000](http://localhost:9000). + + +## Making changes to the site + +The docs can always use another example or more detail, and they should always be up to date and not misleading. If you see something, say something – we always appreciate a [pull request](https://github.com/explosion/spaCy/pulls). To quickly find the correct file to edit, simply click on the "Suggest edits" button at the bottom of a page. + +### File structure + +While all page content lives in the `.jade` files, article meta (page titles, sidebars etc.) is stored as JSON. Each folder contains a `_data.json` with all required meta for its files. + +For simplicity, all sites linked in the [tutorials](https://spacy.io/docs/usage/tutorials) and [showcase](https://spacy.io/docs/usage/showcase) are also stored as JSON. So in order to edit those pages, there's no need to dig into the Jade files – simply edit the [`_data.json`](website/docs/usage/_data.json). + +### Markup language and conventions + +Jade/Pug is a whitespace-sensitive markup language that compiles to HTML. Indentation is used to nest elements, and for template logic, like `if`/`else` or `for`, mainly used to iterate over objects and arrays in the meta data. It also allows inline JavaScript expressions. + +For an overview of Harp and Jade, see [this blog post](https://ines.io/blog/the-ultimate-guide-static-websites-harp-jade). For more info on the Jade/Pug syntax, check out their [documentation](https://pugjs.org). + +In the [spacy.io](https://spacy.io) source, we use 4 spaces to indent and hard-wrap at 80 characters. + +```pug +p This is a very short paragraph. It stays inline. + +p + | This is a much longer paragraph. It's hard-wrapped at 80 characters to + | make it easier to read on GitHub and in editors that do not have soft + | wrapping enabled. To prevent Jade from interpreting each line as a new + | element, it's prefixed with a pipe and two spaces. This ensures that no + | spaces are dropped – for example, if your editor strips out trailing + | whitespace by default. Inline links are added using the inline syntax, + | like this: #[+a("https://google.com") Google]. +``` + +Note that for external links, `+a("...")` is used instead of `a(href="...")` – it's a mixin that takes care of adding all required attributes. + +### Mixins + +Each file includes a collection of [custom mixins](website/_includes/_mixins.jade) that make it easier to add content components – no HTML or class names required. + +For example: +```pug +//- Bulleted list + ++list + +item This is a list item. + +item This is another list item. + +//- Table with header + ++table([ "Header one", "Header two" ]) + +row + +cell Table cell + +cell Another one + + +row + +cell And one more. + +cell And the last one. + +//- Headlines with optional permalinks + ++h(2, "link-id") Headline 2 with link to #link-id +``` + +Code blocks are implemented using the `+code` or `+aside-code` (to display them in the sidebar). A `.` is added after the mixin call to preserve whitespace: + +```pug ++code("This is a label"). + import spacy + en_nlp = spacy.load('en') + en_doc = en_nlp(u'Hello, world. Here are two sentences.') +``` + +You can find the documentation for the available mixins in [`_includes/_mixins.jade`](website/_includes/_mixins.jade). + +### Linking to the Github repo + +Since GitHub links can be long and tricky, you can use the `gh()` function to generate them automatically for spaCy and all repositories owned by [explosion](https://github.com/explosion): + +```pug +//- Syntax: gh(repo, [file], [branch]) + ++src(gh("spaCy", "spacy/matcher.pyx")) + +//- https://github.com/explosion/spaCy/blob/master/spacy/matcher.pyx + +``` + +`+src()` creates a link with a little source icon to indicate it's linking to a code source. + +### Most common causes of compile errors + +| Problem | Fix | +| --- | --- | +| JSON formatting errors | make sure last elements of objects don't end with commas and/or use a JSON linter | +| unescaped characters like `<` or `>` and sometimes `'` in inline elements | replace with encoded version: `<`, `>` etc. | +| "Cannot read property 'call' of undefined" / "foo is not a function" | make sure mixin names are spelled correctly and mixins file is included with the correct path | +| "no closing bracket found" | make sure inline elements end with a `]`, like `#[code spacy.load('en')]` and for nested inline elements, make sure they're all on the same line and contain spaces between them (**bad:** `#[+api("doc")#[code Doc]]`) | + +If Harp fails and throws a Jade error, don't take the reported line number at face value – it's often wrong, as the page is compiled from templates and several files. diff --git a/website/_data.json b/website/_data.json index 17b29dd20..56da2f63e 100644 --- a/website/_data.json +++ b/website/_data.json @@ -2,27 +2,27 @@ "index": { "landing": true, "logos": [ - [ - ["chartbeat", "https://chartbeat.com"], - ["socrata", "https://www.socrata.com"], - ["chattermill", "https://chattermill.io"], - ["cytora", "http://www.cytora.com"], - ["signaln", "http://signaln.com"], - ["duedil", "https://www.duedil.com/"], - ["spyjack", "https://spyjack.io"] - ], - [ - ["keyreply", "https://keyreply.com/"], - ["dato", "https://dato.com"], - ["kip", "http://kipthis.com"], - ["wonderflow", "http://www.wonderflow.co"], - ["foxtype", "https://foxtype.com"] - ], - [ - ["synapsify", "http://www.gosynapsify.com"], - ["stitchfix", "https://www.stitchfix.com/"], - ["wayblazer", "http://wayblazer.com"] - ] + { + "chartbeat": "https://chartbeat.com", + "cytora": "http://www.cytora.com", + "duedil": "https://www.duedil.com", + "socrata": "https://www.socrata.com", + "indico": "https://indico.io", + "signaln": "http://signaln.com" + }, + { + "keyreply": "https://keyreply.com", + "dato": "https://dato.com", + "kip": "http://kipthis.com", + "wonderflow": "http://www.wonderflow.co", + "foxtype": "https://foxtype.com" + }, + { + "synapsify": "http://www.gosynapsify.com", + "stitchfix": "https://www.stitchfix.com", + "wayblazer": "http://wayblazer.com", + "chattermill": "https://chattermill.io" + } ] }, @@ -32,28 +32,10 @@ "404": { "title": "404 Error", - "asides": false + "landing": true }, - "styleguide": { - "title" : "Styleguide", - "asides": true, - - "sidebar": { - "About": [ - ["Introduction", "#section-introduction", "introduction"] - ], - "Design": [ - ["Colors", "#section-colors", "colors"], - ["Logo", "#section-logo", "logo"], - ["Typography", "#section-typography", "typography"], - ["Grid", "#section-grid", "grid"], - ["Elements", "#section-elements", "elements"], - ["Components", "#section-components", "components"] - ], - "Code": [ - ["Source", "#section-source", "source"] - ] - } + "announcement" : { + "title": "Important Announcement" } } diff --git a/website/_harp.json b/website/_harp.json index 753351b46..80a9ebc37 100644 --- a/website/_harp.json +++ b/website/_harp.json @@ -1,10 +1,10 @@ { "globals": { - "title": "spaCy.io", + "title": "spaCy", "description": "spaCy is a free open-source library featuring state-of-the-art speed and accuracy and a powerful Python API.", "SITENAME": "spaCy", - "SLOGAN": "Industrial-strength Natural Language Processing", + "SLOGAN": "Industrial-strength Natural Language Processing in Python", "SITE_URL": "https://spacy.io", "EMAIL": "contact@explosion.ai", @@ -12,6 +12,8 @@ "COMPANY_URL": "https://explosion.ai", "DEMOS_URL": "https://demos.explosion.ai", + "SPACY_VERSION": "1.1", + "SOCIAL": { "twitter": "spacy_io", "github": "explosion", @@ -21,9 +23,39 @@ "SCRIPTS" : [ "main", "prism" ], "DEFAULT_SYNTAX" : "python", "ANALYTICS": "UA-58931649-1", + "MAILCHIMP": { + "user": "spacy.us12", + "id": "83b0498b1e7fa3c91ce68c3f1", + "list": "89ad33e698" + }, + + "NAVIGATION": { + "Home": "/", + "Docs": "/docs", + "Demos": "/docs/usage/showcase", + "Blog": "https://explosion.ai/blog" + }, + + "FOOTER": { + "spaCy": { + "Usage": "/docs/usage", + "API Reference": "/docs/api", + "Tutorials": "/docs/usage/tutorials", + "Showcase": "/docs/usage/showcase" + }, + "Support": { + "Issue Tracker": "https://github.com/explosion/spaCy/issues", + "StackOverflow": "http://stackoverflow.com/questions/tagged/spacy", + "Reddit usergroup": "https://www.reddit.com/r/spacynlp/", + "Gitter chat": "https://gitter.im/explosion/spaCy" + }, + "Connect": { + "Twitter": "https://twitter.com/spacy_io", + "GitHub": "https://github.com/explosion/spaCy", + "Blog": "https://explosion.ai/blog", + "Contact": "mailto:contact@explosion.ai" + } + } - "SPACY_VERSION": "1.0", - "SPACY_STARS": "2500", - "GITHUB": { "user": "explosion", "repo": "spacy" } } } diff --git a/website/_includes/_footer.jade b/website/_includes/_footer.jade index bd7688bfb..8f11c2c80 100644 --- a/website/_includes/_footer.jade +++ b/website/_includes/_footer.jade @@ -1,17 +1,30 @@ -//- ---------------------------------- //- 💫 INCLUDES > FOOTER -//- ---------------------------------- include _mixins -footer.o-footer.o-inline-list.u-pattern.u-text-center.u-text-label.u-text-strong - span © #{new Date().getFullYear()} #[+a(COMPANY_URL, true)=COMPANY] +footer.o-footer.u-text.u-border-dotted + +grid.o-content + each group, label in FOOTER + +grid-col("quarter") + ul + li.u-text-label.u-color-subtle=label - +a(COMPANY_URL + "/legal", true) Legal / Imprint - a(href="mailto:#{EMAIL}") #[+icon("mail", 16)] + each url, item in group + li + +a(url)(target=url.includes("http") ? "_blank" : "")=item - +a("https://twitter.com/" + SOCIAL.twitter)(aria-label="Twitter") - +icon("twitter", 20) + if SECTION != "docs" + +grid-col("quarter") + include _newsletter - +a("https://github.com/" + SOCIAL.github + "/spaCy")(aria-label="GitHub") - +icon("github", 20) + if SECTION == "docs" + .o-content.o-block.u-border-dotted + include _newsletter + + .o-inline-list.u-text-center.u-text-tiny.u-color-subtle + span © #{new Date().getFullYear()} #[+a(COMPANY_URL, true)=COMPANY] + + +a(COMPANY_URL, true) + +svg("graphics", "explosion", 45).o-icon.u-color-theme.u-grayscale + + +a(COMPANY_URL + "/legal", true) Legal / Imprint diff --git a/website/_includes/_functions.jade b/website/_includes/_functions.jade index a191b330d..754ae1a4f 100644 --- a/website/_includes/_functions.jade +++ b/website/_includes/_functions.jade @@ -1,6 +1,11 @@ -//- ---------------------------------- //- 💫 INCLUDES > FUNCTIONS -//- ---------------------------------- + +//- More descriptive variables for current.path and current.source + +- CURRENT = current.source +- SECTION = current.path[0] +- SUBSECTION = current.path[1] + //- Add prefixes to items of an array (for modifier CSS classes) @@ -9,3 +14,10 @@ - return prefix + '--' + arg; - }).join(' '); - } + + +//- Generate GitHub links + +- function gh(repo, filepath, branch) { +- return 'https://github.com/' + SOCIAL.github + '/' + repo + (filepath ? '/blob/' + (branch || 'master') + '/' + filepath : '' ); +- } diff --git a/website/_includes/_logo.jade b/website/_includes/_logo.jade deleted file mode 100644 index a315e681b..000000000 --- a/website/_includes/_logo.jade +++ /dev/null @@ -1,6 +0,0 @@ -//- ---------------------------------- -//- 💫 INCLUDES > LOGO -//- ---------------------------------- - -svg.o-logo(class=(logo_size) ? "o-logo--" + logo_size : "" viewBox="0 0 675 215" width="500") - path(d="M83.6 83.3C68.3 81.5 67.2 61 47.5 62.8c-9.5 0-18.4 4-18.4 12.7 0 13.2 20.3 14.4 32.5 17.7 20.9 6.3 41 10.7 41 33.3 0 28.8-22.6 38.8-52.4 38.8-24.9 0-50.2-8.9-50.2-31.8 0-6.4 6.1-11.3 12-11.3 7.5 0 10.1 3.2 12.7 8.4 5.8 10.2 12.3 15.6 28.3 15.6 10.2 0 20.6-3.9 20.6-12.7 0-12.6-12.8-15.3-26.1-18.4-23.5-6.6-43.6-10-46-36.1C-1 34.5 91.7 32.9 97 71.9c.1 7.1-6.5 11.4-13.4 11.4zm110.2-39c32.5 0 51 27.2 51 60.8 0 33.7-17.9 60.8-51 60.8-18.4 0-29.8-7.8-38.1-19.8v44.5c0 13.4-4.3 19.8-14.1 19.8-11.9 0-14.1-7.6-14.1-19.8V61.3c0-10.6 4.4-17 14.1-17 9.1 0 14.1 7.2 14.1 17v3.6c9.2-11.6 19.7-20.6 38.1-20.6zm-7.7 98.4c19.1 0 27.6-17.6 27.6-38.1 0-20.1-8.6-38.1-27.6-38.1-19.8 0-29 16.3-29 38.1 0 21.2 9.2 38.1 29 38.1zM266.9 76c0-23.4 26.9-31.7 52.9-31.7 36.6 0 51.7 10.7 51.7 46v34c0 8.1 5 24.1 5 29 0 7.4-6.8 12-14.1 12-8.1 0-14.1-9.5-18.4-16.3-11.9 9.5-24.5 16.3-43.8 16.3-21.3 0-38.1-12.6-38.1-33.3 0-18.4 13.2-28.9 29-32.5 0 .1 51-12 51-12.1 0-15.7-5.5-22.6-22-22.6-14.5 0-21.9 4-27.5 12.7-4.5 6.6-4 10.6-12.7 10.6-6.9-.1-13-4.9-13-12.1zm43.6 70.2c22.3 0 31.8-11.8 31.8-35.3v-5c-6 2-30.3 8-36.8 9.1-7 1.4-14.1 6.6-14.1 14.9.1 9.1 9.4 16.3 19.1 16.3zM474.5 0c31.5 0 65.7 18.8 65.7 48.8 0 7.7-5.8 14.1-13.4 14.1-10.3 0-11.8-5.5-16.3-13.4-7.6-13.9-16.5-23.3-36.1-23.3-30.2-.2-43.7 25.6-43.7 57.8 0 32.4 11.2 55.8 42.4 55.8 20.7 0 32.2-12 38.1-27.6 2.4-7.1 6.7-14.1 15.6-14.1 7 0 14.1 7.2 14.1 14.8 0 31.8-32.4 53.8-65.8 53.8-36.5 0-57.2-15.4-68.5-41-5.5-12.2-9.1-24.9-9.1-42.4-.1-49.2 28.6-83.3 77-83.3zm180.3 44.3c8 0 12.7 5.2 12.7 13.4 0 3.3-2.6 9.9-3.6 13.4L625.1 173c-8.6 22.1-15.1 37.4-44.5 37.4-14 0-26.1-1.2-26.1-13.4 0-7 5.3-10.6 12.7-10.6 1.4 0 3.6.7 5 .7 2.1 0 3.6.7 5 .7 14.7 0 16.8-15.1 22-25.5l-37.4-92.6c-2.1-5-3.6-8.4-3.6-11.3 0-8.2 6.4-14.1 14.8-14.1 9.5 0 13.3 7.5 15.6 15.6l24.7 73.5L638 65.5c3.9-10.5 4.2-21.2 16.8-21.2z") diff --git a/website/_includes/_mixins-base.jade b/website/_includes/_mixins-base.jade new file mode 100644 index 000000000..27f195690 --- /dev/null +++ b/website/_includes/_mixins-base.jade @@ -0,0 +1,102 @@ +//- 💫 MIXINS > BASE + +//- Aside wrapper + +mixin aside-wrapper(label) + aside.c-aside + .c-aside__content(role="complementary")&attributes(attributes) + if label + h4.u-text-label.u-text-label--dark=label + + block + +//- Date + input - [string] date in the format YYYY-MM-DD + +mixin date(input) + - var date = new Date(input) + - var months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] + + time(datetime=JSON.parse(JSON.stringify(date)))&attributes(attributes)=months[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear() + + +//- SVG from map + +mixin svg(file, name, width, height) + svg(aria-hidden="true" viewBox="0 0 #{width} #{height || width}" width=width height=(height || width))&attributes(attributes) + use(xlink:href="/assets/img/#{file}.svg##{name}") + + +//- Icon + +mixin icon(name, size) + +svg("icons", "icon-" + name, size || 20).o-icon&attributes(attributes) + + +//- Pro/Con/Neutral icon + +mixin procon(icon) + - colors = { pro: "green", con: "red" } + +icon(icon)(class="u-color-#{colors[icon] || 'subtle'}" aria-label=icon)&attributes(attributes) + + +//- Headlines Helper Mixin + +mixin headline(level) + if level == 1 + h1.u-heading-1&attributes(attributes) + block + + else if level == 2 + h2.u-heading-2&attributes(attributes) + block + + else if level == 3 + h3.u-heading-3&attributes(attributes) + block + + else if level == 4 + h4.u-heading-4&attributes(attributes) + block + + else if level == 5 + h5.u-heading-5&attributes(attributes) + block + + +//- Permalink rendering + +mixin permalink(id) + if id + a.u-permalink(id=id href="##{id}") + +icon("anchor").u-permalink__icon + block + + else + block + + +//- Terminal-style code window + +mixin terminal(label) + .x-terminal + .x-terminal__icons: span + .u-padding-small.u-text-label.u-text-center=label + + +code.x-terminal__code + block + + +//- Logo + +mixin logo() + +svg("graphics", "spacy", 500).o-logo&attributes(attributes) + + +//- Landing + +mixin landing-header() + header.c-landing + .c-landing__wrapper + .c-landing__content + block diff --git a/website/_includes/_mixins.jade b/website/_includes/_mixins.jade index 04faf8993..4d047c91e 100644 --- a/website/_includes/_mixins.jade +++ b/website/_includes/_mixins.jade @@ -1,9 +1,255 @@ -//- ---------------------------------- //- 💫 INCLUDES > MIXINS -//- ---------------------------------- include _functions +include _mixins-base -include _mixins/_base -include _mixins/_components -include _mixins/_headlines + +//- Headlines + level - [integer] headline level, corresponds to h1, h2, h3 etc. + id - [string] unique identifier, creates permalink (optional) + +mixin h(level, id) + +headline(level).u-heading&attributes(attributes) + +permalink(id) + block + + +//- External links + url - [string] link href + trusted - [boolean] if not set / false, rel="noopener nofollow" is added + info: https://mathiasbynens.github.io/rel-noopener/ + +mixin a(url, trusted) + a(href=url target="_blank" rel=(!trusted) ? "noopener nofollow" : "")&attributes(attributes) + block + +//- Source link (with added icon for "code") + url - [string] link href, can also be gh() function to generate GitHub link + see _functions.jade for more info + +mixin src(url) + +a(url) + block + + | #[+icon("code", 16).u-color-subtle] + + +//- API link (with added tag and automatically generated path) + path - [string] path to API docs page relative to /docs/api/ + +mixin api(path) + +a("/docs/api/" + path, true)(target="_self").u-no-border.u-inline-block + block + + | #[+icon("book", 18).o-help-icon.u-color-subtle] + + +//- Aside for text + label - [string] aside title (optional) + +mixin aside(label) + +aside-wrapper(label) + .c-aside__text.u-text-small + block + + +//- Aside for code + label - [string] aside title (optional or false for no label) + language - [string] language for syntax highlighting (default: "python") + supports basic relevant languages available for PrismJS + +mixin aside-code(label, language) + +aside-wrapper(label) + +code(false, language).o-no-block + block + + +//- Link button + url - [string] link href + trusted - [boolean] if not set / false, rel="noopener nofollow" is added + info: https://mathiasbynens.github.io/rel-noopener/ + ...style - all other arguments are added as class names c-button--argument + see assets/css/_components/_buttons.sass + +mixin button(url, trusted, ...style) + a.c-button.u-text-label(href=url class=prefixArgs(style, "c-button") role="button" target="_blank" rel=(!trusted) ? "noopener nofollow" : "")&attributes(attributes) + block + + +//- Code block + label - [string] aside title (optional or false for no label) + language - [string] language for syntax highlighting (default: "python") + supports basic relevant languages available for PrismJS + +mixin code(label, language) + pre.c-code-block.o-block(class="lang-#{(language || DEFAULT_SYNTAX)}")&attributes(attributes) + if label + h4.u-text-label.u-text-label--dark=label + + code.c-code-block__content + block + + +//- Images / figures + url - [string] url or path to image + width - [integer] image width in px, for better rendering (default: 500) + caption - [string] image caption + alt - [string] alternative image text, defaults to caption + +mixin image(url, width, caption, alt) + figure.o-block&attributes(attributes) + img(src=url alt=(alt || caption) width="#{width || 500}") + + if caption + +image-caption=caption + + else + block + +//- Image caption + +mixin image-caption() + figcaption.u-text-small.u-color-subtle.u-padding-small&attributes(attributes) + block + + +//- Label + +mixin label() + .u-text-label.u-color-subtle&attributes(attributes) + block + + +//- Tag + +mixin tag() + span.u-text-tag.u-text-tag--spaced(aria-hidden="true") + block + + +//- List + type - [string] "numbers", "letters", "roman" (bulleted list if none set) + start - [integer] start number + +mixin list(type, start) + if type + ol.c-list.o-block.u-text(class="c-list--#{type}" style=(start === 0 || start) ? "counter-reset: li #{(start - 1)}" : "")&attributes(attributes) + block + + else + ul.c-list.c-list--bullets.o-block.u-text&attributes(attributes) + block + + +//- List item (only used within +list) + +mixin item(procon) + if procon + li&attributes(attributes) + +procon(procon).c-list__icon + block + + else + li.c-list__item&attributes(attributes) + block + + +//- Table + head - [array] table headings (should match number of columns) + +mixin table(head) + table.c-table.o-block&attributes(attributes) + + if head + +row + each column in head + th.c-table__head-cell.u-text-label=column + + block + + +//- Table row (only used within +table) + +mixin row() + tr.c-table__row&attributes(attributes) + block + + +//- Footer table row (only ued within +table) + +mixin footrow() + tr.c-table__row.c-table__row--foot&attributes(attributes) + block + + +//- Table cell (only used within +row in +table) + +mixin cell() + td.c-table__cell.u-text&attributes(attributes) + block + + +//- Grid Container + +mixin grid() + .o-grid.o-block&attributes(attributes) + block + + +//- Grid Column (only used within +grid) + width - [string] "quarter", "third", "half", "two-thirds", "three-quarters" + see $grid in assets/css/_variables.sass + +mixin grid-col(width) + .o-grid__col(class="o-grid__col--#{width}")&attributes(attributes) + block + + +//- Card (only used within +grid) + title - [string] card title + details - [object] url, image, author, description, tags etc. + (see /docs/usage/_data.json) + +mixin card(title, details) + +grid-col("half").u-border.u-padding-medium.u-text&attributes(attributes) + if details.image + +a(details.url).o-block-small + img(src=details.image alt=title width="300" role="presentation") + + if title + +a(details.url) + +h(3)=title + + if details.author + .u-text-small.u-color-subtle by #{details.author} + + if details.description || details.tags + ul + if details.description + li=details.description + + if details.tags + li + each tag in details.tags + span.u-text-tag #{tag} + |   + + block + + +//- Simpler card list item (only used within +list) + title - [string] card title + details - [object] url, image, author, description, tags etc. + (see /docs/usage/_data.json) + +mixin card-item(title, details) + +item&attributes(attributes) + +a(details.url)=title + + if details.description + br + span=details.description + + if details.author + br + span.u-text-small.u-color-subtle by #{details.author} diff --git a/website/_includes/_mixins/_base.jade b/website/_includes/_mixins/_base.jade deleted file mode 100644 index 4d8d7c571..000000000 --- a/website/_includes/_mixins/_base.jade +++ /dev/null @@ -1,42 +0,0 @@ -//- ---------------------------------- -//- 💫 MIXINS > BASE -//- ---------------------------------- - -//- External Link - -mixin a(url, trusted) - a(href=url target="_blank" rel=(!trusted) ? "noopener nofollow" : "")&attributes(attributes) - block - - -//- Sections for content pages - id - [string] id, can be headline id as it's being prefixed (optional) - block - section content (block and inline elements) - -mixin section(id) - section.o-section(id=(id) ? 'section-' + id : '')&attributes(attributes) - block - - -//- Date - input - [string] date in the format YYYY-MM-DD - -mixin date(input) - - var date = new Date(input) - - var months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] - - time(datetime=JSON.parse(JSON.stringify(date)))&attributes(attributes)=months[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear() - - -//- Grid Container - -mixin grid(...style) - .o-grid.o-block(class=prefixArgs(style, "o-grid"))&attributes(attributes) - block - - -//- Grid Column - -mixin grid-col(...style) - .o-grid__col(class=prefixArgs(style, "o-grid__col"))&attributes(attributes) - block diff --git a/website/_includes/_mixins/_components.jade b/website/_includes/_mixins/_components.jade deleted file mode 100644 index c7deffe67..000000000 --- a/website/_includes/_mixins/_components.jade +++ /dev/null @@ -1,112 +0,0 @@ -//- ---------------------------------- -//- 💫 MIXINS > COMPONENTS -//- ---------------------------------- - -//- Aside - -mixin aside(label) - span.c-aside.u-text-small(role="complementary")&attributes(attributes) - span.c-aside__label.u-text-label.u-text-strong.u-color-theme=label - block - - -//- Button - -mixin button(url, trusted, ...style) - a.c-button.u-text-label(href=url class=prefixArgs(style, "c-button") role="button" target="_blank" rel=(!trusted) ? "noopener nofollow" : "")&attributes(attributes) - block - - -//- Code - -mixin code(language, label, small) - pre.c-code-block(class="lang-#{(language || DEFAULT_SYNTAX)} #{small ? '' : 'o-block'}")&attributes(attributes) - if label - span.c-code-block__label.u-text-label.u-text-strong=label - - code.c-code-block__content(class=small ? "u-code-small" : "u-code-regular") - block - - -//- Icon - -mixin icon(name, size) - - var size = size || 20 - - svg.o-icon(aria-hidden="true" viewBox="0 0 #{size} #{size}" width=size height=size)&attributes(attributes) - use(xlink:href="/assets/img/icons.svg#icon-#{name}") - - -//- Image for illustration purposes - file - [string] file name (in /assets/img) - alt - [string] descriptive alt text (optional) - caption - [string] image caption (optional) - -mixin image(file, alt, caption) - figure.o-block&attributes(attributes) - img(src="/assets/img/#{file}" alt=(alt || caption) width="800") - - if caption - figcaption.u-text-small=caption - - block - - -//- Label - -mixin label() - .u-text-label.u-text-strong.u-color-theme&attributes(attributes) - block - - -//- List - -mixin list(type, start) - if type - ol.c-list.o-block(class="c-list--#{type}" style=(start === 0 || start) ? "counter-reset: li #{(start - 1)}" : "")&attributes(attributes) - block - - else - ul.c-list.c-list--bullets.o-block&attributes(attributes) - block - - -//- List item - -mixin item() - li.c-list__item.u-text-regular&attributes(attributes) - block - - -//- Table - -mixin table(head) - table.c-table.o-block.has-aside&attributes(attributes) - - if head - +row - each column in head - th.c-table__head-cell.u-text-label.u-text-strong=column - - block - - -//- Table row - -mixin row(...style) - tr.c-table__row(class=prefixArgs(style, "c-table__cell"))&attributes(attributes) - block - - -//- Table cell - -mixin cell(...style) - td.c-table__cell.u-text-regular.has-aside(class=prefixArgs(style, "c-table__cell"))&attributes(attributes) - block - - -//- Tag - -mixin tag() - span.u-text-tag.u-text-label.u-color-theme.u-text-strong.u-padding-small - block diff --git a/website/_includes/_mixins/_headlines.jade b/website/_includes/_mixins/_headlines.jade deleted file mode 100644 index 93396dca5..000000000 --- a/website/_includes/_mixins/_headlines.jade +++ /dev/null @@ -1,49 +0,0 @@ -//- ---------------------------------- -//- 💫 MIXINS > HEADLINES -//- ---------------------------------- - -//- Headlines Helper Mixin - -mixin headline(level) - if level == 1 - h1.u-heading-1&attributes(attributes) - block - - else if level == 2 - h2.u-heading-2&attributes(attributes) - block - - else if level == 3 - h3.u-heading-3&attributes(attributes) - block - - else if level == 4 - h4.u-heading-4&attributes(attributes) - block - - else if level == 5 - h5.u-heading-5&attributes(attributes) - block - - -//- Permalink rendering - -mixin permalink(id) - if id - a.u-permalink(id=id href="##{id}") - +icon("link").u-permalink__icon - block - - else - block - - -//- Headlines - -mixin h(level, id, source) - +headline(level)&attributes(attributes) - +permalink(id) - block - - if source - +button(source, false, "secondary").u-text-small.u-float-right Source diff --git a/website/_includes/_navigation.jade b/website/_includes/_navigation.jade index a4318d628..e2b18aa4b 100644 --- a/website/_includes/_navigation.jade +++ b/website/_includes/_navigation.jade @@ -1,26 +1,17 @@ -//- ---------------------------------- //- 💫 INCLUDES > TOP NAVIGATION -//- ---------------------------------- include _mixins -nav.c-nav.u-text-label.js-nav +nav.c-nav.u-text.js-nav(class=landing ? "c-nav--theme" : "") + a(href='/') #[+logo] - a(href='/') - !=partial("_includes/_logo", { logo_size: 'small' }) + if SUBSECTION != "index" + .u-text-label.u-padding-small=SUBSECTION ul.c-nav__menu - li.c-nav__menu__item(class=(current.path[0] == 'index') ? "is-active" : "") - a(href='/') Home - - li.c-nav__menu__item(class=(current.path[0] == 'docs') ? "is-active" : "") - a(href="/docs") Docs + each url, item in NAVIGATION + li.c-nav__menu__item + a(href=url target=url.includes("http") ? "_blank" : "")=item li.c-nav__menu__item - a(href="https://demos.explosion.ai" target="_blank") Demos - - li.c-nav__menu__item - a(href="https://explosion.ai/blog" target="_blank") Blog - - li.c-nav__menu__item - a(href="https://github.com/" + SOCIAL.github + "/spaCy" target="_blank") #[+icon("github", 18)] #[span.u-hidden-sm GitHub] + +a(gh("spaCy"))(aria-label="GitHub").u-hidden-xs #[+icon("github", 20)] diff --git a/website/_includes/_newsletter.jade b/website/_includes/_newsletter.jade index 80dc01c22..9bfe88d39 100644 --- a/website/_includes/_newsletter.jade +++ b/website/_includes/_newsletter.jade @@ -1,20 +1,16 @@ -//- ---------------------------------- -//- 💫 INCLUDES > NEWSLETTER SIGNUP -//- ---------------------------------- +//- 💫 INCLUDES > NEWSLETTER -include _mixins +ul.o-block + li.u-text-label.u-color-subtle Stay in the loop! + li Receive updates about new releases, tutorials and more. -.o-block.u-text-center.u-padding.u-border-top +form.o-grid#mc-embedded-subscribe-form(action="//#{MAILCHIMP.user}.list-manage.com/subscribe/post?u=#{MAILCHIMP.id}&id=#{MAILCHIMP.list}" method="post" name="mc-embedded-subscribe-form" target="_blank" novalidate) - +label Sign up for the spaCy newsletter - h3.u-heading-1 Stay in the loop! - p.u-text-large Receive updates about new releases, tutorials and more. + //- MailChimp spam protection + div(style="position: absolute; left: -5000px;" aria-hidden="true") + input(type="text" name="b_#{MAILCHIMP.id}_#{MAILCHIMP.list}" tabindex="-1" value="") - form#mc-embedded-subscribe-form.o-inline-list(action="https://spacy.us12.list-manage.com/subscribe/post?u=83b0498b1e7fa3c91ce68c3f1&id=89ad33e698" method="post" name="mc-embedded-subscribe-form" target="_blank" novalidate) - input#mce-EMAIL.u-border.u-padding-small.u-text-regular(type="email" name="EMAIL" placeholder="Your email address") + .o-grid-col.u-border.u-padding-small + input#mce-EMAIL.u-text(type="email" name="EMAIL" placeholder="Your email") - //- Spam bot protection - div(style="position: absolute; left: -5000px;" aria-hidden="true") - input(type="text" name="b_83b0498b1e7fa3c91ce68c3f1_89ad33e698" tabindex="-1" value="") - - button#mc-embedded-subscribe.c-button.c-button--primary.u-text-label(type="submit" name="subscribe") Sign up + button#mc-embedded-subscribe.u-text-label.u-color-theme(type="submit" name="subscribe") Sign up diff --git a/website/_includes/_page-docs.jade b/website/_includes/_page-docs.jade new file mode 100644 index 000000000..44a5698f0 --- /dev/null +++ b/website/_includes/_page-docs.jade @@ -0,0 +1,27 @@ +//- 💫 INCLUDES > DOCS PAGE TEMPLATE + +- sidebar_content = (SUBSECTION != "index") ? public.docs[SUBSECTION]._data.sidebar : public.docs._data.sidebar || FOOTER + +include _sidebar + +main.o-main.o-main--sidebar.o-main--aside + article.o-content + +h(1)=title + if tag + +tag=tag + + !=yield + + +grid.o-content.u-text + +grid-col("half") + if next && public.docs[SUBSECTION]._data[next] + - data = public.docs[SUBSECTION]._data[next] + + .o-inline-list + span #[strong.u-text-label Read next:] #[a(href=next).u-link=data.title] + + +grid-col("half").u-text-right + .o-inline-list + +button(gh("spacy", "website/" + current.path.join('/') + ".jade"), false, "secondary").u-text-tag Suggest edits #[+icon("code", 14)] + + include _footer diff --git a/website/_includes/_scripts.jade b/website/_includes/_scripts.jade deleted file mode 100644 index 839cd39f9..000000000 --- a/website/_includes/_scripts.jade +++ /dev/null @@ -1,14 +0,0 @@ -//- ---------------------------------- -//- 💫 INCLUDES > SCRIPTS -//- ---------------------------------- - -each script in SCRIPTS - script(src="/assets/js/" + script + ".js", type="text/javascript") - -if landing - script(async src="https://platform.twitter.com/widgets.js" charset="utf-8") - -if environment == "deploy" - script window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date; ga('create', '#{ANALYTICS}', 'auto'); ga('send', 'pageview'); - - script(async src="https://www.google-analytics.com/analytics.js") diff --git a/website/_includes/_sidebar.jade b/website/_includes/_sidebar.jade index 051ca28e1..fb695e369 100644 --- a/website/_includes/_sidebar.jade +++ b/website/_includes/_sidebar.jade @@ -1,13 +1,13 @@ -//- ---------------------------------- //- 💫 INCLUDES > SIDEBAR -//- ---------------------------------- include _mixins -nav.c-sidebar.js-sidebar - .c-sidebar__body.u-text-regular - each items, menu in sidebar - ul.o-block-small +menu.c-sidebar.js-sidebar.u-text + if sidebar_content + each items, menu in sidebar_content + ul.c-sidebar__section.o-block li.u-text-label.u-color-subtle=menu - each item in items - li: a(href=item[1] data-section=(item[2]) ? "section-" + item[2] : "")=item[0] + + each url, item in items + li(class=(CURRENT == url || (CURRENT == "index" && url == "./")) ? "is-active" : "") + +a(url)(target=url.includes("http") ? "_blank" : "")=item diff --git a/website/_layout.jade b/website/_layout.jade index 1f6890473..0a3de88ad 100644 --- a/website/_layout.jade +++ b/website/_layout.jade @@ -1,13 +1,19 @@ -//- ---------------------------------- //- 💫 GLOBAL LAYOUT -//- ---------------------------------- include _includes/_mixins doctype html html(lang="en") - title=(current.path[0] == "index") ? SITENAME + " | " + SLOGAN : title + " | " + SITENAME + title + if SECTION == "docs" && SUBSECTION && SUBSECTION != "index" + | #{title} | #{SITENAME} #{SUBSECTION == "api" ? "API" : "Usage"} Documentation + + else if SECTION != "index" + | #{title} | #{SITENAME} + + else + | #{SITENAME} - #{SLOGAN} meta(charset="utf-8") meta(name="viewport" content="width=device-width, initial-scale=1.0") @@ -19,41 +25,40 @@ html(lang="en") meta(property="og:url" content="#{SITE_URL}/#{current.path.join('/')}") meta(property="og:title" content=title) meta(property="og:description" content=description) - meta(property="og:image" content="/assets/img/social.png") + meta(property="og:image" content="#{SITE_URL}/assets/img/social#{(SECTION == 'docs') ? '_docs' : ''}.jpg") meta(name="twitter:card" content="summary_large_image") meta(name="twitter:site" content="@" + SOCIAL.twitter) meta(name="twitter:title" content=title) meta(name="twitter:description" content=description) - meta(name="twitter:image" content="/assets/img/social.jpg") + meta(name="twitter:image" content="#{SITE_URL}/assets/img/social#{(SECTION == 'docs') ? '_docs' : ''}.jpg") link(rel="shortcut icon" href="/assets/img/favicon.ico") link(rel="icon" type="image/x-icon" href="/assets/img/favicon.ico") - link(href="/assets/css/style.css" rel="stylesheet") + + if SUBSECTION == "usage" + link(href="/assets/css/style_red.css?v1" rel="stylesheet") + + else + link(href="/assets/css/style.css?v1" rel="stylesheet") body include _includes/_navigation - if !landing - header.o-header.u-pattern.u-text-center - if current.path[1] == "tutorials" - h2.u-heading-1.u-text-shadow Tutorials - - else - +h(1).u-text-shadow=title - - if sidebar - include _includes/_sidebar - - main.o-content(class="#{(sidebar) ? 'o-content--sidebar' : '' } #{((current.path[0] == 'docs' && asides != false) || asides) ? 'o-content--asides' : '' } #{(current.path[1] == 'tutorials') ? 'o-content--article' : '' }") - if current.path[1] == "tutorials" - +h(1)=title - - !=yield + if SECTION == "docs" + include _includes/_page-docs else - !=yield + main!=yield + include _includes/_footer - include _includes/_footer + each script in SCRIPTS + script(src="/assets/js/" + script + ".js?v1", type="text/javascript") - include _includes/_scripts + if environment == "deploy" + script + | window.ga=window.ga||function(){ + | (ga.q=ga.q||[]).push(arguments)}; ga.l=+new Date; + | ga('create', '#{ANALYTICS}', 'auto'); ga('send', 'pageview'); + + script(async src="https://www.google-analytics.com/analytics.js") diff --git a/website/announcement.jade b/website/announcement.jade new file mode 100644 index 000000000..5ea9866be --- /dev/null +++ b/website/announcement.jade @@ -0,0 +1,14 @@ +//- 💫 SPACY ANNOUNCEMENT FROM 2016-08-09 (needs to stay for reference) + +include _includes/_mixins + +.o-content.u-padding + +h(1) + +label #[+date("2016-08-09")] + | Dear spaCy users, + + p Unfortunately, we (Henning Peters and Matthew Honnibal) are parting ways. Breaking up is never easy, and it's taken us a while to get our stuff together. Hopefully, you didn't notice anything was up — if you did, we hope you haven't been inconvenienced. + + p Here's how this is going to work: Matt will continue to develop and maintain spaCy and all related projects under his name. Nothing will change for you. Henning will take over our legal structure and start a new business under a new name. + + p Sincerely,#[br] Henning Peters and Matthew Honnibal diff --git a/website/assets/css/_base/_animations.sass b/website/assets/css/_base/_animations.sass index 9812f904b..376ac5c2f 100644 --- a/website/assets/css/_base/_animations.sass +++ b/website/assets/css/_base/_animations.sass @@ -1,6 +1,4 @@ -//- ---------------------------------- -//- 💫 BASE > ANIMATIONS -//- ---------------------------------- +//- 💫 CSS > BASE > ANIMATIONS //- Fade in diff --git a/website/assets/css/_base/_fonts.sass b/website/assets/css/_base/_fonts.sass index cef2cc4f6..72aaf97f8 100644 --- a/website/assets/css/_base/_fonts.sass +++ b/website/assets/css/_base/_fonts.sass @@ -1,6 +1,4 @@ -//- ---------------------------------- -//- 💫 BASE > FONTS -//- ---------------------------------- +//- 💫 CSS > BASE > FONTS // Source Sans Pro diff --git a/website/assets/css/_base/_grid.sass b/website/assets/css/_base/_grid.sass index 06e72ef63..35e570c2d 100644 --- a/website/assets/css/_base/_grid.sass +++ b/website/assets/css/_base/_grid.sass @@ -1,6 +1,4 @@ -//- ---------------------------------- -//- 💫 BASE > GRID -//- ---------------------------------- +//- 💫 CSS > BASE > GRID //- Grid container diff --git a/website/assets/css/_base/_layout.sass b/website/assets/css/_base/_layout.sass index 276117169..bb5e82e62 100644 --- a/website/assets/css/_base/_layout.sass +++ b/website/assets/css/_base/_layout.sass @@ -1,21 +1,14 @@ -//- ---------------------------------- -//- 💫 BASE > LAYOUT -//- ---------------------------------- +//- 💫 CSS > BASE > LAYOUT //- HTML html - @include breakpoint(min, lg) - font-size: $type-base + font-size: $type-base - @include breakpoint(max, md) - font-size: $type-base * 0.8 //- Body body - display: flex - flex-flow: row wrap animation: fadeIn 0.25s ease background: $color-back color: $color-front @@ -24,15 +17,12 @@ body //- Paragraphs p - @extend .o-block, .u-text-regular, .has-aside - - .o-content--article &:not([class]) - @extend .u-text-medium + @extend .o-block, .u-text //- Links -main p a, main table a, main li a, .c-aside a +main p a, main table a, main > *:not(footer) li a, .c-aside a @extend .u-link @@ -41,4 +31,3 @@ main p a, main table a, main li a, .c-aside a ::selection background: $color-theme color: $color-back - text-shadow: none diff --git a/website/assets/css/_base/_objects.sass b/website/assets/css/_base/_objects.sass index 87f265f40..6193801e8 100644 --- a/website/assets/css/_base/_objects.sass +++ b/website/assets/css/_base/_objects.sass @@ -1,67 +1,80 @@ -//- ---------------------------------- -//- 💫 BASE > OBJECTS -//- ---------------------------------- +//- 💫 CSS > BASE > OBJECTS -//- Containers +//- Main container -.o-content - flex: 1 1 auto - padding: $nav-height 4rem 8rem - width: $content-width - $aside-width +.o-main + padding: $nav-height 0 0 0 max-width: 100% + min-height: 100vh @include breakpoint(min, md) - &.o-content--asides - padding-left: 5rem - padding-right: $aside-width + $aside-padding * 2 + &.o-main--sidebar + margin-left: $sidebar-width -//- Header + &.o-main--aside + margin-right: $aside-width + position: relative -.o-header - display: flex - justify-content: center - flex-flow: column nowrap - padding: 3rem 5rem - margin-top: $nav-height - width: 100% - min-height: 250px + &:after + @include position(absolute, top, left, 0, 100%) + @include size($aside-width, 100%) + content: "" + display: block + background: $pattern + z-index: -1 + min-height: 100vh + + +//- Content container + +.o-content + padding: 3rem 7.5rem + margin: 0 auto + width: $content-width + max-width: 100% + + @include breakpoint(max, sm) + padding: 3rem //- Footer .o-footer position: relative - padding: 5rem 0 + padding: 2.5rem 0 overflow: auto - width: 100% - z-index: 200 //- Blocks .o-block - margin-bottom: 5rem + margin-bottom: 3rem .o-block-small margin-bottom: 2rem -.o-section - margin-bottom: 12.5rem +.o-no-block + margin-bottom: 0 -.o-responsive - overflow: auto - width: 100% - max-width: 100% +.o-card + background: $color-back + border-radius: 2px + + +//- Icons .o-icon vertical-align: middle +.o-help-icon + cursor: help + margin: 0 0.5rem 0 0.25rem + //- Inline List .o-inline-list > * display: inline - margin-bottom: 3rem &:not(:last-child) margin-right: 3rem @@ -70,9 +83,7 @@ //- Logo .o-logo - @include size(100%, auto) + @include size($logo-width, auto) fill: currentColor - - @each $name, $size in $logo-sizes - &.o-logo--#{$name} - width: $size + vertical-align: middle + margin: 0 0.5rem diff --git a/website/assets/css/_base/_reset.sass b/website/assets/css/_base/_reset.sass index 33895f460..1d9d9ffbe 100644 --- a/website/assets/css/_base/_reset.sass +++ b/website/assets/css/_base/_reset.sass @@ -1,9 +1,4 @@ -//- ---------------------------------- -//- 💥 BASE > RESET -//- ---------------------------------- - -//- adapted from "normalize.css" by Nicolas Gallagher & Jonathan Neal -//- https://github.com/necolas/normalize.css +//- 💫 CSS > BASE > RESET * box-sizing: border-box @@ -11,12 +6,14 @@ margin: 0 border: 0 outline: 0 - -webkit-font-smoothing: antialiased html font-family: sans-serif + text-rendering: optimizeSpeed -ms-text-size-adjust: 100% -webkit-text-size-adjust: 100% + -webkit-font-smoothing: antialiased + -moz-osx-font-smoothing: grayscale body margin: 0 @@ -64,6 +61,7 @@ img max-width: 100% svg + max-width: 100% color-interpolation-filters: sRGB fill: currentColor @@ -88,17 +86,15 @@ table max-width: 100% border-collapse: collapse - td, - th + td, th vertical-align: top -ul, -ol +ul, ol list-style: none -input, -button +input, button appearance: none button + background: transparent cursor: pointer diff --git a/website/assets/css/_base/_utilities.sass b/website/assets/css/_base/_utilities.sass index c51b0dfcc..dfe514e80 100644 --- a/website/assets/css/_base/_utilities.sass +++ b/website/assets/css/_base/_utilities.sass @@ -1,80 +1,84 @@ -//- ---------------------------------- -//- 💫 BASE > UTILITIES -//- ---------------------------------- +//- 💫 CSS > BASE > UTILITIES //- Text -%text - font-family: $font-primary - line-height: 1.5 - -.u-text-regular - @extend %text - font-size: 1.6rem - -.u-text-medium - @extend %text - font-size: 2rem +.u-text + font: 1.5rem/#{1.55} $font-primary .u-text-small - @extend %text - font-size: 1.2rem + font: 1.4rem/#{1.375} $font-primary -.u-text-large - @extend %text - font-size: 2.8rem +.u-text-tiny + font: 1.1rem/#{1.375} $font-primary + + +//- Labels & Tags .u-text-label - @extend %text - font-size: 1.4rem - font-weight: normal + font: normal 600 1.4rem/#{1.5} $font-code text-transform: uppercase -.u-text-strong - font-weight: bold + &.u-text-label--dark + display: inline-block + background: $color-dark + box-shadow: inset 1px 1px 1px rgba($color-front, 0.25) + color: $color-back + padding: 0 0.75rem + margin: 1.5rem 0 0 2rem + border-radius: 2px -.u-code-regular - font: normal normal 1.3rem/#{2} $font-code +.u-text-tag + display: inline-block + font: 600 1.1rem/#{1} $font-code + background: $color-theme + color: $color-back + padding: 0.15em 0.25em + border-radius: 2px + text-transform: uppercase + vertical-align: middle -.u-code-small - font: normal normal 0.85em $font-code - line-height: inherit - -.u-link - color: $color-theme - border-bottom: 1px solid + &.u-text-tag--spaced + margin-left: 0.75em //- Headings +.u-heading + margin-bottom: 2rem + + @include breakpoint(max, md) + word-wrap: break-word + + &:not(:first-child) + padding-top: 3.5rem + .u-heading-0 font: normal bold 7rem/#{1} $font-primary -@each $level, $size in (1: 5.5, 2: 3, 3: 2.6, 4: 2, 5: 1.8) +@each $level, $size in $headings .u-heading-#{$level} font: normal bold #{$size}rem/#{1.25} $font-primary - margin-bottom: 2rem - -.u-heading-label - @extend .u-text-label - margin-bottom: 1rem -//- Permalinks +//- Links + +.u-link + color: $color-theme + border-bottom: 1px solid .u-permalink position: relative &:target display: inline-block - padding-top: $nav-height * 1.5 + padding-top: $nav-height * 1.25 & + * - margin-top: $nav-height * 1.5 + margin-top: $nav-height * 1.25 .u-permalink__icon - @include position(absolute, bottom, left, 0.25em, -3.25rem) - @include size(2rem) + @include position(absolute, bottom, left, 0.35em, -2.75rem) + @include size(1.5rem) color: $color-subtle .u-permalink:hover & @@ -89,46 +93,56 @@ .u-text-center text-align: center -.u-float-right - float: right +.u-text-right + text-align: right + +.u-padding + padding: 5rem .u-padding-small padding: 0.5em 0.75em .u-padding-medium - padding: 2rem + padding: 2.5rem -.u-padding - padding: 5rem +.u-inline-block + display: inline-block + +.u-no-border + border: none .u-border border: 1px solid $color-subtle - border-radius: 3px - -.u-border-top - border-top: 1px solid $color-subtle + border-radius: 2px .u-border-bottom - border-bottom: 1px solid $color-subtle + border: 1px solid $color-subtle -.u-color-theme - color: $color-theme +.u-border-dotted + border-top: 1px dotted $color-subtle -.u-color-subtle - color: $color-subtle-dark +@each $name, $color in (theme: $color-theme, subtle: $color-subtle-dark, light: $color-back, red: $color-red, green: $color-green, yellow: $color-yellow) + .u-color-#{$name} + color: $color -.u-text-shadow - text-shadow: 2px 2px $color-theme-dark +.u-grayscale + filter: grayscale(100%) + transition: filter 0.15s ease + user-select: none + + &:hover + filter: none .u-pattern - background: $color-theme url("/assets/img/pattern.jpg") - color: $color-back + background: $pattern +//- Hidden elements + .u-hidden display: none -@each $breakpoint in (sm, md) - .u-hidden-#{$breakpoint} +@each $breakpoint in (xs, sm, md) + .u-hidden-#{$breakpoint}.u-hidden-#{$breakpoint} @include breakpoint(max, $breakpoint) display: none diff --git a/website/assets/css/_components/_asides.sass b/website/assets/css/_components/_asides.sass index 0f57eaacc..d5b5c64e3 100644 --- a/website/assets/css/_components/_asides.sass +++ b/website/assets/css/_components/_asides.sass @@ -1,37 +1,41 @@ -//- ---------------------------------- -//- 💫 COMPONENTS > ASIDES -//- ---------------------------------- +//- 💫 CSS > COMPONENTS > ASIDES -//- Aside +//- Aside container .c-aside - @include breakpoint(min, md) - @include position(absolute, top, left, 0, calc(100% + #{$aside-padding})) - border-left: 1px solid $color-subtle - opacity: 0.5 - transition: opacity 0.25s ease - padding: 0 $aside-padding - width: $aside-width + position: relative - &:hover - opacity: 1 + +//- Aside content + +.c-aside__content + background: $color-front + z-index: 10 + + @include breakpoint(min, md) + @include position(absolute, top, left, -3rem, calc(100% + 5.5rem)) + width: calc(#{$aside-width} + 2rem) + + // Banner effect + + &:after + $triangle-size: 2rem + + @include position(absolute, bottom, left, -$triangle-size / 2, 0) + @include size(0) + border-color: transparent + border-style: solid + border-top-color: $color-dark + border-width: $triangle-size / 2 0 0 $triangle-size + content: "" @include breakpoint(max, sm) display: block - margin: type(5) 0 + margin: 2rem 0 -//- Aside label +//- Aside text -.c-aside__label - display: block - margin-bottom: 1rem - - -// Aside container - -.has-aside - position: relative - - &:hover > .c-aside - opacity: 1 +.c-aside__text + color: $color-back + padding: 1.5rem 2.5rem 3rem 2rem diff --git a/website/assets/css/_components/_buttons.sass b/website/assets/css/_components/_buttons.sass index a8c3cf11b..647723380 100644 --- a/website/assets/css/_components/_buttons.sass +++ b/website/assets/css/_components/_buttons.sass @@ -1,23 +1,23 @@ -//- ---------------------------------- -//- 💫 COMPONENTS > BUTTONS -//- ---------------------------------- +//- 💫 CSS > COMPONENTS > BUTTONS .c-button display: inline-block font-weight: bold - padding: 0.5em 0.75em + padding: 0.75em 1em border: 2px solid - border-radius: 3px - transition: opacity 0.25s ease - - &:hover - opacity: 0.8 + border-radius: 2px + text-align: center + transition: background 0.25s ease &.c-button--primary background: $color-theme color: $color-back border-color: $color-theme + &:hover + background: $color-theme-dark + border-color: $color-theme-dark + &.c-button--secondary background: $color-back color: $color-theme diff --git a/website/assets/css/_components/_code.sass b/website/assets/css/_components/_code.sass index 73cd5e7c8..fc57618e3 100644 --- a/website/assets/css/_components/_code.sass +++ b/website/assets/css/_components/_code.sass @@ -1,52 +1,40 @@ -//- ---------------------------------- -//- 💫 COMPONENTS > CODE -//- ---------------------------------- +//- 💫 CSS > COMPONENTS > CODE //- Code block .c-code-block - background: $color-subtle-light - padding: 1em 0 - border-left: 5px solid $color-theme + background: $color-front + color: $color-back + padding: 0.75em 0 + border-radius: 2px overflow: auto width: 100% max-width: 100% white-space: pre direction: ltr - :not(.o-block) - margin-bottom: 2rem - //- Code block content .c-code-block__content display: block - padding: 2em 2.5em - - -//- Code block label - -.c-code-block__label - display: inline-block - background: $color-theme - color: $color-back - padding: 1rem - margin-bottom: 1.5rem + font: normal normal 1.1rem/#{2} $font-code + padding: 1em 2em //- Inline code -:not(.c-code-block) > code - @extend .u-code-small - +*:not(.c-code-block) > code + font: normal 600 0.8em/#{1} $font-code background: $color-subtle-light - box-shadow: 1px 1px 0 $color-subtle color: $color-front - padding: 0.15em 0.5em - margin: 0 0.25em - border-radius: 2px - text-shadow: 1px 1px 0 $color-back + padding: 0.1em 0.5em + margin: 0 + border-radius: 1px + + .c-aside__content & + background: $color-dark + color: $color-back //- Syntax Highlighting diff --git a/website/assets/css/_components/_landing.sass b/website/assets/css/_components/_landing.sass new file mode 100644 index 000000000..5bd7e2c43 --- /dev/null +++ b/website/assets/css/_components/_landing.sass @@ -0,0 +1,20 @@ +//- 💫 CSS > COMPONENTS > LANDING + +.c-landing + background: $color-theme + padding-top: 5rem + width: 100% + +.c-landing__wrapper + background: $pattern + padding-bottom: 6rem + width: 100% + +.c-landing__content + background: $pattern-overlay + width: 100% + min-height: 573px + +.c-landing__title + color: $color-back + text-align: center diff --git a/website/assets/css/_components/_lists.sass b/website/assets/css/_components/_lists.sass index 479d3bf13..48a5e92c8 100644 --- a/website/assets/css/_components/_lists.sass +++ b/website/assets/css/_components/_lists.sass @@ -1,6 +1,4 @@ -//- ---------------------------------- -//- 💫 COMPONENTS > LISTS -//- ---------------------------------- +//- 💫 CSS > COMPONENTS > LISTS //- List Container @@ -17,16 +15,22 @@ .c-list__item padding-left: 2rem - margin-bottom: 1em + margin-bottom: 0.5em margin-left: 1.25rem &:before content: '\25CF' display: inline-block - font-size: 1.25em + font-size: 1em font-weight: bold padding-right: 1.25rem margin-left: -3.75rem text-align: right width: 2.5rem counter-increment: li + + +//- List icon + +.c-list__icon + margin-right: 1rem diff --git a/website/assets/css/_components/_misc.sass b/website/assets/css/_components/_misc.sass index 4abf29d01..3bd9bd6b6 100644 --- a/website/assets/css/_components/_misc.sass +++ b/website/assets/css/_components/_misc.sass @@ -1,11 +1,11 @@ -//- ---------------------------------- -//- 💫 COMPONENTS > MISC -//- ---------------------------------- +//- 💫 CSS > COMPONENTS > MISC .x-terminal - background: $color-subtle + background: $color-subtle-light color: $color-front - border-radius: 10px + padding: 4px + border: 1px dotted $color-subtle + border-radius: 5px width: 100% .x-terminal__icons @@ -23,22 +23,20 @@ &:before content: "" - background: #e4514f + background: $color-red span - background: #3ec930 + background: $color-green &:after content: "" - background: #f4c025 + background: $color-yellow .x-terminal__code - background: $color-front - color: $color-back margin: 0 border: none - border-bottom-left-radius: 10px - border-bottom-right-radius: 10px + border-bottom-left-radius: 5px + border-bottom-right-radius: 5px width: 100% max-width: 100% white-space: pre-wrap diff --git a/website/assets/css/_components/_navigation.sass b/website/assets/css/_components/_navigation.sass index 7352a6c6c..5b7275f92 100644 --- a/website/assets/css/_components/_navigation.sass +++ b/website/assets/css/_components/_navigation.sass @@ -1,29 +1,26 @@ -//- ---------------------------------- -//- 💫 COMPONENTS > NAVIGATION -//- ---------------------------------- +//- 💫 CSS > COMPONENTS > NAVIGATION .c-nav @include position(absolute, top, left, 0, 0) @include size(100%, $nav-height) - align-items: center background: $color-back - border-color: $color-back color: $color-theme + align-items: center display: flex justify-content: space-between - padding: 0 2rem - z-index: 10 + padding: 0 2rem 0 1rem + z-index: 20 width: 100% + border-bottom: 1px solid $color-subtle + + &.c-nav--theme + background: $color-theme + color: $color-back + border-bottom: none &.is-fixed animation: slideInDown 0.5s ease-in-out position: fixed - background: $color-theme - color: $color-back - border-color: $color-theme - - @include breakpoint(min, sm) - height: $nav-height * 0.8 .c-nav__menu @include size(100%) @@ -36,17 +33,7 @@ display: flex align-items: center height: 100% + text-transform: uppercase &:not(:last-child) margin-right: 1em - - &.is-active - position: relative - font-weight: bold - border-color: inherit - - &:after - $triangle: 8px - - @include triangle-down($triangle) - @include position(absolute, top, left, 100%, calc(50% - #{$triangle})) diff --git a/website/assets/css/_components/_sidebar.sass b/website/assets/css/_components/_sidebar.sass index a32c85f2b..b7c120350 100644 --- a/website/assets/css/_components/_sidebar.sass +++ b/website/assets/css/_components/_sidebar.sass @@ -1,40 +1,40 @@ -//- ---------------------------------- -//- 💫 COMPONENTS > SIDEBAR -//- ---------------------------------- +//- 💫 CSS > COMPONENTS > SIDEBAR + +//- Sidebar container .c-sidebar - @include breakpoint(min, md) - flex: 0 0 $sidebar-width - margin-right: 6rem - margin-left: 4rem - padding-top: $nav-height - width: $sidebar-width + background: $color-subtle-light + overflow-y: auto - &.is-fixed .c-sidebar__body - @include position(fixed, top, left, $nav-height, 4rem) - @include size($sidebar-width, calc(100vh - #{$nav-height})) - overflow: auto - transition: none + @include breakpoint(min, md) + @include position(fixed, top, left, 0, 0) + @include size($sidebar-width, 100vh) + flex: 0 0 $sidebar-width + padding: calc(#{$nav-height} + 1.5rem) 2rem 2rem + z-index: 10 + border-right: 1px solid $color-subtle @include breakpoint(max, sm) flex: 100% width: 100% - - .c-sidebar__body - display: flex - flex-flow: row wrap - width: 100% - - & > * - flex: 1 1 0 - padding: 1rem - border-bottom: 1px solid $color-subtle + margin-top: $nav-height + display: flex + flex-flow: row wrap + width: 100% - &:not(:last-child) - border-right: 1px solid $color-subtle +//- Sidebar section + +.c-sidebar__section + @include breakpoint(max, sm) + flex: 1 1 0 + padding: 1.25rem + border-bottom: 1px solid $color-subtle + margin: 0 + + &:not(:last-child) + border-right: 1px solid $color-subtle -.c-sidebar__body .is-active font-weight: bold color: $color-theme diff --git a/website/assets/css/_components/_tables.sass b/website/assets/css/_components/_tables.sass index 237e3d28d..b2c8edeaa 100644 --- a/website/assets/css/_components/_tables.sass +++ b/website/assets/css/_components/_tables.sass @@ -1,44 +1,68 @@ -//- ---------------------------------- -//- 💫 COMPONENTS > TABLES -//- ---------------------------------- +//- 💫 CSS > COMPONENTS > TABLES -// Shadows adapted from "CSS only Responsive Tables" by David Bushell -// http://codepen.io/dbushell/pen/wGaamR - -//- Table Container +//- Table container .c-table vertical-align: top - @include breakpoint(max, md) + +//- Table row + +.c-table__row + &:nth-child(odd) + background: lighten($color-subtle-light, 2) + + &.c-table__row--foot + background: $color-subtle-light + border-top: 2px solid $color-theme + + .c-table__cell:first-child + @extend .u-text-label + color: $color-theme + + +//- Table cell + +.c-table__cell + padding: 1rem + + &:not(:last-child) + border-right: 1px solid $color-subtle + + +//- Table head cell + +.c-table__head-cell + font-weight: bold + color: $color-theme + background: $color-back + padding: 1rem 0.5rem + border-bottom: 2px solid $color-theme + + +//- Responsive table +//- Shadows adapted from "CSS only Responsive Tables" by David Bushell +//- http://codepen.io/dbushell/pen/wGaamR + +@include breakpoint(max, md) + .c-table @include scroll-shadow-base($color-front) display: inline-block overflow-x: auto width: auto -webkit-overflow-scrolling: touch - -//- Table Cell - -.c-table__cell - padding: 1rem - border: 1px solid $color-subtle - - &.c-table__cell--highlight - border: 2px solid $color-theme - - @include breakpoint(max, md) + .c-table__cell, + .c-table__head-cell &:first-child @include scroll-shadow-cover(left, $color-back) &:last-child @include scroll-shadow-cover(right, $color-back) + .c-table__row--foot .c-table__cell + &:first-child + @include scroll-shadow-cover(left, lighten($color-subtle-light, 2)) -//- Table Head Cell - -.c-table__head-cell - background: $color-theme - color: $color-back - padding: 1rem - border: 1px solid $color-theme + &:last-child + @include scroll-shadow-cover(right, lighten($color-subtle-light, 2)) diff --git a/website/assets/css/_mixins.sass b/website/assets/css/_mixins.sass index d9fd210e1..e7e7a3432 100644 --- a/website/assets/css/_mixins.sass +++ b/website/assets/css/_mixins.sass @@ -1,6 +1,4 @@ -//- ---------------------------------- -//- 💫 MIXINS -//- ---------------------------------- +//- 💫 CSS > MIXINS // Helper for position // $position - valid position value (static, absolute, fixed, relative) @@ -38,18 +36,6 @@ @content -// Triangle pointing down -// $triangle-size - width of the triangle - -@mixin triangle-down($triangle-size) - @include size(0) - border-color: transparent - border-style: solid - border-top-color: inherit - border-width: $triangle-size $triangle-size 0 $triangle-size - content: "" - - // Scroll shadows for reponsive tables // adapted from David Bushell, http://codepen.io/dbushell/pen/wGaamR // $scroll-shadow-color - color of shadow diff --git a/website/assets/css/_variables.sass b/website/assets/css/_variables.sass index 62c90555c..41b27b309 100644 --- a/website/assets/css/_variables.sass +++ b/website/assets/css/_variables.sass @@ -1,20 +1,20 @@ -//- ---------------------------------- -//- 💫 VARIABLES -//- ---------------------------------- +//- 💫 CSS > VARIABLES // Settings and Sizes $type-base: 11px -$nav-height: 55px -$content-width: 800px -$sidebar-width: 230px -$aside-width: 300px +$nav-height: 45px +$content-width: 1250px +$sidebar-width: 200px +$aside-width: 500px $aside-padding: 25px -$logo-sizes: ( large: 500px, medium: 250px, small: 100px, tiny: 65px ) -$grid: ( third: 3, half: 2, two-thirds: 1.5 ) +$logo-width: 85px + +$grid: ( quarter: 4, third: 3, half: 2, two-thirds: 1.5, three-quarters: 1.33 ) $breakpoints: ( sm: 768px, md: 992px, lg: 1200px ) +$headings: (1: 3, 2: 2.6, 3: 2, 4: 1.8, 5: 1.5) // Fonts @@ -25,13 +25,24 @@ $font-code: 'Source Code Pro', Consolas, 'Andale Mono', Menlo, Monaco, Courier, // Colors -$color-theme: #09a3d5 -$color-theme-dark: #008ebc -$color-back: #fff -$color-front: #222 +$colors: ( blue: #09a3d5, red: #d9515d ) -$color-subtle: #ddd -$color-subtle-light: #f6f6f6 -$color-subtle-dark: #999 +$color-back: #fff !default +$color-front: #1a1e23 !default +$color-dark: lighten($color-front, 20) !default -$syntax-highlighting: ( comment: #999, tag: #3ec930, number: #8130c9, selector: #09a3d5, operator: #e4514f, function: #09a3d5, keyword: #e4514f, regex: #f4c025 ) +$color-theme: map-get($colors, $theme) +$color-theme-dark: darken(map-get($colors, $theme), 5) + +$color-subtle: #ddd !default +$color-subtle-light: #f6f6f6 !default +$color-subtle-dark: #949e9b !default + +$color-red: #d9515d +$color-green: #3ec930 +$color-yellow: #f4c025 + +$syntax-highlighting: ( comment: #949e9b, tag: #3ec930, number: #B084EB, selector: #FFB86C, operator: #FF2C6D, function: #09a3d5, keyword: #45A9F9, regex: #f4c025 ) + +$pattern: $color-theme url("/assets/img/pattern_#{$theme}.jpg") center top repeat +$pattern-overlay: transparent url("/assets/img/pattern_landing.jpg") center -138px no-repeat diff --git a/website/assets/css/style.sass b/website/assets/css/style.sass index f8f6cbc24..5ab135ab9 100644 --- a/website/assets/css/style.sass +++ b/website/assets/css/style.sass @@ -1,6 +1,6 @@ -//- ---------------------------------- -//- 💫 STYLE -//- ---------------------------------- +//- 💫 STYLESHEET + +$theme: blue !default // Variables @@ -25,6 +25,7 @@ @import _components/asides @import _components/buttons @import _components/code +@import _components/landing @import _components/lists @import _components/misc @import _components/navigation diff --git a/website/assets/css/style_red.sass b/website/assets/css/style_red.sass new file mode 100644 index 000000000..83fe330b9 --- /dev/null +++ b/website/assets/css/style_red.sass @@ -0,0 +1,4 @@ +//- 💫 STYLESHEET (RED) + +$theme: red +@import style diff --git a/website/assets/img/graphics.svg b/website/assets/img/graphics.svg new file mode 100644 index 000000000..23036f4ca --- /dev/null +++ b/website/assets/img/graphics.svg @@ -0,0 +1,68 @@ + + + + + brain + + + + + + + computer + + + + + + + + + + eye + + + + + + + + + + + + + + bubble + + + + + + + + + + + + spacy + + + + + explosion + + + + + matt-signature + + + diff --git a/website/assets/img/icons.svg b/website/assets/img/icons.svg index aa29ecdca..9237c9994 100644 --- a/website/assets/img/icons.svg +++ b/website/assets/img/icons.svg @@ -1,29 +1,32 @@ - - mail - - - - menu - - - - link - - - github - - twitter - + + code + - - reddit - + + anchor + + + + book + + + + pro + + + + con + + + + neutral + diff --git a/website/assets/img/logo.png b/website/assets/img/logo.png deleted file mode 100644 index 570b461bfb04c5ad453f172e4d901d08c7e061ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4246 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 diff --git a/website/assets/img/logos/indico.png b/website/assets/img/logos/indico.png new file mode 100644 index 0000000000000000000000000000000000000000..408e397578f23d200be12a9dead68349d57ce9de GIT binary patch literal 1215 zcmV;w1VHTGAvwsN*@+qP{y+dkVy_nS^nCONxS-8Gr|=2z(14Ey$GteqZ@ zPx7mGvA2f!z*$f#+?bCHi5RA_5{u#+hx!Cc8bi$EBH!CUZg#AD;%zw|VvXHfcfiAU zsmUNz?!BcD2a!B$Zvrdc1u_vSc=s)38?VIPR@iLK+e4m=>;0Rr;oDdf9K?RpYtFm2 zu!*t}b!WJZyrC~t68T=P_bs|Bofk#Fcj?L_Ydj>H5)(N!WO>LyjkO|Nz~Z|ohxK!W@Tq)XO2qp z{~TAd2!*oy?hBPP7v-!6{?{E90D4|Dsi~e>002ZQeAUeh9N*GAue4PP<-VtS4R*<1<=;k*@cRpfS|A| z0Z|7DY&VJMRjcL)(9cp$i)dEeS_MEIEYBJTne8s$$pocPtaYn4ty{Nly1=#R-O?av zZoR62D90QGg2 z9Tm~8-v+BQQ&5q7Hys4d2c8(vJ^bjS_CO1_x&koNdb?Q%@aYm9WIIsizh|5AD+FB{ zdj2W~^zx7(T|a_WOZ8M$g+GJ!ETBOY8%IP3ZqqCe zX<+O*pi_i!0|F_?JcO{-BghHRN!F`$l{uzJ|DYz4FQ`cc=xNd(sWH^I_9Cjy(!%@) z{GO@S2EYw z-N35n&bz-AY98a z<;w&%I|vu8sVF>G6M~x9ZKxE!nv8G|;9P1>8j8x^=P2Vqt3fGr)od62nwo!Lk z+f5XP{qf8^&O$}X&ieW6U+WtJ1S9U#<&;Rb^wcIHc9N(l01EJpHE9rA3lzz1l$RF^ zY-Xa(I*Jk=rYI$@*fb@Yro`Bo(!dYlY#aqeg%V#`=kzsk%SSB`Mex?n-#kz>>5^Jj=$9s-h^I!7%&F($A?@cE6!S3n(;@(z96Lo0Tpm?vz dTd(@W{10n;&{~10EJgqT002ovPDHLkV1o7!L0A9) literal 0 HcmV?d00001 diff --git a/website/assets/img/logos/spyjack.png b/website/assets/img/logos/spyjack.png deleted file mode 100644 index a4445ba919b397426323d86c284340dd4fc653b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 644 zcmV-~0(aPjw~u zA^)M0QjgWStOP!7;Qn8--z2fe?KmUOq(nIXPh#n*@l~TnPRXnf;~v2mwHTA6BgQ(t zSaRUAB-{F^jC_xAU!+WUkgVU|%`ug^aYdeP_IQ0ucE+RvW7P8lTwA1-2Ub&OG#=li zp4J__GHfc4CW&LU=2&$=C<%Peb9ZQw@j%c(mLh;Nfxk*Kd7NF{YBnTRkCGtj%8$ME zobJ$~0zZ7-t(;N|Pz3w6?5bW$f7+l9NpZj>iMp618+W1x_1cpRhpzhe(GU7#g)FTg zbGTGJUD6A#*)9p8OWcozI5=7j&;+EG!CzK3>4Z=Y@YiY@L?zhH>TrFOW6ziJ^Y?uI zu8l$IxxZEt8Id`N{q}VrNnO%&>T=tyEt@8?XMB%AaNv%f+SpQyj41cH(9<(sj?pXd zi)Z5T$kl4?nINgwub!4`bdFisn47b~UE+$Kfi$(s>(5!5d;B2&EXk1nMxqRVR!ptu zmn0?oD~UF4g!AL)uJG!4Xh_U4gU) diff --git a/website/assets/img/logos/wonderflow.png b/website/assets/img/logos/wonderflow.png index 9b890e54deca547f026f462869ef7e410de69f58..cb17d78b3f0aa6c6cd2e57da59ea4ee3c5097e74 100644 GIT binary patch delta 341 zcmV-b0jmDN3BU=ElK~j9l;#3|*&PIe=p34WtB4?yV8ZwQPkC9F@OS#9ev`H(%(10Y zf66#zELE1y0gNn7Uj9l-c%>);ya?VDkq_i52Gp#|txDD6rB6Dzi}xX`Vbd7f>JA8Y z7(FX7=A7QC($MCY>M|7qIBx*US1r=W-)SW7|~hcpz??fQZ|GONu-oft4Y-)5NIyq62Ed(Vu6M zDm;+!WhOvXEZ2G7pwd2cDupY|l>77&~5V^2=++*p`FB@g9+hfh&T nMXuuI2(nz+zY)Ln*8kN%YcEJpRvD&300000NkvXXu0mjfY^0^9 delta 342 zcmV-c0jd7L3Bd`FlK~mAl;#3|wH$_l=p32=%f=XtNk}gD|G#pP^?IQ%^-Y>enB!)r zewA~|xzxCHPGA;k@r;+r0A^JNL=mDXGM^|^9cV?3hZ;>6PkqqAqedT!I=-B_tsV)% z4`&n^bFCGfwwx;AJ5NX%%wurqrpp<6a_fUC{eW@NWQ_fP4G1+MQ|erQGMZV<=`EH- z-+4kFbm;`ixq*wJPjY-54DK+JG`CH|k5@>T8jx|Ha7&pdB(ZX&a9TJ`pL9U0F!X6A z*5DN~Kg|Sa%H_IVAs4SR*-j3(KIw!@iT$_tRynV?zK*ugU=1ohR)B1jy618QbZO@UzY;ou-WK%umTzF^fE{#!2kdN07*qoM6N<$f<5D*Bme*a diff --git a/website/assets/img/pattern.jpg b/website/assets/img/pattern.jpg deleted file mode 100644 index 25dd4073b44d40855be402c470f157f4f9524378..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 222353 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

c@r}Gq>An*@Or-a19A< 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