diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..ae772c5 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "app/static/js/vendor/bower" +} diff --git a/.gitignore b/.gitignore index 114b710..9ec97c7 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ config.py bower/ index.css config.py -data/ \ No newline at end of file +db/ \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index 8238065..7dbc559 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,5 +1,6 @@ from flask import Flask from flask.ext.mongoengine import MongoEngine +from flask.ext.assets import Environment, Bundle app = Flask(__name__, static_folder='static', static_url_path='') @@ -9,4 +10,15 @@ # Setup the database. db = MongoEngine(app) -from app import notify +# Assets +assets = Environment() +css = Bundle('css/index.sass', filters='sass', depends=['css/**/*.sass', 'css/**/**/*.sass'], output='css/index.css') +assets.register('css_all', css) +assets.init_app(app) + +# So we can use Jade templates. +app.jinja_env.add_extension('pyjade.ext.jinja.PyJadeExtension') + +# Register blueprints +from app import routes +app.register_blueprint(routes.clones.bp) diff --git a/app/forms.py b/app/forms.py new file mode 100644 index 0000000..7f8ea3a --- /dev/null +++ b/app/forms.py @@ -0,0 +1,6 @@ +from flask_wtf import Form +from wtforms import TextField +from wtforms.validators import Required + +class CloneForm(Form): + username = TextField('Twitter Username', validators=[Required()]) diff --git a/app/models.py b/app/models.py index 6a76f53..fbe1bd7 100644 --- a/app/models.py +++ b/app/models.py @@ -1,42 +1,76 @@ import datetime -from app import db +import random +import re +import config -class Verb(db.Document): +from textblob import TextBlob +from app import db, twitter + +class Clone(db.Document): created_at = db.DateTimeField(default=datetime.datetime.now, required=True) - body = db.StringField(required=True, unique=True) + username = db.StringField(required=True, unique=True) + patterns = db.ListField(db.StringField(), required=True) + vocabulary = db.DictField(required=True) meta = { 'allow_inheritance': True, - 'indexes': ['-created_at'], + 'indexes': ['-created_at', 'username'], 'ordering': ['-created_at'] } -class Noun(db.Document): - created_at = db.DateTimeField(default=datetime.datetime.now, required=True) - body = db.StringField(required=True, unique=True) + def imprint(self, username): + """ + Generate a clone for a given Twitter user. + """ + self.username = username + user_tweets = twitter.tweets(username, count=2000) - meta = { - 'allow_inheritance': True, - 'indexes': ['-created_at'], - 'ordering': ['-created_at'] - } + # { POS tag: words } + self.vocabulary = {} -class Adjective(db.Document): - created_at = db.DateTimeField(default=datetime.datetime.now, required=True) - body = db.StringField(required=True, unique=True) + # Mad-lib Tweet patterns. + self.patterns = [] - meta = { - 'allow_inheritance': True, - 'indexes': ['-created_at'], - 'ordering': ['-created_at'] - } + for tweet in user_tweets: + text = tweet['body'] + if '@' not in text: # Trying without any @mentions. -class Adverb(db.Document): - created_at = db.DateTimeField(default=datetime.datetime.now, required=True) - body = db.StringField(required=True, unique=True) + # Remove urls and @mentions + text = re.sub(r'(?:\@|https?\://)\S+', '', text) + pattern = text - meta = { - 'allow_inheritance': True, - 'indexes': ['-created_at'], - 'ordering': ['-created_at'] - } + # Extract parts of speech. + for t in TextBlob(text).pos_tags: + token = t[0] + tag = t[1] + + # Preserve hashtags. + # Skip untagged tokens. + # Skip tokens which are too short. + if token[0] == '#' or tag == '-NONE-' or len(token) <= 2: + continue + + if tag in config.ELIGIBLE_TAGS: + # Build the pattern. + pattern = pattern.replace(token, '{{{{ {0} }}}}'.format(tag)) + + # Add new tokens to the vocabulary. + if tag not in self.vocabulary: + self.vocabulary[tag] = [] + self.vocabulary[tag].append(token.lower()) + + self.patterns.append(pattern) + + def speak(self): + pattern = random.choice(self.patterns) + tweet = pattern + + # Extract the tags to be replaced. + p = re.compile(r'\{\{\s*([A-Za-z]+)\s*\}\}') + tags = p.findall(pattern) + + # Replace the tags with selections from the vocabulary. + for tag in tags: + token = random.choice(self.vocabulary[tag]) + tweet = re.sub(r'(\{\{\s*' + re.escape(tag) + r'\s*\}\})', token, tweet, 1) + return tweet diff --git a/app/routes/__init__.py b/app/routes/__init__.py new file mode 100644 index 0000000..725bd6c --- /dev/null +++ b/app/routes/__init__.py @@ -0,0 +1 @@ +from . import clones diff --git a/app/routes/clones.py b/app/routes/clones.py new file mode 100644 index 0000000..a5277c8 --- /dev/null +++ b/app/routes/clones.py @@ -0,0 +1,40 @@ +from flask import Blueprint, request, render_template, redirect, url_for, flash +from app.models import Clone +from app.forms import CloneForm +import re + +bp = Blueprint('clones', __name__, url_prefix = '/clones') + +@bp.route('/') +def clone(username): + clone = Clone.objects.get_or_404(username=username) + return render_template('clones/member.jade', clone=clone) + +@bp.route('/', methods=['GET', 'POST']) +def clones(): + form = CloneForm() + if form.validate_on_submit(): + username = form.username.data + if not Clone.objects.get(username): + clone = Clone() + clone.imprint(username) + clone.save() + return redirect(url_for('clones.clone', username=username)) + return render_template('clones/create.jade', form=form) + + +@bp.app_template_filter() +def highlight_pattern(pattern): + """ + A template filter for highlighting + fill-in spots in patterns. + + Example usage (in `pyjade`):: + + div= pattern|highlight_pattern + """ + p = re.compile(r'\{\{\s*([A-Za-z]+)\s*\}\}') + tags = p.findall(pattern) + for tag in tags: + pattern = re.sub(r'(\{\{\s*' + re.escape(tag) + r'\s*\}\})', ''+tag+'', pattern, 1) + return pattern diff --git a/app/static/css/core/_core.sass b/app/static/css/core/_core.sass new file mode 100755 index 0000000..bc8d877 --- /dev/null +++ b/app/static/css/core/_core.sass @@ -0,0 +1,7 @@ +// ========================================== CORE +@import "normalize" +@import "h5bp" +@import "mixins" +@import "type" +@import "lists" +@import "images" diff --git a/app/static/css/core/_h5bp.scss b/app/static/css/core/_h5bp.scss new file mode 100755 index 0000000..0c4576b --- /dev/null +++ b/app/static/css/core/_h5bp.scss @@ -0,0 +1,279 @@ +/* + * HTML5 Boilerplate + * + * What follows is the result of much research on cross-browser styling. + * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal, + * Kroc Camen, and the H5BP dev community and team. + */ + +/* ========================================================================== + Base styles: opinionated defaults + ========================================================================== */ + +html, +button, +input, +select, +textarea { + color: #222; +} + +* { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +/* + * Remove text-shadow in selection highlight: h5bp.com/i + * These selection declarations have to be separate. + * Customize the background color to match your design. + */ + +::-moz-selection { + background: $selection-background; + text-shadow: none; +} + +::selection { + background: $selection-background; + text-shadow: none; +} + +/* + * A better looking default horizontal rule + */ + +hr { + display: block; + height: 1px; + border: 0; + border-top: 1px solid #ccc; + margin: 1em 0; + padding: 0; +} + +/* + * Remove the gap between images and the bottom of their containers: h5bp.com/i/440 + */ + +img { + vertical-align: middle; +} + +/* + * Remove default fieldset styles. + */ + +fieldset { + border: 0; + margin: 0; + padding: 0; +} + +/* + * Allow only vertical resizing of textareas. + */ + +textarea { + resize: vertical; +} + +/* ========================================================================== + Browse Happy prompt + ========================================================================== */ + +.browsehappy { + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; +} + +/* ========================================================================== + Helper classes + ========================================================================== */ + +/* + * Image replacement + */ + +.ir { + background-color: transparent; + border: 0; + overflow: hidden; + /* IE 6/7 fallback */ + *text-indent: -9999px; +} + +.ir:before { + content: ""; + display: block; + width: 0; + height: 100%; +} + +/* + * Hide from both screenreaders and browsers: h5bp.com/u + */ + +.hidden { + display: none !important; + visibility: hidden; +} + +/* + * Hide only visually, but have it available for screenreaders: h5bp.com/v + */ + +.visuallyhidden { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +/* + * Extends the .visuallyhidden class to allow the element to be focusable + * when navigated to via the keyboard: h5bp.com/p + */ + +.visuallyhidden.focusable:active, +.visuallyhidden.focusable:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; +} + +/* + * Hide visually and from screenreaders, but maintain layout + */ + +.invisible { + visibility: hidden; +} + +/* + * Clearfix: contain floats + * + * For modern browsers + * 1. The space content is one way to avoid an Opera bug when the + * `contenteditable` attribute is included anywhere else in the document. + * Otherwise it causes space to appear at the top and bottom of elements + * that receive the `clearfix` class. + * 2. The use of `table` rather than `block` is only necessary if using + * `:before` to contain the top-margins of child elements. + */ + +.clearfix:before, +.clearfix:after { + content: " "; /* 1 */ + display: table; /* 2 */ +} + +.clearfix:after { + clear: both; +} + +/* + * For IE 6/7 only + * Include this rule to trigger hasLayout and contain floats. + */ + +.clearfix { + *zoom: 1; +} + +/* ========================================================================== + EXAMPLE Media Queries for Responsive Design. + Theses examples override the primary ('mobile first') styles. + Modify as content requires. + ========================================================================== */ + +@media only screen and (min-width: 35em) { + /* Style adjustments for viewports that meet the condition */ +} + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (min-resolution: 144dpi) { + /* Style adjustments for high resolution devices */ +} + +/* ========================================================================== + Print styles. + Inlined to avoid required HTTP connection: h5bp.com/r + ========================================================================== */ + +@media print { + * { + background: transparent !important; + color: #000 !important; /* Black prints faster: h5bp.com/s */ + box-shadow: none !important; + text-shadow: none !important; + } + + a, + a:visited { + text-decoration: underline; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + /* + * Don't show links for images, or javascript/internal links + */ + + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + + thead { + display: table-header-group; /* h5bp.com/t */ + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + @page { + margin: 0.5cm; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } +} diff --git a/app/static/css/core/_images.scss b/app/static/css/core/_images.scss new file mode 100755 index 0000000..6300e10 --- /dev/null +++ b/app/static/css/core/_images.scss @@ -0,0 +1,5 @@ +// ========================================== IMAGES +img { + max-width:100%; + vertical-align:middle; +} diff --git a/app/static/css/core/_lists.sass b/app/static/css/core/_lists.sass new file mode 100755 index 0000000..5ea29c6 --- /dev/null +++ b/app/static/css/core/_lists.sass @@ -0,0 +1,39 @@ +// ========================================== LISTS +ul, li + margin: 0 + padding: 0 + list-style-type: none + +.list__horizontal + > li + vertical-align: top + display: inline-block + +.list__horizontal__center + @extend .list__horizontal + text-align: center + +/* Horizontal justified lists. + http://goo.gl/bFGl9A + If you have having issues with vertical spacing, + set the ul's font-size to 0, and define a px font + for the li's. + Also try adjusting the li's line-height. */ + +.list__horizontal__justify + @extend .list__horizontal + text-align: justify + &:before + content: '' + display: block + width: 100% + &:after + content: '' + display: inline-block + width: 100% + > li + position: relative + &:last-child + margin-right: 0 + &:first-child + margin-left: 0 diff --git a/app/static/css/core/_mixins.sass b/app/static/css/core/_mixins.sass new file mode 100755 index 0000000..a6f2553 --- /dev/null +++ b/app/static/css/core/_mixins.sass @@ -0,0 +1,20 @@ +// ========================================== MIXINS +@mixin vendor($name, $argument) + -webkit-#{$name}: $argument + -ms-#{$name}: $argument + -moz-#{$name}: $argument + -o-#{$name}: $argument + #{$name}: $argument + +@mixin transition($target: all, $duration: 0.2s) + @include vendor(transition, $target $duration ease-in-out) + +@mixin gradient($start, $end) + background: $start /* Old browsers */ + background: -moz-linear-gradient(top, $start 0%, $end 100%) /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,$start), color-stop(100%,$end)) /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, $start 0%,$end 100%) /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, $start 0%,$end 100%) /* Opera 11.10+ */ + background: -ms-linear-gradient(top, $start 0%,$end 100%) /* IE10+ */ + background: linear-gradient(to bottom, $start 0%,$end 100%) /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='$start', endColorstr='$end',GradientType=0 ) /* IE6-9 */ diff --git a/app/static/css/core/_normalize.scss b/app/static/css/core/_normalize.scss new file mode 100755 index 0000000..5e79cf0 --- /dev/null +++ b/app/static/css/core/_normalize.scss @@ -0,0 +1,406 @@ +/*! normalize.css v2.1.2 | MIT License | git.io/normalize */ + +/* ========================================================================== + HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined in IE 8/9. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} + +/** + * Correct `inline-block` display not defined in IE 8/9. + */ + +audio, +canvas, +video { + display: inline-block; +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9. + * Hide the `template` element in IE, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* ========================================================================== + Base + ========================================================================== */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* ========================================================================== + Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background: transparent; +} + +/** + * Address `outline` inconsistency between Chrome and other browsers. + */ + +a:focus { + outline: thin dotted; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* ========================================================================== + Typography + ========================================================================== */ + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari 5, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9, Safari 5, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari 5 and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Correct font family set oddly in Safari 5 and Chrome. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} + +/** + * Improve readability of pre-formatted text in all browsers. + */ + +pre { + white-space: pre-wrap; +} + +/** + * Set consistent quote types. + */ + +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* ========================================================================== + Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9. + */ + +img { + border: 0; +} + +/** + * Correct overflow displayed oddly in IE 9. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* ========================================================================== + Figures + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari 5. + */ + +figure { + margin: 0; +} + +/* ========================================================================== + Forms + ========================================================================== */ + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * 1. Correct font family not being inherited in all browsers. + * 2. Correct font size not being inherited in all browsers. + * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. + */ + +button, +input, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +button, +input { + line-height: normal; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. + * Correct `select` style inheritance in Firefox 4+ and Opera. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * 1. Address box sizing set to `content-box` in IE 8/9. + * 2. Remove excess padding in IE 8/9. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari 5 and Chrome + * on OS X. + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * 1. Remove default vertical scrollbar in IE 8/9. + * 2. Improve readability and alignment in all browsers. + */ + +textarea { + overflow: auto; /* 1 */ + vertical-align: top; /* 2 */ +} + +/* ========================================================================== + Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/app/static/css/core/_type.scss b/app/static/css/core/_type.scss new file mode 100755 index 0000000..f56d7c7 --- /dev/null +++ b/app/static/css/core/_type.scss @@ -0,0 +1,42 @@ +// ========================================== TYPE + +body { + font-size: 1em; + line-height: 1.4; +} + +.peta { + font-size: 4em; +} + +h1, .tera { + font-size: 3em; +} + +h2, .giga { + font-size: 2.571em; +} + +h3, .mega { + font-size: 1.714em; +} + +h4, .kilo { + font-size: 1.286em; +} + +h5, .centi { + font-size: 1.143em; +} + +h6 { + font-size: 1em; +} + +.milli { + font-size: 0.857em; +} + +.micro { + font-size: 0.714em; +} diff --git a/app/static/css/exts/_fonts.scss b/app/static/css/exts/_fonts.scss new file mode 100644 index 0000000..91ae64b --- /dev/null +++ b/app/static/css/exts/_fonts.scss @@ -0,0 +1,48 @@ +/* + This font software is the property of Commercial Type. + + You may not modify the font software, use it on another website, or install it on a computer. + + License information is available at http://commercialtype.com/eula + For more information please visit Commercial Type at http://commercialtype.com or email us at info[at]commercialtype.com + + Copyright (C) 2013 Schwartzco Inc. + License: 1404-VDUJKU +*/ + + +@font-face { + font-family: 'Graphik Web'; + src: url('fonts/graphik/Graphik-Regular-Web.eot'); + src: url('fonts/graphik/Graphik-Regular-Web.eot?#iefix') format('embedded-opentype'), + url('fonts/graphik/Graphik-Regular-Web.woff') format('woff'), + url('fonts/graphik/Graphik-Regular-Web.ttf') format('truetype'), + url('fonts/graphik/Graphik-Regular-Web.svg#Graphik Web') format('svg'); + font-weight: 400; + font-style: normal; + font-stretch: normal; +} + +@font-face { + font-family: 'Graphik Web'; + src: url('fonts/graphik/Graphik-RegularItalic-Web.eot'); + src: url('fonts/graphik/Graphik-RegularItalic-Web.eot?#iefix') format('embedded-opentype'), + url('fonts/graphik/Graphik-RegularItalic-Web.woff') format('woff'), + url('fonts/graphik/Graphik-RegularItalic-Web.ttf') format('truetype'), + url('fonts/graphik/Graphik-RegularItalic-Web.svg#Graphik Web') format('svg'); + font-weight: 400; + font-style: italic; + font-stretch: normal; +} + +@font-face { + font-family: 'Graphik Web'; + src: url('fonts/graphik/Graphik-Semibold-Web.eot'); + src: url('fonts/graphik/Graphik-Semibold-Web.eot?#iefix') format('embedded-opentype'), + url('fonts/graphik/Graphik-Semibold-Web.woff') format('woff'), + url('fonts/graphik/Graphik-Semibold-Web.ttf') format('truetype'), + url('fonts/graphik/Graphik-Semibold-Web.svg#Graphik Web') format('svg'); + font-weight: 600; + font-style: normal; + font-stretch: normal; +} diff --git a/app/static/css/exts/_icons.scss b/app/static/css/exts/_icons.scss new file mode 100755 index 0000000..33b9838 --- /dev/null +++ b/app/static/css/exts/_icons.scss @@ -0,0 +1,81 @@ +// ========================================== ICONS +// Uses Font Custom +// http://fontcustom.com/ + +@font-face { + font-family: "icons"; + src: url("fonts/icons/icons.eot?#iefix") format("embedded-opentype"), + url("fonts/icons/icons.woff") format("woff"), + url("fonts/icons/icons.ttf") format("truetype"), + url("fonts/icons/icons.svg#icons") format("svg"); + font-weight: normal; + font-style: normal; +} + +[class^="icon-"]:before, [class*=" icon-"]:before { + font-family: "icons"; + font-weight: normal; + font-style: normal; + font-variant: normal; + display: inline-block; + text-decoration: inherit; + line-height: 1; + text-decoration: inherit; + text-transform: none; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; +} + +a [class^="icon-"], a [class*=" icon-"] { + display: inline-block; + text-decoration: inherit; +} + +/* makes the font 33% larger relative to the icon container */ +.icon-large:before { + vertical-align: top; + font-size: 1.333em; +} + +/* keeps button heights with and without icons the same */ +.btn [class^="icon-"], .btn [class*=" icon-"] { + line-height: 0.9em; +} + +li [class^="icon-"], li [class*=" icon-"] { + display: inline-block; + width: 1.25em; + text-align: center; +} + +/* 1.5 increased font size for icon-large * 1.25 width */ +li .icon-large[class^="icon-"], li .icon-large[class*=" icon-"] { + width: 1.875em; +} + +li[class^="icon-"], li[class*=" icon-"] { + margin-left: 0; + list-style-type: none; +} + +li[class^="icon-"]:before, li[class*=" icon-"]:before { + text-indent: -2em; + text-align: center; +} + +li[class^="icon-"].icon-large:before, li[class*=" icon-"].icon-large:before { + text-indent: -1.333em; +} + +.icon-bookmark:before { content: "\f100"; } +.icon-discuss:before { content: "\f101"; } +.icon-latest:before { content: "\f108"; } +.icon-login:before { content: "\f10a"; } +.icon-logo:before { content: "\f102"; } +.icon-logout:before { content: "\f103"; } +.icon-promote:before { content: "\f104"; } +.icon-search:before { content: "\f10b"; } +.icon-settings:before { content: "\f105"; } +.icon-share:before { content: "\f106"; } +.icon-trending:before { content: "\f109"; } +.icon-watch:before { content: "\f107"; } diff --git a/app/static/css/exts/_sticky_footer.scss b/app/static/css/exts/_sticky_footer.scss new file mode 100755 index 0000000..0cc6f73 --- /dev/null +++ b/app/static/css/exts/_sticky_footer.scss @@ -0,0 +1,29 @@ +// ========================================== STICKY FOOTER + +$sticky-footer: false; +$footer-height: 6em; + +html, body { + height:100%; + position:relative; +} + +.container { + position:relative; + height:auto !important; + height:100%; + min-height:100%; +} + +.main { + @if $sticky-footer { + padding:2em 4em ($footer-height + 2em); + } +} + +footer { + height:$footer-height; + position:absolute; + width:100%; + bottom:0; +} diff --git a/app/static/css/fonts/graphik/Graphik-Regular-Web.eot b/app/static/css/fonts/graphik/Graphik-Regular-Web.eot new file mode 100644 index 0000000..fec328c Binary files /dev/null and b/app/static/css/fonts/graphik/Graphik-Regular-Web.eot differ diff --git a/app/static/css/fonts/graphik/Graphik-Regular-Web.svg b/app/static/css/fonts/graphik/Graphik-Regular-Web.svg new file mode 100644 index 0000000..6746769 --- /dev/null +++ b/app/static/css/fonts/graphik/Graphik-Regular-Web.svg @@ -0,0 +1,579 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/static/css/fonts/graphik/Graphik-Regular-Web.ttf b/app/static/css/fonts/graphik/Graphik-Regular-Web.ttf new file mode 100644 index 0000000..0225195 Binary files /dev/null and b/app/static/css/fonts/graphik/Graphik-Regular-Web.ttf differ diff --git a/app/static/css/fonts/graphik/Graphik-Regular-Web.woff b/app/static/css/fonts/graphik/Graphik-Regular-Web.woff new file mode 100644 index 0000000..e9f4f8a Binary files /dev/null and b/app/static/css/fonts/graphik/Graphik-Regular-Web.woff differ diff --git a/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.eot b/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.eot new file mode 100644 index 0000000..f7f4023 Binary files /dev/null and b/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.eot differ diff --git a/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.svg b/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.svg new file mode 100644 index 0000000..9c0b582 --- /dev/null +++ b/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.svg @@ -0,0 +1,604 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.ttf b/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.ttf new file mode 100644 index 0000000..29b09e8 Binary files /dev/null and b/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.ttf differ diff --git a/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.woff b/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.woff new file mode 100644 index 0000000..22281b4 Binary files /dev/null and b/app/static/css/fonts/graphik/Graphik-RegularItalic-Web.woff differ diff --git a/app/static/css/fonts/graphik/Graphik-Semibold-Web.eot b/app/static/css/fonts/graphik/Graphik-Semibold-Web.eot new file mode 100644 index 0000000..fb604af Binary files /dev/null and b/app/static/css/fonts/graphik/Graphik-Semibold-Web.eot differ diff --git a/app/static/css/fonts/graphik/Graphik-Semibold-Web.svg b/app/static/css/fonts/graphik/Graphik-Semibold-Web.svg new file mode 100644 index 0000000..8e0edaa --- /dev/null +++ b/app/static/css/fonts/graphik/Graphik-Semibold-Web.svg @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/static/css/fonts/graphik/Graphik-Semibold-Web.ttf b/app/static/css/fonts/graphik/Graphik-Semibold-Web.ttf new file mode 100644 index 0000000..5de1d10 Binary files /dev/null and b/app/static/css/fonts/graphik/Graphik-Semibold-Web.ttf differ diff --git a/app/static/css/fonts/graphik/Graphik-Semibold-Web.woff b/app/static/css/fonts/graphik/Graphik-Semibold-Web.woff new file mode 100644 index 0000000..4e37715 Binary files /dev/null and b/app/static/css/fonts/graphik/Graphik-Semibold-Web.woff differ diff --git a/app/static/css/fonts/icons/icons.eot b/app/static/css/fonts/icons/icons.eot new file mode 100644 index 0000000..5b3dc05 Binary files /dev/null and b/app/static/css/fonts/icons/icons.eot differ diff --git a/app/static/css/fonts/icons/icons.svg b/app/static/css/fonts/icons/icons.svg new file mode 100644 index 0000000..75387a3 --- /dev/null +++ b/app/static/css/fonts/icons/icons.svg @@ -0,0 +1,139 @@ + + + + + +Created by FontForge 20120731 at Tue Apr 8 17:05:45 2014 + By Francis Tseng +Created by Francis Tseng with FontForge 2.0 (http://fontforge.sf.net) + + + + + + + + + + + + + + + + + + + diff --git a/app/static/css/fonts/icons/icons.ttf b/app/static/css/fonts/icons/icons.ttf new file mode 100644 index 0000000..3f9c922 Binary files /dev/null and b/app/static/css/fonts/icons/icons.ttf differ diff --git a/app/static/css/fonts/icons/icons.woff b/app/static/css/fonts/icons/icons.woff new file mode 100644 index 0000000..d8dfb69 Binary files /dev/null and b/app/static/css/fonts/icons/icons.woff differ diff --git a/app/static/css/index.sass b/app/static/css/index.sass new file mode 100755 index 0000000..274f3aa --- /dev/null +++ b/app/static/css/index.sass @@ -0,0 +1,42 @@ +/* ========================================== + Config + ========================================== */ +$primary-color: #2b7fdc +$header-color: #20232d +$secondary-color: #86d886 +$muted-color: #bbbdbf +$background-color: #fcfcfc +$error-color: #f55041 +$warning-color: #E2E942 +$success-color: #32b375 +$primary-type: 'Graphik Web', Verdana, Geneva, sans-serif +$primary-type-color: #323232 +$selection-background: $secondary-color +$max-width: 1080px + +@import "core/core" + +/* ========================================== + Extensions + ========================================== */ +@import "exts/icons" +@import "exts/fonts" + +/* ========================================== + Modules + ========================================== */ + +@import "modules/common" +@import "modules/forms" +@import "modules/header" +@import "modules/session" +@import "modules/notations" +@import "modules/mentions" +@import "modules/articles" +@import "modules/stories" +@import "modules/entity/page" +@import "modules/entity/item" +@import "modules/profile" +@import "modules/admin/sources" +@import "modules/search" + diff --git a/app/static/css/modules/_articles.sass b/app/static/css/modules/_articles.sass new file mode 100644 index 0000000..4c211f8 --- /dev/null +++ b/app/static/css/modules/_articles.sass @@ -0,0 +1,20 @@ +.articles + margin: 5em 0 + li + border-bottom: 1px solid #eeeeee + padding: 1em 0 + position: relative + &:last-of-type + border-bottom: none + +.source-icon + width: 48px + height: 48px + position: absolute + left: 0 + +.article-info + padding-left: 64px + +.article-title + font-size: 1.1em diff --git a/app/static/css/modules/_common.sass b/app/static/css/modules/_common.sass new file mode 100644 index 0000000..6ac3417 --- /dev/null +++ b/app/static/css/modules/_common.sass @@ -0,0 +1,152 @@ +html, body + font-family: $primary-type + color: $primary-type-color + background: $background-color + +main + min-height: 100vh + +.bounds + @include transition + max-width: $max-width + padding: 0 1em + margin: 0 auto + +a, a:visited + text-decoration: underline + color: $primary-color + +.heading + background: $primary-color + color: #fff + padding: 0.8em 0 + a, a:visited + text-transform: uppercase + text-decoration: none + color: rgba(255,255,255,0.8) + float: right + font-size: 0.6em + font-weight: normal + line-height: 2 + margin-right: 1.5em + +.subheading + color: #aaaaaa + border-bottom: 1px solid #cccccc + font-size: 0.8em + +.notifications + background: $primary-color + color: #fff + padding: 1.5em + text-align: center + +.title + font-weight: bold + a, a:visited + text-decoration: none + color: $primary-type-color + +.meta + @extend .clearfix + color: $muted-color + font-size: 0.6em + margin: 0.5em 0 + a, a:visited + color: $muted-color + text-decoration: none + &:hover + color: darken($muted-color, 6%) + +.meta-time + float: right +.meta-tags + float: left + text-transform: uppercase + +.popover-notification + right: 0 + left: 0 + bottom: -100% + text-align: center + position: fixed + .popover-notification-content + background: $error-color + color: #fff + width: 18em + padding: 2em + margin: 0 auto + font-size: 0.8em + +.actions + text-transform: uppercase + font-size: 0.4em + margin: 1.5em 0 0 0 + li + vertical-align: middle !important + line-height: 1.4 + color: #ddd + [class^="icon-"], [class*=" icon-"] + font-size: 3.5em + vertical-align: middle + color: $secondary-color + width: 1.25em + a, a:visited + color: #a4a5a4 + text-decoration: none + &:hover + color: $primary-type-color + &.active + color: $primary-color + +.empty + color: $muted-color + font-style: italic + text-align: center + margin: 4em 0 + +.more, a.more, a:visited.more + border: 1px solid #cccccc + color: $muted-color + text-align: center + font-size: 0.8em + padding: 1em + font-style: italic + cursor: pointer + display: block + +.pagination + width: 100% + overflow: hidden + padding: 0 0 2em 0 + a, a:visited + font-size: 0.8em +.pagination-prev + float: left +.pagination-next + float: right + +footer + background: $header-color + padding: 3em 2em 4em 2em + text-align: center + color: lighten($header-color, 16%) + .bounds + max-width: 480px + p + font-size: 0.7em + +.full-back + background: $primary-color + color: #fff + min-height: 100vh + padding: 6em 0 2em 0 + +.knight + width: 120px + +@media only screen and (max-width : 1080px) + .bounds-collapse-both + padding: 0 + .bounds-collapse-right + padding-right: 0 diff --git a/app/static/css/modules/_forms.sass b/app/static/css/modules/_forms.sass new file mode 100644 index 0000000..06e1efc --- /dev/null +++ b/app/static/css/modules/_forms.sass @@ -0,0 +1,15 @@ +input[type=text], +input[type=password] + border: none + padding: 0.5em 1em + +label + cursor: pointer + display: block + +input[type=submit] + padding: 0.5em 1em + border: none + +.form-actions + text-align: center diff --git a/app/static/css/modules/_header.sass b/app/static/css/modules/_header.sass new file mode 100644 index 0000000..c3c1659 --- /dev/null +++ b/app/static/css/modules/_header.sass @@ -0,0 +1,44 @@ +.header__primary + background: $header-color + color: #fff + padding: 0.5em 0 + overflow: hidden + a, a:visited + text-decoration: none + +.header__primary--title + float: left + a, a:visited + color: #fff + +.logo + @include transition + font-size: 1.6em + vertical-align: middle + margin: 0 0.2em 0 -1.2em + +nav + text-transform: uppercase + font-size: 0.6em + float: right + li + vertical-align: middle !important + line-height: 1.4 + margin-left: 2.2em + a, a:visited + color: #7783a0 + &.active + color: $primary-color + [class^="icon-"], [class*=" icon-"] + font-size: 2.5em + vertical-align: middle + color: #fff + +.protoflag + font-size: 0.6em + padding: 0 0.5em + color: $secondary-color + +@media only screen and (max-width : 1220px) + .logo + margin-left: 0 diff --git a/app/static/css/modules/_mentions.sass b/app/static/css/modules/_mentions.sass new file mode 100644 index 0000000..e15ffe8 --- /dev/null +++ b/app/static/css/modules/_mentions.sass @@ -0,0 +1,50 @@ +.mentions + width: 30% + float: right + background: #f6f6f6 + .heading + padding: 1.6em 1.2em + font-size: 0.8em + +.all-mentions + .mentions + width: 100% + .mention + width: 25% + float: left + +.mention-image + height: 200px + width: 100% + background-size: cover + background-position: center 20% + background-repeat: no-repeat + +.mention + margin-bottom: 2em + +.mention-content + padding: 1em + p + font-size: 0.7em + +.mention-title + font-size: 0.8em + margin: 0 0 1em 0 + +@media only screen and (max-width : 980px) + .mentions + width: 100% + float: none + .mention + width: 33.33% + margin-bottom: 4em + float: left + +@media only screen and (max-width : 760px) + .mention + width: 50% + +@media only screen and (max-width : 480px) + .mention + width: 100% diff --git a/app/static/css/modules/_notations.sass b/app/static/css/modules/_notations.sass new file mode 100644 index 0000000..420cfd6 --- /dev/null +++ b/app/static/css/modules/_notations.sass @@ -0,0 +1,34 @@ +.notations + @include transition + position: absolute + left: -5em + width: 5em + +.notation + color: $muted-color + padding: 0 0 0.5em 0 + font-size: 0.7em + +.notation-meta + color: $muted-color + padding: 1em 1em 0 0 + font-size: 0.6em + font-style: italic + text-align: right + +.promotions + padding: 0 0.5em 0.5em + +.promoters + li + text-align: right + padding-right: 0.8em + img + width: 32px + +.bookmark-flag + background: $primary-color + color: #fff + font-size: 1.6em + padding: 0.1em 0 0 0.2em + margin: 0 0 0.5em 0 diff --git a/app/static/css/modules/_profile.sass b/app/static/css/modules/_profile.sass new file mode 100644 index 0000000..816d9e3 --- /dev/null +++ b/app/static/css/modules/_profile.sass @@ -0,0 +1,7 @@ +.profile-stock-chart + width: 100% + +.profile-photos + li + width: 25% + float: left diff --git a/app/static/css/modules/_search.sass b/app/static/css/modules/_search.sass new file mode 100644 index 0000000..0bad7fa --- /dev/null +++ b/app/static/css/modules/_search.sass @@ -0,0 +1,32 @@ +.search-page + padding: 2em 1em 8em 1em + +.search-form + background: $primary-color + padding: 2em 2em 3em 2em + .bounds + max-width: 600px + margin: 0 auto + padding: 0 + label + font-size: 0.8em + input + width: 100% + padding: 0.5em 1em + display: block + font-size: 1.4em + + +.search-result + margin: 2.5em auto + max-width: 600px + img + max-width: 200px + float: left + margin-right: 1em + a, a:visited + text-decoration: none + color: $primary-type-color + .result-summary + font-size: 0.8em + diff --git a/app/static/css/modules/_session.sass b/app/static/css/modules/_session.sass new file mode 100644 index 0000000..40f4634 --- /dev/null +++ b/app/static/css/modules/_session.sass @@ -0,0 +1,33 @@ +.sessions + form + max-width: 400px + margin: 0 auto + label + color: rgba(0,0,0,0.4) + input[type=text], + input[type=password] + width: 100% + input[type=submit] + background: rgba(0,0,0,0.4) + color: #fff + +.sessions-prompt + text-align: center + +.sessions-hello + margin: 0 0 4em 0 + text-align: center + img + width: 120px + h1 + margin: 0 + .creed + color: rgba(0,0,0,0.4) + +.sessions-menu + text-align: center + font-size: 0.8em + a, a:visited + color: rgba(0,0,0,0.4) + li + padding: 1em diff --git a/app/static/css/modules/_stories.sass b/app/static/css/modules/_stories.sass new file mode 100644 index 0000000..fa0616e --- /dev/null +++ b/app/static/css/modules/_stories.sass @@ -0,0 +1,15 @@ +.timeline + margin: 0em 0 2em 0 + + .subheading + color: $primary-type-color + border-bottom: 2px solid $primary-color + padding-left: 1em + +.timeline-date + margin: 2em 0 + +.timeline-group + border-left: 2px solid #ddd + .item + margin-top: 0 diff --git a/app/static/css/modules/admin/_sources.sass b/app/static/css/modules/admin/_sources.sass new file mode 100644 index 0000000..3da8741 --- /dev/null +++ b/app/static/css/modules/admin/_sources.sass @@ -0,0 +1,18 @@ +.admin-sources + padding: 0 0 10em 0 + li + position: relative + border-bottom: 1px solid $primary-color + padding: 1em 0 + +.admin-source-title + float: left + +.admin-source-meta + float: right + padding: 1em 0 + +.admin-source-icon + width: 48px + height: 48px + margin: 0 1em 0 0 diff --git a/app/static/css/modules/entity/_item.sass b/app/static/css/modules/entity/_item.sass new file mode 100644 index 0000000..4e553d9 --- /dev/null +++ b/app/static/css/modules/entity/_item.sass @@ -0,0 +1,85 @@ +.item + margin: 2em 0 + border-bottom: 1px solid #eeeeee + padding: 1em 0 2em 0 + position: relative + &:last-child + border-bottom: none + +.item-notations + top: 1em + +.item-extra + float: left + width: 30% + +.item-thumb + width: 100% + +.item-header, +.item-summary + float: left + padding-left: 2em + width: 70% + +.item-title + font-size: 1.4em + +.item-summary + font-size: 0.8em + line-height: 1.6 + float: right + p:first-child + margin-top: 0 + +@media only screen and (max-width : 1220px) + .item-notations + position: static + width: auto + left: auto + top: auto + clear: both + .bookmark-flag + top: 1em + position: absolute + width: 2em + text-align: right + .promotions + padding: 0.5em 0 0 0 + .promoters li + display: inline-block + +@media only screen and (max-width : 720px) + .item-summary + width: 100% + float: none + padding: 1em 0 + clear: both + .item + padding-top: 4em + .item-notations + position: absolute + top: 0 + .bookmark-flag + position: relative + text-align: center + font-size: 1.35em + width: 1.5em + margin-right: 0.4em + float: left + padding: 0.1em 0 0 0 + .promotions + float: left + padding: 0.1em 0 0 0 + .promoters, + .notation-meta + display: inline-block + + +@media only screen and (max-width : 480px) + .item-extra, + .item-header + width: 100% + float: none + .item-header + padding: 1em 0 0 0 diff --git a/app/static/css/modules/entity/_page.sass b/app/static/css/modules/entity/_page.sass new file mode 100644 index 0000000..e42bc24 --- /dev/null +++ b/app/static/css/modules/entity/_page.sass @@ -0,0 +1,71 @@ +.page + padding: 0 0 8em 0 + +.page-body + position: relative + +.page-notations + top: -24em // hacky + left: -4em + .bookmark-flag + margin: 0 + .promotions + padding-top: 0.5em + +.page-header + padding-right: 2em + +.page-hero + width: 100% + height: 400px + background-size: cover + background-position: center 20% + background-repeat: no-repeat + +.page-content + width: 70% + float: left + section + padding-right: 2em + +.page-title + font-size: 1.6em + +.page-meta + margin: 0.5em 0 3em 0 + +.page-summary + font-size: 0.9em + line-height: 1.5 + p:first-child + margin-top: 0 + .page-meta + text-align: right + +.page-heading + margin: 2em 0 0 0 + padding: 1em + font-weight: bold + +.events + margin: 0 0 2em 0 + +@media only screen and (max-width : 1220px) + .page-notations + left: 1em + background: rgba(0,0,0,0.4) + .bookmark-flag, + .notation + text-align: right + .promoters li, + .notation-meta + padding-right: 0 + +@media only screen and (max-width : 1080px) + .page-notations + left: 0 + +@media only screen and (max-width : 980px) + .page-content + width: 100% + float: none diff --git a/app/templates/clones/create.jade b/app/templates/clones/create.jade new file mode 100644 index 0000000..a963412 --- /dev/null +++ b/app/templates/clones/create.jade @@ -0,0 +1,9 @@ +extends layout.jade + +block content + form(action='', method='post') + {{ form.csrf_token() }} + .field + label Twitter Username + {{ form.username(autofocus=true) }} + h1 hi diff --git a/app/templates/clones/member.jade b/app/templates/clones/member.jade new file mode 100644 index 0000000..f41cc49 --- /dev/null +++ b/app/templates/clones/member.jade @@ -0,0 +1,23 @@ +extends layout.jade + +block content + h1= clone.username + + //- Generate a few samples. + ul + for i in range(10) + li= clone.speak() + + h2 Patterns + ul + for pattern in clone.patterns + li= pattern|highlight_pattern|safe + + h2 Vocabulary + ul + for pos in clone.vocabulary + li + h6= pos + ul + for token in clone.vocabulary[pos] + li= token diff --git a/app/templates/layout.jade b/app/templates/layout.jade new file mode 100644 index 0000000..57dcb55 --- /dev/null +++ b/app/templates/layout.jade @@ -0,0 +1,35 @@ +doctype html +//if lt IE 7 + +//if IE 7 + +//if IE 8 + +// [if gt IE 8] You are using an outdated browser. Please upgrade your browser to improve your experience.

+ main(role="main",id="main") + //- Display notifications, if any. + - with messages = get_flashed_messages() + if messages + .notifications + for message in messages + {{ message }} + + //- Yield for other templates. + block content + + script(type="text/javascript",src="/js/vendor/bower/requirejs/require.js",data-main="/js/main") diff --git a/twitter.py b/app/twitter.py similarity index 74% rename from twitter.py rename to app/twitter.py index c6b0a20..268f64c 100644 --- a/twitter.py +++ b/app/twitter.py @@ -1,3 +1,6 @@ +import itertools +import math + import tweepy from tweepy import TweepError @@ -17,16 +20,26 @@ def _api(): api = _api() -def tweets(username, count=200, page=0): +MAX_COUNT = 200 +def tweets(username, count=200): """ - Returns 200 last tweets for a user. + Returns tweets for a user. """ + pages = math.ceil(count/MAX_COUNT) - 1 + count = min(MAX_COUNT, count) + + # This produces a list of lists. + tweets_ = [api.user_timeline(screen_name=username, count=count, page=i) for i in range(pages)] + + # This flattens the list of lists. + tweets = list(itertools.chain.from_iterable(tweets_)) + return [{ 'body': tweet.text, 'tid': tweet.id, 'protected': tweet.user.protected, 'retweeted': tweet.retweeted - } for tweet in api.user_timeline(screen_name=username, count=count, page=page)] + } for tweet in tweets] def retweet(id): """ diff --git a/application.py b/application.py index 4af28fb..357912d 100644 --- a/application.py +++ b/application.py @@ -1,4 +1,4 @@ from app import app if __name__ == '__main__': - app.run(debug=False) + app.run(debug=True) diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..627333a --- /dev/null +++ b/bower.json @@ -0,0 +1,8 @@ +{ + "name": "youtwos", + "version": "0.0.1", + "dependencies": { + "requirejs": "latest" + } +} + diff --git a/config-sample.py b/config-sample.py index a725e3e..239ea5d 100644 --- a/config-sample.py +++ b/config-sample.py @@ -14,3 +14,16 @@ TWITTER_CONSUMER_SECRET = 'fill_me_in' TWITTER_ACCESS_TOKEN = 'fill_me_in' TWITTER_ACCESS_SECRET = 'fill_me_in' + +ELIGIBLE_TAGS = [ + 'CD', # numbers + 'JJ', # adjectives + 'NN', # nouns + 'NNP', # proper nouns + 'NNPS', # plural proper nouns + 'NNS', # plural nouns + 'VBN', + 'VBG', + 'VB', + 'RB' # adverbs +] diff --git a/requirements.txt b/requirements.txt index ceddb51..9759763 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ Flask==0.10.1 +Flask-Assets==0.10 Flask-WTF==0.9.5 Jinja2==2.7.3 MarkupSafe==0.23 @@ -8,10 +9,12 @@ Werkzeug==0.9.6 flask-mongoengine==0.7.0 itsdangerous==0.24 mongoengine==0.8.7 -nltk==3.0b1 numpy==1.8.1 +pyjade==2.2.0 pymongo==2.7.1 +six==1.7.3 textblob==0.8.4 +webassets==0.10.1 git+git://github.com/nltk/nltk.git git+git://github.com/ze-phyr-us/tweepy.git diff --git a/run.py b/run.py deleted file mode 100644 index 2f8515c..0000000 --- a/run.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8 -*- -import sys -import string -import random -import json -import twitter -import re -from textblob import TextBlob - -ELIGIBLE_TAGS = [ - 'CD', # numbers - 'JJ', # adjectives - 'NN', # nouns - 'NNP', # proper nouns - 'NNPS', # plural proper nouns - 'NNS', # plural nouns - 'VBN', - 'VBG', - 'VB', - 'RB' # adverbs -] - -def main(): - try: - import config - except ImportError: - print('No config found. Have you renamed `config-sample.py` to `config.py` and filled in your info?') - return - - if len(sys.argv) < 2: - print('Please tell me what example to run!') - return - - try: - globals()[sys.argv[1]](); - except KeyError: - print('Doesn\'t seem to be an example by that name.') - return - -def tweets(): - user_tweets = [] - for i in range(10): - user_tweets += twitter.tweets('brian_justie', page=i) - with open('data/data.txt', 'w') as outfile: - json.dump(user_tweets, outfile) - -def process(): - f = open('data/data.txt', 'r') - - # Words matched with POS tags. - speech_parts = {} - - # Chains of POS tags to build - # tweets out of. - speech_patterns = [] - for tweet in json.load(f): - if '@' not in tweet['body']: # Trying without any @ mentions. - text = tweet['body'] - - # Remove urls and @mentions. - text = re.sub(r"(?:\@|https?\://)\S+", "", text) - pattern = text - - for t in TextBlob(text).pos_tags: - token = t[0] - tag = t[1] - - # Preserve hashtags. - if token[0] == '#': - continue - - if tag in ELIGIBLE_TAGS and len(token) > 2: - pattern = pattern.replace(token, '{{{{ {0} }}}}'.format(tag)) - - if tag == '-NONE-': - continue - - if tag not in speech_parts: - speech_parts[tag] = [] - speech_parts[tag].append(token.lower()) - - speech_patterns.append(pattern) - - with open('data/speech_parts.json', 'w') as outfile: - json.dump(speech_parts, outfile, indent=4, sort_keys=True) - - with open('data/speech_patterns.json', 'w') as outfile: - json.dump(speech_patterns, outfile, indent=4, sort_keys=True ) - -def generate(): - with open('data/speech_parts.json', 'r') as f: - speech_parts = json.load(f) - with open('data/speech_patterns.json', 'r') as f: - speech_patterns = json.load(f) - - pattern = random.choice(speech_patterns) - tweet = pattern - - p = re.compile(r'\{\{\s*([A-Za-z]+)\s*\}\}') - tags = p.findall(pattern) - - for tag in tags: - token = random.choice(speech_parts[tag]) - tweet = re.sub(r'(\{\{\s*' + re.escape(tag) + r'\s*\}\})', token, tweet, 1) - print(tweet) - - - -if __name__ == '__main__': - main() -