Introducing Pillar Framework

Refactor of pillar-server and pillar-web into a single python package. This
simplifies the overall architecture of pillar applications.

Special thanks @sybren and @venomgfx
This commit is contained in:
2016-08-19 09:19:06 +02:00
parent a5e92e1d87
commit 2c5dc34ea2
232 changed files with 79508 additions and 2232 deletions

View File

@@ -0,0 +1,27 @@
| {% macro add_new_menu(node_types) %}
| {% for node_type in node_types %}
| {% if node_type['name'] in ['group', 'group_texture', 'group_hdri', 'asset', 'texture', 'page', 'hdri'] %}
| {% set node_type_name = node_type['name'] %}
| {% if node_type_name == 'group' %}
| {% set node_type_name = 'folder' %}
| {% endif %}
li(class="button-{{ node_type['name'] }}")
a.item_add_node(
href="#",
title="{{ node_type['description'] }}",
data-node-type-name="{{ node_type['name'] }}",
data-toggle="tooltip",
data-placement="left")
i.pi(class="icon-{{ node_type['name'] }}")
| {% if node_type_name == 'group_texture' %}
| Texture Folder
| {% elif node_type_name == 'group_hdri' %}
| HDRi Folder
| {% else %}
| {{ node_type_name }}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% endmacro %}

View File

@@ -0,0 +1,18 @@
| {% macro render_file_uploader() %}
#fileUploaderModal.modal.fade(
tabindex="-1", role="dialog", aria-labelledby="fileUploaderModalLabel", aria-hidden="true")
.modal-dialog
.modal-content
.modal-header
button.close(type="button", data-dismiss="modal", aria-label="Close")
span(aria-hidden="true") ×
h4.modal-title Upload file
.modal-body
| {% include '_macros/include _file_uploader_form.html' %}
.modal-footer
button.btn.btn-default(type="button", data-dismiss="modal") Close
| {% endmacro %}

View File

@@ -0,0 +1,70 @@
#node-add-container
#node-add-header
.node-add-title Upload Assets
#node-add-form
p.
This is the first step in the asset creation process. Once files are uploaded,
they are stored in a temp location until further actions are taken.
You can upload multiple assets simultaneously, but you can only edit one at a time.
hr
// The file upload form used as target for the file upload widget
form#fileupload(action="{{url_for('files.upload')}}", method='POST', enctype='multipart/form-data')
// Redirect browsers with JavaScript disabled to the origin page
noscript
input(type='hidden', name='redirect', value="{{url_for('files.upload')}}")
// The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload
.row.fileupload-buttonbar
.col-lg-7
// The fileinput-button span is used to style the file input field as button
span.btn.btn-success.fileinput-button
i.pi-plus
span Add files...
input(type='file', name='file', multiple='')
button.btn.btn-primary.start(type='submit')
i.pi-upload
span Start upload
button.btn.btn-warning.cancel(type='reset')
i.pi-cancel
span Cancel upload
button.btn.btn-danger.delete(type='button')
i.pi-trash
span Delete
input.toggle(type='checkbox')
// The global file processing state
span.fileupload-process
// The global progress state
.col-lg-5.fileupload-progress.fade
// The global progress bar
.progress.progress-striped.active(role='progressbar', aria-valuemin='0', aria-valuemax='100')
.progress-bar.progress-bar-success(style='width:0%;')
// The extended global progress state
.progress-extended  
// The table listing the files available for upload/download
table.table(role='presentation')
tbody.files
br
h3 Notes
ul
li
| The maximum file size for this interface is
strong {{ config.MAX_CONTENT_LENGTH | filesizeformat }}
| .
li
| Only the following formats are allowed:
br
strong.text-uppercase
| {% for f in config.ALLOWED_EXTENSIONS %}
| {{f}}
| {% endfor %}

View File

@@ -0,0 +1,133 @@
| {% raw %}
// The template to display files available for upload
script#template-upload(type="text/x-tmpl").
| {% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-upload fade">
<td>
<span class="preview"></span>
</td>
<td>
<span class="name">{%=file.name%}</span>
<strong class="error text-danger"></strong>
</td>
<td>
<p class="size">Processing...</p>
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
</td>
<td>
{% if (!i && !o.options.autoUpload) { %}
<button class="btn btn-primary start" disabled>
<i class="ion-upload"></i>
<span>Start</span>
</button>
{% } %}
{% if (!i) { %}
<button class="btn btn-warning cancel">
<i class="ion-close-round"></i>
<span>Cancel</span>
</button>
{% } %}
</td>
</tr>
| {% } %}
// The template to display files available for download
script#template-download(type="text/x-tmpl").
| {% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-download fade">
<td>
<span class="preview">
{% if (file.thumbnailUrl) { %}
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
{% } %}
</span>
</td>
<td>
<span class="name">
{% if (file.url) { %}
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
{% } else { %}
<span>{%=file.name%}</span>
{% } %}
</span>
{% if (file.error) { %}
<div><span class="label label-danger">Error</span> {%=file.error%}</div>
{% } %}
</td>
<td>
<span class="size">{%=o.formatFileSize(file.size)%}</span>
</td>
<td>
{% if (file.deleteUrl) { %}
<button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
<i class="ion-trash-b"></i>
<span>Delete</span>
</button>
<input type="checkbox" name="delete" value="1" class="toggle">
<div class="btn btn-success create" data-name="{%=file.name%}" data-type="{%=file.type%}">
<i class="ion-upload"></i>
Create
</div>
{% } else { %}
<button class="btn btn-warning cancel">
<i class="ion-close-round"></i>
<span>Cancel</span>
</button>
{% } %}
</td>
</tr>
| {% } %}
| {% endraw %}
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.iframe-transport.min.js') }}")
script(src="{{ url_for('static_pillar', filename='javascript-templates/js/tmpl.min.js') }}")
script(src="{{ url_for('static_pillar', filename='javascript-load-image/js/load-image.all.min.js') }}")
script(src="{{ url_for('static_pillar', filename='javascript-canvas-to-blob/js/canvas-to-blob.min.js') }}")
script(src="{{ url_for('static_pillar', filename='gallery/js/jquery.blueimp-gallery.min.js') }}")
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.iframe-transport.min.js') }}")
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.fileupload.min.js') }}")
script(src="{{ url_for('static_pillar', filename='jquery-file-upload/js/jquery.fileupload-process.js') }}")
script(src="{{ url_for('static_pillar', filename='jquery-file-upload/js/jquery.fileupload-image.js') }}")
script(src="{{ url_for('static_pillar', filename='jquery-file-upload/js/jquery.fileupload-audio.js') }}")
script(src="{{ url_for('static_pillar', filename='jquery-file-upload/js/jquery.fileupload-video.js') }}")
script(src="{{ url_for('static_pillar', filename='jquery-file-upload/js/jquery.fileupload-validate.js') }}")
script(src="{{ url_for('static_pillar', filename='jquery-file-upload/js/jquery.fileupload-ui.js') }}")
script(src="{{ url_for('static_pillar', filename='jquery-file-upload/js/main.js') }}")
script().
$('body').unbind('click');
$('body').on('click', '.create', function(event) {
// Start the asset creation process
event.preventDefault();
var parent_id = ProjectUtils.nodeId();
$('#node-add-form').text('Please wait...');
$.post('{{url_for('nodes.assets_create')}}', {
name: $(this).attr('data-name'),
project_id: ProjectUtils.projectId(),
type: $(this).attr('data-type'),
parent_id: parent_id})
.done(function(data) {
if (parent_id) {
// We are in embedded mode and try to call the editNode function
editNode(data.asset_id);
} else {
window.location.replace("/nodes/" + data.asset_id + "/edit");
}
//alert( "Data Loaded: " + data.message );
});
});
// Temporary list of CSS to style the upload form
var cssLinks = ['/static/assets/css/blueimp/blueimp-gallery.min.css',
'/static/jquery-file-upload/css/jquery.fileupload.css',
'/static/jquery-file-upload/css/jquery.fileupload-ui.css']
$.each(cssLinks, function(index, value) {
// Check if the CSS is needed
if (!$("link[href='" + value + "']").length) {
$('<link href="' + value + '" rel="stylesheet">').appendTo("head");
}
});

View File

@@ -0,0 +1,15 @@
| {% macro navigation_tabs(title) %}
section#nav-tabs
ul#nav-tabs__list
li.nav-tabs__list-tab(
class="{% if title == 'homepage' %}active{% endif %}")
a(href="{{ url_for('main.homepage') }}") Activity
li.nav-tabs__list-tab(
class="{% if title == 'dashboard' %}active{% endif %}")
a(href="{{ url_for('projects.index') }}") My Projects
li.nav-tabs__list-tab(
class="{% if title == 'home' %}active{% endif %}")
a(href="{{ url_for('projects.home_project') }}") Home
| {% endmacro %}

View File

@@ -0,0 +1,34 @@
| {% macro render_field(field) %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {% if field.type == 'BooleanField' %}
.checkbox
label
| {{ field(class='checkbox') }}
| {{ field.label }}
| {% elif field.type == 'FieldList' %}
ul.fieldlist#files
| {% for file in field %}
li.fieldlist-item
| {% for subfield in file %}
| {{ render_field(subfield) }}
| {% endfor %}
| {% endfor %}
| {% else %}
| {{ field.label }}
| {{ field(class='form-control') }}
| {% endif %}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endmacro %}

13
src/templates/_modal.jade Normal file
View File

@@ -0,0 +1,13 @@
// Modal
#modal-default.modal.fade(tabindex='-1', role='dialog', aria-labelledby='modal-default-label')
.modal-dialog(role='document')
.modal-content
.modal-header
button.close(type='button', data-dismiss='modal', aria-label='Close')
span(aria-hidden='true') ×
h4#modal-default-label.modal-title Modal title
.modal-body
| ...
.modal-footer
button.btn.btn-default(type='button', data-dismiss='modal') Close
button.btn.btn-primary(type='button') Save changes

View File

@@ -0,0 +1,4 @@
ul#notifications-list
li.nc-item
#notifications-loader
i.pi-spin.spin

View File

@@ -0,0 +1,4 @@
| {% extends "errors/layout.html" %}
| {% block body %}
| {% include "errors/403_embed.html" %}
| {% endblock %}

View File

@@ -0,0 +1,25 @@
#error_container.403
#error_box
.error-top-container
.error-title Sorry to bother you, but...
.error-lead.
This content is only available to Cloud subscribers.<br/>
Get full access to the Blender Cloud for only $9.90 per month.
.buttons
a.sign-up.btn.btn-outline(href="https://store.blender.org/product/membership/")
i.pi-check
| Subscribe Now
| {% if not current_user.is_authenticated %}
a.sign-in.btn.btn-empty(href="{{ url_for('users.login') }}")
i.pi-log-in
| Log in
| {% endif %}
hr
.error-lead.extra.
If you have just subscribed, please <a href="{{ url_for('users.logout') }}">log out</a> and in again.<br/>
For any other issue get in touch with <a href="mailto:cloudsupport@blender.org">cloudsupport@blender.org</a>

View File

@@ -0,0 +1,17 @@
| {% extends "errors/layout.html" %}
| {% block body %}
#error_container.404.standalone
#error_box
.error-top-container
.error-title Not found.
.error-lead
p.
The error has been logged and we're working on getting it fixed.
hr
p.
Looking for the Open Movies? Check out <a href="https://www.youtube.com/BlenderFoundation">Blender Foundation's YouTube</a> channel. <br/> Were you looking for tutorials instead? <a href="http://www.blender.org/support/tutorials/">blender.org</a> has a good selection.
.error-lead.extra.
We'll be back soon, in the meantime follow <a href="https://twitter.com/Blender_Cloud">@Blender_Cloud</a> for updates.
| {% endblock %}

View File

@@ -0,0 +1,12 @@
#error_container.404
#error_box
.error-title 404. Not Found.
.error-lead.
Whatever you're looking for, it's not here.
hr
.error-lead.extra.
Is this content missing? Let us know on <a href="https://twitter.com/Blender_Cloud">Twitter</a>
or email <a href="mailto:cloudsupport@blender.org">cloudsupport@blender.org</a>

View File

@@ -0,0 +1,42 @@
doctype
html(lang="en")
head
meta(charset="utf-8")
title Blender Cloud
meta(name="viewport", content="width=device-width, initial-scale=1.0")
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 past open projects.")
meta(name="author", content="Blender Institute")
meta(name="theme-color", content="#3e92aa")
script.
!function(e){"use strict";e.loadCSS=function(t,n,o){var r,i=e.document,l=i.createElement("link");if(n)r=n;else{var d=(i.body||i.getElementsByTagName("head")[0]).childNodes;r=d[d.length-1]}var a=i.styleSheets;l.rel="stylesheet",l.href=t,l.media="only x",r.parentNode.insertBefore(l,n?r:r.nextSibling);var f=function(e){for(var t=l.href,n=a.length;n--;)if(a[n].href===t)return e();setTimeout(function(){f(e)})};return l.onloadcssdefined=f,f(function(){l.media=o||"all"}),l},"undefined"!=typeof module&&(module.exports=e.loadCSS)}(this);
loadCSS( "//fonts.googleapis.com/css?family=Roboto:300,400,500" );
loadCSS( "//fonts.googleapis.com/css?family=Lato:300,400" );
link(href="{{ url_for('static_pillar', filename='assets/ico/favicon.png') }}", rel="shortcut icon")
link(href="{{ url_for('static_pillar', filename='assets/ico/apple-touch-icon-precomposed.png') }}", rel="icon apple-touch-icon-precomposed", sizes="192x192")
link(href="{{ url_for('static_pillar', filename='assets/css/main.css') }}", rel="stylesheet")
body.error
#error_container.500.standalone
#error_box
.error-top-container
.error-title Something went wrong.
.error-lead
p.
The error has been logged and we're working on getting it fixed.
hr
p.
Looking for the Open Movies? Check out <a href="https://www.youtube.com/BlenderFoundation">Blender Foundation's YouTube</a> channel. <br/> Were you looking for tutorials instead? <a href="http://www.blender.org/support/tutorials/">blender.org</a> has a good selection.
.error-lead.extra.
We'll be back soon, in the meantime follow <a href="https://twitter.com/Blender_Cloud">@Blender_Cloud</a> for updates.
noscript
link(href='//fonts.googleapis.com/css?family=Roboto:300,400,500', rel='stylesheet', type='text/css')
link(href='//fonts.googleapis.com/css?family=Lato:300,400', rel='stylesheet', type='text/css')

View File

@@ -0,0 +1,27 @@
doctype
html(lang="en")
head
meta(charset="utf-8")
title Blender Cloud
meta(name="viewport", content="width=device-width, initial-scale=1.0")
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 past open projects.")
meta(name="author", content="Blender Institute")
meta(name="theme-color", content="#3e92aa")
script.
!function(e){"use strict";e.loadCSS=function(t,n,o){var r,i=e.document,l=i.createElement("link");if(n)r=n;else{var d=(i.body||i.getElementsByTagName("head")[0]).childNodes;r=d[d.length-1]}var a=i.styleSheets;l.rel="stylesheet",l.href=t,l.media="only x",r.parentNode.insertBefore(l,n?r:r.nextSibling);var f=function(e){for(var t=l.href,n=a.length;n--;)if(a[n].href===t)return e();setTimeout(function(){f(e)})};return l.onloadcssdefined=f,f(function(){l.media=o||"all"}),l},"undefined"!=typeof module&&(module.exports=e.loadCSS)}(this);
loadCSS( "//fonts.googleapis.com/css?family=Roboto:300,400,500" );
loadCSS( "//fonts.googleapis.com/css?family=Lato:300,400" );
link(href="{{ url_for('static_pillar', filename='assets/ico/favicon.png') }}", rel="shortcut icon")
link(href="{{ url_for('static_pillar', filename='assets/ico/apple-touch-icon-precomposed.png') }}", rel="icon apple-touch-icon-precomposed", sizes="192x192")
link(href="{{ url_for('static_pillar', filename='assets/css/main.css') }}", rel="stylesheet")
body.error
| {% block body %}{% endblock %}
noscript
link(href='//fonts.googleapis.com/css?family=Roboto:300,400,500', rel='stylesheet', type='text/css')
link(href='//fonts.googleapis.com/css?family=Lato:300,400', rel='stylesheet', type='text/css')

378
src/templates/homepage.jade Normal file
View File

@@ -0,0 +1,378 @@
| {% extends 'layout.html' %}
| {% from '_macros/_navigation.html' import navigation_tabs %}
| {% set title = 'homepage' %}
| {% block og %}
meta(property="og:title", content="Blender Cloud")
meta(property="og:url", content="https://cloud.blender.org/")
meta(property="og:image", content="{% if main_project.picture_header %}{{ main_project.picture_header.thumbnail('l', api=api) }}{% else %}{{ url_for('static', filename='assets/img/backgrounds/background_caminandes_3_02.jpg')}}{% endif %}")
| {% endblock %}
| {% block tw %}
meta(name="twitter:title", content="Blender Cloud")
meta(name="twitter: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="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_caminandes_3_02.jpg')}}{% endif %}")
| {% endblock %}
| {% block body %}
.dashboard-container
section#main
| {{ navigation_tabs(title) }}
section#stream
h3#activity-stream__title
| Activity Stream
ul#activity-stream__filters
li Filter
li.filter.active(
data-filter='image',
title="List images")
i.pi-picture
li.filter.active(
data-filter='video',
title="List videos")
i.pi-film-thick
li.filter.active(
data-filter='file',
title="List files")
i.pi-file-archive
li.filter.active(
data-filter='post',
title="List blog posts")
i.pi-newspaper
li.filter(
data-filter='comment',
title="List comments")
i.pi-comment
ul#activity-stream__list
| {% for n in activity_stream %}
| {% if n.node_type == 'comment' %}
li.activity-stream__list-item.hidden(
class="{{ n.node_type }}",
data-url="{{ url_for_node(node=n) }}")
a.activity-stream__list-thumbnail(href="{{ url_for_node(node=n) }}")
i.pi-comment
.activity-stream__list-details
a.title(href="{{ url_for_node(node=n) }}") {{ n.properties.content }}
ul.meta
li.who {{ n.user.full_name }}
li.where-project
a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}
li.where-parent
a(href="{{ url_for_node(node_id=n.attached_to._id) }}") {{ n.attached_to.name }}
li.when
a(href="{{ url_for_node(node=n) }}", title="{{ n._created }}") {{ n._created | pretty_date_time }}
| {% elif n.node_type == 'asset' %}
li.activity-stream__list-item(
class="{{ n.node_type }} {{ n.properties.content_type }}",
data-url="{{ url_for_node(node=n) }}")
a.activity-stream__list-thumbnail(
class="{{ n.properties.content_type }}",
href="{{ url_for_node(node=n) }}")
| {% 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 %}
.activity-stream__list-details
| {% if n.picture %}
a.image(href="{{ url_for_node(node=n) }}")
| {% if n.properties.content_type == 'video' %}
i.pi-play
| {% endif %}
img(src="{{ n.picture.thumbnail('l', api=api) }}")
| {% endif %}
a.date(href="{{ url_for_node(node=n) }}", title="{{ n._created }}") {{ n._created | pretty_date_time }}
a.title(href="{{ url_for_node(node=n) }}")
| {{ n.name }}
| {% if n.permissions.world %}
.ribbon
span free
| {% endif %}
ul.meta
li.what {{ n.properties.content_type }}
li.who {{ n.user.full_name }}
li.where-project
a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}
| {% elif n.node_type == 'post' %}
li.activity-stream__list-item(
class="{{ n.node_type }}",
data-url="{{ url_for_node(node=n) }}")
a.activity-stream__list-thumbnail(href="{{ url_for_node(node=n) }}")
i.pi-newspaper
.activity-stream__list-details
| {% if n.picture %}
a.image(href="{{ url_for_node(node=n) }}")
img(src="{{ n.picture.thumbnail('l', api=api) }}")
| {% endif %}
a.date(href="{{ url_for_node(node=n) }}", title="{{ n._created }}") {{ n._created | pretty_date_time }}
a.title(href="{{ url_for_node(node=n) }}") {{ n.name }}
ul.meta
li.what Blog Post
li.where-project
a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}")
| {{ n.project.name }}
| {% endif %}
| {% endfor %}
li.activity-stream__list-item.empty#activity-stream__empty
| No items to list.
section#side
section#announcement
| {% if main_project.picture_header %}
a(href="https://cloud.blender.org/blog/introducing-blender-sync")
img.header(
src="{{ main_project.picture_header.thumbnail('l', api=api) }}")
| {% endif %}
.text
.title
a(href="https://cloud.blender.org/blog/introducing-blender-sync") Blender Sync
.lead
span.
Save your settings once. Use them anywhere.
Carry your Blender configuration with you, use our free add-on to sync your keymaps and preferences.
<hr/>
Syncing is free for everyone. No subscription required.
.buttons
a.btn.btn-default.btn-outline.orange(
href="https://cloud.blender.org/r/downloads/blender_cloud-latest-bundle.zip")
i.pi-download
| Download <small>v</small> {{ config.BLENDER_CLOUD_ADDON_VERSION }}
a.btn.btn-default.btn-outline.blue(
href="https://cloud.blender.org/blog/introducing-blender-sync")
| Learn More
section#random-asset
h3
a(href="/search") Explore the Cloud
span.section-lead Random selection of the best assets &amp; tutorials
ul.random-asset__list
| {% for n in random_featured %}
| {% if n.picture and loop.first %}
li.random-asset__list-item.featured
| {% if n.permissions.world %}
.ribbon
span free
| {% endif %}
a.random-asset__thumbnail(
href="{{ url_for_node(node=n) }}",
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="{{ url_for_node(node=n) }}")
| {{ n.name }}
ul.meta
li.what
a(href="{{ url_for_node(node=n) }}")
| {% if n.properties.content_type %}{{ n.properties.content_type }}{% else %}Folder{% endif %}
li.where
a(href="{{ url_for('projects.view', project_url=n.project.url) }}")
| {{ n.project.name }}
| {% else %}
li.random-asset__list-item
| {% if n.permissions.world %}
.ribbon
span free
| {% endif %}
a.random-asset__list-thumbnail(
href="{{ url_for_node(node=n) }}",
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="{{ url_for_node(node=n) }}") {{ n.name }}
ul.meta
li.what
a(href="{{ url_for_node(node=n) }}")
| {% if n.properties.content_type %}{{ n.properties.content_type }}{% else %}Folder{% endif %}
li.where
a(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}
| {% endif %}
| {% endfor %}
section#blog-stream
a.feed(
href="{{ url_for('main.feeds_blogs') }}",
title="Blender Cloud & Projects Blog Feed",
data-toggle="tooltip",
data-placement="left")
i.pi-rss
h3
a(href="{{ url_for('main.main_blog') }}") Blog
ul#blog-stream__list
| {% if latest_posts %}
| {% for n in latest_posts %}
| {% if n.picture and loop.first %}
li.blog-stream__list-item.featured
a.blog-stream__thumbnail(
href="{{ url_for_node(node=n) }}")
img(src="{{ n.picture.thumbnail('l', api=api) }}")
a.title(href="{{ url_for_node(node=n) }}")
| {{ n.name }}
ul.meta
li.when
a(href="{{ url_for_node(node=n) }}",
title="Updated {{ n._updated | pretty_date }}")
| {{ n._created | pretty_date }}
li.where-project
a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}
| {% else %}
li.blog-stream__list-item
a.blog-stream__list-thumbnail(href="{{ url_for_node(node=n) }}")
| {% if n.picture %}
img.image(src="{{ n.picture.thumbnail('s', api=api) }}")
| {% else %}
i.pi-newspaper
| {% endif %}
.blog-stream__list-details
a.title(href="{{ url_for_node(node=n) }}") {{ n.name }}
ul.meta
li.when
a(href="{{ url_for_node(node=n) }}",
title="Updated {{ n._updated | pretty_date }}")
| {{ n._created | pretty_date }}
li.where-project
a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}
| {% endif %}
| {% endfor %}
| {% else %}
li.blog-stream__list-item
.blog-stream__list-details
ul.meta
li.when No updates yet
| {% endif %}
li.blog-stream__list-item.more
a(href="{{ url_for('main.main_blog') }}") See All Blog Posts
| {% endblock %}
| {% block footer_scripts %}
script.
$(function () {
/* cleanup mentions in comments */
$('.activity-stream__list-details a.title').each(function(){
$(this).text($(this).text().replace(/\*|\@|\<(.*?)\>/g, ''));
});
function saveFilters(){
var filtersEnabled = [];
$('ul#activity-stream__filters li.filter.active').each(function(){
filtersEnabled.push($(this).attr('data-filter'));
});
setJSONCookie('bcloud_ui', 'homepage_activity_filters', filtersEnabled);
}
function loadFilters(){
var filters = Cookies.getJSON('bcloud_ui');
if (filters) {
if (filters.homepage_activity_filters && filters.homepage_activity_filters.length){
/* Clear style on filters/items */
$('ul#activity-stream__filters li.filter').removeClass('active');
$('ul#activity-stream__list li.activity-stream__list-item').addClass('hidden');
for (var f in filters.homepage_activity_filters){
var savedFilter = filters.homepage_activity_filters[f];
/* Style each filter type */
$('ul#activity-stream__filters li.filter').each(function(){
if ($(this).attr('data-filter') == savedFilter){
$(this).addClass('active');
}
});
/* Show items that are on the cookie */
$('ul#activity-stream__list li.activity-stream__list-item').each(function(){
if ($(this).hasClass(savedFilter)) {
$(this).removeClass('hidden');
}
});
}
}
}
}
/* Toggle filters */
$('ul#activity-stream__filters li.filter').click(function(){
// Style the filter button
$(this).toggleClass('active');
var filterType = $(this).attr('data-filter');
saveFilters();
// Toggle hidden class on list item if it has class matching the filter
$('ul#activity-stream__list li.activity-stream__list-item').each(function(){
if ($(this).hasClass(filterType)) {
$(this).toggleClass('hidden');
}
});
var hiddenItems = $('ul#activity-stream__list li.activity-stream__list-item.hidden').length;
if (hiddenItems == '{{ activity_stream|length }}'){
$('#activity-stream__empty').show();
}
});
loadFilters();
/* Click on the whole asset/comment row to go */
$('li.activity-stream__list-item.asset, li.activity-stream__list-item.comment').click(function(e){
window.location.href = $(this).data('url');
$(this).addClass('active');
$(this).find('.activity-stream__list-thumbnail i')
.removeAttr('class')
.addClass('pi-spin spin');
});
hopToTop(); // Display jump to top button
});
| {% endblock %}

537
src/templates/join.jade Normal file
View File

@@ -0,0 +1,537 @@
| {% extends 'layout.html' %}
| {% block page_title %}Welcome{% endblock %}
| {% set title = 'join' %}
| {% block og %}
meta(property="og:title", content="Join the Blender Cloud")
meta(property="og:url", content="https://cloud.blender.org/")
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_services.jpg')}}")
| {% endblock %}
| {% block header_backdrop %}
.navbar-backdrop.join(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/background_andy_hdribot_01.jpg')}})")
| {% endblock %}
| {% block page_overlay %}
#page-overlay.video
.video-embed
| {% endblock %}
| {% block body %}
#page-container.join
#page-header
.page-title-icons
i.pi-blender
i.pi-heart-filled
i.pi-blender-cloud
.page-title
| Your Own Production Platform
//- .page-title-summary
//- | Get inspiration, knowledge, and tools all in one place.
.page-header-cta-container
a.page-header-cta(href="https://store.blender.org/product/membership/")
| Join Now
a.page-header-cta-extra(href="{{ url_for('main.nodes_search_index') }}")
| Explore
i.pi-angle-right
#page-content
.page-triplet-container.homepage
.row
.col-md-4
.triplet-card(data-url="{{ url_for('main.open_projects') }}")
.triplet-card-thumbnail
img(
alt="Open Projects",
src="{{ url_for('static', filename='assets/img/features/open_movies_02.jpg')}}")
.triplet-card-info
h3 Open Projects
p.
The iconic Blender Institute Open Movies,
featuring all the production files, assets, artwork, and never-seen-before content.
span.triplet-cta
| LEARN MORE
.col-md-4
.triplet-card(data-url="{{ url_for('main.training') }}")
.triplet-card-thumbnail
img(
alt="Training and Tutorials",
src="{{ url_for('static', filename='assets/img/features/training_02.jpg')}}")
.triplet-card-info
h3 Training &amp; Tutorials
p.
Character modeling, 3D printing, VFX, rigging and more. We offer
12 complete training series with +100 hours of training.
span.triplet-cta
| LEARN MORE
.col-md-4
.triplet-card(data-url="{{ url_for('main.services') }}")
.triplet-card-thumbnail
img(
alt="Services and Tools",
src="{{ url_for('static', filename='assets/img/features/services_01.jpg')}}")
.triplet-card-info
h3 Services
p.
Crate your personal projects, collaborate with other members, store
and sync your Blender settings across multiple workstations.
span.triplet-cta
| LEARN MORE
section.page-card-header
h2 Download 1000s of files and assets
.page-triplet-container.homepage
.row
.col-md-4
.triplet-card(data-url="{{ url_for('main.redir_hdri') }}")
.triplet-card-thumbnail
img(
alt="HDRI",
src="{{ url_for('static', filename='assets/img/features/hdri_01.jpg')}}")
.triplet-card-info
h3 HDRI
p.
Up to 8K and 18 EVs (extremely high) HDR images to light your renders.
span.triplet-cta
| LEARN MORE
.col-md-4
.triplet-card(data-url="{{ url_for('main.redir_textures') }}")
.triplet-card-thumbnail
img(
alt="Textures",
src="{{ url_for('static', filename='assets/img/features/textures_01.jpg')}}")
.triplet-card-info
h3 Textures
p.
More than 1500 texture maps.
Browse online or from Blender with our awesome add-on.
span.triplet-cta
| LEARN MORE
.col-md-4
.triplet-card(data-url="{{ url_for('main.redir_characters') }}")
.triplet-card-thumbnail
img(
alt="Characters",
src="{{ url_for('static', filename='assets/img/features/characters_01.jpg')}}")
.triplet-card-info
h3 Characters
p.
Production quality, fully rigged and shaded characters ready to animate.
span.triplet-cta
| LEARN MORE
section.page-card-header
h2 Learn by Example
section.page-card.services-projects
.page-card-side
h2.page-card-title Exclusive Production Insights
.page-card-summary
p.
Watch the original authors of shots breaking it down into a detailed
explanation and share their insight in the production process. Watch
animation reviews, narrated timelapses, shot walk-throughs.
.page-card-side
.page-card-image
img(
alt="Exclusive Production Insights",
src="{{ url_for('static', filename='assets/img/features/animation_review_01.gif')}}")
section.page-card.right.services-projects
.page-card-side
h2.page-card-title Production Quality Files
.page-card-summary
p.
From fully rigged characters ready to animate to an Art Gallery
curated by the best Blender artists, access top quality blendfiles to learn
new techniques and improve your art.
.page-card-side
.page-card-image
img(
alt="High Quality Assets",
src="{{ url_for('static', filename='assets/img/features/locomotive_01.jpg')}}")
#blender-addon.page-section-container(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/pattern_bw_01.jpg')}})")
section.page-card-header.dark Blender Cloud Add-on
span.page-card-header_lead.dark Connect Blender with the Cloud
a.page-card-cta.download(
href="https://cloud.blender.org/r/downloads/blender_cloud-latest-bundle.zip")
i.pi-download
| Download <small>v</small>{{ config.BLENDER_CLOUD_ADDON_VERSION }}
section.page-card.dark.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 free add-on to sync your keymaps and preferences.
<hr/>
<small>Syncing settings is free for everyone! No subscription required.</small>
a.page-card-cta(
href="https://cloud.blender.org/blog/introducing-blender-sync")
| Learn More
.page-card-side
.page-card-icon
svg(xmlns="http://www.w3.org/2000/svg",
width="64", height="54", viewBox="0 0 64 54")
g(fill="none", stroke="#aaa", stroke-width="2", stroke-miterlimit="10")
path(d="M29 47H5l-4-4v-2h24l2 2h2M29 3H10C8.344 3 7 4.343 7 6v32M35 51h24l4-4v-2H39l-2 2h-2M35 7h19c1.656 0 3 1.343 3 3v32M32 34v20M32 20v8M32 0v14")
g
path(d="M32 31c-3.866 0-7-3.134-7-7M32 17c3.866 0 7 3.134 7 7M32 31h8M24 17h8M36 35l4-4-4-4M28 21l-4-4 4-4")
path(d="M29 37H11V7h18M35 11h18v30H35")
section.page-card.dark
.page-card-side
h2.page-card-title Texture Browser
.page-card-summary
p.
Access the <a href="https://cloud.blender.org/p/textures/">Blender Cloud Textures and HDRI</a>
libraries from within Blender.
Create, manage and share <em>your own</em> texture libraries!
a.page-card-cta.watch-video(
href="https://www.youtube.com/watch?v=-srXYv2Osjw",
data-youtube-id="-srXYv2Osjw")
i.pi-play
| Watch Video
.page-card-side
.page-card-icon
svg(xmlns="http://www.w3.org/2000/svg",
width="64", height="60",
viewBox="0 0 64 60")
g(fill="#aaa")
path(d="M32 60c-.188 0-.377-.053-.542-.16l-31-20C.173 39.656 0 39.34 0 39s.173-.656.458-.84l31-20c.33-.213.754-.213 1.084 0l31 20c.285.184.458.5.458.84s-.173.656-.458.84l-31 20c-.165.107-.354.16-.542.16zM2.845 39L32 57.81 61.155 39 32 20.19 2.845 39z")
path(d="M32 51c-.188 0-.377-.053-.542-.16l-31-20C.173 30.656 0 30.34 0 30s.173-.656.458-.84l31-20c.33-.213.754-.213 1.084 0l31 20c.285.184.458.5.458.84s-.173.656-.458.84l-31 20c-.165.107-.354.16-.542.16zM2.845 30L32 48.81 61.155 30 32 11.19 2.845 30z")
path(d="M32 42c-.188 0-.377-.053-.542-.16l-31-20C.173 21.656 0 21.34 0 21s.173-.656.458-.84l31-20c.33-.213.754-.213 1.084 0l31 20c.285.184.458.5.458.84s-.173.656-.458.84l-31 20c-.165.107-.354.16-.542.16zM2.845 21L32 39.81 61.155 21 32 2.19 2.845 21z")
path(d="M31 27h2v2h-2zm0-4h2v2h-2zm0 8h2v2h-2zm4-4h2v2h-2zm4 2h2v2h-2zm-16 0h2v2h-2zm12 2h2v2h-2zm-8-4h2v2h-2zm0 4h2v2h-2zm4 4h2v2h-2zm31 15h2v2h-2zm0-4h2v2h-2zm0 8h2v2h-2zm0 4h2v2h-2zm0-54h2v2h-2zm0-4h2v2h-2zm0 8h2v2h-2zm0 4h2v2h-2zM0 50h2v2H0zm0-4h2v2H0zm0 8h2v2H0zm0 4h2v2H0zM0 4h2v2H0zm0-4h2v2H0zm4 0h2v2H4zm4 0h2v2H8zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm22 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zM4 58h2v2H4zm4 0h2v2H8zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm22 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zM0 8h2v2H0zm0 4h2v2H0z")
section.page-card.dark.right
.page-card-side
h2.page-card-title
| Image Sharing
.page-card-summary
p.
Got a nice render, a Blender oddity, a cool screenshot?
Share it instantly from within Blender to the Cloud, to the world!
a.page-card-cta(
href="https://cloud.blender.org/blog/introducing-image-sharing")
| Learn More
.page-card-side
.page-card-icon
svg(xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64")
g(fill="none",
stroke="#aaa",
stroke-width="2",
stroke-linejoin="round",
stroke-miterlimit="10")
path(d="M1 1h62v62H1zM4 59h2M8 59h2M12 59h2M60 49H48M46 49H27M60 53H40")
path(d="M5 5h54v40H5z")
path(d="M9 45v-3c0-1.656 1.344-3 3-3h6c1.656 0 3 1.344 3 3v3M29 45v-3c0-1.656 1.344-3 3-3h6c1.656 0 3 1.344 3 3v3M13 45v-3M17 45v-3M33 45v-3M37 45v-3M22 31h-5c-2.762 0-5 2.238-5 5v3M38 39v-3c0-2.762-2.238-5-5-5h-5M31 20c0 3.313-1 9-6 9s-6-5.687-6-9c0-1 0-5 6-5s6 4 6 5z")
path(d="M29 27l-2 8h-4l-2-8M18 31c-4-3-5-9-5-9l6-3M32 31c4-3 5-9 5-9l-6-3M59 24L44 9l-8 8M44 9l8 36")
circle(cx="12", cy="12", r="3")
section.page-card
.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.
a.page-card-cta(
href="https://cloud.blender.org/blog/introducing-private-projects")
| Learn More
.page-card-side
.page-card-icon
svg(xmlns='http://www.w3.org/2000/svg', width='56', height='64', viewbox='0 0 56 64')
g(fill='#555')
path(d='M42 38H14V26h28v12zm-26-2h24v-8H16v8zm-4-5H8c-1.654 0-3-1.346-3-3V15h2v13c0 .55.45 1 1 1h4v2z')
path(d='M9.293 19.707L6 16.414l-3.293 3.293-1.414-1.414 4-4c.39-.39 1.023-.39 1.414 0l4 4-1.414 1.414zM48 31h-4v-2h4c.55 0 1-.45 1-1V15h2v13c0 1.654-1.346 3-3 3z')
path(d='M53.293 19.707L50 16.414l-3.293 3.293-1.414-1.414L50 13.586l4.707 4.707M27 15h2v9h-2z')
path(d='M31.293 19.707L28 16.414l-3.293 3.293-1.414-1.414L28 13.586l4.707 4.707M7 49H5V36c0-1.654 1.346-3 3-3h4v2H8c-.55 0-1 .45-1 1v13z')
path(d='M6 50c-.256 0-.512-.098-.707-.293l-4-4 1.414-1.414L6 47.586l3.293-3.293 1.414 1.414-4 4c-.195.195-.45.293-.707.293zm45-1h-2V36c0-.55-.45-1-1-1h-4v-2h4c1.654 0 3 1.346 3 3v13z')
path(d='M50 50.414l-4.707-4.707 1.414-1.414L50 47.586l3.293-3.293 1.414 1.414M27 40h2v9h-2z')
path(d='M28 50.414l-4.707-4.707 1.414-1.414L28 47.586l3.293-3.293 1.414 1.414M6 12c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zM6 2C3.794 2 2 3.794 2 6s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zm22 10c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zm22 10c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zM6 64c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zm22 10c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zm22 10c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zM27 31h2v2h-2zm-4 0h2v2h-2zm8 0h2v2h-2z')
section.pricing
.container
.row
.col-md-12
h2 Simple Pricing. Any payment method.
.row
.col-md-4.col-sm-4
.box.monthly
h3 Monthly
.pricing-display
span.currency-sign $
span.digit-int 9
span.digit-dec .90 / month*
.pricing-caption
p * with a 3-months minimum period
a.sign-up-now(href="https://store.blender.org/product/membership/")
| Subscribe Now
.col-md-4.col-sm-4
.box.yearly
h3 Yearly
.pricing-display
span.currency-sign $
span.digit-int 109
span.digit-dec .00 / year
.pricing-caption
p 1 month free!
p Free copy of the <a href="https://store.blender.org/product/art-of-blender-2/">Art of Blender</a>
a.sign-up-now(href="https://store.blender.org/product/membership/")
| Subscribe Now
.col-md-4.col-sm-4
.box.education
h3 Education
.pricing-caption
p.
We also provide flexible options for group subscription
ideal for schools or teams.
p.
Get in touch to discuss direct support, custom solutions,
team management tools and Single Sign-on.
a.sign-up-now(href="mailto:cloudsupport@blender.org")
i.pi-email
| Get in Touch
section.team(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/pattern_01.jpg')}})")
.container
.row
.col-md-12
h2.
A restless team of artists and developers <br/>
wants to share their work with you.
.people-container
.people-intro
h3 Blender Institute
span Amsterdam, The Netherlands
.people-faces
.face(data-blenderhead='ton')
img(alt="Ton", src="{{ url_for('static', filename='assets/img/people/ton.jpg')}}")
.face(data-blenderhead='francesco')
img(alt="Francesco", src="{{ url_for('static', filename='assets/img/people/francesco.jpg')}}")
.face(data-blenderhead='pablo')
img(alt="Pablo", src="{{ url_for('static', filename='assets/img/people/pablo.jpg')}}")
.face(data-blenderhead='andy')
img(alt="Andy", src="{{ url_for('static', filename='assets/img/people/andy.jpg')}}")
.face(data-blenderhead='hjalti')
img(alt="Hjalti", src="{{ url_for('static', filename='assets/img/people/hjalti.jpg')}}")
.face(data-blenderhead='sergey')
img(alt="Sergey", src="{{ url_for('static', filename='assets/img/people/sergey.jpg')}}")
.face(data-blenderhead='sybren')
img(alt="Sybren", src="{{ url_for('static', filename='assets/img/people/sybren.jpg')}}")
.people-bio
.bio#ton
h3 Ton Roosendaal
small CEO Blender Foundation. Producer Blender Institute
span The Netherlands
.bio#francesco
h3 Francesco Siddi
small Pipeline Tools & Back-end Web Development
span Italy
.bio#pablo
h3 Pablo Vázquez
small Lighting, Rendering. Front-end Web Development
span Argentina
.bio#andy
h3 Andy Goralczyk
small Shading, Lighting, Rendering, FX
span Germany
.bio#hjalti
h3 Hjalti Hjálmarsson
small Animation. Layout Artist.
span Iceland
.bio#sergey
h3 Sergey Sharybin
small Blender & Cycles Core Developer
span Russia
.bio#sybren
h3 Sybren Stüvel
small Blender Cloud Developer
span The Netherlands
.people-container.online
.people-intro
h3 Online Collaborators
span Contributing to Blender Cloud from all over the globe.
.people-faces
.face(data-blenderhead='gleb')
img(alt="Gleb", src="{{ url_for('static', filename='assets/img/people/gleb.jpg')}}")
.face(data-blenderhead='david')
img(alt="David", src="{{ url_for('static', filename='assets/img/people/david.jpg')}}")
.face(data-blenderhead='sebastian')
img(alt="Sebastian", src="{{ url_for('static', filename='assets/img/people/sebastian.jpg')}}")
.face(data-blenderhead='jpbouza')
img(alt="Juan Pablo", src="{{ url_for('static', filename='assets/img/people/jpbouza.jpg')}}")
.face(data-blenderhead='bassam')
img(alt="Bassam", src="{{ url_for('static', filename='assets/img/people/bassam.jpg')}}")
.people-bio
.bio#gleb
h3 Gleb Alexandrov
small Lighting & Shading
span Belarus
.bio#david
h3 David Revoy
small Illustrator & Concept Artist
span France
.bio#jpbouza
h3 Juan Pablo Bouza
small Rigging
span Argentina
.bio#bassam
h3 Bassam Kurdali
small Rigging & Pipeline
span United States
.bio#sebastian
h3 Sebastian König
small VFX
span Germany
section.page-card.oneofus.
Join <strong>2021</strong> awesome people, <a href="">subscribe to Blender Cloud</a> now.
section.supported-by
h2 Our projects were supported by
img.logos(alt="Supported by", src="{{ url_for('static', filename='assets/img/support_logos.png') }}")
section.page-card.subscribe(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/background_services.jpg')}});")
.page-card-side
h2.page-card-title
| Get inspiration, knowledge, and tools in one place.
.page-card-summary
| Join us for only $9.90/month!
a.page-card-cta(
href="https://store.blender.org/product/membership/")
| Subscribe Now
| {% endblock %}
| {% block footer_scripts %}
script.
$('.triplet-card').click(function(){
window.location.replace($(this).attr('data-url'));
});
$(window).on('load scroll', function() {
var y = $(this).scrollTop();
if (y < 100){
$('.navbar-backdrop').css('background-position-y', (parseInt(-y / 4) * -1) + 'px');
}
});
function getSubscribers(){
$.get('https://store.blender.org/product-counter/?prod=cloud', function(data) {
}).done(function(data){
if (data.total_sold > 0) {
$('.page-card.oneofus').addClass('active');
$('.page-card.oneofus strong').html(data.total_sold);
}
});
}
getSubscribers();
$('.people-faces .face').hover(
function(){
var who = $(this).data('blenderhead');
$('#' + who).addClass('active');
$(this).parent().prev().addClass('active');
},
function(){
$('.bio, .people-intro').removeClass('active');
}
);
// Click anywhere in the page to hide the overlay
function hideOverlay() {
$('#page-overlay.video').removeClass('active');
$('#page-overlay.video .video-embed').html('');
}
$(document).click(function() {
hideOverlay();
});
$(document).keyup(function(e) {
if (e.keyCode == 27) {
hideOverlay();
}
});
$('a.watch-video').click(function(e){
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>')
});
| {% endblock %}

436
src/templates/layout.jade Normal file
View File

@@ -0,0 +1,436 @@
doctype
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="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")
meta(property="og:site_name", content="Blender Cloud")
| {% block og %}
meta(property="og:title", content="Blender Cloud")
meta(property="og:url", content="https://cloud.blender.org")
meta(property="og:type", content="website")
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_gleb_locomotive.jpg')}}")
| {% endblock %}
meta(name="twitter:card", content="summary_large_image")
meta(name="twitter:site", content="@Blender_Cloud")
| {% block tw %}
meta(name="twitter:title", content="Blender Cloud")
meta(name="twitter: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="twitter:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_gleb_locomotive.jpg')}}")
| {% endblock %}
script(src="//code.jquery.com/jquery-2.2.1.min.js")
script(src="//cdn.jsdelivr.net/typeahead.js/0.11.1/typeahead.jquery.min.js")
script(src="//cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js")
script(src="//cdnjs.cloudflare.com/ajax/libs/js-cookie/2.0.3/js.cookie.min.js",)
script.
var algolia = algoliasearch("{{config['ALGOLIA_USER']}}", "{{config['ALGOLIA_PUBLIC_KEY']}}");
var index = algolia.initIndex("{{config['ALGOLIA_INDEX_NODES']}}");
!function(e){"use strict";e.loadCSS=function(t,n,o){var r,i=e.document,l=i.createElement("link");if(n)r=n;else{var d=(i.body||i.getElementsByTagName("head")[0]).childNodes;r=d[d.length-1]}var a=i.styleSheets;l.rel="stylesheet",l.href=t,l.media="only x",r.parentNode.insertBefore(l,n?r:r.nextSibling);var f=function(e){for(var t=l.href,n=a.length;n--;)if(a[n].href===t)return e();setTimeout(function(){f(e)})};return l.onloadcssdefined=f,f(function(){l.media=o||"all"}),l},"undefined"!=typeof module&&(module.exports=e.loadCSS)}(this);
loadCSS( "//fonts.googleapis.com/css?family=Roboto:300,400,500" );
loadCSS( "//fonts.googleapis.com/css?family=Lato:300,400" );
script(src="{{ url_for('static_pillar', filename='assets/js/markdown.min.js', v=040820161) }}")
script(src="{{ url_for('static_pillar', filename='assets/js/tutti.min.js', v=040820161) }}")
link(href="{{ url_for('static_pillar', filename='assets/ico/favicon.png') }}", rel="shortcut icon")
link(href="{{ url_for('static_pillar', filename='assets/ico/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")
| {% block head %}{% endblock %}
| {% block css %}
| {% if title == 'blog' %}
link(href="{{ url_for('static_pillar', filename='assets/css/blog.css', v=040820161) }}", rel="stylesheet")
| {% else %}
link(href="{{ url_for('static_pillar', filename='assets/css/main.css', v=040820161) }}", rel="stylesheet")
| {% endif %}
| {% endblock %}
| {% if not title %}{% set title="default" %}{% endif %}
body(class="{{ title }}")
.container-page
header.navbar-backdrop-container
| {% block header_backdrop %}
img(src="{{ url_for('static', filename='assets/img/backgrounds/pattern_02_blur.jpg')}}")
| {% endblock %}
| {% 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 %}
nav.navbar.navbar-transparent.navbar-fixed-top
.navbar-overlay
.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="/",
title="Blender Cloud")
span.app-logo
i.pi-blender-cloud
| {% block navigation_search %}
.search-input
input#cloud-search(
type="text",
placeholder="Search assets, tutorials...")
i.search-icon.pi-search
| {% endblock %}
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 %}
| {% 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(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('main.redir_hdri') }}",
title="HDRI Library",
data-toggle="tooltip",
data-placement="left")
i.pi-globe
| HDRI
li
a.navbar-item(
href="{{ url_for('main.redir_textures') }}",
title="Textures Library",
data-toggle="tooltip",
data-placement="left")
i.pi-folder-texture
| Textures
li
a.navbar-item(
href="{{ url_for('main.redir_characters') }}",
title="Character Library",
data-toggle="tooltip",
data-placement="left")
i.pi-character
| Characters
li
a.navbar-item(
href="{{ url_for('main.gallery') }}",
title="Curated artwork collection",
data-toggle="tooltip",
data-placement="left")
i.pi-image
| Art Gallery
li
a.navbar-item(
href="{{ url_for('main.training') }}",
title="Training & Tutorials",
data-toggle="tooltip",
data-placement="bottom",
class="{% if category == 'training' %}active{% endif %}")
span Training
li
a.navbar-item(
href="{{ url_for('main.open_projects') }}",
title="Browse all the Open Projects",
data-toggle="tooltip",
data-placement="bottom",
class="{% if category in ['open-projects', 'film'] %}active{% endif %}")
span Open Projects
li
a.navbar-item(
href="{{ url_for('main.services') }}",
title="Blender Cloud Services",
data-toggle="tooltip",
data-placement="bottom",
class="{% if category == 'services' %}active{% endif %}")
span Services
| {% endblock %}
| {% if current_user.is_anonymous %}
li
a.navbar-item(
href="https://store.blender.org/product/membership/",
title="Sign up") Sign up
| {% endif %}
| {% if current_user.is_authenticated %}
| {% if current_user.has_role('demo') %}
| {% set subscription = 'demo' %}
| {% elif current_user.has_role('subscriber') %}
| {% set subscription = 'subscriber' %}
| {% else %}
| {% set subscription = 'none' %}
| {% endif %}
li.nav-notifications
a.navbar-item#notifications-toggle(
title="Notifications",
data-toggle="tooltip",
data-placement="bottom")
i.pi-notifications-none.nav-notifications-icon
span#notifications-count
span
.flyout-hat
#notifications.flyout.notifications
.flyout-content
span.flyout-title Notifications
a#notifications-markallread(
title="Mark All as Read",
href="/notifications/read-all")
| Mark All as Read
| {% include '_notifications.html' %}
li(class="dropdown{% if title in ['profile', 'billing-address', 'pledges', 'manage-collection']: %} active{% endif %}")
a.navbar-item.dropdown-toggle(href="#", data-toggle="dropdown", title="{{ current_user.email }}")
img.gravatar(
src="{{ current_user.gravatar }}",
class="{{ subscription }}",
alt="Avatar")
.special(class="{{ subscription }}")
| {% if subscription == 'subscriber' %}
i.pi-check
| {% elif subscription == 'demo' %}
i.pi-heart-filled
| {% else %}
i.pi-attention
| {% endif %}
ul.dropdown-menu
| {% if not current_user.has_role('protected') %}
li.subscription-status(class="{{ subscription }}")
| {% if subscription == 'subscriber' %}
a.navbar-item(
href="{{url_for('users.settings_billing')}}"
title="View subscription info")
i.pi-grin
span Your subscription is active!
| {% elif subscription == 'demo' %}
a.navbar-item(
href="{{url_for('users.settings_billing')}}"
title="View subscription info")
i.pi-heart-filled
span You have a free account.
| {% else %}
a.navbar-item(
href="https://store.blender.org/product/membership/"
title="Renew subscription")
i.pi-unhappy
span.info Your subscription is not active.
span.renew Click here to renew.
| {% endif %}
li
a.navbar-item(
href="{{ url_for('projects.home_project') }}"
title="Home")
i.pi-home
| Home
li
home_project
a.navbar-item(
href="{{ url_for('projects.index') }}"
title="My Projects")
i.pi-star
| My Projects
li
a.navbar-item(
href="{{ url_for('users.settings_profile') }}"
title="Settings")
i.pi-cog
| Settings
li
a.navbar-item(
href="{{ url_for('users.settings_billing') }}"
title="Billing")
i.pi-credit-card
| Subscription
li.divider(role="separator")
| {% endif %}
li
a.navbar-item(
href="{{ url_for('users.logout') }}")
i.pi-log-out(title="Log Out")
| Log out
| {% else %}
li.nav-item-sign-in
a.navbar-item(href="{{ url_for('users.login') }}")
| Log in
| {% endif %}
.page-content
#search-overlay
| {% block page_overlay %}
#page-overlay
| {% endblock %}
.page-body
| {% block body %}{% endblock %}
| {% block footer_container %}
#footer-container
| {% block 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://twitter.com/Blender_Cloud",
title="Follow us on Twitter")
i.pi-social-twitter
li
a(href="mailto:cloudsupport@blender.org"
title="Support Email")
i.pi-email
.col-md-2.col-xs-6
h4
a(href="{{ url_for('main.homepage') }}")
| Blender Cloud
ul.footer-links
li
a(href="{{ url_for('main.main_blog') }}",
title="Blender Cloud Blog")
| Blog
li
a(href="{{ url_for('main.services') }}",
title="Blender Cloud Services")
| Services
li
a(href="https://cloud.blender.org/blog/blender-cloud-v3",
title="About Blender Cloud")
| About
.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://www.blender.org/store",
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 %}
| {% block footer %}
footer.container
ul.links
li
a(href="{{ url_for('main.homepage') }}")
| Blender Cloud
#hop(title="Be awesome in space")
i.pi-angle-up
| {% endblock %}
| {% endblock %}
#notification-pop(data-url="", data-read-toggle="")
.nc-progress
a#pop-close(href="#", title="Dismiss")
i.pi-cancel
.nc-item
.nc-avatar
.nc-text
span.nc-date
a(href="")
noscript
link(href='//fonts.googleapis.com/css?family=Roboto:300,400,500', rel='stylesheet', type='text/css')
link(href='//fonts.googleapis.com/css?family=Lato:300,400', rel='stylesheet', type='text/css')
script(type="text/javascript", src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js")
script(type="text/javascript", src="//cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/0.6.10/js/min/perfect-scrollbar.min.js")
script(type="text/javascript", src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js")
script.
$(document).ready(function() {
{% if current_user.is_authenticated %}
getNotificationsLoop(); // Check for new notifications in the background
// Resize #notifications and change overflow for scrollbars
$(window).on("resize", function() { notificationsResize(); });
// Load perfectScrollbar
Ps.initialize(document.getElementById('notifications'), {suppressScrollX: true});
{% endif %}
});
| {% block footer_scripts %}{% endblock %}
script.
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '{{ config.GOOGLE_ANALYTICS_TRACKING_ID }} ', 'auto', {'allowAnchor': true});
ga('send', 'pageview');

View File

@@ -0,0 +1,445 @@
#comments-container
a(name="comments")
section#comments-list
.comment-reply-container
| {% if current_user.is_authenticated %}
| {% if has_method_POST %}
.comment-reply-avatar
img(src="{{ current_user.gravatar }}")
.comment-reply-form
.comment-reply-field
textarea(
id="comment_field",
data-parent_id="{{ parent_id }}",
placeholder="Join the conversation...",)
.comment-reply-meta
.comment-details
.comment-rules
a(
title="Markdown Supported"
href="https://guides.github.com/features/mastering-markdown/")
i.pi-markdown
.comment-author
span.commenting-as commenting as
span.author-name {{ current_user.full_name }}
button.comment-action-cancel.btn.btn-outline(
type="button",
title="Cancel")
i.pi-cancel
button.comment-action-submit.btn.btn-outline(
id="comment_submit",
type="button",
title="Post Comment")
| Post Comment
span.hint (Ctrl+Enter)
.comment-reply-preview
| {% else %}
| {# * It's authenticated, but has no 'POST' permission #}
.comment-reply-form
.comment-reply-field.sign-in
textarea(
disabled,
id="comment_field",
data-parent_id="{{ parent_id }}",
placeholder="")
.sign-in
| Join the conversation!&nbsp;<a href="https://store.blender.org/product/membership/">Subscribe to Blender Cloud now.</a>
| {% endif %}
| {% else %}
| {# * It's not autenticated #}
.comment-reply-form
.comment-reply-field.sign-in
textarea(
disabled,
id="comment_field",
data-parent_id="{{ parent_id }}",
placeholder="")
.sign-in
a(href="{{ url_for('users.login') }}") Log in
| to comment.
| {% endif %}
section#comments-list-header
#comments-list-title
#comments-list-items
#comments-list-items-loading
i.pi-spin
script#comment-template(type="text/x-handlebars-template")
| {% raw %}
| {{#list items }}
.comment-container(
id="{{ _id }}",
data-node_id="{{ _id }}",
class="{{#if is_team}}is-team{{/if}}{{#if is_reply}}is-reply{{else}}is-first{{/if}}")
.comment-header
.comment-avatar
img(src="{{ gravatar }}")
.comment-author(class="{{#if is_own}}own{{/if}}")
| {{ author }}
span.username ({{ author_username }})
| {{#if is_team}}
.comment-badge.badge-team(title="Project Member") team
| {{/if}}
.comment-time {{ time_published }} {{#if time_edited }} (edited {{ time_edited }}){{/if}}
.comment-content {{{ content }}}
| {{#if is_own}}
.comment-content-preview
| {{/if}}
.comment-meta
.comment-rating(
class="{{#if is_rated}}rated{{/if}}{{#if is_rated_positive}} positive{{/if}}")
.comment-rating-value(title="Number of likes") {{ rating }}
.comment-action-rating.up(title="Like comment")
.comment-action-reply(title="Reply to this comment")
span reply
| {{#if is_own}}
.comment-action-edit
span.edit_mode(title="Edit comment") edit
span.edit_save(title="Save comment")
i.pi-check
| save changes
span.edit_cancel(title="Cancel changes")
i.pi-cancel
| cancel
| {{/if}}
| {{/list}}
| {% endraw %}
| {% block comment_scripts %}
script.
// Markdown initialization
var convert = new Markdown.getSanitizingConverter();
Markdown.Extra.init(convert);
convert = convert.makeHtml;
// Define the template for handlebars
var source = $("#comment-template").html();
var template = Handlebars.compile(source);
// Register the helper for generating the comments list
Handlebars.registerHelper('list', function(context, options) {
var ret = "";
var comments_count = 0
// Loop through all first-level comments
for(var i=0, j=context.length; i<j; i++) {
comments_count++
// Convert Markdown for each comment
context[i]['content'] = convert(context[i]['content']);
// Append compiled comment to return string
ret = ret + options.fn(context[i]);
// Search for replies to the current comment
if (context[i]['replies']) {
var replies = context[i]['replies'];
var compiled_replies = "";
// Loop through replies
for(var r=0, t=replies.length; r<t; r++) {
// Convert Markdown for each comment
replies[r]['content'] = convert(replies[r]['content']);
// Append compiled replies
compiled_replies = compiled_replies + options.fn(replies[r]);
comments_count++
}
// Append replies list to the return string
ret = ret + compiled_replies;
}
}
$("#comments-list-title").html(((comments_count > 0) ? comments_count : 'No') + ((comments_count == 1) ? ' comment' : ' comments'));
return ret;
});
// Helper for the if/else statement
Handlebars.registerHelper('if', function(conditional, options) {
if(conditional) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
/* Build the markdown preview when typing in textarea */
$(function() {
var $textarea = $('.comment-reply-field textarea'),
$container = $('.comment-reply-form'),
$preview = $('.comment-reply-preview');
// As we type in the textarea
$textarea.keyup(function(e) {
// Convert markdown
$preview.html(convert($textarea.val()));
// While we are at it, style when empty
if ($textarea.val()) {
$container.addClass('filled');
} else {
$container.removeClass('filled');
};
// Send on ctrl+enter
if ((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey){
$( ".comment-action-submit" ).trigger( "click" );
};
}).trigger('keyup');
});
// Get the comments list in JSON
$.getJSON( "{{url_for('nodes.comments_index')}}?parent_id={{ parent_id }}&format=json", function( data ) {
// Format using handlebars template
var comments = template(data);
if (comments && comments.trim() !="") {
$('#comments-list-items').html(comments);
} else {
$('#comments-list-items').html('');
}
})
.done(function(){
var scrollToId = location.hash;
if (scrollToId.length <= 1) return;
document.getElementById(scrollToId.substr(1)).scrollIntoView(true);
$(scrollToId).addClass('comment-linked');
});
/* Submit comment */
$('.comment-action-submit').click(function(e){
var $this = $(this);
var $textarea = $('.comment-reply-field textarea');
var commentField = document.getElementById('comment_field');
var comment = commentField.value;
function error(msg) {
// No content in the textarea
$this.addClass('button-field-error');
$textarea.addClass('field-error')
$this.html(msg);
setTimeout(function(){
$this.html('Post Comment');
$this.removeClass('button-field-error');
$textarea.removeClass('field-error');
}, 2500);
}
if (comment.length < 5) {
if (comment.length == 0) error("Say something...");
else error("Minimum 5 characters.");
return;
}
$this.addClass('submitting');
$this.html('<i class="pi-spin spin"></i> Posting...');
// Collect parent_id
parent_id = commentField.getAttribute('data-parent_id');
$.post("{{url_for('nodes.comments_create')}}",
// Submit content and parent_id for comment creation
{'content': comment, 'parent_id': parent_id}
)
.fail(function(){
$this.addClass('button-field-error');
$textarea.addClass('field-error')
$this.html("Houston! Try again?");
setTimeout(function(){
$this.html('Post Comment');
$this.removeClass('button-field-error');
$textarea.removeClass('field-error');
}, 2500);
})
.done(function(){
// Load the comments
var url = "{{url_for('nodes.comments_index')}}?parent_id={{ parent_id }}";
$.get(url, function(dataHtml) {
// Update the DOM injecting the generate HTML into the page
$('#comments-container').replaceWith(dataHtml);
})
});
});
/* Edit comment */
// Markdown convert as we type in the textarea
$(document).on('keyup','body .comment-content textarea',function(e){
var $textarea = $(this),
$container = $(this).parent(),
$preview = $container.next();
// Convert markdown
$preview.html(convert($textarea.val()));
// While we are at it, style if empty
if (!$textarea.val()) {
$container.addClass('empty');
} else {
$container.removeClass('empty');
};
}).trigger('keyup');
/* Enter edit mode */
$(document).on('click','body .comment-action-edit span.edit_mode',function(){
$(this).hide();
$(this).siblings('span.edit_cancel').show();
$(this).siblings('span.edit_save').show();
var comment_content = $(this).parent().parent().siblings('.comment-content');
var comment_id = comment_content.parent().attr('data-node_id');
var height = comment_content.height();
var url = '/nodes/' + comment_id + '/view?format=json';
$.get(url, function(data) {
var comment_raw = data['node']['properties']['content'];
comment_content.html('<textarea>' + comment_raw + '</textarea>');
comment_content.addClass('editing')
.find('textarea')
.height(height)
.focus();
comment_content.siblings('.comment-content-preview').show();
})
.fail(function(data){
statusBarSet('error', 'Error entering edit mode.', 'pi-warning');
});
});
/* Return UI to normal, when cancelling or saving */
function commentEditCancel(comment_container) {
var comment_id = comment_container.parent().attr('id');
var url = '/nodes/' + comment_id + '/view?format=json';
$.get(url, function(data) {
var comment_raw = data['node']['properties']['content'];
comment_container.html(convert(comment_raw))
.removeClass('editing');
comment_container.siblings('.comment-content-preview').html('').hide();
})
.fail(function(data){
statusBarSet('error', 'Error canceling.', 'pi-warning');
});
}
$(document).on('click','body .comment-action-edit span.edit_cancel',function(e){
$(this).hide();
$(this).siblings('span.edit_save').hide();
$(this).siblings('span.edit_mode').show();
var commentContainer = $(this).parent().parent().siblings('.comment-content');
commentEditCancel(commentContainer);
});
/* Save edited comment */
$(document).on('click','body .comment-action-edit span.edit_save',function(e){
var $this = $(this);
var commentContainer = $(this).parent().parent().siblings('.comment-content');
var commentField = commentContainer.find('textarea');
var comment = commentField.val();
var commentId = commentContainer.parent().attr('id');
function error(msg) {
// No content in the textarea
$this.addClass('error')
.html(msg);
commentField.addClass('field-error')
setTimeout(function(){
$this.html('<i class="pi-check"></i> save changes')
.removeClass('error');
commentField.removeClass('field-error');
}, 2500);
}
if (comment.length < 5) {
if (comment.length == 0) error("Say something...");
else error("Minimum 5 characters.");
return;
}
$this.addClass('saving')
.html('<i class="pi-spin spin"></i> Saving...');
$.post('/nodes/comments/' + commentId,
{'content': comment}
)
.fail(function(){
$this.addClass('error')
.html("Houston! Try again?");
commentField.addClass('field-error')
setTimeout(function(){
$this.html('Save changes')
.removeClass('error');
commentField.removeClass('field-error');
}, 2500);
})
.done(function(){
commentEditCancel(commentContainer);
commentContainer
.html(convert(comment));
commentContainer.next().text(comment);
$this.html('<i class="pi-grin"></i> saved!')
.removeClass('saving')
.siblings('span.edit_cancel').hide();
setTimeout(function(){
$this.html('<i class="pi-check"></i> save changes')
.hide()
.siblings('span.edit_mode').show();
}, 2500);
});
});
| {% endblock %}

View File

@@ -0,0 +1,189 @@
script(type="text/javascript").
/* Convert Markdown */
var convert_fields = '.node-details-description, .blog_index-item .item-content';
var convert = new Markdown.getSanitizingConverter();
Markdown.Extra.init(convert);
convert = convert.makeHtml;
/* Parse description/content fields to convert markdown */
$(convert_fields).each(function(i){
$(convert_fields).eq(i).html(convert($(convert_fields).eq(i).text()));
});
ProjectUtils.setProjectAttributes({isProject: false});
{% if node %}
ProjectUtils.setProjectAttributes({
nodeId: '{{node._id}}',
nodeType: '{{node.node_type}}'});
var node_type = ProjectUtils.nodeType();
var node_type_str = node_type;
if (node_type === 'group'){
node_type_str = 'Folder';
} else if (node_type === 'group_texture') {
node_type_str = 'Texture Folder';
} else if (node_type === 'group_hdri') {
node_type_str = 'HDRi Folder';
}
$('a', '.button-edit').html('<i class="pi-edit button-edit-icon"></i> Edit ' + node_type_str);
$('a', '.button-delete').html('<i class="pi-trash button-delete-icon"></i>Delete ' + node_type_str);
{% if parent %}
ProjectUtils.setProjectAttributes({parentNodeId: '{{parent._id}}'});
{% endif %}
// If we are im preview mode, update the image source
var page_overlay = document.getElementById('page-overlay');
if (page_overlay.classList.contains('active')) {
var node_preview = document.getElementById('node-preview');
if (node_preview){
if ($(node_preview).hasClass('image') || $(node_preview).hasClass('file')){
var src = $(node_preview).find('img').attr('src');
showOverlayPreviewImage(src);
}
} else {
$(page_overlay).html('<div class="nav-prev"></div><div class="no-preview">No Preview Available</div><div class="nav-next"></div>');
}
}
function loadComments(){
var commentsUrl = "{{ url_for('nodes.comments_index', parent_id=node._id) }}";
$.get(commentsUrl, function(dataHtml) {
})
.done(function(dataHtml){
// Update the DOM injecting the generate HTML into the page
$('#comments-container').replaceWith(dataHtml);
})
.fail(function(e, data){
statusBarSet('error', 'Couldn\'t load comments. Error: ' + data.errorThrown, 'pi-attention', 5000);
$('#comments-container').html('<a id="comments-reload"><i class="pi-refresh"></i> Reload comments</a>');
});
}
loadComments();
$('body').on('click', '#comments-reload', function(){
loadComments();
});
{% if node.has_method('PUT') %}
$('.project-mode-view').show();
{% else %}
$('.project-mode-view').hide();
{% endif %}
{% if node.picture %}
function showOverlayPreviewImage(src) {
$(page_overlay)
.addClass('active')
.html('<div class="nav-prev"></div><img src="' + src + '"/><div class="nav-next"></div>');
}
$('#node-preview.image, #node-preview.file').click(function(e){
e.preventDefault();
e.stopPropagation();
showOverlayPreviewImage("{{ node.picture.thumbnail('l', api=api) }}");
});
{% endif %}
// Click anywhere in the page to hide the overlay
function hidePageOverlay() {
$(page_overlay)
.removeAttr('class')
.html('');
}
$(page_overlay).click(function(e) {
e.stopPropagation();
e.preventDefault();
hidePageOverlay();
});
function navigateTree(prev){
var tree = $('#project_tree').jstree(true);
var curr = tree.get_selected(false);
if (prev === undefined){
var n = tree.get_next_dom(curr);
} else {
var n = tree.get_prev_dom(curr);
}
if (n && n.length > 0) {
tree.deselect_all();
tree.select_node(n);
}
}
document.onkeydown = function(e) {
var event = document.all ? window.event : e;
switch (e.target.tagName.toLowerCase()) {
case "input":
case "textarea":
case "select":
case "button":
break
default:
if (event.keyCode==27) hidePageOverlay();
if (event.keyCode==37) navigateTree(true);
if (event.keyCode==39) navigateTree();
break;
}
}
$(page_overlay).find('.nav-prev').click(function(e){
e.stopPropagation();
e.preventDefault();
navigateTree(true);
});
$(page_overlay).find('.nav-next').click(function(e){
e.stopPropagation();
e.preventDefault();
navigateTree();
});
// Auto-scale the image preview to the right aspect ratio
var node_preview = document.getElementById("node-preview-thumbnail");
if (node_preview) {
node_preview.addEventListener('load', function() {
var preview_aspect = this.naturalWidth / this.naturalHeight
if (preview_aspect > 1.0){
$('.node-preview, .node-preview-thumbnail').css({'max-height': 'auto', 'width': '100%'});
$('.node-preview img').css({'max-height': '100%'});
}
});
}
$('#node-overlay').click(function(){
$(this).removeClass('active').hide().html();
});
if (typeof $().popover != 'undefined'){
$('#asset-license').popover();
}
{% endif %}
if (typeof $().tooltip != 'undefined'){
$('[data-toggle="tooltip"]').tooltip({'delay' : {'show': 1250, 'hide': 250}});
}

View File

@@ -0,0 +1,128 @@
| {% block body %}
#node-container
#node-overlay
| {% if node.picture %}
section#node-preview.node-preview.file
img.node-preview-thumbnail#node-preview-thumbnail(
src="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
section.node-details-container.file
.node-details-header
.node-title#node-title
| {{node.name}}
.node-details-meta.header
ul.node-details-meta-list
| {% if node.permissions.world %}
li.node-details-meta-list-item.access.public(
data-toggle="tooltip",
data-placement="left",
title="Anybody can download. Share it!")
i.pi-lock-open
span Public
| {% endif %}
| {% if node.file %}
li.node-details-meta-list-item.type
| {{ node.file.content_type }}
li.node-details-meta-list-item.file.length
| {{ node.file.length | filesizeformat }}
| {% endif %}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
li.node-details-meta-list-item.license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
li.node-details-meta-list-item.license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
| {% if node.file %}
li.node-details-meta-list-item.file.download(title="Download File")
| {% if node.file.link %}
a(href="{{ node.file.link }}",
title="Download file",
download="{{ node.file.filename }}")
button.btn.btn-default(type="button")
i.pi-download
| {% else %}
button.btn.btn-default.disabled.sorry(type="button")
i.pi-download
| {% endif %}
| {% endif %}
| {% if node.description %}
.node-details-description#node-description
| {{node.description}}
| {% endif %}
| {% if node.properties.license_notes %}
.node-details-meta.license
| {{ node.properties.license_notes }}
| {% endif %}
.node-details-meta.footer
ul.node-details-meta-list
li.node-details-meta-list-item.status
| {{node.properties.status}}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
li.node-details-meta-list-item.date(title="Created {{ node._created }}")
| {{ node._created | pretty_date }}
| {% if (node._created | pretty_date) != (node._updated | pretty_date) %}
span(title="Updated {{ node._updated }}") (updated {{ node._updated | pretty_date }})
| {% endif %}
#comments-container
#comments-list-items-loading
i.pi-spin
include ../../_scripts
| {% endblock %}
| {% block footer_scripts %}
script.
// Generate GA pageview
ga('send', 'pageview', location.pathname);
var content_type = $("li.node-details-meta-list-item.type").text();
var type_trimmed = content_type.substring(content_type.indexOf("/") + 1);
if (type_trimmed == 'x-blender' || type_trimmed == 'blend'){
type_trimmed = '<span class="blend"><i class="pi-blender-logo"></i></span>';
};
$("li.node-details-meta-list-item.type").html(type_trimmed);
$('.sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).addClass('active');
})
});
| {% endblock %}

View File

@@ -0,0 +1,4 @@
| {% extends 'layout.html' %}
| {% block footer_scripts %}
| {% endblock %}

View File

@@ -0,0 +1,128 @@
| {% block body %}
#node-container
#node-overlay
| {% if node.picture %}
section#node-preview.node-preview.image
img.node-preview-thumbnail#node-preview-thumbnail(
src="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
section.node-details-container.image
.node-details-header
.node-title#node-title
| {{node.name}}
.node-details-meta.header
ul.node-details-meta-list
| {% if node.permissions.world %}
li.node-details-meta-list-item.access.public(
data-toggle="tooltip",
data-placement="left",
title="Anybody can download. Share it!")
i.pi-lock-open
span Public
| {% endif %}
| {% if node.short_link %}
li.node-details-meta-list-item.access.shared
a(href="{{ node.short_link }}")
i.pi-share
| Shared
| {% endif %}
| {% if node.file %}
li.node-details-meta-list-item.type
| {{ node.file.content_type }}
li.node-details-meta-list-item.image.length
| {{ node.file.length | filesizeformat }}
| {% endif %}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
li.node-details-meta-list-item.license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title=" {{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
li.node-details-meta-list-item.license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
| {% if node.file %}
li.node-details-meta-list-item.image.download(title="Download Image")
| {% if node.file.link %}
a(href="{{ node.file.link }}",
title="Download image",
download="{{ node.file.filename }}")
button.btn.btn-default(type="button")
i.pi-download
| {% else %}
button.btn.btn-default.disabled.sorry(type="button")
i.pi-download
| {% endif %}
| {% endif %}
| {% if node.description %}
.node-details-description#node-description
| {{node.description}}
| {% endif %}
| {% if node.properties.license_notes %}
.node-details-meta.license
| {{ node.properties.license_notes }}
| {% endif %}
.node-details-meta.footer
ul.node-details-meta-list
| {% if node.has_method('PUT') %}
li.node-details-meta-list-item.status
| {{node.properties.status}}
| {% endif %}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
li.node-details-meta-list-item.date(title="Created {{ node._created }}")
| {{ node._created | pretty_date }}
| {% if (node._created | pretty_date) != (node._updated | pretty_date) %}
span(title="Updated {{ node._updated }}") (updated {{ node._updated | pretty_date }})
| {% endif %}
#comments-container
#comments-list-items-loading
i.pi-spin
include ../../_scripts
| {% endblock %}
| {% block footer_scripts %}
script.
// Generate GA pageview
ga('send', 'pageview', location.pathname);
var content_type = $("li.node-details-meta-list-item.type").text();
$("li.node-details-meta-list-item.type").text(content_type.substring(content_type.indexOf("/") + 1));
$('.sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).addClass('active');
})
});
| {% endblock %}

View File

@@ -0,0 +1,6 @@
| {% extends 'layout.html' %}
| {% from '_macros/_file_uploader_javascript.html' import render_file_uploader_javascript %}
| {% block footer_scripts %}
| {{render_file_uploader_javascript()}}
| {% endblock %}

View File

@@ -0,0 +1,158 @@
| {% block body %}
#node-container
#node-overlay
section.node-preview.video
#flowplayer_container.is-splash.play-button(
style="{% if node.picture %}background-image:url({{node.picture.thumbnail('l', api=api)}}); background-repeat:no-repeat; {% endif %}")
.fp-startscreen.fp-toggle
a.big-play-button
i.pi-play
.fp-endscreen
a.watch-again.fp-toggle
i.pi-replay
| Watch again
.fp-waiting
i.pi-spin.spin
section.node-details-container.video
.node-details-header
.node-title#node-title
| {{node.name}}
.node-details-meta.header
ul.node-details-meta-list
| {% if node.permissions.world %}
li.node-details-meta-list-item.access.public(
data-toggle="tooltip",
data-placement="bottom",
title="Anybody can download. Share it!")
i.pi-lock-open
span Public
| {% endif %}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
li.node-details-meta-list-item.video.license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
li.node-details-meta-list-item.video.license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
| {% if node.file %}
| {% if node.file_variations %}
li.btn-group.node-details-meta-list-item.video.download(
title="Download Video")
button.btn.btn-default.dropdown-toggle(
type="button",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false")
i.pi-download
i.pi-angle-down.icon-dropdown-menu
ul.dropdown-menu
| {% for child in node.file_variations %}
li
a(href="{{ child.link }}",
title="Download this video format",
download)
span.length {{ child.length | filesizeformat }}
span.format {{ child.format }}
span.size {{ child.size }}
| {% endfor %}
| {% else %}
li.btn-group.node-details-meta-list-item.video.download.disabled(
title="Download Video")
button.btn.btn-default.sorry(type="button")
i.pi-download
i.pi-angle-down.icon-dropdown-menu
| {% endif %}
| {% endif %}
| {% if node.description %}
.node-details-description#node-description
| {{node.description}}
| {% endif %}
| {% if node.properties.license_notes %}
.node-details-meta.license
| {{ node.properties.license_notes }}
| {% endif %}
.node-details-meta.footer
ul.node-details-meta-list
li.node-details-meta-list-item.status
| {{node.properties.status}}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
li.node-details-meta-list-item.date(title="Created {{ node._created }}")
| {{ node._created | pretty_date }}
| {% if (node._created | pretty_date) != (node._updated | pretty_date) %}
span(title="Updated {{ node._updated }}") (updated {{ node._updated | pretty_date }})
| {% endif %}
#comments-container
#comments-list-items-loading
i.pi-spin
include ../../_scripts
| {% endblock %}
| {% block footer_scripts %}
script(type="text/javascript").
$(function(){
// Generate GA pageview
ga('send', 'pageview', location.pathname);
var content_type = $("li.node-details-meta-list-item.type").text();
$("li.node-details-meta-list-item.type").text(content_type.substring(content_type.indexOf("/") + 1));
var container = document.getElementById("flowplayer_container");
flowplayer(container, {
key: "{{config.FLOWPLAYER_KEY}}",
embed: false,
splash: true,
{% if node.video_sources %}
clip: {
sources: {{ node.video_sources | safe }}
}
{% else %}
disabled: true
{% endif %}
});
{% if not node.video_sources %}
$('#flowplayer_container, .sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).addClass('active');
})
});
{% endif %}
});
| {% endblock %}

View File

@@ -0,0 +1,127 @@
#theatre-media
img(src="{{ node.picture.thumbnail('h', api=api) }}", onmousedown="return false")
ul#theatre-tools
li.theatre-tool-resize(title="Toggle Normal Size")
span
i.pi-resize-full
| {% if node.file and node.file.link %}
li.download
a(href="{{ node.file.link }}",
title="Download the original file",
download="{{ node.file.filename }}")
i.pi-download
| {% else %}
li.download.disabled
a(href="{{ url_for('users.login') }}",
title="Sign in to download the original file")
i.pi-download
| {% endif %}
#theatre-info
.theatre-info-header
.theatre-info-title {{ node.name }}
.theatre-info-user {{ node.user.full_name }}
.theatre-info-date {{ node._created | pretty_date_time }}
ul.theatre-info-details
li
span Type
span {{ node.file.content_type }}
li
span Dimensions
span {{ node.file.width }} <small>x</small> {{ node.file.height }}
li
span Size
span {{ node.file.length | filesizeformat }}
| {% if node.short_link %}
li
span Share link
a(href="{{ node.short_link }}") {{ node.short_link }}
| {% endif %}
#comments-container
#comments-list-items-loading
i.pi-spin
include ../_scripts
script.
$(function () {
// Load scrollbar for sidebar
Ps.initialize(document.getElementById('theatre-info'), {suppressScrollX: true});
var file_width = {{ node.file.width }};
var file_height = {{ node.file.height }};
var theatre_media = document.getElementById('theatre-media');
var $theatre_media = $(theatre_media);
function canZoom() {
return theatre_media.scrollWidth < file_width ||
theatre_media.scrollHeight < file_height;
}
// TODO: update this whenever the screen resizes.
if (canZoom()) $theatre_media.addClass('zoomed-out');
function theatreZoom() {
var started_zoomed_in = $theatre_media.hasClass('zoomed-in');
// See if we need to zoom in at all. Zooming out is always allowed.
if (!started_zoomed_in && !canZoom()) {
$theatre_media.removeClass('zoomed-out');
return;
}
// Use add/removeClass to ensure there is always exactly one of zoomed-{in,out}.
// If we were to use toggleClass() they could both be applied when we started
// without zoomed-out class.
if (started_zoomed_in) {
$theatre_media.removeClass('zoomed-in');
$theatre_media.addClass('zoomed-out');
Ps.destroy(theatre_media);
} else {
$theatre_media.addClass('zoomed-in');
$theatre_media.removeClass('zoomed-out');
Ps.initialize(theatre_media);
}
// Style toolbar button
$('ul#theatre-tools li.theatre-tool-resize').toggleClass('active');
}
$('ul#theatre-tools li.theatre-tool-resize').on('click', function (e) {
theatreZoom();
});
$('ul.nav.navbar-nav a.navbar-item.info').on('click', function (e) {
e.preventDefault();
$('#theatre-container').toggleClass('with-info');
});
$("#theatre-media img").on('click', function (e) {
var $parent = $(this).parent();
var mouse_x = e.pageX;
var mouse_y = e.pageY;
// Compute relative position before zooming in.
var pre_width = e.target.clientWidth;
var rel_x = e.offsetX / pre_width;
var rel_y = e.offsetY / e.target.clientHeight;
theatreZoom();
var post_width = e.target.clientWidth;
if (post_width > pre_width) {
// We zoomed in, scroll such that the target position is under the mouse.
var target_x = Math.round(rel_x * post_width);
var target_y = Math.round(rel_y * e.target.clientHeight);
$parent
.scrollLeft(target_x - mouse_x + e.target.parentElement.parentElement.offsetLeft)
.scrollTop(target_y - mouse_y + e.target.parentElement.parentElement.offsetTop);
}
});
});

View File

@@ -0,0 +1,130 @@
| {% extends 'layout.html' %}
| {% set title = 'blog' %}
| {% block page_title %}Blog{% endblock%}
| {% block body %}
.container.box
#blog_container(class="{% if project._id == config.MAIN_PROJECT_ID %}cloud-blog{% endif %}")
#blog_index-container
| {% if project._id == config.MAIN_PROJECT_ID and project.node_type_has_method('post', 'POST', api=api) %}
a.btn.btn-default.button-create(href="{{url_for('nodes.posts_create', project_id=project._id)}}")
i.pi-plus
| Create New Post
| {% endif %}
| {% if posts %}
| {% for node in posts %}
| {% if loop.first %}
| {% if node.picture %}
.blog_index-header
img(src="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
.blog_index-item
a.item-title(
href="{{ url_for_node(node=node) }}")
| {{node.name}}
.item-info.
<span title="{{node._created}}">{{node._created | pretty_date }}</span>
{% if node._created != node._updated %}
<span title="{{node._updated}}">(updated {{node._updated | pretty_date }})</span>
{% endif %}
{% if node.properties.category %}| {{node.properties.category}}{% endif %}
| by {{node.user.full_name}}
| <a href="{{ url_for_node(node=node) }}#comments">Leave a comment</a>
{% if node.properties.status != 'published' %} | {{ node.properties.status}} {% endif %}
.item-content
| {{node.properties.content}}
.item-meta
a(href="{{ url_for_node(node=node) }}#comments") Leave a comment
| {% else %}
| {% if loop.index == 2 %}
h4.blog_index-title Blasts from the past
| {% endif %}
.blog_index-item.list
| {% if node.picture %}
.item-header
img.image(src="{{ node.picture.thumbnail('s', api=api) }}")
| {% else %}
.item-header.nothumb
i.pi-document-text
| {% endif %}
a.item-title(
href="{{ url_for_node(node=node) }}")
| {{node.name}}
.item-info.
<span title="{{node._created}}">{{node._created | pretty_date }}</span>
{% if node._created != node._updated %}
<span title="{{node._updated}}">(updated {{node._updated | pretty_date }})</span>
{% endif %}
{% if node.properties.category %}| {{node.properties.category}}{% endif %}
| by {{node.user.full_name}}
{% if node.properties.status != 'published' %} | {{ node.properties.status}} {% endif %}
| {% endif %} {# loop #}
| {% endfor %} {# posts #}
| {% else %}
.blog_index-item
.item-content No posts yet.
| {% endif %} {# posts #}
| {% if project._id != config.MAIN_PROJECT_ID %}
#blog_index-sidebar
.blog_project-card
a.item-header(
href="{{ url_for('projects.view', project_url=project.url) }}")
.overlay
| {% if project.picture_header %}
img.background(src="{{ project.picture_header.thumbnail('m', api=api) }}")
| {% endif %}
a.card-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img.thumb(src="{{ project.picture_square.thumbnail('m', api=api) }}")
| {% endif %}
.item-info
a.item-title(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
| {% if project.summary %}
p.item-description
| {{project.summary|safe}}
| {% endif %}
| {% if project.node_type_has_method('post', 'POST', api=api) %}
.blog_project-sidebar
a.btn.btn-default.button-create(href="{{url_for('nodes.posts_create', project_id=project._id)}}")
| Create New Post
| {% endif %}
| {% endif %}
| {% endblock %}
| {% block footer_scripts %}
include ../_scripts
script hopToTop(); // Display jump to top button
| {% endblock %}

View File

@@ -0,0 +1,254 @@
| {% block body %}
#node-container
section.node-preview.group
| {% if node.picture %}
img.backdrop(src="{{ node.picture.thumbnail('l', api=api) }}")
.overlay
| {% endif %}
.node-title#node-title
| {{node.name}}
section.node-details-container.group
.node-details-meta.preview
ul.node-details-meta-list
li.node-details-meta-list-item.date(title="Created {{ node._created | pretty_date }}")
| {{ node._updated | pretty_date }}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
| {% if node.properties.status != 'published' %}
li.node-details-meta-list-item.status
| {{node.properties.status}}
| {% endif %}
.node-details-meta-actions
.btn-browsetoggle(
title="Toggle between list/grid view",
data-toggle="tooltip",
data-placement="top")
i.pi-list
| {% if node.description %}
.node-details-description
| {{node.description}}
| {% endif %}
section.node-children.group
| {% if children %}
| {% for child in children %}
| {# Browse type: List #}
a(
href="#",
data-node_id="{{ child._id }}",
class="item_icon list-node-children-item browse-list")
.list-node-children-item-thumbnail
| {% if child.picture %}
img(
src="{{ child.picture.thumbnail('t', api=api)}} ")
| {% endif %}
.list-node-children-item-thumbnail-icon
| {# If there's a type available, otherwise show a folder icon #}
| {% if child.properties.content_type %}
| {# Show an icon if there's no thumbnail #}
| {% if not child.picture %}
| {% if child.properties.content_type == 'image' %}
i.dark.pi-image
| {% elif child.properties.content_type == 'video' %}
i.dark.pi-film-thick
| {% elif child.properties.content_type == 'file' %}
i.dark.pi-document
| {% endif %}
| {% else %}
| {% if child.properties.content_type == 'video' %}
i.pi-play
| {% endif %}
| {% endif %}
| {% else %}
| {% if not child.picture %}
i.dark.pi-folder
| {% endif %}
| {% endif %}
| {% if child.permissions.world %}
.list-node-children-item-ribbon
span free
| {% endif %}
.list-node-children-item-name {{ child.name }}
.list-node-children-item-meta
| {% if child.properties.status != 'published' %}
span.status {{ child.properties.status }}
| {% endif %}
| {% if child.properties.content_type == 'video' %}
span Video ·
| {% elif child.properties.content_type == 'image' %}
span Image ·
| {% elif child.properties.content_type == 'file' %}
span File ·
| {% else %}
| {% if child.picture %}
span Folder ·
| {% endif %}
| {% endif %}
| {% if child._updated %}
span(title="Updated on {{ child._created }}") {{ child._updated | pretty_date }}
span.updated(title="Created on {{ child._updated }}") *
| {% else %}
span(title="Created on {{ child._created }}") {{ child._created | pretty_date }}
| {% endif %}
| {# Browse type: Icon #}
a(href="#", data-node_id="{{ child._id }}", title="{{ child.name }}", class="item_icon list-node-children-item browse-icon")
.list-node-children-item-thumbnail
| {% if child.picture %}
img(
src="{{ child.picture.thumbnail('b', api=api)}} ")
| {% endif %}
.list-node-children-item-thumbnail-icon
| {% if child.properties.content_type %}
| {% if child.properties.content_type == 'video' %}
i.pi-play
| {% endif %}
| {% else %}
i.pi-folder
| {% endif %}
| {% if child.properties.status != 'published' %}
.list-node-children-item-status {{ child.properties.status }}
| {% endif %}
| {% if child.permissions.world %}
.list-node-children-item-ribbon
span free
| {% endif %}
.list-node-children-item-name
| {% if child.properties.content_type == 'video' %}
i.pi-film-thick
| {% elif child.properties.content_type == 'image' %}
i.pi-image
| {% elif child.properties.content_type == 'file' %}
i.pi-document
| {% else %}
i.pi-folder
| {% endif %}
span {{ child.name }}
| {% endfor %}
| {% else %}
.list-node-children-container
.list-node-children-empty No items... yet!
| {% endif %}
script.
// Generate GA pageview
ga('send', 'pageview', location.pathname);
$('a.item_icon').unbind("click")
.click(function(e){
e.preventDefault();
var nodeId = $(this).data('node_id');
if (ProjectUtils.projectId()) {
// When clicking on a node preview, we load its content
// displayNode will run asynchronously and set the bcloud_current_node_id
// as well, but we set it manually in the next line as well, to make sure
// that select_node on jstree works as expected, preventing the node to be
// loaded twice.
Cookies.set('bcloud_current_node_id', nodeId);
displayNode(nodeId);
// Update tree with current selection
var jstree = $('#project_tree').jstree(true);
jstree.deselect_all();
jstree.open_node('n_' + ProjectUtils.nodeId(), function() {
jstree.select_node('n_' + nodeId);
});
} else {
// If there's project_id defined, we use the full link (for search)
window.location.replace('/nodes/' + nodeId + '/redir');
};
});
// Browse type: icon or list
function projectBrowseTypeIcon() {
$(".list-node-children-item.browse-list").hide();
$(".list-node-children-item.browse-icon").show();
$(".btn-browsetoggle").html('<i class="pi-list"></i>');
};
function projectBrowseTypeList() {
$(".list-node-children-item.browse-list").show();
$(".list-node-children-item.browse-icon").hide();
$(".btn-browsetoggle").html('<i class="pi-layout"></i>');
};
function projectBrowseTypeCheck(){
/* Only run if we're in a project, or search */
if(document.getElementById("project-container") !== null || document.getElementById("search-container") !== null) {
var browse_type = Cookies.getJSON('bcloud_ui');
if (browse_type && browse_type.group_browse_type) {
if (browse_type.group_browse_type == 'icon') {
projectBrowseTypeIcon();
} else if ( browse_type.group_browse_type == 'list' ) {
projectBrowseTypeList();
}
} else {
projectBrowseTypeIcon();
};
};
}
function projectBrowseToggle(){
var browse_type = Cookies.getJSON('bcloud_ui');
if (browse_type && browse_type.group_browse_type) {
if (browse_type.group_browse_type == 'icon') {
projectBrowseTypeList();
setJSONCookie('bcloud_ui', 'group_browse_type', 'list');
} else if ( browse_type.group_browse_type == 'list' ) {
projectBrowseTypeIcon();
setJSONCookie('bcloud_ui', 'group_browse_type', 'icon');
}
} else {
projectBrowseTypeList();
setJSONCookie('bcloud_ui', 'group_browse_type', 'list');
}
}
$('.btn-browsetoggle').on('click', function (e) {
e.preventDefault();
projectBrowseToggle();
});
projectBrowseTypeCheck();
include ../_scripts
| {% endblock %}

View File

@@ -0,0 +1,159 @@
| {% block body %}
#node-container.texture
.texture-title#node-title
| {{node.name}}
| {% if node.picture %}
.texture-backdrop(
style="background-image: url({{ node.picture.thumbnail('m', api=api) }})")
| {% endif %}
| {% if children %}
section.node-row.texture-info
span.texture-info-files {{ children|length }} item{% if children|length != 1 %}s{% endif %}
| {% endif %}
section.node-children.group.texture
| {% if children %}
| {% for child in children %}
| {% if child.properties.status == 'published' %}
a.list-node-children-container(
href="#",
data-node_id="{{ child._id }}",
class="item_icon {{child.node_type}} {% if child.picture %}thumbnail{% endif %}")
.list-node-children-item-preview
span.texture-name {{child.name}}
| {% if child.picture %}
img.texture-preview(
src="",
data-preview="{{ child.picture.thumbnail('m', api=api)}}",
alt='{{child.name}}')
| {% endif %}
.list-node-children-item(class="{{child.node_type}}")
.list-node-children-item-thumbnail
| {% if child.picture %}
img.texture-thumbnail(src="{{ child.picture.thumbnail('b', api=api)}}")
| {% else %}
.list-node-children-item-thumbnail-icon
| {% if child.node_type == 'group_hdri' %}
i.pi-folder-texture
| {% else %}
i.pi-texture
| {% endif %}
| {% endif %}
| {% if child.properties.status != 'published' %}
.list-node-children-item-status {{ child.properties.status }}
| {% endif %}
| {% if child.permissions.world %}
.list-node-children-item-ribbon
span free
| {% endif %}
| {% if child.node_type == 'hdri' %}
.list-node-children-item-name
span.sizes {{ child.name }}
| {% if child.properties.files %}
span.variations
| {% if child.properties.files|length > 6 %}
span {{ child.properties.files|length }} resolutions
span from {{ child.properties.files[0].resolution }}
span to {{ child.properties.files[-1].resolution }}
| {% else %}
| {% for f in child.properties.files %}
span {{ f.resolution }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% if child.node_type == 'group_hdri' %}
.list-node-children-item-name
i.pi-folder-texture
span {{ child.name }}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% else %}
.list-node-children-container
.list-node-children-empty No textures... yet!
| {% endif %}
script.
// Generate GA pageview
ga('send', 'pageview', location.href);
// Display texture preview on mouse hover
$('a.list-node-children-container.texture.thumbnail').hover(
function(){
var thumbnail = $(this);
var src = thumbnail.find('.texture-thumbnail').attr('src');
var src_xl = thumbnail.find('.texture-preview').data('preview');
// Load the bigger preview
var preview_img = thumbnail.find('.texture-preview');
preview_img.attr('src', src_xl);
if (preview_img) {
preview_img.load(function() {
var preview = thumbnail.find('.list-node-children-item-preview');
// Positioning stuff
var offset = thumbnail.offset();
var offset_min_x = $('.node-children').width() - preview.width();
var offset_min_y = $('.node-children').height() - preview.height();
if (preview && offset.top > 300) {
$(preview).css({'top': (preview.height() * (-1))});
};
if (offset.left > offset_min_x) {
$(preview).css({'right': 0});
};
$(preview).addClass('active');
});
}
},
function(){
$('.list-node-children-item-preview').removeClass('active');
});
// hide preview on mouse hover itself
$('.list-node-children-item-preview').hover(function(){
$(this).removeClass('active');
});
$('a.item_icon')
.unbind("click")
.click(function(e){
e.preventDefault();
// When clicking on a node preview, we load its content
var nodeId = $(this).data('node_id');
// displayNode will run asynchronously and set the bcloud_current_node_id
// as well, but we set it manually in the next line as well, to make sure
// that select_node on jstree works as expected, preventing the node to be
// loaded twice.
Cookies.set('bcloud_current_node_id', nodeId);
displayNode(nodeId);
// Update tree with current selection
$('#project_tree').jstree('select_node', 'n_' + nodeId);
});
include ../_scripts
| {% endblock %}

View File

@@ -0,0 +1,190 @@
| {% block body %}
#node-container.texture
.texture-title#node-title
| {{node.name}}
| {% if node.picture %}
.texture-backdrop(
style="background-image: url({{ node.picture.thumbnail('m', api=api) }})")
| {% endif %}
| {% if children %}
section.node-row.texture-info
span.texture-info-files {{ children|length }} item{% if children|length != 1 %}s{% endif %}
| {% endif %}
section.node-children.group.texture
| {% if children %}
| {% for child in children %}
| {% if child.properties.status == 'published' %}
a.list-node-children-container(
href="#",
data-node_id="{{ child._id }}",
class="item_icon {{child.node_type}} {% if child.picture %}thumbnail{% endif %}")
.list-node-children-item-preview
span.texture-name {{child.name}}
| {% if child.picture %}
img.texture-preview(
src="",
data-preview="{{ child.picture.thumbnail('m', api=api)}}",
alt='{{child.name}}')
| {% endif %}
.list-node-children-item(class="{{child.node_type}}")
.list-node-children-item-thumbnail
| {% if child.picture %}
img.texture-thumbnail(src="{{ child.picture.thumbnail('b', api=api)}}")
| {% else %}
.list-node-children-item-thumbnail-icon
| {% if child.node_type == 'group_texture' %}
i.pi-folder-texture
| {% else %}
i.pi-texture
| {% endif %}
| {% endif %}
| {% if child.properties.status != 'published' %}
.list-node-children-item-status {{ child.properties.status }}
| {% endif %}
| {% if child.permissions.world %}
.list-node-children-item-ribbon
span free
| {% endif %}
| {% if child.node_type == 'texture' %}
.list-node-children-item-name
| {% if child.picture.width %}
span.sizes
| {{ child.picture.width }}
small x
| {{ child.picture.height }}
| {% else %}
span.sizes {{ child.name }}
| {% endif %}
span.icons
| {% if child.properties.is_tileable %}
i.pi-puzzle(title="Tileable", data-toggle="tooltip", data-placement="bottom", data-delay=0)
| {% endif %}
| {% if child.properties.files %}
span.variations
| {% for f in child.properties.files %}
| {% if loop.last and loop.index > 5 %}
span.more +{{ loop.length - 5 }} more
| {% elif loop.index <= 5 %}
| {% if f.map_type == 'color' %}
span Color
| {% elif f.map_type == 'bump' %}
span Bump
| {% elif f.map_type == 'specular' %}
span Specular
| {% elif f.map_type == 'normal' %}
span Normal Map
| {% elif f.map_type == 'translucency' %}
span Translucency
| {% elif f.map_type == 'emission' %}
span Emission
| {% elif f.map_type == 'alpha' %}
span Alpha
| {% elif f.map_type == 'id' %}
span ID Map
| {% else %}
span {{ f.map_type }}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% if child.node_type == 'group_texture' %}
.list-node-children-item-name
i.pi-folder-texture
span {{ child.name }}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% else %}
.list-node-children-container
.list-node-children-empty No textures... yet!
| {% endif %}
script.
// Generate GA pageview
ga('send', 'pageview', location.href);
// Display texture preview on mouse hover
$('a.list-node-children-container.texture.thumbnail').hover(
function(){
var thumbnail = $(this);
var src = thumbnail.find('.texture-thumbnail').attr('src');
var src_xl = thumbnail.find('.texture-preview').data('preview');
// Load the bigger preview
var preview_img = thumbnail.find('.texture-preview');
preview_img.attr('src', src_xl);
if (preview_img) {
preview_img.load(function() {
var preview = thumbnail.find('.list-node-children-item-preview');
// Positioning stuff
var offset = thumbnail.offset();
var offset_min_x = $('.node-children').width() - preview.width();
var offset_min_y = $('.node-children').height() - preview.height();
if (preview && offset.top > 300) {
$(preview).css({'top': (preview.height() * (-1))});
};
if (offset.left > offset_min_x) {
$(preview).css({'right': 0});
};
$(preview).addClass('active');
});
}
},
function(){
$('.list-node-children-item-preview').removeClass('active');
});
// hide preview on mouse hover itself
$('.list-node-children-item-preview').hover(function(){
$(this).removeClass('active');
});
$('a.item_icon')
.unbind("click")
.click(function(e){
e.preventDefault();
// When clicking on a node preview, we load its content
var nodeId = $(this).data('node_id');
// displayNode will run asynchronously and set the bcloud_current_node_id
// as well, but we set it manually in the next line as well, to make sure
// that select_node on jstree works as expected, preventing the node to be
// loaded twice.
Cookies.set('bcloud_current_node_id', nodeId);
displayNode(nodeId);
// Update tree with current selection
$('#project_tree').jstree('select_node', 'n_' + nodeId);
});
include ../_scripts
| {% endblock %}

View File

@@ -0,0 +1,133 @@
| {% block body %}
#node-container.texture
#node-overlay
section.node-preview
| {% if node.picture %}
iframe(
width='100%',
height='450px',
scrolling='no',
frameborder='0',
allowfullscreen='',
src="{{url_for('main.vrview', preview=node.picture.thumbnail('l', api=api), image=node.picture.thumbnail('h', api=api), is_stereo='false')}}")
| {% endif %}
section.node-details-container
.node-details-header
.node-title#node-title
| {{node.name}}
.node-details-meta.header
ul.node-details-meta-list
| {% if node.permissions.world %}
li.node-details-meta-list-item.access.public(
data-toggle="tooltip",
data-placement="bottom",
title="Anybody can download. Share it!")
i.pi-lock-open
span Public
| {% endif %}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
li.node-details-meta-list-item.video.license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
li.node-details-meta-list-item.video.license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
| {% if node.properties.files %}
li.btn-group.node-details-meta-list-item.video.download(
title="Download HDRI")
button.btn.btn-default.dropdown-toggle(
type="button",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false")
i.pi-download
i.pi-angle-down.icon-dropdown-menu
ul.dropdown-menu
| {% for var in node.properties.files %}
li
a(href="{{ var.file.link }}",
title="Download this HDRi format",
download)
span.length {{ var.file.length | filesizeformat }}
span.format {{ var.file.format }}
span.size {{ var.resolution }}
| {% endfor %}
| {% else %}
li.btn-group.node-details-meta-list-item.video.download.disabled(
title="Download HDRi")
button.btn.btn-default.sorry(type="button")
i.pi-download
i.pi-angle-down.icon-dropdown-menu
| {% endif %}
| {% if node.description %}
.node-details-description#node-description
| {{node.description}}
| {% endif %}
| {% if node.properties.license_notes %}
.node-details-meta.license
| {{ node.properties.license_notes }}
| {% endif %}
.node-details-meta.footer
ul.node-details-meta-list
li.node-details-meta-list-item.status
| {{node.properties.status}}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
li.node-details-meta-list-item.date(title="Created {{ node._created }}")
| {{ node._created | pretty_date }}
| {% if (node._created | pretty_date) != (node._updated | pretty_date) %}
span(title="Updated {{ node._updated }}") (updated {{ node._updated | pretty_date }})
| {% endif %}
include ../_scripts
| {% endblock %}
| {% block footer_scripts %}
script.
$('#asset-license').popover();
// Generate GA pageview
ga('send', 'pageview', location.pathname);
$('.sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).show().addClass('active');
})
});
$('#node-overlay').click(function(){
$(this).removeClass('active').hide().html();
});
| {% endblock %}

View File

@@ -0,0 +1,175 @@
| {% extends 'layout.html' %}
| {% set title = 'blog' %}
| {% block page_title %}New {{ node_type.name }}{% endblock %}
| {% block body %}
.container.box
form(
method='POST',
action="{{url_for('nodes.posts_create', project_id=project._id)}}")
#blog_container.post-create
| {% with errors = errors %}
| {% if errors %}
| {% for field in errors %}
.alert.alert-danger(role='alert')
strong {{field}}
| {% for message in errors[field] %}
| {{message}}|
| {% endfor %}
| {% endfor %}
| {% endif %}
| {% endwith %}
#blog_index-sidebar
| {% if project._id != config.MAIN_PROJECT_ID %}
.blog_project-card
a.item-header(
href="{{ url_for('projects.view', project_url=project.url) }}")
.overlay
| {% if project.picture_header %}
img.background(src="{{ project.picture_header.thumbnail('m', api=api) }}")
| {% endif %}
a.card-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img.thumb(src="{{ project.picture_square.thumbnail('m', api=api) }}")
| {% endif %}
.item-info
a.item-title(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
| {% endif %}
.blog_project-sidebar
#blog_post-edit-form
| {% for field in form %}
| {% if field.name in ['picture', 'status'] %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endfor %}
input.btn.btn-default.button-create(type='submit', value='Create {{ node_type.name }}')
a.btn.btn-default.button-back(href="{{ url_for('projects.view', project_url=project.url) }}blog")
| Back to Blog
#blog_post-create-container
#blog_post-edit-title
| Create {{ node_type.name }} on {{ project.name }}
#blog_post-edit-form
| {% for field in form %}
| {% if field.name == 'csrf_token' %}
| {{ field }}
| {% else %}
| {% if field.type == 'HiddenField' %}
| {{ field }}
| {% else %}
| {% if field.name not in ['description', 'picture', 'category', 'status'] %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% endblock %}
| {% block footer_scripts %}
script(type="text/javascript").
function FormatForUrl(str) {
return str.replace(/_/g, '-')
.replace(/ /g, '-')
.replace(/:/g, '-')
.replace(/\\/g, '-')
.replace(/\//g, '-')
.replace(/[^a-zA-Z0-9\-]+/g, '')
.replace(/-{2,}/g, '-')
.toLowerCase();
};
var convert = new Markdown.getSanitizingConverter().makeHtml;
/* Build the markdown preview when typing in textarea */
$(function() {
var $textarea = $('.form-group.content textarea'),
$loader = $('<div class="md-preview-loading"><i class="pi-spin spin"></i></div>').insertAfter($textarea),
$preview = $('<div class="node-edit-form-md-preview" />').insertAfter($loader);
$loader.hide();
// Delay function to not start converting heavy posts immediately
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$textarea.keyup(function() {
/* If there's an iframe (YouTube embed), delay markdown convert 1.5s */
if (/iframe/i.test($textarea.val())) {
$loader.show();
delay(function(){
// Convert markdown
$preview.html(convert($textarea.val()));
$loader.hide();
}, 1500 );
} else {
// Convert markdown
$preview.html(convert($textarea.val()));
};
}).trigger('keyup');
});
$(function() {
var $name_input = $('.form-group.name input');
$name_input.keyup(function() {
$('#url').val(FormatForUrl($name_input.val()));
}).trigger('keyup');
});
| {% endblock %}
| {% block footer_navigation %}
| {% endblock %}
| {% block footer %}
| {% endblock %}

View File

@@ -0,0 +1,168 @@
| {% extends 'layout.html' %}
| {% set title = 'blog' %}
| {% block page_title %}New {{ node_type.name }}{% endblock %}
| {% block body %}
.container.box
form(
method='POST',
action="{{url_for('nodes.posts_edit', post_id=post._id)}}")
#blog_container.post-create
| {% with errors = errors %}
| {% if errors %}
| {% for field in errors %}
.alert.alert-danger(role='alert')
strong {{field}}
| {% for message in errors[field] %}
| {{message}}|
| {% endfor %}
| {% endfor %}
| {% endif %}
| {% endwith %}
#blog_index-sidebar
| {% if project._id != config.MAIN_PROJECT_ID %}
.blog_project-card
a.item-header(
href="{{ url_for('projects.view', project_url=project.url) }}")
.overlay
| {% if project.picture_header %}
img.background(src="{{ project.picture_header.thumbnail('m', api=api) }}")
| {% endif %}
a.card-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img.thumb(src="{{ project.picture_square.thumbnail('m', api=api) }}")
| {% endif %}
.item-info
a.item-title(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
| {% endif %}
.blog_project-sidebar
#blog_post-edit-form
| {% for field in form %}
| {% if field.name in ['picture', 'status'] %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endfor %}
button.btn.btn-default.button-create(type='submit')
i.pi-check
| Update {{ node_type.name }}
a.btn.btn-default.button-back(href="{{ url_for_node(node=post) }}")
i.pi-angle-left
| Back to Post
a.btn.btn-default.button-back(href="{{ url_for('projects.view', project_url=project.url) }}blog")
| Go to Blog
#blog_post-edit-container
#blog_post-edit-title
| Edit {{ node_type.name }}
#blog_post-edit-form
| {% for field in form %}
| {% if field.name == 'csrf_token' %}
| {{ field }}
| {% else %}
| {% if field.type == 'HiddenField' %}
| {{ field }}
| {% else %}
| {% if field.name not in ['description', 'picture', 'category', 'status'] %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% endblock %}
| {% block footer_scripts %}
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.iframe-transport.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.iframe-transport.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.fileupload.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/file_upload.min.js') }}")
script(type="text/javascript").
var convert = new Markdown.getSanitizingConverter().makeHtml;
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}"});
/* Build the markdown preview when typing in textarea */
$(function() {
var $textarea = $('.form-group.content textarea'),
$loader = $('<div class="md-preview-loading"><i class="pi-spin spin"></i></div>').insertAfter($textarea),
$preview = $('<div class="node-edit-form-md-preview" />').insertAfter($loader);
$loader.hide();
// Delay function to not start converting heavy posts immediately
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$textarea.keyup(function() {
/* If there's an iframe (YouTube embed), delay markdown convert 1.5s */
if (/iframe/i.test($textarea.val())) {
$loader.show();
delay(function(){
// Convert markdown
$preview.html(convert($textarea.val()));
$loader.hide();
}, 1500 );
} else {
// Convert markdown
$preview.html(convert($textarea.val()));
};
}).trigger('keyup');
});
| {% endblock %}
| {% block footer_navigation %}
| {% endblock %}
| {% block footer %}
| {% endblock %}

View File

@@ -0,0 +1,4 @@
| {% extends 'layout.html' %}
| {% block page_title %}{{node.name}} - Blog{% endblock%}
include view_embed

View File

@@ -0,0 +1,128 @@
| {% block og %}
| {% set title = 'blog' %}
| {% if project %}
meta(property="og:title", content="{{ node.name }}{% if project._id == config.MAIN_PROJECT_ID %} — Blender Cloud Blog{% else%} - {{ project.name }} — Blender Cloud{% endif %}")
| {% endif %}
| {% if project and project.properties.picture_header %}
meta(property="og:image", content="{{ project.properties.picture_header.thumbnail('l', api=api) }}")
| {% elif node and node.picture %}
meta(property="og:image", content="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
meta(property="og:description", content="{{ node.properties.content }}")
meta(property="og:type", content="article")
meta(property="article:type", content="{{node.user.full_name}}")
meta(property="article:published_time", content="{{node._created | pretty_date }}")
meta(property="og:see_also", content="https://cloud.blender.org/blog")
meta(property="og:url", content="https://cloud.blender.org{{ url_for_node(node=node) }}")
| {% endblock %}
| {% block tw %}
meta(name="twitter:card", content="summary_large_image")
| {% if project._id == config.MAIN_PROJECT_ID %}
meta(property="twitter:title", content="{{ node.name }} — Blender Cloud Blog")
| {% else %}
meta(property="twitter:title", content="{{ node.name }} - {{ project.name }} Blog — Blender Cloud")
| {% endif %}
| {% if project and project.properties.picture_header %}
meta(name="twitter:image", content="{{ project.properties.picture_header.thumbnail('l', api=api) }}")
| {% elif node and node.picture %}
meta(name="twitter:image", content="{{ node.picture.thumbnail('l', api=api) }}")
| {% else %}
meta(name="twitter:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_caminandes_3_02.jpg')}}")
| {% endif %}
meta(name="twitter:description", content="{{ node.properties.content }}")
| {% endblock %}
| {% block body %}
.container.box
#blog_container(class="{% if project._id == config.MAIN_PROJECT_ID %}cloud-blog{% endif %}")
#blog_post-container
| {% if project._id == config.MAIN_PROJECT_ID %}
a.btn.btn-default.button-back(href="{{ url_for('projects.view', project_url=project.url) }}blog")
| Back to Blog
| {% if node.has_method('PUT') %}
a.btn.btn-default.button-edit(href="{{url_for('nodes.posts_edit', post_id=node._id)}}")
i.pi-edit
| Edit Post
| {% endif %}
.clearfix
| {% endif %}
| {% if node.picture %}
.blog_index-header
img(src="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
.blog_index-item
.item-title
| {{node.name}}
.item-info.
<span title="{{node._created}}">{{node._created | pretty_date }}</span>
{% if node._created != node._updated %}
<span title="{{node._updated}}">(updated {{node._updated | pretty_date }})</span>
{% endif %}
{% if node.properties.category %}| {{node.properties.category}}{% endif %}
| by {{node.user.full_name}}
.item-content
| {{ node.properties.content }}
#comments-container
#comments-list-items-loading
i.pi-spin
| {% if project._id != config.MAIN_PROJECT_ID %}
#blog_index-sidebar
.blog_project-card
a.item-header(
href="{{ url_for('projects.view', project_url=project.url) }}")
.overlay
| {% if project.picture_header %}
img.background(src="{{ project.picture_header.thumbnail('m', api=api) }}")
| {% endif %}
a.card-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img.thumb(src="{{ project.picture_square.thumbnail('m', api=api) }}")
| {% endif %}
.item-info
a.item-title(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
| {% if project.summary %}
p.item-description
| {{project.summary|safe}}
| {% endif %}
.blog_project-sidebar
| {% if node.has_method('PUT') %}
a.btn.btn-default.button-create(href="{{url_for('nodes.posts_edit', post_id=node._id)}}")
| Edit Post
| {% endif %}
a.btn.btn-default.button-back(href="{{ url_for('projects.view', project_url=project.url) }}blog")
| Back to Blog
| {% endif %}
| {% endblock %}
| {% block footer_scripts %}
include ../_scripts
script hopToTop(); // Display jump to top button
| {% endblock %}

View File

@@ -0,0 +1,53 @@
| {% block body %}
#node-container
section.node-details-container.storage
.node-details-header
.node-title
| {{node.name}}
section.node-children.storage
| {% if node.children %}
| {% for child in node.children %}
a(href="#", data-node_id="{{ node._id }}" data-path="{{ child['path'] }}", title="{{ child['name'] }}", class="item_icon")
.list-node-children-item
.list-node-children-item-thumbnail
.list-node-children-item-thumbnail-icon
| {% if child['content_type'] == 'video' %}
i.pi-film
| {% elif child['content_type'] == 'image' %}
i.pi-image
| {% elif child['content_type'] == 'file' %}
i.pi-document
| {% elif child['content_type'] == 'binary' %}
i.pi-file-archive
| {% else %}
i.pi-folder
| {% endif %}
.list-node-children-item-name
span {{ child['name'] }}
| {% endfor %}
| {% endif %}
script.
$('a.item_icon').click(function(e){
// When clicking on a node preview, we load its content
e.preventDefault;
var nodeId = $(this).data('node_id');
var path = $(this).data('path');
displayStorage(nodeId, path);
// Update tree with current selection
//$('#project_tree').jstree('select_node', 'n_' + nodeId);
});
| {% endblock %}

View File

@@ -0,0 +1,33 @@
| {% block body %}
#node-container
section.node-details-container.storage
.node-details-header
.node-title
| {{node.name}}
//- .node-details-description
//- | {{node.description}}
.node-details-meta
ul.node-details-meta-list
li.node-details-meta-list-item.status
| {{node.status}}
li.node-details-meta-list-item.date(title="Created {{ node._created | pretty_date }}")
| {{ node._updated | pretty_date }}
li.node-details-meta-list-item.file.length
| {{ node.length | filesizeformat }}
li.node-details-meta-list-item.file.download
a(href="{% if node.has_method('GET') %}{{ node.download_link }}{% else %}{{ url_for('users.login') }}{% endif %}")
button.btn.btn-default(type="button")
| Download
| {% endblock %}

View File

@@ -0,0 +1,195 @@
| {% block body %}
#node-container.texture
#node-overlay
.texture-title#node-title
| {{node.name}}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
.texture-license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
.texture-license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
section.node-row.texture-info
| {% if node.properties.files %}
span.texture-info-files
i.pi-texture
| {{ node.properties.files|length }} map{% if node.properties.files|length != 1 %}s{% endif %}
| {% endif %}
span.texture-info-seamless
i.pi-puzzle
| {% if not node.properties.is_tileable %}Not {% endif %}Seamless
| {% if node.properties.files %}
| {% for f in node.properties.files %}
section.node-row.texture-map
section.node-preview.texture
img.node-preview-thumbnail(
src="{{ f.file.thumbnail('m', api=api) }}",
data-preview="{{ f.file.thumbnail('l', api=api) }}",
data-aspect_ratio="{{ node.properties.aspect_ratio }}")
| {% if f.map_type == 'color' %}
| {% set map_type = 'Color Map' %}
| {% elif f.map_type == 'bump' %}
| {% set map_type = 'Bump Map' %}
| {% elif f.map_type == 'specular' %}
| {% set map_type = 'Specular Map' %}
| {% elif f.map_type == 'normal' %}
| {% set map_type = 'Normal Map' %}
| {% elif f.map_type == 'translucency' %}
| {% set map_type = 'Translucency' %}
| {% elif f.map_type == 'emission' %}
| {% set map_type = 'Emission' %}
| {% elif f.map_type == 'alpha' %}
| {% set map_type = 'Alpha' %}
| {% elif f.map_type == 'id' %}
| {% set map_type = 'ID Map' %}
| {% else %}
| {% set map_type = f.map_type %}
| {% endif %}
section.node-details-container.texture
.node-details-header
.node-title {{map_type}}
.node-details-attributes
span.sizes
span.x
| Width:
strong {{ f.file.width }}
span.y
| Height:
strong {{ f.file.height }}
span.length
| {{ f.file.length | filesizeformat }}
span.content_type
| {{ f.file.content_type }}
.node-details-meta
ul.node-details-meta-list
li.node-details-meta-list-item.texture.download
| {% if f.file.link %}
a(href="{{ f.file.link }}",,
title="Download texture",
download="{{ f.file.filename }}")
button.btn.btn-default(type="button")
i.pi-download
| Download
| {% else %}
button.btn.btn-default.disabled.sorry(type="button")
| Download
| {% endif %}
| {% endfor %}
| {% else %}
section.node-row
section.node-details-container.texture
.node-details-header.nofiles
.node-title No texture maps... yet!
| {% endif %}
include ../_scripts
| {% endblock %}
| {% block footer_scripts %}
script.
$('#asset-license').popover();
// Generate GA pageview
ga('send', 'pageview', location.pathname);
var str = $('.texture-title').text();
var to_replace = /_color|_bump|_specular|_normal|_translucency|_emission|_alpha|_tileable|.jpg|.png/g;
$('.texture-title').text(str.replace(to_replace,'').replace(/_/g,' '));
$('.node-preview-thumbnail').each(function(i){
$(this).closest('.node-preview').css({'height' : $(this).width() / $(this).data('aspect_ratio')});
var thumbnail = $(this);
var src = $(this).attr('src');
var src_xl = $(thumbnail).data('preview');
var src_xl_width, src_xl_height;
/* Make dummy img in memory otherwise we have css issues */
$("<img/>")
.attr('src', src_xl)
.load(function(){
src_xl_width = this.width;
src_xl_height = this.height;
});
$(this).on('click', function(e){
e.preventDefault();
});
$(this).hover(
function(){
var preview = $(this);
/* Replace image src with larger one */
if (src_xl_width > 350 || src_xl_height > 250) {
$(thumbnail).attr('src', src_xl);
$(preview).css({width: src_xl_width + 'px', height: src_xl_height + 'px'});
}
var parent = $(preview).parent();
var parentOffset = parent.offset();
if (src_xl_width > 600 || src_xl_height > 300) {
$(document).on('mousemove', function(e){
$(preview).css({
left: e.pageX - parentOffset.left - (src_xl_width / 2),
top: e.pageY - parentOffset.top - (src_xl_height / 2),
transform: 'initial',
cursor: 'grabbing',
});
});
};
},
function(){
$(document).off('mousemove');
$(this).attr('src', src);
$(this).css({left: '50%', top: "50%", width: '100%', height: 'auto', transform: 'translate(-50%, -50%)'});
}
);
});
$('.sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).show().addClass('active');
})
});
$('#node-overlay').click(function(){
$(this).removeClass('active').hide().html();
});
| {% endblock %}

View File

@@ -0,0 +1,11 @@
| {% extends 'layout.html' %}
| {% block body %}
div.container
div.page-content
| {% include 'nodes/edit_embed.html' %}
| {% endblock %}
| {% block footer_scripts %}
| {% include '_macros/_file_uploader_javascript.html' %}
| {% endblock %}

View File

@@ -0,0 +1,347 @@
| {% from '_macros/_node_edit_form.html' import render_field %}
| {% block body %}
| {% with errors = errors %}
| {% if errors %}
| {% for field in errors %}
.alert.alert-danger(role="alert")
strong {{field}}
| {% for message in errors[field] %}
| {{message}}|
| {% endfor %}
| {% endfor %}
| {% endif %}
| {% endwith %}
| {% if error!="" %}
.alert.alert-danger(role="alert")
| {{error}}
| {% endif %}
#node-edit-container
form(
id="node-edit-form",
class="{{ node.node_type }}",
method="POST",
enctype="multipart/form-data",
action="{{url_for('nodes.edit', node_id=node._id)}}")
| {% for field in form %}
| {% if field.name == 'csrf_token' %}
| {{ field }}
| {% elif field.type == 'HiddenField' %}
| {{ field }}
| {% elif field.name == 'attachments' %}
#attachments-actions
.btn.btn-info#attachments-action-add
i.pi-plus
| Add New Attachment
| {{ render_field(field) }}
| {% elif field.name == 'files' %}
.files-header
#files-actions
#files-action-add
i.pi-plus
| Add New File
| {{ render_field(field) }}
| {% else %}
| {{ render_field(field) }}
| {% endif %}
| {% endfor %}
ul.project-edit-tools.bottom
li.button-cancel
a#item_cancel.item-cancel.project-mode-edit(
href="javascript:void(0);",
title="Cancel changes")
i.button-cancel-icon.pi-cancel
| Cancel
li.button-save
a#item_save.item-save.project-mode-edit(
href="javascript:void(0);",
title="Save changes")
i.button-save-icon.pi-check
| Save Changes
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.ui.widget.min.js') }}")
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.iframe-transport.min.js') }}")
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.fileupload.min.js') }}")
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.select2.min.js') }}")
script(src="{{ url_for('static_pillar', filename='assets/js/file_upload.min.js') }}")
script(type="text/javascript").
$(function () {
$('#tags').select2();
});
var convert = new Markdown.getSanitizingConverter();
Markdown.Extra.init(convert);
convert = convert.makeHtml;
/* Build the markdown preview when typing in textarea */
$(function() {
var $textarea = $('.form-group.description textarea'),
$loader = $('<div class="md-preview-loading"><i class="pi-spin spin"></i></div>').insertAfter($textarea),
$preview = $('<div class="node-edit-form-md-preview" />').insertAfter($loader);
$loader.hide();
// Delay function to not start converting heavy posts immediately
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$textarea.keyup(function() {
/* If there's an iframe (YouTube embed), delay markdown convert 1.5s */
if (/iframe/i.test($textarea.val())) {
$loader.show();
delay(function(){
// Convert markdown
$preview.html(convert($textarea.val()));
$loader.hide();
}, 1500 );
} else {
// Convert markdown
$preview.html(convert($textarea.val()));
}
}).trigger('keyup');
});
$(function() {
$('input, textarea').keypress(function () {
// Unused: save status of the page as 'edited'
ProjectUtils.setProjectAttributes({isModified: true});
// Set the beforeunload to warn the user of unsaved changes
$(window).on('beforeunload', function () {
return 'You have unsaved changes in your asset.';
});
});
});
$("#item_save").unbind( "click" );
$("#item_cancel").unbind( "click" );
$(".file_delete").unbind( "click" );
/* Reset Save Changes button status */
$("li.button-save").removeClass('field-error saving');
$("li.button-save a#item_save").html('<i class="pi-check"></i> Save Changes');
/* Submit changes */
$("#node-edit-form").unbind( "submit" )
.submit(function(e) {
e.preventDefault();
/* Let us know started saving */
$("li.button-save").addClass('saving');
$("li.button-save a#item_save").html('<i class="pi-spin spin"></i> Saving...');
$.ajax({
url: "{{url_for('nodes.edit', node_id=node._id)}}",
data: $(this).serialize(),
type: 'POST'
})
.fail(function(data){
/* Something went wrong, print it */
if (data.status == 422) {
statusBarSet('error', 'The submitted data could not be validated.', 8000);
} else {
statusBarSet('error', 'Error! We\'ve been notified and are working on it - '
+ data.status + ' ' + data.statusText, 8000);
}
$("li.button-save").addClass('field-error');
$("li.button-save a#item_save").html('<i class="pi-warning"></i> Houston!');
/* Back to normal */
setTimeout(function(){
$("li.button-save").removeClass('saving field-error');
$("li.button-save a#item_save").html('<i class="pi-check"></i> Save Changes');
}, 8000);
})
.done(function(dataHtml){
/* Success! */
/* Load content*/
$('#project_context').html(dataHtml);
statusBarSet('success', 'Saved Successfully', 'pi-check');
/* Style button */
$("li.button-save").removeClass('saving field-error');
$("li.button-save a#item_save").html('<i class="pi-check"></i> Save Changes');
// XXX TODO - Keeps displaying 'loading', needs further investigation
//- $('#project_tree').jstree("refresh");
updateUi(ProjectUtils.nodeId(), 'view');
});
});
$('#item_save, .item-save').click(function(e){
e.preventDefault();
// Assets always need a file
if ($('.form-group.file #file').val() == ''){
$('.form-group.file').addClass('error');
statusBarSet('error', 'No File Selected', 'pi-warning', 5000);
} else {
$('.form-group.file').removeClass('error');
$("#node-edit-form").submit();
// Disable beforeunolad when submitting a form
$(window).off('beforeunload');
}
});
$('#item_cancel, .item-cancel').click(function(e){
displayNode('{{node._id}}');
});
var attrs = ['for', 'id', 'name', 'data-field-name'];
function resetAttributeNames(section) {
var tags = section.find('input, select, label, div, a');
var idx = section.index();
tags.each(function () {
var $this = $(this);
// Renumber certain attributes.
$.each(attrs, function (i, attr) {
var attr_val = $this.attr(attr);
if (attr_val) {
$this.attr(attr, attr_val.replace(/-\d+/, '-' + idx))
}
});
// Clear input field values
var tagname = $this.prop('tagName');
if (tagname == 'INPUT') {
if ($this.attr('type') == 'checkbox') {
$this.prop('checked', false);
} else {
$this.val('');
}
} else if (tagname == 'SELECT') {
$this.find(':nth-child(1)').prop('selected', true);
}
});
// Click on all file delete buttons to clear all file widgets.
section.find('a.file_delete').click();
section.find('div.form-upload-progress-bar').hide();
}
var initUploadFields = function(selector_string) {
// console.log($(selector_string));
$(selector_string).fileupload({
dataType: 'json',
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
replaceFileInput: false,
dropZone: $(this),
formData: {},
progressall: function (e, data) {
// Update progressbar during upload
var progress = parseInt(data.loaded / data.total * 100, 10);
$(this).next().find('.form-upload-progress-bar').css(
{'width': progress + '%', 'display': 'block'}
).removeClass('progress-error').addClass('progress-active');
fieldUpload = $(this);
},
done: function (e, data) {
// Get the first file upload result (we only need one)
var fileData = data.result.files[0];
// Create a file object on the server and retrieve its id
statusBarSet('info', 'Uploading File...', 'pi-upload-cloud');
$('.button-save').addClass('disabled');
$('li.button-save a#item_save').html('<i class="pi-spin spin"></i> Uploading Preview...');
var payload = {
name: fileData.name,
size: fileData.size,
type: fileData.type,
field_name: $(this).data('field-name'),
project_id: ProjectUtils.projectId()
}
$.post("/files/create", payload)
.done(function (data) {
if (data.status === 'success') {
// If successful, add id to the picture hidden field
var field_name = '#' + data.data.field_name;
if ($(field_name).val()) {
$('.node-preview-thumbnail').hide();
deleteFile($(field_name), data.data.id);
} else {
$(field_name).val(data.data.id);
}
var previewThumbnail = fieldUpload.prev().prev();
$(previewThumbnail).attr('src', data.data.link);
$('.node-preview-thumbnail').show();
statusBarSet('success', 'File Uploaded Successfully', 'pi-check');
$('.button-save').removeClass('disabled');
$('li.button-save a#item_save').html('<i class="pi-check"></i> Save Changes');
$('.progress-active').removeClass('progress-active progress-error');
}
})
.fail(function(data) {
$('.button-save').removeClass('disabled');
$('li.button-save a#item_save').html('<i class="pi-check"></i> Save Changes');
statusBarSet(data.textStatus, 'Upload error: ' + data.errorThrown, 'pi-attention', 8000);
});
},
fail: function (e, data) {
$('.button-save').removeClass('disabled');
$('li.button-save a#item_save').html('<i class="pi-check"></i> Save Changes');
statusBarSet(data.textStatus, 'Upload error: ' + data.errorThrown, 'pi-attention', 8000);
$('.progress-active').addClass('progress-error').removeClass('progress-active');
}
});
}
if (document.getElementById("attachments") !== null) {
$("#attachments-action-add").on('click', function(){
var lastRepeatingGroup = $('#attachments > li').last();
var cloned = lastRepeatingGroup.clone(true);
cloned.insertAfter(lastRepeatingGroup);
resetAttributeNames(cloned);
});
}
if (document.getElementById("files") !== null) {
$("#files-action-add").on('click', function () {
var lastRepeatingGroup = $('#files > li').last();
var cloned = lastRepeatingGroup.clone(false);
cloned.insertAfter(lastRepeatingGroup);
resetAttributeNames(cloned);
cloned.find('.fileupload').each(setup_file_uploader)
});
}
//- console.log($._data($(elementSelector)[0], "events"));
| {% endblock %}

View File

@@ -0,0 +1,301 @@
| {% extends 'layout.html' %}
| {% block page_title %}Search{% if project %} {{ project.name }}{% endif %}{% endblock %}
| {% block og %}
meta(property="og:type", content="website")
| {% if og_picture %}
meta(property="og:image", content="{{ og_picture.thumbnail('l', api=api) }}")
| {% endif %}
| {% if project %}
meta(property="og:title", content="{{project.name}} - Blender Cloud")
meta(property="og:url", content="{{url_for('projects.view', project_url=project.url, _external=True)}}")
meta(property="og:description", content="{{project.summary}}")
| {% endif %}
| {% endblock %}
| {% block tw %}
| {% if og_picture %}
meta(property="twitter:image", content="{{ og_picture.thumbnail('l', api=api) }}")
| {% endif %}
| {% if project %}
meta(name="twitter:title", content="{{project.name}} on Blender Cloud")
meta(name="twitter:description", content="{{project.summary}}")
| {% endif %}
| {% endblock %}
| {% block body %}
#search-container
| {% if project %}
#project_sidebar
ul.project-tabs
li.tabs-thumbnail(
title="About",
data-toggle="tooltip",
data-placement="left",
class="{% if title == 'about' %}active {% endif %}{% if project.picture_square %}image{% endif %}")
a(href="{{url_for('projects.about', project_url=project.url, _external=True)}}")
#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="left")
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
i.pi-tree-flow
li.tabs-search.active(
title="Search",
data-toggle="tooltip",
data-placement="left")
a(href="{{url_for('projects.search', project_url=project.url, _external=True)}}")
i.pi-search
| {% endif %}
#search-sidebar
input.search-field(
type="text",
name="q",
id="q",
autocomplete="off",
spellcheck="false",
autocorrect="false",
placeholder="Search by Title, Type...")
.search-list-filters
.filter-list
| View as:
ul.filter-list
li.filter-list-type.grid(
title="Browse as grid",
data-list-type="grid")
i.pi-layout
li.filter-list-type.list(
title="Browse as list",
data-list-type="list")
i.pi-list
#accordion.panel-group.accordion(role="tablist", aria-multiselectable="true")
#facets
#pagination
.search-list-stats
#stats
#search-list
#hits
#search-details
#search-error
#search-hit-container
| {% raw %}
// Facet template
script(type="text/template", id="facet-template")
.panel.panel-default
a(data-toggle='collapse', data-parent='#accordion', href='#filter_{{ facet }}', aria-expanded='true', aria-controls='filter_{{ facet }}')
.panel-heading(role='tab')
.panel-title {{ title }}
.panel-collapse.collapse.in(id='filter_{{ facet }}', role='tabpanel', aria-labelledby='headingOne')
.panel-body
| {{#values}}
a.facet_link.toggleRefine(
class='{{#refined}}refined{{/refined}}',
data-facet='{{ facet }}',
data-value='{{ value }}',
href='#')
span
| {{ label }}
small.facet_count.pull-right {{ count }}
| {{/values}}
// Hit template
script(type="text/template", id="hit-template")
.search-hit(data-hit-id='{{ objectID }}')
#search-loading.search-loading
.spinner
span.spin ·
.search-hit-thumbnail
| {{#picture}}
img(src="{{{ picture }}}")
| {{/picture}}
| {{^picture}}
.search-hit-thumbnail-icon
| {{#media}}
i(class="pi-{{{ media }}}")
| {{/media}}
| {{^media}}
i.dark(class="pi-{{{ node_type }}}")
| {{/media}}
| {{/picture}}
| {{#is_free}}
.search-hit-ribbon
span free
| {{/is_free}}
.search-hit-name
| {{{ _highlightResult.name.value }}}
.search-hit-meta
span.project {{{ project.name }}} ·
span.node_type {{{ node_type }}}
| {{#media}}
span.media · {{{ media }}}
| {{/media}}
span.when {{{ created }}}
span.context
a(href="/nodes/{{ objectID }}/redir") view in context
// Pagination template
script(type="text/template", id="pagination-template")
ul.search-pagination.
<li {{^prev_page}}class="disabled"{{/prev_page}}><a href="#" {{#prev_page}} class="gotoPage" data-page="{{ prev_page }}" {{/prev_page}}><i class="pi-angle-left"></i></a></li>
{{#pages}}
<li class="{{#current}}active{{/current}}{{#disabled}}disabled{{/disabled}}"><a href="#" {{^disabled}} class="gotoPage" data-page="{{ number }}" {{/disabled}}>{{ number }}</a></li>
{{/pages}}
<li {{^next_page}}class="disabled"{{/next_page}}><a href="#" {{#next_page}} class="gotoPage" data-page="{{ next_page }}" {{/next_page}}><i class="pi-angle-right"></i></a></li>
// Stats template
script(type="text/template", id="stats-template")
span {{ nbHits }} result{{#nbHits_plural}}s{{/nbHits_plural}}
small ({{ processingTimeMS }}ms)
| {% endraw %}
| {% endblock %}
| {% block footer_scripts %}
script(src="//releases.flowplayer.org/6.0.5/flowplayer.min.js", async)
script().
var APPLICATION_ID = '{{config.ALGOLIA_USER}}';
var SEARCH_ONLY_API_KEY = '{{config.ALGOLIA_PUBLIC_KEY}}';
var INDEX_NAME = '{{config.ALGOLIA_INDEX_NODES}}';
var sortByCountDesc = null;
var FACET_CONFIG = [
{ name: 'node_type', title: 'Type', disjunctive: false, sortFunction: sortByCountDesc },
{ name: 'media', title: 'Media', disjunctive: false, sortFunction: sortByCountDesc },
{ name: 'tags', title: 'Tags', disjunctive: false, sortFunction: sortByCountDesc },
{ name: 'is_free', title: 'Free Access', disjunctive: false, sortFunction: sortByCountDesc },
];
{% if project %}
FACET_CONFIG.push({ name: 'project._id', title: 'Project', disjunctive: false, hidden: true, value: '{{project._id}}' })
{% endif %}
script(src="//cdn.jsdelivr.net/algoliasearch.helper/2/algoliasearch.helper.min.js")
script(src="//cdn.jsdelivr.net/hogan.js/3.0.0/hogan.common.js")
script(src="{{ url_for('static_pillar', filename='assets/js/algolia_search.min.js') }}")
script(type="text/javascript").
function displayUser(userId) {
var url = '/nodes/' + userId + '/view';
$.get(url, function(dataHtml){
$('#search-hit-container').html(dataHtml);
})
.done(function(){
$('.search-loading').removeClass('active');
$('#search-error').hide();
$('#search-hit-container').show();
})
.fail(function(data){
$('.search-loading').removeClass('active');
$('#search-hit-container').hide();
$('#search-error').show().html('Houston!\n\n' + data.status + ' ' + data.statusText);
});
}
$('body').on('click', '.search-hit', function(){
if ($('.search-loading').hasClass('active')){
$(this).removeClass('active');
}
$(this).find('#search-loading').addClass('active');
displayUser($(this).data('hit-id'));
$('.search-hit').removeClass('active');
$(this).addClass('active');
});
// Remove focus from search input so that the click event bound to .search-hit
// can be fired on the first click.
$(searchList).hover(function(){
$('#q').blur();
});
$('#search-sidebar').hover(function(){
$('#q').focus();
});
/* UI Stuff */
/* List types, grid or list (default)*/
var uiListType = Cookies.getJSON('bcloud_ui');
var searchList = document.getElementById('search-list');
function uiSetListType(type){
$('.filter-list-type').removeClass('active');
if (type == 'grid'){
$(searchList).addClass('view-grid');
$('.filter-list-type.grid').addClass('active');
} else {
$(searchList).removeClass('view-grid');
$('.filter-list-type.list').addClass('active');
}
}
if (uiListType && uiListType.search_browse_type == 'grid'){
uiSetListType('grid');
} else {
uiSetListType('list');
}
$('.filter-list-type').on('click', function(){
if ($(this).attr('data-list-type') == 'grid'){
uiSetListType('grid');
setJSONCookie('bcloud_ui', 'search_browse_type', 'grid');
} else {
uiSetListType('list');
setJSONCookie('bcloud_ui', 'search_browse_type', 'list');
}
});
/* Scrollbars */
if (typeof Ps !== 'undefined'){
Ps.initialize(searchList, {suppressScrollX: true});
Ps.initialize(document.getElementById('search-hit-container'), {suppressScrollX: true});
}
/* Hide site-wide search, kinda confusing */
$('.search-input').hide();
/* Resize container so we can have custom scrollbars */
container_offset = $('#search-container').offset();
function containerResizeY(window_height){
var container_height = window_height - container_offset.top;
if (container_height > parseInt($('#search-container').css("min-height"))) {
$('#search-container').css(
{'max-height': container_height + 'px', 'height': container_height + 'px'}
);
$('#search-list, #search-hit-container').css(
{'max-height': container_height + 'px', 'height': container_height + 'px'}
);
};
};
$(window).on("load resize",function(){
containerResizeY($(window).height());
});
| {% endblock %}
| {% block footer_navigation %}{% endblock %}
| {% block footer %}{% endblock %}

View File

@@ -0,0 +1,22 @@
script(type="text/javascript").
/* Convert Markdown */
var convert = new Markdown.getSanitizingConverter().makeHtml;
var convert_fields = '.node-details-description, .blog_index-item .item-content';
/* Parse description/content fields to convert markdown */
$(convert_fields).each(function(i){
$(convert_fields).eq(i).html(convert($(convert_fields).eq(i).text()));
});
ProjectUtils.setProjectAttributes({isProject: true, nodeId: '', parentNodeId: ''});
var movingMode = Cookies.getJSON('bcloud_moving_node');
if (movingMode){
$('#item_move_accept').removeClass('disabled').html('<i class="pi-check"></i> Move to Root');
if (movingMode.node_type === 'texture'){
$('#item_move_accept').addClass('disabled').html('Select a Texture Folder');
}
};

View File

@@ -0,0 +1,250 @@
| {% extends 'layout.html' %}
| {% set title = 'edit' %}
| {% block page_title %}Edit {{ project.name }}{% endblock %}
| {% block body %}
#project-container
#project-side-container
#project_sidebar
ul.project-tabs
li.tabs-thumbnail(
title="About",
data-toggle="tooltip",
data-placement="left",
class="{% if title == 'about' %}active {% endif %}{% if project.picture_square %}image{% endif %}")
a(href="{{url_for('projects.about', project_url=project.url, _external=True)}}")
#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="left")
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
i.pi-tree-flow
| {% if not project.is_private %}
li.tabs-search(
title="Search",
data-toggle="tooltip",
data-placement="left")
a(href="{{url_for('projects.search', project_url=project.url, _external=True)}}")
i.pi-search
| {% endif %}
.project_nav-toggle-btn(
title="Expand Navigation [T]",
data-toggle="tooltip",
data-placement="right")
i.pi-angle-double-left
#project_nav
#project_nav-container
#project_nav-header
.project-title
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| {{ project.name }}
// TODO - make list a macro
#project_tree
ul.project_nav-edit-list
li(class="{% if title == 'edit' %}active{% endif %}")
a(href="{{ url_for('projects.edit', project_url=project.url) }}")
i.pi-list
| Overview
li(class="{% if title == 'sharing' %}active{% endif %}")
a(href="{{ url_for('projects.sharing', project_url=project.url) }}")
i.pi-share
| Sharing
li(class="{% if title == 'edit_node_types' %}active{% endif %}")
a(href="{{ url_for('projects.edit_node_types', project_url=project.url) }}")
i.pi-puzzle
| Node Types
.project_split(title="Toggle Navigation [T]")
#project_context-container
#project_context-header
span#project-statusbar
span#project-edit-title
| Edit Project
ul.project-edit-tools
// Edit Mode
li.button-cancel
a#item_cancel.project-mode-edit(
href="{{url_for('projects.view', project_url=project.url, _external=True)}}",
title="Cancel changes")
i.button-cancel-icon.pi-back
| Go to Project
li.button-save
a#item_save.project-mode-edit(
href="#",
title="Save changes")
i.button-save-icon.pi-check
| Save Changes
#project_context
#node-edit-container
form(
id="node-edit-form"
method='POST',
action="{{url_for('projects.edit', project_url=project.url)}}")
| {% with errors = errors %}
| {% if errors %}
| {% for field in errors %}
.alert.alert-danger(role='alert')
strong {{field}}
| {% for message in errors[field] %}
| {{message}}|
| {% endfor %}
| {% endfor %}
| {% endif %}
| {% endwith %}
| {% for field in form %}
| {% if field.name == 'csrf_token' %}
| {{ field }}
| {% else %}
| {% if field.type == 'HiddenField' %}
| {{ field }}
| {% else %}
| {% if field.name not in hidden_fields %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {% if field.name == 'picture' %}
| {% if post.picture %}
img.node-preview-thumbnail(src="{{ post.picture.thumbnail('m', api=api) }}")
a(href="#", class="file_delete", data-field-name="picture", data-file_id="{{post.picture._id}}") Delete
| {% endif %}
| {% endif %}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% else %}
| {{ field(class='hidden') }}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endfor %}
ul.project-edit-tools.bottom
li.button-cancel
a#item_cancel.project-mode-edit(
href="{{url_for('projects.view', project_url=project.url, _external=True)}}",
title="Cancel changes")
i.button-cancel-icon.pi-back
| Go to Project
li.button-save
a#item_save.project-mode-edit(
href="#",
title="Save changes")
i.button-save-icon.pi-check
| Save Changes
| {% endblock %}
| {% block footer_scripts %}
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.ui.widget.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.iframe-transport.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.fileupload.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/file_upload.min.js') }}")
script(type="text/javascript").
/* UI Stuff */
$(window).on("load resize",function(){
containerResizeY($(window).height());
});
/* Initialize scrollbars */
if ((typeof Ps !== 'undefined') && window.innerWidth > 768){
Ps.initialize(document.getElementById('project_tree'), {suppressScrollX: true});
}
$('.project-mode-edit').show();
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}", isProject: true, nodeId: ''});
var convert = new Markdown.getSanitizingConverter().makeHtml;
$('.button-save').on('click', function(e){
e.preventDefault();
// Disable beforeunolad when submitting a form
$(window).off('beforeunload');
$(this).children('a').html('<i class="pi-spin spin"></i> Saving');
$('#node-edit-form').submit();
});
/* Build the markdown preview when typing in textarea */
$(function() {
var $textarea = $('.form-group.description textarea'),
$loader = $('<div class="md-preview-loading"><i class="pi-spin spin"></i></div>').insertAfter($textarea),
$preview = $('<div class="node-edit-form-md-preview" />').insertAfter($loader);
$loader.hide();
// Delay function to not start converting heavy posts immediately
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$textarea.keyup(function() {
/* If there's an iframe (YouTube embed), delay markdown convert 1.5s */
if (/iframe/i.test($textarea.val())) {
$loader.show();
delay(function(){
// Convert markdown
$preview.html(convert($textarea.val()));
$loader.hide();
}, 1500 );
} else {
// Convert markdown
$preview.html(convert($textarea.val()));
};
}).trigger('keyup');
$('input, textarea').keypress(function () {
// Unused: save status of the page as 'edited'
ProjectUtils.setProjectAttributes({isModified: true});
// Set the beforeunload to warn the user of unsaved changes
$(window).on('beforeunload', function () {
return 'You have unsaved changes in your project.';
});
});
});
| {% endblock %}
| {% block footer_navigation %}
| {% endblock %}
| {% block footer %}
| {% endblock %}

View File

@@ -0,0 +1,88 @@
| {% extends 'layout.html' %}
| {% set title = 'edit_node_types' %}
| {% block page_title %}Project {{ project.name }}{% endblock %}
| {% block body %}
.container.box
form(
method='POST',
action="{{url_for('projects.edit_node_type', project_url=project.url, node_type_name=node_type['name'])}}")
#blog_container.post-create
| {% with errors = errors %}
| {% if errors %}
| {% for field in errors %}
.alert.alert-danger(role='alert')
strong {{field}}
| {% for message in errors[field] %}
| {{message}}|
| {% endfor %}
| {% endfor %}
| {% endif %}
| {% endwith %}
#blog_index-sidebar
.blog_project-sidebar
input.btn.btn-default.button-create(type='submit', value="Update {{ node_type['name'] }}")
a.btn.btn-default.button-back(href="{{ url_for('projects.view', project_url=project.url) }}")
| Back to Project
#blog_post-edit-container
#blog_post-edit-title
| Edit {{ node_type['name'] }}
#blog_post-edit-form
| {% for field in form %}
| {% if field.name == 'csrf_token' %}
| {{ field }}
| {% else %}
| {% if field.type == 'HiddenField' %}
| {{ field }}
| {% else %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% endblock %}
| {% block footer_scripts%}
script(src="https://cdn.jsdelivr.net/g/ace@1.2.3(noconflict/ace.js+noconflict/mode-json.js)")
script.
var dynSchemaEditorContainer = $("<div>", {id: "dyn_schema_editor"});
$(".form-group.dyn_schema").before(dynSchemaEditorContainer);
var dynSchemaEditor = ace.edit("dyn_schema_editor");
dynSchemaEditor.getSession().setValue($("#dyn_schema").val());
var formSchemaEditorContainer = $("<div>", {id: "form_schema_editor"});
$(".form-group.form_schema").before(formSchemaEditorContainer);
var formSchemaEditor = ace.edit("form_schema_editor");
formSchemaEditor.getSession().setValue($("#form_schema").val());
var permissionsEditorContainer = $("<div>", {id: "permissions_editor"});
$(".form-group.permissions").before(permissionsEditorContainer);
var permissionsEditor = ace.edit("permissions_editor");
permissionsEditor.getSession().setValue($("#permissions").val());
$("form").submit(function(e) {
$("#dyn_schema").val(dynSchemaEditor.getSession().getValue());
$("#form_schema").val(formSchemaEditor.getSession().getValue());
$("#permissions").val(permissionsEditor.getSession().getValue());
});
| {% endblock %}

View File

@@ -0,0 +1,110 @@
| {% extends 'layout.html' %}
| {% set title = 'edit_node_types' %}
| {% block page_title %}Node Types: {{ project.name }}{% endblock %}
| {% block body %}
#project-container
#project-side-container
#project_sidebar
ul.project-tabs
li.tabs-thumbnail(
title="About",
data-toggle="tooltip",
data-placement="left",
class="{% if title == 'about' %}active {% endif %}{% if project.picture_square %}image{% endif %}")
a(href="{{url_for('projects.about', project_url=project.url, _external=True)}}")
#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="left")
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
i.pi-tree-flow
| {% if not project.is_private %}
li.tabs-search(
title="Search",
data-toggle="tooltip",
data-placement="left")
a(href="{{url_for('projects.search', project_url=project.url, _external=True)}}")
i.pi-search
| {% endif %}
.project_nav-toggle-btn(
title="Expand Navigation [T]",
data-toggle="tooltip",
data-placement="right")
i.pi-angle-double-left
#project_nav
#project_nav-container
#project_nav-header
.project-title
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| {{ project.name }}
// TODO - make list a macro
#project_tree
ul.project_nav-edit-list
li(class="{% if title == 'edit' %}active{% endif %}")
a(href="{{ url_for('projects.edit', project_url=project.url) }}")
i.pi-list
| Overview
li(class="{% if title == 'sharing' %}active{% endif %}")
a(href="{{ url_for('projects.sharing', project_url=project.url) }}")
i.pi-share
| Sharing
li(class="{% if title == 'edit_node_types' %}active{% endif %}")
a(href="{{ url_for('projects.edit_node_types', project_url=project.url) }}")
i.pi-puzzle
| Node Types
.project_split(title="Toggle Navigation [T]")
#project_context-container
#project_context-header
span#project-statusbar
span#project-edit-title
| Edit Project
#project_context
#node-edit-container
div(id="node-edit-form")
h3 Node Types (coming soon)
p.
Nodes are all the items that can be found in a project.
Everything is a node: a file, a folder, a comment. They are
defined with custom properties and properly presented to you.
When we add support for new node types in the future, it means we
allow the creation of new items (such as textures).
| {% if current_user.has_role('admin') %}
ul
| {% for node_type in project.node_types %}
li
a(href="{{ url_for('projects.edit_node_type', project_url=project.url, node_type_name=node_type.name) }}")
| {{node_type.name}}
| {% endfor %}
| {% endif %}
| {% endblock %}
| {% block footer_scripts %}
script(type="text/javascript").
$(window).on("load resize",function(){
containerResizeY($(window).height());
});
| {% endblock %}
| {% block footer_navigation %}
| {% endblock %}
| {% block footer %}
| {% endblock %}

View File

@@ -0,0 +1,139 @@
| {% extends 'projects/home_layout.html' %}
| {% set subtab = 'images' %}
| {% set learn_more_btn_url = '/blog/introducing-image-sharing' %}
| {% block currenttab %}
section.nav-tabs__tab.active#tab-images
.tab_header-container
| {% if not shared_images %}
.tab_header-intro(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/pattern_01.jpg')}})")
.tab_header-intro_text
h2 Share what you see.
p.
Got a nice render, a Blender oddity, or a cool screenshot?
<br/>
Share it instantly from within Blender to the world!
.tab_header-intro_icons
i.pi-blender
i.pi-heart-filled
i.pi-picture-album
| {% endif %}
| {% if shared_images %}
div#home-images__list
| {% for node in shared_images %}
div.home-images__list-item
.home-images__list-details
a.title(href="{{ url_for_node(node=node) }}?t")
| {{ node.name }}
| {% if node.picture %}
a.home-images__list-thumbnail(
href="{{ url_for_node(node=node) }}?t")
img(src="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
.home-images__list-details
ul.meta
li.when(title="{{ node._created }}") {{ node._created | pretty_date_time }}
li.delete-image
a.delete-prompt(href='javascript:void(0);')
| Delete
span.delete-confirm
| Are you sure?
a.delete-confirm(href='javascript:void(0);',
data-image-id="{{ node._id }}")
i.pi-check
| Yes, delete
a.delete-cancel(href='javascript:void(0);')
i.pi-cancel
| No, cancel
| {% if node.short_link %}
li
a(href="{{ node.short_link }}") {{ node.short_link }}
| {% endif %}
| {% endfor %}
| {% else %}
.blender_sync-main.empty
.blender_sync-main-header
span.blender_sync-main-title
| Share some images using the
a(
href="https://cloud.blender.org/r/downloads/blender_cloud-latest-bundle.zip")
| Blender Cloud add-on.
| {% endif %}
| {% endblock %}
| {% block side_announcement %}
.title
a(href="https://cloud.blender.org/blog/introducing-image-sharing") Image Sharing
.lead
p.
Share your renders, painted textures, and other images, straight from Blender
to the cloud.
hr
| {% if show_addon_download_buttons %}
p.
Image Sharing requires a Blender Cloud subscription, which you have!
| {% else %}
p.
Image Sharing requires a Blender Cloud subscription.
.buttons
a.btn.btn-default.btn-outline.green(href="https://store.blender.org/product/membership/")
| Join Now
| {% endif %}
| {% endblock %}
| {% block footer_scripts %}
| {{ super() }}
script.
var urlNodeDelete = "{{url_for('projects.delete_node')}}";
$(document).ready(function() {
// 'Delete' link on images
var $home_image_list = $('#home-images__list');
$home_image_list.find('a.delete-prompt').on('click', function(e){
$(this)
.hide()
.next().show();
});
// 'Cancel delete' link on images
$home_image_list.find('a.delete-cancel').on('click', function(e){
$(this).parent()
.hide()
.prev().show();
});
// 'Confirm delete' link on images
$home_image_list.find('a.delete-confirm').on('click', function (e) {
var image_id = this.dataset.imageId;
var $this = $(this);
var parent = $this.closest('.home-images__list-item');
console.log('My parent is', parent);
var error_elt = $this.parent();
$.ajax({
type: 'POST',
url: urlNodeDelete,
data: {node_id: image_id},
success: function () {
if (parent.siblings().length == 0) {
// This was the last shared image. Reload the page,
// so that we can show the correct "no images shared"
// content with Jinja2.
window.location = window.location;
}
parent.hide('slow', function() { parent.remove(); });
},
error: function (jqxhr, textStatus, errorThrown) {
error_elt.text('Unable to delete image; ' + textStatus + ': ' + errorThrown);
}
});
});
hopToTop(); // Display jump to top button
});
| {% endblock %}

View File

@@ -0,0 +1,43 @@
| {% extends 'projects/home_layout.html' %}
| {% set subtab = 'blender_sync' %}
| {% set learn_more_btn_url = '/blog/introducing-blender-sync' %}
| {% block currenttab %}
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 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.
.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
h2.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,79 @@
| {% extends 'layout.html' %}
| {% from '_macros/_navigation.html' import navigation_tabs %}
| {% set title = 'home' %}
| {% block og %}
meta(property="og:title", content="Blender Cloud - Home")
meta(property="og:url", content="https://cloud.blender.org{{ request.path }}")
meta(property="og:type", content="website")
| {% endblock %}
| {% block tw %}
meta(name="twitter:card", content="summary_large_image")
meta(name="twitter:site", content="@Blender_Cloud")
meta(name="twitter:title", content="Blender Cloud")
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 body %}
.dashboard-container
section#main
| {{ navigation_tabs(title) }}
section#projects
section#sub-nav-tabs.home
ul#sub-nav-tabs__list
li.nav-tabs__list-tab#subtab-blender_sync(data-tab-url='.')
i.pi-blender
| Blender Sync
li.nav-tabs__list-tab#subtab-images(data-tab-url='images')
i.pi-picture
| Images
| {% block currenttab %}{% endblock %}
section#side
section#announcement
img.header(
src="{{ url_for('static', filename='assets/img/blender_sync_header.jpg') }}")
.text
| {% block side_announcement %}
.title
a(href="https://cloud.blender.org/blog/introducing-blender-sync") Blender Sync
.lead
span.
Save your settings once. Use them anywhere.
Carry your Blender configuration with you, use our free add-on to sync your keymaps and preferences.
<hr/>
Syncing is free for everyone. No subscription required.
| {% endblock %}
| {% if show_addon_download_buttons %}
.buttons
a.btn.btn-default.btn-outline.orange(
href="https://cloud.blender.org/r/downloads/blender_cloud-latest-bundle.zip")
i.pi-download
| Download <small>v</small>{{ config.BLENDER_CLOUD_ADDON_VERSION }}
a.btn.btn-default.btn-outline.blue(
href="{{ learn_more_btn_url }}")
| Learn More
| {% endif %}
| {% endblock %}
| {% block footer_scripts %}
script.
$(document).ready(function () {
$('#subtab-{{ subtab }}').addClass('active');
var $nav_tabs = $('#sub-nav-tabs__list').find('li.nav-tabs__list-tab');
$nav_tabs.on('click', function (e) {
window.location = $(this).attr('data-tab-url');
});
});
| {% endblock %}

View File

@@ -0,0 +1,87 @@
| {% extends 'layout.html' %}
| {% block og %}
meta(property="og:title", content="{% if title == 'open-projects' %}Open Projects{% elif title == 'training' %}Training{% endif %}")
// XXX - Replace with actual url
meta(property="og:url", content="https://cloud.blender.org")
meta(property="og:type", content="website")
| {% endblock %}
| {% block tw %}
meta(name="twitter:card", content="summary_large_image")
meta(name="twitter:site", content="@Blender_Cloud")
meta(name="twitter:title", content="{% if title == 'open-projects' %}Open Projects{% elif title == 'training' %}Training{% endif %} on Blender Cloud")
meta(name="twitter:description", content="{% if title == 'open-projects' %}Full production data and tutorials from all open movies, for you to use freely{% elif title == 'training' %}Production quality training by 3D professionals{% endif %}")
meta(name="twitter:image", content="{% if title == 'training' %}{{ url_for('static', filename='assets/img/backgrounds/background_caminandes_3_03.jpg')}}{% else %}{{ url_for('static', filename='assets/img/backgrounds/background_agent327_01.jpg')}}{% endif %}")
| {% endblock %}
| {% block page_title %}
| {% if title == 'open-projects' %}Open Projects{% elif title == 'training' %}Training{% else %}Projects{% endif %}
| {% endblock %}
| {% block body %}
#project-container
#node_index-container
#node_index-header.collection
img.background-header(src="{% if title == 'training' %}{{ url_for('static', filename='assets/img/backgrounds/background_caminandes_3_03.jpg')}}{% else %}{{ url_for('static', filename='assets/img/backgrounds/background_agent327_01.jpg')}}{% endif %}")
#node_index-collection-info
| {% if title == 'open-projects' %}
.node_index-collection-name
span Open Projects
.node_index-collection-description
span.
The iconic Blender Institute Open Movies.
Featuring all the production files, assets, artwork, and never-seen-before content.
| {% elif title == 'training' %}
.node_index-collection-name
span Training
.node_index-collection-description
span.
Character modeling, 3D printing, VFX, rigging and more.
| {% endif %}
.node_index-collection
| {% for project in projects %}
| {% if (project.status == 'published') or (project.status == 'pending' and current_user.is_authenticated) and project._id != config.MAIN_PROJECT_ID %}
.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('m', 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}}
| {% endif %}
a.learn-more LEARN MORE
| {% endif %}
| {% endfor %}
| {% endblock %}
| {% block footer_scripts %}
script.
$('.node_index-collection-card.project').on('click', function(e){
e.preventDefault();
window.location.href = $(this).data('url');
});
| {% endblock %}

View File

@@ -0,0 +1,232 @@
| {% extends 'layout.html' %}
| {% from '_macros/_navigation.html' import navigation_tabs %}
| {% set title = 'dashboard' %}
| {% block og %}
meta(property="og:title", content="Dashboard")
meta(property="og:url", content="https://cloud.blender.org/{{ request.path }}")
meta(property="og:type", content="website")
| {% endblock %}
| {% block tw %}
meta(name="twitter:card", content="summary_large_image")
meta(name="twitter:site", content="@Blender_Cloud")
meta(name="twitter:title", content="Blender Cloud")
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 body %}
.dashboard-container
section#main
| {{ navigation_tabs(title) }}
section#projects
section#sub-nav-tabs.projects
ul#sub-nav-tabs__list
li.nav-tabs__list-tab.active(data-tab-toggle='own_projects')
| Own Projects
| {% if projects_user|length != 0 %}
span ({{ projects_user|length }})
| {% endif %}
li.nav-tabs__list-tab(data-tab-toggle='shared')
| Shared with me
| {% if projects_shared|length != 0 %}
span ({{ projects_shared|length }})
| {% endif %}
| {% if (current_user.has_role('subscriber') or current_user.has_role('admin')) %}
li.create(
data-url="{{ url_for('projects.create') }}")
a#project-create(
href="{{ url_for('projects.create') }}")
i.pi-plus
| Create Project
| {% endif %}
section.nav-tabs__tab.active#own_projects
ul.projects__list
| {% if projects_user %}
| {% 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.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.is_authenticated and current_user.has_role('admin') %}
li.pending Not Published
| {% endif %}
| {% endfor %}
| {% else %}
li.projects__list-item
a.projects__list-thumbnail
i.pi-plus
.projects__list-details
a.title(href="{{ url_for('projects.create') }}")
| Create a project to get started!
| {% endif %}
section.nav-tabs__tab#shared
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.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.is_authenticated and current_user.has_role('admin') %}
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
.projects__list-details
.title
| No projects shared with you... yet!
| {% endif %}
section#side
section#announcement
img.header(
src="{{ url_for('static', filename='assets/img/backgrounds/services_projects.jpg')}}")
.text
.title Projects
.lead
span.
Create and manage your own personal projects.
Upload assets and collaborate with other Blender Cloud members.
.buttons
a.btn.btn-default.btn-outline.blue(
href="https://cloud.blender.org/blog/introducing-private-projects")
| Learn More
| {% 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('li.nav-tabs__list-tab');
$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();
});
// Create project
$nav_tabs_list.find('li.create').on('click', function(e){
e.preventDefault();
$(this).addClass('disabled');
$('a', this).html('<i class="pi-spin spin"></i> Creating project...');
window.location.href = $(this).data('url');
});
// 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
});
| {% endblock %}

View File

@@ -0,0 +1,266 @@
| {% extends 'layout.html' %}
| {% set title = 'sharing' %}
| {% block page_title %}Sharing: {{ project.name }}{% endblock %}
| {% block body %}
#project-container
#project-side-container
#project_sidebar
ul.project-tabs
li.tabs-thumbnail(
title="About",
data-toggle="tooltip",
data-placement="left",
class="{% if title == 'about' %}active {% endif %}{% if project.picture_square %}image{% endif %}")
a(href="{{url_for('projects.about', project_url=project.url, _external=True)}}")
#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="left")
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
i.pi-tree-flow
| {% if not project.is_private %}
li.tabs-search(
title="Search",
data-toggle="tooltip",
data-placement="left")
a(href="{{url_for('projects.search', project_url=project.url, _external=True)}}")
i.pi-search
| {% endif %}
.project_nav-toggle-btn(
title="Expand Navigation [T]",
data-toggle="tooltip",
data-placement="right")
i.pi-angle-double-left
#project_nav
#project_nav-container
#project_nav-header
.project-title
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| {{ project.name }}
// TODO - make list a macro
#project_tree
ul.project_nav-edit-list
li(class="{% if title == 'edit' %}active{% endif %}")
a(href="{{ url_for('projects.edit', project_url=project.url) }}")
i.pi-list
| Overview
li(class="{% if title == 'sharing' %}active{% endif %}")
a(href="{{ url_for('projects.sharing', project_url=project.url) }}")
i.pi-share
| Sharing
li(class="{% if title == 'edit_node_types' %}active{% endif %}")
a(href="{{ url_for('projects.edit_node_types', project_url=project.url) }}")
i.pi-puzzle
| Node Types
.project_split(title="Toggle Navigation [T]")
#project_context-container
#project_context-header
span#project-statusbar
span#project-edit-title
| Manage users for this project
#project_context
#node-edit-container
#node-edit-form
.col-md-6
| {% if (project.user == current_user.objectid or current_user.has_role('admin')) %}
.sharing-users-search
.form-group
input#user-select.form-control(
name='contacts',
type='text',
placeholder='Add users by name')
| {% else %}
.sharing-users-search
.disabled Only project owners can manage users
| {% endif %}
ul.sharing-users-list
| {% for user in users %}
li.sharing-users-item(
user-id="{{ user['_id'] }}",
class="{% if current_user.objectid == user['_id'] %}self{% endif %}")
.sharing-users-avatar
img(src="{{ user['avatar'] }}")
.sharing-users-details
span.sharing-users-name
| {{user['full_name']}}
| {% if project.user == user['_id'] and current_user.objectid == user['_id'] %}
small (You, owner)
| {% elif project.user == user['_id'] %}
small (Owner)
| {% elif current_user.objectid == user['_id'] %}
small (You)
| {% endif %}
span.sharing-users-extra {{user['username']}}
.sharing-users-action
| {# Only allow deletion if we are: admin, project owners, or current_user in the team #}
| {% if current_user.has_role('admin') or (project.user == current_user.objectid) or (current_user.objectid == user['_id']) %}
| {% if project.user == user['_id'] %}
span
i.pi-happy(title="Hi boss!")
| {% elif current_user.objectid == user['_id'] %}
button.user-remove(title="Leave this project") Leave
| {% else %}
button.user-remove(title="Remove this user from your project")
i.pi-trash
| {% endif %}
| {% endif %}
| {% endfor %}
.col-md-6
.sharing-users-info
h4 What can team members do?
p.
Team members are able to upload new content to the
project; as well as view, edit, and comment on the content previously created.
| {% endblock %}
| {% block footer_navigation %}
| {% endblock %}
| {% block footer_scripts %}
script(type="text/javascript").
$(window).on("load resize",function(){
containerResizeY($(window).height());
});
| {% if (project.user == current_user.objectid or current_user.has_role('admin')) %}
script(src='//cdn.jsdelivr.net/autocomplete.js/0/autocomplete.jquery.min.js')
script.
$(document).ready(function() {
var APPLICATION_ID = '{{config.ALGOLIA_USER}}'
var SEARCH_ONLY_API_KEY = '{{config.ALGOLIA_PUBLIC_KEY}}';
var INDEX_NAME = '{{config.ALGOLIA_INDEX_USERS}}';
var client = algoliasearch(APPLICATION_ID, SEARCH_ONLY_API_KEY);
var index = client.initIndex(INDEX_NAME);
$('#user-select').autocomplete({hint: false}, [
{
source: function (q, cb) {
index.search(q, {hitsPerPage: 5}, function (error, content) {
if (error) {
cb([]);
return;
}
cb(content.hits, content);
});
},
displayKey: 'full_name',
minLength: 2,
limit: 10,
templates: {
suggestion: function (hit) {
return hit._highlightResult.full_name.value + ' (' + hit._highlightResult.username.value + ')';
}
}
}
]).on('autocomplete:selected', function (event, hit, dataset) {
var lis = document.getElementsByClassName('sharing-users-item');
var has_match = false;
for (var i = 0; i < lis.length; ++i) {
// Check if the user already is in the list
if ($(lis[i]).attr('user-id') == hit.objectID){
$(lis[i]).addClass('active');
setTimeout(function(){ $('.sharing-users-item').removeClass('active');}, 350);
statusBarSet('info', 'User is already part of the project', 'pi-info');
has_match = false;
break;
} else {
has_match = true;
continue;
}
};
if (has_match){
addUser(hit.objectID);
}
});
function addUser(userId){
if (userId && userId.length > 0) {
$.post("{{url_for('projects.sharing', project_url=project.url)}}",
{user_id: userId, action: 'add'})
.done(function (data) {
$("ul.sharing-users-list").prepend('' +
'<li class="sharing-users-item" user-id="' + data._id + '">' +
'<div class="sharing-users-avatar">' +
'<img src="' + data.avatar + '">'+
'</div>' +
'<div class="sharing-users-details">' +
'<span class="sharing-users-name">' + data.full_name + '</span>' +
'<span class="sharing-users-extra">' + data.username + '</span>' +
'</div>' +
'<div class="sharing-users-action">' +
'<button title="Remove this user from your project" class="user-remove">'+
'<i class="pi-trash"></i>'+
'</button>'+
'</div>'+
'</li>');
$("ul.sharing-users-list").find("[user-id='" + userId + "']").addClass('added');
setTimeout(function(){ $('.sharing-users-item').removeClass('added');}, 350);
statusBarSet('success', 'User added to this project!', 'pi-grin');
})
.fail(function (jsxhr){
data = jsxhr.responseJSON;
statusBarSet('error', 'Could not add user (' + data.message + ')', 'pi-warning');
});
} else {
statusBarSet('error', 'Please select a user from the list', 'pi-warning');
}
};
});
| {% endif %}
script.
$(document).ready(function() {
$('body').on('click', '.user-remove', function(e) {
var userId = $(this).parent().parent().attr('user-id');
removeUser(userId);
});
function removeUser(userId){
$.post("{{url_for('projects.sharing', project_url=project.url)}}",
{user_id: userId, action: 'remove'})
.done(function (data) {
$("ul.sharing-users-list").find("[user-id='" + userId + "']").remove();
statusBarSet('success', 'User removed from this project', 'pi-trash');
})
.fail(function (data){
statusBarSet('error', 'Could not remove user (' + data._status + ')', 'pi-warning');
});
}
});
| {% endblock %}

View File

@@ -0,0 +1,586 @@
| {% extends 'layout.html' %}
| {% from '_macros/_add_new_menu.html' import add_new_menu %}
| {% block page_title %}{{project.name}}{% endblock%}
| {% block og %}
meta(property="og:type", content="website")
| {% if og_picture %}
meta(property="og:image", content="{{ og_picture.thumbnail('l', api=api) }}")
| {% endif %}
| {% if show_project %}
meta(property="og:title", content="{{project.name}} - Blender Cloud")
meta(property="og:url", content="{{url_for('projects.view', project_url=project.url, _external=True)}}")
meta(property="og:description", content="{{project.summary}}")
| {% else %}
meta(property="og:title", content="{{node.name}} - Blender Cloud")
meta(property="og:url", content="{{url_for('projects.view_node', project_url=project.url, node_id=node._id)}}")
meta(property="og:description", content="{{node.description}}")
| {% endif %}
| {% endblock %}
| {% block tw %}
| {% if og_picture %}
meta(property="twitter:image", content="{{ og_picture.thumbnail('l', api=api) }}")
| {% endif %}
| {% if show_project %}
meta(name="twitter:title", content="{{project.name}} on Blender Cloud")
meta(name="twitter:description", content="{{project.summary}}")
| {% else %}
meta(name="twitter:title", content="{{node.name}} on Blender Cloud")
meta(name="twitter:description", content="{{node.description}}")
| {% endif %}
| {% endblock %}
| {% block head %}
link(href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.1/themes/default/style.min.css", rel="stylesheet")
| {% endblock %}
| {% block css %}
link(href="{{ url_for('static_pillar', filename='assets/css/project-main.css', v=040820161) }}", rel="stylesheet")
| {% endblock %}
| {% block body %}
#project-container
#project-side-container
#project_sidebar
ul.project-tabs
li.tabs-thumbnail(
title="About",
data-toggle="tooltip",
data-placement="left",
class="{% if title == 'about' %}active {% endif %}{% if project.picture_square %}image{% endif %}")
a(href="{{url_for('projects.about', project_url=project.url, _external=True)}}")
#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="left",
class="{% if title != 'about' %}active{% endif %}")
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
i.pi-tree-flow
| {% if not project.is_private %}
li.tabs-search(
title="Search",
data-toggle="tooltip",
data-placement="left")
a(href="{{url_for('projects.search', project_url=project.url, _external=True)}}")
i.pi-search
| {% endif %}
.project_nav-toggle-btn(
title="Expand Navigation [T]",
data-toggle="tooltip",
data-placement="right")
i.pi-angle-double-left
#project_nav(class="{{ title }}")
#project_nav-container
| {% if title != 'about' %}
#project_nav-header
.project-title
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| {{ project.name }}
#project_tree
| {% endif %}
.project_split(title="Toggle Navigation [T]")
#project_context-container
| {% if project.has_method('PUT') %}
#project_context-header
span#project-statusbar
ul.project-edit-tools.disabled
li.button-dropdown
a#item_add.dropdown-toggle.project-mode-view(
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(
href="javascript:void(0);",
title="Edit",
data-project_id="{{project._id}}")
i.button-edit-icon.pi-edit
| Edit Project
li.button-dropdown
a.dropdown-toggle.project-mode-view(
type="button",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false")
i.pi-more-vertical
ul.dropdown-menu
| {% if current_user.has_role('admin') %}
li.button-featured
a#item_featured(
href="javascript:void(0);",
title="Feature on project's homepage",
data-toggle="tooltip",
data-placement="left")
i.button-featured-icon.pi-star
| Toggle Featured
li.button-toggle-public
a#item_toggle_public(
href="javascript:void(0);",
title="Toggle public",
data-toggle="tooltip",
data-placement="left")
i.pi-lock-open
| Toggle public
| {% endif %}
li.button-toggle-projheader
a#item_toggle_projheader(
href="javascript:void(0);",
title="Feature as project's header",
data-toggle="tooltip",
data-placement="left")
i.button-featured-icon.pi-star
| Toggle Project Header video
li.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.button-delete
a#item_delete(
href="javascript:void(0);",
title="Delete",
data-toggle="tooltip",
data-placement="left")
i.pi-trash
| Delete Project
// Edit Mode
li.button-cancel
a#item_cancel.project-mode-edit(
href="javascript:void(0);",
title="Cancel changes")
i.button-cancel-icon.pi-cancel
| Cancel
li.button-save
a#item_save.project-mode-edit(
href="javascript:void(0);",
title="Save changes")
i.button-save-icon.pi-check
| Save Changes
| {% endif %}
#project_context
| {% if show_project %}
| {% include "projects/view_embed.html" %}
| {% endif %}
#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_navigation %}{% endblock %}
| {% block footer %}{% endblock %}
| {% block footer_scripts %}
script(src="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.1/jstree.min.js")
script(src="//releases.flowplayer.org/6.0.5/flowplayer.min.js")
| {% 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', v=190520161) }}")
| {% endif %}
script.
{% if show_project %}
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}", isProject: true, nodeId: ''});
{% else %}
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}", isProject: false, nodeId: '{{node._id}}'});
{% endif %}
var projectTree = document.getElementById('project_tree');
/* Initialize project_tree scrollbar */
if ((typeof Ps !== 'undefined') && projectTree && window.innerWidth > 768){
Ps.initialize(projectTree, {suppressScrollX: true});
}
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 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').show();
$('.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').show();
} 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();
var nodeTitle = document.getElementById('node-title');
var nodeTitleText = $(nodeTitle).text() + " - {{project.name}} - Blender Cloud";
document.title = nodeTitleText;
// 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');
}
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').show();
$('.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-file-archive", "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-film-thick", "max_children": 0},
"blog" : {"icon": "pi-newspaper", "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.type == 'blog') {
window.location.replace('blog');
} 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);
}
/* Update scrollbar */
Ps.update(projectTree);
});
$(projectTree).on("open_node.jstree", function () {
/* Update scrollbar */
Ps.update(projectTree);
});
$(projectTree).on("close_node.jstree", function () {
/* Update scrollbar */
Ps.update(projectTree);
});
};
// Initialize the page
loadContent();
/* UI Stuff */
$(window).on("load resize",function(){
containerResizeY($(window).height());
});
if (projectTree){
$(projectTree).hover(function(){
Ps.update(projectTree);
});
}
| {% endblock %}
| {% block comment_scripts %} {% endblock%}

View File

@@ -0,0 +1,188 @@
| {% block head %}
| {% if header_video_file %}
script(src="//releases.flowplayer.org/6.0.5/flowplayer.min.js")
script.
$(function() {
$('#flowplayer_container').flowplayer({
key: "{{config.FLOWPLAYER_KEY}}",
embed: false,
splash: true,
clip: { sources: [
{% for var in header_video_file.variations %}
{type: "{{ var.content_type }}", src: "{{ var.link|safe }}"},
{% endfor %}
]}
});
});
| {% endif %}
| {% endblock %}
| {% block body %}
#node-container
section.node-preview.project
| {% if project.url == 'caminandes-3' %}
iframe(
style="height: 490px",
src="https://www.youtube.com/embed/SkVqJ1SGeL0?rel=0&amp;controls=0&amp;showinfo=0",
frameborder="0",
allowfullscreen)
| {% elif header_video_file %}
#flowplayer_container.is-splash.play-button(
style="{% if header_video_node.picture %}background-image:url({{header_video_node.picture.thumbnail('l', api=api)}}); background-repeat:no-repeat; {% endif %}")
.fp-startscreen.fp-toggle
a.big-play-button
i.pi-play
.fp-endscreen
a.watch-again.fp-toggle
i.pi-replay
| Watch again
.fp-waiting
i.pi-spin.spin
| {% elif project.picture_header %}
a(href="{{ url_for( 'projects.about', project_url=project.url) }}")
img.header(src="{{ project.picture_header.thumbnail('l', api=api) }}")
| {% endif %}
section.node-details-container.project
| {# Hide for now
.node-details-header
.node-title-details
.date(title="Last updated {{ project._updated | pretty_date }}") {{ project._created | pretty_date }}
| {% if project.status %}
.status {{project.status}}
| {% endif %}
| #}
.node-details-title
h1
a(href="{{ url_for( 'projects.about', project_url=project.url) }}") {{ project.name }}
| {% if title != 'about' or not project.description %}
| {% set description = project.summary %}
| {% else %}
| {% set description = project.description %}
| {% endif %}
.node-details-description
| {{ description }}
| {% if title != 'about' %}
.node-extra
a.learn-more(href="{{ url_for( 'projects.about', project_url=project.url) }}") LEARN MORE
| {% endif %}
| {% if project.nodes_featured %}
.project-featured-container
h3 Featured Content
.featured-list#featured-list
| {% for n in project.nodes_featured %}
| {% if n.picture %}
a.featured-item.hidden(href="{{ url_for_node(node=n) }}")
.featured-item-info
span.type {{ n.properties.content_type }} - {{ n.user.full_name }}
span.title {{ n.name }}
img(src="{{ n.picture.thumbnail('l', api=api) }}")
| {% endif %}
| {% endfor %}
| {% endif %}
.node-extra
| {% if project.nodes_blog %}
.node-blog
h3 Blog
ul.node-blog-list
| {% for n in project.nodes_blog %}
li.node-blog-list-item(data-node_id="{{ n._id }}")
a.image(href="{{ url_for_node(node=n) }}")
| {% if n.picture %}
img(src="{{ n.picture.thumbnail('s', api=api) }}")
| {% else %}
i.pi-chatbubble-working
| {% endif %}
.info
a.title(href="{{ url_for_node(node=n) }}") {{ n.name }}
span.details
span.when {{ n._updated | pretty_date }} by
span.who {{ n.user.full_name }}
| {% endfor %}
| {% endif %}
| {% if project.nodes_latest %}
.node-updates
h3 Latest Updates
ul.node-updates-list
| {% for n in project.nodes_latest %}
| {% if n.node_type not in ['comment'] %}
li.node-updates-list-item(data-node_id="{{ n._id }}")
a.image(href="{{ url_for_node(node=n) }}")
| {% if n.picture %}
img(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 %}
.info
a.title(href="{{ url_for_node(node=n) }}") {{ n.name }}
span.details
span.what {% if n.properties.content_type %}{{ n.properties.content_type }}{% else %}folder{% endif %} ·
span.when {{ n._updated | pretty_date }} by
span.who {{ n.user.full_name }}
| {% endif %}
| {% endfor %}
| {% endif %}
include _scripts
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.montage.min.js') }}")
script.
function montage(){
var $container = $('#featured-list'),
$imgs = $container.find('img').hide(),
totalImgs = $imgs.length,
cnt = 0;
$imgs.each(function(i) {
var $img = $(this);
$('<img/>').load(function() {
++cnt;
if( cnt === totalImgs ) {
$imgs.show();
$container.montage({
fillLastRow : true,
alternateHeight : true,
alternateHeightRange : {
min : 180,
max : 240
},
margin : 3
});
}
}).attr('src',$img.attr('src'));
$img.parent().removeClass('hidden');
});
}
$(function() {
montage();
$(".node-updates-list-item, .node-blog-list-item")
.unbind('click')
.click(function(e) {
e.preventDefault();
displayNode($(this).data('node_id'));
});
});
| {% endblock %}

View File

@@ -0,0 +1,57 @@
| {% extends 'layout.html' %}
| {% set title = 'theatre' %}
| {% block og %}
meta(property="og:title", content="{{ node.name }}")
meta(property="og:url", content="{{ url_for('projects.view_node', project_url=project.url, node_id=node._id, t=1, _external=True) }}")
meta(property="og:type", content="website")
meta(property="og:description", content="Created on {{ node._created.strftime('%d %b %Y') }}")
| {% if og_picture %}
meta(property="og:image", content="{{ og_picture.thumbnail('l', api=api) }}")
meta(property="og:image:secure_url", content="{{ og_picture.thumbnail('l', api=api) }}")
meta(property="og:image:type", content="{{ og_picture.content_type }}")
meta(property="og:image:witdh", content="{{ og_picture.width }}")
meta(property="og:image:height", content="{{ og_picture.height }}")
| {% endif %}
| {% endblock %}
| {% block tw %}
| {% if og_picture %}
meta(property="twitter:image", content="{{ og_picture.thumbnail('l', api=api) }}")
| {% endif %}
meta(name="twitter:title", content="{{node.name}}")
meta(name="twitter:description", content="Created on {{ node._created.strftime('%d %b %Y') }}")
| {% endblock %}
| {% block header_backdrop %}{% endblock %}
| {% block navigation_search %}{% endblock %}
| {% block navigation_sections %}
li
a.navbar-item.info(
href="",
title="Toggle info & sidebar")
i.pi-info
| {% endblock %}
| {% block css %}
link(href="{{ url_for('static_pillar', filename='assets/css/theatre.css', v=2016) }}", rel="stylesheet")
| {% endblock %}
| {% block body %}
#theatre-container(class="{% if current_user.is_authenticated %}with-info{% endif %}")
| {% endblock %}
| {% block footer_scripts %}
script.
$(function(){
$.get("{{url_for('nodes.view', node_id=node._id, t=True)}}", function(dataHtml) {
$("#theatre-container").html(dataHtml);
});
});
| {% endblock %}
| {% block footer %}{% endblock %}
| {% block footer_navigation %}{% endblock %}

218
src/templates/services.jade Normal file
View File

@@ -0,0 +1,218 @@
| {% extends 'layout.html' %}
| {% block page_title %}Services{% endblock %}
| {% set title = 'services' %}
| {% block og %}
meta(property="og:title", content="Services - Blender Cloud")
meta(property="og:url", content="https://cloud.blender.org/services")
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_services.jpg')}}")
| {% endblock %}
| {% block header_backdrop %}
.navbar-backdrop(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/services_projects.jpg')}})")
.navbar-backdrop-overlay.services
| {% endblock %}
| {% block page_overlay %}
#page-overlay.video
.video-embed
| {% endblock %}
| {% block body %}
#page-container
#page-header
.page-title(style="text-align: left")
i.pi-blender-cloud-logo
em SERVICES
.page-title-summary
| Personal Projects · Blender Integration · Texture Browsing · Production Management
#page-content
section.page-card
.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.
a.page-card-cta(
href="https://cloud.blender.org/blog/introducing-private-projects")
| Learn More
.page-card-side
.page-card-icon
svg(xmlns='http://www.w3.org/2000/svg', width='56', height='64', viewbox='0 0 56 64')
g(fill='#555')
path(d='M42 38H14V26h28v12zm-26-2h24v-8H16v8zm-4-5H8c-1.654 0-3-1.346-3-3V15h2v13c0 .55.45 1 1 1h4v2z')
path(d='M9.293 19.707L6 16.414l-3.293 3.293-1.414-1.414 4-4c.39-.39 1.023-.39 1.414 0l4 4-1.414 1.414zM48 31h-4v-2h4c.55 0 1-.45 1-1V15h2v13c0 1.654-1.346 3-3 3z')
path(d='M53.293 19.707L50 16.414l-3.293 3.293-1.414-1.414L50 13.586l4.707 4.707M27 15h2v9h-2z')
path(d='M31.293 19.707L28 16.414l-3.293 3.293-1.414-1.414L28 13.586l4.707 4.707M7 49H5V36c0-1.654 1.346-3 3-3h4v2H8c-.55 0-1 .45-1 1v13z')
path(d='M6 50c-.256 0-.512-.098-.707-.293l-4-4 1.414-1.414L6 47.586l3.293-3.293 1.414 1.414-4 4c-.195.195-.45.293-.707.293zm45-1h-2V36c0-.55-.45-1-1-1h-4v-2h4c1.654 0 3 1.346 3 3v13z')
path(d='M50 50.414l-4.707-4.707 1.414-1.414L50 47.586l3.293-3.293 1.414 1.414M27 40h2v9h-2z')
path(d='M28 50.414l-4.707-4.707 1.414-1.414L28 47.586l3.293-3.293 1.414 1.414M6 12c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zM6 2C3.794 2 2 3.794 2 6s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zm22 10c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zm22 10c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zM6 64c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zm22 10c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zm22 10c-3.31 0-6-2.692-6-6s2.69-6 6-6 6 2.692 6 6-2.69 6-6 6zm0-10c-2.206 0-4 1.794-4 4s1.794 4 4 4 4-1.794 4-4-1.794-4-4-4zM27 31h2v2h-2zm-4 0h2v2h-2zm8 0h2v2h-2z')
#blender-addon.page-section-container(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/pattern_bw_01.jpg')}})")
section.page-card-header.dark Blender Cloud Add-on
span.page-card-header_lead.dark Connect Blender with the Cloud
a.page-card-cta.download(
href="https://cloud.blender.org/r/downloads/blender_cloud-latest-bundle.zip")
i.pi-download
| Download <small>v</small>1.3
section.page-card.dark.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 free add-on to sync your keymaps and preferences.
<hr/>
<small>Syncing settings is free for everyone! No subscription required.</small>
a.page-card-cta(
href="https://cloud.blender.org/blog/introducing-blender-sync")
| Learn More
.page-card-side
.page-card-icon
svg(xmlns="http://www.w3.org/2000/svg",
width="64", height="54", viewBox="0 0 64 54")
g(fill="none", stroke="#aaa", stroke-width="2", stroke-miterlimit="10")
path(d="M29 47H5l-4-4v-2h24l2 2h2M29 3H10C8.344 3 7 4.343 7 6v32M35 51h24l4-4v-2H39l-2 2h-2M35 7h19c1.656 0 3 1.343 3 3v32M32 34v20M32 20v8M32 0v14")
g
path(d="M32 31c-3.866 0-7-3.134-7-7M32 17c3.866 0 7 3.134 7 7M32 31h8M24 17h8M36 35l4-4-4-4M28 21l-4-4 4-4")
path(d="M29 37H11V7h18M35 11h18v30H35")
section.page-card.dark
.page-card-side
h2.page-card-title Texture 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!
a.page-card-cta.watch-video(
href="https://www.youtube.com/watch?v=-srXYv2Osjw",
data-youtube-id="-srXYv2Osjw")
i.pi-play
| Watch Video
.page-card-side
.page-card-icon
svg(xmlns="http://www.w3.org/2000/svg",
width="64", height="60",
viewBox="0 0 64 60")
g(fill="#aaa")
path(d="M32 60c-.188 0-.377-.053-.542-.16l-31-20C.173 39.656 0 39.34 0 39s.173-.656.458-.84l31-20c.33-.213.754-.213 1.084 0l31 20c.285.184.458.5.458.84s-.173.656-.458.84l-31 20c-.165.107-.354.16-.542.16zM2.845 39L32 57.81 61.155 39 32 20.19 2.845 39z")
path(d="M32 51c-.188 0-.377-.053-.542-.16l-31-20C.173 30.656 0 30.34 0 30s.173-.656.458-.84l31-20c.33-.213.754-.213 1.084 0l31 20c.285.184.458.5.458.84s-.173.656-.458.84l-31 20c-.165.107-.354.16-.542.16zM2.845 30L32 48.81 61.155 30 32 11.19 2.845 30z")
path(d="M32 42c-.188 0-.377-.053-.542-.16l-31-20C.173 21.656 0 21.34 0 21s.173-.656.458-.84l31-20c.33-.213.754-.213 1.084 0l31 20c.285.184.458.5.458.84s-.173.656-.458.84l-31 20c-.165.107-.354.16-.542.16zM2.845 21L32 39.81 61.155 21 32 2.19 2.845 21z")
path(d="M31 27h2v2h-2zm0-4h2v2h-2zm0 8h2v2h-2zm4-4h2v2h-2zm4 2h2v2h-2zm-16 0h2v2h-2zm12 2h2v2h-2zm-8-4h2v2h-2zm0 4h2v2h-2zm4 4h2v2h-2zm31 15h2v2h-2zm0-4h2v2h-2zm0 8h2v2h-2zm0 4h2v2h-2zm0-54h2v2h-2zm0-4h2v2h-2zm0 8h2v2h-2zm0 4h2v2h-2zM0 50h2v2H0zm0-4h2v2H0zm0 8h2v2H0zm0 4h2v2H0zM0 4h2v2H0zm0-4h2v2H0zm4 0h2v2H4zm4 0h2v2H8zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm22 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zM4 58h2v2H4zm4 0h2v2H8zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm22 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zM0 8h2v2H0zm0 4h2v2H0z")
section.page-card.dark.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!
a.page-card-cta(
href="https://cloud.blender.org/blog/introducing-image-sharing")
| Learn More
.page-card-side
.page-card-icon
svg(xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64")
g(fill="none",
stroke="#aaa",
stroke-width="2",
stroke-linejoin="round",
stroke-miterlimit="10")
path(d="M1 1h62v62H1zM4 59h2M8 59h2M12 59h2M60 49H48M46 49H27M60 53H40")
path(d="M5 5h54v40H5z")
path(d="M9 45v-3c0-1.656 1.344-3 3-3h6c1.656 0 3 1.344 3 3v3M29 45v-3c0-1.656 1.344-3 3-3h6c1.656 0 3 1.344 3 3v3M13 45v-3M17 45v-3M33 45v-3M37 45v-3M22 31h-5c-2.762 0-5 2.238-5 5v3M38 39v-3c0-2.762-2.238-5-5-5h-5M31 20c0 3.313-1 9-6 9s-6-5.687-6-9c0-1 0-5 6-5s6 4 6 5z")
path(d="M29 27l-2 8h-4l-2-8M18 31c-4-3-5-9-5-9l6-3M32 31c4-3 5-9 5-9l-6-3M59 24L44 9l-8 8M44 9l8 36")
circle(cx="12", cy="12", r="3")
section.page-card.services-attract
.page-card-side
h2.page-card-title
| Attract
small (soon)
.page-card-summary.
Production-management software for your film, game, or commercial projects.
.page-card-side
.page-card-icon
svg(xmlns='http://www.w3.org/2000/svg', width='56', height='64', viewbox='0 0 56 64')
path(fill='#aaa', d='M16 32C7.178 32 0 24.822 0 16S7.178 0 16 0s16 7.178 16 16-7.178 16-16 16zm0-30C8.28 2 2 8.28 2 16s6.28 14 14 14 14-6.28 14-14S23.72 2 16 2z')
path(fill='#aaa', d='M16 56c-2.757 0-5-2.243-5-5V31h2v20c0 1.654 1.346 3 3 3s3-1.346 3-3V31h2v20c0 2.757-2.243 5-5 5z')
path(fill='#aaa', d='M15 40h2v2h-2zM15 44h2v2h-2zM15 48h2v2h-2zM46.414 64H15v-6h2v4h28.586L54 53.586V8H32V6h24v48.414')
path(fill='#aaa', d='M47 63h-2V53h10v2h-8M24 24H8V8h12v2H10v12h12v-6h2')
path(fill='#aaa', d='M16 19.414l-3.707-3.707 1.414-1.414L16 16.586l6.293-6.293 1.414 1.414M29 39h-6v-6h6v6zm-4-2h2v-2h-2v2zM29 47h-6v-6h6v6zm-4-2h2v-2h-2v2zM29 55h-6v-6h6v6zm-4-2h2v-2h-2v2zM31 33h19v2H31zM31 37h19v2H31zM31 41h19v2H31zM31 45h19v2H31zM31 53h10v2H31zM31 49h19v2H31z')
g
path(fill='#aaa', d='M50 29H31v-2h17v-8H34v-2h16')
g
path(fill='#aaa', d='M48 13h2v2h-2z')
g
path(fill='#aaa', d='M44 13h2v2h-2z')
g
path(fill='#aaa', d='M40 13h2v2h-2z')
| {% if not current_user.has_role('subscriber') %}
section.page-card.subscribe(
style="background-image: url({{ url_for('static', filename='assets/img/backgrounds/background_services.jpg')}});background-size: cover")
.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 %}
| {% endblock %}
| {% block footer_scripts %}
script.
// Click anywhere in the page to hide the overlay
function hideOverlay() {
$('#page-overlay.video').removeClass('active');
$('#page-overlay.video .video-embed').html('');
}
$(document).click(function() {
hideOverlay();
});
$(document).keyup(function(e) {
if (e.keyCode == 27) {
hideOverlay();
}
});
$('a.watch-video').click(function(e){
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>')
});
| {% endblock %}

120
src/templates/stats.jade Normal file
View File

@@ -0,0 +1,120 @@
| {% extends 'layout.html' %}
| {% block page_title %}Stats{% endblock %}
| {% block body %}
.container
#stats-container.page-content
.row
.col-md-6
.box
span.stats__graph-title.income
span.stats__graph-title-amount
small &dollar;
| 20307
span.stats__graph-title-label Monthly Income
#site-stats.stats__graph
.col-md-6
.box
span.stats__graph-title subscribers
span.stats__graph-title-amount 1807
span.stats__graph-title-label Active Subscribers
#site-stats2.stats__graph
hr
.row
.col-md-12
.box
.row
.col-md-6.text-left
p.
The Blender Cloud is our Open Production platform - a hub for creating and sharing open content and training online. The Blender Institute projects - developers and artists who work on compelling technical creative targets - are made possible thanks to the support of subscribers to the Cloud.
p.
We created this page to share with you the numbers that make the Cloud.
p.
Thank you very much for your support.
<br/>
The Blender Institute team
.col-md-6 stats__join
a(href="https://cloud.blender.org/join")
h3.
Get a subscription
h3.
Now only &dollar;10 per month
.btn.btn-default
| Join the Cloud
hr
.row.stats__data
.col-md-12
.row
.col-md-3 stats__data-type_money
.box
h2.
<small>&dollar;</small> 20307
h3.
<small>Monthly Income</small>
i.fa.fa-money backicon
</div>
</div>
.col-md-2 stats__data-type_money
.box
i.fa.fa-users backicon
h2.
1807
h3.
<small>Active Subscribers</small>
</div>
</div>
.col-md-2 stats__data-type_quantity
.box
i.fa.fa-film backicon
h2.
245
h3.
<small>Hours of Video</small>
</div>
</div>
.col-md-2 stats__data-type_quantity
.box
i.fa.fa-database backicon
h2.
94
h3.
<small>Gigabytes of Data</small>
</div>
</div>
.col-md-3 stats__data-type_quantity
.box
i.fa.fa-cloud-download backicon
h2.
3641
h3.
<small>Downloadable Assets</small>
| {% endblock %}

25
src/templates/upload.jade Normal file
View File

@@ -0,0 +1,25 @@
| {% extends 'layout.html' %}
| {% block head %}
| {{ super() }}
// blueimp Gallery styles
link(rel="stylesheet", href="{{ url_for('static_pillar', filename='assets/css/blueimp/blueimp-gallery.min.css') }}")
// CSS to style the file input field as button and adjust the Bootstrap progress bars
link(rel="stylesheet", href="{{ url_for('static_pillar', filename='jquery-file-upload/css/jquery.fileupload.css') }}")
link(rel="stylesheet", href="{{ url_for('static_pillar', filename='jquery-file-upload/css/jquery.fileupload-ui.css') }}")
| {% endblock %}
| {% block body %}
.container
#project-container(style="background-color:white;padding:20px")
| {% include '_macros/_file_uploader_form.html' %}
| {% endblock %}
| {% block footer_scripts %}
| {% include '_macros/_file_uploader_javascript.html' %}
| {% endblock %}

View File

@@ -0,0 +1,4 @@
#node-add-container
| {% include '_macros/_file_uploader_form.html' %}
| {% include '_macros/_file_uploader_javascript.html' %}

View File

@@ -0,0 +1,78 @@
| {% block body %}
#user-edit-container
#user-edit-header
.user-edit-name {{user.full_name}}
.user-edit-username {{user.username}}
.user-edit-email {{user.email}}
form(
id="user-edit-form",
method="POST",
enctype="multipart/form-data",
action="{{url_for('users.users_edit', user_id=user._id)}}")
| {% for field in form %}
| {% if field.name == 'csrf_token' %}
| {{ field }}
| {% else %}
| {% if field.type == 'HiddenField' %}
| {{ field }}
| {% else %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endfor %}
a#button-cancel.btn.btn-default(href="#", data-user-id='{{user._id}}') Cancel
input#submit_edit_user.btn.btn-default(
data-user-id="{{user._id}}",
type="submit" value="Submit")
#user-edit-notification
script(type="text/javascript").
$('#roles').select2();
$('#user-edit-form').submit(function(e){
e.preventDefault();
//- console.log($(this).serialize());
$.post($(this).attr('action'), $(this).serialize())
.done(function(data){
$('#user-edit-notification').addClass('success').html('Success!');
})
.fail(function(data){
$('#user-edit-notification').addClass('fail').html('Houston!');
});
//- $("#user-edit-form").submit();
});
$('#button-cancel').click(function(e){
$('#user-container').html('')
});
| {% endblock %}

View File

@@ -0,0 +1,120 @@
| {% extends 'layout.html' %}
| {% block page_title %}Users{% endblock %}
| {% block body %}
#search-container
#search-sidebar
input.search-field(
type="text",
name="q",
id="q",
autocomplete="off",
spellcheck="false",
autocorrect="false",
placeholder="Search by Full Name, Username...")
.search-list-filters
#accordion.panel-group.accordion(role="tablist", aria-multiselectable="true")
#facets
#pagination
.search-list-stats
#stats
#search-list
#hits
#search-details
#search-hit-container
| {% raw %}
// Facet template
script(type="text/template", id="facet-template")
.panel.panel-default
a(data-toggle='collapse', data-parent='#accordion', href='#filter_{{ facet }}', aria-expanded='true', aria-controls='filter_{{ facet }}')
.panel-heading(role='tab')
.panel-title {{ title }}
.panel-collapse.collapse.in(id='filter_{{ facet }}', role='tabpanel', aria-labelledby='headingOne')
.panel-body
| {{#values}}
a.facet_link.toggleRefine(
class='{{#refined}}refined{{/refined}}',
data-facet='{{ facet }}',
data-value='{{ value }}',
href='#')
span
| {{ label }}
small.facet_count.text-muted.pull-right {{ count }}
| {{/values}}
// Hit template
script(type="text/template", id="hit-template")
.search-hit.users(data-user-id='{{ objectID }}')
.search-hit-name
| {{{ _highlightResult.full_name.value }}}
small ({{{ username }}})
.search-hit-roles
| {{{ roles }}}
// Pagination template
script(type="text/template", id="pagination-template")
ul.search-pagination.
<li {{^prev_page}}class="disabled"{{/prev_page}}><a href="#" {{#prev_page}} class="gotoPage" data-page="{{ prev_page }}" {{/prev_page}}><i class="pi-angle-left"></i></a></li>
{{#pages}}
<li class="{{#current}}active{{/current}}{{#disabled}}disabled{{/disabled}}"><a href="#" {{^disabled}} class="gotoPage" data-page="{{ number }}" {{/disabled}}>{{ number }}</a></li>
{{/pages}}
<li {{^next_page}}class="disabled"{{/next_page}}><a href="#" {{#next_page}} class="gotoPage" data-page="{{ next_page }}" {{/next_page}}><i class="pi-angle-right"></i></a></li>
// Stats template
script(type="text/template", id="stats-template")
h5 {{ nbHits }} result{{#nbHits_plural}}s{{/nbHits_plural}}
span ({{ processingTimeMS }}ms)
| {% endraw %}
| {% endblock %}
| {% block footer_scripts %}
script().
var APPLICATION_ID = '{{config.ALGOLIA_USER}}';
var SEARCH_ONLY_API_KEY = '{{config.ALGOLIA_PUBLIC_KEY}}';
var INDEX_NAME = '{{config.ALGOLIA_INDEX_USERS}}';
var sortByCountDesc = null;
var FACET_CONFIG = [
{ name: 'roles', title: 'Roles', disjunctive: false, sortFunction: sortByCountDesc },
];
script(src="//cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js")
script(src="//cdn.jsdelivr.net/algoliasearch.helper/2/algoliasearch.helper.min.js")
script(src="//cdn.jsdelivr.net/hogan.js/3.0.0/hogan.common.js")
script(src="{{ url_for('static_pillar', filename='assets/js/algolia_search.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.select2.min.js') }}")
script(type="text/javascript").
if (typeof Ps !== 'undefined'){
Ps.initialize(document.getElementById('hits'), {suppressScrollX: true});
}
function displayUser(userId) {
var url = '/u/' + userId + '/edit?embed=1';
$.get(url, function(dataHtml){
$('#search-hit-container').html(dataHtml);
});
}
$('body').on('click', '.search-hit', function(){
displayUser($(this).data('user-id'));
});
// Remove focus from search input so that the click event bound to .user-hit
// can be fired on the first click.
$('#search-list').hover(function(){
$('#q').blur();
});
| {% endblock %}

View File

@@ -0,0 +1,45 @@
| {% extends 'layout.html' %}
| {% block body %}
.container
#login-container
.login-title Welcome back!
.login-info
| Log in using your shared username and password.
.login-form
form#login-form(method="POST", action="{{url_for('users.login_local')}}")
.form-group
| {{ form.username.label }}
| {{ form.username(class='form-control') }}
.form-group
| {{ form.password.label }}
| {{ form.password(class='form-control') }}
.buttons
.login-button-container
//a.forgot(href="https://blender.org/id/reset") forgot your password?
button.btn.btn-default.button-login(type="submit")
i.pi-log-in
| Login
//a.btn.btn-default.button-register(href="https://blender.org/id/register", target="_blank")
// i.pi-star-outline
// | Create Account
| {% endblock %}
| {% block footer_scripts %}
script.
$('.button-login').on('click', function(e){
e.preventDefault();
$(this).html('<i class="pi-spin spin"></i> Hold on...');
$('#login-form').submit();
});
| {% endblock %}
| {% block footer_container %}{% endblock %}

View File

@@ -0,0 +1,20 @@
#settings-sidebar
.settings-header
.settings-title Settings
.settings-content
ul
a(class="{% if title == 'profile' %}active{% endif %}",
href="{{ url_for('users.settings_profile') }}")
li
i.pi-vcard
| Profile
a(class="{% if title == 'emails' %}active{% endif %}",
href="{{ url_for('users.settings_emails') }}")
li
i.pi-email
| Emails
a(class="{% if title == 'billing' %}active{% endif %}",
href="{{ url_for('users.settings_billing') }}")
li
i.pi-credit-card
| Subscription

View File

@@ -0,0 +1,55 @@
| {% extends 'layout.html' %}
| {% block body %}
.container
#settings
include _sidebar
#settings-container
.settings-header
.settings-title Subscription
.settings-content
| {% if store_user['cloud_access'] %}
h3.subscription-active
i.pi-check
| Your subscription is active
h4 Thank you for supporting us!
hr
p Subscription expires on: <strong>{{ store_user['expiration_date'][:10] }}</strong>
a(href="https://store.blender.org/my-account/") Manage your subscription on Blender Store
hr
| {# This text is confusing (refers to the total payments ever made by the user)
.settings-billing-info.
Paid balance: {{ store_user['paid_balance'] }} {{ store_user['balance_currency'] }}
| #}
| {% else %}
| {% if 'demo' in groups %}
h3.subscription-demo
i.pi-heart-filled
| You have a free account
hr
p You have full access to the Blender Cloud, provided by the Blender Institute. This account is meant for free evaluation of the service. Get in touch with #[a(href="mailto:cloudsupport@blender.org") cloudsupport@blender.org] if you have any questions.
| {% else %}
h3.subscription-missing
i.pi-info
| You do not have an active subscription.
h3
a(href="https://store.blender.org/product/membership/") Get full access to Blender Cloud now!
| {% endif %}
| {% endif %}
| {% endblock %}

View File

@@ -0,0 +1,27 @@
| {% extends 'layout.html' %}
| {% block body %}
.container
#settings
include _sidebar
#settings-container
.settings-header
.settings-title Emails
.settings-content
.settings-form
form#settings-form(method='POST', action="{{url_for('users.settings_emails')}}")
| {{ form.csrf_token }}
| {% for subfield in form.email_communications %}
.form-group.
{{ subfield }}
{{ subfield.label }}
| {% endfor %}
.buttons
button.btn.btn-default.button-submit(type='submit')
i.pi-check
| Save Changes
| {% endblock %}

View File

@@ -0,0 +1,45 @@
| {% extends 'layout.html' %}
| {% block body %}
.container
#settings
include _sidebar
#settings-container
.settings-header
.settings-title Profile
.settings-content
.settings-form
form#settings-form(method='POST', action="{{url_for('users.settings_profile')}}")
.left
.form-group
| {{ form.full_name.label }}
| {{ form.full_name(size=20, class='form-control') }}
| {% if form.full_name.errors %}
| {% for error in form.full_name.errors %}{{ error|e }}{% endfor %}
| {% endif %}
.form-group
| {{ form.username.label }}
| {{ form.username(size=20, class='form-control') }}
| {% if form.username.errors %}
| {% for error in form.username.errors %}{{ error|e }}{% endfor %}
| {% endif %}
.form-group.settings-password
| Change your password at the
a(href="https://blender.org/id/change") Blender ID
.right
.settings-avatar
a(href="https://gravatar.com/")
img(src="{{ current_user.gravatar }}")
span Change Gravatar
.buttons
button.btn.btn-default.button-submit(type='submit')
i.pi-check
| Save Changes
| {% endblock %}

View File

@@ -0,0 +1,170 @@
| {% extends 'layout.html' %}
| {% block header_items %}
link(href='//cdn.datatables.net/plug-ins/1.10.7/integration/bootstrap/3/dataTables.bootstrap.css', rel='stylesheet')
| {% endblock %}
| {% block body %}
#shots-main.col-md-8
table#user_tasks.table.table-striped.table-hover(
cellpadding='0', cellspacing='0', border='0')
thead
tr
th {# 0 #}
th {# 1 #}
th {# 2 #}
th {# 3 #}
th {# 4 #} Shot
th {# 5 #} Name
th {# 6 #} Description
th {# 7 #} Duration
th {# 8 #} Status
| {% endblock %}
| {% block sidebar %}
#shots-sidebar.col-md-4
#shot_details_container
#task_details_container
| {% endblock %}
| {% block footer_scripts %}
script(type='text/javascript', src='//cdn.datatables.net/1.10.7/js/jquery.dataTables.min.js')
script().
$(document).ready(function(){
function render_timing(timing) {
var timing_text = '';
if (timing['cut_in'] && timing['cut_out']) {
timing_frames = timing['cut_out'] - timing['cut_in'];
timing_text += '<span title="';
timing_text += timing_frames;
timing_text += 'f">';
timing_text += Math.round(timing_frames / 24);
timing_text += 's</span>';
}
return timing_text;
}
function render_status_options(status) {
var selected = false;
var options = []
statuses = ['todo', 'in_progress', 'on_hold', 'review', 'approved', 'final']
$.each(statuses, function(key, value) {
selected = false;
if (status === value) {
selected = true;
};
option = $("<option />", {
value: value,
text: value,
selected: selected
});
options.push(option);
});
return options;
}
function render_status_label(task, task_name) {
switch(task.status) {
case 'todo':
label_text = 'ToDo';
break;
case 'in_progress':
label_text = 'In progress';
break;
case 'on_hold':
label_text = 'On Hold';
break;
case 'cbb':
label_text = 'Could Be Better';
break;
case 'review':
label_text = 'Review';
break;
case 'approved':
label_text = 'Approved';
break;
case 'final':
label_text = 'Final';
break;
case 'conflict':
label_text = 'Conflict';
break;
default:
label_text = task.status;
break
}
if (task.is_conflicting) {
label_text = 'Conflict';
task.status = 'conflict';
}
return tag = '<span task-edit-url="' + task.url_edit + '" class="load-task-view label label-' + task.status + '">' + label_text + '</span>'
}
var shots_table = $('#user_tasks').DataTable({
"paging": false,
"order": [[ 7, "desc" ]],
"data": {{tasks_data | safe}},
"columns": [
/* */ {"data": "_id"},
/* */ {"data": "order"},
/* 0 */ {"data": "picture", "width": "80px", "className": "shots-shot_thumbnail"},
/* 1 */ {"data": "parent.name"},
/* 2 */ {"data": "name", "className": "shots-shot_name"},
/* 3 */ {"data": "description", "className": "shots-shot_description"},
/* 4 */ {"data": null,},
/* 5 */ {"data": "status"},
/* 6 */ {"data": null}
],
"columnDefs": [
{
"targets": [0, 1],
"visible": false,
"searchable": false
},
],
"rowCallback": function ( row, data, index ) {
if ( data.picture) {
var img_tag = '<img alt="' + data.name + '" src="' + data.picture_thumbnail + '" class="table-thumbnail">';
$('td', row).eq(0).html('<a href="' + data.url_view + '">' + img_tag + '</a>');
}
$('td', row).eq(2).html('<a class="load-shot-view" shot-view-url="' + data.url_edit + '" href="' + data.url_view + '">' + data.name + '</a>');
$('td', row).eq(4).html(render_timing(data.timing));
$('td', row).eq(5).html(render_status_label(data, data.name));
var view_tag = '<span class="btn btn-default btn-xs load-shot-view" shot-view-url="' + data.url_edit + '"><i class="glyphicon glyphicon-edit"></i> View</span>';
$('td', row).eq(6).html(view_tag);
}
});
$(document).on("click", ".load-task-view", function() {
$(".task-update").off( "click" );
task_view_url = $(this).attr('task-edit-url');
$.get(task_view_url, function(data) {
$('#shot_details_container').hide();
$('#task_details_container').html(data);
$('#task_details_container').show();
});
$('.load-task-view').removeClass('active');
$(this).addClass('active');
var shots_table = $('#user_tasks').DataTable();
var row = shots_table.row($(this).closest('tr'))
// Remove class 'active' from rows, and add to current one
shots_table.rows('.active').nodes().to$().removeClass('active updated');
shots_table.row(row).nodes().to$().addClass('active');
shots_table.draw();
});
});
| {% endblock %}

16
src/templates/vrview.jade Normal file
View File

@@ -0,0 +1,16 @@
doctype html
html(lang='en')
head
title VR view
meta(charset='utf-8')
meta(name='viewport', content='width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0')
meta(name='mobile-web-app-capable', content='yes')
meta(name='apple-mobile-web-app-capable', content='yes')
meta(name='apple-mobile-web-app-status-bar-style', content='black-translucent')
link(rel="stylesheet", href="{{url_for('static_pillar', filename='assets/css/vrview.css')}}")
body
#error.dialog
.wrap
h1.title Error
p.message An unknown error occurred.
script(src="{{url_for('static_pillar', filename='assets/js/vrview-analytics.min.js')}}")