40 Commits

Author SHA1 Message Date
e076346765 Start of "production videos", a.k.a. tagged assets overview
Tagged assets are shown in a list per tag. The list is dynamically
loaded with JavaScript.
2018-09-06 15:46:31 +02:00
0b1f295480 Services: Fix layout 2018-09-06 14:33:44 +02:00
a64d3902fd Bootstrap popovers are no longer used. 2018-09-06 14:24:31 +02:00
8dd1de1018 Merge branch 'wip-redesign'
# Conflicts:
#	src/templates/homepage.pug
#	src/templates/services.pug
2018-09-06 14:13:22 +02:00
b12b320cf0 Project view: include video_plugins.min.js 2018-09-06 13:32:57 +02:00
95e51e90de Homepage cleanup. 2018-09-06 13:03:40 +02:00
92106459a0 Use Navigation Tabs for homepage and index collections 2018-09-06 13:03:22 +02:00
982047fc3b Pug: Tweaks to components 2018-09-06 12:59:48 +02:00
5a36888f61 Navigation: Dropdowns for Services and Open Projects 2018-09-06 12:58:56 +02:00
59e0adf3ca Pug: Bring new templates from Pillar 2018-09-06 12:54:15 +02:00
3fdbb92b93 Fixed typo 2018-09-05 15:11:46 +02:00
cf98883633 Make <meta property="og:url"> tags have an absolute URL
Most of those can simply use `{{ request.url }}`, as this already contains
the absolute URL of the currently displayed page.
2018-09-05 13:58:13 +02:00
7b32b97203 Remove https://cloud.blender.org from URLs
URLs should be host-relative, so that they also work on devservers.
URLs in emails should remain absolute, though; we may want to change those
to use {{ url_for(..., _external=True) }} at some point.
2018-09-05 13:57:15 +02:00
7f58be4568 Updated Blender Cloud add-on to 1.9.0
Also change the config_local.py so that we only have to change one variable
for a new version.
2018-09-05 13:40:24 +02:00
c25df6f0ad Cleanup 2018-08-31 19:33:14 +02:00
813750a006 Layout cleanup 2018-08-31 19:08:52 +02:00
9ba2735c8c CSS Cleanup 2018-08-31 19:08:23 +02:00
73e8a81f3c Minor style tweaks 2018-08-31 13:58:26 +02:00
9ffcde3348 Use styling from Pillar 2018-08-31 13:58:08 +02:00
f0b18e88f4 Use pug mixins for header, cards and navigation 2018-08-31 13:57:51 +02:00
ed211f9473 Introducing Pug mixin components
For now added jumbotron, secondary navigation, card decks and individual cards.

Thanks @sybren for the suggestion.
2018-08-31 13:57:09 +02:00
7a4c7d75f6 Project Landing uses new CSS 2018-08-31 13:55:35 +02:00
cc16351136 NPM: Upgrade libraries
New dependency is jQuery, we already depended on it it but now we use it
from npm package for easier version control and upgrades.
2018-08-31 13:54:39 +02:00
7dc1e6f9a1 Gulp: Only chmod files when in --production 2018-08-31 13:53:37 +02:00
fcf715b5b1 Services page: move to bootstrap 4 2018-08-31 13:52:40 +02:00
099984f97c Added #!/bin/sh at top of shell script 2018-08-30 12:53:34 +02:00
8bfb40ce54 Various Docker image upgrades, read the entire commit message!
- Ubuntu 17.10 → 18.04.
- Python 3.6.3 → 3.6.6.
- Use `DEBIAN_FRONTEND=noninteractive` to prevent prompts during
  installation.
- Install `tzdata` in the base image as it's required by subimages.
- Correctly set maintainer in Dockerfile.
2018-08-30 12:53:34 +02:00
d60a65c9f0 End BLENDER_ID_ENDPOINT with a slash 2018-08-30 12:46:58 +02:00
9cd2853e49 Upgrade pip after building Python 2018-08-30 12:31:31 +02:00
3d5554d9ce BLENDER_ID_ENDPOINT should end with a slash
There is always a path component in a URL.
2018-08-29 14:20:23 +02:00
764ccfa78e Add -e . to requirements-dev.txt 2018-08-29 12:24:45 +02:00
0b8ebecfea Don't import flask_login.request
`flask_login.request` is the exact same thing as `flask.request`, so
importing it from `flask_login` makes no sense. Also, it's been removed
from the new Flask-Login.
2018-08-29 12:19:40 +02:00
68d09dc886 CSS: cleanup 2018-08-28 15:56:06 +02:00
169a7f51f0 navbar-container: cleanup 2018-08-28 15:55:32 +02:00
f48a4883ae Index collection redesign 2018-08-27 16:58:01 +02:00
01b6693324 Cleanup styling. Use bootstrap classes instead 2018-08-27 16:57:34 +02:00
012ba06655 Use system fonts (see main.sass) 2018-08-27 16:55:48 +02:00
2be601d0b0 Introducing Bootstrap 4
Bootstrap (and its dependency popper.js) are now used from npm packages,
allowing better version control and custom building of only the required
components for both styling and javascript.

At this moment the whole styling of bootstrap is included, once the Cloud
redesign is over it will be stripped to only the used components.
2018-08-27 16:52:22 +02:00
4dc11b075a Gulp: watch Pillar styles folder for changes and compile Sass 2018-08-27 15:17:00 +02:00
4696d09fed Corrected rewrite rule for Caminandes 2018-07-06 14:56:40 +02:00
60 changed files with 3125 additions and 1532 deletions

4
.gitignore vendored
View File

@@ -3,9 +3,11 @@
.coverage
*.pyc
__pycache__
*.js.map
*.css.map
/cloud/templates/
/cloud/static/assets/css/
/cloud/static/assets/
node_modules/
/config_local.py

View File

@@ -41,6 +41,7 @@ class CloudExtension(PillarExtension):
'EXTERNAL_SUBSCRIPTIONS_MANAGEMENT_SERVER': 'https://store.blender.org/api/',
'EXTERNAL_SUBSCRIPTIONS_TIMEOUT_SECS': 10,
'BLENDER_ID_WEBHOOK_USER_CHANGED_SECRET': 'oos9wah1Zoa0Yau6ahThohleiChephoi',
'NODE_TAGS': ['animation', 'modelling', 'rigging'],
}
def eve_settings(self):

View File

@@ -391,6 +391,11 @@ def privacy():
return render_template('privacy.html')
@blueprint.route('/production')
def production():
return render_template('production.html')
@blueprint.route('/emails/welcome.send')
@login_required
def emails_welcome_send():

3
cloud/tagged/__init__.py Normal file
View File

@@ -0,0 +1,3 @@
"""Routes for fetching tagged assets."""

16
cloud/tagged/routes.py Normal file
View File

@@ -0,0 +1,16 @@
import logging
import datetime
import functools
from flask import Blueprint, jsonify
blueprint = Blueprint('cloud.tagged', __name__, url_prefix='/tagged')
log = logging.getLogger(__name__)
@blueprint.route('/')
def index():
"""Return all tagged assets as JSON, grouped by tag."""

View File

@@ -7,8 +7,7 @@ import json
import logging
import typing
from flask_login import request
from flask import Blueprint
from flask import Blueprint, request
import werkzeug.exceptions as wz_exceptions
from pillar import current_app

View File

@@ -2,7 +2,7 @@ import os
DEBUG = True
BLENDER_ID_ENDPOINT = 'http://id.local:8000'
BLENDER_ID_ENDPOINT = 'http://id.local:8000/'
SERVER_NAME = 'cloud.local:5001'
SCHEME = 'http'

View File

@@ -1,6 +1,10 @@
FROM ubuntu:17.10
MAINTAINER Francesco Siddi <francesco@blender.org>
FROM ubuntu:18.04
LABEL maintainer="Sybren A. Stüvel <sybren@blender.studio>"
RUN apt-get update && apt-get install -qyy \
-o APT::Install-Recommends=false -o APT::Install-Suggests=false \
openssl ca-certificates
RUN set -ex; \
apt-get update; \
DEBIAN_FRONTEND=noninteractive apt-get install \
-qyy -o APT::Install-Recommends=false -o APT::Install-Suggests=false \
tzdata openssl ca-certificates locales; \
locale-gen en_US.UTF-8 en_GB.UTF-8 nl_NL.UTF-8
ENV LANG en_US.UTF-8

View File

@@ -1 +0,0 @@
1325134dd525b4a2c3272a1a0214dd54 Python-3.6.4.tar.xz

View File

@@ -0,0 +1 @@
c3f30a0aff425dda77d19e02f420d6ba Python-3.6.6.tar.xz

View File

@@ -34,6 +34,9 @@ make -j8 install
# Make sure we can run Python
ldconfig
# Upgrade pip
/opt/python/bin/python3 -m pip install -U pip
# Build mod-wsgi-py3 for Python 3.6
cd /dpkg/mod-wsgi-*
./configure --with-python=/opt/python/bin/python3

View File

@@ -1,9 +1,9 @@
FROM pillar_base
LABEL maintainer Sybren A. Stüvel <sybren@blender.studio>
LABEL maintainer="Sybren A. Stüvel <sybren@blender.studio>"
RUN sed -i 's/^# deb-src/deb-src/' /etc/apt/sources.list && \
apt-get update && \
apt-get install -qy \
DEBIAN_FRONTEND=noninteractive apt-get install -qy \
build-essential \
apache2-dev \
checkinstall \
@@ -11,13 +11,13 @@ RUN sed -i 's/^# deb-src/deb-src/' /etc/apt/sources.list && \
RUN apt-get build-dep -y python3.6
ADD Python-3.6.4.tar.xz.md5 /Python-3.6.4.tar.xz.md5
ADD Python-3.6.6.tar.xz.md5 /Python-3.6.6.tar.xz.md5
# Install Python sources
RUN curl -O https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz && \
md5sum -c Python-3.6.4.tar.xz.md5 && \
tar xf Python-3.6.4.tar.xz && \
rm -v Python-3.6.4.tar.xz
RUN curl -O https://www.python.org/ftp/python/3.6.6/Python-3.6.6.tar.xz && \
md5sum -c Python-3.6.6.tar.xz.md5 && \
tar xf Python-3.6.6.tar.xz && \
rm -v Python-3.6.6.tar.xz
# Install mod-wsgi sources
RUN mkdir -p /dpkg && cd /dpkg && apt-get source libapache2-mod-wsgi-py3
@@ -32,4 +32,4 @@ RUN echo /opt/python/lib > /etc/ld.so.conf.d/python.conf
RUN ldconfig
ENV PATH=/opt/python/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ENV PYTHONSOURCE=/Python-3.6.4
ENV PYTHONSOURCE=/Python-3.6.6

View File

@@ -1,5 +1,5 @@
FROM pillar_base
LABEL maintainer Sybren A. Stüvel <sybren@blender.studio>
LABEL maintainer="Sybren A. Stüvel <sybren@blender.studio>"
ADD python /opt/python
@@ -10,5 +10,4 @@ RUN echo Python is installed in /opt/python/ > README.python
ENV PATH=/opt/python/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
RUN cd /opt/python/bin && \
ln -s python3 python && \
ln -s pip3 pip
ln -s python3 python

View File

@@ -1,7 +1,9 @@
FROM armadillica/pillar_py:3.6
LABEL maintainer Sybren A. Stüvel <sybren@blender.studio>
LABEL maintainer="Sybren A. Stüvel <sybren@blender.studio>"
RUN apt-get update && apt-get install -qy \
RUN set -ex; \
apt-get update; \
DEBIAN_FRONTEND=noninteractive apt-get install -qy \
git \
build-essential \
checkinstall \

View File

@@ -1,17 +1,19 @@
FROM armadillica/pillar_py:3.6
LABEL maintainer Sybren A. Stüvel <sybren@blender.studio>
LABEL maintainer="Sybren A. Stüvel <sybren@blender.studio>"
RUN apt-get update && apt-get install -qyy \
-o APT::Install-Recommends=false -o APT::Install-Suggests=false \
git \
apache2 \
libapache2-mod-xsendfile \
libjpeg8 \
libtiff5 \
ffmpeg \
rsyslog logrotate \
nano vim-tiny curl \
&& rm -rf /var/lib/apt/lists/*
RUN set -ex; \
apt-get update; \
DEBIAN_FRONTEND=noninteractive apt-get install -qy \
-o APT::Install-Recommends=false -o APT::Install-Suggests=false \
git \
apache2 \
libapache2-mod-xsendfile \
libjpeg8 \
libtiff5 \
ffmpeg \
rsyslog logrotate \
nano vim-tiny curl; \
rm -rf /var/lib/apt/lists/*
RUN ln -s /usr/bin/vim.tiny /usr/bin/vim

View File

@@ -40,7 +40,7 @@
# Redirects for blender-cloud projects
RewriteRule "^/p/blender-cloud/?$" "/blog" [R=301,L]
RewriteRule "^/agent327/?$" "/p/agent-327" [R=301,L]
RewriteRule "^/caminandes/?$" "/p/caminandes" [R=301,L]
RewriteRule "^/caminandes/?$" "/p/caminandes-3" [R=301,L]
RewriteRule "^/cf2/?$" "/p/creature-factory-2" [R=301,L]
RewriteRule "^/characters/?$" "/p/characters" [R=301,L]
RewriteRule "^/gallery/?$" "/p/gallery" [R=301,L]

View File

@@ -28,7 +28,7 @@ CACHE_REDIS_URL = 'redis://redis:6379'
PILLAR_SERVER_ENDPOINT = 'https://cloud.blender.org/api/'
BLENDER_ID_ENDPOINT = 'https://www.blender.org/id'
BLENDER_ID_ENDPOINT = 'https://www.blender.org/id/'
GCLOUD_APP_CREDENTIALS = '/data/config/google_app.json'
GCLOUD_PROJECT = 'blender-cloud'
@@ -83,21 +83,22 @@ LOGGING = {
}
}
# Latest version of the add-on.
BLENDER_CLOUD_ADDON_VERSION = '1.9.0'
REDIRECTS = {
# For old links, refer to the services page (hopefully it refreshes then)
'downloads/blender_cloud-latest-bundle.zip': 'https://cloud.blender.org/services#blender-addon',
# Latest Blender Cloud add-on; remember to update BLENDER_CLOUD_ADDON_VERSION.
# Latest Blender Cloud add-on.
'downloads/blender_cloud-latest-addon.zip':
'https://storage.googleapis.com/institute-storage/addons/blender_cloud-1.8.0.addon.zip',
f'https://storage.googleapis.com/institute-storage/addons/'
f'blender_cloud-{BLENDER_CLOUD_ADDON_VERSION}.addon.zip',
# Redirect old Grafista endpoint to /stats
'/stats/': '/stats',
}
# Latest version of the add-on; remember to update REDIRECTS.
BLENDER_CLOUD_ADDON_VERSION = '1.8.0'
UTM_LINKS = {
'cartoon_brew': {
'image': 'https://imgur.com/13nQTi3.png',

View File

@@ -1,3 +1,4 @@
#!/bin/sh
if [ -f /installed ]; then
return

View File

@@ -1,5 +1,6 @@
var argv = require('minimist')(process.argv.slice(2));
var autoprefixer = require('gulp-autoprefixer');
var cache = require('gulp-cached');
var chmod = require('gulp-chmod');
var concat = require('gulp-concat');
var git = require('gulp-git');
@@ -11,16 +12,16 @@ var plumber = require('gulp-plumber');
var rename = require('gulp-rename');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var uglify = require('gulp-uglify');
var cache = require('gulp-cached');
var uglify = require('gulp-uglify-es').default;
var enabled = {
uglify: argv.production,
maps: argv.production,
maps: !argv.production,
failCheck: !argv.production,
prettyPug: !argv.production,
cachify: !argv.production,
cleanup: argv.production,
chmod: argv.production,
};
var destination = {
@@ -29,6 +30,12 @@ var destination = {
js: 'cloud/static/assets/js',
}
var source = {
pillar: '../pillar/',
bootstrap: 'node_modules/bootstrap/',
popper: 'node_modules/popper.js/'
}
/* CSS */
gulp.task('styles', function() {
@@ -73,7 +80,7 @@ gulp.task('scripts', function() {
.pipe(gulpif(enabled.uglify, uglify()))
.pipe(rename({suffix: '.min'}))
.pipe(gulpif(enabled.maps, sourcemaps.write(".")))
.pipe(chmod(644))
.pipe(gulpif(enabled.chmod, chmod(644)))
.pipe(gulp.dest(destination.js))
.pipe(gulpif(argv.livereload, livereload()));
});
@@ -88,12 +95,34 @@ gulp.task('scripts_concat_tutti', function() {
.pipe(concat("tutti.min.js"))
.pipe(gulpif(enabled.uglify, uglify()))
.pipe(gulpif(enabled.maps, sourcemaps.write(".")))
.pipe(chmod(644))
.pipe(gulpif(enabled.chmod, chmod(644)))
.pipe(gulp.dest(destination.js))
.pipe(gulpif(argv.livereload, livereload()));
});
// Combine all needed Bootstrap JavaScript into a single file.
gulp.task('scripts_concat_bootstrap', function() {
toUglify = [
source.popper + 'dist/umd/popper.min.js',
source.bootstrap + 'js/dist/index.js',
source.bootstrap + 'js/dist/util.js',
source.bootstrap + 'js/dist/tooltip.js',
source.bootstrap + 'js/dist/dropdown.js',
];
gulp.src(toUglify)
.pipe(gulpif(enabled.failCheck, plumber()))
.pipe(gulpif(enabled.maps, sourcemaps.init()))
.pipe(concat("bootstrap.min.js"))
.pipe(gulpif(enabled.uglify, uglify()))
.pipe(gulpif(enabled.maps, sourcemaps.write(".")))
.pipe(gulpif(enabled.chmod, chmod(644)))
.pipe(gulp.dest(destination.js))
.pipe(gulpif(argv.livereload, livereload()));
});
// While developing, run 'gulp watch'
gulp.task('watch',function() {
@@ -103,6 +132,8 @@ gulp.task('watch',function() {
}
gulp.watch('src/styles/**/*.sass',['styles']);
gulp.watch(source.pillar + 'src/styles/**/*.sass',['styles']);
gulp.watch('src/templates/**/*.pug',['templates']);
gulp.watch('src/scripts/*.js',['scripts']);
gulp.watch('src/scripts/tutti/**/*.js',['scripts_concat_tutti']);
@@ -125,4 +156,5 @@ gulp.task('cleanup', function() {
// Run 'gulp' to build everything at once
var tasks = [];
if (enabled.cleanup) tasks.push('cleanup');
gulp.task('default', tasks.concat(['styles', 'templates', 'scripts', 'scripts_concat_tutti']));
gulp.task('default', tasks.concat(['styles', 'templates', 'scripts', 'scripts_concat_tutti', 'scripts_concat_bootstrap']));

View File

@@ -8,20 +8,24 @@
},
"devDependencies": {
"gulp": "~3.9.1",
"gulp-autoprefixer": "~2.3.1",
"gulp-cached": "~1.1.0",
"gulp-chmod": "~1.3.0",
"gulp-concat": "~2.6.0",
"gulp-if": "^2.0.1",
"gulp-git": "~2.4.2",
"gulp-pug": "~3.2.0",
"gulp-jade": "~1.1.0",
"gulp-livereload": "~3.8.1",
"gulp-plumber": "~1.1.0",
"gulp-rename": "~1.2.2",
"gulp-sass": "~2.3.1",
"gulp-sourcemaps": "~1.6.0",
"gulp-uglify": "~1.5.3",
"gulp-autoprefixer": "~6.0.0",
"gulp-cached": "~1.1.1",
"gulp-chmod": "~2.0.0",
"gulp-concat": "~2.6.1",
"gulp-if": "^2.0.2",
"gulp-git": "~2.8.0",
"gulp-livereload": "~4.0.0",
"gulp-plumber": "~1.2.0",
"gulp-pug": "~4.0.1",
"gulp-rename": "~1.4.0",
"gulp-sass": "~4.0.1",
"gulp-sourcemaps": "~2.6.4",
"gulp-uglify-es": "^1.0.4",
"minimist": "^1.2.0"
},
"dependencies": {
"bootstrap": "^4.1.3",
"jquery": "^3.3.1",
"popper.js": "^1.14.4"
}
}

View File

@@ -9,3 +9,4 @@
-e ../attract
-e ../flamenco
-e ../pillar-svnman
-e .

View File

@@ -0,0 +1,109 @@
/**
* Support for fetching & rendering assets by tags.
*/
(function($) {
/* How many nodes to load initially, and when clicked on the 'Load Next' link. */
const LOAD_INITIAL_COUNT = 5;
const LOAD_NEXT_COUNT = 3;
/* Renders a node as a <li> element, returns a jQuery object. */
function renderAsset(node) {
let li = $('<li>').addClass('tagged-asset');
let link = $('<a>')
.attr('href', '/nodes/' + node._id + '/redir')
.appendTo(li);
function warnNoPicture() {
li.addClass('warning');
link.text('no picture for node ' + node._id);
}
if (!node.picture) {
warnNoPicture();
return li;
}
// TODO: show 'loading' thingy
$.get('/api/files/' + node.picture)
.fail(function(error) {
let msg = xhrErrorResponseMessage(error);
li.addClass('error').text(msg);
})
.done(function(resp) {
// Render the picture if it has the proper size.
var show_variation = null;
if (typeof resp.variations != 'undefined') {
for (variation of resp.variations) {
if (variation.size != 'm') continue;
show_variation = variation;
break;
}
}
if (show_variation == null) {
warnNoPicture();
return;
}
let img = $('<img>')
.attr('alt', node.name)
.attr('src', variation.link)
.attr('width', variation.width)
.attr('height', variation.height);
link.append(img);
});
return li;
}
function loadNext(ul_element) {
let $ul = $(ul_element);
let tagged_assets = ul_element.tagged_assets; // Stored here by loadTaggedAssets().
let already_loaded = $ul.find('li.tagged-asset').length;
let load_next = $ul.find('li.load-next');
let nodes_to_load = tagged_assets.slice(already_loaded, already_loaded + LOAD_NEXT_COUNT);
for (node of nodes_to_load) {
let li = renderAsset(node);
load_next.before(li);
}
if (already_loaded + LOAD_NEXT_COUNT >= tagged_assets.length)
load_next.remove();
}
$.fn.loadTaggedAssets = function(api_base_url) {
this.each(function(index, ul_element) {
// TODO(Sybren): show a 'loading' animation.
$.get('/api/nodes/tagged/' + ul_element.dataset.assetTag)
.fail(function(error) {
let msg = xhrErrorResponseMessage(error);
$('<li>').addClass('error').text(msg).appendTo(ul_element);
})
.done(function(resp) {
// 'resp' is a list of node documents.
// Store the response on the DOM <ul>-element so that we can later render more.
ul_element.tagged_assets = resp;
// Here render the first N.
for (node of resp.slice(0, LOAD_INITIAL_COUNT)) {
let li = renderAsset(node);
li.appendTo(ul_element);
}
// Don't bother with a 'load next' link if there is no more.
if (resp.length <= LOAD_INITIAL_COUNT) return;
// Construct the 'load next' link.
let load_next = $('<li>').addClass('load-next');
let link = $('<a>')
.attr('href', 'javascript:void(0);')
.click(function() { loadNext(ul_element); return false; })
.text('Load next')
.appendTo(load_next);
load_next.appendTo(ul_element);
});
});
};
}(jQuery));

File diff suppressed because it is too large Load Diff

View File

@@ -10,9 +10,6 @@
li a.navbar-item
color: $color-text
.navbar-container
+container-behavior
.navbar-toggle
border: 2px solid $color-text-dark-primary
color: $color-text
@@ -267,22 +264,6 @@
+media-xs
margin-top: 20px
.navbar
.nav-item-sign-in
a.navbar-item
background-color: $color-primary
border: none
border-radius: 3px
color: white
height: auto
font-weight: bold
margin-top: 5px
margin-left: 10px
padding: 10px 20px
&:hover
background-color: lighten($color-primary, 10%)
box-shadow: none
.container.wide-on-sm
+media-sm
@@ -334,9 +315,7 @@ section.pricing
+button($color-primary, 3px, true)
h3
font:
size: 1.8em
family: $font-body
font-size: 1.8em
padding-bottom: 0
margin: 25px 0 0 10px

View File

@@ -1,26 +1,99 @@
@import ../../../pillar/src/styles/_normalize
@import ../../../pillar/src/styles/_config
@import ../../../pillar/src/styles/_utils
// Bootstrap variables and utilities.
@import "../../node_modules/bootstrap/scss/functions"
@import "../../node_modules/bootstrap/scss/variables"
@import "../../node_modules/bootstrap/scss/mixins"
/* Generic styles (comments, notifications, etc) come from base.css */
// Pillar variables and utilities.
@import "../../../pillar/src/styles/config"
@import "../../../pillar/src/styles/utils"
// Bootstrap components.
@import "../../node_modules/bootstrap/scss/root"
@import "../../node_modules/bootstrap/scss/reboot"
@import "../../node_modules/bootstrap/scss/type"
@import "../../node_modules/bootstrap/scss/images"
@import "../../node_modules/bootstrap/scss/code"
@import "../../node_modules/bootstrap/scss/grid"
@import "../../node_modules/bootstrap/scss/tables"
@import "../../node_modules/bootstrap/scss/forms"
@import "../../node_modules/bootstrap/scss/buttons"
@import "../../node_modules/bootstrap/scss/transitions"
@import "../../node_modules/bootstrap/scss/dropdown"
@import "../../node_modules/bootstrap/scss/button-group"
@import "../../node_modules/bootstrap/scss/input-group"
@import "../../node_modules/bootstrap/scss/custom-forms"
@import "../../node_modules/bootstrap/scss/nav"
@import "../../node_modules/bootstrap/scss/navbar"
@import "../../node_modules/bootstrap/scss/card"
@import "../../node_modules/bootstrap/scss/breadcrumb"
@import "../../node_modules/bootstrap/scss/pagination"
@import "../../node_modules/bootstrap/scss/badge"
@import "../../node_modules/bootstrap/scss/jumbotron"
@import "../../node_modules/bootstrap/scss/alert"
@import "../../node_modules/bootstrap/scss/progress"
@import "../../node_modules/bootstrap/scss/media"
@import "../../node_modules/bootstrap/scss/list-group"
@import "../../node_modules/bootstrap/scss/close"
@import "../../node_modules/bootstrap/scss/modal"
@import "../../node_modules/bootstrap/scss/tooltip"
@import "../../node_modules/bootstrap/scss/popover"
@import "../../node_modules/bootstrap/scss/carousel"
@import "../../node_modules/bootstrap/scss/utilities"
@import "../../node_modules/bootstrap/scss/print"
// Pillar components.
@import "../../../pillar/src/styles/apps_base"
@import "../../../pillar/src/styles/error"
@import "../../../pillar/src/styles/components/base"
@import "../../../pillar/src/styles/components/jumbotron"
@import "../../../pillar/src/styles/components/alerts"
@import "../../../pillar/src/styles/components/navbar"
@import "../../../pillar/src/styles/components/dropdown"
@import "../../../pillar/src/styles/components/footer"
@import "../../../pillar/src/styles/components/shortcode"
@import "../../../pillar/src/styles/components/statusbar"
@import "../../../pillar/src/styles/components/search"
@import "../../../pillar/src/styles/components/flyout"
@import "../../../pillar/src/styles/components/forms"
@import "../../../pillar/src/styles/components/inputs"
@import "../../../pillar/src/styles/components/buttons"
@import "../../../pillar/src/styles/components/popover"
@import "../../../pillar/src/styles/components/tooltip"
@import "../../../pillar/src/styles/components/checkbox"
@import "../../../pillar/src/styles/components/overlay"
@import "../../../pillar/src/styles/components/card"
@import "../../../pillar/src/styles/comments"
@import "../../../pillar/src/styles/notifications"
/* Blender Cloud specific styles */
@import ../../../pillar/src/styles/_project
@import ../../../pillar/src/styles/_project-sharing
@import ../../../pillar/src/styles/_project-dashboard
@import ../../../pillar/src/styles/_user
@import "../../../pillar/src/styles/_project"
@import "../../../pillar/src/styles/_project-sharing"
@import "../../../pillar/src/styles/_project-dashboard"
@import "../../../pillar/src/styles/_user"
@import _welcome
@import _homepage
@import _services
@import _about
@import ../../../pillar/src/styles/_search
@import ../../../pillar/src/styles/_organizations
@import "../../../pillar/src/styles/_search"
@import "../../../pillar/src/styles/_organizations"
/* services, about, etc */
@import ../../../pillar/src/styles/_pages
@import "../../../pillar/src/styles/_pages"
/* plugins are included here, don't include in base unless needed by other pillar apps */
@import ../../../pillar/src/styles/plugins/_jstree
@import ../../../pillar/src/styles/plugins/_js_select2
@import "../../../pillar/src/styles/plugins/_jstree"
@import "../../../pillar/src/styles/plugins/_js_select2"
/* CSS for pillar-font comes from fontello.com using static/assets/font/config.json */

View File

@@ -1,47 +1,88 @@
@import ../../../pillar/src/styles/_config
@import ../../../pillar/src/styles/_utils
// Bootstrap variables and utilities.
@import "../../node_modules/bootstrap/scss/functions"
@import "../../node_modules/bootstrap/scss/variables"
@import "../../node_modules/bootstrap/scss/mixins"
// Pillar variables and utilities.
@import "../../../pillar/src/styles/config"
@import "../../../pillar/src/styles/utils"
// Bootstrap components.
@import "../../node_modules/bootstrap/scss/root"
@import "../../node_modules/bootstrap/scss/reboot"
@import "../../node_modules/bootstrap/scss/type"
@import "../../node_modules/bootstrap/scss/images"
@import "../../node_modules/bootstrap/scss/code"
@import "../../node_modules/bootstrap/scss/grid"
@import "../../node_modules/bootstrap/scss/tables"
@import "../../node_modules/bootstrap/scss/forms"
@import "../../node_modules/bootstrap/scss/buttons"
@import "../../node_modules/bootstrap/scss/transitions"
@import "../../node_modules/bootstrap/scss/dropdown"
@import "../../node_modules/bootstrap/scss/button-group"
@import "../../node_modules/bootstrap/scss/input-group"
@import "../../node_modules/bootstrap/scss/custom-forms"
@import "../../node_modules/bootstrap/scss/nav"
@import "../../node_modules/bootstrap/scss/navbar"
@import "../../node_modules/bootstrap/scss/card"
@import "../../node_modules/bootstrap/scss/breadcrumb"
@import "../../node_modules/bootstrap/scss/pagination"
@import "../../node_modules/bootstrap/scss/badge"
@import "../../node_modules/bootstrap/scss/jumbotron"
@import "../../node_modules/bootstrap/scss/alert"
@import "../../node_modules/bootstrap/scss/progress"
@import "../../node_modules/bootstrap/scss/media"
@import "../../node_modules/bootstrap/scss/list-group"
@import "../../node_modules/bootstrap/scss/close"
@import "../../node_modules/bootstrap/scss/modal"
@import "../../node_modules/bootstrap/scss/tooltip"
@import "../../node_modules/bootstrap/scss/popover"
@import "../../node_modules/bootstrap/scss/carousel"
@import "../../node_modules/bootstrap/scss/utilities"
@import "../../node_modules/bootstrap/scss/print"
// Pillar components.
@import "../../../pillar/src/styles/apps_base"
@import "../../../pillar/src/styles/error"
@import "../../../pillar/src/styles/components/base"
@import "../../../pillar/src/styles/components/jumbotron"
@import "../../../pillar/src/styles/components/alerts"
@import "../../../pillar/src/styles/components/navbar"
@import "../../../pillar/src/styles/components/dropdown"
@import "../../../pillar/src/styles/components/footer"
@import "../../../pillar/src/styles/components/shortcode"
@import "../../../pillar/src/styles/components/statusbar"
@import "../../../pillar/src/styles/components/search"
@import "../../../pillar/src/styles/components/flyout"
@import "../../../pillar/src/styles/components/inputs"
@import "../../../pillar/src/styles/components/buttons"
@import "../../../pillar/src/styles/components/popover"
@import "../../../pillar/src/styles/components/tooltip"
@import "../../../pillar/src/styles/components/checkbox"
@import "../../../pillar/src/styles/components/overlay"
@import "../../../pillar/src/styles/components/card"
@import "../../../pillar/src/styles/notifications"
@import "../../../pillar/src/styles/_search"
$node-latest-thumbnail-size: 160px
$node-latest-gallery-thumbnail-size: 200px
body
background-color: white
.page-body
background-color: white
nav.navbar
background-color: white
.navbar-header
+media-xs
width: 100%
.navbar-brand
color: $color-text
li a.navbar-item
color: $color-text
&:hover
color: black
&:focus
color: black
&.active
color: black
.dropdown.open
a
background-color: white
.dropdown.libraries
&:hover
background: none
ul.dropdown-menu
background-color: white
li
a
color: $color-text
&:hover
color: black
background-color: white
.navbar-container
+container-behavior
.navbar-toggle
border: none
color: $color-text
@@ -57,11 +98,11 @@ nav.navbar
.node-details-container
max-width: 620px
font-family: $font-body
font-size: 1.3em
line-height: 1.5em
margin: 0 auto 40px auto
padding-bottom: 40px
+media-xs
padding-left: 10px
padding-right: 10px
@@ -106,20 +147,10 @@ section
border-top: thin solid $color-background
margin: 0 auto
a.btn
margin: 20px auto
font-size: 1.3em
padding: 9px 18px
border-radius: 8px
color: $color-text-dark
.navbar-secondary
max-width: 620px
margin: 0 auto
.navbar-container
border-bottom: 1px solid #dddddd
.navbar-collapse
padding-left: 0

View File

@@ -0,0 +1,26 @@
include ../mixins/components
| {% macro navigation_tabs(title) %}
+nav-secondary()
+nav-secondary-link(
class="{% if title == 'homepage' %}active{% endif %}",
href="{{ url_for('main.homepage') }}")
| Activity
+nav-secondary-link(
class="{% if title == 'home' %}active{% endif %}",
href="{{ url_for('projects.home_project') }}")
| Home
+nav-secondary-link(
class="{% if title == 'dashboard' %}active{% endif %}",
href="{{ url_for('projects.index') }}")
| My Projects
| {% if current_user.has_organizations() %}
+nav-secondary-link(
class="{% if title == 'organizations' %}active{% endif %}",
href="{{ url_for('pillar.web.organizations.index') }}")
| My Organizations
| {% endif %}
| {% endmacro %}

View File

@@ -193,16 +193,16 @@ style.
small October 30th, 2015
.page-card-summary
| Introducing integrated blogs in Blender Cloud projects. Glass Half is the first project fully developed on the new Blender Cloud. It's also the first and only project to have share its
a(href='https://cloud.blender.org/p/glass-half/5627bb22f0e7220061109c9f') animation dailies
a(href='/p/glass-half/5627bb22f0e7220061109c9f') animation dailies
| ! But the biggest outcome from Glass Half was definitely
a(href='https://cloud.blender.org/p/glass-half/569d6044c379cf445461293e') Flexirig
a(href='/p/glass-half/569d6044c379cf445461293e') Flexirig
| .
.page-card-side
a(href='https://cloud.blender.org/p/glass-half/blog/glass-half-premiere')
a(href='/p/glass-half/blog/glass-half-premiere')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_10_30_glass.jpg') }}", alt="Glass Half")
section.page-card
.page-card-side
a(href='https://cloud.blender.org/blog/new-art-gallery-with-gleb-alexandrov')
a(href='/blog/new-art-gallery-with-gleb-alexandrov')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_11_19_art.jpg') }}", alt="Art Gallery")
.page-card-side
h2.page-card-title
@@ -218,11 +218,11 @@ style.
.page-card-summary
| With so much going on in the Cloud at at the studio. The Blender Institute Podcast was born! Sharing our daily studio work, Blender community news, and interacting with the awesome Blender Cloud subscribers.
.page-card-side
a(href='https://cloud.blender.org/blog/introducing-blender-institute-podcast')
a(href='/blog/introducing-blender-institute-podcast')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_11_24_bip.jpg') }}", alt="Blender Institute Podcast")
section.page-card
.page-card-side
a(href='https://cloud.blender.org/p/blenrig/blog/welcome-to-the-blenrig-project')
a(href='/p/blenrig/blog/welcome-to-the-blenrig-project')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_12_01_blenrig.jpg') }}", alt="Blenrig")
.page-card-side
h2.page-card-title
@@ -238,11 +238,11 @@ style.
.page-card-summary
| The biggest source for CC0/Public Domain textures on the interwebs goes live. First as beta, as a quick gift right before Xmas 2015!
.page-card-side
a(href='https://cloud.blender.org/blog/new-texture-library')
a(href='/blog/new-texture-library')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_12_23_textures.jpg') }}", alt="Texture Library")
section.page-card
.page-card-side
a(href='https://cloud.blender.org/blog/nraryew-the-character-lib')
a(href='/blog/nraryew-the-character-lib')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_01_05_charlib.jpg') }}", alt="Character Library")
.page-card-side
h2.page-card-title
@@ -262,11 +262,11 @@ style.
a(href='https://www.youtube.com/watch?v=kQH897V9bDg&list=PLI2TkLMzCSr_H6ppmzDtU0ut0RwxGvXjv') nicely edited Weekly video reports
| .
.page-card-side
a(href='https://cloud.blender.org/p/caminandes-3/blog/caminandes-llamigos')
a(href='/p/caminandes-3/blog/caminandes-llamigos')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_01_30_llamigos.jpg') }}", alt="Caminandes: Llamigos")
section.page-card
.page-card-side
a(href='https://cloud.blender.org/blog/welcome-sybren')
a(href='/blog/welcome-sybren')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_03_01_sybren.jpg') }}", alt="Dr. Sybren!")
.page-card-side
h2.page-card-title
@@ -282,11 +282,11 @@ style.
.page-card-summary
| Create your own private projects on Blender Cloud.
.page-card-side
a(href='https://cloud.blender.org/blog/welcome-sybren')
a(href='/blog/welcome-sybren')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_03_projects.jpg') }}", alt="Projects")
section.page-card
.page-card-side
a(href='https://cloud.blender.org/blog/introducing-project-sharing')
a(href='/blog/introducing-project-sharing')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_09_projectsharing.jpg') }}", alt="Sharing")
.page-card-side
h2.page-card-title
@@ -302,11 +302,11 @@ style.
.page-card-summary
| Browse the textures from within Blender!
.page-card-side
a(href='https://cloud.blender.org/blog/introducing-project-sharing')
a(href='/blog/introducing-project-sharing')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_11_addon.jpg') }}", alt="Blender Cloud Add-on")
section.page-card
.page-card-side
a(href='https://cloud.blender.org/blog/introducing-private-texture-libraries')
a(href='/blog/introducing-private-texture-libraries')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_23_privtextures.jpg') }}", alt="Texture Libraries")
.page-card-side
h2.page-card-title
@@ -322,11 +322,11 @@ style.
.page-card-summary
| Sync your Blender preferences across multiple devices.
.page-card-side
a(href='https://cloud.blender.org/blog/introducing-blender-sync')
a(href='/blog/introducing-blender-sync')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_06_30_sync.jpg') }}", alt="Blender Sync")
section.page-card
.page-card-side
a(href='https://cloud.blender.org/blog/introducing-image-sharing')
a(href='/blog/introducing-image-sharing')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_07_14_image.jpg') }}", alt="Image Sharing")
.page-card-side
h2.page-card-title
@@ -337,21 +337,21 @@ style.
section.page-card
.page-card-side
h2.page-card-title
a(href='https://cloud.blender.org/blog/introducing-the-hdri-library')
a(href='/blog/introducing-the-hdri-library')
| HDRI Library
small July 27th, 2016
.page-card-summary
| High-dynamic range images are now available on Blender Cloud! With their own special viewer. Also available via the Blender Cloud add-on.
.page-card-side
a(href='https://cloud.blender.org/blog/introducing-the-hdri-library')
a(href='/blog/introducing-the-hdri-library')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_07_27_hdri.jpg') }}", alt="HDRI Library")
section.page-card
.page-card-side
a(href='https://cloud.blender.org/blog/introducing-the-hdri-library')
a(href='/blog/introducing-the-hdri-library')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_12_06_toon.jpg') }}", alt="Hdri Library")
.page-card-side
h2.page-card-title
a(href='https://cloud.blender.org/blog/new-training-toon-character-workflow')
a(href='/blog/new-training-toon-character-workflow')
| Toon Character Workflow
small December 6th, 2016
.page-card-summary
@@ -366,7 +366,7 @@ style.
| to all resources and training produced so far!
a.page-card-cta(href='https://store.blender.org/product/membership/') Subscribe
.page-card-side
a(href='https://cloud.blender.org/p/agent-327')
a(href='/p/agent-327')
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2017_03_10_agent.jpg') }}", alt="Agent 327")

View File

@@ -6,7 +6,7 @@
| {% block og %}
meta(property="og:type", content="website")
meta(property="og:url", content="https://cloud.blender.org/")
meta(property="og:url", content="{{ request.url }}")
meta(property="og:title", content="Blender Cloud")
meta(name="twitter:title", content="Blender Cloud")
@@ -18,238 +18,229 @@ meta(property="og:image", content="{% if main_project.picture_header %}{{ main_p
meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_project.picture_header.thumbnail('l', api=api) }}{% else %}{{ url_for('static', filename='assets/img/backgrounds/background_agent327_04.jpg')}}{% endif %}")
| {% endblock %}
| {% block navigation_tabs %}
| {{ navigation_tabs(title) }}
| {% endblock navigation_tabs %}
| {% block body %}
.dashboard-container
section.dashboard-main
.container-fluid.dashboard-container.imgs-fluid
.row
.col-md-8
section.blog
ul.list-unstyled
| {% if latest_posts %}
| {% for node in latest_posts %}
| {{ render_blog_post(node) }}
| {% endfor %}
| {% else %}
li
| No blog entries... yet!
| {% endif %}
section.blog-stream
ul.blog-stream__list
| {% if latest_posts %}
| {% for node in latest_posts %}
| {{ render_blog_post(node) }}
| {% endfor %}
| {% else %}
li
.blog-stream__list-details
ul.meta
li.when No blog entries... yet!
| {% endif %}
.d-block.text-center
a.d-inline-block.p-3.text-muted(href="{{ url_for('main.main_blog') }}")
| See All Blog Posts
.more
a(href="{{ url_for('main.main_blog') }}")
| See All Blog Posts
a.d-inline-block.p-3.text-muted(
href="{{ url_for('main.feeds_blogs') }}",
title="Blogs Feed",
data-toggle="tooltip",
data-placement="left")
i.pi-rss
| RSS Feed
a.feed(
href="{{ url_for('main.feeds_blogs') }}",
title="Blogs Feed",
data-toggle="tooltip",
data-placement="left")
i.pi-rss
.col-md-4
.dashboard-sidebar
section.pt-3
h6.title-underline In Production
a(href="/p/spring/")
img(src="{{ url_for('static', filename='assets/img/projects/spring_450x150.jpg')}}")
p.text-muted.pt-2.
A poetic short film about a mountain spirit and her wise little dog. #[a(href="/p/spring/") Check it out].
section.dashboard-secondary
| {{ navigation_tabs(title) }}
section.stream.py-3
h6.title-underline Latest Assets
section.dashboard-in-production
h4 In Production
span.section-lead.
Check out these projects currently in production!
a.in-production-project(href="https://cloud.blender.org/p/spring/")
img(src="{{ url_for('static', filename='assets/img/projects/spring_450x150.jpg')}}")
p.
#[strong Spring] - A poetic short film about a mountain spirit and her wise little dog.
a.in-production-project(href="https://cloud.blender.org/p/hero/")
img(src="{{ url_for('static', filename='assets/img/projects/hero_450x150.jpg')}}")
p.
#[strong Hero] - A '2D' trailer-style movie focused on getting grease pencil
production ready for Blender 2.8.
section.stream
h4 Latest Assets
ul.activity-stream__list
| {% for n in activity_stream %}
li(
class="{{ n.node_type }} {{ n.properties.content_type }} {% if n.picture %}with-picture{% endif %}",
data-url="{{ n.url }}")
a.activity-stream__list-thumbnail(
class="{{ n.properties.content_type }}",
href="{{ n.url }}")
| {% if n.picture %}
img(src="{{ n.picture.thumbnail('m', api=api) }}")
| {% endif %}
.activity-stream__list-thumbnail-icon
| {% if n.node_type == 'asset' %}
| {% if n.properties.content_type == 'video' %}
i.pi-play
| {% elif n.properties.content_type == 'image' %}
i.pi-picture
| {% elif n.properties.content_type == 'file' %}
i.pi-file-archive
| {% else %}
i.pi-folder
| {% endif %}
| {% endif %}
.activity-stream__list-details
a.title(href="{{ n.url }}")
| {{ n.name }}
| {% if n.permissions.world %}
.ribbon
span free
| {% endif %}
ul.meta
| {% if not n.picture %}
li.when
a(href="{{ n.url }}", title="{{ n._created }}") {{ n._created | pretty_date_time }}
li.who {{ n.user.full_name }}
| {% endif %}
| {% if n.attached_to %}
li.where-parent
a(href="{{ n.attached_to.url }}") {{ n.attached_to.name }}
| {% endif %}
li.where-project
a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}
li.what
| {% if n.node_type == 'asset' %}
| {{ n.properties.content_type | undertitle }}
ul.activity-stream__list.list-unstyled
| {% for n in activity_stream %}
li(
class="{{ n.node_type }} {{ n.properties.content_type }} {% if n.picture %}with-picture{% endif %}",
data-url="{{ n.url }}")
a.activity-stream__list-thumbnail(
class="{{ n.properties.content_type }}",
href="{{ n.url }}")
| {% if n.picture %}
img(src="{{ n.picture.thumbnail('m', api=api) }}")
| {% endif %}
| {% if n.picture %}
ul.meta.extra
li.when
a(href="{{ n.url }}", title="{{ n._created }}") {{ n._created | pretty_date_time }}
li.who {{ n.user.full_name }}
| {% endif %}
| {% endfor %}
li.activity-stream__list-item.empty#activity-stream__empty
| No items to list.
.activity-stream__list-thumbnail-icon
| {% if n.node_type == 'asset' %}
| {% if n.properties.content_type == 'video' %}
i.pi-play
| {% elif n.properties.content_type == 'image' %}
i.pi-picture
| {% elif n.properties.content_type == 'file' %}
i.pi-file-archive
| {% else %}
i.pi-folder
| {% endif %}
| {% endif %}
section.random-asset
h4
a(href="/search") Explore the Cloud
span.section-lead Random selection of the best assets &amp; tutorials
.activity-stream__list-details
a.title(href="{{ n.url }}")
| {{ n.name }}
ul.random-asset__list
| {% for n in random_featured %}
| {% if n.picture and loop.first %}
li.random-asset__list-item.project
| {% if n.project.picture_square %}
a.random-asset__list-thumbnail(
href="{{ n.project.url }}")
img.image(src="{{ n.project.picture_square.thumbnail('s', api=api) }}")
| {% endif %}
.random-asset__list-details
a.title(href="{{ n.project.url }}") {{ n.project.name }}
| {% if n.project.summary %}
ul.meta
li.what
a(href="{{ n.project.url }}") {{ n.project.summary }}
| {% endif %}
| {% if n.permissions.world %}
.ribbon
span free
| {% endif %}
ul.list-unstyled.d-flex.text-muted
| {% if not n.picture %}
li.when
a(href="{{ n.url }}", title="{{ n._created }}") {{ n._created | pretty_date_time }}
li.who {{ n.user.full_name }}
| {% endif %}
li.random-asset__list-item.featured
| {% if n.permissions.world %}
.ribbon
span free
| {% endif %}
a.random-asset__thumbnail(
href="{{ n.url }}",
class="{{ n.properties.content_type }}")
| {% if n.picture %}
img(src="{{ n.picture.thumbnail('l', api=api) }}")
| {% if n.attached_to %}
li.where-parent
a(href="{{ n.attached_to.url }}") {{ n.attached_to.name }}
| {% endif %}
li.where-project
a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}
li.what
| {% if n.node_type == 'asset' %}
| {{ n.properties.content_type | undertitle }}
| {% endif %}
| {% if n.properties.content_type == 'video' %}
i.pi-play
| {% endif %}
| {% if n.picture %}
ul.list-unstyled.d-flex.text-muted.extra
li.when
a(href="{{ n.url }}", title="{{ n._created }}") {{ n._created | pretty_date_time }}
li.who {{ n.user.full_name }}
| {% endif %}
| {% endfor %}
| {% endif %}
li.activity-stream__list-item.empty#activity-stream__empty
| No items to list.
a.title(href="{{ n.url }}")
| {{ n.name }}
ul.meta
li.what
a(href="{{ n.url }}")
| {% if n.properties.content_type %}{{ n.properties.content_type | undertitle }}{% else %}Folder{% endif %}
li.where
a(href="{{ n.project.url }}")
| {{ n.project.name }}
| {% else %}
li
| {% if n.permissions.world %}
.ribbon
span free
| {% endif %}
a.random-asset__list-thumbnail(
href="{{ n.url }}",
class="{{ n.properties.content_type }}")
| {% if n.picture %}
img.image(src="{{ n.picture.thumbnail('s', api=api) }}")
section.random-asset.py-3
h6.title-underline
a(href="/search") Explore the Cloud
.pb-3.text-muted Random selection of the best assets &amp; tutorials
ul.random-asset__list.list-unstyled
| {% for n in random_featured %}
| {% if n.picture and loop.first %}
li.random-asset__list-item.project
| {% if n.project.picture_square %}
a.random-asset__list-thumbnail(
href="{{ n.project.url }}")
img.image(src="{{ n.project.picture_square.thumbnail('s', api=api) }}")
| {% endif %}
.random-asset__list-details
a.title(href="{{ n.project.url }}") {{ n.project.name }}
| {% if n.project.summary %}
ul.list-unstyled.d-flex.text-muted
li.what
a(href="{{ n.project.url }}") {{ n.project.summary }}
| {% endif %}
li.random-asset__list-item.featured
| {% if n.permissions.world %}
.ribbon
span free
| {% endif %}
a.random-asset__thumbnail(
href="{{ n.url }}",
class="{{ n.properties.content_type }}")
| {% if n.picture %}
img(src="{{ n.picture.thumbnail('l', api=api) }}")
| {% if n.properties.content_type == 'video' %}
i.pi-play
| {% endif %}
| {% endif %}
a.title(href="{{ n.url }}")
| {{ n.name }}
ul.list-unstyled.d-flex.text-muted
li.what
a(href="{{ n.url }}")
| {% if n.properties.content_type %}{{ n.properties.content_type | undertitle }}{% else %}Folder{% endif %}
li.where
a(href="{{ n.project.url }}")
| {{ n.project.name }}
| {% else %}
| {% if n.properties.content_type == 'video' %}
i.pi-film-thick
| {% elif n.properties.content_type == 'image' %}
i.pi-picture
| {% elif n.properties.content_type == 'file' %}
i.pi-file-archive
li
| {% if n.permissions.world %}
.ribbon
span free
| {% endif %}
a.random-asset__list-thumbnail(
href="{{ n.url }}",
class="{{ n.properties.content_type }}")
| {% if n.picture %}
img.image(src="{{ n.picture.thumbnail('s', api=api) }}")
| {% else %}
| {% if n.properties.content_type == 'video' %}
i.pi-film-thick
| {% elif n.properties.content_type == 'image' %}
i.pi-picture
| {% elif n.properties.content_type == 'file' %}
i.pi-file-archive
| {% else %}
i.pi-folder
| {% endif %}
| {% endif %}
.random-asset__list-details
a.title(href="{{ n.url }}") {{ n.name }}
ul.list-unstyled.d-flex.text-muted
li.what
a(href="{{ n.url }}")
| {% if n.properties.content_type %}{{ n.properties.content_type }}{% else %}Folder{% endif %}
li.where
a(href="{{ n.project.url }}") {{ n.project.name }}
| {% endif %}
| {% endfor %}
section.comments.py-3
h6.title-underline Latest Comments
ul.list-unstyled
| {% if latest_comments %}
| {% for n in latest_comments %}
li(
class="{{ n.node_type }}",
data-url="{{ n.url }}")
a.comment-content(href="{{ n.url }}")
| {{ n.properties.content | striptags | truncate(200) }}
ul.list-unstyled.d-flex.text-muted
li.who {{ n.user.full_name }}
| {% if n.attached_to %}
li.where-parent
a(href="{{ n.attached_to.url }}") {{ n.attached_to.name }}
| {% endif %}
li.when
a(href="{{ n.url }}", title="{{ n._created }}")
| {{ n._created | pretty_date_time }}
| {% endfor %}
| {% else %}
i.pi-folder
li.activity-stream__list-item.empty#activity-stream__empty
| No comments... yet!
| {% endif %}
| {% endif %}
.random-asset__list-details
a.title(href="{{ n.url }}") {{ n.name }}
ul.meta
li.what
a(href="{{ n.url }}")
| {% if n.properties.content_type %}{{ n.properties.content_type }}{% else %}Folder{% endif %}
li.where
a(href="{{ n.project.url }}") {{ n.project.name }}
| {% endif %}
| {% endfor %}
section.comments
h4 Latest Comments
ul
| {% if latest_comments %}
| {% for n in latest_comments %}
li(
class="{{ n.node_type }}",
data-url="{{ n.url }}")
a.comment-content(href="{{ n.url }}")
| {{ n.properties.content | striptags | truncate(200) }}
ul.meta
li.who {{ n.user.full_name }}
| {% if n.attached_to %}
li.where-parent
a(href="{{ n.attached_to.url }}") {{ n.attached_to.name }}
| {% endif %}
li.when
a(href="{{ n.url }}", title="{{ n._created }}")
| {{ n._created | pretty_date_time }}
| {% endfor %}
| {% else %}
li.activity-stream__list-item.empty#activity-stream__empty
| No comments... yet!
| {% endif %}
| {% endblock %}

View File

@@ -3,7 +3,7 @@ html(lang="en")
head
meta(charset="utf-8")
title {% if self.page_title() %}{% block page_title %}{% endblock %} — {% endif %}Blender Cloud
meta(name="viewport", content="width=device-width, initial-scale=1.0")
meta(name="viewport", content="width=device-width, initial-scale=1, shrink-to-fit=no")
meta(name="description", content="Blender Cloud is a web based service developed by Blender Institute that allows people to access the training videos and all the data from the open projects.")
meta(name="author", content="Blender Institute")
meta(name="theme-color", content="#3e92aa")
@@ -19,7 +19,7 @@ html(lang="en")
| {% block og %}
meta(property="og:title", content="Blender Cloud")
meta(property="og:url", content="https://cloud.blender.org")
meta(property="og:url", content="{{ request.url }}")
meta(property="og:type", content="website")
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_gleb_locomotive.jpg')}}")
meta(property="og:description", content="Blender Cloud is a web based service developed by Blender Institute that allows people to access the training videos and all the data from the open projects.")
@@ -46,14 +46,10 @@ html(lang="en")
link(href="{{ url_for('static', filename='assets/img/favicon.png') }}", rel="shortcut icon")
link(href="{{ url_for('static', filename='assets/img/apple-touch-icon-precomposed.png') }}", rel="icon apple-touch-icon-precomposed", sizes="192x192")
link(href="{{ url_for('static_pillar', filename='assets/css/vendor/bootstrap.min.css') }}", rel="stylesheet")
link(href="{{ url_for('static', filename='assets/google-font-roboto/roboto.css') }}", rel="stylesheet")
| {% block head %}{% endblock %}
| {% block css %}
link(href="{{ url_for('static_pillar', filename='assets/css/font-pillar.css') }}", rel="stylesheet")
link(href="{{ url_for('static_pillar', filename='assets/css/base.css') }}", rel="stylesheet")
| {% if title == 'blog' %}
link(href="{{ url_for('static_pillar', filename='assets/css/blog.css') }}", rel="stylesheet")
| {% else %}
@@ -61,216 +57,331 @@ html(lang="en")
| {% endif %}
| {% endblock css %}
| {% if not title %}{% set title="default" %}{% endif %}
| {% if not title %}{% set title="default" %}{% endif %}
body(class="{{ title }}")
.container-page
| {% with messages = get_flashed_messages(with_categories=True) %}
| {% if messages %}
| {% with messages = get_flashed_messages(with_categories=True) %}
| {% if messages %}
| {% for (category, message) in messages %}
.alert(role="alert", class="alert-{{ category }}")
i.alert-icon(class="{{ category }}")
span {{ message }}
button.close(type="button", data-dismiss="alert")
i.pi-cancel
| {% endfor %}
| {% endif %}
| {% endwith %}
| {% for (category, message) in messages %}
.alert(role="alert", class="alert-{{ category }}")
i.alert-icon(class="{{ category }}")
span {{ message }}
button.close(type="button", data-dismiss="alert")
i.pi-cancel
| {% endfor %}
nav.navbar.navbar-expand-md.fixed-top.bg-white
a.navbar-brand(
href="{{ url_for('main.homepage') }}",
title="Blender Cloud")
span.app-logo
i.pi-blender-cloud
| {% endif %}
| {% endwith %}
button.navbar-toggler.text-light(
data-target=".navbar-collapse",
data-toggle="collapse",
type="button")
span.sr-only Toggle navigation
span.navbar-toggler-icon.d-flex.align-items-center
i.pi-menu
nav.navbar
.navbar-container
header.navbar-header
button.navbar-toggle(data-target=".navbar-collapse", data-toggle="collapse", type="button")
span.sr-only Toggle navigation
i.pi-menu
a.navbar-brand(
href="{{ url_for('main.homepage') }}",
title="Blender Cloud")
span.app-logo
i.pi-blender-cloud
| {% block navigation_tabs %}
| {% endblock navigation_tabs %}
| {% block navigation_search %}
.search-input
input#cloud-search(
type="text",
placeholder="Search assets, tutorials...")
i.search-icon.pi-search
| {% endblock navigation_search %}
| {% block navigation_search %}
// TODO (pablo) - bring it back asap
.search-input
input#cloud-search(
type="text",
placeholder="Search assets, tutorials...")
i.search-icon.pi-search
| {% endblock navigation_search %}
nav.collapse.navbar-collapse
ul.nav.navbar-nav.navbar-right
| {% if node and node.properties and node.properties.category %}
| {% set category = node.properties.category %}
| {% else %}
| {% set category = title %}
| {% endif %}
.collapse.navbar-collapse
ul.navbar-nav.ml-auto
| {% if node and node.properties and node.properties.category %}
| {% set category = node.properties.category %}
| {% else %}
| {% set category = title %}
| {% endif %}
| {% block navigation_sections %}
| {% block navigation_sections %}
li
a.navbar-item(
href="{{ url_for('main.main_blog') }}",
title="Blender Cloud Blog",
data-toggle="tooltip",
data-placement="bottom",
class="{% if category == 'blog' %}active{% endif %}")
span Blog
li.dropdown
a.navbar-item.dropdown-toggle(
href="",
data-toggle="dropdown",
title="Libraries")
span Libraries
i.pi-angle-down
ul.dropdown-menu.p-0
li
a.navbar-item(
href="{{ url_for('main.main_blog') }}",
title="Blender Cloud Blog",
href="{{ url_for('projects.view', project_url='hdri') }}",
title="HDRI Library",
data-toggle="tooltip",
data-placement="bottom",
class="{% if category == 'blog' %}active{% endif %}")
span Blog
li(class="dropdown libraries")
a.navbar-item.dropdown-toggle(
href="",
data-toggle="dropdown",
title="Libraries")
span Libraries
i.pi-angle-down
ul.dropdown-menu
li
a.navbar-item(
href="{{ url_for('projects.view', project_url='hdri') }}",
title="HDRI Library",
data-toggle="tooltip",
data-placement="left")
i.pi-globe
| HDRI
li
a.navbar-item(
href="{{ url_for('projects.view', project_url='textures') }}",
title="Textures Library",
data-toggle="tooltip",
data-placement="left")
i.pi-folder-texture
| Textures
li
a.navbar-item(
href="{{ url_for('projects.view', project_url='characters') }}",
title="Character Library",
data-toggle="tooltip",
data-placement="left")
i.pi-character
| Characters
li(class="dropdown libraries")
a.navbar-item.dropdown-toggle(
href="",
data-toggle="dropdown",
title="Training")
span Training
i.pi-angle-down
ul.dropdown-menu
li
a.navbar-item(
href="{{ url_for('cloud.courses') }}",
title="Courses",
data-toggle="tooltip",
data-placement="left")
i.pi-graduation-cap
| Courses
li
a.navbar-item(
href="{{ url_for('cloud.workshops') }}",
title="Workshops",
data-toggle="tooltip",
data-placement="left")
i.pi-lightbulb
| Workshops
li
a.navbar-item(
href="{{ url_for('projects.view', project_url='gallery') }}",
title="Curated artwork collection",
data-toggle="tooltip",
data-placement="left")
i.pi-image
| Art Gallery
data-placement="left")
i.pi-globe
| HDRI
li
a.navbar-item(
href="{{ url_for('cloud.open_projects') }}",
title="Browse all the Open Projects",
href="{{ url_for('projects.view', project_url='textures') }}",
title="Textures Library",
data-toggle="tooltip",
data-placement="bottom",
class="{% if category in ['open-projects', 'film'] %}active{% endif %}")
span Open Projects
data-placement="left")
i.pi-folder-texture
| Textures
li
a.navbar-item(
href="{{ url_for('cloud.services') }}",
title="Blender Cloud Services",
href="{{ url_for('projects.view', project_url='characters') }}",
title="Character Library",
data-toggle="tooltip",
data-placement="bottom",
class="{% if category == 'services' %}active{% endif %}")
span Services
| {% endblock navigation_sections %}
data-placement="left")
i.pi-character
| Characters
| {% if current_user.is_anonymous %}
li(class="dropdown")
a.navbar-item.dropdown-toggle(
href="{{ url_for('cloud.workshops') }}"
data-toggle="dropdown",
title="Training")
span Training
i.pi-angle-down
ul.dropdown-menu
li
a.navbar-item(
href="https://store.blender.org/product/membership/",
title="Sign up") Sign up
| {% endif %}
href="{{ url_for('cloud.courses') }}",
title="Courses",
data-toggle="tooltip",
data-placement="left")
i.pi-graduation-cap
| Courses
li
a.navbar-item(
href="{{ url_for('cloud.workshops') }}",
title="Workshops",
data-toggle="tooltip",
data-placement="left")
i.pi-lightbulb
| Workshops
li
a.navbar-item(
href="{{ url_for('projects.view', project_url='gallery') }}",
title="Curated artwork collection",
data-toggle="tooltip",
data-placement="left")
i.pi-image
| Art Gallery
li(class="dropdown")
a.navbar-item.dropdown-toggle(
href="{{ url_for('cloud.open_projects') }}",
title="Browse all the Open Projects",
data-toggle="dropdown",
class="{% if category in ['open-projects', 'film'] %}active{% endif %}")
span Open Projects
i.pi-angle-down
| {% block navigation_user %}
ul.dropdown-menu
li
a.navbar-item(href="/p/spring")
span.px-2 Spring
li
a.navbar-item(href="/p/hero")
span.px-2 Hero
li
a.navbar-item(href="/p/dailydweebs")
span.px-2 The Daily Dweebs
li
a.navbar-item(href="/p/agent-327")
span.px-2 Agent 327
li
a.navbar-item(href="/p/caminandes-3")
span.px-2 Caminandes: Llamigos
| {% include 'menus/notifications.html' %}
| {% include 'menus/user.html' %}
li.dropdown-divider
| {% endblock navigation_user %}
li
a.navbar-item(href="{{ url_for('cloud.open_projects') }}")
span.pl-2 All Open Projects
li(class="dropdown")
a.navbar-item.dropdown-toggle(
href="{{ url_for('cloud.services') }}",
title="Blender Cloud Services",
data-toggle="dropdown",
class="{% if category == 'services' %}active{% endif %}")
span Services
i.pi-angle-down
.page-content
#search-overlay
| {% block page_overlay %}
#page-overlay
| {% endblock page_overlay %}
.page-body
| {% block body %}{% endblock %}
ul.dropdown-menu
li
a.navbar-item(
href="/attract",
title="Production Management",
data-toggle="tooltip",
data-placement="left")
i.pi-attract
| Attract
li
a.navbar-item(
href="/flamenco",
title="Render Management",
data-toggle="tooltip",
data-placement="left")
i.pi-flamenco
| Flamenco
li
a.navbar-item(
href="/services#blender-cloud-add-on",
title="Blender Sync, Texture Browser and more",
data-toggle="tooltip",
data-placement="left")
i.pi-blender
| Blender Cloud Add-on
li.dropdown-divider
li
a.navbar-item(
href="{{ url_for('cloud.services') }}",
title="All Blender Cloud services",
data-toggle="tooltip",
data-placement="left")
i.pi-list
| All Services
| {% endblock navigation_sections %}
| {% block navigation_user %}
| {% include 'menus/notifications.html' %}
| {% include 'menus/user.html' %}
| {% endblock navigation_user %}
| {% if current_user.is_anonymous %}
li.pt-1
a.btn.btn-sm.btn-primary.px-3.mx-1(
href="https://store.blender.org/product/membership/",
title="Sign up") Sign up
| {% endif %}
.page-content
#search-overlay
| {% block page_overlay %}
#page-overlay
| {% endblock page_overlay %}
.page-body
| {% block body %}{% endblock %}
| {% block footer_container %}
#footer-container
.footer-wrapper
| {% block footer_navigation %}
#footer-navigation
.footer-navigation
.container
.row
.col-md-4.col-xs-6
.footer-support
h4 Support & Feedback
p.
Let us know what you think or if you have any issues
just write to cloudsupport at blender dot org
.col-md-2.col-xs-6
ul.footer-social
li
a(href="https://www.facebook.com/BlenderCloudOfficial/",
title="Follow us on Facebook")
i.pi-social-facebook
li
a(href="https://twitter.com/Blender_Cloud",
title="Follow us on Twitter")
i.pi-social-twitter
.col-md-2.col-xs-6
h4
a(href="{{ url_for('main.homepage') }}")
| Blender Cloud
ul.footer-links
i.pi-blender-cloud-logo
p.pl-2.
Blender Cloud is the creative hub for your projects,
powered by Free and Open Source Software.
h5.d-flex
a.px-2(href="https://twitter.com/Blender_Cloud",
title="Follow us on Twitter")
i.pi-social-youtube
a.px-2(href="https://twitter.com/Blender_Cloud",
title="Follow us on Twitter")
i.pi-social-twitter
a.px-2(href="https://www.facebook.com/BlenderCloudOfficial/",
title="Follow us on Facebook")
i.pi-social-facebook
.col-md-2.col-xs-6
h7.font-weight-bold
| TRAINING
ul.list-unstyled
li
a(href="{{ url_for('cloud.courses') }}")
| Courses
li
a(href="{{ url_for('cloud.workshops') }}")
| Workshops
li
a(href="{{ url_for('projects.view', project_url='gallery') }}")
| Art Gallery
.col-md-2.col-xs-6
h7.font-weight-bold
| LIBRARIES
ul.list-unstyled
li
a(href="{{ url_for('main.main_blog') }}",
title="Blender Cloud Blog")
| Blog
| HDRIs
li
a(href="{{ url_for('cloud.services') }}",
title="Blender Cloud Services")
| Services
| Textures
li
a(href="{{ url_for('cloud.about') }}",
title="About Blender Cloud")
| About
| Characters
.col-md-2.col-xs-6
h7.font-weight-bold
a(href="{{ url_for('cloud.services') }}")
| SERVICES
ul.list-unstyled
li
a(href="{{ url_for('main.main_blog') }}",
title="Blender Cloud Blog")
| Add-on
li
a(href="{{ url_for('main.main_blog') }}",
title="Blender Cloud Blog")
| Blender Sync
li
a(href="{{ url_for('cloud.services') }}",
title="Blender Cloud Services")
| Attract
li
a(href="{{ url_for('cloud.about') }}",
title="About Blender Cloud")
| Flamenco
li
a(href="{{ url_for('cloud.about') }}",
title="About Blender Cloud")
| Image Sharing
.col-md-2.col-xs-6
h7.font-weight-bold
| BLENDER
ul.list-unstyled
li
a(href="{{ url_for('main.main_blog') }}",
title="Blender Cloud Blog")
| blender.org
li
a(href="{{ url_for('cloud.terms_and_conditions') }}",
title="Terms and Conditions")
@@ -279,33 +390,11 @@ html(lang="en")
a(href="{{ url_for('cloud.privacy') }}",
title="Privacy")
| Privacy
.col-md-2.col-xs-6
h4
a(href="https://www.blender.org",
title="Blender official Website")
| Blender
ul.footer-links
li
a(href="https://www.blender.org",
title="Blender official Website")
| Blender.org
li
a(href="https://store.blender.org/",
title="The official Blender Store")
| Blender Store
.col-md-2.col-xs-6.special
| With the support of the <br/> MEDIA Programme of the European Union<br/><br/>
img(alt="MEDIA Programme of the European Union",
src="https://gooseberry.blender.org/wp-content/uploads/2014/01/media_programme.png")
| {% endblock footer_navigation %}
| {% block footer %}
footer.container
#hop(title="Be awesome in space")
i.pi-angle-up
| {% endblock footer %}
#hop(title="Be awesome in space")
i.pi-angle-up
| {% endblock footer_container %}
#notification-pop(data-url="", data-read-toggle="")
@@ -318,10 +407,7 @@ html(lang="en")
span.nc-date
a(href="")
noscript
link(href='//fonts.googleapis.com/css?family=Roboto:300,400', rel='stylesheet', type='text/css')
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.bootstrap-3.3.7.min.js') }}")
script(src="{{ url_for('static_cloud', filename='assets/js/bootstrap.min.js') }}")
| {% if current_user.is_authenticated %}
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.typewatch-3.0.0.min.js') }}")
@@ -350,9 +436,6 @@ html(lang="en")
if (typeof $().tooltip != 'undefined'){
$('[data-toggle="tooltip"]').tooltip({'delay' : {'show': 0, 'hide': 0}});
}
if(typeof($.fn.popover) != 'undefined'){
$('[data-toggle="popover"]').popover();
}
| {% block footer_scripts_pre %}{% endblock %}
| {% block footer_scripts %}{% endblock %}

View File

@@ -0,0 +1,69 @@
// {#
// Header of landing pages. title or text can be skipped:
// +jumbotron("{{ page_title }}", null, "{{ page_header_image }}")
// Any extra attributes added (in a separate group) will be passed as is:
// +jumbotron("{{ page_title }}", null, "{{ page_header_image }}")(data-node-id='{{ node._id }}')
// #}
mixin jumbotron(title, text, image, url)
if url
a.jumbotron.jumbotron-overlay.text-white(
style='background-image: url(' + image + ');',
href=url)&attributes(attributes)
.container
.row
.col-md-9
if title
.display-4.text-uppercase.font-weight-bold
=title
if text
.lead
=text
else
.jumbotron.jumbotron-overlay.text-white(style='background-image: url(' + image + ');')&attributes(attributes)
.container
.row
.col-md-9
if title
.display-4.text-uppercase.font-weight-bold
=title
if text
.lead
=text
// {# Secondary navigation.
// e.g. Workshops, Courses. #}
mixin nav-secondary(title)
ul.nav.nav-secondary&attributes(attributes)
if title
li.font-weight-bold.px-2
=title
if block
block
else
p No items defined.
mixin nav-secondary-link()
li.nav-item
a.nav-link&attributes(attributes)
block
// {# Takes as argument the number of columns to use in this deck. 1-6 #}
mixin card-deck(columns)
.card-deck.card-padless(class='card-' + columns + '-columns')
if block
block
else
p No cards defined.
// {#
// Passes all attributes to the card.
// You can do fun stuff in a loop even like:
// +card(data-url="{{ url_for('projects.view', project_url=project.url) }}", tabindex='{{ loop.index }}')
// #}
mixin card()
.card.card-fade.cursor-pointer.mb-4.js-project-go&attributes(attributes)
if block
block
else
p No card content defined.

View File

@@ -0,0 +1,164 @@
include ../../../mixins/components
| {% import 'projects/_macros.html' as projectmacros %}
| {% macro render_blog_post(node, project=None, pages=None) %}
.expand-image-links.imgs-fluid
| {% if node.picture %}
+jumbotron(
"{{ node.name }}",
"{{ node._created | pretty_date }}",
"{{ node.picture.thumbnail('h', api=api) }}",
"{{ node.url }}")(class="row")
| {% else %}
.pt-3.text-center.text-muted
h2
a.text-muted(href="{{ node.url }}")
| {{ node.name }}
ul.d-flex.list-unstyled.justify-content-center
| {% if node.project.name %}
li.pr-2 {{ node.project.name }}
| {% endif %}
| {% if node.user.full_name %}
li.pr-2
| {{ node.user.full_name }}
| {% endif %}
li
a.px-2.text-muted(href="{{ node.url }}",
title="Updated {{ node._updated | pretty_date }}")
| {{ node._created | pretty_date }}
li
a.px-2(href="{{ node.url }}#comments")
| Leave a comment
| {% if node.has_method('PUT') %}
li
a.px-2(href="{{url_for('nodes.edit', node_id=node._id)}}")
i.pi-edit
| Edit Post
| {% endif %}
| {% endif %}
| {% if project and project._id != config.MAIN_PROJECT_ID %}
| {{ projectmacros.render_secondary_navigation(project, pages=pages) }}
| {% endif %}
.row
.col-md-9.mx-auto
.item-content.pt-4
| {{ node.properties | markdowned('content') }}
hr.my-4
| {% endmacro %}
//- ******************************************************* -//
| {% macro render_blog_list_item(node) %}
.row.position-relative.py-2
.col-md-1
| {% if node.picture %}
a.imgs-fluid(href="{{ node.url }}")
img(src="{{ node.picture.thumbnail('s', api=api) }}")
| {% else %}
.bg-primary.rounded.h-100
a.d-flex.align-items-center.justify-content-center.h-100.text-white(href="{{ node.url }}")
i.pi-document-text
| {% endif %}
.col-md-11
h5
a.text-muted(href="{{ node.url }}") {{node.name}}
.text-muted.
#[span(title="{{node._created}}") {{node._created | pretty_date }}]
{% if node._created != node._updated %}
#[span(title="{{node._updated}}") (updated {{node._updated | pretty_date }})]
{% endif %}
{% if node.properties.category %} · {{node.properties.category}}{% endif %}
· {{node.user.full_name}}
{% if node.properties.status != 'published' %} · {{ node.properties.status}} {% endif %}
| {% endmacro %}
//- ******************************************************* -//
| {% macro render_blog_index(project, posts, can_create_blog_posts, api, more_posts_available, posts_meta, pages=None) %}
| {% if can_create_blog_posts %}
+nav-secondary
+nav-secondary-link(href="{{url_for('nodes.posts_create', project_id=project._id)}}")
span.text-success
i.pi-plus
| Create New Blog Post
| {% endif %}
| {% if posts %}
| {{ render_blog_post(posts[0], project=project, pages=pages) }}
.container
.row
.col-md-9.mx-auto
| {% for node in posts[1:] %}
| {% if loop.first %}
h5.text-muted.text-center Blasts from the past
| {% endif %}
| {{ render_blog_list_item(node) }}
| {% endfor %}
| {% if more_posts_available %}
.blog-archive-navigation
a(href="{{ project.blog_archive_url }}")
| {{posts_meta.total - posts|length}} more blog posts over here
i.pi-angle-right
| {% endif %}
| {% else %}
.text-center
p No posts... yet!
| {% endif %} {# posts #}
| {% endmacro %}
//- Macro for rendering the navigation buttons for prev/next pages -//
| {% macro render_archive_pagination(project) %}
.blog-archive-navigation
| {% if project.blog_archive_prev %}
a.archive-nav-button(
href="{{ project.blog_archive_prev }}", rel="prev")
i.pi-angle-left
| Previous page
| {% else %}
span.archive-nav-button
i.pi-angle-left
| Previous page
| {% endif %}
a.archive-nav-button(
href="{{ url_for('main.project_blog', project_url=project.url) }}")
| Blog Index
| {% if project.blog_archive_next %}
a.archive-nav-button(
href="{{ project.blog_archive_next }}", rel="next")
| Next page
i.pi-angle-right
| {% else %}
span.archive-nav-button
| Next page
i.pi-angle-right
| {% endif %}
| {% endmacro %}
| {% macro render_archive(project, posts, posts_meta) %}
| {{ render_archive_pagination(project) }}
| {% for node in posts %}
| {{ render_blog_list_item(node) }}
| {% endfor %}
| {{ render_archive_pagination(project) }}
| {% endmacro %}

View File

@@ -0,0 +1,213 @@
| {% extends 'layout.html' %}
| {% from '_macros/_navigation.html' import navigation_tabs %}
include ../mixins/components
| {% set title = 'organizations' %}
| {% block page_title %}Organizations{% endblock %}
| {% block og %}
meta(property="og:title", content="Dashboard")
meta(name="twitter:title", content="Blender Cloud")
meta(property="og:url", content="https://cloud.blender.org/{{ request.path }}")
meta(property="og:type", content="website")
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/cloud_services_oti.jpg')}}")
meta(name="twitter:image", content="{{ url_for('static', filename='assets/img/backgrounds/cloud_services_oti.jpg')}}")
| {% endblock %}
| {% block navigation_tabs %}
| {{ navigation_tabs(title) }}
| {% endblock navigation_tabs %}
| {% block body %}
+nav-secondary
| {% if can_create_organization %}
+nav-secondary-link(
class="create",
onclick='createNewOrganization(this)')
span.text-success
i.pi-plus
| Create Organization
| {% endif %}
li#create_organization_result_panel.result
.container-fluid.dashboard-container
.row
.col-md-6
ul.projects__list
| {% if organizations %}
| {% for organization in organizations['_items'] %}
| {% set link_url = url_for('pillar.web.organizations.view_embed', organization_id=organization._id) %}
li.projects__list-item(
data-url="{{ link_url }}",
id="organization-{{ organization._id }}")
a.projects__list-thumbnail(
href="{{ link_url }}")
i.pi-users
.projects__list-details
a.title(href="{{ link_url }}")
| {{ organization.name }}
ul.meta
li(title="Members")
| {{ organization.members|hide_none|count }} Member{{ organization.members|hide_none|count|pluralize }}
| {% if (organization.unknown_members|count) != 0 %}
| ({{ organization.unknown_members|hide_none|count }} pending)
| {% endif %}
li(title="Seats")
| {{ organization.seat_count }} Seat{{ organization.seat_count|pluralize }}
| {% endfor %}
| {% else %}
li.projects__list-item
a.projects__list-thumbnail
i.pi-blender-cloud
.projects__list-details
span Create an Organization to get started!
| {% endif %}
.col-md-6.py-1.pb-3
#item-details
| {% endblock %}
| {% block footer_scripts %}
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.typeahead-0.11.1.min.js')}}")
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.autocomplete-0.22.0.min.js') }}", async=true)
script.
/* Returns a more-or-less reasonable message given an error response object. */
function xhrErrorResponseMessage(err) {
if (typeof err.responseJSON == 'undefined')
return err.statusText;
if (typeof err.responseJSON._error != 'undefined' && typeof err.responseJSON._error.message != 'undefined')
return err.responseJSON._error.message;
if (typeof err.responseJSON._message != 'undefined')
return err.responseJSON._message
return err.statusText;
}
/**
* Open an organization in the #item-details div.
*/
function item_open(item_id, pushState)
{
if (item_id === undefined ) {
throw new ReferenceError("item_open(" + item_id + ") called.");
}
// Style elements starting with item_type and dash, e.g. "#job-uuid"
var clean_classes = 'active processing';
var current_item = $('#organization-' + item_id);
$('[id^="organization-"]').removeClass(clean_classes);
current_item
.removeClass(clean_classes)
.addClass('processing');
var item_url = '/o/' + item_id;
$.get(item_url, function(item_data) {
$('#item-details').html(item_data);
current_item
.removeClass(clean_classes)
.addClass('active');
}).fail(function(xhr) {
if (console) {
console.log('Error fetching organization', item_id, 'from', item_url);
console.log('XHR:', xhr);
}
current_item.removeClass(clean_classes);
toastr.error('Failed to open organization');
if (xhr.status) {
$('#item-details').html(xhr.responseText);
} else {
$('#item-details').html('<p class="text-danger">Opening ' + item_type + ' failed. There possibly was ' +
'an error connecting to the server. Please check your network connection and ' +
'try again.</p>');
}
});
// Determine whether we should push the new state or not.
pushState = (typeof pushState !== 'undefined') ? pushState : true;
if (!pushState) return;
// Push the correct URL onto the history.
var push_state = {itemId: item_id};
window.history.pushState(
push_state,
'Organization: ' + item_id,
item_url
);
}
$('li.projects__list-item').click(function(e){
url = $(this).data('url');
if (typeof url === 'undefined') return;
window.location.href = url;
if (console) console.log(url);
$(this).addClass('active');
$(this).find('.projects__list-thumbnail i')
.removeAttr('class')
.addClass('pi-spin spin');
});
{% if open_organization_id %}
$(function() { item_open('{{ open_organization_id }}', false); });
{% endif %}
{% if can_create_organization %}
function createNewOrganization(button) {
$(button)
.attr('disabled', 'disabled')
.fadeTo(200, 0.1);
$('#create_organization_result_panel').html('');
// TODO: create a form to get the initial info from the user.
$.post(
'{{ url_for('pillar.web.organizations.create_new') }}',
{
name: 'New Organization',
seat_count: 1,
}
)
.done(function(result) {
var $p = $('<p>').text('organization created, reloading list.')
$('#create_organization_result_panel').html($p);
window.location.href = result.location;
})
.fail(function(err) {
var msg = xhrErrorResponseMessage(err);
$('#create_organization_result_panel').html('Error creating organization: ' + msg);
$(button)
.fadeTo(1000, 1.0)
.queue(function() {
$(this)
.removeAttr('disabled')
.dequeue()
;
})
})
;
return false;
}
{% endif %}
| {% endblock %}

View File

@@ -0,0 +1,35 @@
| {% extends 'layout.html' %}
| {% block page_title %}Production of Stuff{% endblock %}
| {% block head %}
script(src="{{ url_for('static_cloud', filename='assets/js/tagged_assets.min.js') }}")
script.
$(function() {
$('ul.asset-list').loadTaggedAssets();
})
| {% endblock %}
| {% block body %}
#page-container
#page-content
h2 Production of Stuff
p.
Here are our hand-selected assets 'bout stuff.
h3 Animation
ul.asset-list(data-asset-tag="animation")
h3 Modelling
ul.asset-list(data-asset-tag="modelling")
h3 Rigging
ul.asset-list(data-asset-tag="rigging")
h3 pipeline
ul.asset-list(data-asset-tag="pipeline")
h3 lookdev
ul.asset-list(data-asset-tag="lookdev")
h3 crazyspace
ul.asset-list(data-asset-tag="crazyspace")
| {% endblock body%}

View File

@@ -0,0 +1,59 @@
| {% extends 'projects/home_layout.html' %}
| {% set subtab = 'blender_sync' %}
| {% set learn_more_btn_url = '/blog/introducing-blender-sync' %}
| {% block currenttab %}
.container-fluid
section.nav-tabs__tab.active#tab-blender_sync
.tab_header-container
.tab_header-intro(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/pattern_01.jpg')}})")
.tab_header-intro_text
h2 Connect Blender with the Cloud
p
| Save your Blender preferences and keymaps once, load them anywhere.
<br/>
| Use the
=' '
a(href='https://cloud.blender.org/r/downloads/blender_cloud-latest-bundle.zip') Blender Cloud add-on
=' '
| to synchronise your settings from within Blender.
| {% if show_addon_download_buttons %}
.row
.col-md-6
a.btn.btn-block.btn-outline-success(
href="https://cloud.blender.org/r/downloads/blender_cloud-latest-bundle.zip")
i.pi-download
| Download <small>v</small>{{ config.BLENDER_CLOUD_ADDON_VERSION }}
.col-md-6
a.btn.btn-link(
href="{{ learn_more_btn_url }}")
| Learn More
i.pi-angle-right
| {% endif %}
.tab_header-intro_icons
i.pi-blender
i.pi-heart-filled
i.pi-blender-cloud
| {% for version in synced_versions %}
.blender_sync-main
.blender_sync-main-header
h5.blender_sync-main-title
i.pi-blender
| Blender {{ version.version }}
.blender_sync-main-last
| Last synced on: {{ version.date|pretty_date }}
| {% else %}
.blender_sync-main.empty
.blender_sync-main-header
span.blender_sync-main-title
| No settings synced yet
<hr/>
a.download(
href='https://cloud.blender.org/r/downloads/blender_cloud-latest-bundle.zip')
| Download add-on
| {% endfor %}
| {% endblock %}

View File

@@ -0,0 +1,51 @@
| {% extends 'layout.html' %}
| {% from '_macros/_navigation.html' import navigation_tabs %}
include ../mixins/components
| {% set title = 'home' %}
| {% block og %}
meta(property="og:type", content="website")
meta(property="og:url", content="https://cloud.blender.org{{ request.path }}")
meta(property="og:title", content="Blender Cloud - Home")
meta(name="twitter:title", content="Blender Cloud")
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/cloud_services_oti.jpg')}}")
meta(name="twitter:image", content="{{ url_for('static', filename='assets/img/backgrounds/cloud_services_oti.jpg')}}")
| {% endblock %}
| {% block page_title %}
| {{current_user.full_name}}
| {% endblock %}
| {% block navigation_tabs %}
| {{ navigation_tabs(title) }}
| {% endblock navigation_tabs %}
| {% block body %}
.dashboard-container
section#projects.bg-white
+nav-secondary()(id='sub-nav-tabs__list')
+nav-secondary-link(id="subtab-blender_sync", data-tab-url="{{ url_for('projects.home_project')}}")
| Blender Sync
+nav-secondary-link(id="subtab-images", data-tab-url="{{ url_for('projects.home_project_shared_images')}}")
| Images
| {% block currenttab %}{% endblock %}
| {% endblock %}
| {% block footer_scripts %}
script.
$(document).ready(function () {
$('#subtab-{{ subtab }}').addClass('active');
var $nav_tabs = $('#sub-nav-tabs__list').find('a.nav-link');
$nav_tabs.on('click', function (e) {
console.log($(this));
window.location = $(this).attr('data-tab-url');
});
});
| {% endblock %}

View File

@@ -0,0 +1,300 @@
| {% extends 'layout.html' %}
| {% from '_macros/_navigation.html' import navigation_tabs %}
include ../mixins/components
| {% set title = 'dashboard' %}
| {% block og %}
meta(property="og:title", content="Dashboard")
meta(name="twitter:title", content="Blender Cloud")
meta(property="og:url", content="https://cloud.blender.org/{{ request.path }}")
meta(property="og:type", content="website")
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/cloud_services_oti.jpg')}}")
meta(name="twitter:image", content="{{ url_for('static', filename='assets/img/backgrounds/cloud_services_oti.jpg')}}")
| {% endblock %}
| {% block page_title %}
| {{current_user.full_name}}
| {% endblock %}
| {% block css %}
| {{ super() }}
style.
.deleted-projects-toggle {
z-index: 10;
position: absolute;
right: 0;
font-size: 20px;
padding: 3px;
text-shadow: 0 0 2px white;
}
.deleted-projects-toggle .show-deleted {
color: #aaa;
}
.deleted-projects-toggle .hide-deleted {
color: #bbb;
}
| {% endblock %}
| {% block navigation_tabs %}
| {{ navigation_tabs(title) }}
| {% endblock navigation_tabs %}
| {% block body %}
.dashboard-container
section.dashboard-main
section#projects.bg-white
+nav-secondary()(id='sub-nav-tabs__list')
+nav-secondary-link(data-tab-toggle='own_projects', class="active")
| Own Projects
| {% if projects_user|length != 0 %}
span ({{ projects_user|length }})
| {% endif %}
+nav-secondary-link(data-tab-toggle='shared')
| Shared with me
| {% if projects_shared|length != 0 %}
span ({{ projects_shared|length }})
| {% endif %}
| {% if current_user.has_cap('subscriber') %}
+nav-secondary-link(
id="project-create",
data-url="{{ url_for('projects.create') }}",
href="{{ url_for('projects.create') }}")
span.text-success
| #[i.pi-plus] Create New Project
| {% elif current_user.has_cap('can-renew-subscription') %}
+nav-secondary-link(
id="project-create",
data-url="{{ url_for('projects.create') }}",
href="/renew",
target="_blank")
| #[i.pi-heart-filled.text-danger] Resubscribe to Create a Project
| {% endif %}
nav.nav-tabs__tab.active#own_projects
.deleted-projects-toggle
| {% if show_deleted_projects %}
a.hide-deleted(href="{{ request.base_url }}", title='Hide deleted projects')
i.pi-trash
| {% else %}
a.show-deleted(href="{{ request.base_url }}?deleted=1", title='Show deleted projects')
i.pi-trash
| {% endif %}
ul.projects__list
| {% for project in projects_deleted %}
li.projects__list-item.deleted
span.projects__list-thumbnail
| {% if project.picture_square %}
img(src="{{ project.picture_square.thumbnail('s', api=api) }}")
| {% else %}
i.pi-blender-cloud
| {% endif %}
.projects__list-details
span.title {{ project.name }}
ul.meta
li.status.deleted Deleted
li.edit
a(href="javascript:undelete_project('{{ project._id }}')") Restore project
| {% else %}
| {% if show_deleted_projects %}
li.projects__list-item.deleted You have no recenly deleted projects. Deleted projects can be restored within a month after deletion.
| {% endif %}
| {% endfor %}
| {% for project in projects_user %}
li.projects__list-item(
data-url="{{ url_for('projects.view', project_url=project.url) }}")
a.projects__list-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img(src="{{ project.picture_square.thumbnail('s', api=api) }}")
| {% else %}
i.pi-blender-cloud
| {% endif %}
.projects__list-details
a.title(href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
ul.meta
li.status(
class="{{ project.is_private | yesno('private,public,') }}",
title="{{ project.is_private | yesno('Private Project,Public Project,') }}")
| {{ project.is_private | yesno('Private,Public,') }}
li.when(title="{{ project._created }}") {{ project._created | pretty_date }}
li.edit
a(href="{{ url_for('projects.edit', project_url=project.url) }}") Edit
| {% if project.status == 'pending' and current_user.has_cap('view-pending-nodes') %}
li.pending Not Published
| {% endif %}
| {% else %}
| {% if current_user.has_cap('subscriber') %}
li.projects__list-item(data-url="{{ url_for('projects.create') }}")
a.projects__list-thumbnail
i.pi-plus
.projects__list-details
a.title(href="{{ url_for('projects.create') }}")
| Create a project to get started!
| {% elif current_user.has_cap('can-renew-subscription') %}
li.projects__list-item(data-url="https://store.blender.org/renew-my-subscription.php")
a.projects__list-thumbnail
i.pi-plus
.projects__list-details
a.title(href="https://store.blender.org/renew-my-subscription.php")
| Renew your Blender Cloud subscription to create your own projects!
| {% else %}
li.projects__list-item(data-url="/join")
a.projects__list-thumbnail
i.pi-plus
.projects__list-details
a.title(href="/join")
| Join Blender Cloud to create your own projects!
| {% endif %}
| {% endfor %}
section.nav-tabs__tab#shared(style='display: none')
ul.projects__list
| {% if projects_shared %}
| {% for project in projects_shared %}
li.projects__list-item(
data-url="{{ url_for('projects.view', project_url=project.url) }}")
a.projects__list-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img(src="{{ project.picture_square.thumbnail('s', api=api) }}")
| {% else %}
i.pi-blender-cloud
| {% endif %}
.projects__list-details
a.title(href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
ul.meta
li.status(
class="{{ project.is_private | yesno('private,public,') }}",
title="{{ project.is_private | yesno('Private Project,Public Project,') }}")
| {{ project.is_private | yesno('Private,Public,') }}
li.when {{ project._created | pretty_date }}
li.who by {{ project.user.full_name }}
li.edit
a(href="{{ url_for('projects.edit', project_url=project.url) }}") Edit
| {% if project.status == 'pending' and current_user.has_cap('view-pending-nodes') %}
li.pending Not Published
| {% endif %}
li.leave
span.user-remove-prompt
| Leave Project
span.user-remove
| Are you sure?
span.user-remove-confirm(
user-id="{{ current_user.objectid }}",
project-url="{{url_for('projects.sharing', project_url=project.url)}}")
i.pi-check
| Yes, leave
span.user-remove-cancel
i.pi-cancel
| No, cancel
| {% endfor %}
| {% else %}
li.projects__list-item
a.projects__list-thumbnail
i.pi-heart-broken
.projects__list-details
.title
| No projects shared with you... yet!
| {% endif %}
| {% endblock %}
| {% block footer_scripts %}
script.
$(document).ready(function() {
$('li.projects__list-item').click(function(e){
url = $(this).data('url');
if (typeof url === 'undefined') return;
window.location.href = url;
if (console) console.log(url);
$(this).addClass('active');
$(this).find('.projects__list-thumbnail i')
.removeAttr('class')
.addClass('pi-spin spin');
});
// Tabs behavior
var $nav_tabs_list = $('#sub-nav-tabs__list');
var $nav_tabs = $nav_tabs_list.find('a.nav-link');
$nav_tabs.on('click', function(e){
e.preventDefault();
$nav_tabs.removeClass('active');
$(this).addClass('active');
$('.nav-tabs__tab').hide();
$('#' + $(this).attr('data-tab-toggle')).show();
});
// Leave project
var $projects_list = $('ul.projects__list');
$projects_list.find('span.user-remove-prompt').on('click', function(e){
e.stopPropagation();
e.preventDefault();
$(this).next().show();
$(this).hide();
});
$projects_list.find('span.user-remove-cancel').on('click', function(e){
e.stopPropagation();
e.preventDefault();
$(this).parent().prev().show();
$(this).parent().hide();
});
$projects_list.find('span.user-remove-confirm').on('click', function(e){
e.stopPropagation();
e.preventDefault();
var parent = $(this).closest('.projects__list-item');
function removeUser(userId, projectUrl){
$.post(projectUrl, {user_id: userId, action: 'remove'})
.done(function (data) {
parent.remove();
});
}
removeUser($(this).attr('user-id'), $(this).attr('project-url'));
});
hopToTop(); // Display jump to top button
});
var patch_url = '{{ url_for('projects.patch.patch_project', project_id='PROJECTID') }}';
function undelete_project(project_id) {
console.log('undeleting project', project_id);
$.ajax({
url: patch_url.replace('PROJECTID', project_id),
method: 'PATCH',
data: JSON.stringify({'op': 'undelete'}),
contentType: 'application/json'
})
.done(function(data, textStatus, jqXHR) {
location.href = jqXHR.getResponseHeader('Location');
})
.fail(function(err) {
toastr.error(xhrErrorResponseMessage(err), 'Undeletion failed');
})
}
| {% endblock %}

View File

@@ -51,7 +51,7 @@ meta(name="twitter:description", content="Blender Cloud, your source for open co
| {% endif %}
meta(property="og:url", content="{{url_for('projects.view_node', project_url=project.url, node_id=node._id)}}")
meta(property="og:url", content="{{url_for('projects.view_node', project_url=project.url, node_id=node._id, _external=True)}}")
| {% else %}
meta(property="og:title", content="{{ project.name }} Blog on Blender Cloud")
meta(name="twitter:title", content="{{ project.name }} Blog on Blender Cloud")
@@ -78,8 +78,6 @@ script(src="{{ url_for('static_pillar', filename='assets/js/vendor/videojs-hotke
| {% endblock %}
| {% block css %}
link(href="{{ url_for('static_pillar', filename='assets/css/font-pillar.css') }}", rel="stylesheet")
link(href="{{ url_for('static_pillar', filename='assets/css/base.css') }}", rel="stylesheet")
link(href="{{ url_for('static_cloud', filename='assets/css/project-landing.css') }}", rel="stylesheet")
| {% endblock %}

View File

@@ -0,0 +1,688 @@
| {% extends 'layout.html' %}
| {% from '_macros/_add_new_menu.html' import add_new_menu %}
include ../mixins/components
| {% block page_title %}{{ project.name }}{% endblock%}
| {% set title = 'project' %}
| {% block og %}
meta(property="og:type", content="website")
| {% if og_picture %}
meta(property="og:image", content="{{ og_picture.thumbnail('l', api=api) }}")
meta(name="twitter:image", content="{{ og_picture.thumbnail('l', api=api) }}")
| {% elif node and node.picture %}
meta(property="og:image", content="{{ node.picture.thumbnail('l', api=api) }}")
meta(name="twitter:image", content="{{ node.picture.thumbnail('l', api=api) }}")
| {% elif project.picture_header %}
meta(property="og:image", content="{{ project.picture_header.thumbnail('l', api=api) }}")
meta(name="twitter:image", content="{{ project.picture_header.thumbnail('l', api=api) }}")
| {% endif %}
| {% if show_project %}
meta(property="og:title", content="{{ project.name }} - Blender Cloud")
meta(name="twitter:title", content="{{ project.name }} - Blender Cloud")
meta(property="og:description", content="{{ project.summary }}")
meta(name="twitter:description", content="{{ project.summary }}")
meta(property="og:url", content="{{ url_for('projects.view', project_url=project.url, _external=True) }}")
| {% else %}
| {% if node %}
meta(property="og:title", content="{{ node.name }} - Blender Cloud")
meta(name="twitter:title", content="{{ node.name }} on Blender Cloud")
| {% if node.node_type == 'post' %}
| {% if node.properties.content %}
meta(property="og:description", content="{{ node.properties.content | truncate(180) }}")
meta(name="twitter:description", content="{{ node.properties.content | truncate(180) }}")
| {% else %}
meta(property="og:description", content="Blender Cloud, your source for open content and training")
meta(name="twitter:description", content="Blender Cloud, your source for open content and training")
| {% endif %}
| {% else %}
| {% if node.description %}
meta(property="og:description", content="{{ node.description | truncate(180) }}")
meta(name="twitter:description", content="{{ node.description | truncate(180) }}")
| {% else %}
meta(property="og:description", content="Blender Cloud, your source for open content and training")
meta(name="twitter:description", content="Blender Cloud, your source for open content and training")
| {% endif %}
| {% endif %}
meta(property="og:url", content="{{url_for('projects.view_node', project_url=project.url, node_id=node._id)}}")
| {% else %}
meta(property="og:title", content="{{ project.name }} Blog on Blender Cloud")
meta(name="twitter:title", content="{{ project.name }} Blog on Blender Cloud")
meta(property="og:description", content="{{ project.summary }}")
meta(name="twitter:description", content="{{ project.summary }}")
meta(property="og:url", content="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| {% endif %}
| {% endif %}
| {% endblock %}
| {% block head %}
link(href="{{ url_for('static_pillar', filename='assets/jstree/themes/default/style.min.css') }}", rel="stylesheet")
| {% if node %}
link(rel="amphtml", href="{{ url_for('nodes.view', node_id=node._id, _external=True, format='amp') }}")
| {% endif %}
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/videojs-6.2.8.min.js') }}")
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/videojs-ga-0.4.2.min.js') }}")
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/videojs-hotkeys-0.2.20.min.js') }}")
script(src="{{ url_for('static_pillar', filename='assets/js/video_plugins.min.js') }}")
| {% endblock %}
| {% block css %}
link(href="{{ url_for('static_pillar', filename='assets/css/font-pillar.css') }}", rel="stylesheet")
link(href="{{ url_for('static_pillar', filename='assets/css/project-main.css') }}", rel="stylesheet")
| {% endblock %}
| {% block navigation_tabs %}
+nav-secondary()(class="bg-white")
| {% if project.category == 'course' %}
li.text-capitalize
a.nav-link.text-muted.px-0(href="{{ url_for('cloud.courses') }}")
| Courses
| {% elif project.category == 'workshop' %}
li.text-capitalize
a.nav-link.text-muted.px-0(href="{{ url_for('cloud.workshops') }}")
| Workshops
li.px-1
i.pi-angle-right
| {% endif %}
+nav-secondary-link(
class="px-0",
href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| {{ project.name }}
| {% if project.category == "open_project" %}
+nav-secondary-link(
class="active",
href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| Explore
+nav-secondary-link(
href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| Blog
+nav-secondary-link(
href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| About
+nav-secondary-link(
href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| Team
+nav-secondary-link(
href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| Awards
| {% endif %}
| {% endblock navigation_tabs %}
| {% block body %}
#project-container
#project-side-container
#project_sidebar.bg-white
ul.project-tabs.p-0
//- li.tabs-thumbnail(class="{% if project.picture_square %}image{% endif %}")
//- a(href="{{url_for('projects.view', project_url=project.url)}}")
//- #project-loading
//- i.pi-spin
//- | {% if project.picture_square %}
//- img(src="{{ project.picture_square.thumbnail('b', api=api) }}")
//- | {% else %}
//- i.pi-home
//- | {% endif %}
li.tabs-browse(
title="Browse",
data-toggle="tooltip",
data-placement="right",
class="active")
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
i.pi-folder
| {% if not project.is_private %}
| {% if current_user_is_subscriber %}
li.tabs-search(
title="Search",
data-toggle="tooltip",
data-placement="right")
a(href="{{ url_for('projects.search', project_url=project.url, _external=True)}} ")
i.pi-search
| {% else %}
li.tabs-search(
title="Search (subscribers only)",
data-toggle="tooltip",
data-placement="right")
a(href="{{ url_for('cloud.join') }}")
i.pi-search
| {% endif %}
| {% endif %}
| {{ extension_sidebar_links }}
| {% if project.has_method('PUT') %}
li(
title="Edit Project",
data-toggle="tooltip",
data-placement="right")
a(href="{{ url_for('projects.edit', project_url=project.url) }}")
i.pi-cog
| {% endif %}
#project_nav(class="{{ title }}")
#project_nav-container
| {% if title != 'about' %}
//- +nav-secondary(class="bg-white")
//- +nav-secondary-link(
//- class="active",
//- href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
//- | {{ project.name }}
//- #project_nav-header.bg-white
//- a.project-title.p-2.font-weight-bold.text-dark(
//- href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
//- | {{ project.name }}
| {% block project_tree %}
#project_tree.bg-white
| {% endblock project_tree %}
| {% endif %}
#project_context-container.border-left
| {% if project.has_method('PUT') %}
#project_context-header.bg-white
span#status-bar
ul.project-edit-tools.disabled
li.dropdown
button#item_add.project-mode-view.btn.btn-sm.btn-outline-secondary.dropdown-toggle(
type="button",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false")
i.button-add-icon.pi-collection-plus
| New...
ul.dropdown-menu.add_new-menu
| {{ add_new_menu(project.node_types) }}
li.button-edit
a#item_edit.project-mode-view.btn.btn-sm.btn-outline-secondary.ml-2(
href="javascript:void(0);",
title="Edit",
data-project_id="{{project._id}}")
i.button-edit-icon.pi-edit
| Edit Project
li.dropdown
button.dropdown-toggle.project-mode-view.btn.btn-sm.btn-outline-secondary.mx-2(
type="button",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false")
i.pi-more-vertical.p-0
ul.dropdown-menu
| {% if current_user.has_cap('admin') %}
li.dropdown-item
a#item_featured(
href="javascript:void(0);",
title="Feature on project's homepage",
data-toggle="tooltip",
data-placement="left")
i.pi-star
| Toggle Featured
li.dropdown-item
a#item_toggle_public(
href="javascript:void(0);",
title="Make it accessible to anyone",
data-toggle="tooltip",
data-placement="left")
i.pi-lock-open
| Toggle Public
| {% endif %}
li.dropdown-item
a#item_toggle_projheader(
href="javascript:void(0);",
title="Feature as project's header",
data-toggle="tooltip",
data-placement="left")
i.pi-star
| Toggle Project Header video
li.dropdown-item.button-move
a#item_move(
href="javascript:void(0);",
title="Move into a folder...",
data-toggle="tooltip",
data-placement="left")
i.button-move-icon.pi-move
| Move
li.dropdown-item.button-delete
a#item_delete(
href="javascript:void(0);",
title="Can be undone within a month",
data-toggle="tooltip",
data-placement="left")
i.pi-trash
| Delete Project
// Edit Mode
li.button-cancel
a#item_cancel.project-mode-edit.btn.btn-outline-secondary(
href="javascript:void(0);",
title="Cancel changes")
i.button-cancel-icon.pi-cancel
| Cancel
li.button-save
a#item_save.project-mode-edit.btn.btn-outline-success.mx-2(
href="javascript:void(0);",
title="Save changes")
i.button-save-icon.pi-check
| Save Changes
| {% endif %}
| {% set utm_source = request.args.get('utm_source') %}
| {% if config.UTM_LINKS and utm_source in config.UTM_LINKS %}
#utm_container
a(href="{{config.UTM_LINKS[utm_source]['link']}}")
img(src="{{config.UTM_LINKS[utm_source]['image']}}", alt="gift", class="img-responsive")
| {% endif %}
#project_context
| {% block project_context %}
| {% if show_project %}
| {% include "projects/view_embed.html" %}
| {% endif %}
| {% endblock project_context %}
#overlay-mode-move-container
.overlay-container
.title
i.pi-angle-left
| Select the <strong>folder</strong> where you want to move it
.buttons
button#item_move_accept.move.disabled
| Select a Folder
button#item_move_cancel.cancel
i.pi-cancel
| Cancel
| {% endblock %}
| {% block footer_container %}{% endblock %}
| {% block footer_scripts_pre %}
| {% if project.has_method('PUT') %}
| {# JS containing the Edit, Add, Featured, and Move functions #}
script(type="text/javascript", src="{{ url_for('static_pillar', filename='assets/js/project-edit.min.js') }}")
| {% endif %}
script.
function updateToggleProjHeaderMenuItem() {
var $toggle_projheader = $('#item_toggle_projheader');
if (ProjectUtils.isProject()) {
$toggle_projheader.hide();
return;
}
if (ProjectUtils.nodeType() == 'asset') {
$toggle_projheader.show();
} else {
$toggle_projheader.hide();
}
}
$(updateToggleProjHeaderMenuItem);
// Function to update the interface on loadNodeContent, and edit/saving assets
function updateUi(nodeId, mode) {
if (mode === 'view') {
$('.project-mode-view').displayAs('inline-block');
$('.project-mode-edit').hide();
$("#node-edit-form").unbind("submit");
$("#item_save").unbind("click");
$("#item_cancel").unbind("click");
} else if (mode === 'edit') {
$('.project-mode-view').hide();
$('.project-mode-edit').displayAs('inline-block');
} else {
if (console) console.log('Invalid mode:', mode);
}
// Prevent flicker by scrolling to top.
$("#project_context-container").scrollTop(0);
// Enable specific items under the Add New dropdown
if (ProjectUtils.nodeType() === 'group') {
addMenuEnable(['asset', 'group']);
} else if (ProjectUtils.nodeType() === 'group_texture') {
addMenuEnable(['group_texture', 'texture']);
} else if (ProjectUtils.nodeType() === 'group_hdri') {
addMenuEnable(['group_hdri', 'hdri']);
} else if (!ProjectUtils.isProject()) {
addMenuEnable(false);
}
updateToggleProjHeaderMenuItem();
// Set the page title on the document
var page_title = $('#node-title').text() + " - {{ project.name }} — Blender Cloud";
DocumentTitleAPI.set_page_title(page_title);
// TODO: Maybe remove this, now it's also in loadNodeContent(), but double-check
// it's done like that in all users of updateUi().
$('#project-loading').removeAttr('class');
}
| {% endblock %}
| {% block footer_scripts %}
script(src="{{ url_for('static_pillar', filename='assets/jstree/jstree.min.js') }}")
script.
{% if show_project %}
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}", isProject: true, nodeId: ''});
{% else %}
{% if node %}
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}", isProject: false, nodeId: '{{node._id}}'});
{% endif %}
{% endif %}
var projectTree = document.getElementById('project_tree');
var urlNodeMove = "{{url_for('projects.move_node')}}";
var urlNodeFeature = "{{url_for('projects.add_featured_node')}}";
var urlNodeDelete = "{{url_for('projects.delete_node')}}";
var urlNodeTogglePublic = "{{url_for('projects.toggle_node_public')}}";
var urlNodeToggleProjHeader = "{{url_for('projects.toggle_node_project_header')}}";
var urlProjectDelete = "{{url_for('projects.delete')}}";
var urlProjectEdit = "{{url_for('projects.edit', project_url=project.url)}}";
function loadNodeContent(url, nodeId) {
$('#project-loading').addClass('active');
$.get(url, function(dataHtml) {
// Update the DOM injecting the generate HTML into the page
$('#project_context').html(dataHtml);
})
.done(function(){
updateUi(nodeId, 'view');
})
.fail(function(dataResponse) {
$('#project_context').html($('<iframe id="server_error"/>'));
$('#server_error').attr('src', url);
})
.always(function(){
$('#project-loading').removeAttr('class');
$('.button-edit-icon').addClass('pi-edit').removeClass('pi-spin spin');
});
}
function loadProjectContent(url) {
$('#project-loading').addClass('active');
$.get(url, function(dataHtml) {
// Update the DOM injecting the generated HTML into the page
$('#project_context').html(dataHtml);
})
.done(function() {
updateUi('', 'view');
addMenuEnable();
addMenuDisable(['texture']);
})
.fail(function(dataResponse) {
$('#project_context').html($('<iframe id="server_error"/>'));
$('#server_error').attr('src', url);
})
.always(function(){
$('#project-loading').removeAttr('class');
$('.button-edit-icon').addClass('pi-edit').removeClass('pi-spin spin');
});
}
function displayStorage(storageNodeId, path) {
var url = '/nodes/' + storageNodeId + '/view?path=' + path;
loadNodeContent(url);
}
function displayNode(nodeId, pushState) {
// Remove the 'n_' suffix from the id
if (nodeId.substring(0, 2) == 'n_') {
nodeId = nodeId.substr(2);
}
var url = '/nodes/' + nodeId + '/view';
loadNodeContent(url, nodeId);
// Determine whether we should push the new state or not.
pushState = (typeof pushState !== 'undefined') ? pushState : true;
if (!pushState) return;
// Push the correct URL onto the history.
var push_state = {nodeId: nodeId, url: url};
var push_url = '{{url_for("projects.view", project_url=project.url)}}' + nodeId;
// console.log('Pushing state ', push_state, ' with URL ', push_url);
window.history.pushState(
push_state,
'Node ' + nodeId, // TODO: use sensible title
push_url
);
}
function redirectToNode(nodeId) {
var generic_url = '{{ url_for("projects.view_node", project_url=project.url, node_id="theNodeId") }}';
var node_url = generic_url.replace('theNodeId', nodeId);
// This makes the user skip the current page when using the 'back' button,
// i.e. it works as a proper redirect.
location.replace(node_url);
}
window.onpopstate = function(event) {
var state = event.state;
// console.log('State popped. location:', document.location, 'state:', state);
// Deselect any selected node. We'll select the visited node (if any) later on.
var jstreeAPI = $(projectTree).jstree(true);
jstreeAPI.deselect_all(true);
if (state == null) {
// Went back to the project.
displayProject();
return;
}
// Went back to a node.
loadNodeContent(state.url, state.nodeId);
// Annoying hack because jstreeAPI.select_node() can only suppress the
// changed.jstree event, and NOT the selected_node.jstree event.
projectTree.dataset.ignoreSelectNode = true;
jstreeAPI.select_node('n_' + state.nodeId, true);
delete projectTree.dataset.ignoreSelectNode;
};
function displayProject() {
var url = "{{url_for('projects.view', project_url=project.url, embed=1)}}";
loadProjectContent(url);
}
function getHashId() {
if (console)
console.log('getHashId() should not be used any more!');
}
/* Loaded once, on page load */
function loadContent() {
var nodeId = ProjectUtils.nodeId();
var isProject = ProjectUtils.isProject();
if (isProject) {
// No need to asynchronously load the project, as it's embedded by Jinja.
// displayProject() is still needed, though, when people use 'back' to go there.
if (location.hash) {
// Handle old-style /p/{url}/#node-ID links, and redirect them to the correct spot.
redirectToNode(location.hash.substr(1));
}
$('.project-mode-view').displayAs('inline-block');
$('.project-mode-edit').hide();
} else {
displayNode(nodeId, false);
}
$(projectTree).jstree({
'core': {
'data': function (obj, callback) {
if(obj.id === '#') { //tree root
if (isProject) {
$.getJSON("{{url_for('projects.jstree', project_url=project.url)}}", function (jsonObject) {
callback.call(this, jsonObject['items']);
});
} else {
$.getJSON('/nodes/' + nodeId + '/jstree', function(jsonObject) {
callback.call(this, jsonObject['items']);
});
}
} else { //normal node
var childNodeId;
if (obj.original.type == 'group_storage') {
childNodeId = obj.original.storage_node;
$.getJSON('/nodes/' + childNodeId + '/jstree?children=1&path=' + obj.original.path, function(jsonObject) {
callback.call(this, jsonObject.children);
});
} else {
// Remove the 'n_' suffix from the id
childNodeId = obj.id.substring(2);
$.getJSON('/nodes/' + childNodeId + '/jstree?children=1', function(jsonObject) {
callback.call(this, jsonObject.children);
});
}
}
}
},
"types" : {
"#": {"valid_children": ["collection"]},
"chapter" : {"icon": "pi-folder"},
"group" : {"icon": "pi-folder"},
"group_texture" : {"icon": "pi-folder-texture"},
"group_hdri" : {"icon": "pi-folder-texture", "max_children": 0},
"group_storage" : {"icon": "pi-folder"},
"filesystem_node" : {"icon": "pi-folder"},
"file" : {"icon": "pi-document", "max_children": 0},
"filesystem_file" : {"icon": "pi-document", "max_children": 0},
"image" : {"icon": "pi-image", "max_children": 0},
"hdri" : {"icon": "pi-globe", "max_children": 0},
"texture" : {"icon": "pi-texture", "max_children": 0},
"video" : {"icon": "pi-play", "max_children": 0},
"blog" : {"icon": "pi-newspaper", "max_children": 0},
"page" : {"icon": "pi-document-text", "max_children": 0},
"default" : {"icon": "pi-document"}
},
"plugins": ["types",] //, "state", "sort"
});
var jstreeAPI = $(projectTree).jstree(true);
$(projectTree).on("select_node.jstree", function (e, data) {
var selectedNodeId = data.node.id.substr(2);
// Ignore events that can't be suppressed otherwise.
// This can be removed if jstreeAPI.select_node() allows suppressing
// the select_node.jstree event.
if (e.target.dataset.ignoreSelectNode === 'true') return;
if (typeof(data.node.original.path) === 'undefined') {
var movingMode = Cookies.getJSON('bcloud_moving_node');
// Check if we are in the process of moving a node
if (movingMode) {
// Allow moving nodes only inside of node_type group
if (data.node.original.type != 'group' || movingMode.node_id === selectedNodeId || movingMode.node_id === ProjectUtils.parentNodeId()) {
if (movingMode.node_type === 'texture') {
if (data.node.original.type === 'group_texture') {
$('#item_move_accept').html('<i class="pi-check"></i>Move Here').removeClass('disabled');
} else {
$('#item_move_accept').html('Select a Texture Folder').addClass('disabled');
}
} else if (movingMode.node_type === 'hdri') {
if (data.node.original.type === 'group_hdri') {
$('#item_move_accept').html('<i class="pi-check"></i>Move Here').removeClass('disabled');
} else {
$('#item_move_accept').html('Select an HDRi Folder').addClass('disabled');
}
} else {
$('#item_move_accept').html('Select a Folder').addClass('disabled');
}
} else {
$('#item_move_accept').html('<i class="pi-check"></i>Move Here').removeClass('disabled');
}
}
// Check the type of node and act accordingly
if (data.node.original.custom_view) {
window.location = data.node.a_attr.href;
} else {
var currentNodeId = ProjectUtils.nodeId();
if (currentNodeId != selectedNodeId) {
displayNode(selectedNodeId);
}
jstreeAPI.open_node(data.node);
}
} else {
displayStorage(data.node.original.storage_node, data.node.original.path);
jstreeAPI.toggle_node(data.node);
}
});
};
{% if is_embedded_edit is not defined or is_embedded_edit %}
// Initialize the page if we are not directly editing a node (most of the time)
loadContent();
{% endif %}
var project_container = document.getElementById('project-container');
/* UI Stuff */
$(window).on("load resize",function(){
containerResizeY($(window).height());
if ($(window).width() > 480) {
project_container.style.height = (window.innerHeight - project_container.offsetTop) + "px";
}
});
{% if current_user_is_subscriber %}
$(projectTree).addClass('is_subscriber');
{% endif %}
| {% endblock %}
| {% block comment_scripts %} {% endblock%}

View File

@@ -1,5 +1,7 @@
| {% extends 'layout.html' %}
include mixins/components
| {# Default case is Open Projects #}
| {% set page_title = 'Open Projects' %}
| {% set page_description = 'Full production data and tutorials from all open movies, for you to use freely' %}
@@ -9,20 +11,20 @@
| {% if title == 'courses' %}
| {% set page_title = 'Courses' %}
| {% set page_description = 'Production quality training by 3D professionals' %}
| {% set page_header_image = url_for('static', filename='assets/img/backgrounds/background_caminandes_3_03.jpg') %}
| {% set page_header_image = url_for('static', filename='assets/img/backgrounds/background_agent327_04.jpg') %}
| {% set page_header_text = 'Character modeling, 3D printing, VFX, rigging and more.' %}
| {% elif title == 'workshops' %}
| {% set page_title = 'Workshops' %}
| {% set page_description = 'Production quality training by 3D professionals' %}
| {% set page_header_image = url_for('static', filename='assets/img/backgrounds/background_caminandes_3_03.jpg') %}
| {% set page_header_image = url_for('static', filename='assets/img/backgrounds/background_agent327_04.jpg') %}
| {% set page_header_text = 'Enter the artist workshop and learn by example.' %}
| {% endif %}
| {% block og %}
meta(property="og:type", content="website")
meta(property="og:url", content="https://cloud.blender.org")
meta(property="og:url", content="{{ request.url }}")
meta(property="og:title", content="{{ page_title }} on Blender Cloud")
meta(name="twitter:title", content="{{ page_title }} on Blender Cloud")
@@ -38,59 +40,70 @@ meta(name="twitter:image", content="{{ page_header_image }}")
| {{ page_title }}
| {% endblock %}
| {% block navigation_tabs %}
| {% if title in ['courses', 'workshops'] %}
+nav-secondary
+nav-secondary-link(
class="{% if title == 'workshops' %}active{% endif %}",
href="{{ url_for('cloud.workshops') }}")
| Workshops
+nav-secondary-link(
class="{% if title == 'courses' %}active{% endif %}",
href="{{ url_for('cloud.courses') }}")
| Courses
+nav-secondary-link(
class="{% if title == 'gallery' %}active{% endif %}",
href="{{ url_for('projects.view', project_url='gallery') }}")
| Art Gallery
| {% endif %}
| {% endblock navigation_tabs %}
| {% block body %}
#project-container
.container.pb-5
.pt-4
h2.text-uppercase.font-weight-bold
| {{ page_title }}
.lead
| {{ page_header_text }}
#node_index-container
#node_index-header.collection
img.background-header(src="{{ page_header_image }}")
#node_index-collection-info
.node_index-collection-name
span {{ page_title }}
.node_index-collection-description
span.
{{ page_header_text }}
hr.pb-2
.node_index-collection
+card-deck(3)
| {% for project in projects %}
| {% for project in projects %}
| {% if (project.status == 'published') or (project.status == 'pending' and current_user.is_authenticated) and project._id != config.MAIN_PROJECT_ID %}
| {% if (project.status == 'published') or (project.status == 'pending' and current_user.is_authenticated) and project._id != config.MAIN_PROJECT_ID %}
+card(data-url="{{ url_for('projects.view', project_url=project.url) }}", tabindex='{{ loop.index }}')
| {% if project.picture_header %}
a(href="{{ url_for('projects.view', project_url=project.url) }}")
img.card-img-top(
src="{{ project.picture_header.thumbnail('l', api=api) }}", alt="{{ project.name }}")
| {% endif %}
.node_index-collection-card.project(
data-url="{{ url_for('projects.view', project_url=project.url) }}",
tabindex="{{ loop.index }}")
| {% if project.picture_header %}
a.item-header(
href="{{ url_for('projects.view', project_url=project.url) }}")
img(src="{{ project.picture_header.thumbnail('l', api=api) }}")
| {% endif %}
.item-info
a.item-title(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {{project.name}}
| {% if project.status == 'pending' and current_user.is_authenticated and current_user.has_role('admin') %}
small (pending)
| {% endif %}
| {% if project.summary %}
p.item-description
| {{project.summary|safe}}
.card-body
h5.card-title
| {{ project.name }}
| {% if project.status == 'pending' and current_user.is_authenticated and current_user.has_role('admin') %}
small (pending)
| {% endif %}
a.learn-more LEARN MORE
| {% endif %}
| {% endfor %}
| {% if project.summary %}
p.card-text
| {{project.summary|safe}}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% endblock %}
| {% block footer_scripts %}
script.
$('.node_index-collection-card.project').on('click', function(e){
$('.js-project-go').on('click', function(e){
e.preventDefault();
window.location.href = $(this).data('url');
});

View File

@@ -1,10 +1,11 @@
| {% extends 'layout.html' %}
| {% block page_title %}Services{% endblock %}
| {% set title = 'services' %}
include mixins/components
| {% block og %}
meta(property="og:type", content="website")
meta(property="og:url", content="{{ url_for('cloud.services') }}")
meta(property="og:url", content="{{ request.url }}")
meta(property="og:title", content="Services - Blender Cloud")
meta(name="twitter:title", content="Services - Blender Cloud")
@@ -20,204 +21,201 @@ meta(name="twitter:image", content="{{ url_for('static', filename='assets/img/ba
| {% endblock %}
| {% block body %}
#page-container
#page-header(style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/services_projects.jpg')}})")
.container
.page-title
| Blender Cloud Services
.page-title-summary
span.text-background
p.
Blender Cloud is the creative hub for your projects, powered by Free and Open Source software.
- var header_text = "On Blender Cloud you can create and share personal projects, access our texture and HDRI library (or create your own), keep track of your production, manage your renders and much more!";
+jumbotron("Services", header_text, "{{ url_for('static', filename='assets/img/backgrounds/services_projects.jpg')}}")
p.
On Blender Cloud you can create and share personal projects, access our texture and HDRI
library (or create your own), keep track of your production, manage your renders and much more!
- var addon_text = 'Available through the <a href="{{ url_for(\'cloud.services\') }}#blender-cloud-add-on">Blender Cloud add-on</a>';
section#blender-cloud-add-on.page-card
.page-card-side
h2.page-card-title
| Blender Cloud add-on
.page-card-summary
p.
The Blender Cloud add-on provides access to most of our services directly within Blender.
p.
Use the add-on to share images online, submit renders to Flamenco or browse textures and HDRI libraries!
.navbar-backdrop-overlay
hr
- var addon_text = 'Available through the <a href="{{ url_for(\'cloud.services\') }}#blender-cloud-add-on">Blender Cloud add-on</a>'
small Blender Cloud add-on requires Blender 2.78 or newer
#page-content
a.btn.btn-primary(
href="/r/downloads/blender_cloud-latest-addon.zip")
i.pi-download
| Download add-on &nbsp;<small>v</small> {{ config.BLENDER_CLOUD_ADDON_VERSION }}
section#blender-cloud-add-on.page-card
.page-card-side
h2.page-card-title
| Blender Cloud add-on
.page-card-summary
p.
The Blender Cloud add-on provides access to most of our services directly within Blender.
p.
Use the add-on to share images online, submit renders to Flamenco or browse textures and HDRI libraries!
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/blender_cloud_addon_thumbnail.png')}}")
hr
section#blender-sync.page-card.right
.page-card-side
h2.page-card-title Blender Sync
.page-card-summary
| Save your settings once. Use them anywhere.
| Carry your Blender configuration with you,
| use our add-on to sync your keymaps and preferences.
hr
small Blender Sync is <strong>free</strong> for everyone! No subscription required.
small This add-on requires Blender 2.78 or newer.
small Blender Cloud add-on requires Blender 2.78 or newer
.tip !{addon_text}
a.page-card-cta.download(
href="https://cloud.blender.org/r/downloads/blender_cloud-latest-addon.zip")
i.pi-download
| Download add-on &nbsp;<small>v</small> {{ config.BLENDER_CLOUD_ADDON_VERSION }}
a.btn.btn-outline-primary(
href="/r/downloads/blender_cloud-latest-addon.zip")
i.pi-download
| Download add-on &nbsp;<small>v</small> {{ config.BLENDER_CLOUD_ADDON_VERSION }}
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/blender_cloud_addon_thumbnail.png')}}")
a.btn.btn-link(
href="/blog/introducing-blender-sync")
| Learn More
i.pi-angle-right
section#blender-sync.page-card.right
.page-card-side
h2.page-card-title Blender Sync
.page-card-summary
| Save your settings once. Use them anywhere.
| Carry your Blender configuration with you,
| use our add-on to sync your keymaps and preferences.
hr
small Blender Sync is <strong>free</strong> for everyone! No subscription required.
small This add-on requires Blender 2.78 or newer.
.tip !{addon_text}
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/sync_thumbnail.jpg')}}")
a.page-card-cta(
href="https://cloud.blender.org/blog/introducing-blender-sync")
| Learn More
section#texture-browser.page-card.right
.page-card-side
h2.page-card-title Texture & HDRI Browser
.page-card-summary
p.
Access the <a href="/p/textures/">Blender Cloud Textures</a>
library from within Blender using our exclusive add-on.
Create, manage and share <em>your own</em> texture libraries!
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/sync_thumbnail.jpg')}}")
.tip !{addon_text}
a.btn.btn-outline-primary.js-watch-video(
href="https://www.youtube.com/watch?v=-srXYv2Osjw",
data-youtube-id="-srXYv2Osjw")
i.pi-play
| Watch Video
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/tex_library_thumbnail.jpg')}}")
section#texture-browser.page-card.right
.page-card-side
h2.page-card-title Texture & HDRI Browser
.page-card-summary
p.
Access the <a href="https://cloud.blender.org/p/textures/">Blender Cloud Textures</a>
library from within Blender using our exclusive add-on.
Create, manage and share <em>your own</em> texture libraries!
section#image-sharing.page-card.right
.page-card-side
h2.page-card-title Image Sharing
.page-card-summary
| Got a nice render, a Blender oddity, a cool screenshot?
| Share it instantly from within Blender to the Cloud, to the world!
.tip !{addon_text}
.tip !{addon_text}
a.page-card-cta.js-watch-video.download(
href="https://www.youtube.com/watch?v=-srXYv2Osjw",
data-youtube-id="-srXYv2Osjw")
i.pi-play
| Watch Video
a.btn.btn-outline-primary.js-watch-video(
href="https://www.youtube.com/watch?v=yvtqeMBOAyk",
data-youtube-id="yvtqeMBOAyk")
i.pi-play
| Watch Video
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/tex_library_thumbnail.jpg')}}")
a.btn.btn-link(
href="/blog/introducing-image-sharing")
| Learn More
i.pi-angle-right
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/image_sharing_thumbnail.jpg')}}")
section#image-sharing.page-card.right
.page-card-side
h2.page-card-title Image Sharing
.page-card-summary
| Got a nice render, a Blender oddity, a cool screenshot?
| Share it instantly from within Blender to the Cloud, to the world!
section#projects.page-card.right
.page-card-side
h2.page-card-title Private Projects
.page-card-summary.
Create and manage your own personal projects.
Upload assets and collaborate with other Blender Cloud members.
.tip !{addon_text}
a.btn.btn-link(
href="/blog/introducing-private-projects")
| Learn More
i.pi-angle-right
a.page-card-cta.download.js-watch-video(
href="https://www.youtube.com/watch?v=yvtqeMBOAyk",
data-youtube-id="yvtqeMBOAyk")
i.pi-play
| Watch Video
a.page-card-cta.outline(
href="https://cloud.blender.org/blog/introducing-image-sharing")
| Learn More
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/image_sharing_thumbnail.jpg')}}")
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/projects_thumbnail.jpg')}}")
section#projects.page-card.right
.page-card-side
h2.page-card-title Private Projects
.page-card-summary.
Create and manage your own personal projects.
Upload assets and collaborate with other Blender Cloud members.
section#attract.page-card.right
.page-card-side
h2.page-card-title
| Attract
.page-card-summary.
Production-management software for your film, game, or commercial projects.
a.page-card-cta(
href="https://cloud.blender.org/blog/introducing-private-projects")
| Learn More
a.btn.btn-outline-primary.js-watch-video(
href="https://www.youtube.com/watch?v=b9x1rlyyt_o",
data-youtube-id="b9x1rlyyt_o")
i.pi-play
| Watch Video
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/projects_thumbnail.jpg')}}")
a.btn.btn-link(
href="/blog/attract-and-flamenco-public-beta",
title="Learn more about Attract")
| Learn More
i.pi-angle-right
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/attract_thumbnail.jpg')}}")
section#attract.page-card.right
.page-card-side
h2.page-card-title
| Attract
.page-card-summary.
Production-management software for your film, game, or commercial projects.
section#flamenco.page-card.right
.page-card-side
h2.page-card-title
| Flamenco
.page-card-summary.
Take control of your computing infrastructure and get things done.
a.page-card-cta.download.js-watch-video(
href="https://www.youtube.com/watch?v=b9x1rlyyt_o",
data-youtube-id="b9x1rlyyt_o")
i.pi-play
| Watch Video
a.btn.btn-outline-primary.js-watch-video(
href="https://www.youtube.com/watch?v=7cnFKhsM67Q",
data-youtube-id="7cnFKhsM67Q")
i.pi-play
| Watch Video
a.page-card-cta(
href="https://cloud.blender.org/blog/attract-and-flamenco-public-beta",
title="Learn more about Attract")
| Learn More
a.btn.btn-link(
href="https://flamenco.io",
title="Learn more about Flamenco")
| Learn More
i.pi-angle-right
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/attract_thumbnail.jpg')}}")
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/flamenco_thumbnail.jpg')}}")
section#flamenco.page-card.right
.page-card-side
h2.page-card-title
| Flamenco
.page-card-summary.
Take control of your computing infrastructure and get things done.
| {% if not current_user.has_role('subscriber') %}
section.page-card(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/pattern_01.jpg')}})")
.page-card-side
a.page-card-cta.download.js-watch-video(
href="https://www.youtube.com/watch?v=7cnFKhsM67Q",
data-youtube-id="7cnFKhsM67Q")
i.pi-play
| Watch Video
h2.page-card-title
| All of this, plus hours of training and production assets.
a.page-card-cta(
href="https://flamenco.io",
title="Learn more about Flamenco")
| Learn More
.page-card-summary.text-white
| Join us for only $9.90/month!
.page-card-side
img(
src="{{ url_for('static', filename='assets/img/features/flamenco_thumbnail.jpg')}}")
| {% if not current_user.has_role('subscriber') %}
section.page-card.subscribe(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/pattern_01.jpg')}})")
.page-card-side
h2.page-card-title
| All of this, plus hours of training and production assets.
.page-card-summary
| Join us for only $9.90/month!
a.page-card-cta(
href="https://store.blender.org/product/membership/")
| Subscribe Now
| {% endif %}
a.btn.btn-outline-light.px-3(href="https://store.blender.org/product/membership/")
i.pi-heart.mr-2
| Subscribe Now
| {% endif %}
| {% endblock %}
| {% block footer_scripts %}
script.
// Click anywhere in the page to hide the overlay
// Hide the video overlay.
function hideOverlay() {
$('#page-overlay.video').removeClass('active');
$('#page-overlay.video .video-embed').html('');
}
// Click anywhere in the page or hit Esc to hide the overlay.
$(document).click(function() {
hideOverlay();
});
@@ -229,12 +227,12 @@ script.
});
$('a.js-watch-video').click(function(e){
var videoId = $(this).attr('data-youtube-id');
e.preventDefault();
e.stopPropagation();
$('#page-overlay.video').addClass('active');
var videoId = $(this).attr('data-youtube-id');
$('#page-overlay .video-embed').html('<iframe src="https://www.youtube.com/embed/' + videoId +'?rel=0&amp;showinfo=0;autoplay=1" frameborder="0" allowfullscreen></iframe>')
});

View File

@@ -5,7 +5,7 @@
| {% block og %}
meta(property="og:title", content="Blender Cloud Statistics")
meta(property="og:url", content="https://cloud.blender.org/stats")
meta(property="og:url", content="{{ request.url }}")
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_andy_hdribot_01.jpg')}}")
| {% endblock %}

View File

@@ -65,7 +65,7 @@ p Your organisation provides you with your subscription.
hr
p
button#recheck_subscription.btn.btn-default(onclick="javascript:recheck_subscription(this)") Re-check my subscription
button#recheck_subscription.btn.btn-outline-secondary(onclick="javascript:recheck_subscription(this)") Re-check my subscription
hr

View File

@@ -11,7 +11,7 @@
| {% endfor %}
.buttons
button.btn.btn-default.button-submit(type='submit')
button.btn.btn-outline-success.button-submit(type='submit')
i.pi-check
| Save Changes
| {% endblock %}

View File

@@ -8,7 +8,7 @@
| {% block og %}
meta(property="og:title", content="Blender Cloud - Open Content Production Platform")
meta(property="og:url", content="https://cloud.blender.org/")
meta(property="og:url", content="{{ request.url }}")
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_dweebs_01.jpg')}}")
| {% endblock og %}
@@ -28,12 +28,12 @@ li
| {% endblock navigation_sections %}
| {% block navigation_user %}
li.nav-item-sign-in
li.pt-1.pr-1
| {% if current_user.is_anonymous %}
a.navbar-item(href="{{ url_for('users.login', next='/') }}")
a.btn.btn-outline-success(href="{{ url_for('users.login', next='/') }}")
| Log in and Explore
| {% else %}
a.navbar-item(href="{{ url_for('main.homepage') }}")
a.btn.btn-outline-success(href="{{ url_for('main.homepage') }}")
| Explore
| {% endif %}
| {% endblock navigation_user %}
@@ -70,7 +70,7 @@ li.nav-item-sign-in
improve it for everyone's benefit.
.page-card-side
a.page-card-image(href="https://cloud.blender.org/p/caminandes-3/56bdacccc379cf00797160b0", target="_blank")
a.page-card-image(href="/p/caminandes-3/56bdacccc379cf00797160b0", target="_blank")
video(autoplay, loop)
source(src="{{ url_for('static', filename='assets/img/features/animation_review_01.mp4')}}")
@@ -92,7 +92,7 @@ li.nav-item-sign-in
Access high quality content, organized in
#[a(href="{{ url_for('cloud.courses') }}") classes],
#[a(href="{{ url_for('cloud.workshops') }}") workshop] and the
#[a(href="https://cloud.blender.org/p/gallery") art gallery],
#[a(href="/p/gallery") art gallery],
a curated artwork selection, where you can open a
.blend file and see how it was made.
@@ -108,7 +108,7 @@ li.nav-item-sign-in
| See #[a.learn(href="{{ url_for('cloud.courses') }}") Courses] & #[a.learn(href="{{ url_for('cloud.courses') }}") Workshops]
.page-card-side
a.page-card-image(href="https://cloud.blender.org/p/scripting-for-artists/")
a.page-card-image(href="/p/scripting-for-artists/")
img(
alt="Sybren teaches Python Scripting with Blender",
src="{{ url_for('static', filename='assets/img/backgrounds/background_sybren_01.jpg')}}")
@@ -121,7 +121,7 @@ li.nav-item-sign-in
.page-triplet-container.homepage
.row
.col-md-4
.triplet-card(data-url="https://cloud.blender.org/p/minecraft-animation-workshop/")
.triplet-card(data-url="/p/minecraft-animation-workshop/")
.triplet-card-thumbnail
img(
alt="Textures",
@@ -130,11 +130,11 @@ li.nav-item-sign-in
h3 Minecraft Animation
p.
Learn how to make animations with this workshop by Dillon Gu.
a.triplet-cta(href="https://cloud.blender.org/p/minecraft-animation-workshop/")
a.triplet-cta(href="/p/minecraft-animation-workshop/")
| LEARN MORE
.col-md-4
.triplet-card(data-url="https://cloud.blender.org/p/motion-graphics/")
.triplet-card(data-url="/p/motion-graphics/")
.triplet-card-thumbnail
img(
alt="HDRI",
@@ -143,11 +143,11 @@ li.nav-item-sign-in
h3 Motion Graphics
p.
A comprehensive guide to motion graphics techniques using Blender.
a.triplet-cta(href="https://cloud.blender.org/p/motion-graphics/")
a.triplet-cta(href="/p/motion-graphics/")
| LEARN MORE
.col-md-4
.triplet-card(data-url="https://cloud.blender.org/p/gallery")
.triplet-card(data-url="/p/gallery")
.triplet-card-thumbnail
img(
alt="Characters",
@@ -156,25 +156,25 @@ li.nav-item-sign-in
h3 Art Walk-throughs
p.
Follow the creative process and techniques behind stunning artwork.
a.triplet-cta(href="https://cloud.blender.org/p/gallery")
a.triplet-cta(href="/p/gallery")
| LEARN MORE
.row.training-other
.col-md-10.col-md-offset-1
p.
Other training:
#[a(href="https://cloud.blender.org/p/toon-character-workflow/") Toon Character Workflow],
#[a(href="https://cloud.blender.org/p/3d-printing/") Blender for 3D Printing],
#[a(href="https://cloud.blender.org/p/game-asset-creation/") Game Asset Creation],
#[a(href="https://cloud.blender.org/p/blenderella/") Character Modeling],
#[a(href="https://cloud.blender.org/p/character-animation/") Character Animation],
#[a(href="https://cloud.blender.org/p/humane-rigging/") Introduction] and
#[a(href="https://cloud.blender.org/p/blenrig/") Advanced Rigging],
#[a(href="https://cloud.blender.org/p/track-match-2/") VFX Workflow],
#[a(href="https://cloud.blender.org/p/creature-factory-2/") Creature] and
#[a(href="https://cloud.blender.org/p/venoms-lab-2/") Cartoon Character creation],
#[a(href="https://cloud.blender.org/p/chaos-evolution/") Advanced]
#[a(href="https://cloud.blender.org/p/blend-and-paint/") Digital Painting] and
#[a(href="/p/toon-character-workflow/") Toon Character Workflow],
#[a(href="/p/3d-printing/") Blender for 3D Printing],
#[a(href="/p/game-asset-creation/") Game Asset Creation],
#[a(href="/p/blenderella/") Character Modeling],
#[a(href="/p/character-animation/") Character Animation],
#[a(href="/p/humane-rigging/") Introduction] and
#[a(href="/p/blenrig/") Advanced Rigging],
#[a(href="/p/track-match-2/") VFX Workflow],
#[a(href="/p/creature-factory-2/") Creature] and
#[a(href="/p/venoms-lab-2/") Cartoon Character creation],
#[a(href="/p/chaos-evolution/") Advanced]
#[a(href="/p/blend-and-paint/") Digital Painting] and
#[a(href="{{ url_for('cloud.courses') }}") much more]!
@@ -215,7 +215,7 @@ li.nav-item-sign-in
.page-triplet-container.homepage
.row
.col-md-4
.triplet-card(data-url="https://cloud.blender.org/p/hero/")
.triplet-card(data-url="/p/hero/")
.triplet-card-thumbnail
img(
alt="Hero",
@@ -224,11 +224,11 @@ li.nav-item-sign-in
h3 Hero
p.
The first ever Grease Pencil open movie made with Blender 2.8
a.triplet-cta(href="https://cloud.blender.org/p/hero/")
a.triplet-cta(href="/p/hero/")
| LEARN MORE
.col-md-4
.triplet-card(data-url="https://cloud.blender.org/p/spring/")
.triplet-card(data-url="/p/spring/")
.triplet-card-thumbnail
img(
alt="Spring",
@@ -237,11 +237,11 @@ li.nav-item-sign-in
h3 Spring
p.
A poetic fantasy film. #[br] A stunning visual journey.
a.triplet-cta(href="https://cloud.blender.org/p/spring/")
a.triplet-cta(href="/p/spring/")
| LEARN MORE
.col-md-4
.triplet-card(data-url="https://cloud.blender.org/p/caminandes-3/")
.triplet-card(data-url="/p/caminandes-3/")
.triplet-card-thumbnail
img(
alt="Caminandes",
@@ -250,21 +250,21 @@ li.nav-item-sign-in
h3 Caminandes
p.
Follow the adventures of Koro through the Patagonian pampas.
a.triplet-cta(href="https://cloud.blender.org/p/caminandes-3/")
a.triplet-cta(href="/p/caminandes-3/")
| LEARN MORE
.row.training-other
.col-md-10.col-md-offset-1
p.
Other open movies:
#[a(href="https://cloud.blender.org/p/elephants-dream/") Elephants Dream],
#[a(href="https://cloud.blender.org/p/big-buck-bunny/") Big Buck Bunny],
#[a(href="https://cloud.blender.org/p/sintel/") Sintel],
#[a(href="https://cloud.blender.org/p/tears-of-steel/") Tears of Steel],
#[a(href="https://cloud.blender.org/p/cosmos-laundromat/") Cosmos Laundromat],
#[a(href="https://cloud.blender.org/p/glass-half/") Glass Half],
#[a(href="https://cloud.blender.org/p/dailydweebs/") The Daily Dweebs],
#[a(href="https://cloud.blender.org/p/agent-327/") Agent 327]
#[a(href="/p/elephants-dream/") Elephants Dream],
#[a(href="/p/big-buck-bunny/") Big Buck Bunny],
#[a(href="/p/sintel/") Sintel],
#[a(href="/p/tears-of-steel/") Tears of Steel],
#[a(href="/p/cosmos-laundromat/") Cosmos Laundromat],
#[a(href="/p/glass-half/") Glass Half],
#[a(href="/p/dailydweebs/") The Daily Dweebs],
#[a(href="/p/agent-327/") Agent 327]
and #[a(href="{{ url_for('cloud.open_projects') }}") more]

View File

@@ -1,112 +0,0 @@
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(0eC6fl06luXEYWpBSJvXCBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(Fl4y0QdOxyyTHEGMXX8kcRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(-L14Jk06m6pUHB-5mXQQnRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(I3S1wsgSg9YCurV6PUkTORJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(NYDWBdD4gIq26G5XYbHsFBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(Pru33qjShpZSmG3z6VYwnRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(Hgo13k-tfSpn0qi1SFdUfVtXRa8TVwTICgirnJhmVJw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(ek4gzZ-GeXAPcSbHtCeQI_esZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(mErvLBYg_cXG3rLvUsKT_fesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(-2n2p-_Y08sg57CNWQfKNvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(u0TOpm082MNkS5K0Q4rhqvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(NdF9MtnOpLzo-noMoG0miPesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(Fcx7Wwv8OzT71A3E1XOAjvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(CWB0XYA8bzo0kSThX0UTuA.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
}